Added initial version of org.eclipse.rap.ui.workbench bundle.

Change-Id: I0a2710492db5a785fa5e919fcc33267175232bc0

This version is compatible with Eclipse Oxygen.2 and it has been derived
from org.eclipse.ui.workbench (3.110.1.v20170704-1208) and
org.eclipse.rap.ui.workbench (RAP 3.4.0-R-20171204-1637)

Change-Id: I0a2710492db5a785fa5e919fcc33267175232bc0
diff --git a/bundles/org.eclipse.rap.ui.workbench/.api_description b/bundles/org.eclipse.rap.ui.workbench/.api_description
new file mode 100644
index 0000000..a8fdbfa
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/.api_description
@@ -0,0 +1,205 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<component name="org.eclipse.ui.workbench_3.110.1.v20170704-1208" version="1.2">
+    <plugin id="org.eclipse.ui.workbench_3.110.1.v20170704-1208"/>
+    <package name="org.eclipse.ui" visibility="1">
+        <type name="IActionBars" restrictions="1"/>
+        <type name="IActionBars2" restrictions="1"/>
+        <type name="IAggregateWorkingSet" restrictions="1"/>
+        <type name="IDecoratorManager" restrictions="1"/>
+        <type name="IEditorDescriptor" restrictions="1"/>
+        <type name="IEditorReference" restrictions="1"/>
+        <type name="IEditorRegistry" restrictions="1"/>
+        <type name="IEditorSite" restrictions="1"/>
+        <type name="IFileEditorMapping" restrictions="1"/>
+        <type name="IFolderLayout" restrictions="1"/>
+        <type name="IInPlaceEditor" restrictions="1"/>
+        <type name="IKeyBindingService" restrictions="1"/>
+        <type name="ILocalWorkingSetManager" restrictions="1"/>
+        <type name="IMemento" restrictions="1"/>
+        <type name="INavigationHistory" restrictions="1"/>
+        <type name="INavigationLocation" restrictions="1"/>
+        <type name="INestableKeyBindingService" restrictions="1"/>
+        <type name="IPageLayout" restrictions="1"/>
+        <type name="IPageService" restrictions="1"/>
+        <type name="IPartService" restrictions="1"/>
+        <type name="IPerspectiveDescriptor" restrictions="1"/>
+        <type name="IPerspectiveRegistry" restrictions="1"/>
+        <type name="IPlaceholderFolderLayout" restrictions="1"/>
+        <type name="ISelectionService" restrictions="1"/>
+        <type name="ISharedImages" restrictions="3"/>
+        <type name="ISources" restrictions="3"/>
+        <type name="IViewLayout" restrictions="1"/>
+        <type name="IViewReference" restrictions="1"/>
+        <type name="IViewSite" restrictions="1"/>
+        <type name="IWorkbench" restrictions="1"/>
+        <type name="IWorkbenchActionConstants" restrictions="3"/>
+        <type name="IWorkbenchCommandConstants" restrictions="3"/>
+        <type name="IWorkbenchPage" restrictions="1"/>
+        <type name="IWorkbenchPartConstants" restrictions="1"/>
+        <type name="IWorkbenchPartDescriptor" restrictions="1"/>
+        <type name="IWorkbenchPartReference" restrictions="1"/>
+        <type name="IWorkbenchPartSite" restrictions="1"/>
+        <type name="IWorkbenchPreferenceConstants" restrictions="3"/>
+        <type name="IWorkbenchSite" restrictions="1"/>
+        <type name="IWorkbenchWindow" restrictions="1"/>
+        <type name="IWorkingSet" restrictions="1"/>
+        <type name="IWorkingSetManager" restrictions="1"/>
+        <type name="MultiPartInitException" restrictions="2"/>
+        <type name="PartInitException" restrictions="2"/>
+        <type name="WorkbenchException" restrictions="2"/>
+    </package>
+    <package name="org.eclipse.ui.about" visibility="1">
+        <type name="IInstallationPageContainer" restrictions="1"/>
+    </package>
+    <package name="org.eclipse.ui.actions" visibility="1">
+        <type name="ExportResourcesAction" restrictions="2"/>
+        <type name="ImportResourcesAction" restrictions="2"/>
+        <type name="LabelRetargetAction" restrictions="2"/>
+        <type name="NewWizardAction" restrictions="2"/>
+        <type name="OpenNewPageMenu" restrictions="2"/>
+        <type name="OpenNewWindowMenu" restrictions="2"/>
+        <type name="OpenPerspectiveMenu" restrictions="2"/>
+        <type name="RetargetAction" restrictions="2"/>
+    </package>
+    <package name="org.eclipse.ui.activities" visibility="1">
+        <type name="IActivity" restrictions="1"/>
+        <type name="IActivityManager" restrictions="1"/>
+        <type name="IActivityPatternBinding" restrictions="1"/>
+        <type name="IActivityRequirementBinding" restrictions="1"/>
+        <type name="ICategory" restrictions="1"/>
+        <type name="ICategoryActivityBinding" restrictions="1"/>
+        <type name="IIdentifier" restrictions="1"/>
+        <type name="IMutableActivityManager" restrictions="1"/>
+        <type name="ITriggerPoint" restrictions="1"/>
+        <type name="ITriggerPointAdvisor" restrictions="3"/>
+        <type name="ITriggerPointManager" restrictions="1"/>
+        <type name="IWorkbenchActivitySupport" restrictions="1"/>
+    </package>
+    <package name="org.eclipse.ui.application" visibility="1">
+        <type name="IActionBarConfigurer" restrictions="1"/>
+        <type name="IWorkbenchConfigurer" restrictions="1"/>
+        <type name="IWorkbenchWindowConfigurer" restrictions="1"/>
+    </package>
+    <package name="org.eclipse.ui.browser" visibility="1">
+        <type name="IWebBrowser" restrictions="1"/>
+        <type name="IWorkbenchBrowserSupport" restrictions="3"/>
+    </package>
+    <package name="org.eclipse.ui.commands" visibility="1">
+        <type name="CommandException" restrictions="2"/>
+        <type name="ICategory" restrictions="1"/>
+        <type name="ICommand" restrictions="1"/>
+        <type name="ICommandImageService" restrictions="3"/>
+        <type name="ICommandManager" restrictions="1"/>
+        <type name="ICommandService" restrictions="3"/>
+        <type name="IKeyConfiguration" restrictions="1"/>
+        <type name="IKeySequenceBinding" restrictions="1"/>
+        <type name="IWorkbenchCommandSupport" restrictions="1"/>
+    </package>
+    <package name="org.eclipse.ui.contexts" visibility="1">
+        <type name="ContextException" restrictions="2"/>
+        <type name="IContext" restrictions="1"/>
+        <type name="IContextManager" restrictions="1"/>
+        <type name="IContextService" restrictions="3"/>
+        <type name="IWorkbenchContextSupport" restrictions="1"/>
+    </package>
+    <package name="org.eclipse.ui.dialogs" visibility="1">
+        <type name="EditorSelectionDialog" restrictions="2"/>
+        <type name="IWorkingSetEditWizard" restrictions="1"/>
+        <type name="IWorkingSetNewWizard" restrictions="1"/>
+        <type name="IWorkingSetSelectionDialog" restrictions="1"/>
+        <type name="ListSelectionDialog" restrictions="2"/>
+        <type name="PropertyDialogAction" restrictions="2"/>
+    </package>
+    <package name="org.eclipse.ui.handlers" visibility="1">
+        <type name="HandlerUtil" restrictions="6"/>
+        <type name="IHandlerService" restrictions="3"/>
+    </package>
+    <package name="org.eclipse.ui.help" visibility="1">
+        <type name="DialogPageContextComputer" restrictions="14"/>
+        <type name="IContextComputer" restrictions="11"/>
+        <type name="IWorkbenchHelpSystem" restrictions="1"/>
+        <type name="ViewContextComputer" restrictions="14"/>
+        <type name="WorkbenchHelp" restrictions="14"/>
+    </package>
+    <package name="org.eclipse.ui.intro" visibility="1">
+        <type name="IIntroManager" restrictions="1"/>
+        <type name="IIntroPart" restrictions="1"/>
+        <type name="IIntroSite" restrictions="1"/>
+    </package>
+    <package name="org.eclipse.ui.keys" visibility="1">
+        <type name="IBindingService" restrictions="3"/>
+        <type name="Key" restrictions="2"/>
+        <type name="NaturalKey" restrictions="2"/>
+    </package>
+    <package name="org.eclipse.ui.menus" visibility="1">
+        <type name="CommandContributionItem" restrictions="2"/>
+        <type name="CommandContributionItemParameter" restrictions="0">
+            <method name="&lt;init&gt;" restrictions="8" signature="(Lorg/eclipse/ui/services/IServiceLocator;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Lorg/eclipse/jface/resource/ImageDescriptor;Lorg/eclipse/jface/resource/ImageDescriptor;Lorg/eclipse/jface/resource/ImageDescriptor;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;Z)V"/>
+        </type>
+        <type name="IMenuService" restrictions="3"/>
+        <type name="MenuUtil" restrictions="6"/>
+        <type name="WorkbenchWindowControlContribution" restrictions="0">
+            <method name="delegateCreateControl" restrictions="24" signature="(Lorg/eclipse/swt/widgets/Composite;)Lorg/eclipse/swt/widgets/Control;"/>
+        </type>
+    </package>
+    <package name="org.eclipse.ui.model" visibility="1">
+        <type name="AdaptableList" restrictions="2"/>
+    </package>
+    <package name="org.eclipse.ui.operations" visibility="1">
+        <type name="IWorkbenchOperationSupport" restrictions="1"/>
+    </package>
+    <package name="org.eclipse.ui.part" visibility="1">
+        <type name="AbstractMultiEditor" restrictions="0">
+            <method name="setChildren" restrictions="8" signature="([Lorg/eclipse/ui/IEditorPart;)V"/>
+        </type>
+        <type name="CellEditorActionHandler" restrictions="2"/>
+        <type name="CoolItemGroupMarker" restrictions="2"/>
+        <type name="IPage" restrictions="1"/>
+        <type name="IPageSite" restrictions="1"/>
+        <type name="MessagePage" restrictions="2"/>
+        <type name="MultiEditorInput" restrictions="2"/>
+        <type name="MultiPageEditorPart" restrictions="0">
+            <method name="addPageChangedListener" restrictions="16" signature="(Lorg/eclipse/jface/dialogs/IPageChangedListener;)V"/>
+            <method name="getActiveEditor" restrictions="16" signature="()Lorg/eclipse/ui/IEditorPart;"/>
+            <method name="getActivePage" restrictions="16" signature="()I"/>
+            <method name="removePageChangedListener" restrictions="16" signature="(Lorg/eclipse/jface/dialogs/IPageChangedListener;)V"/>
+        </type>
+        <type name="MultiPageSelectionProvider" restrictions="2"/>
+        <type name="PageBook" restrictions="2"/>
+        <type name="PluginTransferData" restrictions="2"/>
+        <type name="WorkbenchPart" restrictions="2"/>
+    </package>
+    <package name="org.eclipse.ui.progress" visibility="1">
+        <type name="IProgressConstants2" restrictions="1"/>
+        <type name="IProgressService" restrictions="1"/>
+        <type name="IWorkbenchSiteProgressService" restrictions="1"/>
+    </package>
+    <package name="org.eclipse.ui.services" visibility="1">
+        <type name="IEvaluationReference" restrictions="3"/>
+        <type name="IEvaluationService" restrictions="3"/>
+        <type name="IServiceScopes" restrictions="3"/>
+        <type name="ISourceProviderService" restrictions="3"/>
+    </package>
+    <package name="org.eclipse.ui.statushandlers" visibility="1">
+        <type name="StatusManager" restrictions="0"/>
+        <type name="StatusManager$INotificationTypes" restrictions="3"/>
+        <type name="WorkbenchStatusDialogManager" restrictions="2"/>
+    </package>
+    <package name="org.eclipse.ui.swt" visibility="1">
+        <type name="IFocusService" restrictions="1"/>
+    </package>
+    <package name="org.eclipse.ui.themes" visibility="1">
+        <type name="ITheme" restrictions="1"/>
+        <type name="IThemeManager" restrictions="1"/>
+    </package>
+    <package name="org.eclipse.ui.views" visibility="1">
+        <type name="IStickyViewDescriptor" restrictions="1"/>
+        <type name="IViewDescriptor" restrictions="1"/>
+        <type name="IViewRegistry" restrictions="1"/>
+    </package>
+    <package name="org.eclipse.ui.wizards" visibility="1">
+        <type name="IWizardCategory" restrictions="1"/>
+        <type name="IWizardDescriptor" restrictions="1"/>
+        <type name="IWizardRegistry" restrictions="1"/>
+    </package>
+</component>
diff --git a/bundles/org.eclipse.rap.ui.workbench/.classpath b/bundles/org.eclipse.rap.ui.workbench/.classpath
new file mode 100644
index 0000000..f17aee0
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<classpath>

+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>

+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>

+	<classpathentry kind="src" path="src/"/>

+	<classpathentry kind="output" path="bin"/>

+</classpath>

diff --git a/bundles/org.eclipse.rap.ui.workbench/.options b/bundles/org.eclipse.rap.ui.workbench/.options
new file mode 100644
index 0000000..1f4ea78
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/.options
@@ -0,0 +1,7 @@
+# Debugging options for the org.eclipse.ui.workbench plugin.
+
+# Turn on debugging for the org.eclipse.ui.workbench plugin.
+org.eclipse.ui.workbench/debug=false
+
+# Turn on tracing of e4 development messages
+org.eclipse.ui.workbench/debug/e4=false
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/.project b/bundles/org.eclipse.rap.ui.workbench/.project
new file mode 100644
index 0000000..e5f58ba
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<projectDescription>

+	<name>org.eclipse.rap.ui.workbench</name>

+	<comment></comment>

+	<projects>

+	</projects>

+	<buildSpec>

+		<buildCommand>

+			<name>org.eclipse.jdt.core.javabuilder</name>

+			<arguments>

+			</arguments>

+		</buildCommand>

+		<buildCommand>

+			<name>org.eclipse.pde.ManifestBuilder</name>

+			<arguments>

+			</arguments>

+		</buildCommand>

+		<buildCommand>

+			<name>org.eclipse.pde.SchemaBuilder</name>

+			<arguments>

+			</arguments>

+		</buildCommand>

+	</buildSpec>

+	<natures>

+		<nature>org.eclipse.pde.PluginNature</nature>

+		<nature>org.eclipse.jdt.core.javanature</nature>

+	</natures>

+</projectDescription>

diff --git a/bundles/org.eclipse.rap.ui.workbench/.settings/org.eclipse.jdt.core.prefs b/bundles/org.eclipse.rap.ui.workbench/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..295926d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,7 @@
+eclipse.preferences.version=1

+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled

+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8

+org.eclipse.jdt.core.compiler.compliance=1.8

+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error

+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error

+org.eclipse.jdt.core.compiler.source=1.8

diff --git a/bundles/org.eclipse.rap.ui.workbench/LegacyIDE.e4xmi b/bundles/org.eclipse.rap.ui.workbench/LegacyIDE.e4xmi
new file mode 100644
index 0000000..e14a600
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/LegacyIDE.e4xmi
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="ASCII"?>
+<application:Application xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:application="http://www.eclipse.org/ui/2010/UIModel/application" xmlns:basic="http://www.eclipse.org/ui/2010/UIModel/application/ui/basic" xsi:schemaLocation="http://www.eclipse.org/ui/2010/UIModel/application/ui/basic http://www.eclipse.org/ui/2010/UIModel/application#//ui/basic" xmi:id="org.eclipse.e4.legacy.ide.application" elementId="org.eclipse.e4.legacy.ide.application" bindingContexts="_SeXUHO8EEd6BC9cDb6iV7y">
+  <children xsi:type="basic:TrimmedWindow" xmi:id="IDEWindow" elementId="IDEWindow" width="5" height="5">
+    <trimBars xmi:id="_vCH1AF1sEeOF8qbLMOkG7A" elementId="org.eclipse.ui.main.toolbar"/>
+    <trimBars xmi:id="_CT96oF6VEeO_3ZCXGA_PQg" elementId="org.eclipse.ui.trim.status" side="Bottom"/>
+    <trimBars xmi:id="_DU4lEF6VEeO_3ZCXGA_PQg" elementId="org.eclipse.ui.trim.vertical1" side="Left"/>
+    <trimBars xmi:id="_Ek7QoF6VEeO_3ZCXGA_PQg" elementId="org.eclipse.ui.trim.vertical2" side="Right"/>
+  </children>
+  <bindingTables xmi:id="_SeXUEO8EEd6FC9cDb6iV7x" bindingContext="_SeXUHO8EEd6BC9cDb6iV7y"/>
+  <rootContext xmi:id="_SeXUHO8EEd6BC9cDb6iV7y" elementId="org.eclipse.ui.contexts.dialogAndWindow" name="%bindingcontext.name.dialogAndWindows">
+    <children xmi:id="_SeXUEO8EEd6FC9cDb6iV7w" elementId="org.eclipse.ui.contexts.window" name="%bindingcontext.name.windows">
+      <children xmi:id="_SeXUEO8EEd6FC9cDb6yV7x" elementId="org.eclipse.e4.ui.contexts.views" name="%bindingcontext.name.bindingView"/>
+    </children>
+    <children xmi:id="_SeXUEO8EEd6FC9cDb6iV7x" elementId="org.eclipse.ui.contexts.dialog" name="%bindingcontext.name.dialogs"/>
+  </rootContext>
+  <addons xmi:id="_XGB3wPZlEd-XstlTZ6nTXg" elementId="org.eclipse.e4.core.commands.service" contributionURI="bundleclass://org.eclipse.e4.core.commands/org.eclipse.e4.core.commands.CommandServiceAddon"/>
+  <addons xmi:id="_XGB3wPZlEd-XstlTZ6nTXh" elementId="org.eclipse.e4.ui.contexts.service" contributionURI="bundleclass://org.eclipse.e4.ui.services/org.eclipse.e4.ui.services.ContextServiceAddon"/>
+  <addons xmi:id="_XGB3wPZlEd-XstlTZ6nTXi" elementId="org.eclipse.e4.ui.bindings.service" contributionURI="bundleclass://org.eclipse.e4.ui.bindings/org.eclipse.e4.ui.bindings.BindingServiceAddon"/>
+  <addons xmi:id="_LK0NgPZmEd-XstlTZ6nTXj" elementId="org.eclipse.e4.ui.workbench.commands.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench/org.eclipse.e4.ui.internal.workbench.addons.CommandProcessingAddon"/>
+  <addons xmi:id="_LK0NgPZmEd-XstlTZ6nTXk" elementId="org.eclipse.e4.ui.workbench.contexts.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench/org.eclipse.e4.ui.internal.workbench.addons.ContextProcessingAddon"/>
+  <addons xmi:id="_LK0NgPZmEd-XstlTZ6nTXl" elementId="org.eclipse.e4.ui.workbench.bindings.model" contributionURI="bundleclass://org.eclipse.e4.ui.workbench.swt/org.eclipse.e4.ui.workbench.swt.util.BindingProcessingAddon"/>
+  <addons xmi:id="_XwQYkE2EEd-DfN2vYY4Lew" elementId="Cleanup Addon" contributionURI="bundleclass://org.eclipse.e4.ui.workbench.addons.swt/org.eclipse.e4.ui.workbench.addons.cleanupaddon.CleanupAddon"/>
+  <addons xmi:id="_bqcWME2EEd-DfN2vYY4Lew" elementId="DnD Addon" contributionURI="bundleclass://org.eclipse.e4.ui.workbench.addons.swt/org.eclipse.e4.ui.workbench.addons.dndaddon.DnDAddon"/>
+  <addons xmi:id="_7GC6sGp-Ed-QyNZjH9g15Q" elementId="MinMax Addon" contributionURI="bundleclass://org.eclipse.e4.ui.workbench.addons.swt/org.eclipse.e4.ui.workbench.addons.minmax.MinMaxAddon"/>
+  <addons xmi:id="_00yosOXqEeGugqEu_OWUGQ" elementId="org.eclipse.ui.workbench.addon.0" contributionURI="bundleclass://org.eclipse.e4.ui.workbench/org.eclipse.e4.ui.internal.workbench.addons.HandlerProcessingAddon"/>
+</application:Application>
diff --git a/bundles/org.eclipse.rap.ui.workbench/META-INF/MANIFEST.MF b/bundles/org.eclipse.rap.ui.workbench/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..a2b1e8a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/META-INF/MANIFEST.MF
@@ -0,0 +1,161 @@
+Manifest-Version: 1.0

+Bundle-SymbolicName: org.eclipse.rap.ui.workbench; singleton:=true

+Archiver-Version: Plexus Archiver

+Built-By: genie.releng

+Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.6.0,4.0.0)",

+ org.eclipse.help;bundle-version="[3.2.0,4.0.0)",

+ org.eclipse.rap.jface,

+ org.eclipse.rap.jface.databinding,

+ org.eclipse.core.databinding.property;bundle-version="[1.2.0,2.0.0)",

+ org.eclipse.core.databinding.observable;bundle-version="[1.2.0,2.0.0)",

+ org.eclipse.e4.core.services;bundle-version="1.0.0",

+ org.eclipse.e4.core.contexts;bundle-version="1.0.0",

+ org.eclipse.e4.core.di;bundle-version="1.1.0",

+ org.eclipse.e4.ui.workbench.swt;bundle-version="0.9.1",

+ org.eclipse.e4.ui.di;bundle-version="0.9.0",

+ org.eclipse.e4.ui.model.workbench;bundle-version="0.9.1",

+ org.eclipse.e4.ui.css.swt.theme;bundle-version="0.9.0";resolution:=optional,

+ org.eclipse.e4.ui.bindings;bundle-version="0.9.0",

+ org.eclipse.e4.ui.css.swt;bundle-version="0.9.1";resolution:=optional,

+ org.eclipse.e4.ui.css.core;bundle-version="0.9.0";resolution:=optional,

+ org.eclipse.e4.ui.workbench3;bundle-version="0.12.0";resolution:=optional;visibility:=reexport,

+ org.eclipse.e4.ui.workbench.addons.swt;bundle-version="0.10.0",

+ org.eclipse.emf.ecore;bundle-version="2.7.0",

+ org.eclipse.e4.ui.services,

+ org.eclipse.emf.ecore.xmi;bundle-version="2.11.0",

+ org.eclipse.e4.core.di.extensions;bundle-version="0.13.0",

+ org.eclipse.osgi.services,

+ org.eclipse.rap.e4,

+ org.eclipse.equinox.http.registry

+Bundle-ManifestVersion: 2

+Bundle-ActivationPolicy: lazy

+Bundle-RequiredExecutionEnvironment: JavaSE-1.8

+Eclipse-SourceReferences: scm:git:git://git.eclipse.org/gitroot/platfo

+ rm/eclipse.platform.ui.git;path="bundles/org.eclipse.ui.workbench";ta

+ g="M20170705-0505";commitId=96dc559f38ef55ccbf69f0b4a8ec9ad9c1349da4

+Bundle-Vendor: %providerName

+Import-Package: com.ibm.icu.text,

+ com.ibm.icu.util,

+ javax.annotation,

+ javax.inject;version="1.0.0",

+ javax.servlet,

+ javax.servlet.http,

+ javax.xml.parsers,

+ org.eclipse.e4.core.commands,

+ org.eclipse.e4.core.commands.internal,

+ org.eclipse.e4.ui.internal.workbench,

+ org.eclipse.e4.ui.internal.workbench.addons,

+ org.eclipse.e4.ui.internal.workbench.renderers.swt,

+ org.eclipse.e4.ui.internal.workbench.swt,

+ org.eclipse.e4.ui.services,

+ org.eclipse.e4.ui.workbench,

+ org.eclipse.e4.ui.workbench.modeling,

+ org.eclipse.e4.ui.workbench.renderers.swt,

+ org.eclipse.emf.common.util,

+ org.eclipse.emf.ecore,

+ org.eclipse.emf.ecore.util,

+ org.eclipse.rap.rwt.osgi,

+ org.osgi.service.component.annotations;version="1.2.0";resolution:=optional,

+ org.osgi.service.event;version="1.2.0",

+ org.w3c.dom,

+ org.w3c.dom.css,

+ org.xml.sax

+Require-Capability: osgi.extender; filter:="(&(osgi.extender=osgi.comp

+ onent)(version>=1.2)(!(version>=2.0)))"

+Service-Component: OSGI-INF/org.eclipse.ui.internal.themes.ColorAndFon

+ tProviderImpl.xml

+Export-Package: org.eclipse.e4.ui.workbench.addons.perspectiveswitcher,

+ org.eclipse.rap.ui.internal,

+ org.eclipse.rap.ui.internal.application;x-internal:=true,

+ org.eclipse.rap.ui.internal.branding;x-internal:=true,

+ org.eclipse.rap.ui.internal.preferences;x-internal:=true,

+ org.eclipse.rap.ui.internal.progress;x-internal:=true,

+ org.eclipse.rap.ui.internal.servlet;x-internal:=true,

+ org.eclipse.rap.ui.partdnd,

+ org.eclipse.rap.ui.resources,

+ org.eclipse.ui;ui.workbench=split;mandatory:="ui.workbench",

+ org.eclipse.ui.about,

+ org.eclipse.ui.actions;ui.workbench=split;mandatory:="ui.workbench",

+ org.eclipse.ui.activities,

+ org.eclipse.ui.application,

+ org.eclipse.ui.branding,

+ org.eclipse.ui.browser;ui.workbench=split;mandatory:="ui.workbench",

+ org.eclipse.ui.commands,

+ org.eclipse.ui.contexts,

+ org.eclipse.ui.databinding,

+ org.eclipse.ui.dialogs;ui.workbench=split;mandatory:="ui.workbench",

+ org.eclipse.ui.dnd,

+ org.eclipse.ui.fieldassist,

+ org.eclipse.ui.handlers,

+ org.eclipse.ui.help,

+ org.eclipse.ui.internal;ui.workbench=split;mandatory:="ui.workbench";

+  x-friends:="org.eclipse.ui,

+   org.eclipse.ui.intro,

+   org.eclipse.ui.ide,

+   org.eclipse.ui.ide.application,

+   org.eclipse.ui.views",

+ org.eclipse.ui.internal.about;x-friends:="org.eclipse.ui",

+ org.eclipse.ui.internal.actions;x-friends:="org.eclipse.ui.ide",

+ org.eclipse.ui.internal.activities;x-friends:="org.eclipse.ui",

+ org.eclipse.ui.internal.activities.ws;x-internal:=true,

+ org.eclipse.ui.internal.application;x-internal:=true,

+ org.eclipse.ui.internal.browser;ui.workbench=split;mandatory:="ui.workbench";x-internal:=true,

+ org.eclipse.ui.internal.commands;x-friends:="org.eclipse.ui",

+ org.eclipse.ui.internal.contexts;x-friends:="org.eclipse.ui",

+ org.eclipse.ui.internal.decorators;x-friends:="org.eclipse.ui.ide",

+ org.eclipse.ui.internal.dialogs;x-friends:="org.eclipse.ui.ide,org.eclipse.ui.ide.application",

+ org.eclipse.ui.internal.dialogs.cpd;x-friends:="org.eclipse.ui.ide,org.eclipse.ui.ide.application",

+ org.eclipse.ui.internal.dnd;x-friends:="org.eclipse.ui.intro",

+ org.eclipse.ui.internal.e4.compatibility;x-friends:="org.eclipse.e4.ui.workbench.addons.swt",

+ org.eclipse.ui.internal.e4.migration,

+ org.eclipse.ui.internal.editorsupport;x-internal:=true,

+ org.eclipse.ui.internal.expressions;x-internal:=true,

+ org.eclipse.ui.internal.handlers;x-friends:="org.eclipse.ui,org.eclipse.ui.ide",

+ org.eclipse.ui.internal.help;x-internal:=true,

+ org.eclipse.ui.internal.intro;x-internal:=true,

+ org.eclipse.ui.internal.keys;x-internal:=true,

+ org.eclipse.ui.internal.keys.model;x-internal:=true,

+ org.eclipse.ui.internal.layout;x-friends:="org.eclipse.ui.intro",

+ org.eclipse.ui.internal.menus;x-friends:="org.eclipse.rap.ui",

+ org.eclipse.ui.internal.misc;x-internal:=true,

+ org.eclipse.ui.internal.model;x-internal:=true,

+ org.eclipse.ui.internal.operations;x-internal:=true,

+ org.eclipse.ui.internal.part;x-internal:=true,

+ org.eclipse.ui.internal.preferences;x-friends:="org.eclipse.rap.ui",

+ org.eclipse.ui.internal.progress;x-internal:=true,

+ org.eclipse.ui.internal.provisional.application;x-internal:=true,

+ org.eclipse.ui.internal.quickaccess;x-friends:="org.eclipse.rap.ui",

+ org.eclipse.ui.internal.registry;x-friends:="org.eclipse.rap.ui,org.eclipse.ui.ide",

+ org.eclipse.ui.internal.services;x-friends:="org.eclipse.rap.ui",

+ org.eclipse.ui.internal.splash;x-internal:=true,

+ org.eclipse.ui.internal.statushandlers;x-internal:=true,

+ org.eclipse.ui.internal.testing;x-internal:=true,

+ org.eclipse.ui.internal.themes;x-friends:="org.eclipse.rap.ui",

+ org.eclipse.ui.internal.tweaklets;x-internal:=true,

+ org.eclipse.ui.internal.util;x-friends:="org.eclipse.rap.ui,org.eclipse.ui.ide",

+ org.eclipse.ui.internal.wizards;x-internal:=true,

+ org.eclipse.ui.internal.wizards.preferences;x-internal:=true,

+ org.eclipse.ui.intro,

+ org.eclipse.ui.keys,

+ org.eclipse.ui.menus,

+ org.eclipse.ui.model;ui.workbench=split;mandatory:="ui.workbench",

+ org.eclipse.ui.operations,

+ org.eclipse.ui.part;ui.workbench=split;mandatory:="ui.workbench",

+ org.eclipse.ui.plugin,

+ org.eclipse.ui.preferences,

+ org.eclipse.ui.progress,

+ org.eclipse.ui.services,

+ org.eclipse.ui.splash,

+ org.eclipse.ui.statushandlers,

+ org.eclipse.ui.swt,

+ org.eclipse.ui.testing,

+ org.eclipse.ui.themes,

+ org.eclipse.ui.views,

+ org.eclipse.ui.wizards

+Bundle-Name: %pluginName

+Bundle-Version: 3.4.9.E4CL-qualifier

+Bundle-ClassPath: .

+Bundle-Localization: plugin

+Bundle-Activator: org.eclipse.ui.internal.WorkbenchPlugin

+Created-By: Apache Maven 3.3.3

+Build-Jdk: 1.8.0_121

diff --git a/bundles/org.eclipse.rap.ui.workbench/META-INF/p2.inf b/bundles/org.eclipse.rap.ui.workbench/META-INF/p2.inf
new file mode 100644
index 0000000..fbf82cf
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/META-INF/p2.inf
@@ -0,0 +1,3 @@
+requires.0.namespace = osgi.extender
+requires.0.name = osgi.component
+requires.0.range = [1.2.0, 2)
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/OSGI-INF/org.eclipse.ui.internal.themes.ColorAndFontProviderImpl.xml b/bundles/org.eclipse.rap.ui.workbench/OSGI-INF/org.eclipse.ui.internal.themes.ColorAndFontProviderImpl.xml
new file mode 100644
index 0000000..201735c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/OSGI-INF/org.eclipse.ui.internal.themes.ColorAndFontProviderImpl.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.eclipse.ui.internal.themes.ColorAndFontProviderImpl">
+   <service>
+      <provide interface="org.eclipse.e4.ui.internal.css.swt.definition.IColorAndFontProvider"/>
+   </service>
+   <implementation class="org.eclipse.ui.internal.themes.ColorAndFontProviderImpl"/>
+</scr:component>
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/about.html b/bundles/org.eclipse.rap.ui.workbench/about.html
new file mode 100644
index 0000000..4602330
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/about.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+ 
+<p>June 2, 2006</p>	
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;).  Unless otherwise 
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 (&quot;EPL&quot;).  A copy of the EPL is available 
+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is 
+being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
+apply to your use of any object code in the Content.  Check the Redistributor's license that was 
+provided with the Content.  If no such license exists, contact the Redistributor.  Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org">http://www.eclipse.org</a>.</p>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/build.properties b/bundles/org.eclipse.rap.ui.workbench/build.properties
new file mode 100644
index 0000000..ac93c39
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/build.properties
@@ -0,0 +1,10 @@
+source.. = src/

+bin.includes = META-INF/,\

+               plugin.xml,\

+               .api_description,\

+               .,\

+               plugin.properties,\

+               about.html,\

+               LegacyIDE.e4xmi,\

+               OSGI-INF/,\

+               .options

diff --git a/bundles/org.eclipse.rap.ui.workbench/plugin.properties b/bundles/org.eclipse.rap.ui.workbench/plugin.properties
new file mode 100644
index 0000000..11e0b9e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/plugin.properties
@@ -0,0 +1,22 @@
+###############################################################################
+# Copyright (c) 2000, 2014 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
+###############################################################################
+pluginName= Eclipse Workbench
+providerName= Eclipse.org
+
+command.name.exit = Exit
+command.name.showView = Show View
+command.name.save = Save
+command.name.saveAll = Save All
+bindingcontext.name.dialogAndWindows = In Dialog and Windows
+bindingcontext.name.windows = In Windows
+bindingcontext.name.bindingView = In Binding View
+bindingcontext.name.dialogs = In Dialogs
+Other.defined.by.css.label= Other defined by CSS
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/plugin.xml b/bundles/org.eclipse.rap.ui.workbench/plugin.xml
new file mode 100644
index 0000000..4ff32d9
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/plugin.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.0"?>
+<plugin>
+
+     <extension
+         point="org.eclipse.core.runtime.preferences">
+      <initializer
+            class="org.eclipse.ui.internal.WorkbenchPreferenceInitializer"/>
+   </extension>
+     <extension
+           id="id1"
+           point="org.eclipse.e4.workbench.model">
+        <processor
+              beforefragment="true"
+              class="org.eclipse.ui.internal.CommandToModelProcessor">
+        </processor>
+        <processor
+              beforefragment="true"
+              class="org.eclipse.ui.internal.ContextToModelProcessor">
+        </processor>
+         <processor
+              beforefragment="true"
+              class="org.eclipse.ui.internal.BindingToModelProcessor">
+        </processor>
+         <processor
+               beforefragment="true"
+               class="org.eclipse.ui.internal.ModelMigrationProcessor">
+         </processor>
+     </extension>   
+   <extension point="org.eclipse.ui.themes">
+      <themeElementCategory
+         id="org.eclipse.ui.themes.CssTheme"
+         label="%Other.defined.by.css.label"/>
+   </extension>
+</plugin>
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/e4/ui/workbench/addons/perspectiveswitcher/PerspectiveSwitcher.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/e4/ui/workbench/addons/perspectiveswitcher/PerspectiveSwitcher.java
new file mode 100644
index 0000000..e0a7834
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/e4/ui/workbench/addons/perspectiveswitcher/PerspectiveSwitcher.java
@@ -0,0 +1,971 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2016 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
+ *     Sopot Cela <sopotcela@gmail.com> - Bug 391961
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 440810, 485840, 474320, 497634
+ *     Andrey Loskutov <loskutov@gmx.de> - Bug 380233
+ *     Patrik Suzzi <psuzzi@gmail.com> - Bug 485829
+ ******************************************************************************/
+
+package org.eclipse.e4.ui.workbench.addons.perspectiveswitcher;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Collections;
+import java.util.List;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.NotEnabledException;
+import org.eclipse.core.commands.NotHandledException;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.e4.core.commands.ECommandService;
+import org.eclipse.e4.core.commands.EHandlerService;
+import org.eclipse.e4.core.di.annotations.Optional;
+import org.eclipse.e4.core.services.events.IEventBroker;
+import org.eclipse.e4.core.services.log.Logger;
+import org.eclipse.e4.ui.di.UIEventTopic;
+import org.eclipse.e4.ui.model.application.ui.MElementContainer;
+import org.eclipse.e4.ui.model.application.ui.MUIElement;
+import org.eclipse.e4.ui.model.application.ui.SideValue;
+import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective;
+import org.eclipse.e4.ui.model.application.ui.advanced.MPerspectiveStack;
+import org.eclipse.e4.ui.model.application.ui.basic.MTrimBar;
+import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolControl;
+import org.eclipse.e4.ui.workbench.UIEvents;
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.accessibility.AccessibleAdapter;
+import org.eclipse.swt.accessibility.AccessibleEvent;
+import org.eclipse.swt.events.MenuEvent;
+import org.eclipse.swt.events.MenuListener;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.IPerspectiveRegistry;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPreferenceConstants;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.internal.IPreferenceConstants;
+import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPage;
+import org.eclipse.ui.internal.e4.compatibility.E4Util;
+import org.eclipse.ui.internal.registry.PerspectiveRegistry;
+import org.eclipse.ui.internal.util.PrefUtil;
+import org.eclipse.ui.statushandlers.StatusManager;
+import org.osgi.service.event.Event;
+
+public class PerspectiveSwitcher {
+	/**
+	 *
+	 */
+	public static final String PERSPECTIVE_SWITCHER_ID = "org.eclipse.e4.ui.PerspectiveSwitcher"; //$NON-NLS-1$
+	@Inject
+	protected IEventBroker eventBroker;
+
+	@Inject
+	EModelService modelService;
+
+	@Inject
+	private EHandlerService handlerService;
+
+	@Inject
+	private ECommandService commandService;
+
+	@Inject
+	private MWindow window;
+
+	@Inject
+	private Logger logger;
+
+	private MToolControl perspSwitcherToolControl;
+	private ToolBar perspSwitcherToolbar;
+
+	private Composite comp;
+	private Image backgroundImage;
+	private Image perspectiveImage;
+
+	Color borderColor, curveColor;
+	Control toolParent;
+	IPropertyChangeListener propertyChangeListener;
+
+	@Inject
+	void handleChildrenEvent(@Optional @UIEventTopic(UIEvents.ElementContainer.TOPIC_CHILDREN) Event event) {
+
+		if (event == null)
+			return;
+
+		if (perspSwitcherToolbar.isDisposed()) {
+			return;
+		}
+
+		Object changedObj = event.getProperty(UIEvents.EventTags.ELEMENT);
+
+		if (perspSwitcherToolControl == null || !(changedObj instanceof MPerspectiveStack))
+			return;
+
+		MWindow perspWin = modelService.getTopLevelWindowFor((MUIElement) changedObj);
+		MWindow switcherWin = modelService.getTopLevelWindowFor(perspSwitcherToolControl);
+		if (perspWin != switcherWin)
+			return;
+
+		if (UIEvents.isADD(event)) {
+			for (Object o : UIEvents.asIterable(event, UIEvents.EventTags.NEW_VALUE)) {
+				MPerspective added = (MPerspective) o;
+				// Adding invisible elements is a NO-OP
+				if (!added.isToBeRendered())
+					continue;
+
+				addPerspectiveItem(added);
+			}
+		} else if (UIEvents.isREMOVE(event)) {
+			for (Object o : UIEvents.asIterable(event, UIEvents.EventTags.OLD_VALUE)) {
+				MPerspective removed = (MPerspective) o;
+				// Removing invisible elements is a NO-OP
+				if (!removed.isToBeRendered())
+					continue;
+
+				removePerspectiveItem(removed);
+			}
+		}
+
+	}
+
+	@Inject
+	void handleToBeRenderedEvent(@Optional @UIEventTopic(UIEvents.UIElement.TOPIC_TOBERENDERED) Event event) {
+		if (event == null)
+			return;
+
+		if (perspSwitcherToolbar.isDisposed()) {
+			return;
+		}
+
+		MUIElement changedElement = (MUIElement) event.getProperty(UIEvents.EventTags.ELEMENT);
+
+		if (perspSwitcherToolControl == null || !(changedElement instanceof MPerspective))
+			return;
+
+		MWindow perspWin = modelService.getTopLevelWindowFor(changedElement);
+		MWindow switcherWin = modelService.getTopLevelWindowFor(perspSwitcherToolControl);
+		if (perspWin != switcherWin)
+			return;
+
+		MPerspective persp = (MPerspective) changedElement;
+		if (!persp.getParent().isToBeRendered())
+			return;
+
+		if (changedElement.isToBeRendered()) {
+			addPerspectiveItem(persp);
+		} else {
+			removePerspectiveItem(persp);
+		}
+
+	}
+
+	@Inject
+	void handleLabelEvent(@Optional @UIEventTopic(UIEvents.UILabel.TOPIC_ALL) Event event) {
+		if (event == null)
+			return;
+		if (perspSwitcherToolbar.isDisposed()) {
+			return;
+		}
+
+		MUIElement changedElement = (MUIElement) event.getProperty(UIEvents.EventTags.ELEMENT);
+
+		if (perspSwitcherToolControl == null || !(changedElement instanceof MPerspective))
+			return;
+
+		String attName = (String) event.getProperty(UIEvents.EventTags.ATTNAME);
+		Object newValue = event.getProperty(UIEvents.EventTags.NEW_VALUE);
+
+		MWindow perspWin = modelService.getTopLevelWindowFor(changedElement);
+		MWindow switcherWin = modelService.getTopLevelWindowFor(perspSwitcherToolControl);
+		if (perspWin != switcherWin)
+			return;
+
+		MPerspective perspective = (MPerspective) changedElement;
+		if (!perspective.isToBeRendered())
+			return;
+
+		for (ToolItem ti : perspSwitcherToolbar.getItems()) {
+			if (ti.getData() == perspective) {
+				updateToolItem(ti, attName, newValue);
+			}
+		}
+
+		// update the size
+		fixSize();
+	}
+
+	@Inject
+	void handleSelectionEvent(@Optional @UIEventTopic(UIEvents.ElementContainer.TOPIC_SELECTEDELEMENT) Event event) {
+		if (event == null)
+			return;
+		if (perspSwitcherToolbar.isDisposed()) {
+			return;
+		}
+
+		MUIElement changedElement = (MUIElement) event.getProperty(UIEvents.EventTags.ELEMENT);
+
+		if (perspSwitcherToolControl == null || !(changedElement instanceof MPerspectiveStack))
+			return;
+
+		MWindow perspWin = modelService.getTopLevelWindowFor(changedElement);
+		MWindow switcherWin = modelService.getTopLevelWindowFor(perspSwitcherToolControl);
+		if (perspWin != switcherWin)
+			return;
+
+		MPerspectiveStack perspStack = (MPerspectiveStack) changedElement;
+		if (!perspStack.isToBeRendered())
+			return;
+
+		MPerspective selElement = perspStack.getSelectedElement();
+		for (ToolItem ti : perspSwitcherToolbar.getItems()) {
+			ti.setSelection(ti.getData() == selElement);
+		}
+	}
+
+	@PostConstruct
+	void init() {
+		setPropertyChangeListener();
+	}
+
+	@PreDestroy
+	void cleanUp() {
+		if (perspectiveImage != null) {
+			perspectiveImage.dispose();
+			perspectiveImage = null;
+		}
+
+		PrefUtil.getAPIPreferenceStore().removePropertyChangeListener(propertyChangeListener);
+	}
+
+	@PostConstruct
+	void createWidget(Composite parent, MToolControl toolControl) {
+		perspSwitcherToolControl = toolControl;
+		MUIElement meParent = perspSwitcherToolControl.getParent();
+		int orientation = SWT.HORIZONTAL;
+		if (meParent instanceof MTrimBar) {
+			MTrimBar bar = (MTrimBar) meParent;
+			if (bar.getSide() == SideValue.RIGHT || bar.getSide() == SideValue.LEFT)
+				orientation = SWT.VERTICAL;
+		}
+		comp = new Composite(parent, SWT.NONE);
+		RowLayout layout = new RowLayout(SWT.HORIZONTAL);
+		layout.marginLeft = layout.marginRight = 8;
+		layout.marginBottom = 4;
+		layout.marginTop = 6;
+		comp.setLayout(layout);
+		perspSwitcherToolbar = new ToolBar(comp, SWT.FLAT | SWT.WRAP | SWT.RIGHT + orientation);
+		comp.addListener(SWT.Paint, new Listener() {
+
+            @Override
+            public void handleEvent(org.eclipse.swt.widgets.Event e) {
+                paint(new PaintEvent(e));
+                
+            }
+        });
+		toolParent = ((Control) toolControl.getParent().getWidget());
+
+		comp.addDisposeListener(e -> dispose());
+
+		perspSwitcherToolbar.addMenuDetectListener(e -> {
+			ToolBar tb = (ToolBar) e.widget;
+			Point p = new Point(e.x, e.y);
+			p = perspSwitcherToolbar.getDisplay().map(null, perspSwitcherToolbar, p);
+			ToolItem item = tb.getItem(p);
+			if (item == null)
+				E4Util.message("  ToolBar menu"); //$NON-NLS-1$
+			else {
+				MPerspective persp = (MPerspective) item.getData();
+				if (persp == null)
+					E4Util.message("  Add button Menu"); //$NON-NLS-1$
+				else
+					openMenuFor(item, persp);
+			}
+		});
+
+		perspSwitcherToolbar.addDisposeListener(e -> disposeTBImages());
+
+		perspSwitcherToolbar.getAccessible().addAccessibleListener(new AccessibleAdapter() {
+			@Override
+			public void getName(AccessibleEvent e) {
+				if (0 <= e.childID && e.childID < perspSwitcherToolbar.getItemCount()) {
+					ToolItem item = perspSwitcherToolbar.getItem(e.childID);
+					if (item != null) {
+						e.result = item.getToolTipText();
+					}
+				}
+			}
+		});
+
+		hookupDnD(perspSwitcherToolbar);
+
+		boolean showOpenOnPerspectiveBar = PrefUtil.getAPIPreferenceStore()
+				.getBoolean(IWorkbenchPreferenceConstants.SHOW_OPEN_ON_PERSPECTIVE_BAR);
+		if (showOpenOnPerspectiveBar) {
+			final ToolItem openPerspectiveItem = new ToolItem(perspSwitcherToolbar, SWT.PUSH);
+			openPerspectiveItem.setImage(getOpenPerspectiveImage());
+			openPerspectiveItem.setToolTipText(WorkbenchMessages.get().OpenPerspectiveDialogAction_tooltip);
+			openPerspectiveItem.addSelectionListener(new SelectionListener() {
+				@Override
+				public void widgetSelected(SelectionEvent e) {
+					selectPerspective();
+				}
+
+				@Override
+				public void widgetDefaultSelected(SelectionEvent e) {
+					selectPerspective();
+				}
+			});
+			new ToolItem(perspSwitcherToolbar, SWT.SEPARATOR);
+		}
+
+		MPerspectiveStack stack = getPerspectiveStack();
+		if (stack != null) {
+			// Create an item for each perspective that should show up
+			for (MPerspective persp : stack.getChildren()) {
+				if (persp.isToBeRendered()) {
+					addPerspectiveItem(persp);
+				}
+			}
+		}
+	}
+
+	protected Point downPos = null;
+	protected ToolItem dragItem = null;
+	protected boolean dragging = false;
+	protected Shell dragShell = null;
+
+	private void track(MouseEvent e) {
+		// Create and track the feedback overlay
+		if (dragShell == null)
+			createFeedback();
+
+		// Move the drag shell
+		Rectangle b = dragItem.getBounds();
+		Point p = new Point(e.x, e.y);
+		p = dragShell.getDisplay().map(dragItem.getParent(), null, p);
+		dragShell.setLocation(p.x - (b.width / 2), p.y - (b.height / 2));
+
+		// Set the cursor feedback
+		ToolBar bar = (ToolBar) e.widget;
+		ToolItem curItem = bar.getItem(new Point(e.x, e.y));
+		if (curItem != null && curItem.getData() instanceof MPerspective) {
+			perspSwitcherToolbar.setCursor(perspSwitcherToolbar.getDisplay().getSystemCursor(SWT.CURSOR_HAND));
+		} else {
+			perspSwitcherToolbar.setCursor(perspSwitcherToolbar.getDisplay().getSystemCursor(SWT.CURSOR_NO));
+		}
+	}
+
+	private void createFeedback() {
+		dragShell = new Shell(SWT.NO_TRIM | SWT.NO_BACKGROUND);
+		dragShell.setAlpha(175);
+		ToolBar dragTB = new ToolBar(dragShell, SWT.RIGHT);
+		ToolItem newTI = new ToolItem(dragTB, SWT.RADIO);
+		newTI.setText(dragItem.getText());
+		newTI.setImage(dragItem.getImage());
+		dragTB.pack();
+		dragShell.pack();
+		dragShell.setVisible(true);
+	}
+
+	private void hookupDnD(ToolBar bar) {
+		bar.addMouseListener(new MouseListener() {
+			@Override
+			public void mouseUp(MouseEvent e) {
+				if (dragItem == null)
+					return;
+
+				ToolBar bar = (ToolBar) e.widget;
+				ToolItem curItem = bar.getItem(new Point(e.x, e.y));
+				if (curItem != null && curItem.getData() instanceof MPerspective) {
+					Rectangle bounds = curItem.getBounds();
+					Point center = new Point(bounds.x + (bounds.width / 2), bounds.y
+							+ (bounds.height / 2));
+					boolean atStart = (perspSwitcherToolbar.getStyle() & SWT.HORIZONTAL) != 0 ? e.x < center.x
+							: e.y < center.y;
+
+					// OK, Calculate the correct drop index
+					MPerspective dragPersp = (MPerspective) dragItem.getData();
+					int dragPerspIndex = dragPersp.getParent().getChildren().indexOf(dragPersp);
+					MPerspective dropPersp = (MPerspective) curItem.getData();
+					int dropPerspIndex = dropPersp.getParent().getChildren().indexOf(dropPersp);
+					if (!atStart)
+						dropPerspIndex++; // We're 'after' the item we're over
+
+					if (dropPerspIndex > dragPerspIndex)
+						dropPerspIndex--; // Need to account for the removal of
+											// the drag item itself
+
+					// If it's not a no-op move the perspective
+					if (dropPerspIndex != dragPerspIndex) {
+						MElementContainer<MUIElement> parent = dragPersp.getParent();
+						boolean selected = dragPersp == parent.getSelectedElement();
+						parent.getChildren().remove(dragPersp);
+						parent.getChildren().add(dropPerspIndex, dragPersp);
+						if (selected)
+							parent.setSelectedElement(dragPersp);
+					}
+				}
+
+				// Reset to the initial state
+				dragItem = null;
+				downPos = null;
+				dragging = false;
+				perspSwitcherToolbar.setCursor(null);
+				if (dragShell != null && !dragShell.isDisposed())
+					dragShell.dispose();
+				dragShell = null;
+			}
+
+			@Override
+			public void mouseDown(MouseEvent e) {
+				ToolBar bar = (ToolBar) e.widget;
+				downPos = new Point(e.x, e.y);
+				ToolItem downItem = bar.getItem(downPos);
+
+				// We're only interested if the button went down over a
+				// perspective item
+				if (downItem != null && downItem.getData() instanceof MPerspective)
+					dragItem = downItem;
+			}
+
+			@Override
+			public void mouseDoubleClick(MouseEvent e) {
+			}
+		});
+
+		bar.addDragDetectListener(e -> {
+			if (dragItem != null) {
+				dragging = true;
+				track(e);
+			}
+		});
+
+		// RAP
+//		bar.addMouseMoveListener(e -> {
+//			if (dragging) {
+//				track(e);
+//			}
+//		});
+	}
+
+	private Image getOpenPerspectiveImage() {
+		if (perspectiveImage == null || perspectiveImage.isDisposed()) {
+			ImageDescriptor desc = WorkbenchImages
+					.getImageDescriptor(IWorkbenchGraphicConstants.IMG_ETOOL_NEW_PAGE);
+			perspectiveImage = desc.createImage();
+		}
+		return perspectiveImage;
+	}
+
+	MPerspectiveStack getPerspectiveStack() {
+		List<MPerspectiveStack> psList = modelService.findElements(window, null,
+				MPerspectiveStack.class, null);
+		if (psList.size() > 0)
+			return psList.get(0);
+		return null;
+	}
+
+	private ToolItem addPerspectiveItem(MPerspective persp) {
+		int perspIndex = persp.getParent().getChildren().indexOf(persp);
+
+		int index = perspIndex + 2; // HACK !! accounts for the 'open' and the
+									// separator
+		final ToolItem psItem = index < perspSwitcherToolbar.getItemCount() ? new ToolItem(perspSwitcherToolbar, SWT.RADIO, index)
+				: new ToolItem(perspSwitcherToolbar, SWT.RADIO);
+		psItem.setData(persp);
+		IPerspectiveDescriptor descriptor = getDescriptorFor(persp.getElementId());
+		boolean foundImage = false;
+		if (descriptor != null) {
+			ImageDescriptor desc = descriptor.getImageDescriptor();
+			if (desc != null) {
+				final Image image = desc.createImage(false);
+				if (image != null) {
+					psItem.setImage(image);
+
+					psItem.addListener(SWT.Dispose, event -> {
+						Image currentImage = psItem.getImage();
+						if (currentImage != null)
+							currentImage.dispose();
+					});
+					foundImage = true;
+					psItem.setToolTipText(persp.getLocalizedLabel());
+				}
+			}
+		}
+		if (!foundImage
+				|| PrefUtil.getAPIPreferenceStore().getBoolean(
+						IWorkbenchPreferenceConstants.SHOW_TEXT_ON_PERSPECTIVE_BAR)) {
+			psItem.setText(persp.getLocalizedLabel());
+			psItem.setToolTipText(persp.getLocalizedTooltip());
+		}
+
+		psItem.setSelection(persp == persp.getParent().getSelectedElement());
+
+		psItem.addSelectionListener(new SelectionListener() {
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				MPerspective persp = (MPerspective) e.widget.getData();
+				persp.getParent().setSelectedElement(persp);
+			}
+
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {
+				MPerspective persp = (MPerspective) e.widget.getData();
+				persp.getParent().setSelectedElement(persp);
+			}
+		});
+
+		psItem.addListener(SWT.MenuDetect, event -> {
+			MPerspective persp1 = (MPerspective) event.widget.getData();
+			openMenuFor(psItem, persp1);
+		});
+
+		// update the size
+		fixSize();
+
+		return psItem;
+	}
+
+	// FIXME see https://bugs.eclipse.org/bugs/show_bug.cgi?id=385547
+	private IPerspectiveDescriptor getDescriptorFor(String id) {
+		IPerspectiveRegistry perspectiveRegistry = PlatformUI.getWorkbench()
+				.getPerspectiveRegistry();
+		if (perspectiveRegistry instanceof PerspectiveRegistry) {
+			return ((PerspectiveRegistry) perspectiveRegistry).findPerspectiveWithId(id, false);
+		}
+
+		return perspectiveRegistry.findPerspectiveWithId(id);
+	}
+
+	private void selectPerspective() {
+		// let the handler perform the work to consolidate all the code
+		ParameterizedCommand command = commandService.createCommand(
+				IWorkbenchCommandConstants.PERSPECTIVES_SHOW_PERSPECTIVE, Collections.EMPTY_MAP);
+		handlerService.executeHandler(command);
+	}
+
+	private void openMenuFor(ToolItem item, MPerspective persp) {
+		final Menu menu = new Menu(perspSwitcherToolbar);
+		menu.setData(persp);
+		if (persp.getParent().getSelectedElement() == persp) {
+			addCustomizeItem(menu);
+			addSaveAsItem(menu);
+			addResetItem(menu);
+		}
+
+		if (persp.isVisible()) {
+			addCloseItem(menu);
+		}
+
+		new MenuItem(menu, SWT.SEPARATOR);
+		// addDockOnSubMenu(menu);
+		addShowTextItem(menu);
+
+		Rectangle bounds = item.getBounds();
+		Point point = perspSwitcherToolbar.toDisplay(bounds.x, bounds.y + bounds.height);
+		menu.setLocation(point.x, point.y);
+		menu.setVisible(true);
+		menu.addMenuListener(new MenuListener() {
+
+			@Override
+			public void menuHidden(MenuEvent e) {
+				perspSwitcherToolbar.getDisplay().asyncExec(() -> menu.dispose());
+			}
+
+			@Override
+			public void menuShown(MenuEvent e) {
+				// Nothing to do
+			}
+
+		});
+	}
+
+	private void addCloseItem(final Menu menu) {
+		MenuItem menuItem = new MenuItem(menu, SWT.NONE);
+		menuItem.setText(WorkbenchMessages.get().WorkbenchWindow_close);
+		menuItem.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                MPerspective persp = (MPerspective) menu.getData();
+                if (persp != null)
+                    closePerspective(persp);
+            }
+        });
+	}
+
+	private void closePerspective(MPerspective persp) {
+		WorkbenchPage page = (WorkbenchPage) window.getContext().get(IWorkbenchPage.class);
+		String perspectiveId = persp.getElementId();
+		IPerspectiveDescriptor desc = getDescriptorFor(perspectiveId);
+		page.closePerspective(desc, perspectiveId, true, true);
+	}
+
+	private void addSaveAsItem(final Menu menu) {
+		final MenuItem saveAsMenuItem = new MenuItem(menu, SWT.Activate);
+		saveAsMenuItem.setText(WorkbenchMessages.get().PerspectiveBar_saveAs);
+		final IWorkbenchWindow workbenchWindow = window.getContext().get(IWorkbenchWindow.class);
+		workbenchWindow.getWorkbench().getHelpSystem().setHelp(saveAsMenuItem,
+				IWorkbenchHelpContextIds.SAVE_PERSPECTIVE_ACTION);
+		saveAsMenuItem.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent event) {
+    			if (perspSwitcherToolbar.isDisposed())
+    				return;
+    			IHandlerService handlerService = workbenchWindow.getService(IHandlerService.class);
+    			IStatus status = Status.OK_STATUS;
+    			try {
+    				handlerService.executeCommand(IWorkbenchCommandConstants.WINDOW_SAVE_PERSPECTIVE_AS, null);
+    			} catch (ExecutionException e) {
+    				status = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, e.getMessage(), e);
+    			} catch (NotDefinedException e) {
+    				status = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, e.getMessage(), e);
+    			} catch (NotEnabledException e) {
+    				status = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, e.getMessage(), e);
+    			} catch (NotHandledException e) {
+    			}
+    			if (!status.isOK())
+    				StatusManager.getManager().handle(status,
+    						StatusManager.SHOW | StatusManager.LOG);
+            }
+		});
+	}
+
+	private void addResetItem(final Menu menu) {
+		final MenuItem resetMenuItem = new MenuItem(menu, SWT.Activate);
+		resetMenuItem.setText(WorkbenchMessages.get().PerspectiveBar_reset);
+		final IWorkbenchWindow workbenchWindow = window.getContext().get(IWorkbenchWindow.class);
+		workbenchWindow.getWorkbench().getHelpSystem().setHelp(resetMenuItem,
+				IWorkbenchHelpContextIds.RESET_PERSPECTIVE_ACTION);
+		resetMenuItem.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent event) {
+    			if (perspSwitcherToolbar.isDisposed())
+    				return;
+    			IHandlerService handlerService = workbenchWindow.getService(IHandlerService.class);
+    			IStatus status = Status.OK_STATUS;
+    			try {
+    				handlerService.executeCommand(IWorkbenchCommandConstants.WINDOW_RESET_PERSPECTIVE, null);
+    			} catch (ExecutionException e) {
+    				status = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, e.getMessage(), e);
+    			} catch (NotDefinedException e) {
+    				status = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, e.getMessage(), e);
+    			} catch (NotEnabledException e) {
+    				status = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, e.getMessage(), e);
+    			} catch (NotHandledException e) {
+    			}
+    			if (!status.isOK())
+    				StatusManager.getManager().handle(status,
+    						StatusManager.SHOW | StatusManager.LOG);
+            }
+		});
+	}
+
+	private void addCustomizeItem(final Menu menu) {
+		final MenuItem customizeMenuItem = new MenuItem(menu, SWT.Activate);
+		customizeMenuItem.setText(WorkbenchMessages.get().PerspectiveBar_customize);
+		final IWorkbenchWindow workbenchWindow = window.getContext().get(IWorkbenchWindow.class);
+		customizeMenuItem.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent event) {
+    			if (perspSwitcherToolbar.isDisposed()) {
+    				return;
+    			}
+    			IHandlerService handlerService = workbenchWindow.getService(IHandlerService.class);
+    			IStatus status = Status.OK_STATUS;
+    			try {
+    				handlerService.executeCommand(IWorkbenchCommandConstants.WINDOW_CUSTOMIZE_PERSPECTIVE, null);
+    			} catch (ExecutionException e) {
+    				status = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, e.getMessage(), e);
+    			} catch (NotDefinedException e) {
+    				status = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, e.getMessage(), e);
+    			} catch (NotEnabledException e) {
+    				status = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, e.getMessage(), e);
+    			} catch (NotHandledException e) {
+    			}
+    			if (!status.isOK()) {
+    				StatusManager.getManager().handle(status, StatusManager.SHOW | StatusManager.LOG);
+    			}
+            }
+		});
+	}
+
+	private void addShowTextItem(final Menu menu) {
+		final MenuItem showtextMenuItem = new MenuItem(menu, SWT.CHECK);
+		showtextMenuItem.setText(WorkbenchMessages.get().PerspectiveBar_showText);
+		IPreferenceStore apiPreferenceStore = PrefUtil.getAPIPreferenceStore();
+		String showTextOnPerspectiveBarPreference = IWorkbenchPreferenceConstants.SHOW_TEXT_ON_PERSPECTIVE_BAR;
+		showtextMenuItem.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+    			boolean preference = showtextMenuItem.getSelection();
+    			if (preference != apiPreferenceStore.getDefaultBoolean(showTextOnPerspectiveBarPreference)) {
+    				PrefUtil.getInternalPreferenceStore().setValue(IPreferenceConstants.OVERRIDE_PRESENTATION, true);
+    			}
+    			apiPreferenceStore.setValue(showTextOnPerspectiveBarPreference, preference);
+    			changeShowText(preference);
+            }
+		});
+		showtextMenuItem.setSelection(apiPreferenceStore.getBoolean(showTextOnPerspectiveBarPreference));
+	}
+
+	private void setPropertyChangeListener() {
+		propertyChangeListener = propertyChangeEvent -> {
+			if (IWorkbenchPreferenceConstants.SHOW_TEXT_ON_PERSPECTIVE_BAR
+					.equals(propertyChangeEvent.getProperty())) {
+				Object newValue = propertyChangeEvent.getNewValue();
+				boolean showText = true; // default
+				if (newValue instanceof Boolean)
+					showText = ((Boolean) newValue).booleanValue();
+				else if ("false".equals(newValue)) //$NON-NLS-1$
+					showText = false;
+				changeShowText(showText);
+			}
+		};
+		PrefUtil.getAPIPreferenceStore().addPropertyChangeListener(propertyChangeListener);
+	}
+
+	private void changeShowText(boolean showText) {
+		ToolItem[] items = perspSwitcherToolbar.getItems();
+		for (ToolItem item : items) {
+			MPerspective persp = (MPerspective) item.getData();
+			if (persp != null)
+				if (showText) {
+					if (persp.getLabel() != null)
+						item.setText(persp.getLocalizedLabel());
+					item.setToolTipText(persp.getLocalizedTooltip());
+				} else {
+					Image image = item.getImage();
+					if (image != null) {
+						item.setText(""); //$NON-NLS-1$
+						item.setToolTipText(persp.getLocalizedLabel());
+					}
+				}
+		}
+
+		// update the size
+		fixSize();
+	}
+
+	private void fixSize() {
+		perspSwitcherToolbar.pack();
+		perspSwitcherToolbar.getParent().pack();
+		perspSwitcherToolbar.getShell().layout(new Control[] { perspSwitcherToolbar }, SWT.DEFER);
+	}
+
+	private void removePerspectiveItem(MPerspective toRemove) {
+		ToolItem psItem = getItemFor(toRemove);
+		if (psItem != null) {
+			psItem.dispose();
+		}
+
+		// update the size
+		fixSize();
+	}
+
+	protected ToolItem getItemFor(MPerspective persp) {
+		if (perspSwitcherToolbar == null)
+			return null;
+
+		for (ToolItem ti : perspSwitcherToolbar.getItems()) {
+			if (ti.getData() == persp)
+				return ti;
+		}
+
+		return null;
+	}
+
+	void paint(PaintEvent e) {
+		GC gc = e.gc;
+		Point size = comp.getSize();
+		if (curveColor == null || curveColor.isDisposed()) {
+			curveColor = e.display.getSystemColor(SWT.COLOR_GRAY);
+		}
+		int h = size.y;
+		int[] simpleCurve = new int[] { 0, h - 1, 1, h - 1, 2, h - 2, 2, 1, 3, 0 };
+		// draw border
+		gc.setForeground(curveColor);
+		gc.setAdvanced(true);
+		if (gc.getAdvanced()) {
+			gc.setAntialias(SWT.ON);
+		}
+		gc.drawPolyline(simpleCurve);
+
+		Rectangle bounds = ((Control) e.widget).getBounds();
+		bounds.x = bounds.y = 0;
+//      Region r = new Region();
+//      r.add(bounds);
+//      int[] simpleCurveClose = new int[simpleCurve.length + 4];
+//      System.arraycopy(simpleCurve, 0, simpleCurveClose, 0, simpleCurve.length);
+//      int index = simpleCurve.length;
+//      simpleCurveClose[index++] = bounds.width;
+//      simpleCurveClose[index++] = 0;
+//      simpleCurveClose[index++] = bounds.width;
+//      simpleCurveClose[index++] = bounds.height;
+//      r.subtract(simpleCurveClose);
+//      Region clipping = new Region();
+//      gc.getClipping(clipping);
+//      r.intersect(clipping);
+//      gc.setClipping(r);
+		Image b = toolParent.getBackgroundImage();
+		if (b != null && !b.isDisposed())
+			gc.drawImage(b, 0, 0);
+
+//      r.dispose();
+//      clipping.dispose();
+	}
+
+	// RAP
+//  void resize() {
+//      Point size = comp.getSize();
+//      Image oldBackgroundImage = backgroundImage;
+//      backgroundImage = new Image(comp.getDisplay(), size.x, size.y);
+//      GC gc = new GC(backgroundImage);
+//      comp.getParent().drawBackground(gc, 0, 0, size.x, size.y, 0, 0);
+//      Color background = comp.getBackground();
+//      Color border = comp.getDisplay().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW);
+//      RGB backgroundRGB = background.getRGB();
+//      // TODO naive and hard coded, doesn't deal with high contrast, etc.
+//      Color gradientTop = new Color(comp.getDisplay(), backgroundRGB.red + 12,
+//              backgroundRGB.green + 10, backgroundRGB.blue + 10);
+//      int h = size.y;
+//      int curveStart = 0;
+//      int curve_width = 5;
+//
+//      int[] curve = new int[] { 0, h, 1, h, 2, h - 1, 3, h - 2, 3, 2, 4, 1, 5, 0, };
+//      int[] line1 = new int[curve.length + 4];
+//      int index = 0;
+//      int x = curveStart;
+//      line1[index++] = x + 1;
+//      line1[index++] = h;
+//      for (int i = 0; i < curve.length / 2; i++) {
+//          line1[index++] = x + curve[2 * i];
+//          line1[index++] = curve[2 * i + 1];
+//      }
+//      line1[index++] = x + curve_width;
+//      line1[index++] = 0;
+//
+//      int[] line2 = new int[line1.length];
+//      index = 0;
+//      for (int i = 0; i < line1.length / 2; i++) {
+//          line2[index] = line1[index++] - 1;
+//          line2[index] = line1[index++];
+//      }
+//
+//      // custom gradient
+//      gc.setForeground(gradientTop);
+//      gc.setBackground(background);
+//      gc.drawLine(4, 0, size.x, 0);
+//      gc.drawLine(3, 1, size.x, 1);
+//      gc.fillGradientRectangle(2, 2, size.x - 2, size.y - 3, true);
+//      gc.setForeground(background);
+//      gc.drawLine(2, size.y - 1, size.x, size.y - 1);
+//      gradientTop.dispose();
+//
+//      gc.setForeground(border);
+//      gc.drawPolyline(line2);
+//      gc.dispose();
+//      comp.setBackgroundImage(backgroundImage);
+//      if (oldBackgroundImage != null)
+//          oldBackgroundImage.dispose();
+//
+//  }
+
+	void dispose() {
+		cleanUp();
+
+		if (backgroundImage != null) {
+			comp.setBackgroundImage(null);
+			backgroundImage.dispose();
+			backgroundImage = null;
+		}
+	}
+
+	void disposeTBImages() {
+		ToolItem[] items = perspSwitcherToolbar.getItems();
+		for (ToolItem item : items) {
+			Image image = item.getImage();
+			if (image != null) {
+				item.setImage(null);
+				image.dispose();
+			}
+		}
+	}
+
+	public void setKeylineColor(Color borderColor, Color curveColor) {
+		this.borderColor = borderColor;
+		this.curveColor = curveColor;
+	}
+
+	private void updateToolItem(ToolItem ti, String attName, Object newValue) {
+		boolean showText = PrefUtil.getAPIPreferenceStore()
+				.getBoolean(IWorkbenchPreferenceConstants.SHOW_TEXT_ON_PERSPECTIVE_BAR);
+		if (showText && UIEvents.UILabel.LABEL.equals(attName)) {
+			String newName = (String) newValue;
+			ti.setText(newName);
+		} else if (UIEvents.UILabel.TOOLTIP.equals(attName)) {
+			String newTTip = (String) newValue;
+			ti.setToolTipText(newTTip);
+		} else if (UIEvents.UILabel.ICONURI.equals(attName)) {
+			Image currentImage = ti.getImage();
+			String uri = (String) newValue;
+			URL url = null;
+			try {
+				url = new URL(uri);
+				ImageDescriptor descriptor = ImageDescriptor.createFromURL(url);
+				if (descriptor == null) {
+					ti.setImage(null);
+				} else
+					ti.setImage(descriptor.createImage());
+			} catch (IOException e) {
+				ti.setImage(null);
+				logger.warn(e);
+			} finally {
+				if (currentImage != null)
+					currentImage.dispose();
+			}
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/SessionLocaleProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/SessionLocaleProvider.java
new file mode 100644
index 0000000..d5c8011
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/SessionLocaleProvider.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2015 EclipseSource 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:
+ *    EclipseSource - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.rap.ui.internal;
+
+import java.util.Locale;
+
+import org.eclipse.osgi.service.localization.LocaleProvider;
+import org.eclipse.rap.rwt.internal.service.ContextProvider;
+import org.eclipse.rap.rwt.service.UISession;
+
+
+public final class SessionLocaleProvider implements LocaleProvider {
+
+  @Override
+  public Locale getLocale() {
+    if( ContextProvider.hasContext() ) {
+      UISession uiSession = ContextProvider.getUISession();
+      if( uiSession != null ) {
+        return uiSession.getLocale();
+      }
+    }
+    return Locale.getDefault();
+  }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/application/EntryPointApplicationWrapper.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/application/EntryPointApplicationWrapper.java
new file mode 100644
index 0000000..510a1d5
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/application/EntryPointApplicationWrapper.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 EclipseSource and others.
+ * All rights reserved. This program and the accompanying material
+ * 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:
+ *    EclipseSource - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.rap.ui.internal.application;
+
+import org.eclipse.equinox.app.IApplication;
+import org.eclipse.equinox.app.IApplicationContext;
+import org.eclipse.rap.rwt.application.EntryPoint;
+
+
+public final class EntryPointApplicationWrapper implements EntryPoint {
+
+  private static final IApplicationContext context = new RAPApplicationContext();
+
+  private final Class<? extends IApplication> applicationClass;
+
+  public EntryPointApplicationWrapper( Class<? extends IApplication> applicationClass ) {
+    this.applicationClass = applicationClass;
+  }
+
+  /*
+   * Note [rst]: We don't call IApplication#stop(). According to the documentation, stop() is "only
+   * called to force an application to exit" and "not called if an application exits normally from
+   * start()".
+   * See also https://bugs.eclipse.org/bugs/show_bug.cgi?id=372946
+   */
+  public int createUI() {
+    int result = 0;
+    IApplication application = createApplication();
+    try {
+      Object exitCode = application.start( context );
+      if( exitCode instanceof Integer ) {
+        result = ( ( Integer )exitCode ).intValue();
+      }
+    } catch( Exception exception  ) {
+      String message = "Exception while executing application " + applicationClass.getName();
+      throw new RuntimeException( message, exception );
+    }
+    return result;
+  }
+
+  private IApplication createApplication() {
+    IApplication application;
+    try {
+      application = applicationClass.newInstance();
+    } catch( Exception exception ) {
+      String message = "Failed to create application " + applicationClass.getName();
+      throw new IllegalArgumentException( message, exception );
+    }
+    return application;
+  }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/application/RAPApplicationContext.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/application/RAPApplicationContext.java
new file mode 100644
index 0000000..fddea61
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/application/RAPApplicationContext.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2010 EclipseSource 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:
+ *   EclipseSource - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.rap.ui.internal.application;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.equinox.app.IApplication;
+import org.eclipse.equinox.app.IApplicationContext;
+import org.osgi.framework.Bundle;
+
+/*
+ * Fake context for IApplications
+ */
+final class RAPApplicationContext implements IApplicationContext {
+
+  private final Map arguments;
+  
+  public RAPApplicationContext() {
+    arguments = new HashMap( 2 );
+    arguments.put( IApplicationContext.APPLICATION_ARGS,
+                   Platform.getApplicationArgs() );
+  }
+  
+  public void applicationRunning() {
+    // do nothing
+  }
+
+  public Map getArguments() {
+    return arguments;
+  }
+
+  public String getBrandingApplication() {
+    return null;
+  }
+
+  public Bundle getBrandingBundle() {
+    return null;
+  }
+
+  public String getBrandingDescription() {
+    return null;
+  }
+
+  public String getBrandingId() {
+    return null;
+  }
+
+  public String getBrandingName() {
+    return null;
+  }
+
+  public String getBrandingProperty( final String key ) {
+    return null;
+  }
+  
+  public void setResult( final Object result, final IApplication application ) {
+    // do nothing
+  }
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/branding/AbstractBranding.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/branding/AbstractBranding.java
new file mode 100644
index 0000000..997d6c2
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/branding/AbstractBranding.java
@@ -0,0 +1,165 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2012 Innoopract Informationssysteme GmbH 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:
+ *    Innoopract Informationssysteme GmbH - initial API and implementation
+ *    EclipseSource - ongoing development
+ ******************************************************************************/
+package org.eclipse.rap.ui.internal.branding;
+
+import java.io.IOException;
+
+
+/**
+ * This abstract class is intended to be implemented by clients that want
+ * to have control over various aspects of the web application such as
+ * <ul>
+ * <li>the servlet name at which the application can be accessed,</li>
+ * <li>the default entry point and the list of entry points that may
+ * be accessed</li>
+ * <li>appearance of the startup page (favorites icon, markup of the page
+ * body, etc.),</li>
+ * <li>the theme to be used</li>
+ * </ul>
+ * It serves as a callback that answers requests to the above outlined
+ * aspects via its getter methods.
+ *
+ * <p><strong>Note:</strong> Instances of this class are expected to be
+ * immutable. All getter methods should return the same values whenever
+ * they are called.</p>
+ *
+ * @since 2.0
+ */
+public abstract class AbstractBranding {
+
+  /**
+   * Returns the name of the servlet on which the application should be
+   * available. Defining this attribute will cause your application to
+   * be available at
+   * <code>http://&lt;host&gt;:&lt;port&gt;/&lt;servletName&gt;</code>.
+   * <p>The default behavior is to return <code>null</code>.</p>
+   *
+   * @return the servlet name, must not return <code>null</code>
+   */
+  public String getServletName() {
+    return null;
+  }
+
+  /**
+   * Returns the default entry point. Returning <code>null</code> or an
+   * empty string indicates that there is no default entry point.
+   * A URL like <code>http://&lt;host&gt;:&lt;port&gt;/&lt;servletName&gt;
+   * </code> would automatically execute the entry point returned here.
+   * <p>The default behavior is to return <code>null</code>.</p>
+   *
+   * @return the default entry point or <code>null</code>
+   */
+  public String getDefaultEntryPoint() {
+    return null;
+  }
+
+  /**
+   * Returns an array of entry points which are allowed to be the started with
+   * this branding (or servlet name). If <code>null</code> or an empty array
+   * is returned, every entrypoint is allowed to be started.
+   * <p>The default behavior is to return <code>null</code>.</p>
+   *
+   * @return an array of string, denoting the allowed entry points or
+   * <code>null</code>
+   */
+  public String[] getEntryPoints() {
+    return null;
+  }
+
+  /**
+   * Returns the id of the theme to be used with this branding or
+   * <code>null</code> to indicate that the default theme should be used.
+   * <p>The default behavior is to return <code>null</code>.</p>
+   *
+   * @return the theme id or <code>null</code>
+   */
+  public String getThemeId() {
+    return null;
+  }
+
+  /**
+   * Returns the id of this branding extension.
+   * <p>The default behavior is to return <code>null</code>.</p>
+   *
+   * @return the branding extension's id or <code>null</code>.
+   * @since 1.1
+   */
+  public String getId() {
+    return null;
+  }
+
+  /**
+   * Returns the resource name for the favorites icon or <code>null</code> to
+   * indicate that no favorites icon is available.
+   * <p><strong>Note:</strong> if a fav icon is provided, the application code
+   * must register the resource at the <code>ResourceManager</code>.
+   * Preferrably, this should be done in the <code>registerResources</code>
+   * callback method.</p>
+   * <p>The default behavior is to return <code>null</code>.</p>
+   *
+   * @return the favorites icon or <code>null</code>
+   * @see org.eclipse.rap.rwt.service.ResourceManager
+   * @see #registerResources()
+   */
+  public String getFavIcon() {
+    return null;
+  }
+
+  /**
+   * Returns the title that will be displayed in the browser window or
+   * <code>null</code> to indicate that no title should be displayed.
+   * <p>The default behavior is to return <code>null</code>.</p>
+   *
+   * @return the title or <code>null</code>
+   */
+  public String getTitle() {
+    return null;
+  }
+
+  /**
+   * Returns an array of HTML header tags or null if no additional headers
+   * are provided.
+   * <p>The default behavior is to return <code>null</code>.</p>
+   *
+   * @return an array of <code>Header</code> instances or <code>null</code>
+   * @see Header
+   */
+  public Header[] getHeaders() {
+    return null;
+  }
+
+  /**
+   * Returns HTML code to be placed inside the <code>&lt;body&gt;</code> tag or
+   * <code>null</code> if no custom HTML code should be placed inside the
+   * </code>&lt;body&gt;</code> tag.
+   * <p>Be aware that the HTML code returned by this method is taken as-is
+   * and may break the surrounding HTML page.</p>
+   * <p>The default behavior is to return <code>null</code>.</p>
+   *
+   * @return body HTML code or <code>null</code>
+   */
+  public String getBody() {
+    return null;
+  }
+
+  /**
+   * This method is called before the branding is applied for the first time.
+   * Clients may use this to register resources used by the branding such as
+   * the {@link #getFavIcon() <code>favIcon</code>}.
+   * <p>The default behavior is to do nothing.</p>
+   *
+   * @throws IOException if an I/O error occurs
+   */
+  public void registerResources() throws IOException {
+    // do nothing
+  }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/branding/Branding.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/branding/Branding.java
new file mode 100644
index 0000000..4908532
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/branding/Branding.java
@@ -0,0 +1,128 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2012 Innoopract Informationssysteme GmbH.
+ * 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:
+ *    Innoopract Informationssysteme GmbH - initial API and implementation
+ *    EclipseSource - ongoing development
+ ******************************************************************************/
+package org.eclipse.rap.ui.internal.branding;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.rap.rwt.RWT;
+import org.osgi.framework.Bundle;
+
+
+public final class Branding extends AbstractBranding {
+
+  private static final Header[] EMPTY_HEADERS = new Header[ 0 ];
+
+  private final String contributor;
+  private String title;
+  private String favIcon;
+  private List<Header> headers;
+  private String body;
+  private String themeId;
+  private String brandingId;
+
+  public Branding( final String contributor ) {
+    this.contributor = contributor;
+  }
+
+  /////////////////
+  // Setter methods
+
+  public void setTitle( final String title ) {
+    this.title = title;
+  }
+
+  public void setFavIcon( final String favIcon ) {
+    this.favIcon = favIcon;
+  }
+
+  public void setBody( final String body ) {
+    this.body = body;
+  }
+
+  public void addHeader( final String tagName, final Map<String, String> attributes ) {
+    if( headers == null ) {
+      headers = new ArrayList<Header>();
+    }
+    Header header = new Header( tagName, attributes );
+    headers.add( header );
+  }
+
+  public void setThemeId( final String themeId ) {
+    this.themeId = themeId;
+  }
+
+  void setId( final String brandingId ) {
+    this.brandingId = brandingId;
+  }
+
+  ///////////////////////////
+  // AbstractBranding implementation
+
+  public String getTitle() {
+    return title;
+  }
+
+  @Override
+  public String getFavIcon() {
+    return favIcon;
+  }
+
+  @Override
+  public Header[] getHeaders() {
+    Header[] result;
+    if( headers == null ) {
+      result = EMPTY_HEADERS;
+    } else {
+      result = new Header[ headers.size() ];
+      headers.toArray( result );
+    }
+    return result;
+  }
+
+  @Override
+  public String getBody() {
+    return body;
+  }
+
+  @Override
+  public String getThemeId() {
+    return themeId;
+  }
+
+  @Override
+  public String getId() {
+    return brandingId;
+  }
+
+  @Override
+  public void registerResources() throws IOException {
+    if( favIcon != null && !"".equals( favIcon ) ) {
+      Bundle bundle = Platform.getBundle( contributor );
+      Path file = new Path( favIcon );
+      InputStream stream = FileLocator.openStream( bundle, file, false );
+      if( stream != null ) {
+        try {
+          RWT.getResourceManager().register( favIcon, stream );
+        } finally {
+          stream.close();
+        }
+      }
+    }
+  }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/branding/BrandingExtension.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/branding/BrandingExtension.java
new file mode 100644
index 0000000..5608887
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/branding/BrandingExtension.java
@@ -0,0 +1,194 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2012 Innoopract Informationssysteme GmbH 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:
+ *    Innoopract Informationssysteme GmbH - initial API and implementation
+ *    EclipseSource - ongoing development
+ ******************************************************************************/
+package org.eclipse.rap.ui.internal.branding;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.rap.rwt.application.Application;
+import org.eclipse.rap.rwt.service.ResourceLoader;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.http.HttpService;
+
+
+public final class BrandingExtension {
+
+  private static final String EP_BRANDING = "org.eclipse.rap.ui.branding"; //$NON-NLS-1$
+  private static final String ATT_ID = "id"; //$NON-NLS-1$
+  private static final String ATT_THEME_ID = "themeId"; //$NON-NLS-1$
+  private static final String ATT_FAVICON = "favicon"; //$NON-NLS-1$
+  private static final String ATT_TITLE = "title"; //$NON-NLS-1$
+  private static final String ATT_BODY = "body"; //$NON-NLS-1$
+  private static final String ELEM_ADITIONAL_HEADERS = "additionalHeaders"; //$NON-NLS-1$
+  private static final String TAG_META = "meta"; //$NON-NLS-1$
+  private static final String TAG_LINK = "link"; //$NON-NLS-1$
+  private static final String ELEM_ATTRIBUTE = "attribute"; //$NON-NLS-1$
+  private static final String ATT_NAME = "name"; //$NON-NLS-1$
+  private static final String ATT_CONTENT = "content"; //$NON-NLS-1$
+  private static final String ATT_REL = "rel"; //$NON-NLS-1$
+  private static final String ATT_HREF = "href"; //$NON-NLS-1$
+  private static final String ATT_VALUE = "value"; //$NON-NLS-1$
+  private static final String ELEM_SERVICE_SELECTOR = "httpServiceFilter"; //$NON-NLS-1$
+  private static final String ATT_CLASS = "class"; //$NON-NLS-1$
+
+  private final Application application;
+  private final ServiceReference<HttpService> httpServiceReference;
+
+  public BrandingExtension( Application configuration,
+                            ServiceReference<HttpService> httpServiceReference )
+  {
+    this.application = configuration;
+    this.httpServiceReference = httpServiceReference;
+  }
+
+  public void read() throws IOException {
+    IExtensionRegistry registry = Platform.getExtensionRegistry();
+    IExtensionPoint ep = registry.getExtensionPoint( EP_BRANDING );
+    IConfigurationElement[] brandings = ep.getConfigurationElements();
+    for( int i = 0; i < brandings.length; i++ ) {
+      IConfigurationElement configElement = brandings[ i ];
+      readBranding( configElement );
+    }
+  }
+
+  //////////////////
+  // Helping methods
+
+  private void readBranding( IConfigurationElement element ) throws IOException {
+    String contributor = element.getContributor().getName();
+    String id = element.getAttribute( ATT_ID );
+    String body = element.getAttribute( ATT_BODY );
+    String title = element.getAttribute( ATT_TITLE );
+    String favIcon = element.getAttribute( ATT_FAVICON );
+    String themeId = element.getAttribute( ATT_THEME_ID );
+    Branding branding = new Branding( contributor );
+    branding.setId( id );
+    branding.setBody( readBody( contributor, body ) );
+    branding.setTitle( title );
+    branding.setThemeId( themeId );
+    branding.setFavIcon( favIcon );
+    // loop through all additional headers
+    IConfigurationElement[] additionalHeaders = element.getChildren( ELEM_ADITIONAL_HEADERS );
+    if( additionalHeaders.length > 0 ) {
+      IConfigurationElement additionalHeader = additionalHeaders[ 0 ];
+      readAdditionalHeader( branding, additionalHeader );
+    }
+    if( !isFiltered( element ) ) {
+      register( branding );
+      registerFavIcon( element, favIcon );
+    }
+  }
+
+  private boolean isFiltered( IConfigurationElement element ) {
+    boolean result = false;
+    if( httpServiceReference != null ) {
+      Filter serviceFilter = readServiceFilter( element );
+      result = serviceFilter != null && !serviceFilter.match( httpServiceReference );
+    }
+    return result;
+  }
+
+  // EXPERIMENTAL, see bug 241210
+  private Filter readServiceFilter( IConfigurationElement element ) {
+    Filter result = null;
+    IConfigurationElement[] serviceFilterElements = element.getChildren( ELEM_SERVICE_SELECTOR );
+    if( serviceFilterElements.length > 0 ) {
+      IConfigurationElement serviceFilterElement = serviceFilterElements[ 0 ];
+      String filterClass = serviceFilterElement.getAttribute( ATT_CLASS );
+      if( filterClass != null ) {
+        try {
+          result = ( Filter )serviceFilterElement.createExecutableExtension( ATT_CLASS );
+        } catch( CoreException exception ) {
+          String message = "Could not instantiate http service filter for branding: "
+                         + filterClass;
+          throw new IllegalArgumentException( message, exception );
+        }
+      }
+    }
+    return result;
+  }
+
+  private void register( AbstractBranding branding ) {
+    BrandingManager.getInstance().register( branding );
+  }
+
+  private void registerFavIcon( IConfigurationElement element, final String favIcon ) {
+    if( favIcon != null ) {
+      final Bundle bundle = Platform.getBundle( element.getContributor().getName() );
+      application.addResource( favIcon, new ResourceLoader() {
+        public InputStream getResourceAsStream( String resourceName ) throws IOException {
+          return FileLocator.openStream( bundle, new Path( favIcon ), false );
+        }
+      } );
+    }
+  }
+
+  private void readAdditionalHeader( Branding branding, IConfigurationElement elem ) {
+    IConfigurationElement[] headers = elem.getChildren();
+    for( int i = 0; i < headers.length; i++ ) {
+      IConfigurationElement header = headers[ i ];
+      Map<String, String> attributes = new HashMap<String, String>();
+      // add predefined attributes
+      String tagName = header.getName();
+      if( TAG_META.equals( tagName ) ) {
+        attributes.put( ATT_NAME, header.getAttribute( ATT_NAME ) );
+        attributes.put( ATT_CONTENT, header.getAttribute( ATT_CONTENT ) );
+      } else if( TAG_LINK.equals( tagName ) ) {
+        attributes.put( ATT_REL, header.getAttribute( ATT_REL ) );
+        attributes.put( ATT_HREF, header.getAttribute( ATT_HREF ) );
+      }
+      // add additional attributes
+      IConfigurationElement[] addAttrs = header.getChildren( ELEM_ATTRIBUTE );
+      for( int k = 0; k < addAttrs.length; k++ ) {
+        String name = addAttrs[ k ].getAttribute( ATT_NAME );
+        String value = addAttrs[ k ].getAttribute( ATT_VALUE );
+        attributes.put( name, value );
+      }
+      branding.addHeader( tagName, attributes );
+    }
+  }
+
+  private String readBody( String contributor, String path ) throws IOException {
+    String result = null;
+    if( path != null ) {
+      URL url = Platform.getBundle( contributor ).getResource( path );
+      InputStream inputStream = url.openStream();
+      if( inputStream != null ) {
+        try {
+          StringBuffer buffer = new StringBuffer();
+          byte[] bytes = new byte[ 512 ];
+          int bytesRead = inputStream.read( bytes );
+          while( bytesRead != -1 ) {
+            buffer.append( new String( bytes, 0, bytesRead ) );
+            bytesRead = inputStream.read( bytes );
+          }
+          result = buffer.toString();
+        } finally {
+          inputStream.close();
+        }
+      }
+    }
+    return result;
+  }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/branding/BrandingManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/branding/BrandingManager.java
new file mode 100644
index 0000000..f48891f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/branding/BrandingManager.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2012 Innoopract Informationssysteme GmbH 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:
+ *    Innoopract Informationssysteme GmbH - initial API and implementation
+ *    Frank Appel - replaced singletons and static fields (Bug 337787)
+ *    EclipseSource - ongoing development
+ ******************************************************************************/
+package org.eclipse.rap.ui.internal.branding;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.eclipse.rap.rwt.internal.util.ParamCheck;
+
+
+public class BrandingManager {
+  private static BrandingManager instance;
+
+  public static synchronized BrandingManager getInstance() {
+    if( instance == null ) {
+      instance = new BrandingManager();
+    }
+    return instance;
+  }
+  
+  private final List<AbstractBranding> brandings;
+  
+  public BrandingManager() {
+    brandings = new LinkedList<AbstractBranding>();
+  }
+
+  public void register( AbstractBranding branding ) {
+    ParamCheck.notNull( branding, "branding" );
+    synchronized( brandings ) {
+      brandings.add( branding );
+    }
+  }
+  
+  public void deregister( AbstractBranding branding ) {
+    ParamCheck.notNull( branding, "branding" );
+    synchronized( brandings ) {
+      brandings.remove( branding );
+    }
+  }
+  
+  public void deregisterAll() {
+    synchronized( brandings ) {
+      brandings.clear();
+    }
+  }
+  
+  public AbstractBranding[] getAll() {
+    synchronized( brandings ) {
+      return brandings.toArray( new AbstractBranding[ brandings.size() ] );
+    }
+  }
+
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/branding/BrandingUtil.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/branding/BrandingUtil.java
new file mode 100644
index 0000000..4385848
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/branding/BrandingUtil.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 Innoopract Informationssysteme GmbH 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:
+ *    Innoopract Informationssysteme GmbH - initial API and implementation
+ *    EclipseSource - ongoing development
+ ******************************************************************************/
+package org.eclipse.rap.ui.internal.branding;
+
+import static org.eclipse.rap.rwt.internal.service.ContextProvider.getApplicationContext;
+
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.eclipse.rap.rwt.internal.lifecycle.EntryPointManager;
+import org.eclipse.rap.rwt.internal.lifecycle.EntryPointRegistration;
+import org.eclipse.rap.rwt.internal.service.ContextProvider;
+
+
+public final class BrandingUtil {
+
+  public static final String ENTRY_POINT_BRANDING = "org.eclipse.rap.ui.branding";
+
+  public static String getCurrentBrandingId() {
+    EntryPointManager entryPointManager = getApplicationContext().getEntryPointManager();
+    HttpServletRequest request = ContextProvider.getRequest();
+    EntryPointRegistration registration = entryPointManager.getEntryPointRegistration( request );
+    Map<String, String> properties = registration.getProperties();
+    return properties.get( BrandingUtil.ENTRY_POINT_BRANDING );
+  }
+
+  public static String headerMarkup( AbstractBranding branding ) {
+    StringBuilder buffer = new StringBuilder();
+    appendHeaderMarkup( buffer, branding );
+    return buffer.toString();
+  }
+
+  private static void appendHeaderMarkup( StringBuilder buffer, AbstractBranding branding ) {
+    Header[] headers = branding.getHeaders();
+    if( headers != null ) {
+      buffer.append( createMarkupForHeaders( headers ) );
+    }
+  }
+
+  private static String createMarkupForHeaders( Header... headers ) {
+    StringBuilder buffer = new StringBuilder();
+    for( Header header : headers ) {
+      appendHeaderMarkup( buffer, header );
+    }
+    return buffer.toString();
+  }
+
+  private static String appendHeaderMarkup( StringBuilder buffer, Header header ) {
+    buffer.append( "<" );
+    buffer.append( header.getTagName() );
+    buffer.append( " " );
+    String[] names = header.getNames();
+    String[] values = header.getValues();
+    for( int i = 0; i < names.length; i++ ) {
+      String name = names[ i ];
+      String value = values[ i ];
+      if( name != null && value != null ) {
+        buffer.append( name );
+        buffer.append( "=\"" );
+        buffer.append( value );
+        buffer.append( "\" " );
+      }
+    }
+    buffer.append( "/>\n" );
+    return buffer.toString();
+  }
+
+  private BrandingUtil() {
+    // prevent instantiation
+  }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/branding/Header.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/branding/Header.java
new file mode 100644
index 0000000..32d615e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/branding/Header.java
@@ -0,0 +1,138 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2012 Innoopract Informationssysteme GmbH 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:
+ *    Innoopract Informationssysteme GmbH - initial API and implementation
+ *    EclipseSource - ongoing development
+ ******************************************************************************/
+package org.eclipse.rap.ui.internal.branding;
+
+import java.util.Map;
+
+import org.eclipse.rap.rwt.internal.util.ParamCheck;
+
+
+/**
+ * This data structure represents an HTML tag that goes into the &lt;head&gt;
+ * section of the startup page and is used by the branding facility.
+ *
+ * @see AbstractBranding
+ * @since 2.0
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public final class Header {
+
+  private static final String[] EMPTY_STRINGS = new String[ 0 ];
+
+  private final String tagName;
+  private final String[] names;
+  private final String[] values;
+
+  /**
+   * Constructs a new instance of this class with the given
+   * <code>tagName</code>.
+   *
+   * @param tagName the name of the tag, must either be <code>meta</code> or
+   *          <code>link</code>
+   * @param attributes the attributes for this tag or <code>null</code> if
+   *          there are no attributes.
+   * @throws IllegalArgumentException if <code>tagName</code> isn't either
+   *           <code>meta</code> or <code>link</code>.
+   */
+  public Header( String tagName, Map<String, String> attributes ) {
+    checkTagName( tagName );
+    this.tagName = tagName;
+    if( attributes == null ) {
+      names = EMPTY_STRINGS;
+      values = EMPTY_STRINGS;
+    } else {
+      int size = attributes.size();
+      names = new String[ size ];
+      attributes.keySet().toArray( names );
+      values = new String[ size ];
+      attributes.values().toArray( values );
+    }
+  }
+
+  /**
+   * Constructs a new instance of this class with the given
+   * <code>tagName</code>.
+   *
+   * @param tagName the name of the tag, must either be <code>meta</code> or
+   *          <code>link</code>
+   * @param attributeNames the attribute names for this tag. Must not be
+   *          <code>null</code>.
+   * @param attributeValues the attribute values for this tag. Must match the
+   *          attribute names given in argument <code>attributeNames</code>
+   * @throws IllegalArgumentException if <code>tagName</code> isn't either
+   *           <code>meta</code> or <code>link</code>.
+   */
+  public Header( String tagName, String[] attributeNames, String[] attributeValues ) {
+    checkTagName( tagName );
+    ParamCheck.notNull( attributeNames, "attributeNames" );
+    ParamCheck.notNull( attributeValues, "attributeValues" );
+    if( attributeNames.length != attributeValues.length ) {
+      String msg
+        = "The arguments 'attributeNames' and 'attributeValues' must have "
+        + "the same length.";
+      throw new IllegalArgumentException( msg );
+    }
+    this.tagName = tagName;
+    names = new String[ attributeNames.length ];
+    System.arraycopy( attributeNames, 0, names, 0, attributeNames.length );
+    values = new String[ attributeValues.length ];
+    System.arraycopy( attributeValues, 0, values, 0, attributeValues.length );
+  }
+
+  /**
+   * Returns the name of the header tag.
+   *
+   * @return the tag name
+   */
+  public String getTagName() {
+    return tagName;
+  }
+
+  /**
+   * Returns the array of attribute names. If no attributes are defined, an
+   * empty array is returned.
+   * <p>
+   * Note: This is not the actual structure used by the receiver to maintain
+   * its list of names, so modifying the array will not affect the receiver.
+   * </p>
+   *
+   * @return the attribute names
+   */
+  public String[] getNames() {
+    String[] result = new String[ names.length ];
+    System.arraycopy( names, 0, result, 0, names.length );
+    return result;
+  }
+
+  /**
+   * Returns the array of attribute values. If no attributes are defined, an
+   * empty array is returned.
+   * <p>
+   * Note: This is not the actual structure used by the receiver to maintain
+   * its list of values, so modifying the array will not affect the receiver.
+   * </p>
+   *
+   * @return the attribute values
+   */
+  public String[] getValues() {
+    String[] result = new String[ values.length ];
+    System.arraycopy( values, 0, result, 0, values.length );
+    return result;
+  }
+
+  private static void checkTagName( String tagName ) {
+    if( !"link".equals( tagName ) && !"meta".equals( tagName ) ) {
+      String msg = "Invalid tag name. The tag name must be either 'meta' or 'link'.";
+      throw new IllegalArgumentException( msg );
+    }
+  }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/preferences/SessionPreferenceNodeCore.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/preferences/SessionPreferenceNodeCore.java
new file mode 100644
index 0000000..6185db9
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/preferences/SessionPreferenceNodeCore.java
@@ -0,0 +1,193 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2012 Innoopract Informationssysteme GmbH 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:
+ *    Innoopract Informationssysteme GmbH - initial API and implementation
+ *    EclipseSource - ongoing development
+ ******************************************************************************/
+package org.eclipse.rap.ui.internal.preferences;
+
+import java.io.IOException;
+
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences.INodeChangeListener;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences.NodeChangeEvent;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.rap.rwt.internal.util.ParamCheck;
+import org.eclipse.rap.rwt.service.SettingStore;
+import org.eclipse.rap.rwt.service.SettingStoreEvent;
+import org.eclipse.rap.rwt.service.SettingStoreListener;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.osgi.service.prefs.Preferences;
+
+
+/**
+ * This class is the link between the SessionPreferenceNode hierarchy
+ * (application global) the RWT setting store (session specific).
+ */
+final class SessionPreferenceNodeCore {
+
+  private final SessionPreferencesNode node;
+  private ListenerList prefListeners; // ListenerList is thread safe
+  private final ListenerList nodeListeners
+    = new ListenerList( ListenerList.IDENTITY ); // thread safe
+
+  /* tracks changes in RWT setting store and notifies the prefListeners */
+  private SettingStoreListener rwtListener;
+  /* true to track RWT changes */
+  private boolean trackChanges = true;
+  /* ignore changes to this key for a short time */
+  private String ignoreKey;
+
+  SessionPreferenceNodeCore( final SessionPreferencesNode node ) {
+    ParamCheck.notNull( node, "node" ); //$NON-NLS-1$
+    this.node = node;
+  }
+
+  void addPreferenceChangeListener( IPreferenceChangeListener listener ) {
+    if( listener != null ) {
+      getListenerList().add( listener );
+      setTrackRWTChanges( true );
+    }
+  }
+
+  void removePreferenceChangeListener( IPreferenceChangeListener listener ) {
+    if( listener != null ) {
+      ListenerList list = getListenerList();
+      list.remove( listener );
+      if( list.isEmpty() ) {
+        setTrackRWTChanges( false );
+      }
+    }
+  }
+
+  void firePreferenceEvent( final String key,
+                            final String oldValue,
+                            final String newValue )
+  {
+    if( prefListeners != null ) {
+      final PreferenceChangeEvent event
+        = new PreferenceChangeEvent( node, key, oldValue, newValue );
+      Object[] listeners = prefListeners.getListeners();
+      for( int i = 0; i < listeners.length; i++ ) {
+        final IPreferenceChangeListener listener
+          = ( IPreferenceChangeListener )listeners[ i ];
+        ISafeRunnable op = new ISafeRunnable() {
+          public void handleException( final Throwable exception ) {
+            // logged by SafeRunner
+          }
+          public void run() throws Exception {
+            listener.preferenceChange( event );
+          }
+        };
+        SafeRunner.run( op );
+      }
+    }
+  }
+
+  void clear() {
+    if( prefListeners != null ) {
+      prefListeners.clear();
+      prefListeners = null;
+      setTrackRWTChanges( false );
+    }
+    nodeListeners.clear();
+  }
+
+  synchronized String put( final String uniqueKey,
+                           final String value ) {
+    SettingStore store = RWT.getSettingStore();
+    String result = store.getAttribute( uniqueKey );
+    try {
+      ignoreKey = uniqueKey;
+      store.setAttribute( uniqueKey, value );
+      ignoreKey = null;
+    } catch( IOException exception ) {
+      String msg = "Could not persist preference: " + uniqueKey; //$NON-NLS-1$
+      WorkbenchPlugin.log( msg, exception );
+    }
+    return result;
+  }
+
+  // helping methods
+  //////////////////
+
+  private synchronized ListenerList getListenerList() {
+    if( prefListeners == null ) {
+      prefListeners = new ListenerList( ListenerList.IDENTITY );
+    }
+    return prefListeners;
+  }
+
+  private synchronized void setTrackRWTChanges( final boolean doTrack ) {
+    trackChanges = doTrack;
+    if( trackChanges ) {
+      if( rwtListener == null ) {
+       rwtListener = new SettingStoreListener() {
+        public void settingChanged( SettingStoreEvent event ) {
+          if( trackChanges ) {
+            String fullKey = event.getAttributeName();
+            if( !fullKey.equals( ignoreKey ) ) {
+              String absPath = node.absolutePath();
+              if( fullKey.startsWith( absPath ) ) {
+                String key = fullKey.substring( absPath.length() + 1 );
+                String oldValue = event.getOldValue();
+                String newValue = event.getNewValue();
+                firePreferenceEvent( key, oldValue, newValue );
+              }
+            }
+          }
+        }
+       };
+     }
+     RWT.getSettingStore().addSettingStoreListener( rwtListener );
+   } else { // !trackChanges
+     if( rwtListener != null ) {
+       RWT.getSettingStore().removeSettingStoreListener( rwtListener );
+     }
+   }
+  }
+
+  public void addNodeChangeListener( final INodeChangeListener listener ) {
+    nodeListeners.add( listener );
+  }
+
+  public void removeNodeChangeListener( final INodeChangeListener listener ) {
+    nodeListeners.remove( listener );
+  }
+
+  public void fireNodeEvent( final Preferences child,
+                             final boolean wasAdded,
+                             final SessionPreferencesNode spn )
+  {
+    final NodeChangeEvent event = new NodeChangeEvent( spn, child );
+    Object[] listeners = nodeListeners.getListeners();
+    for( int i = 0; i < listeners.length; i++ ) {
+      final INodeChangeListener listener
+        = ( INodeChangeListener )listeners[ i ];
+      ISafeRunnable op = new ISafeRunnable() {
+        public void handleException( final Throwable exception ) {
+          // logged by SafeRunner
+        }
+        public void run() throws Exception {
+          if( wasAdded ) {
+            listener.added( event );
+          } else {
+            listener.removed( event );
+          }
+        }
+      };
+      SafeRunner.run( op );
+    }
+
+  }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/preferences/SessionPreferencesFactory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/preferences/SessionPreferencesFactory.java
new file mode 100644
index 0000000..0eec784
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/preferences/SessionPreferencesFactory.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Innoopract Informationssysteme GmbH.
+ * 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:
+ *     Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.rap.ui.internal.preferences;
+
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.IScope;
+
+/**
+ * Creates "session" scoped preference nodes.
+ */
+public final class SessionPreferencesFactory implements IScope {
+
+  public IEclipsePreferences create( final IEclipsePreferences parent, 
+                                     final String name )
+  {
+    return new SessionPreferencesNode( parent, name );
+  }
+  
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/preferences/SessionPreferencesNode.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/preferences/SessionPreferencesNode.java
new file mode 100644
index 0000000..b7e3f26
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/preferences/SessionPreferencesNode.java
@@ -0,0 +1,516 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2012 Innoopract Informationssysteme GmbH 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:
+ *    Innoopract Informationssysteme GmbH - initial API and implementation
+ *    EclipseSource - ongoing development
+ ******************************************************************************/
+package org.eclipse.rap.ui.internal.preferences;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.IPreferenceNodeVisitor;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.rap.rwt.internal.util.ParamCheck;
+import org.eclipse.rap.rwt.service.SettingStore;
+import org.eclipse.ui.internal.preferences.Base64;
+import org.osgi.service.prefs.BackingStoreException;
+import org.osgi.service.prefs.Preferences;
+
+
+/**
+ * This node use the RWT setting store to persist its preferences.
+ */
+final class SessionPreferencesNode implements IEclipsePreferences {
+
+  private static final String PATH_SEPARATOR = "/"; //$NON-NLS-1$
+  private static final String DOUBLE_PATH_SEPARATOR = "//"; //$NON-NLS-1$
+  private static final String TRUE  = "true"; //$NON-NLS-1$
+  private static final String FALSE = "false"; //$NON-NLS-1$
+
+  private final String name;
+  private final IEclipsePreferences parent;
+  private boolean isRemoved;
+  /* cache the absolutePath once it has been computed */
+  private String absolutePath;
+
+  private final Map children = new HashMap();    // !thread safe
+
+  SessionPreferencesNode( final IEclipsePreferences parent,
+                          final String name )
+  {
+    ParamCheck.notNull( parent, "parent" ); //$NON-NLS-1$
+    ParamCheck.notNull( name, "name" ); //$NON-NLS-1$
+    checkName( name );
+    this.parent = parent;
+    this.name = name;
+  }
+
+  public void accept( final IPreferenceNodeVisitor visitor )
+    throws BackingStoreException
+  {
+    boolean withChildren = visitor.visit( this );
+    if( withChildren ) {
+      Object[] childrenArray;
+      synchronized( this ) {
+        childrenArray = children.values().toArray();
+      }
+      for( int i = 0; i < childrenArray.length; i++ ) {
+        IEclipsePreferences child = ( IEclipsePreferences )childrenArray[ i ];
+        child.accept( visitor );
+      }
+    }
+  }
+
+  public void addNodeChangeListener( final INodeChangeListener listener ) {
+    checkRemoved();
+    if( listener != null ) {
+      getNodeCore().addNodeChangeListener( listener );
+    }
+  }
+
+  public void addPreferenceChangeListener(
+    final IPreferenceChangeListener listener )
+  {
+    checkRemoved();
+    getNodeCore().addPreferenceChangeListener( listener );
+  }
+
+  public Preferences node( final String path ) {
+    checkPath( path );
+    checkRemoved();
+    Preferences result;
+    if( "".equals( path ) ) { // "" //$NON-NLS-1$
+      result = this;
+    } else if( path.startsWith( PATH_SEPARATOR ) ) { // "/absolute/path"
+      result = findRoot().node( path.substring( 1 ) );
+    } else if( path.indexOf( PATH_SEPARATOR ) > 0 ) { // "foo/bar/baz"
+      int index = path.indexOf( PATH_SEPARATOR );
+      String nodeName = path.substring( 0, index );
+      String rest = path.substring( index + 1, path.length() );
+      result = getChild( nodeName, true ).node( rest );
+    } else { // "foo"
+      result = getChild( path, true );
+    }
+    return result;
+  }
+
+  public synchronized void removeNode() throws BackingStoreException {
+    checkRemoved();
+    // remove all preferences
+    clear();
+    // remove all children
+    Object[] childNodes = children.values().toArray();
+    for( int i = 0; i < childNodes.length; i++ ) {
+      Preferences child = ( Preferences )childNodes[ i ];
+      if( child.nodeExists( "" ) ) { // if !removed //$NON-NLS-1$
+        child.removeNode();
+      }
+    }
+    // remove from parent; this is ugly, because the interface
+    // Preference has no API for removing oneself from the parent.
+    // In general the parent will be a SessionPreferencesNode.
+    // The only case in the workbench where this is not true, is one level
+    // below the root (i.e. at /session ), but the scope root must not
+    // be removable (see IEclipsePreferences#removeNode())
+    if( parent instanceof SessionPreferencesNode ) {
+      // this means:
+      // (a) we know what kind of parent we have, and
+      // (b) we are not the scope root, since that has a
+      /// RootPreference as a parent
+      SessionPreferencesNode spnParent
+        = ( ( SessionPreferencesNode ) parent );
+      spnParent.children.remove( name );
+      spnParent.fireNodeEvent( this, false );
+
+      // the listeners are not needed anymore
+      getNodeCore().clear();
+      children.clear();
+      isRemoved = true;
+    }
+  }
+
+  public void removeNodeChangeListener( final INodeChangeListener listener ) {
+    checkRemoved();
+    if( listener != null ) {
+      getNodeCore().removeNodeChangeListener( listener );
+    }
+  }
+
+  public void removePreferenceChangeListener(
+    final IPreferenceChangeListener listener )
+  {
+    checkRemoved();
+    getNodeCore().removePreferenceChangeListener( listener );
+  }
+
+  public String absolutePath() {
+    if( absolutePath == null ) {
+      if( parent == null ) {
+        absolutePath = name;
+      } else {
+        String parentPath =  parent.absolutePath();
+        absolutePath = parentPath.endsWith( PATH_SEPARATOR )
+                     ? parentPath + name
+                     : parentPath + PATH_SEPARATOR + name;
+      }
+    }
+    return absolutePath;
+  }
+
+  public synchronized String[] childrenNames() {
+    checkRemoved();
+    Set names = children.keySet();
+    return ( String[] )names.toArray( new String[ names.size() ] );
+  }
+
+  public void clear() {
+    checkRemoved();
+    String[] keys = internalGetKeys();
+    for( int i = 0; i < keys.length; i++ ) {
+      remove( keys[ i ] );
+    }
+  }
+
+  public void flush() {
+    checkRemoved();
+    // the current implementation persists everytime the preferences
+    // are modified, so there's nothing to do here
+  }
+
+  public String get( final String key, final String def ) {
+    ParamCheck.notNull( key, "key" ); //$NON-NLS-1$
+    checkRemoved();
+    String result = internalGet( key );
+    return result == null ? def : result;
+  }
+
+  public boolean getBoolean( final String key, final boolean def ) {
+    ParamCheck.notNull( key, "key" ); //$NON-NLS-1$
+    checkRemoved();
+    String value = internalGet( key );
+    return value == null ? def : Boolean.valueOf( value ).booleanValue();
+  }
+
+  public byte[] getByteArray( final String key, final byte[] def ) {
+    ParamCheck.notNull( key, "key" ); //$NON-NLS-1$
+    checkRemoved();
+    String value = internalGet( key );
+    return value == null ? def : Base64.decode( value.getBytes() );
+  }
+
+  public double getDouble( final String key, final double def ) {
+    ParamCheck.notNull( key, "key" ); //$NON-NLS-1$
+    checkRemoved();
+    String value = internalGet( key );
+    double result = def;
+    if( value != null ) {
+      try {
+        result = Double.parseDouble( value );
+      } catch( NumberFormatException nfe ) {
+        // returns def
+      }
+    }
+    return result;
+  }
+
+  public float getFloat( final String key, final float def ) {
+    ParamCheck.notNull( key, "key" ); //$NON-NLS-1$
+    checkRemoved();
+    String value = internalGet( key );
+    float result = def;
+    if( value != null ) {
+      try {
+        result = Float.parseFloat( value );
+      } catch( NumberFormatException nfe ) {
+        // returns def
+      }
+    }
+    return result;
+  }
+
+  public int getInt( final String key, final int def ) {
+    ParamCheck.notNull( key, "key" ); //$NON-NLS-1$
+    checkRemoved();
+    String value = internalGet( key );
+    int result = def;
+    if( value != null ) {
+      try {
+        result = Integer.parseInt( value );
+      } catch( NumberFormatException nfe ) {
+        // returns def
+      }
+    }
+    return result;
+  }
+
+  public long getLong( final String key, final long def ) {
+    ParamCheck.notNull( key, "key" ); //$NON-NLS-1$
+    checkRemoved();
+    String value = internalGet( key );
+    long result = def;
+    if( value != null ) {
+      try {
+        result = Long.parseLong( value );
+      } catch( NumberFormatException nfe ) {
+        // returns def
+      }
+    }
+    return result;
+  }
+
+  public String[] keys() {
+    checkRemoved();
+    return internalGetKeys();
+  }
+
+  public String name() {
+    return name;
+  }
+
+  public synchronized boolean nodeExists( final String path )
+    throws BackingStoreException
+  {
+    boolean result;
+    if( "".equals( path ) ) { //$NON-NLS-1$
+      result = !isRemoved;
+    } else {
+      checkRemoved();
+      checkPath( path );
+      if( path.startsWith( PATH_SEPARATOR ) ) { // "/absolute/path"
+        result = findRoot().nodeExists( path.substring( 1 ) );
+      } else if( path.indexOf( PATH_SEPARATOR ) > 0 ) { // "foo/bar/baz"
+        int index = path.indexOf( PATH_SEPARATOR );
+        String nodeName = path.substring( 0, index );
+        String rest = path.substring( index + 1, path.length() );
+        SessionPreferencesNode child = getChild( nodeName, false );
+        result = child == null ? false : child.nodeExists( rest );
+      } else { // "foo"
+        result = children.containsKey( path );
+      }
+    }
+    return result;
+  }
+
+  public Preferences parent() {
+    checkRemoved();
+    return parent;
+  }
+
+  public void put( final String key, final String newValue ) {
+    ParamCheck.notNull( key, "key" ); //$NON-NLS-1$
+    ParamCheck.notNull( newValue, "newValue" ); //$NON-NLS-1$
+    checkRemoved();
+    String oldValue = internalPut( key, newValue );
+    if( !newValue.equals( oldValue ) ) {
+      getNodeCore().firePreferenceEvent( key, oldValue, newValue );
+    }
+  }
+
+  public void putBoolean( final String key, final boolean value ) {
+    ParamCheck.notNull( key, "key" ); //$NON-NLS-1$
+    checkRemoved();
+    String newValue = value ? TRUE : FALSE;
+    String oldValue = internalPut( key, newValue );
+    if( !newValue.equals( oldValue ) ) {
+      getNodeCore().firePreferenceEvent( key, oldValue, newValue );
+    }
+  }
+
+  public void putByteArray( final String key, final byte[] value ) {
+    ParamCheck.notNull( key, "key" ); //$NON-NLS-1$
+    ParamCheck.notNull( value, "newValue" ); //$NON-NLS-1$
+    checkRemoved();
+    String newValue = new String( Base64.encode( value ) );
+    String oldValue = internalPut( key, newValue );
+    if( !newValue.equals( oldValue) ) {
+      getNodeCore().firePreferenceEvent( key, oldValue, newValue );
+    }
+  }
+
+  public void putDouble( final String key, final double value ) {
+    ParamCheck.notNull( key, "key" ); //$NON-NLS-1$
+    checkRemoved();
+    String newValue = String.valueOf( value );
+    String oldValue = internalPut( key, newValue );
+    if( !newValue.equals( oldValue ) ) {
+      getNodeCore().firePreferenceEvent( key, oldValue, newValue );
+    }
+  }
+
+  public void putFloat( final String key, final float value ) {
+    ParamCheck.notNull( key, "key" ); //$NON-NLS-1$
+    checkRemoved();
+    String newValue = String.valueOf( value );
+    String oldValue = internalPut( key, newValue );
+    if( !newValue.equals( oldValue ) ) {
+      getNodeCore().firePreferenceEvent( key, oldValue, newValue );
+    }
+  }
+
+  public void putInt( final String key, final int value ) {
+    ParamCheck.notNull( key, "key" ); //$NON-NLS-1$
+    checkRemoved();
+    String newValue = String.valueOf( value );
+    String oldValue = internalPut( key, newValue );
+    if( !newValue.equals( oldValue ) ) {
+      getNodeCore().firePreferenceEvent( key, oldValue, newValue );
+    }
+  }
+
+  public void putLong( final String key, final long value ) {
+    ParamCheck.notNull( key, "key" ); //$NON-NLS-1$
+    checkRemoved();
+    String newValue = String.valueOf( value );
+    String oldValue = internalPut( key, newValue );
+    if( !newValue.equals( oldValue ) ) {
+      getNodeCore().firePreferenceEvent( key, oldValue, newValue );
+    }
+  }
+
+  public void remove( final String key ) {
+    checkRemoved();
+    String oldValue = internalGet( key );
+    if( oldValue != null ) {
+      internalPut( key, null );
+      getNodeCore().firePreferenceEvent( key, oldValue, null );
+    }
+  }
+
+  public void sync() throws BackingStoreException {
+    checkRemoved();
+    SettingStore store = RWT.getSettingStore();
+    String id = store.getId();
+    try {
+      store.loadById( id );
+    } catch( IOException sse ) {
+      throw new BackingStoreException( "Failed to sync() node", sse ); //$NON-NLS-1$
+    }
+  }
+
+  @Override
+  public String toString() {
+    return absolutePath() + "@" + hashCode(); //$NON-NLS-1$
+  }
+
+  //////////////////
+  // helping methods
+
+  private void checkName( final String nodeName ) {
+    if( nodeName.indexOf( PATH_SEPARATOR ) != -1 ) {
+      String unboundMsg = "Name ''{0}'' cannot contain or end with ''{1}''"; //$NON-NLS-1$
+      String msg = NLS.bind( unboundMsg, nodeName, PATH_SEPARATOR );
+      throw new IllegalArgumentException( msg );
+    }
+  }
+
+  private void checkPath( final String path ) {
+    if( path.indexOf( DOUBLE_PATH_SEPARATOR ) != -1 ) {
+      String unboundMsg = "''{0}'' is not allowed in path ''{1}''"; //$NON-NLS-1$
+      String msg = NLS.bind( unboundMsg, DOUBLE_PATH_SEPARATOR, path );
+      throw new IllegalArgumentException( msg );
+    }
+    if( path.length() > 1 && path.endsWith( PATH_SEPARATOR ) ) {
+      String unboundMsg = "path ''{0}'' cannot end with ''{1}''"; //$NON-NLS-1$
+      String msg = NLS.bind( unboundMsg, path, PATH_SEPARATOR );
+      throw new IllegalArgumentException( msg );
+    }
+  }
+
+  private synchronized void checkRemoved() {
+    if( isRemoved ) {
+      String msg = "node ''{0}'' has been removed"; //$NON-NLS-1$
+      throw new IllegalStateException( NLS.bind( msg, absolutePath() ) );
+    }
+  }
+
+  private synchronized SessionPreferencesNode createChild(
+    final String childName )
+  {
+    SessionPreferencesNode result
+      = new SessionPreferencesNode( this, childName );
+    children.put( childName, result );
+    fireNodeEvent( result, true );
+    return result;
+  }
+
+  private synchronized SessionPreferencesNode getChild(
+    final String childName,
+    final boolean doCreate )
+  {
+    SessionPreferencesNode result
+      = ( SessionPreferencesNode )children.get( childName );
+    if( result == null && doCreate ) {
+      result = createChild( childName );
+    }
+    return result;
+  }
+
+  private String[] internalGetKeys() {
+    List result = new ArrayList();
+
+    String prefix = absolutePath() + PATH_SEPARATOR;
+    int prefixLength = prefix.length();
+
+    Enumeration attrNames = RWT.getSettingStore().getAttributeNames();
+    while( attrNames.hasMoreElements() ) {
+      String attr = ( String )attrNames.nextElement();
+      if( attr.startsWith( prefix ) ) {
+        String key = attr.substring( prefixLength );
+        result.add( key );
+      }
+    }
+    return ( String[] )result.toArray( new String[ result.size() ] );
+  }
+
+  private Preferences findRoot() {
+    Preferences result = this;
+    while( result.parent() != null ) {
+      result = result.parent();
+    }
+    return result;
+  }
+
+  private String internalGet( final String key ) {
+    SettingStore store = RWT.getSettingStore();
+    String uniqueKey = absolutePath() + PATH_SEPARATOR + key;
+    return store.getAttribute( uniqueKey );
+  }
+
+  private synchronized String internalPut( final String key,
+                                           final String value ) {
+    String uniqueKey = absolutePath() + PATH_SEPARATOR + key;
+    return getNodeCore().put( uniqueKey, value );
+  }
+
+  private void fireNodeEvent( final Preferences child,
+                              final boolean wasAdded ) {
+    getNodeCore().fireNodeEvent( child, wasAdded, this );
+  }
+
+  private SessionPreferenceNodeCore getNodeCore() {
+    SessionPreferenceNodeCore result;
+    final String key = absolutePath();
+    Object object = RWT.getUISession().getAttribute( key );
+    if( object instanceof SessionPreferenceNodeCore ) {
+      result = ( SessionPreferenceNodeCore )object;
+    } else {
+      result = new SessionPreferenceNodeCore( this );
+      RWT.getUISession().setAttribute( key, result );
+    }
+    return result;
+  }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/preferences/SessionScope.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/preferences/SessionScope.java
new file mode 100644
index 0000000..239041d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/preferences/SessionScope.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2012 Innoopract Informationssysteme GmbH 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:
+ *    Innoopract Informationssysteme GmbH - initial API and implementation
+ *    EclipseSource - ongoing development
+ ******************************************************************************/
+package org.eclipse.rap.ui.internal.preferences;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.IScopeContext;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.rap.rwt.internal.util.ParamCheck;
+import org.eclipse.rap.rwt.service.FileSettingStore;
+
+// TODO [fappel]: think about how we can provide this as API (subset rule
+//                of RAP/RCP)
+/**
+ * Object representing the session scope in the Eclipse preferences
+ * hierarchy. Can be used as a context for searching for preference
+ * values (in the IPreferenceService APIs) or for determining the
+ * corrent preference node to set values in the store.
+ * <p>
+ * Session preferences are stored on a <i>per-session</i> basis using
+ * the underlying RWT SettingStore (see {@link RWT#getSettingStore()}. 
+ * Preferences saved during a previous session will be retrieved, as long as
+ * the user can identify himself with the setting store cookie. Session 
+ * preferences are persisted using the setting store implementation
+ * that is configured for the application (see {@link FileSettingStore}.
+ * <p>
+ * The path for preferences defined in the session scope hierarchy is: 
+ * <code>/session/&lt;qualifier&gt;</code>
+ * <p>
+ * This class is not intented to be subclassed. It may be instantiated.
+ *
+ */
+public final class SessionScope implements IScopeContext {
+
+  /**
+   * String constant (value of <code>"session"</code>) used for the 
+   * scope name for the session preference scope.
+   */
+  public static final String SCOPE = "session"; //$NON-NLS-1$
+  
+  /**
+   * Create and return a new session scope instance.
+   */
+  public SessionScope() {
+    super();
+  }
+
+  public IPath getLocation() {
+    return null;
+  }
+
+  public String getName() {
+    return SCOPE;
+  }
+
+  public IEclipsePreferences getNode( String qualifier ) {
+    ParamCheck.notNull( qualifier, "qualifier" ); //$NON-NLS-1$
+    IEclipsePreferences root = Platform.getPreferencesService().getRootNode();
+    return ( IEclipsePreferences ) root.node( SCOPE ).node( qualifier );
+  }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/preferences/WorkbenchFileSettingStoreFactory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/preferences/WorkbenchFileSettingStoreFactory.java
new file mode 100644
index 0000000..143ad7d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/preferences/WorkbenchFileSettingStoreFactory.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2012 Innoopract Informationssysteme GmbH 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:
+ *    Innoopract Informationssysteme GmbH - initial API and implementation
+ *    EclipseSource - ongoing devleopment
+ ******************************************************************************/
+package org.eclipse.rap.ui.internal.preferences;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.rap.rwt.internal.util.ParamCheck;
+import org.eclipse.rap.rwt.service.FileSettingStore;
+import org.eclipse.rap.rwt.service.FileSettingStoreFactory;
+import org.eclipse.rap.rwt.service.SettingStore;
+import org.eclipse.rap.rwt.service.SettingStoreFactory;
+import org.eclipse.ui.PlatformUI;
+import org.osgi.framework.Bundle;
+
+
+/**
+ * A setting store factory that creates {@link FileSettingStore}
+ * instances.
+ * <p>
+ * This particular implementation uses the following strategy to determine
+ * the path for persisting the data of a FileSettingStore:
+ * <ol>
+ * <li>Use the directory specified by the system property
+ * <code>"org.eclipse.rap.rwt.service.FileSettingStore.dir"</code>.
+ * </li>
+ * <li>Use a subdirectory in the state location of the
+ * org.eclipse.rap.ui.workbench bundle.
+ * </li>
+ * </ol>
+ * The first path that can be obtained from the above choices (in the order
+ * given above) will be used. If the path determined does not exist it will
+ * be created.
+ * <p>
+ * <b>Note:</b> This setting store factory should be used in a regular
+ * RAP deployment. For an RWT only deployment use the
+ * {@link FileSettingStoreFactory}.
+ *
+ */
+public final class WorkbenchFileSettingStoreFactory
+  implements SettingStoreFactory
+{
+
+  public SettingStore createSettingStore( final String storeId ) {
+    ParamCheck.notNullOrEmpty( storeId, "storeId" ); //$NON-NLS-1$
+    SettingStore result = new FileSettingStore( getWorkDir() );
+    try {
+      result.loadById( storeId );
+    } catch( IOException exception ) {
+      String message = String.valueOf( exception.getMessage() );
+      RWT.getRequest().getSession().getServletContext().log( message, exception );
+    }
+    return result;
+  }
+
+  //////////////////
+  // helping methods
+
+  private File getWorkDir() {
+    File result = getWorkDirFromEnvironment();
+    if( result == null ) {
+      Bundle bundle = Platform.getBundle( PlatformUI.PLUGIN_ID );
+      IPath stateLoc = Platform.getStateLocation( bundle );
+      File parentDir = stateLoc.toFile();
+      result = new File( parentDir, FileSettingStore.class.getName() );
+    }
+    if( !result.exists() ) {
+      result.mkdirs();
+    }
+    return result;
+  }
+
+  private File getWorkDirFromEnvironment() {
+    String path = System.getProperty( FileSettingStore.FILE_SETTING_STORE_DIR );
+    return ( path != null ) ? new File( path ) : null;
+  }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/progress/IJobMarker.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/progress/IJobMarker.java
new file mode 100644
index 0000000..99e9b3d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/progress/IJobMarker.java
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ * Copyright (c) 2002, 2008 Innoopract Informationssysteme GmbH.
+ * 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:
+ *     Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rap.ui.internal.progress;
+
+// RAP [fappel]: This is a helper class used to avoid a memory leak due to 
+//               thread management.
+//               Note that this is still under investigation.
+//               See comment in JobManagerAdapter
+public interface IJobMarker {
+  boolean canBeRemoved();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/progress/JobCanceler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/progress/JobCanceler.java
new file mode 100644
index 0000000..992758e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/progress/JobCanceler.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2002-2006 Innoopract Informationssysteme GmbH.
+ * 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:
+ *     Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.rap.ui.internal.progress;
+
+import org.eclipse.core.runtime.jobs.IJobChangeEvent;
+import org.eclipse.core.runtime.jobs.IJobChangeListener;
+
+// RAP [fappel]: This is a helper class used to avoid a memory leak due to 
+//               thread management.
+//               Note that this is still under investigation.
+//               See comment in JobManagerAdapter
+public final class JobCanceler implements IJobChangeListener {
+
+  public void aboutToRun( IJobChangeEvent event ) {
+    event.getJob().cancel();
+  }
+
+  public void awake( IJobChangeEvent event ) {
+    event.getJob().cancel();
+  }
+
+  public void done( IJobChangeEvent event ) {
+    event.getJob().cancel();
+  }
+
+  public void running( IJobChangeEvent event ) {
+    event.getJob().cancel();
+  }
+
+  public void scheduled( IJobChangeEvent event ) {
+    event.getJob().cancel();
+  }
+
+  public void sleeping( IJobChangeEvent event ) {
+    event.getJob().cancel();
+  }
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/progress/JobManagerAdapter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/progress/JobManagerAdapter.java
new file mode 100644
index 0000000..5b12bd6
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/progress/JobManagerAdapter.java
@@ -0,0 +1,290 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2012 Innoopract Informationssysteme GmbH 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:
+ *     Innoopract Informationssysteme GmbH - initial API and implementation
+ *     EclipseSource - ongoing development
+ ******************************************************************************/
+package org.eclipse.rap.ui.internal.progress;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.jobs.IJobChangeEvent;
+import org.eclipse.core.runtime.jobs.IJobChangeListener;
+import org.eclipse.core.runtime.jobs.IJobManager;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.core.runtime.jobs.JobChangeAdapter;
+import org.eclipse.core.runtime.jobs.ProgressProvider;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.rap.rwt.internal.lifecycle.LifeCycleUtil;
+import org.eclipse.rap.rwt.internal.serverpush.ServerPushManager;
+import org.eclipse.rap.rwt.internal.service.ContextProvider;
+import org.eclipse.rap.rwt.service.UISession;
+import org.eclipse.rap.rwt.service.UISessionEvent;
+import org.eclipse.rap.rwt.service.UISessionListener;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.internal.progress.ProgressManager;
+import org.eclipse.ui.progress.UIJob;
+
+
+public class JobManagerAdapter extends ProgressProvider implements IJobChangeListener {
+
+  private static JobManagerAdapter _instance;
+  private final Map jobs;
+  private final ProgressManager defaultProgressManager;
+  final Object lock;
+
+  public static synchronized JobManagerAdapter getInstance() {
+    if( _instance == null ) {
+      _instance = new JobManagerAdapter();
+    }
+    return _instance;
+  }
+
+  private JobManagerAdapter() {
+    // To avoid deadlocks we have to use the same synchronization lock.
+    // If anyone has a better idea - you're welcome.
+    IJobManager jobManager = Job.getJobManager();
+    Class clazz = jobManager.getClass();
+    try {
+      Field jobManagerLock = clazz.getDeclaredField( "lock" );
+      jobManagerLock.setAccessible( true );
+      lock = jobManagerLock.get( jobManager );
+    } catch( final Throwable thr ) {
+      String msg = "Could not initialize synchronization lock.";
+      throw new IllegalStateException( msg );
+    }
+    jobs = new HashMap();
+    defaultProgressManager = new ProgressManager();
+    Job.getJobManager().setProgressProvider( this );
+    Job.getJobManager().addJobChangeListener( this );
+  }
+
+  ///////////////////
+  // ProgressProvider
+
+  @Override
+  public IProgressMonitor createMonitor( final Job job ) {
+    IProgressMonitor result = null;
+    ProgressManager manager = findSessionProgressManager( job );
+    if( manager != null ) {
+      result = manager.createMonitor( job );
+    }
+    return result;
+  }
+
+  @Override
+  public IProgressMonitor createMonitor( final Job job,
+                                         final IProgressMonitor group,
+                                         final int ticks )
+  {
+    IProgressMonitor result = null;
+    ProgressManager manager = findSessionProgressManager( job );
+    if( manager != null ) {
+      result = manager.createMonitor( job, group, ticks );
+    }
+    return result;
+  }
+
+  @Override
+  public IProgressMonitor createProgressGroup() {
+    return defaultProgressManager.createProgressGroup();
+  }
+
+  ///////////////////////////////
+  // interface IJobChangeListener
+
+  public void aboutToRun( final IJobChangeEvent event ) {
+    ProgressManager manager = findProgressManager( event.getJob() );
+    manager.changeListener.aboutToRun( event );
+  }
+
+  public void awake( final IJobChangeEvent event ) {
+    ProgressManager manager = findProgressManager( event.getJob() );
+    manager.changeListener.awake( event );
+  }
+
+  public void done( final IJobChangeEvent event ) {
+    final ProgressManager[] manager = new ProgressManager[ 1 ];
+    Display display = null;
+    synchronized( lock ) {
+      try {
+        manager[ 0 ] = findProgressManager( event.getJob() );
+        display = ( Display )jobs.get( event.getJob() );
+      } finally {
+        jobs.remove( event.getJob() );
+      }
+    }
+    if( display != null && !display.isDisposed() ) {
+      display.asyncExec( new Runnable() {
+        public void run() {
+          ServerPushManager.getInstance().deactivateServerPushFor( event.getJob() );
+          manager[ 0 ].changeListener.done( event );
+        }
+      } );
+    } else {
+      // RAP [rh] fixes bug 283595
+      event.getJob().cancel();
+      manager[ 0 ].changeListener.done( event );
+    }
+  }
+
+  public void running( final IJobChangeEvent event ) {
+    ProgressManager manager = findProgressManager( event.getJob() );
+    manager.changeListener.running( event );
+  }
+
+  public void scheduled( final IJobChangeEvent event ) {
+    ProgressManager manager;
+    Display display = findDisplay( event.getJob() );
+    synchronized( lock ) {
+      if( display != null ) {
+        jobs.put( event.getJob(), display );
+        Runnable runnable = new Runnable() {
+
+          public void run() {
+            bindToSession( event.getJob() );
+            ServerPushManager.getInstance().activateServerPushFor( event.getJob() );
+          }
+        };
+        RWT.getUISession( display ).exec( runnable );
+      }
+      manager = findProgressManager( event.getJob() );
+    }
+    manager.changeListener.scheduled( event );
+  }
+
+  public void sleeping( final IJobChangeEvent event ) {
+    ProgressManager manager = findProgressManager( event.getJob() );
+    manager.changeListener.sleeping( event );
+  }
+
+  //////////////////
+  // helping methods
+
+  private ProgressManager findProgressManager( final Job job ) {
+    ProgressManager result = findSessionProgressManager( job );
+    if( result == null ) {
+      result = defaultProgressManager;
+    }
+    return result;
+  }
+
+  private ProgressManager findSessionProgressManager( final Job job ) {
+    synchronized( lock ) {
+      final ProgressManager result[] = new ProgressManager[ 1 ];
+      Display display = ( Display )jobs.get( job );
+      if( display != null ) {
+        RWT.getUISession( display ).exec( new Runnable() {
+          public void run() {
+            result[ 0 ] = ProgressManager.getInstance();
+          }
+        } );
+        if( result[ 0 ] == null ) {
+          String msg = "ProgressManager must not be null.";
+          throw new IllegalStateException( msg );
+        }
+      } else {
+        result[ 0 ] = null;
+      }
+      return result[ 0 ];
+    }
+  }
+
+  private static Display findDisplay( final Job job ) {
+    Display result = null;
+    if( ContextProvider.hasContext() ) {
+      result = LifeCycleUtil.getSessionDisplay();
+    } else {
+      if( job instanceof UIJob ) {
+        UIJob uiJob = ( UIJob )job;
+        result = uiJob.getDisplay();
+        if( result == null ) {
+          String msg = "UIJob "
+                     + uiJob.getName()
+                     + " cannot be scheduled without an associated display.";
+          throw new IllegalStateException( msg );
+        }
+      }
+    }
+    return result;
+  }
+
+  private void bindToSession( final Job job ) {
+    final AtomicBoolean jobDone = new AtomicBoolean();
+    final UISession uiSession = RWT.getUISession();
+    final UISessionListener cleanupListener = new UISessionListener() {
+
+      public void beforeDestroy( UISessionEvent event ) {
+        if( !jobDone.get() ) {
+          try {
+            cleanup( job );
+          } finally {
+            synchronized( lock ) {
+              jobs.remove( job );
+            }
+          }
+        }
+      }
+
+      private void cleanup( final Job jobToRemove ) {
+        // ////////////////////////////////////////////////////////////////////
+        // TODO [fappel]: Very ugly hack to avoid a memory leak.
+        // As a job can not be removed from the
+        // running set directly, I use reflection. Jobs
+        // can be catched in the set on session timeouts.
+        // Don't know a proper solution yet.
+        // Note that this is still under investigation.
+        Display display = ( Display )jobs.get( jobToRemove );
+        if( display != null ) {
+          RWT.getUISession( display ).exec( new Runnable() {
+            public void run() {
+              jobToRemove.cancel();
+              jobToRemove.addJobChangeListener( new JobCanceler() );
+            }
+          } );
+        }
+        try {
+          IJobManager jobManager = Job.getJobManager();
+          Class clazz = jobManager.getClass();
+          Field running = clazz.getDeclaredField( "running" );
+          running.setAccessible( true );
+          Set set = ( Set )running.get( jobManager );
+          synchronized( lock ) {
+            set.remove( job );
+            // still sometimes job get catched - use the job marker adapter
+            // to check whether they can be eliminated
+            Object[] runningJobs = set.toArray();
+            for( int i = 0; i < runningJobs.length; i++ ) {
+              Job toCheck = ( Job )runningJobs[ i ];
+              IJobMarker marker = ( IJobMarker )toCheck.getAdapter( IJobMarker.class );
+              if( marker != null && marker.canBeRemoved() ) {
+                set.remove( toCheck );
+              }
+            }
+          }
+        } catch( final Throwable thr ) {
+          // TODO [fappel]: exception handling
+          thr.printStackTrace();
+        }
+      }
+    };
+    uiSession.addUISessionListener( cleanupListener );
+    job.addJobChangeListener( new JobChangeAdapter() {
+      @Override
+      public void done( final IJobChangeEvent event ) {
+        jobDone.set( true );
+        uiSession.removeUISessionListener( cleanupListener );
+      }
+    } );
+  }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/progress/ProgressUtil.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/progress/ProgressUtil.java
new file mode 100644
index 0000000..4cb604d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/progress/ProgressUtil.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2002, 2012 Innoopract Informationssysteme GmbH 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:
+ *    Innoopract Informationssysteme GmbH - initial API and implementation
+ *    EclipseSource - ongoing development
+ ******************************************************************************/
+
+package org.eclipse.rap.ui.internal.progress;
+
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.PlatformUI;
+
+// RAP [fappel]:
+public final class ProgressUtil {
+  
+  private ProgressUtil() {
+    // prevent instance creation
+  }
+  
+  public static boolean isWorkbenchRunning( final Display display ) {
+    final boolean[] result = new boolean[ 1 ];
+    RWT.getUISession( display ).exec( new Runnable() {
+      public void run() {
+        result[ 0 ] = PlatformUI.isWorkbenchRunning();
+      }
+    } );
+    return result[ 0 ];
+  }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/servlet/HttpServiceTracker.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/servlet/HttpServiceTracker.java
new file mode 100644
index 0000000..641f75d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/servlet/HttpServiceTracker.java
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2013 EclipseSource 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:
+ *    Innoopract Informationssysteme GmbH - initial API and implementation
+ *    Frank Appel - replaced singletons and static fields (Bug 337787)
+ *    EclipseSource - ongoing implementation
+ ******************************************************************************/
+package org.eclipse.rap.ui.internal.servlet;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.equinox.http.registry.HttpContextExtensionService;
+import org.eclipse.rap.rwt.application.ApplicationConfiguration;
+import org.eclipse.rap.rwt.osgi.ApplicationReference;
+import org.eclipse.rap.rwt.osgi.ApplicationLauncher;
+import org.eclipse.ui.PlatformUI;
+import org.osgi.framework.*;
+import org.osgi.service.http.HttpContext;
+import org.osgi.service.http.HttpService;
+import org.osgi.util.tracker.ServiceTracker;
+
+
+public class HttpServiceTracker extends ServiceTracker<HttpService, HttpService> {
+
+  public static final String ID_HTTP_CONTEXT = "org.eclipse.rap.httpcontext";
+
+  private HttpContextExtensionService httpCtxExtService;
+  private HttpContextTracker httpContextTracker;
+  private ApplicationLauncherTracker applicationLauncherTracker;
+  private ApplicationLauncher applicationLauncher;
+  private ApplicationReference applicationReference;
+
+  public HttpServiceTracker( BundleContext context ) {
+    super( context, HttpService.class.getName(), null );
+  }
+
+  @Override
+  public HttpService addingService( ServiceReference<HttpService> reference ) {
+    HttpService result = context.getService( reference );
+    HttpContext httpContext = httpCtxExtService.getHttpContext( reference, ID_HTTP_CONTEXT );
+    applicationReference = startApplication( reference, result, httpContext );
+    return result;
+  }
+
+  @Override
+  public void removedService( ServiceReference<HttpService> reference, HttpService service ) {
+    applicationReference.stopApplication();
+    super.removedService( reference, service );
+  }
+
+  @Override
+  public void open() {
+    httpContextTracker = new HttpContextTracker( context );
+    httpContextTracker.open();
+  }
+
+  @Override
+  public void close() {
+    super.close();
+    httpContextTracker.close();
+  }
+
+  private ApplicationReference startApplication( ServiceReference<HttpService> httpServiceReference,
+                                                 HttpService service,
+                                                 HttpContext context )
+  {
+    ApplicationConfiguration configuration
+      = new WorkbenchApplicationConfiguration( httpServiceReference );
+    String contextDirectory = findContextPath().toString();
+    return applicationLauncher.launch( configuration, service, context, null, contextDirectory );
+  }
+
+  private static IPath findContextPath() {
+    Bundle bundle = Platform.getBundle( PlatformUI.PLUGIN_ID );
+    IPath stateLocation = Platform.getStateLocation( bundle );
+    return stateLocation.append( "context" );
+  }
+
+  private class HttpContextTracker
+    extends ServiceTracker<HttpContextExtensionService, HttpContextExtensionService>
+  {
+
+    private HttpContextTracker( BundleContext context ) {
+      super( context, HttpContextExtensionService.class.getName(), null );
+    }
+
+    @Override
+    public HttpContextExtensionService
+      addingService( ServiceReference<HttpContextExtensionService> reference )
+    {
+      HttpContextExtensionService result = super.addingService( reference );
+      httpCtxExtService = context.getService( reference );
+      applicationLauncherTracker = new ApplicationLauncherTracker( context );
+      applicationLauncherTracker.open();
+      return result;
+    }
+
+    @Override
+    public void removedService( ServiceReference<HttpContextExtensionService> reference,
+                                HttpContextExtensionService service )
+    {
+      applicationLauncherTracker.close();
+      httpCtxExtService = null;
+      super.removedService( reference, service );
+    }
+  }
+
+  private class ApplicationLauncherTracker
+    extends ServiceTracker<ApplicationLauncher, ApplicationLauncher>
+  {
+
+    private ApplicationLauncherTracker( BundleContext context ) {
+      super( context, ApplicationLauncher.class.getName(), null );
+    }
+
+    @Override
+    public ApplicationLauncher addingService( ServiceReference<ApplicationLauncher> reference ) {
+      ApplicationLauncher result = super.addingService( reference );
+      applicationLauncher = context.getService( reference );
+      HttpServiceTracker.super.open();
+      return result;
+    }
+
+    @Override
+    public void removedService( ServiceReference<ApplicationLauncher> reference,
+                                ApplicationLauncher service )
+    {
+      applicationLauncher = null;
+      super.removedService( reference, service );
+    }
+  }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/servlet/ResourceReader.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/servlet/ResourceReader.java
new file mode 100644
index 0000000..930ad0e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/servlet/ResourceReader.java
@@ -0,0 +1,129 @@
+/*******************************************************************************
+ * Copyright (c) 2012 EclipseSource 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:
+ *    EclipseSource - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.rap.ui.internal.servlet;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.rap.ui.resources.IResource;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+
+
+class ResourceReader {
+
+  private static final String ID_RESOURCES = "org.eclipse.rap.ui.resources";
+
+  public static List<IResource> readResources() {
+    DependentResource[] resources = readResourcesFromExtensions();
+    DependentResource[] sortedResources = sortResources( resources );
+    return createResourceList( sortedResources );
+  }
+
+  private static DependentResource[] readResourcesFromExtensions() {
+    IExtensionRegistry registry = Platform.getExtensionRegistry();
+    IExtensionPoint point = registry.getExtensionPoint( ID_RESOURCES );
+    IConfigurationElement[] elements = point.getConfigurationElements();
+    DependentResource[] resources = new DependentResource[ elements.length ];
+    for( int i = 0; i < elements.length; i++ ) {
+      try {
+        IResource resource = ( IResource )elements[ i ].createExecutableExtension( "class" );
+        String resourceId = elements[ i ].getAttribute( "id" );
+        IConfigurationElement[] dependsOn = elements[ i ].getChildren( "dependsOn" );
+        List<String> resourceDependencies = new ArrayList<String>();
+        for( int j = 0; j < dependsOn.length; j++ ) {
+          String dependency = dependsOn[ j ].getAttribute( "resourceId" );
+          resourceDependencies.add( dependency );
+        }
+        resources[ i ] = new DependentResource( resource, resourceId, resourceDependencies );
+      } catch( CoreException ce ) {
+        WorkbenchPlugin.getDefault().getLog().log( ce.getStatus() );
+      }
+    }
+    return resources;
+  }
+
+  private static DependentResource[] sortResources( DependentResource[] resources ) {
+    DependentResource[] result = new DependentResource[ resources.length ];
+    List<String> sortedResourceIds = new ArrayList<String>();
+    List<DependentResource> deferredResources = new ArrayList<DependentResource>();
+    int index = 0;
+    for( int i = 0; i < resources.length; i++ ) {
+      DependentResource resource = resources[ i ];
+      if( resource != null ) {
+        resource.dependencies.removeAll( sortedResourceIds );
+        boolean checkDeferredResources = false;
+        if( resource.dependencies.isEmpty() ) {
+          result[ index++ ] = resource;
+          sortedResourceIds.add( resource.id );
+          checkDeferredResources = true;
+        } else {
+          deferredResources.add( resource );
+        }
+        while( checkDeferredResources ) {
+          checkDeferredResources = false;
+          Iterator<DependentResource> iterator = deferredResources.iterator();
+          while( iterator.hasNext() ) {
+            DependentResource deferredResource = iterator.next();
+            deferredResource.dependencies.removeAll( sortedResourceIds );
+            if( deferredResource.dependencies.isEmpty() ) {
+              result[ index++ ] = deferredResource;
+              sortedResourceIds.add( deferredResource.id );
+              iterator.remove();
+              checkDeferredResources = true;
+            }
+          }
+        }
+      }
+    }
+    if( deferredResources.size() != 0 ) {
+      String pluginId = WorkbenchPlugin.getDefault().getBundle().getSymbolicName();
+      String message = "Dependencies could not be resolved for " + deferredResources;
+      WorkbenchPlugin.getDefault().getLog().log( new Status( IStatus.ERROR, pluginId, message ) );
+    }
+    return result;
+  }
+
+  private static List<IResource> createResourceList( DependentResource[] sortedResources ) {
+    List<IResource> result = new ArrayList<IResource>();
+    for( DependentResource dependentResource : sortedResources ) {
+      result.add( dependentResource.resource );
+    }
+    return result;
+  }
+
+  private static final class DependentResource {
+
+    public final IResource resource;
+    public final String id;
+    public final List<String> dependencies;
+
+    public DependentResource( IResource resource, String id, List<String> dependencies ) {
+      this.resource = resource;
+      this.id = id;
+      this.dependencies = dependencies;
+    }
+
+    @Override
+    public String toString() {
+      return id != null ? id : resource.getClass().getName();
+    }
+
+  }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/servlet/ResourceRegisterer.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/servlet/ResourceRegisterer.java
new file mode 100644
index 0000000..92bbab5
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/servlet/ResourceRegisterer.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) 2012 EclipseSource 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:
+ *    EclipseSource - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.rap.ui.internal.servlet;
+
+import java.io.InputStream;
+import java.util.List;
+
+import org.eclipse.rap.rwt.application.Application;
+import org.eclipse.rap.rwt.internal.application.ApplicationContextImpl;
+import org.eclipse.rap.rwt.internal.application.ApplicationImpl;
+import org.eclipse.rap.rwt.internal.resources.ContentBuffer;
+import org.eclipse.rap.rwt.service.ResourceLoader;
+import org.eclipse.rap.ui.resources.IResource;
+
+
+class ResourceRegisterer {
+
+  private final Application application;
+  private final ApplicationContextImpl applicationContext;
+  private final ContentBuffer concatenatedScript;
+
+  public ResourceRegisterer( Application application ) {
+    this.application = application;
+    applicationContext = ( ( ApplicationImpl )application ).getApplicationContext();
+    concatenatedScript = new ContentBuffer();
+  }
+
+  public void registerResources( List<IResource> resources ) {
+    for( IResource resource : resources ) {
+      if( resource != null ) {
+        registerResource( resource );
+      }
+    }
+    if( concatenatedScript.getContent().length > 0 ) {
+      registerConcatenatedScript();
+    }
+  }
+
+  private void registerResource( IResource resource ) {
+    if( resource.isExternal() ) {
+      applicationContext.getStartupPage().addJsLibrary( resource.getLocation() );
+    } else if( resource.isJSLibrary() ) {
+      appendToConcatenatedScript( resource );
+    } else {
+      String location = resource.getLocation();
+      application.addResource( location, new WorkbenchResourceLoader( resource ) );
+    }
+  }
+
+  private void appendToConcatenatedScript( IResource resource ) {
+    try {
+      concatenatedScript.append( resource.getLoader().getResourceAsStream( resource.getLocation() ) );
+    } catch( Exception exception ) {
+      String message = "Failed to load resource: " + resource.getLocation();
+      throw new IllegalArgumentException( message, exception );
+    }
+  }
+
+  private void registerConcatenatedScript() {
+    application.addResource( "resources.js", new ResourceLoader() {
+      public InputStream getResourceAsStream( String resourceName ) {
+        return concatenatedScript.getContentAsStream();
+      }
+    } );
+    applicationContext.getStartupPage().addJsLibrary( "rwt-resources/resources.js" );
+  }
+
+  private static class WorkbenchResourceLoader implements ResourceLoader {
+
+    private final IResource resource;
+
+    private WorkbenchResourceLoader( IResource resource ) {
+      this.resource = resource;
+    }
+
+    public InputStream getResourceAsStream( String resourceName ) {
+      return resource.getLoader().getResourceAsStream( resource.getLocation() );
+    }
+  }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/servlet/WorkbenchApplicationConfiguration.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/servlet/WorkbenchApplicationConfiguration.java
new file mode 100644
index 0000000..426d468
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/internal/servlet/WorkbenchApplicationConfiguration.java
@@ -0,0 +1,369 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2014 EclipseSource 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:
+ *    Innoopract Informationssysteme GmbH - initial API and implementation
+ *    EclipseSource - ongoing development
+ *    Frank Appel - replaced singletons and static fields (Bug 337787)
+ ******************************************************************************/
+package org.eclipse.rap.ui.internal.servlet;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.text.MessageFormat;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.equinox.app.IApplication;
+import org.eclipse.rap.rwt.application.Application;
+import org.eclipse.rap.rwt.application.Application.OperationMode;
+import org.eclipse.rap.rwt.application.ApplicationConfiguration;
+import org.eclipse.rap.rwt.application.EntryPoint;
+import org.eclipse.rap.rwt.application.EntryPointFactory;
+import org.eclipse.rap.rwt.client.WebClient;
+import org.eclipse.rap.rwt.internal.lifecycle.DefaultEntryPointFactory;
+import org.eclipse.rap.rwt.service.ResourceLoader;
+import org.eclipse.rap.rwt.service.ServiceHandler;
+import org.eclipse.rap.rwt.service.SettingStoreFactory;
+import org.eclipse.rap.ui.internal.application.EntryPointApplicationWrapper;
+import org.eclipse.rap.ui.internal.branding.AbstractBranding;
+import org.eclipse.rap.ui.internal.branding.BrandingExtension;
+import org.eclipse.rap.ui.internal.branding.BrandingManager;
+import org.eclipse.rap.ui.internal.branding.BrandingUtil;
+import org.eclipse.rap.ui.internal.preferences.WorkbenchFileSettingStoreFactory;
+import org.eclipse.rap.ui.resources.IResource;
+import org.eclipse.swt.widgets.Widget;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.http.HttpService;
+
+
+public class WorkbenchApplicationConfiguration implements ApplicationConfiguration {
+
+  private static final String ID_ENTRY_POINT = "org.eclipse.rap.ui.entrypoint";
+  private static final String ID_THEMES = "org.eclipse.rap.ui.themes";
+  private static final String ELEMENT_THEME = "theme";
+  private static final String ELEMENT_THEME_CONTRIBUTION = "themeContribution";
+  private static final String ID_THEMEABLE_WIDGETS = "org.eclipse.rap.ui.themeableWidgets";
+  private static final String ID_SERVICE_HANDLER = "org.eclipse.rap.ui.serviceHandler";
+  private static final String ID_SETTING_STORES = "org.eclipse.rap.ui.settingstores";
+
+  private static final String PROP_SETTING_STORES_FACTORY
+    = "org.eclipse.rap.rwt.settingStoreFactory";
+
+  private static final String RUN = "run"; //$NON-NLS-1$
+  private static final String PI_RUNTIME = "org.eclipse.core.runtime"; //$NON-NLS-1$
+  private static final String PT_APPLICATIONS = "applications"; //$NON-NLS-1$
+  private static final String PT_APP_VISIBLE = "visible"; //$NON-NLS-1$
+
+  private final ServiceReference<HttpService> httpServiceReference;
+
+  // Default constructor to enable subclassing without adding a dependency to OSGi API
+  public WorkbenchApplicationConfiguration() {
+    httpServiceReference = null;
+  }
+
+  /*
+   * Note [rst]: public as per request in https://bugs.eclipse.org/bugs/show_bug.cgi?id=372183
+   */
+  public WorkbenchApplicationConfiguration( ServiceReference<HttpService> httpServiceReference ) {
+    this.httpServiceReference = httpServiceReference;
+  }
+
+  public void configure( Application application ) {
+    application.setOperationMode( OperationMode.SWT_COMPATIBILITY );
+    registerSettingStoreFactory( application );
+    registerThemeableWidgets( application );
+    registerThemes( application );
+    registerThemeContributions( application );
+    registerResources( application );
+    registerServiceHandlers( application );
+    registerBrandings( application ); // [rh] brandings must be red before apps/entry points
+    registerEntryPoints( application );
+  }
+
+  private void registerSettingStoreFactory( Application application ) {
+    // determine which factory to use via an environment setting / config.ini
+    SettingStoreFactory result = null;
+    String factoryId = getOSGiProperty( PROP_SETTING_STORES_FACTORY );
+    if( factoryId != null ) {
+      result = loadSettingStoreFactory( factoryId );
+    }
+    if( result == null ) {
+      result = new WorkbenchFileSettingStoreFactory(); // default
+    }
+    application.setSettingStoreFactory( result );
+  }
+
+  private SettingStoreFactory loadSettingStoreFactory( String factoryId ) {
+    SettingStoreFactory result = null;
+    IExtensionRegistry registry = Platform.getExtensionRegistry();
+    IExtensionPoint point = registry.getExtensionPoint( ID_SETTING_STORES );
+    IConfigurationElement[] elements = point.getConfigurationElements();
+    for( int i = 0; i < elements.length; i++ ) {
+      String id = elements[ i ].getAttribute( "id" );
+      if( factoryId.equals( id ) ) {
+        result = loadSettingStoreFactory( elements[ i ] );
+      }
+    }
+    if( result == null ) {
+      String msg = "Unable to find setting store factory with id '" + factoryId + "'.";
+      WorkbenchPlugin.log( msg );
+    }
+    return result;
+  }
+
+  private SettingStoreFactory loadSettingStoreFactory( IConfigurationElement element ) {
+    SettingStoreFactory result = null;
+    try {
+      result = ( SettingStoreFactory )element.createExecutableExtension( "class" );
+    } catch( CoreException cex ) {
+      WorkbenchPlugin.log( cex.getStatus() );
+    }
+    return result;
+  }
+
+  private static String getOSGiProperty( String name ) {
+    Bundle systemBundle = Platform.getBundle( Constants.SYSTEM_BUNDLE_SYMBOLICNAME );
+    return systemBundle.getBundleContext().getProperty( name );
+  }
+
+  @SuppressWarnings( "unchecked" )
+  private void registerEntryPoints( Application application ) {
+    for( IConfigurationElement element : getEntryPointExtensions() ) {
+      String id = element.getAttribute( "id" );
+      String path = element.getAttribute( "path" );
+      String className = element.getAttribute( "class" );
+      String applicationId = element.getAttribute( "applicationId" );
+      String brandingId = element.getAttribute( "brandingId" );
+      try {
+        EntryPointFactory entryPointFactory;
+        if( className != null ) {
+          Class<? extends EntryPoint> entryPointClass = loadClass( className, element );
+          entryPointFactory = new DefaultEntryPointFactory( entryPointClass );
+        } else if( applicationId != null ) {
+          entryPointFactory = createEntryPointFactoryForApplication( applicationId );
+        } else {
+          throw new IllegalArgumentException( "Neither class nor applicationId specified" );
+        }
+        Map<String, String> properties = getBrandingProperties( brandingId );
+        application.addEntryPoint( path, entryPointFactory, properties );
+      } catch( final Throwable thr ) {
+        String text = "Could not register entry point ''{0}'' with id ''{1}''.";
+        Object[] param = new Object[] { className, id };
+        logProblem( text, param, thr, element.getContributor().getName() );
+      }
+    }
+  }
+
+  @SuppressWarnings( "unchecked" )
+  private EntryPointFactory createEntryPointFactoryForApplication( String applicationId )
+    throws ClassNotFoundException
+  {
+    IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry();
+    String extensionPointId = PI_RUNTIME + '.' + PT_APPLICATIONS;
+    IExtension extension = extensionRegistry.getExtension( extensionPointId, applicationId );
+    if( extension == null ) {
+      String message = "Application extension not found by id: " + applicationId;
+      throw new IllegalArgumentException( message );
+    }
+    IConfigurationElement configElement = extension.getConfigurationElements()[ 0 ];
+    String isVisible = configElement.getAttribute( PT_APP_VISIBLE );
+    if( isVisible != null && !Boolean.valueOf( isVisible ).booleanValue() ) {
+      throw new IllegalArgumentException( "Application is not visible:" + applicationId );
+    }
+    IConfigurationElement[] runElement = configElement.getChildren( RUN );
+    String className = runElement[ 0 ].getAttribute( "class" ); //$NON-NLS-1$
+    Class<? extends IApplication> applicationClass = loadClass( className, configElement );
+    return createApplicationEntryPointFactory( applicationClass );
+  }
+
+  private static EntryPointFactory
+    createApplicationEntryPointFactory( final Class<? extends IApplication> applicationClass )
+  {
+    return new EntryPointFactory() {
+      public EntryPoint create() {
+        return new EntryPointApplicationWrapper( applicationClass );
+      }
+    };
+  }
+
+  @SuppressWarnings( "unchecked" )
+  private void registerThemeableWidgets( Application application ) {
+    IExtensionRegistry registry = Platform.getExtensionRegistry();
+    IExtensionPoint ep = registry.getExtensionPoint( ID_THEMEABLE_WIDGETS );
+    IConfigurationElement[] widgetExts = ep.getConfigurationElements();
+    for( int i = 0; i < widgetExts.length; i++ ) {
+      String contributorName = widgetExts[ i ].getContributor().getName();
+      String widgetClass = widgetExts[ i ].getAttribute( "class" );
+      try {
+        final Bundle bundle = Platform.getBundle( contributorName );
+        Class<? extends Widget> widget = (Class<? extends Widget>)bundle.loadClass( widgetClass );
+        application.addThemeableWidget( widget );
+      } catch( final Throwable thr ) {
+        String text = "Could not register themeable widget ''{0}''.";
+        Object[] param = new Object[] { widgetClass };
+        logProblem( text, param, thr, contributorName );
+      }
+    }
+  }
+
+  private void registerThemes( Application application ) {
+    IExtensionRegistry registry = Platform.getExtensionRegistry();
+    IExtensionPoint ep = registry.getExtensionPoint( ID_THEMES );
+    IConfigurationElement[] elements = ep.getConfigurationElements();
+    for( int i = 0; i < elements.length; i++ ) {
+      if( ELEMENT_THEME.equals( elements[ i ].getName() ) ) {
+        String contributorName = elements[ i ].getContributor().getName();
+        String themeId = elements[ i ].getAttribute( "id" );
+        String themeFile = elements[ i ].getAttribute( "file" );
+        try {
+          Bundle bundle = Platform.getBundle( contributorName );
+          ResourceLoader resourceLoader = createThemeResourceLoader( bundle );
+          application.addStyleSheet( themeId, themeFile, resourceLoader );
+        } catch( final Exception e ) {
+          String text = "Could not register custom theme ''{0}'' from file ''{1}''.";
+          Object[] param = new Object[] { themeId, themeFile };
+          logProblem( text, param, e, contributorName );
+        }
+      }
+    }
+  }
+
+  private void registerThemeContributions( Application application ) {
+    IExtensionRegistry registry = Platform.getExtensionRegistry();
+    IExtensionPoint ep = registry.getExtensionPoint( ID_THEMES );
+    IConfigurationElement[] elements = ep.getConfigurationElements();
+    for( int i = 0; i < elements.length; i++ ) {
+      if( ELEMENT_THEME_CONTRIBUTION.equals( elements[ i ].getName() ) ) {
+        String contributorName = elements[ i ].getContributor().getName();
+        String themeId = elements[ i ].getAttribute( "themeId" );
+        String themeFile = elements[ i ].getAttribute( "file" );
+        try {
+          Bundle bundle = Platform.getBundle( contributorName );
+          ResourceLoader loader = createThemeResourceLoader( bundle );
+          application.addStyleSheet( themeId, themeFile, loader );
+        } catch( final Exception e ) {
+          String text = "Could not register contribution for theme ''{0}'' from file ''{1}''.";
+          Object[] param = new Object[] { themeId, themeFile };
+          logProblem( text, param, e, contributorName );
+        }
+      }
+    }
+  }
+
+  private static void registerResources( Application application ) {
+    List<IResource> resources = ResourceReader.readResources();
+    new ResourceRegisterer( application ).registerResources( resources );
+  }
+
+  private static ResourceLoader createThemeResourceLoader( final Bundle bundle ) {
+    ResourceLoader result = new ResourceLoader() {
+      public InputStream getResourceAsStream( final String resourceName ) throws IOException {
+        InputStream result = null;
+        IPath path = new Path( resourceName );
+        URL url = FileLocator.find( bundle, path, null );
+        if( url != null ) {
+          result = url.openStream();
+        }
+        return result;
+      }
+    };
+    return result;
+  }
+
+  private void registerServiceHandlers( Application application ) {
+    IExtensionRegistry registry = Platform.getExtensionRegistry();
+    IExtensionPoint point = registry.getExtensionPoint( ID_SERVICE_HANDLER );
+    IConfigurationElement[] elements = point.getConfigurationElements();
+    for( int i = 0; i < elements.length; i++ ) {
+      try {
+        String id = elements[ i ].getAttribute( "id" );
+        if( id != null ) {
+          Object extObject = elements[ i ].createExecutableExtension( "class" );
+          ServiceHandler handler = ( ServiceHandler )extObject;
+          application.addServiceHandler( id, handler );
+        }
+      } catch( final CoreException ce ) {
+        WorkbenchPlugin.getDefault().getLog().log( ce.getStatus() );
+      }
+    }
+  }
+
+  private void registerBrandings( Application application ) {
+    try {
+      new BrandingExtension( application, httpServiceReference ).read();
+    } catch( final IOException ioe ) {
+      throw new RuntimeException( "Unable to read branding extension", ioe );
+    }
+  }
+
+  private static AbstractBranding findBrandingById( String id ) {
+    AbstractBranding result = null;
+    AbstractBranding[] brandings = BrandingManager.getInstance().getAll();
+    for( AbstractBranding branding : brandings ) {
+      if( branding.getId() != null && branding.getId().equals( id ) ) {
+        result = branding;
+      }
+    }
+    return result;
+  }
+
+  private Map<String, String> getBrandingProperties( String brandingId ) {
+    AbstractBranding branding = findBrandingById( brandingId );
+    Map<String, String> result = new HashMap<String, String>();
+    result.put( BrandingUtil.ENTRY_POINT_BRANDING, brandingId );
+    if( branding != null ) {
+      result.put( WebClient.THEME_ID, branding.getThemeId() );
+      result.put( WebClient.BODY_HTML, branding.getBody() );
+      result.put( WebClient.PAGE_TITLE, branding.getTitle() );
+      result.put( WebClient.FAVICON, branding.getFavIcon() );
+      result.put( WebClient.HEAD_HTML, BrandingUtil.headerMarkup( branding ) );
+    }
+    return result;
+  }
+
+  private static IConfigurationElement[] getEntryPointExtensions() {
+    IExtensionRegistry registry = Platform.getExtensionRegistry();
+    IExtensionPoint extensionPoint = registry.getExtensionPoint( ID_ENTRY_POINT );
+    IConfigurationElement[] elements = extensionPoint.getConfigurationElements();
+    return elements;
+  }
+
+  private static void logProblem( String text,
+                                  Object[] textParams,
+                                  Throwable problem,
+                                  String bundleId )
+  {
+    String msg = MessageFormat.format( text, textParams );
+    Status status = new Status( IStatus.ERROR, bundleId, IStatus.OK, msg, problem );
+    WorkbenchPlugin.getDefault().getLog().log( status );
+  }
+
+  private static <T> T loadClass( String className, IConfigurationElement element )
+    throws ClassNotFoundException
+  {
+    Bundle bundle = Platform.getBundle( element.getContributor().getName() );
+    return ( T )bundle.loadClass( className );
+  }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/partdnd/DetachPartProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/partdnd/DetachPartProvider.java
new file mode 100644
index 0000000..6bfa09d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/partdnd/DetachPartProvider.java
@@ -0,0 +1,578 @@
+/*******************************************************************************

+ * Copyright (c) 2017 David Marina

+ * 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:

+ *   David Marina - initial API and implementation

+ *******************************************************************************/

+package org.eclipse.rap.ui.partdnd;

+

+import org.eclipse.e4.ui.model.application.ui.MElementContainer;

+import org.eclipse.e4.ui.model.application.ui.MUIElement;

+import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective;

+import org.eclipse.e4.ui.model.application.ui.advanced.MPlaceholder;

+import org.eclipse.e4.ui.model.application.ui.basic.MPart;

+import org.eclipse.e4.ui.model.application.ui.basic.MPartSashContainer;

+import org.eclipse.e4.ui.model.application.ui.basic.MPartSashContainerElement;

+import org.eclipse.e4.ui.model.application.ui.basic.MPartStack;

+import org.eclipse.e4.ui.model.application.ui.basic.MWindow;

+import org.eclipse.e4.ui.workbench.modeling.EModelService;

+import org.eclipse.rap.rwt.SingletonUtil;

+import org.eclipse.rap.ui.partdnd.internal.PartTransfer;

+import org.eclipse.rap.ui.partdnd.internal.WorkaroundDragPartSource;

+import org.eclipse.swt.SWT;

+import org.eclipse.swt.custom.CTabFolder;

+import org.eclipse.swt.custom.CTabItem;

+import org.eclipse.swt.dnd.DND;

+import org.eclipse.swt.dnd.DragSource;

+import org.eclipse.swt.dnd.DragSourceEvent;

+import org.eclipse.swt.dnd.DragSourceListener;

+import org.eclipse.swt.dnd.DropTarget;

+import org.eclipse.swt.dnd.DropTargetEvent;

+import org.eclipse.swt.dnd.DropTargetListener;

+import org.eclipse.swt.dnd.Transfer;

+import org.eclipse.swt.events.SelectionAdapter;

+import org.eclipse.swt.events.SelectionEvent;

+import org.eclipse.swt.graphics.Point;

+import org.eclipse.swt.widgets.Composite;

+import org.eclipse.swt.widgets.Control;

+import org.eclipse.swt.widgets.Menu;

+import org.eclipse.swt.widgets.MenuItem;

+import org.eclipse.swt.widgets.Shell;

+import org.eclipse.ui.IPartListener2;

+import org.eclipse.ui.IWorkbenchPage;

+import org.eclipse.ui.IWorkbenchPart;

+import org.eclipse.ui.IWorkbenchPartReference;

+import org.eclipse.ui.internal.WorkbenchPartReference;

+import org.eclipse.ui.internal.e4.compatibility.CompatibilityPart;

+import org.eclipse.ui.views.IViewDescriptor;

+

+

+/**

+ * Listener for setting drag and drop capabilities to the Compatibility Parts, which allows to

+ * rearrange the parts in the workbench

+ * 

+ * @author David Marina

+ */

+public class DetachPartProvider implements IPartListener2 {

+

+  /** The reference to the user singleton for this listener */

+  public static final DetachPartProvider INSTANCE = SingletonUtil.getSessionInstance( DetachPartProvider.class );

+  /** Tag for shell_detach_parts_menu */

+  private static final String SHELL_DETACH_PARTS_MENU = "shell_detach_parts_menu"; //$NON-NLS-1$

+  /** Tag for stack_selected_part */

+  private static final String STACK_SELECTED_PART = "stack_selected_part"; //$NON-NLS-1$

+  /** The reference to the model service */

+  private EModelService modelService = null;

+

+  /**

+   * Creates a new DetachPartProvider

+   */

+  private DetachPartProvider() {

+  }

+

+  /**

+   * Applies this listener to the given workbench page

+   * 

+   * @param page the reference to the workbench page where this listener will be applied

+   */

+  public static void applyListenerTo( IWorkbenchPage page ) {

+    page.addPartListener( INSTANCE );

+  }

+

+  /** {@inheritDoc} */

+  @Override

+  public void partActivated( IWorkbenchPartReference partRef ) {

+    // Add detach listener to tab item if not present yet

+    applyDetachPartListeners( ( ( WorkbenchPartReference )partRef ).getModel() );

+  }

+

+  /** {@inheritDoc} */

+  @Override

+  public void partBroughtToTop( IWorkbenchPartReference partRef ) {

+    // do nothing

+  }

+

+  /** {@inheritDoc} */

+  @Override

+  public void partClosed( IWorkbenchPartReference partRef ) {

+    // do nothing

+  }

+

+  /** {@inheritDoc} */

+  @Override

+  public void partDeactivated( IWorkbenchPartReference partRef ) {

+    // do nothing

+  }

+

+  /** {@inheritDoc} */

+  @Override

+  public void partOpened( IWorkbenchPartReference partRef ) {

+    // do nothing

+  }

+

+  /** {@inheritDoc} */

+  @Override

+  public void partHidden( IWorkbenchPartReference partRef ) {

+    // do nothing

+  }

+

+  /** {@inheritDoc} */

+  @Override

+  public void partVisible( IWorkbenchPartReference partRef ) {

+    // Add detach listener to tab item if not present yet

+    applyDetachPartListeners( ( ( WorkbenchPartReference )partRef ).getModel() );

+  }

+

+  /** {@inheritDoc} */

+  @Override

+  public void partInputChanged( IWorkbenchPartReference partRef ) {

+    // do nothing

+  }

+

+  /**

+   * Attaches drag and drop listeners to the CTabFolder that is the parent of the given Part, such

+   * as the Parts can be rearranged into different locations of the application.

+   * 

+   * @param part the reference to the part that will attach the drag and drop listeners

+   */

+  private void applyDetachPartListeners( MPart part ) {

+    Object client = part.getObject();

+    if( !( client instanceof CompatibilityPart ) ) {

+      String msg = "Tried to apply DetachPartProvider on a part that is not a Compatibility Part.";

+      System.err.println( msg );

+      return;

+    }

+    Composite parentComposite = part.getContext().get( Composite.class );

+    Composite comp = parentComposite.getParent();

+    while( comp != null && !( comp instanceof CTabFolder ) ) {

+      comp = comp.getParent();

+    }

+    if( comp == null ) {

+      return;

+    }

+    CTabFolder ctf = ( CTabFolder )comp;

+    // Avoid setting multiple times the drag functionality

+    if( ctf.getData( DND.DRAG_SOURCE_KEY ) != null ) {

+      return;

+    }

+    this.modelService = part.getContext().get( EModelService.class );

+    DragSource ds = new WorkaroundDragPartSource( ctf, DND.DROP_COPY | DND.DROP_MOVE );

+    ds.setTransfer( new Transfer[] {

+      PartTransfer.INSTANCE

+    } );

+    ds.addDragListener( new DragSourceListener() {

+

+      /** The serialVersionUID of this DetachPartProvider.java */

+      private static final long serialVersionUID = -3293045502426919932L;

+      private Point dragStartCoordinates = null;

+

+      /** {@inheritDoc} */

+      @Override

+      public void dragStart( DragSourceEvent event ) {

+        Point absolutePoint = new Point( event.x, event.y );

+        this.dragStartCoordinates = absolutePoint;

+        CTabItem item = ctf.getItem( absolutePoint );

+        if( item == null || item != null && !item.getShowClose() ) {

+          event.doit = false;

+        }

+      }

+

+      /** {@inheritDoc} */

+      @Override

+      public void dragSetData( DragSourceEvent event ) {

+        CTabItem eventTabItem = ctf.getItem( this.dragStartCoordinates );

+        if( eventTabItem != null ) {

+          MUIElement uiElement = ( MUIElement )eventTabItem.getData( "modelElement" );

+          MPart tabPart = ( MPart )( ( uiElement instanceof MPart )

+                                                                   ? uiElement

+                                                                   : ( ( MPlaceholder )uiElement ).getRef() );

+          event.data = tabPart;

+        }

+      }

+

+      /** {@inheritDoc} */

+      @Override

+      public void dragFinished( DragSourceEvent event ) {

+        // Do nothing

+      }

+    } );

+    DropTarget dt = new DropTarget( ctf, DND.DROP_DEFAULT | DND.DROP_COPY | DND.DROP_MOVE );

+    dt.setTransfer( new Transfer[] {

+      PartTransfer.INSTANCE

+    } );

+    dt.addDropListener( new DropTargetListener() {

+

+      /** The serialVersionUID of this DetachPartProvider.java */

+      private static final long serialVersionUID = -574998030394417101L;

+

+      /** {@inheritDoc} */

+      @Override

+      public void dropAccept( DropTargetEvent event ) {

+        // Do nothing

+      }

+

+      /** {@inheritDoc} */

+      @Override

+      public void drop( DropTargetEvent event ) {

+        Point absolutePoint = new Point( event.x, event.y );

+        Point relativePoint = ctf.getDisplay().map( null, ctf, absolutePoint );

+        CTabItem eventTabItem = ctf.getItem( relativePoint );

+        if( eventTabItem == null ) {

+          eventTabItem = ctf.getSelection();

+          MUIElement uiElement = ( MUIElement )eventTabItem.getData( "modelElement" );

+          MPart tabPart = ( MPart )( ( uiElement instanceof MPart )

+                                                                   ? uiElement

+                                                                   : ( ( MPlaceholder )uiElement ).getRef() );

+          moveToPartStack( ( MPart )event.data, tabPart );

+        } else {

+          MUIElement uiElement = ( MUIElement )eventTabItem.getData( "modelElement" );

+          MPart tabPart = ( MPart )( ( uiElement instanceof MPart )

+                                                                   ? uiElement

+                                                                   : ( ( MPlaceholder )uiElement ).getRef() );

+          createMovePartContextMenu( absolutePoint, ctf, ( MPart )event.data, tabPart );

+          // movePart((MPart)event.data, tabPart);

+        }

+      }

+

+      /** {@inheritDoc} */

+      @Override

+      public void dragOver( DropTargetEvent event ) {

+        // Do nothing

+      }

+

+      /** {@inheritDoc} */

+      @Override

+      public void dragOperationChanged( DropTargetEvent event ) {

+        // Do nothing

+      }

+

+      /** {@inheritDoc} */

+      @Override

+      public void dragLeave( DropTargetEvent event ) {

+        // Do nothing

+      }

+

+      /** {@inheritDoc} */

+      @Override

+      public void dragEnter( DropTargetEvent event ) {

+        // Do nothing

+      }

+    } );

+  }

+

+  /**

+   * Creates and shows the menu with all the detach options at the given location

+   * 

+   * @param location the menu location

+   * @param control the control owner of the menu

+   * @param partToBeMoved the part that is to be moved

+   * @param destinationRefPart the reference part for placing the dragged part

+   */

+  private void createMovePartContextMenu( Point location,

+                                          Control control,

+                                          MPart partToBeMoved,

+                                          MPart destinationRefPart )

+  {

+    Menu menu = createDetachMenu( control, partToBeMoved );

+    menu.setData( STACK_SELECTED_PART, destinationRefPart );

+    menu.setLocation( location );

+    menu.setVisible( true );

+  }

+

+  /**

+   * Creates and fills the part detach menu

+   * 

+   * @param control the reference to the control that will own the menu

+   * @param partToBeMoved the reference to the part to be moved

+   * @return the reference to the detach menu filled with all the menu items

+   */

+  private Menu createDetachMenu( Control control, MPart partToBeMoved ) {

+    Shell shell = control.getShell();

+    Menu cachedMenu = ( Menu )shell.getData( SHELL_DETACH_PARTS_MENU );

+    if( cachedMenu == null ) {

+      cachedMenu = new Menu( control );

+      shell.setData( SHELL_DETACH_PARTS_MENU, cachedMenu );

+    } else {

+      for( MenuItem item : cachedMenu.getItems() ) {

+        item.dispose();

+      }

+    }

+    final Menu menu = cachedMenu;

+    populateDetachMenu( menu, partToBeMoved );

+    return menu;

+  }

+

+  /**

+   * Populate the tab's context menu for the given part.

+   *

+   * @param menu the menu to be populated

+   * @param partToBeMoved the relevant part

+   */

+  private void populateDetachMenu( final Menu menu, MPart partToBeMoved ) {

+    // Insert into Part Stack option

+    MenuItem menuItemAddToStack = new MenuItem( menu, SWT.NONE );

+    menuItemAddToStack.setText( "Insert into Part Stack" );

+    menuItemAddToStack.addSelectionListener( new SelectionAdapter() {

+

+      /**

+                 *

+                 */

+      private static final long serialVersionUID = 1L;

+

+      @Override

+      public void widgetSelected( SelectionEvent e ) {

+        MPart part = ( MPart )menu.getData( STACK_SELECTED_PART );

+        moveToPartStack( partToBeMoved, part );

+      }

+    } );

+    // Move Beside this Part options

+    MenuItem moveItem = new MenuItem( menu, SWT.CASCADE );

+    moveItem.setText( "Move Beside this Part" );

+    Menu subMenu = new Menu( menu );

+    moveItem.setMenu( subMenu );

+    MenuItem menuItemMoveAbovePart = new MenuItem( subMenu, SWT.NONE );

+    menuItemMoveAbovePart.setText( "Above" );

+    menuItemMoveAbovePart.addSelectionListener( new SelectionAdapter() {

+

+      /** The serialVersionUID of this DetachPartProvider.java */

+      private static final long serialVersionUID = 1L;

+

+      @Override

+      public void widgetSelected( SelectionEvent e ) {

+        MPart part = ( MPart )menu.getData( STACK_SELECTED_PART );

+        moveBeside( partToBeMoved, part, EModelService.ABOVE );

+      }

+    } );

+    MenuItem menuItemMoveBelowPart = new MenuItem( subMenu, SWT.NONE );

+    menuItemMoveBelowPart.setText( "Below" );

+    menuItemMoveBelowPart.addSelectionListener( new SelectionAdapter() {

+

+      /** The serialVersionUID of this DetachPartProvider.java */

+      private static final long serialVersionUID = 1L;

+

+      @Override

+      public void widgetSelected( SelectionEvent e ) {

+        MPart part = ( MPart )menu.getData( STACK_SELECTED_PART );

+        moveBeside( partToBeMoved, part, EModelService.BELOW );

+      }

+    } );

+    MenuItem menuItemMoveLeftOfPart = new MenuItem( subMenu, SWT.NONE );

+    menuItemMoveLeftOfPart.setText( "to the Left" );

+    menuItemMoveLeftOfPart.addSelectionListener( new SelectionAdapter() {

+

+      /** The serialVersionUID of this DetachPartProvider.java */

+      private static final long serialVersionUID = 1L;

+

+      @Override

+      public void widgetSelected( SelectionEvent e ) {

+        MPart part = ( MPart )menu.getData( STACK_SELECTED_PART );

+        moveBeside( partToBeMoved, part, EModelService.LEFT_OF );

+      }

+    } );

+    MenuItem menuItemMoveRightOfPart = new MenuItem( subMenu, SWT.NONE );

+    menuItemMoveRightOfPart.setText( "to the Right" );

+    menuItemMoveRightOfPart.addSelectionListener( new SelectionAdapter() {

+

+      /** The serialVersionUID of this DetachPartProvider.java */

+      private static final long serialVersionUID = 1L;

+

+      @Override

+      public void widgetSelected( SelectionEvent e ) {

+        MPart part = ( MPart )menu.getData( STACK_SELECTED_PART );

+        moveBeside( partToBeMoved, part, EModelService.RIGHT_OF );

+      }

+    } );

+    // Move to the End options

+    MenuItem moveToTheEndItem = new MenuItem( menu, SWT.CASCADE );

+    moveToTheEndItem.setText( "Move to the End" );

+    Menu subMenu2 = new Menu( menu );

+    moveToTheEndItem.setMenu( subMenu2 );

+    MenuItem menuItemMoveToTheEndAbove = new MenuItem( subMenu2, SWT.NONE );

+    menuItemMoveToTheEndAbove.setText( "Above" );

+    menuItemMoveToTheEndAbove.addSelectionListener( new SelectionAdapter() {

+

+      /** The serialVersionUID of this DetachPartProvider.java */

+      private static final long serialVersionUID = 1L;

+

+      @Override

+      public void widgetSelected( SelectionEvent e ) {

+        MPart part = ( MPart )menu.getData( STACK_SELECTED_PART );

+        MWindow destWindow = part.getContext().get( MWindow.class );

+        moveToTheEnd( partToBeMoved, destWindow, EModelService.ABOVE );

+      }

+    } );

+    MenuItem menuItemMoveToTheEndBelow = new MenuItem( subMenu2, SWT.NONE );

+    menuItemMoveToTheEndBelow.setText( "Below" );

+    menuItemMoveToTheEndBelow.addSelectionListener( new SelectionAdapter() {

+

+      /** The serialVersionUID of this DetachPartProvider.java */

+      private static final long serialVersionUID = 1L;

+

+      @Override

+      public void widgetSelected( SelectionEvent e ) {

+        MPart part = ( MPart )menu.getData( STACK_SELECTED_PART );

+        MWindow destWindow = part.getContext().get( MWindow.class );

+        moveToTheEnd( partToBeMoved, destWindow, EModelService.BELOW );

+      }

+    } );

+    MenuItem menuItemMoveToTheEndLeft = new MenuItem( subMenu2, SWT.NONE );

+    menuItemMoveToTheEndLeft.setText( "to the Left" );

+    menuItemMoveToTheEndLeft.addSelectionListener( new SelectionAdapter() {

+

+      /** The serialVersionUID of this DetachPartProvider.java */

+      private static final long serialVersionUID = 1L;

+

+      @Override

+      public void widgetSelected( SelectionEvent e ) {

+        MPart part = ( MPart )menu.getData( STACK_SELECTED_PART );

+        MWindow destWindow = part.getContext().get( MWindow.class );

+        moveToTheEnd( partToBeMoved, destWindow, EModelService.LEFT_OF );

+      }

+    } );

+    MenuItem menuItemMoveToTheEndRight = new MenuItem( subMenu2, SWT.NONE );

+    menuItemMoveToTheEndRight.setText( "to the Right" );

+    menuItemMoveToTheEndRight.addSelectionListener( new SelectionAdapter() {

+

+      /** The serialVersionUID of this DetachPartProvider.java */

+      private static final long serialVersionUID = 1L;

+

+      @Override

+      public void widgetSelected( SelectionEvent e ) {

+        MPart part = ( MPart )menu.getData( STACK_SELECTED_PART );

+        MWindow destWindow = part.getContext().get( MWindow.class );

+        moveToTheEnd( partToBeMoved, destWindow, EModelService.RIGHT_OF );

+      }

+    } );

+  }

+

+  /**

+   * Moves a part into the same stack as another part is placed

+   * 

+   * @param partToBeMoved the reference to the part to be moved

+   * @param destinationRefPart the reference to the other part, whose part stack will be the

+   *          destination of the part to be moved

+   */

+  private void moveToPartStack( MPart partToBeMoved, MPart destinationRefPart ) {

+    MWindow window = partToBeMoved.getContext().get( MWindow.class );

+    MWindow destWindow = destinationRefPart.getContext().get( MWindow.class );

+    if( partToBeMoved.equals( destinationRefPart )

+        || ( !window.equals( destWindow ) && isPartSingleton( partToBeMoved ) ) )

+    {

+      // Do not allow singleton views to be moved to different windows

+      return;

+    }

+    MPlaceholder ph1 = this.modelService.findPlaceholderFor( window, partToBeMoved );

+    MPlaceholder ph2 = this.modelService.findPlaceholderFor( destWindow, destinationRefPart );

+    if( ph1.getParent().equals( ph2.getParent() ) ) {

+      return;

+    }

+    this.modelService.move( ph1, ph2.getParent() );

+  }

+

+  /**

+   * Moves a part beside another part, sharing the Sash Container space

+   * 

+   * @param partToBeMoved the reference to the part to be moved

+   * @param destinationRefPart the reference to the part used as reference for placing the moved

+   *          part

+   * @param position the relative position. One of {@link EModelService#ABOVE},

+   *          {@link EModelService#BELOW}, {@link EModelService#LEFT_OF},

+   *          {@link EModelService#RIGHT_OF}

+   */

+  private void moveBeside( MPart partToBeMoved, MPart destinationRefPart, int position ) {

+    MWindow window = partToBeMoved.getContext().get( MWindow.class );

+    MWindow destWindow = destinationRefPart.getContext().get( MWindow.class );

+    if( ( !window.equals( destWindow ) && isPartSingleton( partToBeMoved ) ) ) {

+      // Do not allow singleton views to be moved to different windows

+      return;

+    }

+    MPlaceholder ph1 = this.modelService.findPlaceholderFor( window, partToBeMoved );

+    MPlaceholder ph2 = this.modelService.findPlaceholderFor( destWindow, destinationRefPart );

+    MPartSashContainerElement cont = ph2;

+    cont = ( MPartSashContainerElement )cont.getParent();

+    MPartStack ps = this.modelService.createModelElement( MPartStack.class );

+    this.modelService.insert( ps, cont, position, 0.5f );

+    ps.getChildren().add( ph1 );

+    ps.setSelectedElement( ph1 );

+  }

+

+  /**

+   * Moves a part to the border of the screen. It will be placed as an element of a new

+   * {@link MPartSashContainer} and the other elemen will contain all the rest of the visible layout

+   * 

+   * @param partToBeMoved the reference to the part to be moved

+   * @param position the relative position. One of {@link EModelService#ABOVE},

+   *          {@link EModelService#BELOW}, {@link EModelService#LEFT_OF},

+   *          {@link EModelService#RIGHT_OF}

+   */

+  private void moveToTheEnd( MPart partToBeMoved, MWindow destinationWindow, int position ) {

+    MWindow window = partToBeMoved.getContext().get( MWindow.class );

+    if( ( !window.equals( destinationWindow ) && isPartSingleton( partToBeMoved ) ) ) {

+      // Do not allow singleton views to be moved to different windows

+      return;

+    }

+    MPlaceholder ph1 = this.modelService.findPlaceholderFor( window, partToBeMoved );

+    MPerspective persp = this.modelService.getActivePerspective( destinationWindow );

+    MPartSashContainer psc = findDisplayedPartShashContainer( persp );

+    MPartStack ps = this.modelService.createModelElement( MPartStack.class );

+    this.modelService.insert( ps, psc, position, 0.3f );

+    ps.getChildren().add( ph1 );

+    ps.setSelectedElement( ph1 );

+  }

+

+  /**

+   * Returns the first {@link MPartSashContainer} in the given perspective where all the elements

+   * are visible.

+   * 

+   * @param persp the reference to the perspective

+   * @return the first {@link MPartSashContainer} in the given perspective where all the elements

+   *         are visible

+   */

+  private MPartSashContainer findDisplayedPartShashContainer( MPerspective persp ) {

+    MElementContainer< ? > parentElem = ( MElementContainer< ? > )persp.getChildren().get( 0 );

+    MPartSashContainer ret = null;

+    while( ret == null && parentElem != null ) {

+      boolean allToBeRendered = parentElem.getChildren().get( 0 ).isToBeRendered()

+                                && parentElem.getChildren().get( 1 ).isToBeRendered();

+      if( allToBeRendered && parentElem instanceof MPartSashContainer ) {

+        ret = ( MPartSashContainer )parentElem;

+      } else {

+        MPartSashContainer renderedChild = null;

+        for( MUIElement child : parentElem.getChildren() ) {

+          if( child.isToBeRendered() && child instanceof MPartSashContainer ) {

+            renderedChild = ( MPartSashContainer )child;

+          }

+        }

+        parentElem = renderedChild;

+      }

+    }

+    return ret;

+  }

+

+  /**

+   * Returns <code>true</code> if the part is a ViewPart and its descriptor allows multiple

+   * instances of the view; <code>false</code> otherwise

+   * 

+   * @param part the reference to the part

+   * @return <code>true</code> if the part is a ViewPart and its descriptor allows multiple

+   *         instances of the view; <code>false</code> otherwise

+   */

+  private boolean isPartSingleton( MPart part ) {

+    boolean ret = false;

+    IWorkbenchPart workbenchPpart = part.getContext().get( IWorkbenchPart.class );

+    IViewDescriptor desctiptor = workbenchPpart.getSite()

+      .getWorkbenchWindow()

+      .getWorkbench()

+      .getViewRegistry()

+      .find( workbenchPpart.getSite().getId() );

+    if( desctiptor != null ) {

+      return !desctiptor.getAllowMultiple();

+    }

+    return ret;

+  }

+}

+// -----------------------------------------------------------------------------

diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/partdnd/internal/PartTransfer.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/partdnd/internal/PartTransfer.java
new file mode 100644
index 0000000..efac4ea
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/partdnd/internal/PartTransfer.java
@@ -0,0 +1,52 @@
+/*******************************************************************************

+ * Copyright (c) 2017 David Marina

+ * 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:

+ *   David Marina - initial API and implementation

+ *******************************************************************************/

+package org.eclipse.rap.ui.partdnd.internal;

+

+import org.eclipse.rap.rwt.SingletonUtil;

+

+

+/**

+ * @author David Marina

+ */

+public class PartTransfer extends SimpleObjectTransfer {

+

+  public static final PartTransfer INSTANCE = SingletonUtil.getSessionInstance( PartTransfer.class );

+  /** The serialVersionUID of this PartTransfer.java */

+  private static final long serialVersionUID = 5415453120868372411L;

+  private static final String TYPE_NAME = "org.eclipse.rap.ui.partdnd.internal.PartTransfer"

+                                          + System.currentTimeMillis()

+                                          + ":" + INSTANCE.hashCode(); //$NON-NLS-1$

+  private static final int TYPE_ID = registerType( TYPE_NAME );

+

+  /**

+   * Creates a new PartTransfer

+   */

+  private PartTransfer() {

+    // do nothing

+  }

+

+  /** {@inheritDoc} */

+  @Override

+  protected int[] getTypeIds() {

+    return new int[] {

+      TYPE_ID

+    };

+  }

+

+  /** {@inheritDoc} */

+  @Override

+  protected String[] getTypeNames() {

+    return new String[] {

+      TYPE_NAME

+    };

+  }

+}

+// -----------------------------------------------------------------------------

diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/partdnd/internal/SimpleObjectTransfer.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/partdnd/internal/SimpleObjectTransfer.java
new file mode 100644
index 0000000..1293723
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/partdnd/internal/SimpleObjectTransfer.java
@@ -0,0 +1,79 @@
+/*******************************************************************************

+ * Copyright (c) 2000, 2010 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.rap.ui.partdnd.internal;

+

+import org.eclipse.swt.dnd.ByteArrayTransfer;

+import org.eclipse.swt.dnd.TransferData;

+

+/**

+ * Holds on to the object being transferred in a field so that

+ * DropTargetListeners can know what's being dragged before the drop occurs. The

+ * object isn't converted to bytes, so this Transfer will only work when

+ * dragging within the same instance of Eclipse. Subclasses should maintain a

+ * single instance of their Transfer and provide a static method to obtain that

+ * instance.

+ */

+public abstract class SimpleObjectTransfer extends ByteArrayTransfer {

+

+	private Object object;

+	private long startTime;

+

+	/**

+	 * Returns the Object.

+	 * 

+	 * @return The Object

+	 */

+	public Object getObject() {

+		return object;

+	}

+

+	/**

+	 * The data object is not converted to bytes. It is held onto in a field.

+	 * Instead, a checksum is written out to prevent unwanted drags across

+	 * mulitple running copies of Eclipse.

+	 * 

+	 * @see org.eclipse.swt.dnd.Transfer#javaToNative(Object, TransferData)

+	 */

+	public void javaToNative(Object object, TransferData transferData) {

+		setObject(object);

+		startTime = System.currentTimeMillis();

+		if (transferData != null)

+			super.javaToNative(String.valueOf(startTime).getBytes(),

+					transferData);

+	}

+

+	/**

+	 * The data object is not converted to bytes. It is held onto in a field.

+	 * Instead, a checksum is written out to prevent unwanted drags across

+	 * mulitple running. copies of Eclipse.

+	 * 

+	 * @see org.eclipse.swt.dnd.Transfer#nativeToJava(TransferData)

+	 */

+	public Object nativeToJava(TransferData transferData) {

+		byte bytes[] = (byte[]) super.nativeToJava(transferData);

+		if (bytes == null) {

+			return null;

+		}

+		long startTime = Long.parseLong(new String(bytes));

+		return (this.startTime == startTime) ? getObject() : null;

+	}

+

+	/**

+	 * Sets the Object.

+	 * 

+	 * @param obj

+	 *            The Object

+	 */

+	public void setObject(Object obj) {

+		object = obj;

+	}

+

+}

diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/partdnd/internal/WorkaroundDragPartSource.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/partdnd/internal/WorkaroundDragPartSource.java
new file mode 100644
index 0000000..bc292a0
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/partdnd/internal/WorkaroundDragPartSource.java
@@ -0,0 +1,174 @@
+/*******************************************************************************

+ * Copyright (c) 2017 David Marina

+ * 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:

+ *   David Marina - initial API and implementation

+ *******************************************************************************/

+package org.eclipse.rap.ui.partdnd.internal;

+

+import static org.eclipse.rap.rwt.internal.protocol.RemoteObjectFactory.getRemoteObject;

+import static org.eclipse.swt.internal.dnd.DNDUtil.convertTransferTypes;

+

+import java.util.concurrent.ScheduledThreadPoolExecutor;

+import java.util.concurrent.TimeUnit;

+

+import org.eclipse.rap.json.JsonValue;

+import org.eclipse.swt.SWT;

+import org.eclipse.swt.custom.CTabFolder;

+import org.eclipse.swt.custom.CTabItem;

+import org.eclipse.swt.dnd.DND;

+import org.eclipse.swt.dnd.DragSource;

+import org.eclipse.swt.dnd.Transfer;

+import org.eclipse.swt.graphics.Point;

+import org.eclipse.swt.widgets.Control;

+import org.eclipse.swt.widgets.Display;

+import org.eclipse.swt.widgets.Event;

+import org.eclipse.swt.widgets.Listener;

+

+

+/**

+ * This class is implemented as a workaround for the following issue:<br>

+ * <br>

+ * When the window is resized and the mouse is on the border of the part (not the part tab itself),

+ * the CTabFolder is catching the event and corrupting the browser's window widget by sending a

+ * wrong JSON message. After this occurs, the window becomes frozen and it is not possible to

+ * restore its functionality. <br>

+ * In order to avoid this situation, a mouse listener will decide if the widget under the cursor

+ * really belongs to the CTabFolder (ignoring the part's borders).It is important to note that the

+ * event sequence might cause that the DragSource event is triggered before the MouseDown event is

+ * sent. If that happens, the next mouse events in a short period of time have to be ignored.

+ * 

+ * @author David Marina

+ */

+public class WorkaroundDragPartSource extends DragSource {

+

+  /** The serialVersionUID of this WorkaroundDragPartSource.java */

+  private static final long serialVersionUID = 8801486978319382719L;

+  /** The reference to a empty Transfer array */

+  private static final Transfer[] EMPTY_TRANSFER = new Transfer[] {};

+  /** The reference to the {@link CTabFolder} */

+  private final CTabFolder ctf;

+  /** Flag to indicated that the drag has started (<code>true</code>) */

+  private boolean dragStarted = false;

+  /**

+   * Flag to ignore mouse events (with <code>true</code>) when the DragStar happens before the

+   * MouseDown

+   */

+  private boolean ignoreEvents = false;

+

+  /**

+   * Creates a new WorkaroundDragPartSource

+   * 

+   * @param control

+   * @param style

+   */

+  public WorkaroundDragPartSource( Control control, int style ) {

+    super( control, style );

+    this.ctf = ( CTabFolder )control;

+    Listener listener = new Listener() {

+

+      /** The serialVersionUID of this WorkaroundDragPartSource.java */

+      private static final long serialVersionUID = 7747075970781676002L;

+

+      /** {@inheritDoc} */

+      @Override

+      public void handleEvent( org.eclipse.swt.widgets.Event event ) {

+        if( event.type == SWT.MouseDown ) {

+          Point absolutePoint = new Point( event.x, event.y );

+          CTabItem item = WorkaroundDragPartSource.this.ctf.getItem( absolutePoint );

+          if( item == null ) {

+            setDragStarted( false );

+          }

+          // The mouse down event could arrive after the DragStart. In

+          // that case we should ignore the mouse event

+          else if( !WorkaroundDragPartSource.this.ignoreEvents ) {

+            setDragStarted( true );

+            startClientTransferRendering();

+          }

+        } else if( event.type == SWT.MouseUp ) {

+          setDragStarted( false );

+        }

+      }

+    };

+    if( this.ctf.getData( "DragWorkaroundListener" ) == null ) {

+      this.ctf.addListener( SWT.MouseDown, listener );

+      this.ctf.addListener( SWT.MouseUp, listener );

+      this.ctf.setData( "DragWorkaroundListener", listener );

+    }

+  }

+

+  /**

+   * Indicates with an argument that the drag started (<code>true</code>) or ended (

+   * <code>false</code>)

+   * 

+   * @param dragStarted a boolean indicating with <code>true</code> the drag start;

+   *          <code>false</code> to indicate the drag end

+   */

+  public void setDragStarted( boolean dragStarted ) {

+    // If there is no drag operation, set the empty transfer to avoid

+    // blocking the window

+    if( !dragStarted ) {

+      JsonValue renderValue = convertTransferTypes( EMPTY_TRANSFER );

+      getRemoteObject( this ).set( "transfer", renderValue );

+      this.ignoreEvents = false;

+    }

+    this.dragStarted = dragStarted;

+  }

+

+  /** {@inheritDoc} */

+  @Override

+  public Transfer[] getTransfer() {

+    Display display = getDisplay();

+    Point location = display.getCursorLocation();

+    Point relativePoint = display.map( null, this.ctf, location );

+    CTabItem item = this.ctf.getItem( relativePoint );

+    if( this.dragStarted || item != null ) {

+      return super.getTransfer();

+    } else {

+      return EMPTY_TRANSFER;

+    }

+  }

+

+  /** {@inheritDoc} */

+  @Override

+  public void notifyListeners( int eventType, Event event ) {

+    if( eventType == DND.DragStart && !this.dragStarted ) {

+      ignoreEvents();

+    }

+    super.notifyListeners( eventType, event );

+    if( event.doit == false || event.type == DND.DragEnd ) {

+      setDragStarted( false );

+      ignoreEvents();

+    }

+  }

+

+  /** {@inheritDoc} */

+  @Override

+  protected void checkSubclass() {

+    // Override to enable subclassing

+  }

+

+  /**

+   * Starts the client transfer rendering

+   */

+  public void startClientTransferRendering() {

+    JsonValue renderValue = convertTransferTypes( super.getTransfer() );

+    getRemoteObject( this ).set( "transfer", renderValue );

+  }

+

+  /**

+   * Indicates that the next mouse events shall be ignored for a short period of time

+   */

+  public void ignoreEvents() {

+    this.ignoreEvents = true;

+    final ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor( 1 );

+    executor.schedule( ( ) -> {

+      this.ignoreEvents = false;

+    }, 500, TimeUnit.MILLISECONDS );

+  }

+}

+// -----------------------------------------------------------------------------

diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/resources/IResource.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/resources/IResource.java
new file mode 100644
index 0000000..73c4e11
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/rap/ui/resources/IResource.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2002, 2012 Innoopract Informationssysteme GmbH 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:
+ *    Innoopract Informationssysteme GmbH - initial API and implementation
+ *    EclipseSource - ongoing development
+ ******************************************************************************/
+package org.eclipse.rap.ui.resources;
+
+
+/**
+ * Implementations of this interface represent an existing resource to be registered, either local
+ * or external.
+ *
+ * @since 2.0
+ */
+public interface IResource {
+
+  /**
+   * Specifies the classloader that should be used to load the local resource. If there is no need
+   * for a particular classloader, implementations should simply return their own classloader:
+   *
+   * <pre>
+   * ClassLoader getLoader() {
+   *   return this.getClass().getClassLoader();
+   * }
+   * </pre>
+   *
+   * @return the classloader to use, or <code>null</code> for external resources
+   */
+  ClassLoader getLoader();
+
+  /**
+   * Returns the location of the resource. For external resources, this is the URL to load the
+   * resource from. For local resources, this is the path that the classloader can read the resource
+   * from.
+   *
+   * @return the location of the resource
+   * @see IResource#isExternal()
+   */
+  String getLocation();
+
+  /**
+   * Indicates whether the resource is a javascript library that should be loaded by the client.
+   * Applies for both, external and local resources.
+   *
+   * @return whether this resource is a javascript library
+   * @see IResource#isExternal()
+   */
+  boolean isJSLibrary();
+
+  /**
+   * Indicates whether the resource is external, i.e. loaded from an external URL. In the case of an
+   * external javascript library it will be included in the generated page with a &lt;script&gt;
+   * tag.
+   *
+   * @return whether the resource is located externally
+   */
+  boolean isExternal();
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/AbstractSourceProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/AbstractSourceProvider.java
new file mode 100644
index 0000000..d9ecd5f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/AbstractSourceProvider.java
@@ -0,0 +1,131 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2016 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.ui;
+
+import java.util.Map;
+import org.eclipse.core.commands.util.Tracing;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.ui.internal.misc.Policy;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * <p>
+ * An implementation of <code>ISourceProvider</code> that provides listener
+ * support. Subclasses need only call <code>fireSourceChanged</code> whenever
+ * appropriate.
+ * </p>
+ *
+ * @since 3.1
+ */
+public abstract class AbstractSourceProvider implements ISourceProvider {
+
+	/**
+	 * Whether source providers should print out debugging information to the
+	 * console when events arrive.
+	 *
+	 * @since 3.2
+	 */
+	protected static boolean DEBUG = Policy.DEBUG_SOURCES;
+
+	/**
+	 * The listeners to this source provider. This value is never
+	 * <code>null</code>.
+	 */
+	private final ListenerList<ISourceProviderListener> listeners = new ListenerList<>(ListenerList.IDENTITY);
+
+
+	@Override
+	public final void addSourceProviderListener(
+			final ISourceProviderListener listener) {
+		if (listener == null) {
+			throw new NullPointerException("The listener cannot be null"); //$NON-NLS-1$
+		}
+
+		listeners.add(listener);
+	}
+
+	/**
+	 * Notifies all listeners that a single source has changed.
+	 *
+	 * @param sourcePriority
+	 *            The source priority that has changed.
+	 * @param sourceName
+	 *            The name of the source that has changed; must not be
+	 *            <code>null</code>.
+	 * @param sourceValue
+	 *            The new value for the source; may be <code>null</code>.
+	 */
+	protected final void fireSourceChanged(final int sourcePriority,
+			final String sourceName, final Object sourceValue) {
+		for (ISourceProviderListener listener : listeners) {
+			listener.sourceChanged(sourcePriority, sourceName, sourceValue);
+		}
+	}
+
+	/**
+	 * Notifies all listeners that multiple sources have changed.
+	 *
+	 * @param sourcePriority
+	 *            The source priority that has changed.
+	 * @param sourceValuesByName
+	 *            The map of source names (<code>String</code>) to source
+	 *            values (<code>Object</code>) that have changed; must not
+	 *            be <code>null</code>. The names must not be
+	 *            <code>null</code>, but the values may be <code>null</code>.
+	 */
+	protected final void fireSourceChanged(final int sourcePriority,
+			final Map sourceValuesByName) {
+
+		for (ISourceProviderListener listener : listeners) {
+			listener.sourceChanged(sourcePriority, sourceValuesByName);
+		}
+	}
+
+	/**
+	 * Logs a debugging message in an appropriate manner. If the message is
+	 * <code>null</code> or the <code>DEBUG</code> is <code>false</code>,
+	 * then this method does nothing.
+	 *
+	 * @param message
+	 *            The debugging message to log; if <code>null</code>, then
+	 *            nothing is logged.
+	 * @since 3.2
+	 */
+	protected final void logDebuggingInfo(final String message) {
+		if (DEBUG && (message != null)) {
+			Tracing.printTrace("SOURCES", message); //$NON-NLS-1$
+		}
+	}
+
+	@Override
+	public final void removeSourceProviderListener(
+			final ISourceProviderListener listener) {
+		if (listener == null) {
+			throw new NullPointerException("The listener cannot be null"); //$NON-NLS-1$
+		}
+
+		listeners.remove(listener);
+	}
+
+	/**
+	 * This method is called when the source provider is instantiated by
+	 * <code>org.eclipse.ui.services</code>. Clients may override this method
+	 * to perform initialization.
+	 *
+	 * @param locator
+	 *            The global service locator. It can be used to retrieve
+	 *            services like the IContextService
+	 * @since 3.4
+	 */
+	public void initialize(final IServiceLocator locator) {
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ActiveShellExpression.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ActiveShellExpression.java
new file mode 100644
index 0000000..d3dde65
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ActiveShellExpression.java
@@ -0,0 +1,127 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui;
+
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.ExpressionInfo;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * <p>
+ * An expression that checks the active shell variable. The variable name is
+ * <code>ISources.ACTIVE_SHELL_NAME</code> and falls back to
+ * <code>ISources.ACTIVE_WORKBENCH_WINDOW</code>. That is, if the active
+ * shell doesn't match, then it will be allowed to match the active workbench
+ * window.
+ * </p>
+ *
+ * @since 3.1
+ */
+public final class ActiveShellExpression extends Expression {
+
+	/**
+	 * The seed for the hash code for all schemes.
+	 */
+	private static final int HASH_INITIAL = ActiveShellExpression.class
+			.getName().hashCode();
+
+	/**
+	 * The sources value to use with this expression.
+	 */
+	public static final int SOURCES = ISources.ACTIVE_SHELL
+			| ISources.ACTIVE_WORKBENCH_WINDOW;
+
+	/**
+	 * The shell that must be active for this expression to evaluate to
+	 * <code>true</code>. If this value is <code>null</code>, then any
+	 * shell may be active.
+	 */
+	private final Shell activeShell;
+
+	/**
+	 * Constructs a new instance of <code>ActiveShellExpression</code>
+	 *
+	 * @param activeShell
+	 *            The shell to match with the active shell; <code>null</code>
+	 *            if it will match any active shell.
+	 */
+	public ActiveShellExpression(final Shell activeShell) {
+		this.activeShell = activeShell;
+	}
+
+	/**
+	 * Expression information for this expression.  Namely active shell and
+	 * active workbench window name.
+	 *
+	 * @since 3.2
+	 */
+	@Override
+	public final void collectExpressionInfo(final ExpressionInfo info) {
+		info.addVariableNameAccess(ISources.ACTIVE_SHELL_NAME);
+		info.addVariableNameAccess(ISources.ACTIVE_WORKBENCH_WINDOW_NAME);
+	}
+
+	@Override
+	protected final int computeHashCode() {
+		return HASH_INITIAL * HASH_FACTOR + hashCode(activeShell);
+	}
+
+	@Override
+	public final boolean equals(final Object object) {
+		if (object instanceof ActiveShellExpression) {
+			final ActiveShellExpression that = (ActiveShellExpression) object;
+			return equals(this.activeShell, that.activeShell);
+		}
+
+		return false;
+	}
+
+	/**
+	 * Evaluates this expression. If the active shell defined by the context
+	 * matches the shell from this expression, then this evaluates to
+	 * <code>EvaluationResult.TRUE</code>. Similarly, if the active workbench
+	 * window shell defined by the context matches the shell from this
+	 * expression, then this evaluates to <code>EvaluationResult.TRUE</code>.
+	 *
+	 * @param context
+	 *            The context from which the current state is determined; must
+	 *            not be <code>null</code>.
+	 * @return <code>EvaluationResult.TRUE</code> if the shell is active;
+	 *         <code>EvaluationResult.FALSE</code> otherwise.
+	 */
+	@Override
+	public final EvaluationResult evaluate(final IEvaluationContext context) {
+		if (activeShell != null) {
+			Object value = context.getVariable(ISources.ACTIVE_SHELL_NAME);
+			if (!activeShell.equals(value)) {
+				value = context
+						.getVariable(ISources.ACTIVE_WORKBENCH_WINDOW_SHELL_NAME);
+				if (!activeShell.equals(value)) {
+					return EvaluationResult.FALSE;
+				}
+			}
+		}
+
+		return EvaluationResult.TRUE;
+	}
+
+	@Override
+	public final String toString() {
+		final StringBuffer buffer = new StringBuffer();
+		buffer.append("ActiveShellExpression("); //$NON-NLS-1$
+		buffer.append(activeShell);
+		buffer.append(')');
+		return buffer.toString();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/BasicWorkingSetElementAdapter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/BasicWorkingSetElementAdapter.java
new file mode 100644
index 0000000..904fae0
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/BasicWorkingSetElementAdapter.java
@@ -0,0 +1,243 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IAdapterManager;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExecutableExtension;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.osgi.framework.Bundle;
+import org.osgi.service.packageadmin.ExportedPackage;
+import org.osgi.service.packageadmin.PackageAdmin;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * Basic IWorkingSetElementAdapter implementation that allows plugins to decribe
+ * simple declarative element adapters.
+ * <p>
+ * The executable extension format for this class is as follows:<br/>
+ * <code>&lt;workingSet
+ * elementAdapterClass="org.eclipse.ui.BasicWorkingSetElementAdapter:class1.to.adapt.to[;option1=value1][;option2=value2],class2.to.adapt.to[;option1=value1][;option2=value2],..."&gt;
+ * ... &lt;/workingSet&gt;</code>
+ * </p>
+ * <p>
+ * The valid options are:<br/>
+ * <dl>
+ * <dt>adapt</dt>
+ * <dd>Values: <code>true</code> or <code>true</code>. Specifies whether
+ * or not the platform {@link org.eclipse.core.runtime.IAdapterManager} and the
+ * {@link org.eclipse.core.runtime.IAdaptable} interface should be consulted.</dd>
+ * </dl>
+ * </p>
+ *
+ * Please see the {@link #adaptElements(IWorkingSet, IAdaptable[])} method for
+ * details on behavior of this implementation.
+ *
+ * @since 3.3
+ */
+public final class BasicWorkingSetElementAdapter implements
+		IWorkingSetElementAdapter, IExecutableExtension {
+
+	private class Type {
+		private static final int NONE = 0;
+		private static final int ADAPT = 1;
+		String className;
+		int flags;
+	}
+
+	private Type[] preferredTypes = new Type[0];
+
+	private ServiceTracker packageTracker;
+
+	/**
+	 * When invoked this method will iterate over all classes specified as
+	 * IExecutableExtension arguements to this class in order and compare with
+	 * the elements. If the element is directly assignable to the provided class
+	 * then it is added to the result array as is. If the class has specified
+	 * "adapt=true" as an argument and there is an available adapter in the
+	 * platform IAdapterManager then it is returned. Finally, if "adapt=true"
+	 * and the class is already loaded (determined by inspecting exported
+	 * bundles via the platform PackageAdmin) a direct query for the adapter is
+	 * made on the object and if it is not <code>null</code> then it is
+	 * returned.
+	 * <p>
+	 * A consequence of the above is that it is possible for this method to
+	 * return differing results based on the state of bundles loaded within the
+	 * system.
+	 * </p>
+	 *
+	 * @see org.eclipse.ui.IWorkingSetElementAdapter#adaptElements(org.eclipse.ui.IWorkingSet,
+	 *      org.eclipse.core.runtime.IAdaptable[])
+	 * @see org.eclipse.core.runtime.IAdapterManager#getAdapter(Object, String)
+	 * @see org.osgi.service.packageadmin.PackageAdmin#getExportedPackage(String)
+	 */
+	@Override
+	public IAdaptable[] adaptElements(IWorkingSet ws, IAdaptable[] elements) {
+		List adaptedElements = new ArrayList();
+		for (IAdaptable element : elements) {
+			IAdaptable adaptable = adapt(element);
+			if (adaptable != null)
+				adaptedElements.add(adaptable);
+		}
+
+		return (IAdaptable[]) adaptedElements
+				.toArray(new IAdaptable[adaptedElements.size()]);
+	}
+
+	/**
+	 * Adapt the given adaptable. Compares the given adaptable against the list
+	 * of desired types and returns the first type that generates a match.
+	 *
+	 * @param adaptable
+	 *            the adaptable to adapt
+	 * @return the resultant adaptable. May be the same adaptable, a new
+	 *         adaptable, or <code>null</code>.
+	 */
+	private IAdaptable adapt(IAdaptable adaptable) {
+		for (Type preferredType : preferredTypes) {
+			IAdaptable adaptedAdaptable = adapt(preferredType, adaptable);
+			if (adaptedAdaptable != null)
+				return adaptedAdaptable;
+		}
+		return null;
+	}
+
+	/**
+	 * Adapt the given adaptable given the reference type.
+	 *
+	 * @param type
+	 *            the reference type
+	 * @param adaptable
+	 *            the adaptable to adapt
+	 * @return the resultant adaptable. May be the same adaptable, a new
+	 *         adaptable, or <code>null</code>.
+	 */
+	private IAdaptable adapt(Type type, IAdaptable adaptable) {
+		IAdapterManager adapterManager = Platform.getAdapterManager();
+		Class[] directClasses = adapterManager.computeClassOrder(adaptable
+				.getClass());
+		for (Class clazz : directClasses) {
+			if (clazz.getName().equals(type.className))
+				return adaptable;
+		}
+
+		if ((type.flags & Type.ADAPT) != 0) {
+			Object adapted = adapterManager.getAdapter(adaptable,
+					type.className);
+			if (adapted instanceof IAdaptable)
+				return (IAdaptable) adapted;
+
+			PackageAdmin admin = getPackageAdmin();
+			if (admin != null) {
+				int lastDot = type.className.lastIndexOf('.');
+				if (lastDot > 0) { // this lives in a package
+					String packageName = type.className.substring(0, lastDot);
+					ExportedPackage[] packages = admin
+							.getExportedPackages(packageName);
+					if (packages != null && packages.length == 1) {
+						// if there is exactly one exporter of this
+						// package
+						// we can go further
+						if (packages[0].getExportingBundle().getState() == Bundle.ACTIVE) {
+							try {
+								// if the bundle is loaded we can safely get the
+								// class object and check for an adapter on the
+								// object directly
+								adapted = adaptable.getAdapter(packages[0]
+										.getExportingBundle().loadClass(
+												type.className));
+								if (adapted instanceof IAdaptable)
+									return (IAdaptable) adapted;
+
+							} catch (ClassNotFoundException e) {
+								WorkbenchPlugin.log(e);
+							}
+						}
+					}
+				}
+			}
+		}
+		return null;
+	}
+
+	@Override
+	public void dispose() {
+		if (packageTracker != null)
+			packageTracker.close();
+	}
+
+	@Override
+	public void setInitializationData(IConfigurationElement config,
+			String propertyName, Object data) {
+
+		if (data instanceof String) {
+			List preferredTypes = new ArrayList(0);
+			for (StringTokenizer toker = new StringTokenizer((String) data, ","); toker.hasMoreTokens();) {//$NON-NLS-1$
+				String classNameAndOptions = toker.nextToken();
+				Type record = new Type();
+				parseOptions(classNameAndOptions, record);
+				preferredTypes.add(record);
+			}
+			this.preferredTypes = (Type[]) preferredTypes
+					.toArray(new Type[preferredTypes.size()]);
+		}
+	}
+
+	/**
+	 * Parse classname/option strings in the form:<br/>
+	 * <code>some.package.Class[:option1=value1][:option2=value2]...
+	 *
+	 * @param classNameAndOptions the class name and possibly options to parse
+	 * @param record the record to fill
+	 */
+	private void parseOptions(String classNameAndOptions, Type record) {
+		for (StringTokenizer toker = new StringTokenizer(classNameAndOptions,
+				";"); toker.hasMoreTokens();) { //$NON-NLS-1$
+			String token = toker.nextToken();
+			if (record.className == null)
+				record.className = token;
+			else {
+				for (StringTokenizer pair = new StringTokenizer(token, "="); pair.hasMoreTokens();) {//$NON-NLS-1$
+					if (pair.countTokens() == 2) {
+						String param = pair.nextToken();
+						String value = pair.nextToken();
+						if ("adapt".equals(param)) { //$NON-NLS-1$
+							record.flags ^= "true".equals(value) ? Type.ADAPT : Type.NONE; //$NON-NLS-1$
+						}
+					}
+				}
+			}
+		}
+	}
+
+	/**
+	 * Prime the PackageAdmin service tracker and return the service (if
+	 * available).
+	 *
+	 * @return the PackageAdmin service or null if it is not available
+	 */
+	private PackageAdmin getPackageAdmin() {
+		if (packageTracker == null) {
+			packageTracker = new ServiceTracker(WorkbenchPlugin.getDefault()
+					.getBundleContext(), PackageAdmin.class.getName(), null);
+			packageTracker.open();
+		}
+
+		return (PackageAdmin) packageTracker.getService();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ExtensionFactory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ExtensionFactory.java
new file mode 100644
index 0000000..c795bd4
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ExtensionFactory.java
@@ -0,0 +1,215 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExecutableExtension;
+import org.eclipse.core.runtime.IExecutableExtensionFactory;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.ui.internal.ShowInMenu;
+import org.eclipse.ui.internal.dialogs.ContentTypesPreferencePage;
+import org.eclipse.ui.internal.dialogs.DecoratorsPreferencePage;
+import org.eclipse.ui.internal.dialogs.EditorsPreferencePage;
+import org.eclipse.ui.internal.dialogs.FileEditorsPreferencePage;
+import org.eclipse.ui.internal.dialogs.PerspectivesPreferencePage;
+//import org.eclipse.ui.internal.dialogs.ViewsPreferencePage;
+import org.eclipse.ui.internal.dialogs.WorkbenchPreferencePage;
+import org.eclipse.ui.internal.keys.KeysPreferencePage;
+import org.eclipse.ui.internal.keys.NewKeysPreferencePage;
+import org.eclipse.ui.internal.progress.ProgressView;
+//import org.eclipse.ui.internal.themes.ColorsAndFontsPreferencePage;
+import org.eclipse.ui.internal.wizards.preferences.PreferencesExportWizard;
+import org.eclipse.ui.internal.wizards.preferences.PreferencesImportWizard;
+
+/**
+ * Factory for the workbench's public extensions.
+ * <p>
+ * This allows the extensions to be made available for use by RCP applications
+ * without exposing their concrete implementation classes.
+ * </p>
+ *
+ * @since 3.1
+ */
+public class ExtensionFactory implements IExecutableExtensionFactory,
+		IExecutableExtension {
+
+	/**
+	 * Factory ID for the Appearance preference page.
+	 */
+	public static final String APPEARANCE_PREFERENCE_PAGE = "appearancePreferencePage"; //$NON-NLS-1$
+
+	/**
+	 * Factory ID for the Colors and Fonts preference page.
+	 */
+	public static final String COLORS_AND_FONTS_PREFERENCE_PAGE = "colorsAndFontsPreferencePage"; //$NON-NLS-1$
+
+	/**
+	 * Factory ID for the Decorators preference page.
+	 */
+	public static final String DECORATORS_PREFERENCE_PAGE = "decoratorsPreferencePage"; //$NON-NLS-1$
+
+	/**
+	 * Factory ID for the Editors preference page.
+	 */
+	public static final String EDITORS_PREFERENCE_PAGE = "editorsPreferencePage"; //$NON-NLS-1$
+
+	/**
+	 * Factory ID for the File Associations preference page.
+	 */
+	public static final String FILE_ASSOCIATIONS_PREFERENCE_PAGE = "fileAssociationsPreferencePage"; //$NON-NLS-1$
+
+	/**
+	 * Factory ID for the Keys preference page.
+	 */
+	public static final String KEYS_PREFERENCE_PAGE = "keysPreferencePage"; //$NON-NLS-1$
+
+	/**
+	 * Factory ID for the new (and improved) keys preference page.
+	 *
+	 * @since 3.2
+	 */
+	public static final String NEW_KEYS_PREFERENCE_PAGE = "newKeysPreferencePage"; //$NON-NLS-1$
+
+	/**
+	 * Factory ID for the Perspectives preference page.
+	 */
+	public static final String PERSPECTIVES_PREFERENCE_PAGE = "perspectivesPreferencePage"; //$NON-NLS-1$
+
+	/**
+	 * Factory ID for the Preferences export wizard.
+	 */
+	public static final String PREFERENCES_EXPORT_WIZARD = "preferencesExportWizard"; // $//$NON-NLS-1$
+
+	/**
+	 * Factory ID for the Preferences import wizard.
+	 */
+	public static final String PREFERENCES_IMPORT_WIZARD = "preferencesImportWizard"; // $//$NON-NLS-1$
+
+	/**
+	 * Factory ID for the Progress view.
+	 */
+	public static final String PROGRESS_VIEW = "progressView"; //$NON-NLS-1$
+
+	/**
+	 * Factory ID for the Workbench preference page.
+	 */
+	public static final String WORKBENCH_PREFERENCE_PAGE = "workbenchPreferencePage"; //$NON-NLS-1$
+
+	/**
+	 * Factory ID for the ContentTypes preference page.
+	 */
+	public static final String CONTENT_TYPES_PREFERENCE_PAGE = "contentTypesPreferencePage"; //$NON-NLS-1$
+
+	/**
+	 * Factory ID for the show in contribution.
+	 *
+	 * @since 3.4
+	 */
+	public static final String SHOW_IN_CONTRIBUTION = "showInContribution"; //$NON-NLS-1$
+
+	private IConfigurationElement config;
+
+	private String id;
+
+	private String propertyName;
+
+	/**
+	 * Constructs a new workbench extension factory.
+	 */
+	public ExtensionFactory() {
+		// do nothing
+	}
+
+	private Object configure(Object obj) throws CoreException {
+		if (obj instanceof IExecutableExtension) {
+			((IExecutableExtension) obj).setInitializationData(config,
+					propertyName, null);
+		}
+		return obj;
+	}
+
+	/**
+	 * Creates the object referenced by the factory id obtained from the
+	 * extension data.
+	 */
+	@Override
+	public Object create() throws CoreException {
+		// RAP [bm]: 
+//		if (APPEARANCE_PREFERENCE_PAGE.equals(id)) {
+//			return configure(new ViewsPreferencePage());
+//		}
+		// RAP [bm]: ColorsAndFontsPreferencePage disabled
+//		if (COLORS_AND_FONTS_PREFERENCE_PAGE.equals(id)) {
+//			return configure(new ColorsAndFontsPreferencePage());
+//		}
+		// RAPEND: [bm] 
+		if (DECORATORS_PREFERENCE_PAGE.equals(id)) {
+			return configure(new DecoratorsPreferencePage());
+		}
+		if (EDITORS_PREFERENCE_PAGE.equals(id)) {
+			return configure(new EditorsPreferencePage());
+		}
+		// RAP [rh] FileEditorsPreferencePage is disabled in RAP
+//		if (FILE_ASSOCIATIONS_PREFERENCE_PAGE.equals(id)) {
+//			return configure(new FileEditorsPreferencePage());
+//		}
+	// RAP [rh] Key configuration prefs useless since keyboard infrastructure disabled
+//		if (KEYS_PREFERENCE_PAGE.equals(id)) {
+//			return configure(new KeysPreferencePage());
+//		}
+//		if (NEW_KEYS_PREFERENCE_PAGE.equals(id)) {
+//			return configure(new NewKeysPreferencePage());
+		if (PERSPECTIVES_PREFERENCE_PAGE.equals(id)) {
+			return configure(new PerspectivesPreferencePage());
+		}
+		// RAP [bm]: missing file handling - download/upload?
+//		if (PREFERENCES_EXPORT_WIZARD.equals(id)) {
+//			return configure(new PreferencesExportWizard());
+//		}
+//		if (PREFERENCES_IMPORT_WIZARD.equals(id)) {
+//			return configure(new PreferencesImportWizard());
+//		}
+		if (PROGRESS_VIEW.equals(id)) {
+			return configure(new ProgressView());
+		}
+		if (WORKBENCH_PREFERENCE_PAGE.equals(id)) {
+			return configure(new WorkbenchPreferencePage());
+		}
+		// RAP [rh] ContentTypesPreferencePage disabled in RAP
+//		if (CONTENT_TYPES_PREFERENCE_PAGE.equals(id)) {
+//			return configure(new ContentTypesPreferencePage());
+//		}
+		if (SHOW_IN_CONTRIBUTION.equals(id)) {
+			ShowInMenu showInMenu = new ShowInMenu();
+			return showInMenu;
+		}
+
+		throw new CoreException(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID,
+				0, "Unknown id in data argument for " + getClass(), null)); //$NON-NLS-1$
+	}
+
+	@Override
+	public void setInitializationData(IConfigurationElement config,
+			String propertyName, Object data) throws CoreException {
+		if (data instanceof String) {
+			id = (String) data;
+		} else {
+			throw new CoreException(new Status(IStatus.ERROR,
+					PlatformUI.PLUGIN_ID, 0,
+					"Data argument must be a String for " + getClass(), null)); //$NON-NLS-1$
+		}
+		this.config = config;
+		this.propertyName = propertyName;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IActionBars.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IActionBars.java
new file mode 100644
index 0000000..8e88827
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IActionBars.java
@@ -0,0 +1,152 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.IStatusLineManager;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * Used by a part to access its menu, toolbar, and status line managers.
+ * <p>
+ * Within the workbench each part, editor or view, has a private set of action
+ * bars.  This set, which contains a menu, toolbar, and status line, appears
+ * in the local toolbar for a view and in the window for an editor.  The view
+ * may provide an implementation for pre-existing actions or add new actions to
+ * the action bars.
+ * </p><p>
+ * In a workbench window there are a number of actions which are applicable to
+ * all parts.  Some common examples are <code>CUT</code>, <code>COPY</code> and
+ * <code>PASTE</code>. These actions, known as "global actions", are contributed to
+ * the workbench window by the window itself and shared by all parts.  The
+ * presentation is owned by the window.  The implementation is delegated to the
+ * active part.
+ * </p><p>
+ * To participate in the global action design an <code>IWorkbenchPart</code> should
+ * register a handler for each global action which is implemented by the part.  This
+ * can be done by calling <code>setGlobalActionHandler</code>.  For convenience, the
+ * standard global actions are defined in
+ * <code>org.eclipse.ui.IWorkbenchActionConstants</code>.
+ * </p><p>
+ * Additional work is required for the <code>Delete</code> global action.  In
+ * this case the accelerator is defined in the menu item text but is not hooked
+ * on the window.  This is to support text editors where the <code>Delete</code>
+ * key is functional even when the <code>Delete</code> action is disabled (no text
+ * is selected).  An implementation for this accelerator must be defined locally,
+ * in each part, by listening for <code>Delete</code> key events.
+ * </p><p>
+ * A part may also contribute new actions to the action bars as required.  To do
+ * this, call <code>getMenuManager</code>, <code>getToolBarManager</code>, or
+ * <code>getStatusLineManager</code> as appropriate to get the action target.
+ * Add the action(s) to the target and call <code>update</code> to commit
+ * any changes to the underlying widgets.
+ * </p><p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IActionBars {
+    /**
+     * Clears the global action handler list.
+     * <p>
+     * Note: Clients who manipulate the global action list are
+     * responsible for calling <code>updateActionBars</code> so that the changes
+     * can be propagated throughout the workbench.
+     * </p>
+     */
+    public void clearGlobalActionHandlers();
+
+    /**
+     * Returns the global action handler for the action with the given id.
+     *
+     * @param actionId an action id declared in the registry
+     * @return an action handler which implements the action id, or
+     *	 <code>null</code> if none is registered
+     * @see IWorkbenchActionConstants
+     * @see #setGlobalActionHandler(String, IAction)
+     */
+    public IAction getGlobalActionHandler(String actionId);
+
+    /**
+     * Returns the menu manager.
+     * <p>
+     * Note: Clients who add or remove items from the returned menu manager are
+     * responsible for calling <code>updateActionBars</code> so that the changes
+     * can be propagated throughout the workbench.
+     * </p>
+     *
+     * @return the menu manager
+     */
+    public IMenuManager getMenuManager();
+
+    /**
+	 * Returns the service locator for these action bars. The locator is found
+	 * by looking locally, and then ascending the action bar hierarchy.
+	 *
+	 * @return The service locator; never <code>null</code>.
+	 * @since 3.2
+	 */
+	public IServiceLocator getServiceLocator();
+
+    /**
+	 * Returns the status line manager.
+	 * <p>
+	 * Note: Clients who add or remove items from the returned status line
+	 * manager are responsible for calling <code>updateActionBars</code> so
+	 * that the changes can be propagated throughout the workbench.
+	 * </p>
+	 *
+	 * @return the status line manager
+	 */
+    public IStatusLineManager getStatusLineManager();
+
+    /**
+     * Returns the tool bar manager.
+     * <p>
+     * Note: Clients who add or remove items from the returned tool bar manager are
+     * responsible for calling <code>updateActionBars</code> so that the changes
+     * can be propagated throughout the workbench.
+     * </p>
+     *
+     * @return the tool bar manager
+     */
+    public IToolBarManager getToolBarManager();
+
+    /**
+     * Sets the global action handler for the action with the given id.
+     * <p>
+     * Note: Clients who manipulate the global action list are
+     * responsible for calling <code>updateActionBars</code> so that the changes
+     * can be propagated throughout the workbench.
+     * </p>
+     *
+     * @param actionId an action id declared in the registry
+     * @param handler an action which implements the action id, or
+     *	<code>null</code> to clear any existing handler
+     * @see IWorkbenchActionConstants
+     */
+    public void setGlobalActionHandler(String actionId, IAction handler);
+
+	/**
+	 * Updates the action bars.
+	 * <p>
+	 * Clients who add or remove items from the menu, tool bar, or status line
+	 * managers, or that update global action handlers, should call this method
+	 * to propagated the changes throughout the workbench.
+	 * </p>
+	 *
+	 * @see #setGlobalActionHandler(String, IAction)
+	 * @see #clearGlobalActionHandlers()
+	 */
+    public void updateActionBars();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IActionBars2.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IActionBars2.java
new file mode 100644
index 0000000..37253c1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IActionBars2.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import org.eclipse.jface.action.ICoolBarManager;
+
+/**
+ * Interface extention to <code>IActionBars</code> that provides an additional
+ * cool bar manager.
+ *
+ * @since 3.0
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IActionBars2 extends IActionBars {
+
+    /**
+     * Returns the cool bar manager.
+     * <p>
+     * Note: Clients who add or remove items from the returned cool bar manager are
+     * responsible for calling <code>updateActionBars</code> so that the changes
+     * can be propagated throughout the workbench.
+     * </p>
+     *
+     * @return the cool bar manager.
+     */
+    public ICoolBarManager getCoolBarManager();
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IActionDelegate.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IActionDelegate.java
new file mode 100644
index 0000000..78acc68
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IActionDelegate.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+
+/**
+ * Interface for actions contributed via an extension point.
+ * <p>
+ * This interface should be implemented by clients who need to contribute actions
+ * via an extension point. The workbench will generate a <b>proxy action</b>
+ * object on behalf of the plug-in to avoid having to activate the plug-in until
+ * the user needs it. If the action is performed the workbench will load the class
+ * that implements this interface and create what is called an <b>action
+ * delegate</b> object. Then the request, and all subsequent ones, are
+ * forwarded through the proxy action to the action delegate, which does the
+ * real work.
+ * </p><p>
+ * The proxy action is the one that appears in the UI, so the action delegate
+ * will need to talk to the proxy action in order to keep up an appropriate
+ * appearance. Once the action delegate has been created, it will be
+ * notified of all selection changes, allowing it to enable or disable the
+ * proxy action appropriately.
+ * </p><p>
+ * An action delegate cannot be consulted about selection changes before the
+ * action is performed because it does not exist.  For this reason, control of
+ * the action's enable state should also be exercised through simple XML rules
+ * contained in the extension.  These rules allow enable state control before
+ * the action delegate's plug-in is loaded.
+ * </p><p>
+ * Clients can choose to subclass the provided abstract implementation
+ * <code>org.eclipse.ui.actions.ActionDelegate</code> or implement the
+ * interface directly.
+ * </p>
+ *
+ * @see org.eclipse.ui.actions.ActionDelegate
+ * @see org.eclipse.ui.IActionDelegate2
+ */
+public interface IActionDelegate {
+    /**
+     * Performs this action.
+     * <p>
+     * This method is called by the proxy action when the action has been
+     * triggered. Implement this method to do the actual work.
+     * </p><p>
+     * <b>Note:</b> If the action delegate also implements
+     * <code>IActionDelegate2</code>, then this method is not invoked but
+     * instead the <code>runWithEvent(IAction, Event)</code> method is called.
+     * </p>
+     *
+     * @param action the action proxy that handles the presentation portion of the
+     *   action
+     */
+    public void run(IAction action);
+
+    /**
+     * Notifies this action delegate that the selection in the workbench has changed.
+     * <p>
+     * Implementers can use this opportunity to change the availability of the
+     * action or to modify other presentation properties.
+     * </p><p>
+     * When the selection changes, the action enablement state is updated based on
+     * the criteria specified in the plugin.xml file. Then the delegate is notified
+     * of the selection change regardless of whether the enablement criteria in the
+     * plugin.xml file is met.
+     * </p>
+     *
+     * @param action the action proxy that handles presentation portion of
+     * 		the action
+     * @param selection the current selection, or <code>null</code> if there
+     * 		is no selection.
+     */
+    public void selectionChanged(IAction action, ISelection selection);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IActionDelegate2.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IActionDelegate2.java
new file mode 100644
index 0000000..3587516
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IActionDelegate2.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.swt.widgets.Event;
+
+/**
+ * Interface extension to <code>IActionDelegate</code> adding lifecycle methods.
+ * In addition, a <code>runWithEvent</code> method that includes the triggering
+ * SWT event.
+ * <p>
+ * An action delegate that implements this interface will have its
+ * <code>runWithEvent(IAction, Event)</code> called instead of its
+ * <code>run(IAction)</code> method.
+ * </p><p>
+ * Clients should implement this interface, in addition to
+ * <code>IActionDelegate</code> or sub-interfaces, if interested in the
+ * triggering event or in the lifecycle of the delegate object.
+ * </p><p>
+ * Clients can choose to subclass the provided abstract implementation
+ * <code>org. eclipse. ui. actions. ActionDelegate</code> or implement the
+ * interface directly.
+ * </p>
+ *
+ * @see org.eclipse.ui.actions.ActionDelegate
+ * @see org.eclipse.ui.IActionDelegate
+ * @since 2.1
+ */
+public interface IActionDelegate2 extends IActionDelegate {
+    /**
+     * Allows the action delegate to initialize itself after being created by
+     * the proxy action. This lifecycle method is called after the
+     * action delegate has been created and before any other method of the
+     * action delegate is called.
+     *
+     * @param action the proxy action that handles the presentation portion of
+     * the action.
+     */
+    public void init(IAction action);
+
+    /**
+     * Allows the action delegate to clean up. This lifecycle method is called
+     * when the proxy action is done with this action delegate. This is the last
+     * method called.
+     */
+    public void dispose();
+
+    /**
+     * Performs this action, passing the SWT event which triggered it. This
+     * method is called by the proxy action when the action has been triggered.
+     * Implement this method to do the actual work.
+     * <p>
+     * <b>Note:</b> This method is called instead of <code>run(IAction)</code>.
+     * </p>
+     *
+     * @param action the action proxy that handles the presentation portion of
+     * the action
+     * @param event the SWT event which triggered this action being run
+     * @since 2.0
+     */
+    public void runWithEvent(IAction action, Event event);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IActionDelegateWithEvent.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IActionDelegateWithEvent.java
new file mode 100644
index 0000000..05232e1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IActionDelegateWithEvent.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.swt.widgets.Event;
+
+/**
+ * This interface is a mixin interface for action delegates, adding the ability to
+ * examine the triggering SWT event when it is run.
+ * If an action delegate implements this interface, then <code>runWithEvent(IAction, Event)</code>
+ * is called instead of <code>run(IAction)</code>.
+ * <p>
+ * Clients should implement this interface, in addition to <code>IActionDelegate</code>
+ * (or subinterface), if they need to examine the triggering event.
+ * Otherwise, they should simply implement <code>IActionDelegate</code> (or subinterface).
+ * <p>
+ *
+ * @since 2.0
+ * @deprecated Use org.eclipse.ui.IActionDelegate2 instead.
+ */
+@Deprecated
+public interface IActionDelegateWithEvent {
+
+    /**
+     * Performs this action, passing the SWT event which triggered it.
+     * <p>
+     * This method is called when the delegating action has been triggered.
+     * Implement this method to do the actual work.
+     * If an action delegate implements this interface, this method
+     * is called instead of <code>run(IAction)</code>.
+     * <p>
+     *
+     * @param action the action proxy that handles the presentation portion of the action
+     * @param event the SWT event which triggered this action being run
+     * @since  2.0
+     * @deprecated Use org.eclipse.ui.IActionDelegate2 instead.
+     */
+    @Deprecated
+	public void runWithEvent(IAction action, Event event);
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IActionFilter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IActionFilter.java
new file mode 100644
index 0000000..6c7d35e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IActionFilter.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+/**
+ * An adapter which performs action filtering.
+ * <p>
+ * Within the workbench a plugin may extend the actions which appear in the
+ * context menu for any object.  The visibility of each action extension is controlled
+ * by action filtering.  By default, the workbench will filter each action extension using
+ * the <code>objectClass</code> and optional <code>nameFilter</code> attributes defined
+ * in xml.  If the action extension passes this test the action will be added to the
+ * context menu for the object.
+ * </p>
+ * <p>
+ * In some situations the object class and name are not enough to describe the intended
+ * target action.  In those situations an action extension may define one or more
+ * <code>filter</code> sub-elements.  Each one of these elements describes one attribute of
+ * the action target using a <code>name value</code> pair.  The attributes for an object
+ * are type specific and beyond the domain of the workbench itself, so the workbench
+ * will delegate filtering at this level to an <code>IActionFilter</code>.  This is a
+ * filtering strategy which is provided by the selection itself and may perform type
+ * specific filtering.
+ * </p>
+ * <p>
+ * The workbench will retrieve the filter from the selected object by testing to see
+ * if it implements <code>IActionFilter</code>.  If that fails, the workbench will ask for
+ * a filter through through the <code>IAdaptable</code> mechanism.  If a filter is
+ * found the workbench will pass each name value pair to the filter to determine if it
+ * matches the state of the selected object.  If so, or there is no filter, the action
+ * will be added to the context menu for the object.
+ * </p>
+ * <p>
+ * Clients that implement this filter mechanism are strongly encouraged to extend this
+ * interface to provide a list of attribute names and possible values that are
+ * considered public for other clients to reference.
+ * </p>
+ *
+ * @see org.eclipse.core.runtime.IAdaptable
+ */
+public interface IActionFilter {
+    /**
+     * Returns whether the specific attribute matches the state of the target
+     * object.
+     *
+     * @param target the target object
+     * @param name the attribute name
+     * @param value the attribute value
+     * @return <code>true</code> if the attribute matches; <code>false</code> otherwise
+     */
+    public boolean testAttribute(Object target, String name, String value);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IAggregateWorkingSet.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IAggregateWorkingSet.java
new file mode 100644
index 0000000..15dfc8c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IAggregateWorkingSet.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2015 Oakland Software 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:
+ *     Francis Upton IV, Oakland Software - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ui;
+
+/**
+ * Contains a set of {@link IWorkingSet}.
+ *
+ * Sets of working sets are used by viewers to contain all of the working
+ * sets being shown.  Sets can also be nested.
+ *
+ * In classes that implement this, the {@link IWorkingSet#getElements()} returns
+ * all of the elements of each of the working sets in this set.
+ *
+ * Instances of {@link IWorkingSet} can be cast to IAggregateWorkingSet if
+ * {@link IWorkingSet#isAggregateWorkingSet()} is true.
+ *
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @since 3.5 initial version
+ */
+public interface IAggregateWorkingSet extends IWorkingSet {
+
+	/**
+	 * Returns the working sets contained in this aggregate working set.
+	 *
+	 * Clients can do what they wish with the returned array, as it
+	 * will have no effect on the state of the this object.
+	 *
+	 * @return the working sets contained in this aggregate working set.
+	 */
+	public IWorkingSet[] getComponents();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IContainmentAdapter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IContainmentAdapter.java
new file mode 100644
index 0000000..e88b67b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IContainmentAdapter.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+/**
+ * This adapter interface provides a way to test element containment
+ * in a model-independent way.
+ * The workbench uses this interface in certain views
+ * to test if a given resource is part of a working set.
+ *
+ * @since 2.1
+ */
+public interface IContainmentAdapter {
+    /**
+     * Checks whether the given element corresponds to the containment context.
+     */
+    public static final int CHECK_CONTEXT = 1;
+
+    /**
+     * Checks whether the given element corresponds to a direct child of the
+     * containment context.  Does not include the containment context itself.
+     */
+    public static final int CHECK_IF_CHILD = 2;
+
+    /**
+     * Checks whether the given element corresponds to an ancestor of the
+     * containment context.  Does not include the containment context itself.
+     */
+    public static final int CHECK_IF_ANCESTOR = 4;
+
+    /**
+     * Checks whether the given element corresponds to a descendant of the
+     * containment context.  Does not include the containment context itself.
+     */
+    public static final int CHECK_IF_DESCENDANT = 8;
+
+    /**
+     * Returns whether the given element is considered contained
+     * in the specified containment context or if it is the context
+     * itself.
+     *
+     * @param containmentContext object that provides containment
+     * 	context for the element. This is typically a container object
+     * 	(e.g., IFolder) and may be the element object itself.
+     * @param element object that should be tested for containment
+     * @param flags one or more of <code>CHECK_CONTEXT</code>,
+     *    <code>CHECK_IF_CHILD</code>, <code>CHECK_IF_ANCESTOR</code>,
+     *    <code>CHECK_IF_DESCENDENT</code> logically ORed together.
+     */
+    public boolean contains(Object containmentContext, Object element, int flags);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IDecoratorManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IDecoratorManager.java
new file mode 100644
index 0000000..b117f7c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IDecoratorManager.java
@@ -0,0 +1,115 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.viewers.DecoratingLabelProvider;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.jface.viewers.IDelayedLabelDecorator;
+import org.eclipse.jface.viewers.ILabelDecorator;
+import org.eclipse.jface.viewers.ILightweightLabelDecorator;
+
+/**
+ * Manages the decorators contributed via the
+ * <code>org.eclipse.ui.decorator</code> extension point. Views which allow
+ * decoration of their elements should use the label decorator returned by
+ * <code>getLabelDecorator()</code>.
+ * <p>
+ * This class is not intended to be implemented by clients.
+ * </p>
+ *
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IDecoratorManager extends IDelayedLabelDecorator{
+
+    /**
+     * Returns the label decorator which applies the decorations from all
+     * enabled decorators.
+     * Views which allow decoration of their elements should use this
+     * label decorator.
+     * This decorator should be disposed when it is no longer referenced
+     * by the caller or the images created within it may be kept until
+     * {@link JFaceResources#getResources()} is disposed.
+     *
+     * @return {@link ILabelDecorator}
+     * @see DecoratingLabelProvider
+     * @see IBaseLabelProvider#dispose()
+     */
+    ILabelDecorator getLabelDecorator();
+
+    /**
+     * Return the IBaseLabelProvider that corresponds to the
+     * decoratorId. This can handle both lightweight and full
+     * decorators.
+     *
+     * @param decoratorId the decorator id
+     * @return the label provider
+     */
+    IBaseLabelProvider getBaseLabelProvider(String decoratorId);
+
+    /**
+     * Returns the full label decorator instance for the specified decorator id
+     * if it is enabled. Otherwise returns <code>null</code>. Returns
+     * <code>null</code> for lightweight decorators. It is recommended that
+     * getBaseLabelProvider is used instead so that lightweight decorators are
+     * also checked.
+     *
+     * @param decoratorId the decorator id
+     * @return the label decorator
+     */
+    ILabelDecorator getLabelDecorator(String decoratorId);
+
+    /**
+     * Returns the lightweight label decorator instance for the specified
+     * decorator id if it is enabled. Otherwise returns <code>null</code>.
+     * Returns <code>null</code> for heavyweight decorators.
+     * Use <code>getLabelDecorator</code> instead for heavyweight
+     * decorators.
+     *
+     * @param decoratorId the decorator id
+     * @return the lightweight label decorator
+     * @deprecated use getBaseLabelProvider(String) instead.
+     */
+    @Deprecated
+	ILightweightLabelDecorator getLightweightLabelDecorator(String decoratorId);
+
+    /**
+     * Returns whether the specified decorator is enabled.
+     *
+     * @param decoratorId the decorator id
+     * @return <code>true</code> if the decorator is enabled, or
+     *   <code>false</code> if not
+     */
+    boolean getEnabled(String decoratorId);
+
+    /**
+     * Sets whether the specified decorator is enabled.
+     *
+     * @param decoratorId the decorator id
+     * @param enabled <code>true</code> to enable the decorator, or
+     * <code>false</code> to disable it
+     * @throws CoreException if the decorator cannot be instantiated
+     */
+    void setEnabled(String decoratorId, boolean enabled) throws CoreException;
+
+    /**
+     * Fire a LabelProviderChangedEvent for the decorator that corresponds to
+     * decoratorID if it exists and is enabled using the IBaseLabelProvider
+     * as the argument to the event. Otherwise do nothing.
+     * <p> This method must be called from the user interface thread as widget
+     * updates may result. </p>
+     *
+     * @param decoratorId the decorator id
+     */
+    void update(String decoratorId);
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IEditorActionBarContributor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IEditorActionBarContributor.java
new file mode 100644
index 0000000..2fea70e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IEditorActionBarContributor.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+/**
+ * A editor action bar contributor defines the actions for one or more editors.
+ * <p>
+ * Within the workbench there may be more than one open editor of a particular
+ * type. For instance, there may be 1 or more open Java Editors. To avoid the
+ * creation of duplicate actions and action images the editor concept has been
+ * split into two. An action contributor is responsible for the creation of
+ * actions. The editor is responsible for action implementation. Furthermore,
+ * the contributor is shared by each open editor. As a result of this design
+ * there is only 1 set of actions for 1 or more open editors.
+ * </p>
+ * <p>
+ * The relationship between editor and contributor is defined by the
+ * <code>org.eclipse.ui.editors</code> extension point in the plugin registry.
+ * </p>
+ * <p>
+ * This interface should not be implemented directly. An implementation of this
+ * interface has been created in <code>EditorActionBarContributor</code>.
+ * Implementors should subclass this and specialize as required.
+ * </p>
+ *
+ * @see IEditorActionBarContributor
+ */
+public interface IEditorActionBarContributor {
+    /**
+     * Initializes this contributor, which is expected to add contributions as
+     * required to the given action bars and global action handlers.
+     * <p>
+     * The page is passed to support the use of <code>RetargetAction</code> by
+     * the contributor. In this case the init method implementors should:
+     * </p>
+     * <p><ul>
+     * <li>1) set retarget actions as global action handlers</li>
+     * <li>2) add the retarget actions as part listeners</li>
+     * <li>3) get the active part and if not <code>null</code>
+     * call partActivated on the retarget actions</li>
+     * </ul></p>
+     * <p>
+     * And in the dispose method the retarget actions should be removed as part listeners.
+     * </p>
+     *
+     * @param bars the action bars
+     * @param page the workbench page for this contributor
+     * @since 2.0
+     */
+    public void init(IActionBars bars, IWorkbenchPage page);
+
+    /**
+     * Sets the active editor for the contributor.
+     * Implementors should disconnect from the old editor, connect to the
+     * new editor, and update the actions to reflect the new editor.
+     *
+     * @param targetEditor the new editor target
+     */
+    public void setActiveEditor(IEditorPart targetEditor);
+
+    /**
+     * Disposes this contributor.
+     *
+     * @since 2.0
+     */
+    public void dispose();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IEditorActionDelegate.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IEditorActionDelegate.java
new file mode 100644
index 0000000..f01b389
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IEditorActionDelegate.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import org.eclipse.jface.action.IAction;
+
+/**
+ * Interface for an action that is contributed into an editor-activated menu or
+ * tool bar. It extends <code>IActionDelegate</code> and adds a method for
+ * connecting the delegate to the editor it should work with. Since there is
+ * always only one action delegate per editor type, this method supplies the
+ * link to the currently active editor instance.
+ */
+public interface IEditorActionDelegate extends IActionDelegate {
+    /**
+     * Sets the active editor for the delegate.
+     * Implementors should disconnect from the old editor, connect to the
+     * new editor, and update the action to reflect the new editor.
+     *
+     * @param action the action proxy that handles presentation portion of the action
+     * @param targetEditor the new editor target
+     */
+    public void setActiveEditor(IAction action, IEditorPart targetEditor);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IEditorDescriptor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IEditorDescriptor.java
new file mode 100644
index 0000000..9717c7f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IEditorDescriptor.java
@@ -0,0 +1,102 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+
+/**
+ * Description of an editor in the workbench editor registry. The
+ * editor descriptor contains the information needed to create editor instances.
+ * <p>
+ * An editor descriptor typically represents one of three types of editors:
+ * <ul>
+ *   <li>a file editor extension for a specific file extension.</li>
+ *   <li>a file editor added by the user (via the workbench preference page)</li>
+ *   <li>a general editor extension which works on objects other than files.</li>
+ * </ul>
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented or extended by clients.
+ * </p>
+ *
+ * @see IEditorRegistry
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IEditorDescriptor extends IWorkbenchPartDescriptor {
+    /**
+     * Returns the editor id.
+     * <p>
+     * For internal editors, this is the extension id as defined in the workbench
+     * registry; for external editors, it is path and file name of the external
+     * program.
+     * </p>
+     *
+     * @return the id of the editor
+     */
+    @Override
+	public String getId();
+
+    /**
+     * Returns the descriptor of the image for this editor.
+     *
+     * @return the descriptor of the image to display next to this editor
+     */
+    @Override
+	public ImageDescriptor getImageDescriptor();
+
+    /**
+     * Returns the label to show for this editor.
+     *
+     * @return the editor label
+     */
+    @Override
+	public String getLabel();
+
+    /**
+     * Returns whether this editor descriptor will open a regular editor
+     * part inside the editor area.
+     *
+     * @return <code>true</code> if editor is inside editor area, and
+     * <code>false</code> otherwise
+     * @since 3.0
+     */
+    public boolean isInternal();
+
+    /**
+     * Returns whether this editor descriptor will open an external
+     * editor in-place inside the editor area.
+     *
+     * @return <code>true</code> if editor is in-place, and <code>false</code>
+     * otherwise
+     * @since 3.0
+     */
+    public boolean isOpenInPlace();
+
+    /**
+     * Returns whether this editor descriptor will open an external editor
+     * in a new window outside the workbench.
+     *
+     * @return <code>true</code> if editor is external, and <code>false</code>
+     * otherwise
+     * @since 3.0
+     */
+    public boolean isOpenExternal();
+
+    /**
+     * Returns the editor matching strategy object for editors
+     * represented by this editor descriptor, or <code>null</code>
+     * if there is no explicit matching strategy specified.
+     *
+     * @return the editor matching strategy, or <code>null</code> if none
+     * @since 3.1
+     */
+    public IEditorMatchingStrategy getEditorMatchingStrategy();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IEditorInput.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IEditorInput.java
new file mode 100644
index 0000000..152edfd
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IEditorInput.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.jface.resource.ImageDescriptor;
+
+/**
+ * <code>IEditorInput</code> is a light weight descriptor of editor input,
+ * like a file name but more abstract. It is not a model. It is a description of
+ * the model source for an <code>IEditorPart</code>.
+ * <p>
+ * Clients implementing this editor input interface should override
+ * <code>Object.equals(Object)</code> to answer true for two inputs that are
+ * the same. The <code>IWorbenchPage.openEditor</code> APIs are dependent on
+ * this to find an editor with the same input.
+ * </p>
+ * <p>
+ * Clients should extend this interface to declare new types of editor inputs.
+ * </p>
+ * <p>
+ * An editor input is passed to an editor via the <code>IEditorPart.init</code>
+ * method. Due to the wide range of valid editor inputs, it is not possible to
+ * define generic methods for getting and setting bytes.
+ * </p>
+ * <p>
+ * Editor input must implement the <code>IAdaptable</code> interface;
+ * extensions are managed by the platform's adapter manager.
+ * </p>
+ * <p>
+ * Please note that it is important that the editor input be light weight.
+ * Within the workbench, the navigation history tends to hold on to editor
+ * inputs as a means of reconstructing the editor at a later time. The
+ * navigation history can hold on to quite a few inputs (i.e., the default is
+ * fifty). The actual data model should probably not be held in the input.
+ * </p>
+ *
+ *
+ * @see org.eclipse.ui.IEditorPart
+ * @see org.eclipse.ui.IWorkbenchPage#openEditor(IEditorInput, String)
+ * @see org.eclipse.ui.IWorkbenchPage#openEditor(IEditorInput, String, boolean)
+ */
+public interface IEditorInput extends IAdaptable {
+	/**
+	 * Returns whether the editor input exists.
+	 * <p>
+	 * This method is primarily used to determine if an editor input should
+	 * appear in the "File Most Recently Used" menu. An editor input will appear
+	 * in the list until the return value of <code>exists</code> becomes
+	 * <code>false</code> or it drops off the bottom of the list.
+	 *
+	 * @return <code>true</code> if the editor input exists;
+	 *         <code>false</code> otherwise
+	 */
+	public boolean exists();
+
+	/**
+	 * Returns the image descriptor for this input.
+	 *
+	 * <p>
+	 * Note: although a null return value has never been permitted from this
+	 * method, there are many known buggy implementations that return null.
+	 * Clients that need the image for an editor are advised to use
+	 * IWorkbenchPart.getImage() instead of IEditorInput.getImageDescriptor(),
+	 * or to recover from a null return value in a manner that records the ID of
+	 * the problematic editor input. Implementors that have been returning null
+	 * from this method should pick some other default return value (such as
+	 * ImageDescriptor.getMissingImageDescriptor()).
+	 * </p>
+	 *
+	 * @return the image descriptor for this input; may be <code>null</code> if
+	 * there is no image.
+	 */
+	public ImageDescriptor getImageDescriptor();
+
+	/**
+	 * Returns the name of this editor input for display purposes.
+	 * <p>
+	 * For instance, when the input is from a file, the return value would
+	 * ordinarily be just the file name.
+	 *
+	 * @return the name string; never <code>null</code>;
+	 */
+	public String getName();
+
+	/**
+	 * Returns an object that can be used to save the state of this editor
+	 * input.
+	 *
+	 * @return the persistable element, or <code>null</code> if this editor
+	 *         input cannot be persisted
+	 */
+	public IPersistableElement getPersistable();
+
+	/**
+	 * Returns the tool tip text for this editor input. This text is used to
+	 * differentiate between two input with the same name. For instance,
+	 * MyClass.java in folder X and MyClass.java in folder Y. The format of the
+	 * text varies between input types.
+	 * </p>
+	 *
+	 * @return the tool tip text; never <code>null</code>.
+	 */
+	public String getToolTipText();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IEditorLauncher.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IEditorLauncher.java
new file mode 100644
index 0000000..10019f1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IEditorLauncher.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * An editor launcher is used to launch external editors on a
+ * file in the local file system.
+ * <p>
+ * Clients should implement this interface to define a new type of editor
+ * launcher.  Each new launcher must be registered as an editor in the
+ * workbench's editor extension point
+ * (named <code>"org.eclipse.ui.editors"</code>).
+ *
+ * For example, the plug-in's XML markup might contain:
+ * <pre>
+ * &LT;extension point = "org.eclipse.ui.editors"&GT;
+ *   &LT;editor
+ *       id="org.eclipse.ui.SwingEditorLauncher"
+ *       name="Swing Editor"
+ *       extensions="xml"
+ *       launcher="org.eclipse.ui.examples.swingeditor.SwingEditorLauncher"
+ *       icon="icons/xml.gif"&GT;
+ *   &LT;/editor&GT;
+ * &LT;/extension&GT;
+ * </pre>
+ * </p><p>
+ * In this example a launcher has been registered for use with <code>xml</code>
+ * files.  Once registered, the launcher will appear in the <code>Open With</code>
+ * menu for an <code>xml</code> file.  If the item is invoked the workbench will
+ * create an instance of the launcher class and call <code>open</code> on it,
+ * passing the input file.
+ * </p>
+ */
+public interface IEditorLauncher {
+
+    /**
+     * Launches this external editor to edit the file at the given
+     * location in the local file system.
+     *
+     * @param file the local file system path of the file to edit
+     */
+    public void open(IPath file);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IEditorMatchingStrategy.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IEditorMatchingStrategy.java
new file mode 100644
index 0000000..93ae801
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IEditorMatchingStrategy.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui;
+
+/**
+ * An editor matching strategy allows editor extensions to provide their own
+ * algorithm for matching the input of an open editor of that type to a
+ * given editor input.  This is used to find a matching editor during
+ * {@link org.eclipse.ui.IWorkbenchPage#openEditor(IEditorInput, String, boolean)} and
+ * {@link org.eclipse.ui.IWorkbenchPage#findEditor(IEditorInput)}.
+ *
+ * @since 3.1
+ */
+public interface IEditorMatchingStrategy {
+
+    /**
+     * Returns whether the editor represented by the given editor reference
+     * matches the given editor input.
+     * <p>
+     * Implementations should inspect the given editor input first,
+     * and try to reject it early before calling <code>IEditorReference.getEditorInput()</code>,
+     * since that method may be expensive.
+     * </p>
+     *
+     * @param editorRef the editor reference to match against
+     * @param input the editor input to match
+     * @return <code>true</code> if the editor matches the given editor input,
+     *   <code>false</code> if it does not match
+     */
+    boolean matches(IEditorReference editorRef, IEditorInput input);
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IEditorPart.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IEditorPart.java
new file mode 100644
index 0000000..5c8ae8a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IEditorPart.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+/**
+ * An editor is a visual component within a workbench page. It is
+ * typically used to edit or browse a document or input object. The input
+ * is identified using an <code>IEditorInput</code>.  Modifications made
+ * in an editor part follow an open-save-close lifecycle model (in contrast
+ * to a view part, where modifications are saved to the workbench
+ * immediately).
+ * <p>
+ * An editor is document or input-centric.  Each editor has an input, and only
+ * one editor can exist for each editor input within a page.  This policy has
+ * been designed to simplify part management.
+ * </p><p>
+ * An editor should be used in place of a view whenever more than one instance
+ * of a document type can exist.
+ * </p><p>
+ * This interface may be implemented directly.  For convenience, a base
+ * implementation is defined in <code>EditorPart</code>.
+ * </p>
+ * <p>
+ * An editor part is added to the workbench in two stages:
+ * <ol>
+ * 	<li>An editor extension is contributed to the workbench registry. This
+ *    extension defines the extension id, extension class, and the file
+ *    extensions which are supported by the editor.</li>
+ *  <li>An editor part based upon the extension is created and added to the
+ *    workbench when the user opens a file with one of the supported file
+ *    extensions (or some other suitable form of editor input).</li>
+ * </ol>
+ * </p>
+ * <p>
+ * All editor parts implement the <code>IAdaptable</code> interface; extensions
+ * are managed by the platform's adapter manager.
+ * </p>
+ *
+ * @see org.eclipse.ui.IWorkbenchPage#openEditor(IEditorInput, String)
+ * @see org.eclipse.ui.part.EditorPart
+ */
+public interface IEditorPart extends IWorkbenchPart, ISaveablePart {
+
+    /**
+     * The property id for <code>isDirty</code>.
+     */
+    public static final int PROP_DIRTY = IWorkbenchPartConstants.PROP_DIRTY;
+
+    /**
+     * The property id for <code>getEditorInput</code>.
+     */
+    public static final int PROP_INPUT = IWorkbenchPartConstants.PROP_INPUT;
+
+    /**
+     * Returns the input for this editor.  If this value changes the part must
+     * fire a property listener event with <code>PROP_INPUT</code>.
+     *
+     * @return the editor input
+     */
+    public IEditorInput getEditorInput();
+
+    /**
+     * Returns the site for this editor.
+     * This method is equivalent to <code>(IEditorSite) getSite()</code>.
+     * <p>
+     * The site can be <code>null</code> while the editor is being initialized.
+     * After the initialization is complete, this value must be non-<code>null</code>
+     * for the remainder of the editor's life cycle.
+     * </p>
+     *
+     * @return the editor site; this value may be <code>null</code> if the editor
+     *         has not yet been initialized
+     */
+    public IEditorSite getEditorSite();
+
+    /**
+     * Initializes this editor with the given editor site and input.
+     * <p>
+     * This method is automatically called shortly after the part is instantiated.
+     * It marks the start of the part's lifecycle. The
+     * {@link IWorkbenchPart#dispose IWorkbenchPart.dispose} method will be called
+     * automically at the end of the lifecycle. Clients must not call this method.
+     * </p><p>
+     * Implementors of this method must examine the editor input object type to
+     * determine if it is understood.  If not, the implementor must throw
+     * a <code>PartInitException</code>
+     * </p>
+     * @param site the editor site
+     * @param input the editor input
+     * @exception PartInitException if this editor was not initialized successfully
+     */
+    public void init(IEditorSite site, IEditorInput input)
+            throws PartInitException;
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IEditorReference.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IEditorReference.java
new file mode 100644
index 0000000..26e32bb
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IEditorReference.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+/**
+ * Implements a reference to an editor. The IEditorPart will not be instantiated
+ * until the editor becomes visible or the API {@link #getEditor(boolean)} is
+ * called with true.
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ *
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IEditorReference extends IWorkbenchPartReference {
+    /**
+     * Returns the factory id of the factory used to
+     * restore this editor. Returns null if the editor
+     * is not persistable.
+     */
+    public String getFactoryId();
+
+	/**
+	 * Returns the editor input's name. May return null if the name is not
+	 * available or if the editor failed to be restored.
+	 */
+    public String getName();
+
+    /**
+     * Returns the editor referenced by this object.
+     * Returns <code>null</code> if the editor was not instantiated or
+     * it failed to be restored. Tries to restore the editor
+     * if <code>restore</code> is true.
+     */
+    public IEditorPart getEditor(boolean restore);
+
+	/**
+	 * Returns true if the editor is pinned, otherwise returns false.
+	 */
+    public boolean isPinned();
+
+    /**
+     * Returns the editor input for the editor referenced by this object.
+     * <p>
+     * Unlike most of the other methods on this type, this method
+     * can trigger plug-in activation.
+     * </p>
+     *
+     * @return the editor input for the editor referenced by this object
+     * @throws PartInitException if there was an error restoring the editor input
+     * @since 3.1
+     */
+    public IEditorInput getEditorInput() throws PartInitException;
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IEditorRegistry.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IEditorRegistry.java
new file mode 100644
index 0000000..5e2903d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IEditorRegistry.java
@@ -0,0 +1,270 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import org.eclipse.core.runtime.content.IContentType;
+import org.eclipse.jface.resource.ImageDescriptor;
+
+/**
+ * Registry of editors known to the workbench.
+ * <p>
+ * An editor can be created in one of two ways:
+ * <ul>
+ *   <li>An editor can be defined by an extension to the workbench.</li>
+ *   <li>The user manually associates an editor with a given resource extension
+ *      type. This will override any default workbench or platform association.
+ *      </li>
+ * </ul>
+ * </p>
+ * <p>
+ * The registry does not keep track of editors that are "implicitly" determined.
+ * For example a bitmap (<code>.bmp</code>) file will typically not have a
+ * registered editor. Instead, when no registered editor is found, the
+ * underlying OS is consulted.
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ *
+ * @see org.eclipse.ui.IWorkbench#getEditorRegistry()
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IEditorRegistry {
+
+    /**
+     * The property identifier for the contents of this registry.
+     */
+    public static final int PROP_CONTENTS = 0x01;
+
+    /**
+     * The identifier for the system external editor descriptor. This descriptor
+     * is always present in the registry on all platforms.
+     * This editor requires an input which implements
+     * {@link org.eclipse.ui.IPathEditorInput IPathEditorInput}.
+     * Use {@link #findEditor findEditor} to access the editor descriptor for
+     * this identifier.
+     *
+     * @since 3.0
+     */
+    public static final String SYSTEM_EXTERNAL_EDITOR_ID = "org.eclipse.ui.systemExternalEditor"; //$NON-NLS-1$
+
+    /**
+     * The identifier for the system in-place editor descriptor. This descriptor
+     * is only present in the registry on platforms that support in-place editing
+     * (for example Win32). This editor requires an input which implements
+     * {@link org.eclipse.ui.IInPlaceEditorInput IInPlaceEditorInput}. Use
+     * {@link #findEditor findEditor} to access the editor descriptor for this
+     * identifier.
+     *
+     * @since 3.0
+     */
+    public static final String SYSTEM_INPLACE_EDITOR_ID = "org.eclipse.ui.systemInPlaceEditor"; //$NON-NLS-1$
+
+    /**
+     * Adds a listener for changes to properties of this registry.
+     * Has no effect if an identical listener is already registered.
+     * <p>
+     * The properties ids are as follows:
+     * <ul>
+     *   <li><code>PROP_CONTENTS</code>: Triggered when the file editor mappings in
+     *       the editor registry change.</li>
+     * </ul>
+     * </p>
+     *
+     * @param listener a property listener
+     */
+    public void addPropertyListener(IPropertyListener listener);
+
+    /**
+     * Finds and returns the descriptor of the editor with the given editor id.
+     *
+     * @param editorId the editor id
+     * @return the editor descriptor with the given id, or <code>null</code> if not
+     *   found
+     */
+    public IEditorDescriptor findEditor(String editorId);
+
+    /**
+     * Returns the default editor. The default editor always exist.
+     *
+     * @return the descriptor of the default editor
+     * @deprecated The system external editor is the default editor.
+     * Use <code>findEditor(IEditorRegistry.SYSTEM_EXTERNAL_EDITOR_ID)</code>
+     * instead.
+     */
+    @Deprecated
+	public IEditorDescriptor getDefaultEditor();
+
+    /**
+	 * Returns the default editor for a given file name. This method assumes an
+	 * unknown content type for the given file.
+	 * <p>
+	 * The default editor is determined by taking the file extension for the
+	 * file and obtaining the default editor for that extension.
+	 * </p>
+	 *
+	 * @param fileName
+	 *            the file name in the system
+	 * @return the descriptor of the default editor, or <code>null</code> if
+	 *         not found
+	 */
+    public IEditorDescriptor getDefaultEditor(String fileName);
+
+    /**
+     * Returns the default editor for a given file name and with the given content type.
+     * <p>
+     * The default editor is determined by taking the file extension for the
+     * file and obtaining the default editor for that extension.
+     * </p>
+     *
+     * @param fileName the file name in the system
+     * @param contentType the content type or <code>null</code> for the unknown content type
+     * @return the descriptor of the default editor, or <code>null</code> if not
+     *   found
+     * @since 3.1
+     */
+    public IEditorDescriptor getDefaultEditor(String fileName, IContentType contentType);
+
+    /**
+	 * Returns the list of file editors registered to work against the file with
+	 * the given file name. This method assumes an unknown content type for the
+	 * given file.
+	 * <p>
+	 * Note: Use <code>getDefaultEditor(String)</code> if you only the need
+	 * the default editor rather than all candidate editors.
+	 * </p>
+	 *
+	 * @param fileName
+	 *            the file name in the system
+	 * @return a list of editor descriptors
+	 */
+    public IEditorDescriptor[] getEditors(String fileName);
+
+    /**
+	 * Returns the list of file editors registered to work against the file with
+	 * the given file name and with the given content type.
+	 * <p>
+	 * Note: Use <code>getDefaultEditor(String)</code> if you only the need
+	 * the default editor rather than all candidate editors.
+	 * </p>
+	 *
+	 * @param fileName
+	 *            the file name in the system
+	 * @param contentType
+	 *            the content type or <code>null</code> for the unknown
+	 *            content type
+	 * @return a list of editor descriptors
+	 * @since 3.1
+	 */
+    public IEditorDescriptor[] getEditors(String fileName, IContentType contentType);
+
+    /**
+     * Returns a list of mappings from file type to editor.  The resulting list
+     * is sorted in ascending order by file extension.
+     * <p>
+     * Each mapping defines an extension and the set of editors that are
+     * available for that type. The set of editors includes those registered
+     * via plug-ins and those explicitly associated with a type by the user
+     * in the workbench preference pages.
+     * </p>
+     *
+     * @return a list of mappings sorted alphabetically by extension
+     */
+    public IFileEditorMapping[] getFileEditorMappings();
+
+    /**
+	 * Returns the image descriptor associated with a given file. This image is
+	 * usually displayed next to the given file. This method assumes an unknown
+	 * content type for the given file.
+	 * <p>
+	 * The image is determined by taking the file extension of the file and
+	 * obtaining the image for the default editor associated with that
+	 * extension. A default image is returned if no default editor is available.
+	 * </p>
+	 *
+	 * @param filename
+	 *            the file name in the system
+	 * @return the descriptor of the image to display next to the file
+	 */
+    public ImageDescriptor getImageDescriptor(String filename);
+
+    /**
+	 * Returns the image descriptor associated with a given file. This image is
+	 * usually displayed next to the given file.
+	 * <p>
+	 * The image is determined by taking the file extension of the file and
+	 * obtaining the image for the default editor associated with that
+	 * extension. A default image is returned if no default editor is available.
+	 * </p>
+	 *
+	 * @param filename
+	 *            the file name in the system
+	 * @param contentType
+	 *            the content type of the file or <code>null</code> for the
+	 *            unknown content type
+	 * @return the descriptor of the image to display next to the file
+	 * @since 3.1
+	 */
+    public ImageDescriptor getImageDescriptor(String filename, IContentType contentType);
+
+    /**
+	 * Removes the given property listener from this registry. Has no effect if
+	 * an identical listener is not registered.
+	 *
+	 * @param listener
+	 *            a property listener
+	 */
+    public void removePropertyListener(IPropertyListener listener);
+
+    /**
+     * Sets the default editor id for the files that match that
+     * specified file name or extension. The specified editor must be
+     * defined as an editor for that file name or extension.
+     *
+     * @param fileNameOrExtension the file name or extension pattern (e.g. "*.xml");
+     * @param editorId the editor id or <code>null</code> for no default
+     */
+    public void setDefaultEditor(String fileNameOrExtension, String editorId);
+
+    /**
+     * Returns whether there is an in-place editor that could handle a file
+     * with the given name.
+     *
+     * @param filename the file name
+     * @return <code>true</code> if an in-place editor is available, and
+     * <code>false</code> otherwise
+     * @since 3.0
+     */
+    public boolean isSystemInPlaceEditorAvailable(String filename);
+
+    /**
+     * Returns whether the system has an editor that could handle a file
+     * with the given name.
+     *
+     * @param filename the file name
+     * @return <code>true</code> if an external editor available, and
+     * <code>false</code> otherwise
+     * @since 3.0
+     */
+    public boolean isSystemExternalEditorAvailable(String filename);
+
+    /**
+     * Returns the image descriptor associated with the system editor that
+     * would be used to edit this file externally.
+     *
+     * @param filename the file name
+     * @return the descriptor of the external editor image, or <code>null</code>
+     * if none
+     * @since 3.0
+     */
+    public ImageDescriptor getSystemExternalEditorImageDescriptor(
+            String filename);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IEditorSite.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IEditorSite.java
new file mode 100644
index 0000000..414d97c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IEditorSite.java
@@ -0,0 +1,115 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.viewers.ISelectionProvider;
+
+/**
+ * The primary interface between an editor part and the workbench.
+ * <p>
+ * The workbench exposes its implemention of editor part sites via this
+ * interface, which is not intended to be implemented or extended by clients.
+ * </p>
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IEditorSite extends IWorkbenchPartSite {
+
+    /**
+     * Returns the action bar contributor for this editor.
+     * <p>
+     * An action contributor is responsable for the creation of actions.
+     * By design, this contributor is used for one or more editors of the same type.
+     * Thus, the contributor returned by this method is not owned completely
+     * by the editor - it is shared.
+     * </p>
+     *
+     * @return the editor action bar contributor, or <code>null</code> if none exists
+     */
+    public IEditorActionBarContributor getActionBarContributor();
+
+    /**
+	 * Returns the action bars for this part site. Editors of the same type (and
+	 * in the same window) share the same action bars. Contributions to the
+	 * action bars are done by the <code>IEditorActionBarContributor</code>.
+	 *
+	 * @return the action bars
+	 * @since 2.1
+	 */
+    public IActionBars getActionBars();
+
+    /**
+     * <p>
+     * Registers a pop-up menu with the default id for extension. The default id
+     * is defined as the part id.
+     * </p>
+     * <p>
+     * By default, context menus include object contributions based on the
+     * editor input for the current editor. It is possible to override this
+     * behaviour by calling this method with <code>includeEditorInput</code>
+     * as <code>false</code>. This might be desirable for editors that
+     * present a localized view of an editor input (e.g., a node in a model
+     * editor).
+     * </p>
+     * <p>
+     * For a detailed description of context menu registration see
+     * {@link IWorkbenchPartSite#registerContextMenu(MenuManager, ISelectionProvider)}
+     * </p>
+     *
+     * @param menuManager
+     *            the menu manager; must not be <code>null</code>.
+     * @param selectionProvider
+     *            the selection provider; must not be <code>null</code>.
+     * @param includeEditorInput
+     *            Whether the editor input should be included when adding object
+     *            contributions to this context menu.
+     * @see IWorkbenchPartSite#registerContextMenu(MenuManager,
+     *      ISelectionProvider)
+     * @since 3.1
+     */
+    public void registerContextMenu(MenuManager menuManager,
+            ISelectionProvider selectionProvider, boolean includeEditorInput);
+
+    /**
+     * <p>
+     * Registers a pop-up menu with a particular id for extension. This method
+     * should only be called if the target part has more than one context menu
+     * to register.
+     * </p>
+     * <p>
+     * By default, context menus include object contributions based on the
+     * editor input for the current editor. It is possible to override this
+     * behaviour by calling this method with <code>includeEditorInput</code>
+     * as <code>false</code>. This might be desirable for editors that
+     * present a localized view of an editor input (e.g., a node in a model
+     * editor).
+     * </p>
+     * <p>
+     * For a detailed description of context menu registration see
+     * {@link IWorkbenchPartSite#registerContextMenu(MenuManager, ISelectionProvider)}
+     * </p>
+     *
+     * @param menuId
+     *            the menu id; must not be <code>null</code>.
+     * @param menuManager
+     *            the menu manager; must not be <code>null</code>.
+     * @param selectionProvider
+     *            the selection provider; must not be <code>null</code>.
+     * @param includeEditorInput
+     *            Whether the editor input should be included when adding object
+     *            contributions to this context menu.
+     * @see IWorkbenchPartSite#registerContextMenu(MenuManager,
+     *      ISelectionProvider)
+     * @since 3.1
+     */
+    public void registerContextMenu(String menuId, MenuManager menuManager,
+            ISelectionProvider selectionProvider, boolean includeEditorInput);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IElementFactory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IElementFactory.java
new file mode 100644
index 0000000..2c59b0e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IElementFactory.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import org.eclipse.core.runtime.IAdaptable;
+
+/**
+ * A factory for re-creating objects from a previously saved memento.
+ * <p>
+ * Clients should implement this interface and include the name of their class
+ * in an extension to the platform extension point named
+ * <code>"org.eclipse.ui.elementFactories"</code>.
+ * For example, the plug-in's XML markup might contain:
+ * <pre>
+ * &LT;extension point="org.eclipse.ui.elementFactories"&GT;
+ *    &LT;factory id="com.example.myplugin.MyFactory" class="com.example.myplugin.MyFactory" /&GT;
+ * &LT;/extension&GT;
+ * </pre>
+ * </p>
+ *
+ * @see IPersistableElement
+ * @see IMemento
+ * @see org.eclipse.ui.IWorkbench#getElementFactory
+ */
+public interface IElementFactory {
+    /**
+	 * Re-creates and returns an object from the state captured within the given
+	 * memento.
+	 * <p>
+	 * If the result is not null, it should be persistable; that is,
+	 * <pre>
+	 * result.getAdapter(org.eclipse.ui.IPersistableElement.class)
+	 * </pre>
+	 * should not return <code>null</code>.
+	 * </p>
+	 *
+	 * @param memento
+	 *            a memento containing the state for the object
+	 * @return an object, or <code>null</code> if the element could not be
+	 *         created
+	 */
+    public IAdaptable createElement(IMemento memento);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IExportWizard.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IExportWizard.java
new file mode 100644
index 0000000..6b1ce90
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IExportWizard.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+/**
+ * Interface for export wizards.
+ * <p>
+ * Clients should implement this interface and include the name of their class
+ * in a wizard contributed to the workbench's export wizard extension point
+ * (named <code>"org.eclipse.ui.exportWizards"</code>).
+ * For example, the plug-in's XML markup might contain:
+ * <pre>
+ * &LT;extension point="org.eclipse.ui.exportWizards"&GT;
+ *   &LT;wizard
+ *       id="com.example.myplugin.blob"
+ *       name="Blob File"
+ *       class="com.example.myplugin.BlobFileExporter"
+ *       icon="icons/export_blob_wiz.gif"&GT;
+ *     &LT;description&GT;Export resources to a BLOB file&LT;/description&GT;
+ *     &LT;selection class="org.eclipse.core.resources.IResource" /&GT;
+ *   &LT;/wizard&GT;
+ * &LT;/extension&GT;
+ * </pre>
+ * </p>
+ *
+ * @see org.eclipse.jface.wizard.IWizard
+ */
+public interface IExportWizard extends IWorkbenchWizard {
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IFileEditorMapping.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IFileEditorMapping.java
new file mode 100644
index 0000000..c77eff5
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IFileEditorMapping.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Jan-Hendrik Diederich, Bredex GmbH - bug 201052
+ *******************************************************************************/
+package org.eclipse.ui;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+
+/**
+ * An association between a file name/extension and a list of known editors for
+ * files of that type.
+ * <p>
+ * The name and extension can never empty or null. The name may contain
+ * the single wild card character (*) to indicate the editor applies to
+ * all files with the same extension (e.g. *.doc). The name can never
+ * embed the wild card character within itself (i.e. rep*)
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ *
+ * @see IEditorRegistry#getFileEditorMappings
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IFileEditorMapping {
+    /**
+     * Returns the default editor registered for this type mapping.
+     *
+     * @return the descriptor of the default editor, or <code>null</code> if there
+     *   is no default editor registered. Will also return <code>null</code> if
+     *   the default editor exists but fails the Expressions check.
+     */
+    public IEditorDescriptor getDefaultEditor();
+
+    /**
+     * Returns the list of editors registered for this type mapping.
+     *
+     * @return a possibly empty list of editors.
+     */
+    public IEditorDescriptor[] getEditors();
+
+    /**
+     * Returns the list of editors formerly registered for this type mapping
+     * which have since been deleted.
+     *
+     * @return a possibly empty list of editors
+     */
+    public IEditorDescriptor[] getDeletedEditors();
+
+    /**
+     * Returns the file's extension for this type mapping.
+     *
+     * @return the extension for this mapping
+     */
+    public String getExtension();
+
+    /**
+     * Returns the descriptor of the image to use for a file of this type.
+     * <p>
+     * The image is obtained from the default editor. A default file image is
+     * returned if no default editor is available.
+     * </p>
+     *
+     * @return the descriptor of the image to use for a resource of this type
+     */
+    public ImageDescriptor getImageDescriptor();
+
+    /**
+     * Returns the label to use for this mapping.
+     * Labels have the form "<it>name</it>.<it>extension</it>".
+     *
+     * @return the label to use for this mapping
+     */
+    public String getLabel();
+
+    /**
+     * Returns the file's name for this type mapping.
+     *
+     * @return the name for this mapping
+     */
+    public String getName();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IFolderLayout.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IFolderLayout.java
new file mode 100644
index 0000000..1a763ea
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IFolderLayout.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+/**
+ * An <code>IFolderLayout</code> is used to define the initial views within a folder.
+ * The folder itself is contained within an <code>IPageLayout</code>.
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ *
+ * @see IPageLayout#createFolder
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IFolderLayout extends IPlaceholderFolderLayout {
+    /**
+     * Adds a view with the given compound id to this folder.
+     * See the {@link IPageLayout} type documentation for more details about compound ids.
+     * The primary id must name a view contributed to the workbench's view extension point
+     * (named <code>"org.eclipse.ui.views"</code>).
+     *
+     * @param viewId the view id
+     */
+    public void addView(String viewId);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IImportWizard.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IImportWizard.java
new file mode 100644
index 0000000..8527581
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IImportWizard.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+/**
+ * Interface for import wizards.
+ * <p>
+ * Clients should implement this interface and include the name of their class
+ * in a wizard contributed to the workbench's import wizard extension point
+ * (named <code>"org.eclipse.ui.importWizards"</code>).
+ * For example, the plug-in's XML markup might contain:
+ * <pre>
+ * &LT;extension point="org.eclipse.ui.importWizards"&GT;
+ *   &LT;wizard
+ *       id="com.example.myplugin.blob"
+ *       name="Blob File"
+ *       class="com.example.myplugin.BlobFileImporter"
+ *       icon="icons/import_blob_wiz.gif"&GT;
+ *     &LT;description&GT;Import resources from a BLOB file&LT;/description&GT;
+ *     &LT;selection class="org.eclipse.core.resources.IResource" /&GT;
+ *   &LT;/wizard&GT;
+ * &LT;/extension&GT;
+ * </pre>
+ * </p>
+ *
+ * @see org.eclipse.jface.wizard.IWizard
+ */
+public interface IImportWizard extends IWorkbenchWizard {
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IInPlaceEditor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IInPlaceEditor.java
new file mode 100644
index 0000000..19aa4a7
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IInPlaceEditor.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui;
+
+/**
+ * Interface for editor parts that represent an in-place style editor.
+ * <p>
+ * This interface is not intended to be implemented or extended by clients.
+ * </p>
+ *
+ * @see org.eclipse.ui.IEditorDescriptor#isOpenInPlace()
+ * @since 3.0
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IInPlaceEditor extends IEditorPart {
+    /**
+     * Informs the in-place editor that the system file it is
+     * editing was deleted by the application.
+     */
+    public void sourceDeleted();
+
+    /**
+     * Informs the in-place editor that the system file it is
+     * editing was moved or renamed by the application.
+     *
+     * @param input the new in-place editor input to use
+     */
+    public void sourceChanged(IInPlaceEditorInput input);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IInPlaceEditorInput.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IInPlaceEditorInput.java
new file mode 100644
index 0000000..edceb63
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IInPlaceEditorInput.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui;
+
+/**
+ * This interface defines an editor input for in-place editors.
+ * <p>
+ * Clients implementing this editor input interface should override
+ * <code>Object.equals(Object)</code> to answer true for two inputs
+ * that are the same. The <code>IWorkbenchPage.openEditor</code> APIs
+ * are dependent on this to find an editor with the same input.
+ * </p><p>
+ * Path-oriented editors should support this as a valid input type, and
+ * can allow full read-write editing of its content.
+ * </p><p>
+ * All editor inputs must implement the <code>IAdaptable</code> interface;
+ * extensions are managed by the platform's adapter manager.
+ * </p>
+ *
+ * @see org.eclipse.ui.IInPlaceEditor
+ * @since 3.0
+ */
+public interface IInPlaceEditorInput extends IPathEditorInput {
+    /**
+     * Sets the in-place editor this input is associated with.
+     *
+     * @param editor the in-place editor associated with this input
+     * 		or <code>null</code> to disassociate.
+     */
+    public void setInPlaceEditor(IInPlaceEditor editor);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IKeyBindingService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IKeyBindingService.java
new file mode 100644
index 0000000..5c07928
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IKeyBindingService.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import org.eclipse.jface.action.IAction;
+
+/**
+ * The key binding service allows one to query or set the scope of Eclipse for
+ * the purposes of resolving key assignments to commands, and to register
+ * actions to handle specific commands. See the <code>org.eclipse.ui.commands</code>
+ * extension point for details.
+ * <p>
+ * A participating workbench part is responsible to register all its actions
+ * with this service. The part is also responsible to set the current scope.
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented or extended by clients.
+ * </p>
+ *
+ * @since 2.0
+ * @deprecated See IContextService to manage <b>scopes</b> and
+ * IHandlerService to manage handlers. IAction can
+ * be proxied by org.eclipse.jface.commands.ActionHandler.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+@Deprecated
+public interface IKeyBindingService {
+
+    /**
+     * Returns the active accelerator scope ids.
+     *
+     * @return the active accelerator scope ids.
+     */
+    String[] getScopes();
+
+    /**
+     * Registers an action with the key binding service.
+     *
+     * @param action
+     *            the action to be registered with the key binding service.
+     */
+    void registerAction(IAction action);
+
+    /**
+     * Sets the active accelerator scope ids.
+     *
+     * @param scopes
+     *            the active accelerator scope ids.
+     */
+    void setScopes(String[] scopes);
+
+    /**
+     * Unregisters an action with the key binding service.
+     *
+     * @param action
+     *            the action to be unregistered with the key binding service.
+     */
+    void unregisterAction(IAction action);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ILocalWorkingSetManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ILocalWorkingSetManager.java
new file mode 100644
index 0000000..3a8a640
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ILocalWorkingSetManager.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+/**
+ * A local working set manager can be used to manage a set of
+ * working sets independently from the working sets managed by
+ * the global working set manager.  A local working set manager
+ * can be saved and restored using the methods <code>saveState</code>
+ * and <code>restoreState</code>.  A new local working set manager can be created
+ * using {@link org.eclipse.ui.IWorkbench#createLocalWorkingSetManager()}.
+ * Clients of local working set managers are responsible for calling
+ * {@link IWorkingSetManager#dispose()} when the working sets it manages
+ * are no longer needed.
+ * <p>
+ * This interface is not intended to be implemented or extended by clients.
+ * </p>
+ *
+ * @see org.eclipse.ui.IWorkbench#createLocalWorkingSetManager()
+ * @since 3.1
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface ILocalWorkingSetManager extends IWorkingSetManager {
+
+	/**
+	 * Saves the state of the working set manager to the given
+	 * memento.
+	 *
+	 * @param memento the memento to save the state to
+	 */
+	public void saveState(IMemento memento);
+
+	/**
+	 * Restores the state of the working set manager from the given
+	 * memento. The method can only be called as long as the working
+	 * set manager is still empty.
+	 *
+	 * @param memento the memento to restore the state from
+	 */
+	public void restoreState(IMemento memento);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IMemento.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IMemento.java
new file mode 100644
index 0000000..637db1f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IMemento.java
@@ -0,0 +1,245 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import org.w3c.dom.DOMException;
+
+/**
+ * Interface to a memento used for saving the important state of an object in a
+ * form that can be persisted in the file system.
+ * <p>
+ * Mementos were designed with the following requirements in mind:
+ * <ol>
+ * <li>Certain objects need to be saved and restored across platform sessions.</li>
+ * <li>When an object is restored, an appropriate class for an object might not
+ * be available. It must be possible to skip an object in this case.</li>
+ * <li>When an object is restored, the appropriate class for the object may be
+ * different from the one when the object was originally saved. If so, the new
+ * class should still be able to read the old form of the data.</li>
+ * </ol>
+ * </p>
+ * <p>
+ * Mementos meet these requirements by providing support for storing a mapping
+ * of arbitrary string keys to primitive values, and by allowing mementos to
+ * have other mementos as children (arranged into a tree). A robust external
+ * storage format based on XML is used.
+ * </p>
+ * <p>
+ * The key for an attribute may be any alpha numeric value that doesn't start
+ * with a number. eg: [A-Za-z][A-Za-z0-9]* Using '.' is unsupported. However,
+ * the value of <code>TAG_ID</code> is reserved for internal use.
+ * </p>
+ * <p>
+ * The default implementation can throw a {@link DOMException} for createChild
+ * and put operations. See {@link XMLMemento}.
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented or extended by clients.
+ * </p>
+ *
+ * @see IPersistableElement
+ * @see IElementFactory
+ * @see XMLMemento
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IMemento {
+    /**
+     * Special reserved key used to store the memento id
+     * (value <code>"IMemento.internal.id"</code>).
+     *
+     * @see #getID()
+     */
+    public static final String TAG_ID = "IMemento.internal.id"; //$NON-NLS-1$
+
+    /**
+     * Creates a new child of this memento with the given type.
+     * <p>
+     * The <code>getChild</code> and <code>getChildren</code> methods
+     * are used to retrieve children of a given type.
+     * </p>
+     *
+     * @param type the type
+     * @return a new child memento
+     * @see #getChild
+     * @see #getChildren
+     */
+    public IMemento createChild(String type);
+
+    /**
+     * Creates a new child of this memento with the given type and id.
+     * The id is stored in the child memento (using a special reserved
+     * key, <code>TAG_ID</code>) and can be retrieved using <code>getId</code>.
+     * <p>
+     * The <code>getChild</code> and <code>getChildren</code> methods
+     * are used to retrieve children of a given type.
+     * </p>
+     *
+     * @param type the type
+     * @param id the child id
+     * @return a new child memento with the given type and id
+     * @see #getID
+     */
+    public IMemento createChild(String type, String id);
+
+    /**
+	 * Returns the first child with the given type id.
+	 *
+	 * @param type
+	 *            the type id
+	 * @return the first child with the given type. May return <code>null</code>
+	 *         .
+	 */
+    public IMemento getChild(String type);
+
+	/**
+	 * Returns all children of this node.
+	 *
+	 * @return an array of children of this node. This will not be
+	 *         <code>null</code>. If there are no children, an array of length
+	 *         zero will be returned.
+	 * @since 3.8
+	 */
+	public IMemento[] getChildren();
+
+    /**
+	 * Returns all children with the given type id.
+	 *
+	 * @param type
+	 *            the type id
+	 * @return an array of children with the given type. This will not be
+	 *         <code>null</code>. If there are no keys, an array of length zero
+	 *         will be returned.
+	 */
+    public IMemento[] getChildren(String type);
+
+    /**
+     * Returns the floating point value of the given key.
+     *
+     * @param key the key
+     * @return the value, or <code>null</code> if the key was not found or was found
+     *   but was not a floating point number
+     */
+    public Float getFloat(String key);
+
+    /**
+	 * Returns the type for this memento.
+	 *
+	 * @return the memento type
+	 * @see #createChild(java.lang.String)
+	 * @see #createChild(java.lang.String,java.lang.String)
+	 * @since 3.4
+	 */
+	public String getType();
+
+    /**
+     * Returns the id for this memento.
+     *
+     * @return the memento id, or <code>null</code> if none
+     * @see #createChild(java.lang.String,java.lang.String)
+     */
+    public String getID();
+
+    /**
+     * Returns the integer value of the given key.
+     *
+     * @param key the key
+     * @return the value, or <code>null</code> if the key was not found or was found
+     *   but was not an integer
+     */
+    public Integer getInteger(String key);
+
+    /**
+     * Returns the string value of the given key.
+     *
+     * @param key the key
+     * @return the value, or <code>null</code> if the key was not found
+     */
+    public String getString(String key);
+
+    /**
+	 * Returns the boolean value of the given key.
+	 *
+	 * @param key the key
+	 * @return the value, or <code>null</code> if the key was not found
+     * @since 3.4
+	 */
+	public Boolean getBoolean(String key);
+
+	/**
+     * Returns the data of the Text node of the memento. Each memento is allowed
+     * only one Text node.
+     *
+     * @return the data of the Text node of the memento, or <code>null</code>
+     * if the memento has no Text node.
+     * @since 2.0
+     */
+    public String getTextData();
+
+    /**
+     * Returns an array of all the attribute keys of the memento. This will not
+     * be <code>null</code>. If there are no keys, an array of length zero will
+     * be returned.
+     * @return an array with all the attribute keys of the memento
+     * @since 3.4
+     */
+	public String[] getAttributeKeys();
+
+    /**
+     * Sets the value of the given key to the given floating point number.
+     *
+     * @param key the key
+     * @param value the value
+     */
+    public void putFloat(String key, float value);
+
+    /**
+     * Sets the value of the given key to the given integer.
+     *
+     * @param key the key
+     * @param value the value
+     */
+    public void putInteger(String key, int value);
+
+    /**
+     * Copy the attributes and children from  <code>memento</code>
+     * to the receiver.
+     *
+     * @param memento the IMemento to be copied.
+     */
+    public void putMemento(IMemento memento);
+
+    /**
+     * Sets the value of the given key to the given string.
+     *
+     * @param key the key
+     * @param value the value
+     */
+    public void putString(String key, String value);
+
+    /**
+	 * Sets the value of the given key to the given boolean value.
+	 *
+	 * @param key the key
+	 * @param value the value
+     * @since 3.4
+	 */
+	public void putBoolean(String key, boolean value);
+
+    /**
+     * Sets the memento's Text node to contain the given data. Creates the Text node if
+     * none exists. If a Text node does exist, it's current contents are replaced.
+     * Each memento is allowed only one text node.
+     *
+     * @param data the data to be placed on the Text node
+     * @since 2.0
+     */
+    public void putTextData(String data);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/INavigationHistory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/INavigationHistory.java
new file mode 100644
index 0000000..ac52aca
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/INavigationHistory.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+/**
+ * Manages a list of entries to keep a history of locations on editors,
+ * enabling the user to go back and forward without losing context.
+ *
+ * The history is a list of <code>INavigationLocation</code> and a pointer
+ * to the current location. Whenever the back or forward action runs the
+ * history restores the previous or next location.
+ *
+ * The back and/or forward actions should not change the content of the history
+ * in any way.
+ *
+ * If the user steps N times in one direction (back or forward) and then N times to
+ * the oposite direction, the editor and location should be exactly the same as before.
+ *
+ * Clients must guarantee that the current location is
+ * always in the history, which can be done either by marking
+ * a new location or by updating the current location.
+ *
+ * Not intended to be implemented by clients.
+ *
+ * @since 2.1
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface INavigationHistory {
+    /**
+     * Mark the current location into the history. This message
+     * should be sent by clients whenever significant changes
+     * in location are detected.
+     *
+     * The location is obtained by calling <code>INavigationLocationProvider.createNavigationLocation</code>
+     *
+     * @param part the editor part
+     */
+    public void markLocation(IEditorPart part);
+
+    /**
+     * Returns the current location.
+     *
+     * @return the current location
+     */
+    public INavigationLocation getCurrentLocation();
+
+    /**
+     * Returns all entries in the history.
+     *
+     * @return all entries in the history
+     */
+    public INavigationLocation[] getLocations();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/INavigationLocation.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/INavigationLocation.java
new file mode 100644
index 0000000..71c5ad5
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/INavigationLocation.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+/**
+ * Represents the context marked for the user in the navigation history.
+ *
+ * Not intended to be implemented by clients. Clients should subclass NavigationLocation
+ * instead.
+ *
+ * @since 2.1
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface INavigationLocation {
+
+    /**
+     * Disposes of this location and frees any allocated resource.
+     */
+    public void dispose();
+
+    /**
+     * Release any state kept by this location. Any relevant state should be
+     * saved by the previous call of saveState(IMemento). This object will
+     * not be used until restoreState is called again.
+     */
+    public void releaseState();
+
+    /**
+     * Persists the state of this location into the <code>memento</code>
+     *
+     * @param memento the storage were the state should be saved into.
+     */
+    public void saveState(IMemento memento);
+
+    /**
+     * Restore the state of this location from the <code>memento</code>
+     *
+     * @param memento the storage were the state was saved into.
+     */
+    public void restoreState(IMemento memento);
+
+    /**
+     * Restore the context saved by this location.
+     */
+    public void restoreLocation();
+
+    /**
+     * Merge the receiver into <code>currentLocation</code>. Return true if
+     * the two locations could be merged otherwise return false.
+     * <p>
+     * This message is sent to all locations before being added to the history;
+     * given the change to the new location to merge itself into the current
+     * location minimizing the number of entries in the navigation history.
+     * </p>
+     *
+     * @param currentLocation where the receiver should be merged into
+     * @return boolean true if the merge was possible
+     */
+    public boolean mergeInto(INavigationLocation currentLocation);
+
+    /**
+     * Returns the input used for this location. Returns <code>null</code> if the
+     * receiver's state has been released.
+     *
+     * @return the input for this location
+     */
+    public Object getInput();
+
+    /**
+     * Returns the display name for this location.  This name is used in the
+     * navigation history list.
+     *
+     * @return the display name
+     */
+    public String getText();
+
+    /**
+     * Sets the location's input.
+     * <p>
+     * Should not be called by clients.
+     * </p>
+     *
+     * @param input the editor input.
+     */
+    public void setInput(Object input);
+
+    /**
+     * The message <code>update</code> is sent to the active location before
+     * another location becomes active.
+     */
+    public void update();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/INavigationLocationProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/INavigationLocationProvider.java
new file mode 100644
index 0000000..26a2ee3
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/INavigationLocationProvider.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+/**
+ * Should be implemented by editors that wish to contribute to the
+ * navigation history. The message <code>createNavigationLocation</code>
+ * will be sent when a new location is marked in the history.
+ *
+ * @since 2.1
+ */
+public interface INavigationLocationProvider {
+    /**
+     * Creates an empty navigation location. The message <code>restoreState</code>
+     * will be sent to the location to restore its state.
+     *
+     * @return INavigationLocation
+     */
+    public INavigationLocation createEmptyNavigationLocation();
+
+    /**
+     * Creates a navigation location describing the current state.
+     *
+     * @return INavigationLocation
+     */
+    public INavigationLocation createNavigationLocation();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/INestableKeyBindingService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/INestableKeyBindingService.java
new file mode 100644
index 0000000..575cbb6
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/INestableKeyBindingService.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * <p>
+ * A service that is capable of nesting other services within itself.  This
+ * allows lower level components to query for a service provider in a
+ * hierarchical fashion, and for information to be resolved in a hierarchical
+ * manner
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented or extended by clients.
+ * </p>
+ *
+ * @since 2.1.3
+ * @deprecated This is now handled by {@link IServiceLocator} which can
+ * be nested.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+@Deprecated
+public interface INestableKeyBindingService extends IKeyBindingService {
+
+    /**
+     * Marks the service associated with <code>nestedSite</code> as active if
+     * one exists.  If there is no service associated, then nothing changes.
+     * Calling this method with <code>null</code> forces deactivation of the
+     * current service.
+     *
+     * @param nestedSite The site whose service should be activated;
+     * <code>null</code> if the current service should be deactivated.
+     * @return <code>true</code> if a service is activated (or deactivated, in
+     * the case of a <code>null</code> parameter); <code>false</code> if
+     * nothing changed.
+     */
+    public boolean activateKeyBindingService(IWorkbenchSite nestedSite);
+
+    /**
+     * An accessor for the nested key binding service associated with a
+     * particular site.  If the key binding service does not exist for this
+     * <code>nestedSite</code> already, then a new one should be constructed.
+     *
+     * @param nestedSite The site for which the service should be found;
+     * should not be <code>null</code>.
+     * @return The associated service, if any; or a new associated service, if
+     * none existed previously.
+     */
+    public IKeyBindingService getKeyBindingService(IWorkbenchSite nestedSite);
+
+    /**
+     * Removes a nested key binding service from this key binding service.  The
+     * service to remove is determined by the <code>nestedSite</code> with
+     * which it is associated.
+     *
+     * @param nestedSite The site from which to remove the nested service.
+     * This site must not be <code>null</code>.
+     * @return <code>true</code> if the service existed and could be removed;
+     * <code>false</code> otherwise.
+     */
+    public boolean removeKeyBindingService(IWorkbenchSite nestedSite);
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/INewWizard.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/INewWizard.java
new file mode 100644
index 0000000..f70a71d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/INewWizard.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+/**
+ * Interface for creation wizards.
+ * <p>
+ * Clients should implement this interface and include the name of their class
+ * in a wizard contributed to the workbench's creation wizard extension point
+ * (named <code>"org.eclipse.ui.newWizards"</code>).
+ * For example, the plug-in's XML markup might contain:
+ * <pre>
+ * &LT;extension point="org.eclipse.ui.newWizards"&GT;
+ *   &LT;wizard
+ *       id="com.example.myplugin.new.blob"
+ *       name="Blob"
+ *       class="com.example.myplugin.BlobCreator"
+ *       icon="icons/new_blob_wiz.gif"&GT;
+ *     &LT;description&GT;Create a new BLOB file&LT;/description&GT;
+ *     &LT;selection class="org.eclipse.core.resources.IResource" /&GT;
+ *   &LT;/wizard&GT;
+ * &LT;/extension&GT;
+ * </pre>
+ * </p>
+ *
+ * @see org.eclipse.jface.wizard.IWizard
+ */
+public interface INewWizard extends IWorkbenchWizard {
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/INullSelectionListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/INullSelectionListener.java
new file mode 100644
index 0000000..4d84f5f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/INullSelectionListener.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+/**
+ * Interface for listening to <code>null</code> selection changes.
+ * <p>
+ * This interface should be implemented by selection listeners
+ * that want to be notified when the selection becomes <code>null</code>.
+ * It has no methods. It simply indicates the desire to receive
+ * <code>null</code> selection events through the existing
+ * <code>selectionChanged</code> method. Either the part or the
+ * selection may be <code>null</code>.
+ * </p>
+ *
+ * @see ISelectionListener#selectionChanged
+ * @see IActionDelegate#selectionChanged
+ * @see org.eclipse.ui.ISelectionListener
+ *
+ * @since 2.0
+ */
+public interface INullSelectionListener extends ISelectionListener {
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IObjectActionDelegate.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IObjectActionDelegate.java
new file mode 100644
index 0000000..10af4f2
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IObjectActionDelegate.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import org.eclipse.jface.action.IAction;
+
+/**
+ * Interface for an object action that is contributed into a popup menu
+ * for a view or editor.  It extends <code>IActionDelegate</code>
+ * and adds an initialization method for connecting the delegate to the
+ * part it should work with.
+ */
+public interface IObjectActionDelegate extends IActionDelegate {
+    /**
+	 * Sets the active part for the delegate. The active part is commonly used
+	 * to get a working context for the action, such as the shell for any dialog
+	 * which is needed.
+	 * <p>
+	 * This method will be called every time the action appears in a popup menu.
+	 * The targetPart may change with each invocation.
+	 * </p>
+	 *
+	 * @param action
+	 *            the action proxy that handles presentation portion of the
+	 *            action; must not be <code>null</code>.
+	 * @param targetPart
+	 *            the new part target; must not be <code>null</code>.
+	 */
+    public void setActivePart(IAction action, IWorkbenchPart targetPart);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPageLayout.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPageLayout.java
new file mode 100644
index 0000000..680d019
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPageLayout.java
@@ -0,0 +1,560 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Chris Gross <schtoo@schtoo.com>
+ *     - Fix for 99155 - allow standalone view placeholders
+ *     Chris Gross chris.gross@us.ibm.com Bug 107443
+ *     Denis Zygann <d.zygann@web.de> - Bug 457390
+ *******************************************************************************/
+package org.eclipse.ui;
+
+/**
+ * A page layout defines the initial layout for a perspective within a page
+ * in a workbench window.
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ * <p>
+ * When a perspective is opened, it creates a new page layout with a single editor area.
+ * This layout is then passed to the perspective factory (implementation of
+ * {@link org.eclipse.ui.IPerspectiveFactory#createInitialLayout(IPageLayout)}) where
+ * additional views and other content can be added, using the existing editor area as
+ * the initial point of reference.
+ * </p>
+ * <p>
+ * In some cases, multiple instances of a particular view may need to be added
+ * to the same layout.  These are disambiguated using a secondary id.
+ * In layout methods taking a view id, the id can have the compound form:
+ * <strong>primaryId [':' secondaryId]</strong>.
+ * If a secondary id is given, the view must allow multiple instances by
+ * having specified <code>allowMultiple="true"</code> in its extension.
+ * View placeholders may also have a secondary id.
+ * </p>
+ * <p>
+ * Wildcards are permitted in placeholder ids (but not regular view ids).
+ * '*' matches any substring, '?' matches any single character.
+ * Wildcards can be specified for the primary id, the secondary id, or both.
+ * For example, the placeholder "someView:*" will match any occurrence of the view
+ * that has primary id "someView" and that also has some non-null secondary id.
+ * Note that this placeholder will not match the view if it has no secondary id,
+ * since the compound id in this case is simply "someView".
+ * </p>
+ * <p>
+ * Example of populating a layout with standard workbench views:
+ * <pre>
+ * IPageLayout layout = ...
+ * // Get the editor area.
+ * String editorArea = layout.getEditorArea();
+ *
+ * // Top left: Project Explorer view and Bookmarks view placeholder
+ * IFolderLayout topLeft = layout.createFolder("topLeft", IPageLayout.LEFT, 0.25f,
+ *    editorArea);
+ * topLeft.addView(IPageLayout.ID_PROJECT_EXPLORER);
+ * topLeft.addPlaceholder(IPageLayout.ID_BOOKMARKS);
+ *
+ * // Bottom left: Outline view and Property Sheet view
+ * IFolderLayout bottomLeft = layout.createFolder("bottomLeft", IPageLayout.BOTTOM, 0.50f,
+ * 	   "topLeft");
+ * bottomLeft.addView(IPageLayout.ID_OUTLINE);
+ * bottomLeft.addView(IPageLayout.ID_PROP_SHEET);
+ *
+ * // Bottom right: Task List view
+ * layout.addView(IPageLayout.ID_TASK_LIST, IPageLayout.BOTTOM, 0.66f, editorArea);
+ * </pre>
+ * </p>
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IPageLayout {
+
+    /**
+     * The part id for the workbench's editor area.  This may only be used
+     * as a reference part for view addition.
+     */
+    public static String ID_EDITOR_AREA = "org.eclipse.ui.editorss"; //$NON-NLS-1$
+
+	/**
+	 * The view id for the workbench's Resource Navigator standard component.
+	 *
+	 * @deprecated this has been replaced by the Common Navigator Framework as
+	 *             of release 3.5.
+	 */
+    @Deprecated
+	public static String ID_RES_NAV = "org.eclipse.ui.views.ResourceNavigator"; //$NON-NLS-1$
+
+    /**
+     * The view id for the Project Explorer.
+     * @since 3.5
+     */
+    public static String ID_PROJECT_EXPLORER = "org.eclipse.ui.navigator.ProjectExplorer"; //$NON-NLS-1$
+
+    /**
+     * The view id for the workbench's Property Sheet standard component.
+     */
+    public static String ID_PROP_SHEET = "org.eclipse.ui.views.PropertySheet"; //$NON-NLS-1$
+
+    /**
+     * The view id for the workbench's Content Outline standard component.
+     */
+    public static String ID_OUTLINE = "org.eclipse.ui.views.ContentOutline"; //$NON-NLS-1$
+
+    /**
+     * The view id for the workbench's Bookmark Navigator standard component.
+     */
+    public static String ID_BOOKMARKS = "org.eclipse.ui.views.BookmarkView"; //$NON-NLS-1$
+
+    /**
+     * The view id for the workbench's Problems View standard component.
+     * @since 3.0
+     */
+    public static String ID_PROBLEM_VIEW = "org.eclipse.ui.views.ProblemView"; //$NON-NLS-1$
+
+    /**
+     * The view id for the workbench's Progress View standard component.
+     * @since 3.2
+     */
+    public static String ID_PROGRESS_VIEW = "org.eclipse.ui.views.ProgressView"; //$NON-NLS-1$
+
+    /**
+     * The view id for the workbench's Task List standard component.
+     */
+    public static String ID_TASK_LIST = "org.eclipse.ui.views.TaskList"; //$NON-NLS-1$
+
+    /**
+     * Id of the navigate action set.
+     * (value <code>"org.eclipse.ui.NavigateActionSet"</code>)
+     * @since 2.1
+     */
+    public static final String ID_NAVIGATE_ACTION_SET = "org.eclipse.ui.NavigateActionSet"; //$NON-NLS-1$
+
+    /**
+     * Relationship constant indicating a part should be placed to the left of
+     * its relative.
+     */
+    public static final int LEFT = 1;
+
+    /**
+     * Relationship constant indicating a part should be placed to the right of
+     * its relative.
+     */
+    public static final int RIGHT = 2;
+
+    /**
+     * Relationship constant indicating a part should be placed above its
+     * relative.
+     */
+    public static final int TOP = 3;
+
+    /**
+     * Relationship constant indicating a part should be placed below its
+     * relative.
+     */
+    public static final int BOTTOM = 4;
+
+    /**
+     * Minimum acceptable ratio value when adding a view
+     * @since 2.0
+     */
+    public static final float RATIO_MIN = 0.05f;
+
+    /**
+     * Maximum acceptable ratio value when adding a view
+     * @since 2.0
+     */
+    public static final float RATIO_MAX = 0.95f;
+
+    /**
+     * The default fast view ratio width.
+     * @since 2.0
+     * @deprecated discontinued support for fast views
+     */
+    @Deprecated
+    public static final float DEFAULT_FASTVIEW_RATIO = 0.3f;
+
+    /**
+     * The default view ratio width for regular (non-fast) views.
+     * @since 2.0
+     */
+    public static final float DEFAULT_VIEW_RATIO = 0.5f;
+
+    /**
+     * A variable used to represent invalid  ratios.
+     * @since 2.0
+     */
+    public static final float INVALID_RATIO = -1f;
+
+    /**
+     * A variable used to represent a ratio which has not been specified.
+     * @since 2.0
+     */
+    public static final float NULL_RATIO = -2f;
+
+    /**
+     * Adds an action set with the given id to this page layout.
+     * The id must name an action set contributed to the workbench's extension
+     * point (named <code>"org.eclipse.ui.actionSet"</code>).
+     *
+     * @param actionSetId the action set id
+     */
+    public void addActionSet(String actionSetId);
+
+    /**
+     * Adds the view with the given compound id to the page layout as a fast view.
+     * See the {@link IPageLayout} type documentation for more details about compound ids.
+     * The primary id must name a view contributed to the workbench's view extension
+     * point (named <code>"org.eclipse.ui.views"</code>).
+     *
+     * @param viewId the compound id of the view to be added
+     * @since 2.0
+     * @deprecated discontinued support for fast views
+     */
+    @Deprecated
+    public void addFastView(String viewId);
+
+    /**
+     * Adds the view with the given compound id to the page layout as a fast view
+     * with the given width ratio.
+     * See the {@link IPageLayout} type documentation for more details about compound ids.
+     * The primary id must name a view contributed to the workbench's view extension
+     * point (named <code>"org.eclipse.ui.views"</code>).
+     *
+     * @param viewId the compound id of the view to be added
+     * @param ratio the percentage of the workbench the fast view will cover
+     * @since 2.0
+     * @deprecated discontinued support for fast views
+     */
+    @Deprecated
+    public void addFastView(String viewId, float ratio);
+
+    /**
+     * Adds a new wizard shortcut to the page layout.
+     * These are typically shown in the UI to allow rapid navigation to appropriate new wizards.
+     * For example, in the Eclipse IDE, these appear as items under the File > New menu.
+     * The id must name a new wizard extension contributed to the
+     * workbench's new wizards extension point (named <code>"org.eclipse.ui.newWizards"</code>).
+     *
+     * @param id the wizard id
+     */
+    public void addNewWizardShortcut(String id);
+
+    /**
+     * Adds a perspective shortcut to the page layout.
+     * These are typically shown in the UI to allow rapid navigation to appropriate new wizards.
+     * For example, in the Eclipse IDE, these appear as items under the Window > Open Perspective menu.
+     * The id must name a perspective extension contributed to the
+     * workbench's perspectives extension point (named <code>"org.eclipse.ui.perspectives"</code>).
+     *
+     * @param id the perspective id
+     */
+    public void addPerspectiveShortcut(String id);
+
+    /**
+     * Adds a view placeholder to this page layout.
+     * A view placeholder is used to define the position of a view before the view
+     * appears.  Initially, it is invisible; however, if the user ever opens a view
+     * whose compound id matches the placeholder, the view will appear at the same
+     * location as the placeholder.
+     * See the {@link IPageLayout} type documentation for more details about compound ids.
+     * If the placeholder contains wildcards, it remains in the layout, otherwise
+     * it is replaced by the view.
+     * If the primary id of the placeholder has no wildcards, it must refer to a view
+     * contributed to the workbench's view extension point
+     * (named <code>"org.eclipse.ui.views"</code>).
+     *
+     * @param viewId the compound view id (wildcards allowed)
+     * @param relationship the position relative to the reference part;
+     *  one of <code>TOP</code>, <code>BOTTOM</code>, <code>LEFT</code>,
+     *  or <code>RIGHT</code>
+     * @param ratio a ratio specifying how to divide the space currently occupied by the reference part,
+     *    in the range <code>0.05f</code> to <code>0.95f</code>.
+     *    Values outside this range will be clipped to facilitate direct manipulation.
+     *    For a vertical split, the part on top gets the specified ratio of the current space
+     *    and the part on bottom gets the rest.
+     *    Likewise, for a horizontal split, the part at left gets the specified ratio of the current space
+     *    and the part at right gets the rest.
+     * @param refId the id of the reference part; either a view id, a folder id,
+     *   or the special editor area id returned by <code>getEditorArea</code>
+     */
+    public void addPlaceholder(String viewId, int relationship, float ratio,
+            String refId);
+
+    /**
+     * Adds an item to the Show In prompter.
+     * The id must name a view contributed to the workbench's view extension point
+     * (named <code>"org.eclipse.ui.views"</code>).
+     *
+     * @param id the view id
+     *
+     * @since 2.1
+     */
+    public void addShowInPart(String id);
+
+    /**
+     * Adds a show view shortcut to the page layout.
+     * These are typically shown in the UI to allow rapid navigation to appropriate views.
+     * For example, in the Eclipse IDE, these appear as items under the Window > Show View menu.
+     * The id must name a view contributed to the workbench's views extension point
+     * (named <code>"org.eclipse.ui.views"</code>).
+     *
+     * @param id the view id
+     */
+    public void addShowViewShortcut(String id);
+
+    /**
+     * Adds a view with the given compound id to this page layout.
+     * See the {@link IPageLayout} type documentation for more details about compound ids.
+     * The primary id must name a view contributed to the workbench's view extension point
+     * (named <code>"org.eclipse.ui.views"</code>).
+     *
+     * @param viewId the compound view id
+     * @param relationship the position relative to the reference part;
+     *  one of <code>TOP</code>, <code>BOTTOM</code>, <code>LEFT</code>,
+     *  or <code>RIGHT</code>
+     * @param ratio a ratio specifying how to divide the space currently occupied by the reference part,
+     *    in the range <code>0.05f</code> to <code>0.95f</code>.
+     *    Values outside this range will be clipped to facilitate direct manipulation.
+     *    For a vertical split, the part on top gets the specified ratio of the current space
+     *    and the part on bottom gets the rest.
+     *    Likewise, for a horizontal split, the part at left gets the specified ratio of the current space
+     *    and the part at right gets the rest.
+     * @param refId the id of the reference part; either a view id, a folder id,
+     *   or the special editor area id returned by <code>getEditorArea</code>
+     */
+    public void addView(String viewId, int relationship, float ratio,
+            String refId);
+
+    /**
+     * Creates and adds a new folder with the given id to this page layout.
+     * The position and relative size of the folder is expressed relative to
+     * a reference part.
+     *
+     * @param folderId the id for the new folder.  This must be unique within
+     *  the layout to avoid collision with other parts.
+     * @param relationship the position relative to the reference part;
+     *  one of <code>TOP</code>, <code>BOTTOM</code>, <code>LEFT</code>,
+     *  or <code>RIGHT</code>
+     * @param ratio a ratio specifying how to divide the space currently occupied by the reference part,
+     *    in the range <code>0.05f</code> to <code>0.95f</code>.
+     *    Values outside this range will be clipped to facilitate direct manipulation.
+     *    For a vertical split, the part on top gets the specified ratio of the current space
+     *    and the part on bottom gets the rest.
+     *    Likewise, for a horizontal split, the part at left gets the specified ratio of the current space
+     *    and the part at right gets the rest.
+     * @param refId the id of the reference part; either a view id, a folder id,
+     *   or the special editor area id returned by <code>getEditorArea</code>
+     * @return the new folder
+     */
+    public IFolderLayout createFolder(String folderId, int relationship,
+            float ratio, String refId);
+
+    /**
+     * Creates and adds a placeholder for a new folder with the given id to this page layout.
+     * The position and relative size of the folder is expressed relative to
+     * a reference part.
+     *
+     * @param folderId the id for the new folder.  This must be unique within
+     *  the layout to avoid collision with other parts.
+     * @param relationship the position relative to the reference part;
+     *  one of <code>TOP</code>, <code>BOTTOM</code>, <code>LEFT</code>,
+     *  or <code>RIGHT</code>
+     * @param ratio a ratio specifying how to divide the space currently occupied by the reference part,
+     *    in the range <code>0.05f</code> to <code>0.95f</code>.
+     *    Values outside this range will be clipped to facilitate direct manipulation.
+     *    For a vertical split, the part on top gets the specified ratio of the current space
+     *    and the part on bottom gets the rest.
+     *    Likewise, for a horizontal split, the part at left gets the specified ratio of the current space
+     *    and the part at right gets the rest.
+     * @param refId the id of the reference part; either a view id, a folder id,
+     *   or the special editor area id returned by <code>getEditorArea</code>
+     * @return a placeholder for the new folder
+     * @since 2.0
+     */
+    public IPlaceholderFolderLayout createPlaceholderFolder(String folderId,
+            int relationship, float ratio, String refId);
+
+    /**
+     * Returns the special identifier for the editor area in this page
+     * layout.  The identifier for the editor area is also stored in
+     * <code>ID_EDITOR_AREA</code>.
+     * <p>
+     * The editor area is automatically added to each layout before anything else.
+     * It should be used as the point of reference when adding views to a layout.
+     * </p>
+     *
+     * @return the special id of the editor area
+     */
+    public String getEditorArea();
+
+    /**
+     * Returns whether the page's layout will show
+     * the editor area.
+     *
+     * @return <code>true</code> when editor area visible, <code>false</code> otherwise
+     */
+    public boolean isEditorAreaVisible();
+
+    /**
+     * Show or hide the editor area for the page's layout.
+     *
+     * @param showEditorArea <code>true</code> to show the editor area, <code>false</code> to hide the editor area
+     */
+    public void setEditorAreaVisible(boolean showEditorArea);
+
+    /**
+     * Returns the number of open editors before reusing editors or -1 if the
+     * preference settings should be used instead.
+     *
+     * @return the number of open editors before reusing editors or -1 if the
+     * preference settings should be used instead.
+     *
+     * @deprecated this always returns -1 as of Eclipse 2.1
+     */
+    @Deprecated
+	public int getEditorReuseThreshold();
+
+    /**
+     * Sets the number of open editors before reusing editors.
+     * If < 0 the user preference settings will be used.
+     *
+     * @param openEditors the number of open editors
+     *
+     * @deprecated this method has no effect, as of Eclipse 2.1
+     */
+    @Deprecated
+	public void setEditorReuseThreshold(int openEditors);
+
+    /**
+     * Sets whether this layout is fixed.
+     * In a fixed layout, layout parts cannot be moved or zoomed, and the initial
+     * set of views cannot be closed.
+     *
+     * @param isFixed <code>true</code> if this layout is fixed, <code>false</code> if not
+     * @since 3.0
+     */
+    public void setFixed(boolean isFixed);
+
+    /**
+     * Returns <code>true</code> if this layout is fixed, <code>false</code> if not.
+     * In a fixed layout, layout parts cannot be moved or zoomed, and the initial
+     * set of views cannot be closed.
+     * The default is <code>false</code>.
+     *
+     * @return <code>true</code> if this layout is fixed, <code>false</code> if not.
+     * @since 3.0
+     */
+    public boolean isFixed();
+
+    /**
+     * Returns the layout for the view or placeholder with the given compound id in
+     * this page layout.
+     * See the {@link IPageLayout} type documentation for more details about compound ids.
+     * Returns <code>null</code> if the specified view or placeholder is unknown to the layout.
+     *
+     * @param id the compound view id or placeholder
+     * @return the view layout, or <code>null</code>
+     * @since 3.0
+     */
+    public IViewLayout getViewLayout(String id);
+
+    /**
+     * Adds a standalone view with the given compound id to this page layout.
+     * See the {@link IPageLayout} type documentation for more details about compound ids.
+     * A standalone view cannot be docked together with other views.
+     * A standalone view's title can optionally be hidden.  If hidden,
+     * then any controls typically shown with the title (such as the close button)
+     * are also hidden.  Any contributions or other content from the view itself
+     * are always shown (e.g. toolbar or view menu contributions, content description).
+     * <p>
+     * The id must name a view contributed to the workbench's view extension point
+     * (named <code>"org.eclipse.ui.views"</code>).
+     * </p>
+     *
+     * @param viewId the compound view id
+     * @param showTitle <code>true</code> to show the title and related controls,
+     *  <code>false</code> to hide them
+     * @param relationship the position relative to the reference part;
+     *  one of <code>TOP</code>, <code>BOTTOM</code>, <code>LEFT</code>,
+     *  or <code>RIGHT</code>
+     * @param ratio a ratio specifying how to divide the space currently occupied by the reference part,
+     *    in the range <code>0.05f</code> to <code>0.95f</code>.
+     *    Values outside this range will be clipped to facilitate direct manipulation.
+     *    For a vertical split, the part on top gets the specified ratio of the current space
+     *    and the part on bottom gets the rest.
+     *    Likewise, for a horizontal split, the part at left gets the specified ratio of the current space
+     *    and the part at right gets the rest.
+     * @param refId the id of the reference part; either a view id, a folder id,
+     *   or the special editor area id returned by <code>getEditorArea</code>
+     *
+     * @since 3.0
+     */
+    public void addStandaloneView(String viewId, boolean showTitle,
+            int relationship, float ratio, String refId);
+
+    /**
+	 * Adds a standalone view placeholder to this page layout. A view
+	 * placeholder is used to define the position of a view before the view
+	 * appears. Initially, it is invisible; however, if the user ever opens a
+	 * view whose compound id matches the placeholder, the view will appear at
+	 * the same location as the placeholder. See the {@link IPageLayout} type
+	 * documentation for more details about compound ids. If the placeholder
+	 * contains wildcards, it remains in the layout, otherwise it is replaced by
+	 * the view. If the primary id of the placeholder has no wildcards, it must
+	 * refer to a view contributed to the workbench's view extension point
+	 * (named <code>"org.eclipse.ui.views"</code>).
+	 *
+	 * @param viewId
+	 *            the compound view id (wildcards allowed)
+	 * @param relationship
+	 *            the position relative to the reference part; one of
+	 *            <code>TOP</code>, <code>BOTTOM</code>, <code>LEFT</code>,
+	 *            or <code>RIGHT</code>
+	 * @param ratio
+	 *            a ratio specifying how to divide the space currently occupied
+	 *            by the reference part, in the range <code>0.05f</code> to
+	 *            <code>0.95f</code>. Values outside this range will be
+	 *            clipped to facilitate direct manipulation. For a vertical
+	 *            split, the part on top gets the specified ratio of the current
+	 *            space and the part on bottom gets the rest. Likewise, for a
+	 *            horizontal split, the part at left gets the specified ratio of
+	 *            the current space and the part at right gets the rest.
+	 * @param refId
+	 *            the id of the reference part; either a view id, a folder id,
+	 *            or the special editor area id returned by
+	 *            <code>getEditorArea</code>
+	 * @param showTitle
+	 *            true to show the view's title, false if not
+	 *
+	 * @since 3.2
+	 */
+    public void addStandaloneViewPlaceholder(String viewId, int relationship,
+			float ratio, String refId, boolean showTitle);
+
+
+    /**
+	 * Returns the perspective descriptor for the perspective being layed out.
+	 *
+	 * @return the perspective descriptor for the perspective being layed out
+	 * @since 3.2
+	 */
+    public IPerspectiveDescriptor getDescriptor();
+
+    /**
+	 * Returns the folder layout for the view or placeholder with the given
+	 * compound id in this page layout. See the {@link IPageLayout} type
+	 * documentation for more details about compound ids. Returns
+	 * <code>null</code> if the specified view or placeholder is unknown to
+	 * the layout, or the placeholder was not in a folder.
+	 *
+	 * @param id
+	 *            the compound view id or placeholder. Must not be
+	 *            <code>null</code>.
+	 * @return the folder layout, or <code>null</code>
+	 * @since 3.3
+	 */
+    public IPlaceholderFolderLayout getFolderForView(String id);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPageListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPageListener.java
new file mode 100644
index 0000000..8455cbc
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPageListener.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 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.ui;
+
+/**
+ * Interface for listening to page lifecycle events.
+ * <p>
+ * This interface may be implemented by clients.
+ * </p>
+ *
+ * @see IPageService#addPageListener
+ */
+public interface IPageListener {
+    /**
+     * Notifies this listener that the given page has been activated.
+     *
+     * @param page the page that was activated
+     * @see IWorkbenchWindow#setActivePage
+     */
+    public void pageActivated(IWorkbenchPage page);
+
+    /**
+     * Notifies this listener that the given page has been closed.
+     *
+     * @param page the page that was closed
+     * @see IWorkbenchPage#close
+     */
+    public void pageClosed(IWorkbenchPage page);
+
+    /**
+     * Notifies this listener that the given page has been opened.
+     *
+     * @param page the page that was opened
+     * @see IWorkbenchWindow#openPage
+     */
+    public void pageOpened(IWorkbenchPage page);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPageService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPageService.java
new file mode 100644
index 0000000..3947d73
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPageService.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+/**
+ * A page service tracks the page and perspective lifecycle events
+ * within a workbench window.
+ * <p>
+ * This service can be acquired from your service locator:
+ * <pre>
+ * 	IPageService service = (IPageService) getSite().getService(IPageService.class);
+ * </pre>
+ * <ul>
+ * <li>This service is not available globally, only from the workbench window level down.</li>
+ * </ul>
+ * </p>
+ *
+ * @see IWorkbenchWindow
+ * @see IPageListener
+ * @see IPerspectiveListener
+ * @see org.eclipse.ui.services.IServiceLocator#getService(Class)
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IPageService {
+    /**
+     * Adds the given listener for page lifecycle events.
+     * Has no effect if an identical listener is already registered.
+	 * <p>
+	 * <b>Note:</b> listeners should be removed when no longer necessary. If
+	 * not, they will be removed when the IServiceLocator used to acquire this
+	 * service is disposed.
+	 * </p>
+     *
+     * @param listener a page listener
+     * @see #removePageListener(IPageListener)
+     */
+    public void addPageListener(IPageListener listener);
+
+    /**
+     * Adds the given listener for a page's perspective lifecycle events.
+     * Has no effect if an identical listener is already registered.
+	 * <p>
+	 * <b>Note:</b> listeners should be removed when no longer necessary. If
+	 * not, they will be removed when the IServiceLocator used to acquire this
+	 * service is disposed.
+	 * </p>
+     *
+     * @param listener a perspective listener
+     * @see #removePerspectiveListener(IPerspectiveListener)
+     */
+    public void addPerspectiveListener(IPerspectiveListener listener);
+
+    /**
+     * Returns the active page.
+     *
+     * @return the active page, or <code>null</code> if no page is currently active
+     */
+    public IWorkbenchPage getActivePage();
+
+    /**
+	 * Removes the given page listener. Has no effect if an identical listener
+	 * is not registered.
+	 *
+	 * @param listener
+	 *            a page listener
+	 */
+    public void removePageListener(IPageListener listener);
+
+    /**
+	 * Removes the given page's perspective listener. Has no effect if an
+	 * identical listener is not registered.
+	 *
+	 * @param listener
+	 *            a perspective listener
+	 */
+    public void removePerspectiveListener(IPerspectiveListener listener);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPartListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPartListener.java
new file mode 100644
index 0000000..eca1d5b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPartListener.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+/**
+ * Interface for listening to part lifecycle events.
+ * <p>
+ * This interface may be implemented by clients.
+ * </p>
+ *
+ * @see IPartService#addPartListener(IPartListener)
+ */
+public interface IPartListener {
+
+    /**
+     * Notifies this listener that the given part has been activated.
+     *
+     * @param part the part that was activated
+     * @see IWorkbenchPage#activate
+     */
+    public void partActivated(IWorkbenchPart part);
+
+    /**
+     * Notifies this listener that the given part has been brought to the top.
+     * <p>
+     * These events occur when an editor is brought to the top in the editor area,
+     * or when a view is brought to the top in a page book with multiple views.
+     * They are normally only sent when a part is brought to the top
+     * programmatically (via <code>IPerspective.bringToTop</code>). When a part is
+     * activated by the user clicking on it, only <code>partActivated</code> is sent.
+     * </p>
+     *
+     * @param part the part that was surfaced
+     * @see IWorkbenchPage#bringToTop
+     */
+    public void partBroughtToTop(IWorkbenchPart part);
+
+    /**
+     * Notifies this listener that the given part has been closed.
+     *
+     * @param part the part that was closed
+     * @see IWorkbenchPage#hideView(IViewPart)
+     */
+    public void partClosed(IWorkbenchPart part);
+
+    /**
+     * Notifies this listener that the given part has been deactivated.
+     *
+     * @param part the part that was deactivated
+     * @see IWorkbenchPage#activate(IWorkbenchPart)
+     */
+    public void partDeactivated(IWorkbenchPart part);
+
+    /**
+     * Notifies this listener that the given part has been opened.
+     *
+     * @param part the part that was opened
+     * @see IWorkbenchPage#showView(String)
+     */
+    public void partOpened(IWorkbenchPart part);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPartListener2.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPartListener2.java
new file mode 100644
index 0000000..f8c129e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPartListener2.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import org.eclipse.jface.dialogs.IPageChangeProvider;
+import org.eclipse.jface.dialogs.IPageChangedListener;
+import org.eclipse.jface.dialogs.PageChangedEvent;
+
+
+/**
+ * Interface for listening to part lifecycle events.
+ * <p>
+ * This is a replacement for <code>IPartListener</code>.
+ * <p>
+ * As of 3.5, if the implementation of this listener also implements
+ * {@link IPageChangedListener} then it will also be notified about
+ * {@link PageChangedEvent}s from parts that implement
+ * {@link IPageChangeProvider}.
+ * </p>
+ * <p>
+ * This interface may be implemented by clients.
+ * </p>
+ *
+ * @see IPartService#addPartListener(IPartListener2)
+ */
+public interface IPartListener2 {
+
+    /**
+     * Notifies this listener that the given part has been activated.
+     *
+     * @param partRef the part that was activated
+     * @see IWorkbenchPage#activate
+     */
+    public void partActivated(IWorkbenchPartReference partRef);
+
+    /**
+     * Notifies this listener that the given part has been brought to the top.
+     * <p>
+     * These events occur when an editor is brought to the top in the editor area,
+     * or when a view is brought to the top in a page book with multiple views.
+     * They are normally only sent when a part is brought to the top
+     * programmatically (via <code>IPerspective.bringToTop</code>). When a part is
+     * activated by the user clicking on it, only <code>partActivated</code> is sent.
+     * </p>
+     *
+     * @param partRef the part that was surfaced
+     * @see IWorkbenchPage#bringToTop
+     */
+    public void partBroughtToTop(IWorkbenchPartReference partRef);
+
+    /**
+     * Notifies this listener that the given part has been closed.
+     * <p>
+     * Note that if other perspectives in the same page share the view,
+     * this notification is not sent.  It is only sent when the view
+     * is being removed from the page entirely (it is being disposed).
+     * </p>
+     *
+     * @param partRef the part that was closed
+     * @see IWorkbenchPage#hideView
+     */
+    public void partClosed(IWorkbenchPartReference partRef);
+
+    /**
+     * Notifies this listener that the given part has been deactivated.
+     *
+     * @param partRef the part that was deactivated
+     * @see IWorkbenchPage#activate
+     */
+    public void partDeactivated(IWorkbenchPartReference partRef);
+
+    /**
+     * Notifies this listener that the given part has been opened.
+     * <p>
+     * Note that if other perspectives in the same page share the view,
+     * this notification is not sent.  It is only sent when the view
+     * is being newly opened in the page (it is being created).
+     * </p>
+     *
+     * @param partRef the part that was opened
+     * @see IWorkbenchPage#showView
+     */
+    public void partOpened(IWorkbenchPartReference partRef);
+
+    /**
+     * Notifies this listener that the given part is hidden or obscured by another part.
+     *
+     * @param partRef the part that is hidden or obscured by another part
+     */
+    public void partHidden(IWorkbenchPartReference partRef);
+
+    /**
+     * Notifies this listener that the given part is visible.
+     *
+     * @param partRef the part that is visible
+     */
+    public void partVisible(IWorkbenchPartReference partRef);
+
+    /**
+     * Notifies this listener that the given part's input was changed.
+     *
+     * @param partRef the part whose input was changed
+     */
+    public void partInputChanged(IWorkbenchPartReference partRef);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPartService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPartService.java
new file mode 100644
index 0000000..af12d80
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPartService.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+/**
+ * A part service tracks the creation and activation of parts within a
+ * workbench page.
+ * <p>
+ * This service can be acquired from your service locator:
+ * <pre>
+ * 	IPartService service = (IPartService) getSite().getService(IPartService.class);
+ * </pre>
+ * <ul>
+ * <li>This service is not available globally, only from the workbench window level down.</li>
+ * </ul>
+ * </p>
+ *
+ * @see IWorkbenchPage
+ * @see org.eclipse.ui.services.IServiceLocator#getService(Class)
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IPartService {
+
+    /**
+     * Adds the given listener for part lifecycle events.
+     * Has no effect if an identical listener is already registered.
+	 * <p>
+	 * <b>Note:</b> listeners should be removed when no longer necessary. If
+	 * not, they will be removed when the IServiceLocator used to acquire this
+	 * service is disposed.
+	 * </p>
+     *
+     * @param listener a part listener
+     * @see #removePartListener(IPartListener)
+     */
+    public void addPartListener(IPartListener listener);
+
+    /**
+     * Adds the given listener for part lifecycle events.
+     * Has no effect if an identical listener is already registered.
+     * <p>
+     * As of 3.5, the IPartListener2 can also implement IPageChangedListener
+     * to be notified about any parts that implement IPageChangeProvider and
+     * post PageChangedEvents.
+     * </p>
+	 * <p>
+	 * <b>Note:</b> listeners should be removed when no longer necessary. If
+	 * not, they will be removed when the IServiceLocator used to acquire this
+	 * service is disposed.
+	 * </p>
+     *
+     * @param listener a part listener
+     * @see #removePartListener(IPartListener2)
+     * @see org.eclipse.jface.dialogs.IPageChangeProvider
+     * @see org.eclipse.jface.dialogs.IPageChangedListener
+     */
+    public void addPartListener(IPartListener2 listener);
+
+    /**
+     * Returns the active part.
+     *
+     * @return the active part, or <code>null</code> if no part is currently active
+     */
+    public IWorkbenchPart getActivePart();
+
+    /**
+     * Returns the active part reference.
+     *
+     * @return the active part reference, or <code>null</code> if no part
+     * is currently active
+     */
+    public IWorkbenchPartReference getActivePartReference();
+
+    /**
+	 * Removes the given part listener. Has no effect if an identical listener
+	 * is not registered.
+	 *
+	 * @param listener
+	 *            a part listener
+	 */
+    public void removePartListener(IPartListener listener);
+
+    /**
+	 * Removes the given part listener. Has no effect if an identical listener
+	 * is not registered.
+	 *
+	 * @param listener
+	 *            a part listener
+	 */
+    public void removePartListener(IPartListener2 listener);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPathEditorInput.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPathEditorInput.java
new file mode 100644
index 0000000..20a0376
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPathEditorInput.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2007 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.ui;
+
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * This interface defines an editor input based on the local file system path
+ * of a file.
+ * <p>
+ * Clients implementing this editor input interface should override
+ * <code>Object.equals(Object)</code> to answer true for two inputs
+ * that are the same. The <code>IWorkbenchPage.openEditor</code> APIs
+ * are dependent on this to find an editor with the same input.
+ * </p><p>
+ * Path-oriented editors should support this as a valid input type, and
+ * can allow full read-write editing of its content.
+ * </p><p>
+ * All editor inputs must implement the <code>IAdaptable</code> interface;
+ * extensions are managed by the platform's adapter manager.
+ * </p>
+ *
+ * @see org.eclipse.core.runtime.IPath
+ * @since 3.0
+ */
+public interface IPathEditorInput extends IEditorInput {
+    /**
+     * Returns the local file system path of the file underlying this editor input.
+     *
+     * @return a local file system path
+     */
+    public IPath getPath();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPersistable.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPersistable.java
new file mode 100644
index 0000000..8955848
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPersistable.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui;
+
+
+/**
+ * Objects implementing this interface are capable of saving their
+ * state in an {@link IMemento}.
+ *
+ * @since 3.1
+ */
+public interface IPersistable {
+    /**
+     * Saves the state of the object in the given memento.
+     *
+     * @param memento the storage area for object's state
+     */
+    public void saveState(IMemento memento);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPersistableEditor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPersistableEditor.java
new file mode 100644
index 0000000..fdb20b5
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPersistableEditor.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui;
+
+/**
+ * An editor can implement this interface and participate in the workbench
+ * session save/restore cycle using <code>IMemento</code>, similar to how
+ * <code>IViewPart</code> currently works.
+ * <p>
+ * Refer to IWorkbenchPart for the part lifecycle.
+ * </p>
+ * <p>
+ * If a memento is available, restoreState(*) will be inserted into the editor
+ * startup.
+ * <ol>
+ * <li><code>editor.init(site, input)</code></li>
+ * <li><code>editor.restoreState(memento)</code></li>
+ * <li><code>editor.createPartControl(parent)</code></li>
+ * <li>...</li>
+ * </ol>
+ * </p>
+ * <p>
+ * On workbench shutdown, the editor state will be persisted when the editor
+ * references are saved.
+ * </p>
+ *
+ * @since 3.3
+ */
+public interface IPersistableEditor extends IPersistable {
+	/**
+	 * Called with a memento for this editor. The editor can parse the data or
+	 * save the memento. This method may not be called.
+	 *
+	 * @param memento
+	 *            the saved state for this editor. May be <code>null</code>.
+	 */
+	public void restoreState(IMemento memento);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPersistableElement.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPersistableElement.java
new file mode 100644
index 0000000..d487fcd
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPersistableElement.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+
+/**
+ * Interface for asking an object to store its state in a memento.
+ * <p>
+ * This interface is typically included in interfaces where
+ * persistance is required.
+ * </p><p>
+ * When the workbench is shutdown objects which implement this interface
+ * will be persisted.  At this time the <code>getFactoryId</code> method
+ * is invoked to discover the id of the element factory that will be used
+ * to re-create the object from a memento.  Then the <code>saveState</code>
+ * method is invoked to store the element data into a newly created memento.
+ * The resulting mementos are collected up and written out to a single file.
+ * </p>
+ * <p>
+ * During workbench startup these mementos are read from the file.  The
+ * factory Id for each is retrieved and mapped to an <code>IElementFactory</code>
+ * which has been registered in the element factory extension point.  If a
+ * factory exists for the Id it will be engaged to re-create the original
+ * object.
+ * </p>
+ *
+ * @see org.eclipse.core.runtime.IAdaptable
+ * @see org.eclipse.ui.IMemento
+ * @see org.eclipse.ui.IElementFactory
+ */
+public interface IPersistableElement extends IPersistable {
+    /**
+     * Returns the id of the element factory which should be used to re-create this
+     * object.
+     * <p>
+     * Factory ids are declared in extensions to the standard extension point
+     * <code>"org.eclipse.ui.elementFactories"</code>.
+     * </p>
+     *
+     * @return the element factory id
+     * @see IElementFactory
+     */
+    public String getFactoryId();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPerspectiveDescriptor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPerspectiveDescriptor.java
new file mode 100644
index 0000000..abbeadd
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPerspectiveDescriptor.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+
+/**
+ * A perspective descriptor describes a perspective in an
+ * <code>IPerspectiveRegistry</code>.
+ * <p>
+ * A perspective is a template for view visibility, layout, and action visibility
+ * within a workbench page. There are two types of perspective: a predefined
+ * perspective and a custom perspective.
+ * <ul>
+ *   <li>A predefined perspective is defined by an extension to the workbench's
+ *     perspective extension point (<code>"org.eclipse.ui.perspectives"</code>).
+ *     The extension defines a id, label, and <code>IPerspectiveFactory</code>.
+ *     A perspective factory is used to define the initial layout for a page.
+ *     </li>
+ *   <li>A custom perspective is defined by the user.  In this case a predefined
+ *     perspective is modified to suit a particular task and saved as a new
+ *     perspective.  The attributes for the perspective are stored in a separate file
+ *     in the workbench's metadata directory.
+ *     </li>
+ * </ul>
+ * </p>
+ * <p>
+ * Within a page the user can open any of the perspectives known
+ * to the workbench's perspective registry, typically by selecting one from the
+ * workbench's <code>Open Perspective</code> menu. When selected, the views
+ * and actions within the active page rearrange to reflect the perspective.
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ * @see IPerspectiveRegistry
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IPerspectiveDescriptor {
+    /**
+     * Returns the description of this perspective.
+     * This is the value of its <code>"description"</code> attribute.
+     *
+     * @return the description
+     * @since 3.0
+     */
+    public String getDescription();
+
+    /**
+     * Returns this perspective's id. For perspectives declared via an extension,
+     * this is the value of its <code>"id"</code> attribute.
+     *
+     * @return the perspective id
+     */
+    public String getId();
+
+    /**
+     * Returns the descriptor of the image to show for this perspective.
+     * If the extension for this perspective specifies an image, the descriptor
+     * for it is returned.  Otherwise a default image is returned.
+     *
+     * @return the descriptor of the image to show for this perspective
+     */
+    public ImageDescriptor getImageDescriptor();
+
+    /**
+     * Returns this perspective's label. For perspectives declared via an extension,
+     * this is the value of its <code>"label"</code> attribute.
+     *
+     * @return the label
+     */
+    public String getLabel();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPerspectiveFactory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPerspectiveFactory.java
new file mode 100644
index 0000000..6e035dc
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPerspectiveFactory.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+/**
+ * A perspective factory generates the initial page layout and visible
+ * action set for a page.
+ * <p>
+ * When a new page is created in the workbench a perspective is used to define
+ * the initial page layout.  If this is a predefined perspective (based on an extension to
+ * the workbench's perspective extension point) an <code>IPerspectiveFactory</code>
+ * is used to define the initial page layout.
+ * </p><p>
+ * The factory for the perspective is created and passed an <code>IPageLayout</code>
+ * where views can be added.  The default layout consists of the editor area with no
+ * additional views.  Additional views are added to the layout using
+ * the editor area as the initial point of reference.  The factory is used only briefly
+ * while a new page is created; then discarded.
+ * </p><p>
+ * To define a perspective clients should implement this interface and
+ * include the name of their class in an extension to the workbench's perspective
+ * extension point (named <code>"org.eclipse.ui.perspectives"</code>).  For example,
+ * the plug-in's XML markup might contain:
+ * <pre>
+ * &LT;extension point="org.eclipse.ui.perspectives"&GT;
+ *   &LT;perspective
+ *       id="com.example.javaplugin.perspective"
+ *       name="Java"
+ *       class="com.example.javaplugin.JavaPerspective"&GT;
+ *   &LT;/perspective&GT;
+ * &LT;/extension&GT;
+ * </pre>
+ * </p><p>
+ * Example of populating a page with standard workbench views:
+ * <pre>
+ * public void createInitialLayout(IPageLayout layout) {
+ *		// Get the editor area.
+ *		String editorArea = layout.getEditorArea();
+ *
+ *		// Top left: Resource Navigator view and Bookmarks view placeholder
+ *		IFolderLayout topLeft = layout.createFolder("topLeft", IPageLayout.LEFT, 0.25f,
+ *			editorArea);
+ *		topLeft.addView(IPageLayout.ID_RES_NAV);
+ *		topLeft.addPlaceholder(IPageLayout.ID_BOOKMARKS);
+ *
+ *		// Bottom left: Outline view and Property Sheet view
+ *		IFolderLayout bottomLeft = layout.createFolder("bottomLeft", IPageLayout.BOTTOM, 0.50f,
+ *			"topLeft");
+ *		bottomLeft.addView(IPageLayout.ID_OUTLINE);
+ *		bottomLeft.addView(IPageLayout.ID_PROP_SHEET);
+ *
+ *		// Bottom right: Task List view
+ *		layout.addView(IPageLayout.ID_TASK_LIST, IPageLayout.BOTTOM, 0.66f, editorArea);
+ *	}
+ * </pre>
+ * </p><p>
+ * Within the workbench a user may override the visible views, layout and
+ * action sets of a predefined perspective to create a custom perspective.  In such cases
+ * the layout is persisted by the workbench and the factory is not used.
+ * </p>
+ */
+public interface IPerspectiveFactory {
+    /**
+     * Creates the initial layout for a page.
+     * <p>
+     * Implementors of this method may add additional views to a
+     * perspective.  The perspective already contains an editor folder
+     * identified by the result of <code>IPageLayout.getEditorArea()</code>.
+     * Additional views should be added to the layout using this value as
+     * the initial point of reference.
+     * </p>
+     *
+     * @param layout the page layout
+     */
+    public void createInitialLayout(IPageLayout layout);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPerspectiveListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPerspectiveListener.java
new file mode 100644
index 0000000..fd973c6
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPerspectiveListener.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+/**
+ * Interface for listening to perspective lifecycle events.
+ * <p>
+ * This interface may be implemented by clients.
+ * </p>
+ *
+ * @see IPageService#addPerspectiveListener(IPerspectiveListener)
+ * @see PerspectiveAdapter
+ */
+public interface IPerspectiveListener {
+    /**
+     * Notifies this listener that a perspective in the given page
+     * has been activated.
+     *
+     * @param page the page containing the activated perspective
+     * @param perspective the perspective descriptor that was activated
+     * @see IWorkbenchPage#setPerspective
+     */
+    public void perspectiveActivated(IWorkbenchPage page,
+            IPerspectiveDescriptor perspective);
+
+    /**
+     * Notifies this listener that a perspective has changed in some way
+     * (for example, editor area hidden, perspective reset,
+     * view show/hide, editor open/close, etc).
+     *
+     * @param page the page containing the affected perspective
+     * @param perspective the perspective descriptor
+     * @param changeId one of the <code>CHANGE_*</code> constants on IWorkbenchPage
+     */
+    public void perspectiveChanged(IWorkbenchPage page,
+            IPerspectiveDescriptor perspective, String changeId);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPerspectiveListener2.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPerspectiveListener2.java
new file mode 100644
index 0000000..c7e9d6d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPerspectiveListener2.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui;
+
+/**
+ * Extension interface to <code>IPerspectiveListener</code> which
+ * adds support for listening to part-specific perspective lifecycle events.
+ * For example, this allows a perspective listener to determine which view
+ * is being hidden during a <code>CHANGE_VIEW_HIDE</code> event.
+ * <p>
+ * This interface may be implemented by clients.
+ * </p>
+ *
+ * @see IPageService#addPerspectiveListener(IPerspectiveListener)
+ * @see PerspectiveAdapter
+ * @since 3.0
+ */
+public interface IPerspectiveListener2 extends IPerspectiveListener {
+
+    /**
+     * Notifies this listener that a part in the given page's perspective
+     * has changed in some way (for example, view show/hide, editor open/close, etc).
+     *
+     * @param page the workbench page containing the perspective
+     * @param perspective the descriptor for the changed perspective
+     * @param partRef the reference to the affected part
+     * @param changeId one of the <code>CHANGE_*</code> constants on IWorkbenchPage
+     */
+    public void perspectiveChanged(IWorkbenchPage page,
+            IPerspectiveDescriptor perspective,
+            IWorkbenchPartReference partRef, String changeId);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPerspectiveListener3.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPerspectiveListener3.java
new file mode 100644
index 0000000..7b7fdc1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPerspectiveListener3.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui;
+
+/**
+ * Extension interface to <code>IPerspectiveListener</code> which
+ * adds support for listening to perspective open and close events.
+ * <p>
+ * This interface may be implemented by clients.
+ * </p>
+ *
+ * @see IPageService#addPerspectiveListener(IPerspectiveListener)
+ * @see PerspectiveAdapter
+ * @since 3.1
+ */
+public interface IPerspectiveListener3 extends IPerspectiveListener2 {
+
+    /**
+     * Notifies this listener that a perspective in the given page has been
+     * opened.
+     *
+     * @param page
+     *            the page containing the opened perspective
+     * @param perspective
+     *            the perspective descriptor that was opened
+     * @see IWorkbenchPage#setPerspective(IPerspectiveDescriptor)
+     */
+    public void perspectiveOpened(IWorkbenchPage page,
+            IPerspectiveDescriptor perspective);
+
+    /**
+     * Notifies this listener that a perspective in the given page has been
+     * closed.
+     *
+     * @param page
+     *            the page containing the closed perspective
+     * @param perspective
+     *            the perspective descriptor that was closed
+     * @see IWorkbenchPage#closePerspective(IPerspectiveDescriptor, boolean, boolean)
+     * @see IWorkbenchPage#closeAllPerspectives(boolean, boolean)
+     */
+    public void perspectiveClosed(IWorkbenchPage page,
+            IPerspectiveDescriptor perspective);
+
+    /**
+     * Notifies this listener that a perspective in the given page has been
+     * deactivated.
+     *
+     * @param page
+     *            the page containing the deactivated perspective
+     * @param perspective
+     *            the perspective descriptor that was deactivated
+     * @see IWorkbenchPage#setPerspective(IPerspectiveDescriptor)
+     */
+    public void perspectiveDeactivated(IWorkbenchPage page,
+            IPerspectiveDescriptor perspective);
+
+    /**
+     * Notifies this listener that a perspective in the given page has been
+     * saved as a new perspective with a different perspective descriptor.
+     *
+     * @param page
+     *            the page containing the saved perspective
+     * @param oldPerspective
+     *            the old perspective descriptor
+     * @param newPerspective
+     *            the new perspective descriptor
+     * @see IWorkbenchPage#savePerspectiveAs(IPerspectiveDescriptor)
+     */
+    public void perspectiveSavedAs(IWorkbenchPage page,
+            IPerspectiveDescriptor oldPerspective,
+            IPerspectiveDescriptor newPerspective);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPerspectiveListener4.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPerspectiveListener4.java
new file mode 100644
index 0000000..58ab495
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPerspectiveListener4.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui;
+
+/**
+ * Extension interface to <code>IPerspectiveListener</code> which adds support
+ * for listening to perspective pre-deactivate events.
+ * <p>
+ * This interface may be implemented by clients.
+ * </p>
+ *
+ * @see IPageService#addPerspectiveListener(IPerspectiveListener)
+ * @see PerspectiveAdapter
+ * @since 3.2
+ *
+ */
+public interface IPerspectiveListener4 extends IPerspectiveListener3 {
+	/**
+	 * <p>
+	 * Notifies this listener that a perspective in the given page is about to
+	 * be deactivated.
+	 * </p>
+	 * <p>
+	 * Note: This does not have the ability to veto a perspective deactivation.
+	 * </p>
+	 *
+	 * @param page
+	 *            the page containing the deactivated perspective
+	 * @param perspective
+	 *            the perspective descriptor that was deactivated
+	 * @see IWorkbenchPage#setPerspective(IPerspectiveDescriptor)
+	 */
+	public void perspectivePreDeactivate(IWorkbenchPage page,
+			IPerspectiveDescriptor perspective);
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPerspectiveRegistry.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPerspectiveRegistry.java
new file mode 100644
index 0000000..ebbfa7e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPerspectiveRegistry.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+/**
+ * The workbench's global registry of perspectives.
+ * <p>
+ * This registry contains a descriptor for each perspectives in the workbench.
+ * It is initially populated with stock perspectives from the workbench's
+ * perspective extension point (<code>"org.eclipse.ui.perspectives"</code>) and
+ * with custom perspectives defined by the user.
+ * </p><p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ * @see IWorkbench#getPerspectiveRegistry
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IPerspectiveRegistry {
+    /**
+     * Clones an existing perspective.
+     *
+     * @param id the id for the cloned perspective, which must not already be used by
+     *   any registered perspective
+     * @param label the label assigned to the cloned perspective
+     * @param desc the perspective to clone
+     * @return the cloned perspective descriptor
+     * @throws IllegalArgumentException if there is already a perspective with the given id
+     *
+     * @since 3.0
+     */
+    public IPerspectiveDescriptor clonePerspective(String id, String label,
+            IPerspectiveDescriptor desc) throws IllegalArgumentException;
+
+	/**
+	 * Deletes a perspective. Has no effect if the perspective is defined in an
+	 * extension.
+	 *
+	 * @param persp the perspective to delete
+	 * @since 3.2
+	 */
+	public void deletePerspective(IPerspectiveDescriptor persp);
+
+    /**
+     * Finds and returns the registered perspective with the given perspective id.
+     *
+     * @param perspectiveId the perspective id
+     * @return the perspective, or <code>null</code> if none
+     * @see IPerspectiveDescriptor#getId
+     */
+    public IPerspectiveDescriptor findPerspectiveWithId(String perspectiveId);
+
+    /**
+     * Finds and returns the registered perspective with the given label.
+     *
+     * @param label the label
+     * @return the perspective, or <code>null</code> if none
+     * @see IPerspectiveDescriptor#getLabel
+     */
+    public IPerspectiveDescriptor findPerspectiveWithLabel(String label);
+
+    /**
+     * Returns the id of the default perspective for the workbench.  This identifies one
+     * perspective extension within the workbench's perspective registry.
+     * <p>
+     * Returns <code>null</code> if there is no default perspective.
+     * </p>
+     *
+     * @return the default perspective id, or <code>null</code>
+     */
+    public String getDefaultPerspective();
+
+    /**
+     * Returns a list of the perspectives known to the workbench.
+     *
+     * @return a list of perspectives
+     */
+    public IPerspectiveDescriptor[] getPerspectives();
+
+    /**
+     * Sets the default perspective for the workbench to the given perspective id.
+     * If non-<code>null</code>, the id must correspond to a perspective extension
+     * within the workbench's perspective registry.
+     * <p>
+     * A <code>null</code> id indicates no default perspective.
+     * </p>
+     *
+     * @param id a perspective id, or <code>null</code>
+     */
+    public void setDefaultPerspective(String id);
+
+    /**
+     * Reverts a perspective back to its original definition
+     * as specified in the plug-in manifest.
+     *
+     * @param perspToRevert the perspective to revert
+     *
+     * @since 3.0
+     */
+    public void revertPerspective(IPerspectiveDescriptor perspToRevert);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPlaceholderFolderLayout.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPlaceholderFolderLayout.java
new file mode 100644
index 0000000..878356d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPlaceholderFolderLayout.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Chris Gross chris.gross@us.ibm.com Bug 107443
+ *******************************************************************************/
+package org.eclipse.ui;
+
+/**
+ * An <code>IPlaceholderFolderLayout</code> is used to define the initial
+ * view placeholders within a folder.
+ * The folder itself is contained within an <code>IPageLayout</code>.
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ *
+ * @see IPageLayout#createPlaceholderFolder
+ * @since 2.0
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IPlaceholderFolderLayout {
+
+    /**
+     * Adds a view placeholder to this folder.
+     * A view placeholder is used to define the position of a view before the view
+     * appears.  Initially, it is invisible; however, if the user ever opens a view
+     * whose compound id matches the placeholder, the view will appear at the same
+     * location as the placeholder.
+     * See the {@link IPageLayout} type documentation for more details about compound ids.
+     * If the placeholder contains wildcards, it remains in the layout, otherwise
+     * it is replaced by the view.
+     * If the primary id of the placeholder has no wildcards, it must refer to a view
+     * contributed to the workbench's view extension point
+     * (named <code>"org.eclipse.ui.views"</code>).
+     *
+     * @param viewId the compound view id (wildcards allowed)
+     */
+    public void addPlaceholder(String viewId);
+
+    /**
+	 * Returns the property with the given id or <code>null</code>. Folder
+	 * properties are an extensible mechanism for perspective authors to
+	 * customize the appearance of view stacks. The list of customizable
+	 * properties is determined by the presentation factory.
+	 *
+	 * @param id
+	 *            Must not be <code>null</code>.
+	 * @return property value, or <code>null</code> if the property is not
+	 *         set.
+	 * @since 3.3
+	 */
+    public String getProperty(String id);
+
+    /**
+	 * Sets the given property to the given value. Folder properties are an
+	 * extensible mechanism for perspective authors to customize the appearance
+	 * of view stacks. The list of customizable properties is determined by the
+	 * presentation factory.
+	 * <p>
+	 * These folder properties are intended to be set during
+	 * <code>IPerspectiveFactory#createInitialLayout</code>. Any subsequent
+	 * changes to property values after this method completes will not fire
+	 * change notifications and will not be reflected in the presentation.
+	 * </p>
+	 *
+	 * @param id
+	 *            property id. Must not be <code>null</code>.
+	 * @param value
+	 *            property value. <code>null</code> will clear the property.
+	 * @since 3.3
+	 */
+    public void setProperty(String id, String value);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPluginContribution.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPluginContribution.java
new file mode 100644
index 0000000..5d81994
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPluginContribution.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui;
+
+/**
+ * An interface that descriptor classes may implement in addition to their
+ * descriptor interface. This indicates that they may or may not originate from
+ * a plugin contribution. This is useful in various activity filtering
+ * scenarios.
+ *
+ * @since 3.0
+ */
+public interface IPluginContribution {
+
+    /**
+     * @return the local id of the contribution. Must not be <code>null</code>.
+     *         This should correspond to the extension-specific identifier for
+     *         a given contribution.
+     */
+    public String getLocalId();
+
+    /**
+     * @return the id of the originating plugin. Can be <code>null</code> if
+     *         this contribution did not originate from a plugin.
+     */
+    public String getPluginId();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPropertyListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPropertyListener.java
new file mode 100644
index 0000000..bd26d68
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IPropertyListener.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 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.ui;
+
+/**
+ * Interface for listening for property changes on an object.
+ * <p>
+ * This interface may be implemented by clients.
+ * </p>
+ *
+ * @see IWorkbenchPart#addPropertyListener
+ */
+public interface IPropertyListener {
+    /**
+     * Indicates that a property has changed.
+     *
+     * @param source the object whose property has changed
+     * @param propId the id of the property which has changed; property ids
+     *   are generally defined as constants on the source class
+     */
+    public void propertyChanged(Object source, int propId);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IReusableEditor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IReusableEditor.java
new file mode 100644
index 0000000..5b0a60b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IReusableEditor.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+/**
+ * Interface for reusable editors.
+ *
+ * An editors may support changing its input so that
+ * the workbench may change its contents instead of
+ * opening a new editor.
+ */
+public interface IReusableEditor extends IEditorPart {
+    /**
+     * Sets the input to this editor.
+     *
+     * <p><b>Note:</b> Clients must fire the {@link IEditorPart#PROP_INPUT }
+     * property change within their implementation of
+     * <code>setInput()</code>.<p>
+     *
+     * @param input the editor input
+     */
+    public void setInput(IEditorInput input);
+}
+
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISaveableFilter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISaveableFilter.java
new file mode 100644
index 0000000..347b858
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISaveableFilter.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui;
+
+/**
+ * A filter for selecting Saveables.
+ * @see IWorkbench#saveAll(org.eclipse.jface.window.IShellProvider, org.eclipse.jface.operation.IRunnableContext, ISaveableFilter, boolean)
+ * @since 3.3
+ */
+public interface ISaveableFilter {
+
+	/**
+	 * Indicate whether the given saveable matches this filter.
+	 * @param saveable the saveable being tested
+	 * @param containingParts the parts that contain the saveable. This list may
+	 *    contain zero or more parts.
+	 * @return whether the given saveable matches this filter
+	 */
+	public boolean select(Saveable saveable, IWorkbenchPart[] containingParts);
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISaveablePart.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISaveablePart.java
new file mode 100644
index 0000000..23055ab
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISaveablePart.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * Workbench parts implement or adapt to this interface to participate
+ * in the enablement and execution of the <code>Save</code> and
+ * <code>Save As</code> actions.
+ *
+ * @since 2.1
+ * @see org.eclipse.ui.IEditorPart
+ */
+public interface ISaveablePart {
+
+    /**
+     * The property id for <code>isDirty</code>.
+     */
+    public static final int PROP_DIRTY = IWorkbenchPartConstants.PROP_DIRTY;
+
+    /**
+     * Saves the contents of this part.
+     * <p>
+     * If the save is successful, the part should fire a property changed event
+     * reflecting the new dirty state (<code>PROP_DIRTY</code> property).
+     * </p>
+     * <p>
+     * If the save is cancelled through user action, or for any other reason, the
+     * part should invoke <code>setCancelled</code> on the <code>IProgressMonitor</code>
+     * to inform the caller.
+     * </p>
+     * <p>
+     * This method is long-running; progress and cancellation are provided
+     * by the given progress monitor.
+     * </p>
+     *
+     * @param monitor the progress monitor
+     */
+    public void doSave(IProgressMonitor monitor);
+
+    /**
+     * Saves the contents of this part to another object.
+     * <p>
+     * Implementors are expected to open a "Save As" dialog where the user will
+     * be able to select a new name for the contents. After the selection is made,
+     * the contents should be saved to that new name.  During this operation a
+     * <code>IProgressMonitor</code> should be used to indicate progress.
+     * </p>
+     * <p>
+     * If the save is successful, the part fires a property changed event
+     * reflecting the new dirty state (<code>PROP_DIRTY</code> property).
+     * </p>
+     */
+    public void doSaveAs();
+
+    /**
+     * Returns whether the contents of this part have changed since the last save
+     * operation. If this value changes the part must fire a property listener
+     * event with <code>PROP_DIRTY</code>.
+     * <p>
+     * <b>Note:</b> this method is called often on a part open or part
+     * activation switch, for example by actions to determine their
+     * enabled status.
+     * </p>
+     *
+     * @return <code>true</code> if the contents have been modified and need
+     *   saving, and <code>false</code> if they have not changed since the last
+     *   save
+     */
+    public boolean isDirty();
+
+    /**
+     * Returns whether the "Save As" operation is supported by this part.
+     *
+     * @return <code>true</code> if "Save As" is supported, and <code>false</code>
+     *  if not supported
+     */
+    public boolean isSaveAsAllowed();
+
+    /**
+     * Returns whether the contents of this part should be saved when the part
+     * is closed.
+     *
+     * @return <code>true</code> if the contents of the part should be saved on
+     *   close, and <code>false</code> if the contents are expendable
+     */
+    public boolean isSaveOnCloseNeeded();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISaveablePart2.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISaveablePart2.java
new file mode 100644
index 0000000..02a97d2
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISaveablePart2.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+/**
+ * Workbench parts implement or adapt to this interface to participate
+ * in actions that require a prompt for the user to provide input on
+ * what to do with unsaved data when the part is closed or the Workbench
+ * is shut down.
+ * <p>
+ * Note that if a part implements this interface, it is excluded from the
+ * common "prompt to save" dialog, and instead opens its own dialog.  This may
+ * cause multiple prompts to the end user during a single user operation.
+ * Implementors should be aware that this may lead to a less than optimal
+ * user experience.
+ * </p>
+ *
+ * @since 3.1
+ */
+public interface ISaveablePart2 extends ISaveablePart {
+
+	/**
+	 * Standard return code constant (value 0) indicating that the part
+	 * needs to be saved.
+	 */
+	public static final int YES = 0;
+
+	/**
+	 * Standard return code constant (value 1) indicating that the part
+	 * does not need to be saved and the part should be closed.
+	 */
+	public static final int NO = 1;
+
+	/**
+	 * Standard return code constant (value 2) indicating that the part
+	 * does not need to be saved and the part should not be closed.
+	 */
+	public static final int CANCEL = 2;
+
+	/**
+	 * Standard return code constant (value 3) indicating that the default
+	 * behavior for prompting the user to save will be used.
+	 */
+	public static final int DEFAULT = 3;
+
+    /**
+     * Prompts the user for input on what to do with unsaved data.
+     * This method is only called when the part is closed or when
+     * the Workbench is shutting down.
+     * <p>
+     * Implementors are expected to open a custom dialog where the
+     * user will be able to determine what to do with the unsaved data.
+     * Implementors may also return a result of <code>DEFAULT</code>
+     * to get the default prompt handling from the Workbench.
+     * </p>
+     *
+	 * @return the return code, must be either <code>YES</code>,
+	 * <code>NO</code>, <code>CANCEL</code> or <code>DEFAULT</code>.
+	 */
+	public int promptToSaveOnClose();
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISaveablesLifecycleListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISaveablesLifecycleListener.java
new file mode 100644
index 0000000..fd7cd5c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISaveablesLifecycleListener.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui;
+
+/**
+ * Listener for events fired by implementers of {@link ISaveablesSource}.
+ *
+ * <p>
+ * This service can be acquired from a part's service locator:
+ *
+ * <pre>
+ * ISaveablesLifecycleListener listener = (ISaveablesLifecycleListener) getSite()
+ * 		.getService(ISaveablesLifecycleListener.class);
+ * </pre>
+ *
+ * or, in the case of implementers of {@link ISaveablesSource} that are not a
+ * part, from the workbench:
+ *
+ * <pre>
+ * ISaveablesLifecycleListener listener = (ISaveablesLifecycleListener) workbench
+ * 		.getService(ISaveablesLifecycleListener.class);
+ * </pre>
+ *
+ * <ul>
+ * <li>This service is available globally.</li>
+ * </ul>
+ * </p>
+ *
+ * @since 3.2
+ */
+public interface ISaveablesLifecycleListener {
+
+	/**
+	 * Handle the given event. This method must be called on the UI thread.
+	 *
+	 * @param event
+	 */
+	public void handleLifecycleEvent(SaveablesLifecycleEvent event);
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISaveablesSource.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISaveablesSource.java
new file mode 100644
index 0000000..840d750
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISaveablesSource.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui;
+
+import org.eclipse.ui.part.EditorPart;
+
+/**
+ * Represents a source of Saveable objects (units of saveability). Workbench
+ * parts that show more than one unit of saveability, or whose units of
+ * saveability change over time, should implement this interface in order to
+ * provide better integration with workbench facilities like the Save command,
+ * prompts to save on part close or shutdown, etc.
+ * <p>
+ * IMPORTANT: As of 3.2, implementers of <code>ISaveablesSource</code> must
+ * satisfy the following conditions:
+ * <ul>
+ * <li>If ISaveablesSource is implemented by an IWorkbenchPart:
+ * <ul>
+ * <li>the part must implement <code>ISaveablePart</code></li>
+ * <li>if any of its Saveable objects are dirty, the part must return
+ * <code>true</code> from {@link ISaveablePart#isDirty()}</li>
+ * <li>the part must return <code>true</code> from
+ * {@link ISaveablePart#isSaveOnCloseNeeded()} if it is dirty (the default
+ * behaviour implemented by {@link EditorPart})</li>
+ * <li>the part must not implement {@link ISaveablePart2}</li>
+ * </ul>
+ * </li>
+ * <li>If ISaveablesSource is implemented by a non-part (possible as of 3.2.1 and 3.3):
+ * <ul>
+ * <li>the Workbench's {@link ISaveablesLifecycleListener} (obtained from the
+ * Workbench by calling
+ * <code>workbench.getService(ISaveablesLifecycleListener.class)</code>) must
+ * be notified of any change to the result of {@link #getSaveables()} </li>
+ * <li>getActiveSaveables() should be implemented to return an empty array
+ * </li>
+ * </ul>
+ * </ul>
+ * If any of these conditions are not met, it is undefined whether the Workbench
+ * will prompt to save dirty Saveables when closing parts or the Workbench.
+ * </p>
+ * <p>
+ * These conditions may be relaxed in future releases.
+ * </p>
+ *
+ * @since 3.2
+ */
+public interface ISaveablesSource {
+
+	/**
+	 * Returns the saveables presented by the workbench part. If the return
+	 * value of this method changes during the lifetime of
+	 * this part (i.e. after initialization and control creation but before disposal)
+	 * the part must notify an implicit listener using
+	 * {@link ISaveablesLifecycleListener#handleLifecycleEvent(SaveablesLifecycleEvent)}.
+	 * <p>
+	 * Additions of saveables to the list of saveables of this part are
+	 * announced using an event of type
+	 * {@link SaveablesLifecycleEvent#POST_OPEN}. Removals are announced in a
+	 * two-stage process, first using an event of type
+	 * {@link SaveablesLifecycleEvent#PRE_CLOSE} followed by an event of type
+	 * {@link SaveablesLifecycleEvent#POST_CLOSE}. Since firing the
+	 * <code>PRE_CLOSE</code> event may trigger prompts to save dirty
+	 * saveables, the cancellation status of the event must be checked by the
+	 * part after the notification. When removing only non-dirty saveables,
+	 * <code>POST_CLOSE</code> notification is sufficient.
+	 * </p>
+	 * <p>
+	 * The listener is obtained from the part site by calling
+	 * <code>partSite.getService(ISaveablesLifecycleListener.class)</code>.
+	 * </p>
+	 * <p>
+	 * The part must not notify from its initialization methods (e.g. <code>init</code>
+	 * or <code>createPartControl</code>), or from its dispose method. Parts that
+	 * implement {@link IReusableEditor} must notify when their input is changed
+	 * through {@link IReusableEditor#setInput(IEditorInput)}.
+	 * </p>
+	 *
+	 * @return the saveables presented by the workbench part
+	 *
+	 * @see ISaveablesLifecycleListener
+	 */
+	Saveable[] getSaveables();
+
+	/**
+	 * Returns the saveables currently active in the workbench part.
+	 * <p>
+	 * Certain workbench actions, such as Save, target only the active saveables
+	 * in the active part. For example, the active saveables could be determined
+	 * based on the current selection in the part.
+	 * </p>
+	 *
+	 * @return the saveables currently active in the workbench part
+	 */
+	Saveable[] getActiveSaveables();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISecondarySaveableSource.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISecondarySaveableSource.java
new file mode 100644
index 0000000..f20830a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISecondarySaveableSource.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Andrey Loskutov <loskutov@gmx.de>.
+ * 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:
+ *     Andrey Loskutov <loskutov@gmx.de> - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ui;
+
+import org.eclipse.core.runtime.IAdaptable;
+
+/**
+ * Interface for parts providing an adapter to {@link ISaveablePart} objects
+ * created or managed originally by other parts.
+ * <p>
+ * In case the same {@link ISaveablePart} object is created originally by a
+ * "primary" part and shown or edited by multiple parts, the "primary" part
+ * might want be the only UI element showing the "dirty" state in the UI.
+ * <p>
+ * This interface allows "primary" parts define the default behavior for all
+ * "secondary" parts; and allows "secondary" parts to override this and decide
+ * how they should behave and how they should be represented in the UI.
+ * <p>
+ * <li>Parts implementing this interface directly are considered to be
+ * "secondary" parts and define only their own behavior.
+ * <li>Parts can also provide an adapter to this interface via
+ * {@link IAdaptable#getAdapter(Class)}. If such part is not implementing this
+ * interface directly, it can considered as primary "source" part, and can
+ * define a default behavior for all secondary parts.
+ * <p>
+ * Per default, dirty state of "secondary" parts is ignored by the framework.
+ *
+ * @since 3.109
+ */
+public interface ISecondarySaveableSource {
+
+	/**
+	 * Whether the dirty state changes should be supported by the framework if
+	 * the part directly implements {@link ISecondarySaveableSource}.
+	 * <p>
+	 * If the part providing the adapter is not implementing
+	 * {@link ISecondarySaveableSource}, return value defines the default
+	 * behavior of "secondary" parts connected to this part.
+	 *
+	 * @return default implementation returns {@code false}
+	 */
+	default boolean isDirtyStateSupported() {
+		return false;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISelectionListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISelectionListener.java
new file mode 100644
index 0000000..b3d3301
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISelectionListener.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import java.util.EventListener;
+
+import org.eclipse.jface.viewers.ISelection;
+
+/**
+ * Interface for listening to selection changes.
+ * <p>
+ * This interface may be implemented by clients.
+ * </p>
+ *
+ * @see ISelectionService#addSelectionListener(ISelectionListener)
+ * @see ISelectionService#addSelectionListener(String, ISelectionListener)
+ * @see org.eclipse.ui.INullSelectionListener
+ */
+public interface ISelectionListener extends EventListener {
+    /**
+     * Notifies this listener that the selection has changed.
+     * <p>
+     * This method is called when the selection changes from one to a
+     * <code>non-null</code> value, but not when the selection changes to
+     * <code>null</code>. If there is a requirement to be notified in the latter
+     * scenario, implement <code>INullSelectionListener</code>. The event will
+     * be posted through this method.
+     * </p>
+     *
+     * @param part the workbench part containing the selection
+     * @param selection the current selection. This may be <code>null</code>
+     * 		if <code>INullSelectionListener</code> is implemented.
+     */
+    public void selectionChanged(IWorkbenchPart part, ISelection selection);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISelectionService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISelectionService.java
new file mode 100644
index 0000000..d8fda56
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISelectionService.java
@@ -0,0 +1,177 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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.ui;
+
+import org.eclipse.jface.viewers.ISelection;
+
+/**
+ * A selection service tracks the selection within an object.
+ * <p>
+ * A listener that wants to be notified when the selection becomes
+ * <code>null</code> must implement the <code>INullSelectionListener</code>
+ * interface.
+ * </p>
+ * <p>
+ * This service can be acquired from your service locator:
+ * <pre>
+ * 	ISelectionService service = (ISelectionService) getSite().getService(ISelectionService.class);
+ * </pre>
+ * <ul>
+ * <li>This service is not available globally, only from the workbench window level down.</li>
+ * </ul>
+ * </p>
+ *
+ * @see org.eclipse.ui.ISelectionListener
+ * @see org.eclipse.ui.INullSelectionListener
+ * @see org.eclipse.ui.services.IServiceLocator#getService(Class)
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface ISelectionService {
+    /**
+     * Adds the given selection listener.
+     * Has no effect if an identical listener is already registered.
+	 * <p>
+	 * <b>Note:</b> listeners should be removed when no longer necessary. If
+	 * not, they will be removed when the IServiceLocator used to acquire this
+	 * service is disposed.
+	 * </p>
+     *
+     * @param listener a selection listener
+     * @see #removeSelectionListener(ISelectionListener)
+     */
+    public void addSelectionListener(ISelectionListener listener);
+
+    /**
+     * Adds a part-specific selection listener which is notified when selection changes
+     * in the part with the given id. This is independent of part activation - the part
+     * need not be active for notification to be sent.
+     * <p>
+     * When the part is created, the listener is passed the part's initial selection.
+     * When the part is disposed, the listener is passed a <code>null</code> selection,
+     * but only if the listener implements <code>INullSelectionListener</code>.
+     * </p>
+     * <p>
+     * Note: This will not correctly track editor parts as each editor does
+     * not have a unique partId.
+     * </p>
+	 * <p>
+	 * <b>Note:</b> listeners should be removed when no longer necessary. If
+	 * not, they will be removed when the IServiceLocator used to acquire this
+	 * service is disposed.
+	 * </p>
+     *
+     * @param partId the id of the part to track
+     * @param listener a selection listener
+     * @since 2.0
+     * @see #removeSelectionListener(String, ISelectionListener)
+     */
+    public void addSelectionListener(String partId, ISelectionListener listener);
+
+    /**
+     * Adds the given post selection listener.It is equivalent to selection
+     * changed if the selection was triggered by the mouse but it has a
+     * delay if the selection is triggered by the keyboard arrows.
+     * Has no effect if an identical listener is already registered.
+     *
+     * Note: Works only for StructuredViewer(s).
+	 * <p>
+	 * <b>Note:</b> listeners should be removed when no longer necessary. If
+	 * not, they will be removed when the IServiceLocator used to acquire this
+	 * service is disposed.
+	 * </p>
+     *
+     * @param listener a selection listener
+     * @see #removePostSelectionListener(ISelectionListener)
+     */
+    public void addPostSelectionListener(ISelectionListener listener);
+
+    /**
+     * Adds a part-specific selection listener which is notified when selection changes
+     * in the part with the given id. This is independent of part activation - the part
+     * need not be active for notification to be sent.
+     * <p>
+     * When the part is created, the listener is passed the part's initial selection.
+     * When the part is disposed, the listener is passed a <code>null</code> selection,
+     * but only if the listener implements <code>INullSelectionListener</code>.
+     * </p>
+     * <p>
+     * Note: This will not correctly track editor parts as each editor does
+     * not have a unique partId.
+     * </p>
+	 * <p>
+	 * <b>Note:</b> listeners should be removed when no longer necessary. If
+	 * not, they will be removed when the IServiceLocator used to acquire this
+	 * service is disposed.
+	 * </p>
+     *
+     * @param partId the id of the part to track
+     * @param listener a selection listener
+     * @since 2.0
+     * @see #removePostSelectionListener(String, ISelectionListener)
+     */
+	public void addPostSelectionListener(String partId, ISelectionListener listener);
+
+    /**
+     * Returns the current selection in the active part.  If the selection in the
+     * active part is <em>undefined</em> (the active part has no selection provider)
+     * the result will be <code>null</code>.
+     *
+     * @return the current selection, or <code>null</code> if undefined
+     */
+    public ISelection getSelection();
+
+    /**
+     * Returns the current selection in the part with the given id.  If the part is not open,
+     * or if the selection in the active part is <em>undefined</em> (the active part has no selection provider)
+     * the result will be <code>null</code>.
+     *
+     * @param partId the id of the part
+     * @return the current selection, or <code>null</code> if undefined
+     * @since 2.0
+     */
+    public ISelection getSelection(String partId);
+
+    /**
+     * Removes the given selection listener.
+     * Has no effect if an identical listener is not registered.
+     *
+     * @param listener a selection listener
+     */
+    public void removeSelectionListener(ISelectionListener listener);
+
+    /**
+     * Removes the given part-specific selection listener.
+     * Has no effect if an identical listener is not registered for the given part id.
+     *
+     * @param partId the id of the part to track
+     * @param listener a selection listener
+     * @since 2.0
+     */
+	public void removeSelectionListener(String partId, ISelectionListener listener);
+
+    /**
+     * Removes the given post selection listener.
+     * Has no effect if an identical listener is not registered.
+     *
+     * @param listener a selection listener
+     */
+    public void removePostSelectionListener(ISelectionListener listener);
+
+    /**
+     * Removes the given part-specific post selection listener.
+     * Has no effect if an identical listener is not registered for the given part id.
+     *
+     * @param partId the id of the part to track
+     * @param listener a selection listener
+     * @since 2.0
+     */
+	public void removePostSelectionListener(String partId, ISelectionListener listener);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISharedImages.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISharedImages.java
new file mode 100644
index 0000000..8779e11
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISharedImages.java
@@ -0,0 +1,619 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.Cursor;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.Device;
+
+/**
+ * A registry for common images used by the workbench which may be useful
+ * to other plug-ins.
+ * <p>
+ * This class provides <code>Image</code> and <code>ImageDescriptor</code>s
+ * for each named image in the interface.  All <code>Image</code> objects provided
+ * by this class are managed by this class and must never be disposed
+ * by other clients.
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noextend This interface is not intended to be extended by clients.
+ */
+public interface ISharedImages {
+    /**
+     * Identifies the error overlay image.
+     * @since 3.4
+     */
+    public final static String IMG_DEC_FIELD_ERROR = "IMG_DEC_FIELD_ERROR"; //$NON-NLS-1$
+
+    /**
+     * Identifies the warning overlay image.
+     * @since 3.4
+     */
+    public final static String IMG_DEC_FIELD_WARNING = "IMG_DEC_FIELD_WARNING"; //$NON-NLS-1$
+
+    /**
+     * Identifies the default image used for views.
+     */
+    public final static String IMG_DEF_VIEW = "IMG_DEF_VIEW"; //$NON-NLS-1$
+
+    /**
+     * Identifies the collapse all image in the enabled state.
+     * @since 3.4
+     */
+    public final static String IMG_ELCL_COLLAPSEALL = "IMG_ELCL_COLLAPSEALL"; //$NON-NLS-1$
+
+    /**
+     * Identifies the collapse all image in the disabled state.
+     * @since 3.4
+     */
+    public final static String IMG_ELCL_COLLAPSEALL_DISABLED = "IMG_ELCL_COLLAPSEALL_DISABLED"; //$NON-NLS-1$
+
+    /**
+     * Identifies the remove image in the enabled state.
+     * @since 3.4
+     */
+    public final static String IMG_ELCL_REMOVE = "IMG_ELCL_REMOVE"; //$NON-NLS-1$
+
+    /**
+     * Identifies the remove image in the disabled state.
+     * @since 3.4
+     */
+    public final static String IMG_ELCL_REMOVE_DISABLED = "IMG_ELCL_REMOVE_DISABLED"; //$NON-NLS-1$
+
+    /**
+     * Identifies the remove all image in the enabled state.
+     * @since 3.4
+     */
+    public final static String IMG_ELCL_REMOVEALL = "IMG_ELCL_REMOVEALL"; //$NON-NLS-1$
+
+    /**
+     * Identifies the remove all image in the disabled state.
+     * @since 3.4
+     */
+    public final static String IMG_ELCL_REMOVEALL_DISABLED = "IMG_ELCL_REMOVEALL_DISABLED"; //$NON-NLS-1$
+
+    /**
+     * Identifies the stop image in the enabled state.
+     * @since 3.4
+     */
+    public final static String IMG_ELCL_STOP = "IMG_ELCL_STOP"; //$NON-NLS-1$
+
+    /**
+     * Identifies the stop image in the disabled state.
+     * @since 3.4
+     */
+    public final static String IMG_ELCL_STOP_DISABLED = "IMG_ELCL_STOP_DISABLED"; //$NON-NLS-1$
+
+    /**
+     * Identifies the synchronize image in the enabled state.
+     * @since 3.4
+     */
+    public final static String IMG_ELCL_SYNCED = "IMG_ELCL_SYNCED"; //$NON-NLS-1$
+
+    /**
+     * Identifies the synchronize image in the disabled state.
+     * @since 3.4
+     */
+    public final static String IMG_ELCL_SYNCED_DISABLED = "IMG_ELCL_SYNCED_DISABLED"; //$NON-NLS-1$
+
+    /**
+     * Identifies the clear image in the enabled state.
+     * @since 3.4
+     */
+    public final static String IMG_ETOOL_CLEAR = "IMG_ETOOL_CLEAR"; //$NON-NLS-1$
+
+    /**
+     * Identifies the clear image in the disabled state.
+     * @since 3.4
+     */
+    public final static String IMG_ETOOL_CLEAR_DISABLED = "IMG_ETOOL_CLEAR_DISABLED"; //$NON-NLS-1$
+
+    /**
+     * Identifies the default perspective image.
+     * @since 3.4
+     */
+    public final static String IMG_ETOOL_DEF_PERSPECTIVE = "IMG_ETOOL_DEF_PERSPECTIVE"; //$NON-NLS-1$
+
+    /**
+     * Identifies the delete image in the enabled state.
+     * @since 3.4
+     */
+    public final static String IMG_ETOOL_DELETE = "IMG_ETOOL_DELETE"; //$NON-NLS-1$
+
+    /**
+     * Identifies the delete image in the disabled state.
+     * @since 3.4
+     */
+    public final static String IMG_ETOOL_DELETE_DISABLED = "IMG_ETOOL_DELETE_DISABLED"; //$NON-NLS-1$
+
+    /**
+     * Identifies the home image in the enabled state.
+     * @since 3.4
+     */
+    public final static String IMG_ETOOL_HOME_NAV = "IMG_ETOOL_HOME_NAV"; //$NON-NLS-1$
+
+    /**
+     * Identifies the home image in the disabled state.
+     * @since 3.4
+     */
+    public final static String IMG_ETOOL_HOME_NAV_DISABLED = "IMG_ETOOL_HOME_NAV_DISABLED"; //$NON-NLS-1$
+
+    /**
+     * Identifies the print image in the enabled state.
+     * @since 3.4
+     */
+    public final static String IMG_ETOOL_PRINT_EDIT = "IMG_ETOOL_PRINT_EDIT"; //$NON-NLS-1$
+
+    /**
+     * Identifies the print image in the disabled state.
+     * @since 3.4
+     */
+    public final static String IMG_ETOOL_PRINT_EDIT_DISABLED = "IMG_ETOOL_PRINT_EDIT_DISABLED"; //$NON-NLS-1$
+
+    /**
+     * Identifies the save image in the enabled state.
+     * @since 3.4
+     */
+    public final static String IMG_ETOOL_SAVE_EDIT = "IMG_ETOOL_SAVE_EDIT"; //$NON-NLS-1$
+
+    /**
+     * Identifies the save image in the disabled state.
+     * @since 3.4
+     */
+    public final static String IMG_ETOOL_SAVE_EDIT_DISABLED = "IMG_ETOOL_SAVE_EDIT_DISABLED"; //$NON-NLS-1$
+
+    /**
+     * Identifies the save all image in the enabled state.
+     * @since 3.4
+     */
+    public final static String IMG_ETOOL_SAVEALL_EDIT = "IMG_ETOOL_SAVEALL_EDIT"; //$NON-NLS-1$
+
+    /**
+     * Identifies the save all image in the disabled state.
+     * @since 3.4
+     */
+    public final static String IMG_ETOOL_SAVEALL_EDIT_DISABLED = "IMG_ETOOL_SAVEALL_EDIT_DISABLED"; //$NON-NLS-1$
+
+    /**
+     * Identifies the save as image in the enabled state.
+     * @since 3.4
+     */
+    public final static String IMG_ETOOL_SAVEAS_EDIT = "IMG_ETOOL_SAVEAS_EDIT"; //$NON-NLS-1$
+
+    /**
+     * Identifies the save as image in the disabled state.
+     * @since 3.4
+     */
+    public final static String IMG_ETOOL_SAVEAS_EDIT_DISABLED = "IMG_ETOOL_SAVEAS_EDIT_DISABLED"; //$NON-NLS-1$
+
+    /**
+     * Identifies the help image.
+     * @since 3.4
+     */
+    public final static String IMG_LCL_LINKTO_HELP = "IMG_LCL_LINKTO_HELP"; //$NON-NLS-1$
+
+    /**
+     * Identifies the add image.
+     * @since 3.4
+     */
+    public final static String IMG_OBJ_ADD = "IMG_OBJ_ADD"; //$NON-NLS-1$
+
+    /**
+     * Identifies an element image.
+     */
+    public final static String IMG_OBJ_ELEMENT = "IMG_OBJ_ELEMENTS"; //$NON-NLS-1$
+
+    /**
+     * Identifies a file image.
+     */
+    public final static String IMG_OBJ_FILE = "IMG_OBJ_FILE"; //$NON-NLS-1$
+
+    /**
+     * Identifies a folder image.
+     */
+    public final static String IMG_OBJ_FOLDER = "IMG_OBJ_FOLDER"; //$NON-NLS-1$
+
+    /**
+     * Identifies a project image.
+     *
+     * @deprecated in 3.0. This image is IDE-specific, and is therefore found
+     * only in IDE configurations. IDE-specific tools should use
+     * <code>org.eclipse.ui.ide.IDE.SharedImages.IMG_OBJ_PROJECT</code> instead.
+     */
+    @Deprecated
+	public final static String IMG_OBJ_PROJECT = "IMG_OBJ_PROJECT"; //$NON-NLS-1$
+
+    /**
+     * Identifies a closed project image.
+     *
+     * @deprecated in 3.0. This image is IDE-specific, and is therefore found
+     * only in IDE configurations. IDE-specific tools should use
+     * <code>org.eclipse.ui.ide.IDE.SharedImages.IMG_OBJ_PROJECT_CLOSED</code> instead.
+     */
+    @Deprecated
+	public final static String IMG_OBJ_PROJECT_CLOSED = "IMG_OBJ_PROJECT_CLOSED"; //$NON-NLS-1$
+
+    /**
+     * Identifies the default image used to indicate a bookmark.
+     *
+     * @deprecated in 3.0. This image is IDE-specific, and is therefore found
+     * only in IDE configurations. IDE-specific tools should use
+     * <code>org.eclipse.ui.ide.IDE.SharedImages.IMG_OBJS_BKMRK_TSK</code> instead.
+     */
+    @Deprecated
+	public final static String IMG_OBJS_BKMRK_TSK = "IMG_OBJS_BKMRK_TSK"; //$NON-NLS-1$
+
+    /**
+     * Identifies the default image used to indicate errors.
+     */
+    public final static String IMG_OBJS_ERROR_TSK = "IMG_OBJS_ERROR_TSK"; //$NON-NLS-1$
+
+    /**
+     * Identifies the default image used to indicate information only.
+     */
+    public final static String IMG_OBJS_INFO_TSK = "IMG_OBJS_INFO_TSK"; //$NON-NLS-1$
+
+    /**
+     * Identifies the default image used to indicate a task.
+     *
+     * @deprecated in 3.0. This image is IDE-specific, and is therefore found
+     * only in IDE configurations. IDE-specific tools should use
+     * <code>org.eclipse.ui.ide.IDE.SharedImages.IMG_OBJS_TASK_TSK</code> instead.
+     */
+    @Deprecated
+	public final static String IMG_OBJS_TASK_TSK = "IMG_OBJS_TASK_TSK"; //$NON-NLS-1$
+
+    /**
+     * Identifies the default image used to indicate warnings.
+     */
+    public final static String IMG_OBJS_WARN_TSK = "IMG_OBJS_WARN_TSK"; //$NON-NLS-1$
+
+    /**
+     * Identifies the image used for "open marker".
+     *
+     * @deprecated in 3.0. This image is IDE-specific, and is therefore found
+     * only in IDE configurations. IDE-specific tools should use
+     * <code>org.eclipse.ui.ide.IDE.SharedImages.IMG_OPEN_MARKER</code> instead.
+     */
+    @Deprecated
+	public final static String IMG_OPEN_MARKER = "IMG_OPEN_MARKER"; //$NON-NLS-1$
+
+    /**
+     * Identifies the back image in the enabled state.
+     */
+    public final static String IMG_TOOL_BACK = "IMG_TOOL_BACK"; //$NON-NLS-1$
+
+    /**
+     * Identifies the back image in the disabled state.
+     */
+    public final static String IMG_TOOL_BACK_DISABLED = "IMG_TOOL_BACK_DISABLED"; //$NON-NLS-1$
+
+    /**
+     * Identifies the back image in the hover (colored) state.
+     *
+     * @deprecated in 3.0. This image is now the same as <code>IMG_TOOL_BACK</code>.
+     *   Enabled images are now in color.  The workbench itself no longer uses the hover image variants.
+     */
+    @Deprecated
+	public final static String IMG_TOOL_BACK_HOVER = "IMG_TOOL_BACK_HOVER"; //$NON-NLS-1$
+
+    /**
+     * Identifies the copy image in the enabled state.
+     */
+    public final static String IMG_TOOL_COPY = "IMG_TOOL_COPY"; //$NON-NLS-1$
+
+    /**
+     * Identifies the copy image in the disabled state.
+     */
+    public final static String IMG_TOOL_COPY_DISABLED = "IMG_TOOL_COPY_DISABLED"; //$NON-NLS-1$
+
+    /**
+     * Identifies the copy image in the hover (colored) state.
+     *
+     * @deprecated in 3.0. This image is now the same as <code>IMG_TOOL_COPY</code>.
+     *   Enabled images are now in color.  The workbench itself no longer uses the hover image variants.
+     */
+    @Deprecated
+	public final static String IMG_TOOL_COPY_HOVER = "IMG_TOOL_COPY_HOVER"; //$NON-NLS-1$
+
+    /**
+     * Identifies the cut image in the enabled state.
+     */
+    public final static String IMG_TOOL_CUT = "IMG_TOOL_CUT"; //$NON-NLS-1$
+
+    /**
+     * Identifies the cut image in the disabled state.
+     */
+    public final static String IMG_TOOL_CUT_DISABLED = "IMG_TOOL_CUT_DISABLED"; //$NON-NLS-1$
+
+    /**
+     * Identifies the cut image in the hover (colored) state.
+     *
+     * @deprecated in 3.0. This image is now the same as <code>IMG_TOOL_CUT</code>.
+     *   Enabled images are now in color.  The workbench itself no longer uses the hover image variants.
+     */
+    @Deprecated
+	public final static String IMG_TOOL_CUT_HOVER = "IMG_TOOL_CUT_HOVER"; //$NON-NLS-1$
+
+    /**
+     * Identifies the delete image in the enabled state.
+     * @since 3.4
+     */
+    public final static String IMG_TOOL_DELETE = "IMG_TOOL_DELETE"; //$NON-NLS-1$
+
+    /**
+     * Identifies the delete image in the disabled state.
+     * @since 3.4
+     */
+    public final static String IMG_TOOL_DELETE_DISABLED = "IMG_TOOL_DELETE_DISABLED"; //$NON-NLS-1$
+
+    /**
+     * Identifies the delete image in the hover (colored) state.
+     *
+     * @deprecated in 3.0. This image is now the same as <code>IMG_TOOL_DELETE</code>.
+     *   Enabled images are now in color.  The workbench itself no longer uses the hover image variants.
+     */
+    @Deprecated
+	public final static String IMG_TOOL_DELETE_HOVER = "IMG_TOOL_DELETE_HOVER"; //$NON-NLS-1$
+
+    /**
+     * Identifies the forward image in the enabled state.
+     */
+    public final static String IMG_TOOL_FORWARD = "IMG_TOOL_FORWARD"; //$NON-NLS-1$
+
+    /**
+     * Identifies the forward image in the disabled state.
+     */
+    public final static String IMG_TOOL_FORWARD_DISABLED = "IMG_TOOL_FORWARD_DISABLED"; //$NON-NLS-1$
+
+    /**
+     * Identifies the forward image in the hover (colored) state.
+     *
+     * @deprecated in 3.0. This image is now the same as <code>IMG_TOOL_FORWARD</code>.
+     *   Enabled images are now in color.  The workbench itself no longer uses the hover image variants.
+     */
+    @Deprecated
+	public final static String IMG_TOOL_FORWARD_HOVER = "IMG_TOOL_FORWARD_HOVER"; //$NON-NLS-1$
+
+    /**
+     * Identifies the new wizard image in the enabled state.
+     */
+    public final static String IMG_TOOL_NEW_WIZARD = "IMG_TOOL_NEW_WIZARD"; //$NON-NLS-1$
+
+    /**
+     * Identifies the new wizard image in the disabled state.
+     */
+    public final static String IMG_TOOL_NEW_WIZARD_DISABLED = "IMG_TOOL_NEW_WIZARD_DISABLED"; //$NON-NLS-1$
+
+    /**
+     * Identifies the new wizard image in the hover (colored) state.
+     *
+     * @deprecated in 3.0. This image is now the same as <code>IMG_TOOL_NEW_WIZARD</code>.
+     *   Enabled images are now in color.  The workbench itself no longer uses the hover image variants.
+     */
+    @Deprecated
+	public final static String IMG_TOOL_NEW_WIZARD_HOVER = "IMG_TOOL_NEW_WIZARD_HOVER"; //$NON-NLS-1$
+
+    /**
+     * Identifies the paste image in the enabled state.
+     */
+    public final static String IMG_TOOL_PASTE = "IMG_TOOL_PASTE"; //$NON-NLS-1$
+
+    /**
+     * Identifies the paste image in the disabled state.
+     */
+    public final static String IMG_TOOL_PASTE_DISABLED = "IMG_TOOL_PASTE_DISABLED"; //$NON-NLS-1$
+
+    /**
+     * Identifies the paste image in the hover (colored) state.
+     *
+     * @deprecated in 3.0. This image is now the same as <code>IMG_TOOL_PASTE</code>.
+     *   Enabled images are now in color.  The workbench itself no longer uses the hover image variants.
+     */
+    @Deprecated
+	public final static String IMG_TOOL_PASTE_HOVER = "IMG_TOOL_PASTE_HOVER"; //$NON-NLS-1$
+
+    /**
+     * Identifies the redo image in the enabled state.
+     */
+    public final static String IMG_TOOL_REDO = "IMG_TOOL_REDO"; //$NON-NLS-1$
+
+    /**
+     * Identifies the redo image in the disabled state.
+     */
+    public final static String IMG_TOOL_REDO_DISABLED = "IMG_TOOL_REDO_DISABLED"; //$NON-NLS-1$
+
+    /**
+     * Identifies the redo image in the hover (colored) state.
+     *
+     * @deprecated in 3.0. This image is now the same as <code>IMG_TOOL_REDO</code>.
+     *   Enabled images are now in color.  The workbench itself no longer uses the hover image variants.
+     */
+    @Deprecated
+	public final static String IMG_TOOL_REDO_HOVER = "IMG_TOOL_REDO_HOVER"; //$NON-NLS-1$
+
+    /**
+     * Identifies the undo image in the enabled state.
+     */
+    public final static String IMG_TOOL_UNDO = "IMG_TOOL_UNDO"; //$NON-NLS-1$
+
+    /**
+     * Identifies the undo image in the disabled state.
+     */
+    public final static String IMG_TOOL_UNDO_DISABLED = "IMG_TOOL_UNDO_DISABLED"; //$NON-NLS-1$
+
+    /**
+     * Identifies the undo image in the hover (colored) state.
+     *
+     * @deprecated in 3.0. This image is now the same as <code>IMG_TOOL_UNDO</code>.
+     *   Enabled images are now in color.  The workbench itself no longer uses the hover image variants.
+     */
+    @Deprecated
+	public final static String IMG_TOOL_UNDO_HOVER = "IMG_TOOL_UNDO_HOVER"; //$NON-NLS-1$
+
+    /**
+     * Identifies the up image in the enabled state.
+     */
+    public final static String IMG_TOOL_UP = "IMG_TOOL_UP"; //$NON-NLS-1$
+
+    /**
+     * Identifies the up image in the disabled state.
+     */
+    public final static String IMG_TOOL_UP_DISABLED = "IMG_TOOL_UP_DISABLED"; //$NON-NLS-1$
+
+    /**
+     * Identifies the up image in the hover (colored) state.
+     *
+     * @deprecated in 3.0. This image is now the same as <code>IMG_TOOL_UP</code>.
+     *   Enabled images are now in color.  The workbench itself no longer uses the hover image variants.
+     */
+    @Deprecated
+	public final static String IMG_TOOL_UP_HOVER = "IMG_TOOL_UP_HOVER"; //$NON-NLS-1$
+
+    // The following set of constants represent the image pairs that are used
+    // to construct cursors for drag and drop operations within the workbench
+    // Each cursor is represented by two images; the 'source' and the 'mask'
+    // These need to be combined using the following code snippet:
+	//    source = getImageDescriptor(sourceId);
+	//    mask = getImageDescriptor(maskId);
+	//    cursor = new Cursor(display, source.getImageData(), mask.getImageData(), 16, 16);
+
+    /**
+     * Cursor 'source' for the left arrow cursor. For cursor construction see:
+     * @see Cursor#Cursor(Device, ImageData, ImageData, int, int)
+     * @since 3.5
+     */
+    public final static String IMG_OBJS_DND_LEFT_SOURCE = "IMG_OBJS_DND_LEFT_SOURCE"; //$NON-NLS-1$
+    /**
+     * Cursor 'mask' for the left arrow cursor. For cursor construction see:
+     * @see Cursor#Cursor(Device, ImageData, ImageData, int, int)
+     * @since 3.5
+     */
+    public final static String IMG_OBJS_DND_LEFT_MASK = "IMG_OBJS_DND_LEFT_MASK"; //$NON-NLS-1$
+
+    /**
+     * Cursor 'source' for the right arrow cursor. For cursor construction see:
+     * @see Cursor#Cursor(Device, ImageData, ImageData, int, int)
+     * @since 3.5
+     */
+    public final static String IMG_OBJS_DND_RIGHT_SOURCE = "IMG_OBJS_DND_RIGHT_SOURCE"; //$NON-NLS-1$
+    /**
+     * Cursor 'mask' for the right arrow cursor. For cursor construction see:
+     * @see Cursor#Cursor(Device, ImageData, ImageData, int, int)
+     * @since 3.5
+     */
+    public final static String IMG_OBJS_DND_RIGHT_MASK = "IMG_OBJS_DND_RIGHT_MASK"; //$NON-NLS-1$
+
+    /**
+     * Cursor 'source' for the up arrow cursor. For cursor construction see:
+     * @see Cursor#Cursor(Device, ImageData, ImageData, int, int)
+     * @since 3.5
+     */
+    public final static String IMG_OBJS_DND_TOP_SOURCE = "IMG_OBJS_DND_TOP_SOURCE"; //$NON-NLS-1$
+    /**
+     * Cursor 'mask' for the up arrow cursor. For cursor construction see:
+     * @see Cursor#Cursor(Device, ImageData, ImageData, int, int)
+     * @since 3.5
+     */
+    public final static String IMG_OBJS_DND_TOP_MASK = "IMG_OBJS_DND_TOP_MASK"; //$NON-NLS-1$
+
+    /**
+     * Cursor 'source' for the down arrow cursor. For cursor construction see:
+     * @see Cursor#Cursor(Device, ImageData, ImageData, int, int)
+     * @since 3.5
+     */
+    public final static String IMG_OBJS_DND_BOTTOM_SOURCE = "IMG_OBJS_DND_BOTTOM_SOURCE"; //$NON-NLS-1$
+    /**
+     * Cursor 'mask' for the down arrow cursor. For cursor construction see:
+     * @see Cursor#Cursor(Device, ImageData, ImageData, int, int)
+     * @since 3.5
+     */
+    public final static String IMG_OBJS_DND_BOTTOM_MASK = "IMG_OBJS_DND_BOTTOM_MASK"; //$NON-NLS-1$
+
+    /**
+     * Cursor 'source' for the 'no drop' arrow cursor. For cursor construction see:
+     * @see Cursor#Cursor(Device, ImageData, ImageData, int, int)
+     * @since 3.5
+     */
+    public final static String IMG_OBJS_DND_INVALID_SOURCE = "IMG_OBJS_DND_INVALID_SOURCE"; //$NON-NLS-1$
+    /**
+     * Cursor 'mask' for the 'no drop' arrow cursor. For cursor construction see:
+     * @see Cursor#Cursor(Device, ImageData, ImageData, int, int)
+     * @since 3.5
+     */
+    public final static String IMG_OBJS_DND_INVALID_MASK = "IMG_OBJS_DND_INVALID_MASK"; //$NON-NLS-1$
+
+    /**
+     * Cursor 'source' for the 'in stack' arrow cursor. For cursor construction see:
+     * @see Cursor#Cursor(Device, ImageData, ImageData, int, int)
+     * @since 3.5
+     */
+    public final static String IMG_OBJS_DND_STACK_SOURCE = "IMG_OBJS_DND_STACK_SOURCE"; //$NON-NLS-1$
+    /**
+     * Cursor 'mask' for the 'in stack' arrow cursor. For cursor construction see:
+     * @see Cursor#Cursor(Device, ImageData, ImageData, int, int)
+     * @since 3.5
+     */
+    public final static String IMG_OBJS_DND_STACK_MASK = "IMG_OBJS_DND_STACK_MASK"; //$NON-NLS-1$
+
+    /**
+     * Cursor 'source' for the 'off-screen' (detached window) arrow cursor. For cursor construction see:
+     * @see Cursor#Cursor(Device, ImageData, ImageData, int, int)
+     * @since 3.5
+     */
+    public final static String IMG_OBJS_DND_OFFSCREEN_SOURCE = "IMG_OBJS_DND_OFFSCREEN_SOURCE"; //$NON-NLS-1$
+    /**
+     * Cursor 'mask' for the 'off-screen' (detached window) arrow cursor. For cursor construction see:
+     * @see Cursor#Cursor(Device, ImageData, ImageData, int, int)
+     * @since 3.5
+     */
+    public final static String IMG_OBJS_DND_OFFSCREEN_MASK = "IMG_OBJS_DND_OFFSCREEN_MASK"; //$NON-NLS-1$
+
+    /**
+     * Cursor 'source' for the 'fast-view' arrow cursor. For cursor construction see:
+     * @see Cursor#Cursor(Device, ImageData, ImageData, int, int)
+     * @since 3.5
+     */
+    public static final String IMG_OBJS_DND_TOFASTVIEW_SOURCE = "IMG_OBJS_DND_TOFASTVIEW_SOURCE"; //$NON-NLS-1$
+    /**
+     * Cursor 'mask' for the 'fast-view' arrow cursor. For cursor construction see:
+     * @see Cursor#Cursor(Device, ImageData, ImageData, int, int)
+     * @since 3.5
+     */
+    public static final String IMG_OBJS_DND_TOFASTVIEW_MASK = "IMG_OBJS_DND_TOFASTVIEW_MASK"; //$NON-NLS-1$
+
+    /**
+     * Retrieves the specified image from the workbench plugin's image registry.
+     * Note: The returned <code>Image</code> is managed by the workbench; clients
+     * must <b>not</b> dispose of the returned image.
+     *
+     * @param symbolicName the symbolic name of the image; there are constants
+     * declared in this interface for build-in images that come with the workbench
+     * @return the image, or <code>null</code> if not found
+     */
+    public Image getImage(String symbolicName);
+
+    /**
+     * Retrieves the image descriptor for specified image from the workbench's
+     * image registry. Unlike <code>Image</code>s, image descriptors themselves do
+     * not need to be disposed.
+     *
+     * @param symbolicName the symbolic name of the image; there are constants
+     * declared in this interface for build-in images that come with the workbench
+     * @return the image descriptor, or <code>null</code> if not found
+     */
+    public ImageDescriptor getImageDescriptor(String symbolicName);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IShowEditorInput.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IShowEditorInput.java
new file mode 100644
index 0000000..a774196
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IShowEditorInput.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui;
+
+
+/**
+ * Shows the given editor input.  Used when an editor is being opened and an existing
+ * editor's input matches the one being opened.
+ * <p>
+ * Editors can optionally implement this interface, giving the editor the opportunity
+ * to show the given input if it represents a different subset of the editor's content
+ * than the one currently being shown.
+ * </p>
+ *
+ * @since 3.1
+ */
+public interface IShowEditorInput {
+
+    /**
+     * Shows the given input if it represents a different subset of the editor's content
+     * than the one currently being shown.
+     *
+     * @param editorInput the editor input to show
+     */
+    void showEditorInput(IEditorInput editorInput);
+
+}
+
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISizeProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISizeProvider.java
new file mode 100644
index 0000000..2e83bb7
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISizeProvider.java
@@ -0,0 +1,152 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui;
+
+
+/**
+ * Interface implemented by objects that are capable of computing a preferred
+ * size.
+ *
+ * @since 3.1
+ */
+public interface ISizeProvider {
+
+    /**
+     * Constant used to indicate infinite size. This is equal to Integer.MAX_VALUE, ensuring
+     * that it is greater than any other integer.
+     */
+    public static final int INFINITE = Integer.MAX_VALUE;
+
+    /**
+     * Returns a bitwise combination of flags indicating how and when computePreferredSize should
+     * be used. When called with horizontal=true, this indicates the usage of computePreferredSize(true,...)
+     * for computing widths. When called with horizontal=false, this indicates the usage of computeSize(false,...)
+     * for computing heights. These flags are used for optimization. Each flag gives the part more control
+     * over its preferred size but slows down the layout algorithm. Parts should return the minimum set
+     * of flags necessary to specify their constraints.
+     * <p>
+     * If the return value of this function ever changes, the part must call <code>flushLayout</code> before
+     * the changes will take effect.
+     * </p>
+     *
+     * <ul>
+     * <li>SWT.MAX: The part has a maximum size that will be returned by computePreferredSize(horizontal,
+     * 	   INFINITE, someWidth, INFINITE)</li>
+     * <li>SWT.MIN: The part has a minimum size that will be returned by computePreferredSize(horizontal,
+     * 	   INFINITE, someWidth, 0)</li>
+     * <li>SWT.WRAP: Indicates that computePreferredSize makes use of the availablePerpendicular argument. If this
+     * 	   flag is not specified, then the third argument to computePreferredSize will always be set to
+     *     INFINITE. The perpendicular size is expensive to compute, and it is usually only used
+     *     for wrapping parts.
+     * <li>SWT.FILL: The part may not return the preferred size verbatim when computePreferredSize is
+     *     is given a value between the minimum and maximum sizes. This is commonly used if the part
+     *     wants to use a set of predetermined sizes instead of using the workbench-provided size.
+     *     For example, computePreferredSize(horizontal, availableSpace, someWidth,
+     *     preferredSize) may return the nearest predetermined size. Note that this flag should
+     *     be used sparingly. It can prevent layout caching and cause the workbench layout algorithm
+     *     to degrade to exponential worst-case runtime. If this flag is omitted, then
+     *     computePreferredSize may be used to compute the minimum and maximum sizes, but not for
+     *     anything in between.</li>
+     * </ul>
+     *
+     * @param width a value of true or false determines whether the return value applies when computing
+     * widths or heights respectively. That is, getSizeFlags(true) will be used when calling
+     * computePreferredSize(true,...)
+     * @return any bitwise combination of SWT.MAX, SWT.MIN, SWT.WRAP, and SWT.FILL
+     */
+    public int getSizeFlags(boolean width);
+
+    /**
+	 * <p>
+	 * Returns the best size for this part, given the available width and height
+	 * and the workbench's preferred size for the part. Parts can overload this
+	 * to enforce a minimum size, maximum size, or a quantized set of preferred
+	 * sizes. If width == true, this method computes a width in pixels. If width
+	 * == false, this method computes a height. availableParallel and
+	 * availablePerpendicular contain the space available, and preferredParallel
+	 * contains the preferred result.
+	 * </p>
+	 *
+	 * <p>
+	 * This method returns an answer that is less than or equal to
+	 * availableParallel and as close to preferredParallel as possible. Return
+	 * values larger than availableParallel will be truncated.
+	 * </p>
+	 *
+	 * <p>
+	 * Most presentations will define a minimum size at all times, and a maximum
+	 * size that only applies when maximized.
+	 * </p>
+	 *
+	 * <p>
+	 * The getSizeFlags method controls how frequently this method will be
+	 * called and what information will be available when it is. Any subclass
+	 * that specializes this method should also specialize getSizeFlags.
+	 * computePreferredSize(width, INFINITE, someSize, 0) returns the minimum
+	 * size of the control (if any). computePreferredSize(width, INFINITE,
+	 * someSize, INFINITE) returns the maximum size of the control.
+	 * </p>
+	 *
+	 * <p>
+	 * Examples:
+	 * <ul>
+	 * <li>To maintain a constant size of 100x300 pixels: {return width ? 100 :
+	 * 300}, getSizeFlags(boolean) must return SWT.MIN | SWT.MAX</li>
+	 * <li>To grow without constraints: {return preferredResult;},
+	 * getSizeFlags(boolean) must return 0.</li>
+	 * <li>To enforce a width that is always a multiple of 100 pixels, to a
+	 * minimum of 100 pixels: <code>
+	 *        {
+	 *              if (width && preferredResult != INFINITE) {
+	 *                  int result = preferredResult - ((preferredResult + 50) % 100) + 50;
+	 *                  result = Math.max(100, Math.min(result, availableParallel - (availableParallel % 100)));
+	 *
+	 *                  return result;
+	 *              }
+	 *              return preferredResult;
+	 *         }
+	 * 		</code> In this case, getSizeFlags(boolean width) must return (width ?
+	 * SWT.FILL | SWT.MIN: 0)
+	 * </ul>
+	 * <li>To maintain a minimum area of 100000 pixels: <code>
+	 *     {return availablePerpendicular < 100 ? 1000 : 100000 / availablePerpendicular;}
+	 *     </code> getSizeFlags(boolean width) must return SWT.WRAP | SWT.MIN;</li>
+	 * </p>
+	 *
+	 * @param width
+	 *            indicates whether a width (if <code>true</code>) or a height
+	 *            (if <code>false</code>) is being computed
+	 * @param availableParallel
+	 *            available space. This is a width (pixels) if width == true,
+	 *            and a height (pixels) if width == false. A return value larger
+	 *            than this will be ignored.
+	 * @param availablePerpendicular
+	 *            available space perpendicular to the direction being measured
+	 *            or INFINITE if unbounded (pixels). This is a height if width
+	 *            == true, or a height if width == false. Implementations will
+	 *            generally ignore this argument unless they contain wrapping
+	 *            widgets. Note this argument will only contain meaningful
+	 *            information if the part returns the SWT.WRAP flag from
+	 *            getSizeFlags(width)
+	 * @param preferredResult
+	 *            preferred size of the control (pixels, <= availableParallel).
+	 *            Set to INFINITE if unknown or unbounded.
+	 * @return returns the preferred size of the control (pixels). This is a
+	 *         width if width == true or a height if width == false. Callers are
+	 *         responsible for rounding down the return value if it is larger
+	 *         than availableParallel. If availableParallel is INFINITE, then a
+	 *         return value of INFINITE is permitted, indicating that the
+	 *         preferred size of the control is unbounded.
+	 *
+	 * @see ISizeProvider#getSizeFlags(boolean)
+	 */
+    public int computePreferredSize(boolean width, int availableParallel, int availablePerpendicular, int preferredResult);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISourceProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISourceProvider.java
new file mode 100644
index 0000000..425f06c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISourceProvider.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui;
+
+import java.util.Map;
+
+/**
+ * <p>
+ * A provider of notifications for when a change has occurred to a particular
+ * type of source. These providers can be given to the appropriate service, and
+ * this service will then re-evaluate the appropriate pieces of its internal
+ * state in response to these changes.
+ * </p>
+ * <p>
+ * It is recommended that clients subclass <code>AbstractSourceProvider</code>
+ * instead, as this provides some common support for listeners.
+ * </p>
+ *
+ * @since 3.1
+ * @see org.eclipse.ui.handlers.IHandlerService
+ * @see org.eclipse.ui.ISources
+ */
+public interface ISourceProvider {
+
+	/**
+	 * Adds a listener to this source provider. This listener will be notified
+	 * whenever the corresponding source changes.
+	 *
+	 * @param listener
+	 *            The listener to add; must not be <code>null</code>.
+	 */
+	public void addSourceProviderListener(ISourceProviderListener listener);
+
+	/**
+	 * Allows the source provider an opportunity to clean up resources (e.g.,
+	 * listeners) before being released. This method should be called by the
+	 * creator after the source provider has been removed from all the services
+	 * with which it was registered.
+	 */
+	public void dispose();
+
+	/**
+	 * Returns the current state of the sources tracked by this provider. This
+	 * is used to provide a view of the world if the event loop is busy and
+	 * things are some state has already changed.
+	 * <p>
+	 * For use with core expressions, this map should contain
+	 * IEvaluationContext#UNDEFINED_VARIABLE for properties which
+	 * are only sometimes available.
+	 * </p>
+	 *
+	 * @return A map of variable names (<code>String</code>) to variable
+	 *         values (<code>Object</code>). This may be empty, and may be
+	 *         <code>null</code>.
+	 */
+	public Map getCurrentState();
+
+	/**
+	 * Returns the names of those sources provided by this class. This is used
+	 * by clients of source providers to determine which source providers they
+	 * actually need.
+	 *
+	 * @return An array of source names. This value should never be
+	 *         <code>null</code> or empty.
+	 */
+	public String[] getProvidedSourceNames();
+
+	/**
+	 * Removes a listener from this source provider. This listener will be
+	 * notified whenever the corresponding source changes.
+	 *
+	 * @param listener
+	 *            The listener to remove; must not be <code>null</code>.
+	 */
+	public void removeSourceProviderListener(ISourceProviderListener listener);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISourceProviderListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISourceProviderListener.java
new file mode 100644
index 0000000..a640925
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISourceProviderListener.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui;
+
+import java.util.Map;
+
+/**
+ * <p>
+ * A listener to changes in a particular source of information. This listener is
+ * notified as the source changes. Typically, workbench services will implement
+ * this interface, and register themselves as listeners to the
+ * <code>ISourceProvider</code> instances that are registered with them.
+ * </p>
+ *
+ * @since 3.1
+ * @see org.eclipse.ui.ISources
+ * @see org.eclipse.ui.ISourceProvider
+ */
+public interface ISourceProviderListener {
+
+	/**
+	 * Handles a change to multiple sources. The source priority should be a bit
+	 * mask indicating the sources. The map will be used to construct the
+	 * variables on an <code>IEvaluationContext</code>
+	 *
+	 * @param sourcePriority
+	 *            A bit mask of all the source priorities that have changed.
+	 * @param sourceValuesByName
+	 *            A mapping of the source names (<code>String</code>) to the
+	 *            source values (<code>Object</code>). The names should
+	 *            never be <code>null</code>, but the values may be. The map
+	 *            must not be <code>null</code>, and should contain at least
+	 *            two elements (one for each source).
+	 * @see org.eclipse.core.expressions.IEvaluationContext
+	 * @see ISources
+	 */
+	public void sourceChanged(final int sourcePriority,
+			final Map sourceValuesByName);
+
+	/**
+	 * Handles a change to one source. The source priority should indicate the
+	 * source, and the name-value pair will be used to create an
+	 * <code>IEvaluationContext</code> with a single variable.
+	 *
+	 * @param sourcePriority
+	 *            A bit mask of all the source priorities that have changed.
+	 * @param sourceName
+	 *            The name of the source that changed; must not be
+	 *            <code>null</code>.
+	 * @param sourceValue
+	 *            The new value for that source; may be <code>null</code>.
+	 * @see org.eclipse.core.expressions.IEvaluationContext
+	 * @see ISources
+	 */
+	public void sourceChanged(final int sourcePriority,
+			final String sourceName, final Object sourceValue);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISources.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISources.java
new file mode 100644
index 0000000..ba6979c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/ISources.java
@@ -0,0 +1,332 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui;
+
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.ui.part.IShowInSource;
+
+/**
+ * <p>
+ * A source is type of event change that can occur within the workbench. For
+ * example, the active workbench window can change, so it is considered a
+ * source. Workbench services can track changes to these sources, and thereby
+ * try to resolve conflicts between a variety of possible options. This is most
+ * commonly used for things like handlers and contexts.
+ * </p>
+ * <p>
+ * This interface defines the source that are known to the workbench at
+ * compile-time. These sources can be combined in a bit-wise fashion. So, for
+ * example, a <code>ACTIVE_PART | ACTIVE_CONTEXT</code> source includes change
+ * to both the active context and the active part.
+ * </p>
+ * <p>
+ * The values assigned to each source indicates its relative priority. The
+ * higher the value, the more priority the source is given in resolving
+ * conflicts. Another way to look at this is that the higher the value, the more
+ * "local" the source is to what the user is currently doing. This is similar
+ * to, but distinct from the concept of components. The nesting support provided
+ * by components represent only one source (<code>ACTIVE_SITE</code>) that
+ * the workbench understands.
+ * </p>
+ * <p>
+ * Note that for backward compatibility, we must reserve the lowest three bits
+ * for <code>Priority</code> instances using the old
+ * <code>HandlerSubmission</code> mechanism. This mechanism was used in
+ * Eclipse 3.0.
+ * </p>
+ * <p>
+ * <b>Note in 3.3:</b>
+ * </p>
+ * <p>
+ * Currently, source variables are not extensible by user plugins, and
+ * the number of bits available for resolving conflicts is limited.  When
+ * the variable sources become user extensible a new conflict resolution
+ * mechanism will be implemented.
+ * </p>
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noextend This interface is not intended to be extended by clients.
+ *
+ * @see org.eclipse.ui.ISourceProvider
+ * @since 3.1
+ */
+public interface ISources {
+
+	/**
+	 * The priority given to default handlers and handlers that are active
+	 * across the entire workbench.
+	 */
+	public static final int WORKBENCH = 0;
+
+	/**
+	 * The priority given when the activation is defined by a handler submission
+	 * with a legacy priority.
+	 */
+	public static final int LEGACY_LEGACY = 1;
+
+	/**
+	 * The priority given when the activation is defined by a handler submission
+	 * with a low priority.
+	 */
+	public static final int LEGACY_LOW = 1 << 1;
+
+	/**
+	 * The priority given when the activation is defined by a handler submission
+	 * with a medium priority.
+	 */
+	public static final int LEGACY_MEDIUM = 1 << 2;
+
+	/**
+	 * The priority given when the source includes a particular context.
+	 */
+	public static final int ACTIVE_CONTEXT = 1 << 6;
+
+	/**
+	 * The variable name for the active contexts. This is for use with the
+	 * <code>ISourceProvider</code> and <code>IEvaluationContext</code>.
+	 * @since 3.2
+	 */
+	public static final String ACTIVE_CONTEXT_NAME = "activeContexts"; //$NON-NLS-1$
+
+	/**
+	 * The priority given when the source includes a particular action set.
+	 * @since 3.2
+	 */
+	public static final int ACTIVE_ACTION_SETS = 1 << 8;
+
+	/**
+	 * The variable name for the active action sets. This is for use with the
+	 * {@link ISourceProvider} and {@link IEvaluationContext}.
+	 * @since 3.2
+	 */
+	public static final String ACTIVE_ACTION_SETS_NAME = "activeActionSets"; //$NON-NLS-1$
+
+	/**
+	 * The priority given when the source includes the currently active shell.
+	 */
+	public static final int ACTIVE_SHELL = 1 << 10;
+
+	/**
+	 * The variable name for the active shell. This is for use with the
+	 * <code>ISourceProvider</code> and <code>IEvaluationContext</code>.
+	 */
+	public static final String ACTIVE_SHELL_NAME = "activeShell"; //$NON-NLS-1$
+
+	/**
+	 * The priority given when the source includes the currently active
+	 * workbench window shell.
+	 * @since 3.2
+	 */
+	public static final int ACTIVE_WORKBENCH_WINDOW_SHELL = 1 << 12;
+
+	/**
+	 * The variable name for the active workbench window shell. This is for use
+	 * with the <code>ISourceProvider</code> and
+	 * <code>IEvaluationContext</code>.
+	 * @since 3.2
+	 */
+	public static final String ACTIVE_WORKBENCH_WINDOW_SHELL_NAME = "activeWorkbenchWindowShell"; //$NON-NLS-1$
+
+	/**
+	 * The priority given when the source includes the currently active
+	 * workbench window.
+	 */
+	public static final int ACTIVE_WORKBENCH_WINDOW = 1 << 14;
+
+	/**
+	 * The variable name for the active workbench window. This is for use with
+	 * the <code>ISourceProvider</code> and <code>IEvaluationContext</code>.
+	 */
+	public static final String ACTIVE_WORKBENCH_WINDOW_NAME = "activeWorkbenchWindow"; //$NON-NLS-1$
+
+	/**
+	 * The priority given when the source includes subordinate properties of the currently active
+	 * workbench window.
+	 *
+	 * @since 3.3
+	 */
+	public static final int ACTIVE_WORKBENCH_WINDOW_SUBORDINATE = 1 << 15;
+
+	/**
+	 * The variable name for the coolbar visibility state of the active
+	 * workbench window. This is for use with the <code>ISourceProvider</code>
+	 * and <code>IEvaluationContext</code>.
+	 *
+	 * @since 3.3
+	 */
+	public static final String ACTIVE_WORKBENCH_WINDOW_IS_COOLBAR_VISIBLE_NAME = ACTIVE_WORKBENCH_WINDOW_NAME
+			+ ".isCoolbarVisible"; //$NON-NLS-1$
+
+	/**
+	 * The variable name for the perspective bar visibility state of the active
+	 * workbench window. This is for use with the <code>ISourceProvider</code>
+	 * and <code>IEvaluationContext</code>.
+	 *
+	 * @since 3.3
+	 */
+	public static final String ACTIVE_WORKBENCH_WINDOW_IS_PERSPECTIVEBAR_VISIBLE_NAME = ACTIVE_WORKBENCH_WINDOW_NAME
+			+ ".isPerspectiveBarVisible"; //$NON-NLS-1$
+
+	/**
+	 * The variable name for the current perspective of the active workbench
+	 * window. This is for use with the <code>ISourceProvider</code> and
+	 * <code>IEvaluationContext</code>.
+	 *
+	 * @since 3.4
+	 */
+	public static final String ACTIVE_WORKBENCH_WINDOW_ACTIVE_PERSPECTIVE_NAME = ACTIVE_WORKBENCH_WINDOW_NAME
+	+ ".activePerspective"; //$NON-NLS-1$
+
+	/**
+	 * The priority given when the source includes the active editor part.
+	 */
+	public static final int ACTIVE_EDITOR = 1 << 16;
+
+	/**
+	 * The variable name for the active editor part. This is for use with the
+	 * <code>ISourceProvider</code> and <code>IEvaluationContext</code>.
+	 * @since 3.2
+	 */
+	public static final String ACTIVE_EDITOR_NAME = "activeEditor"; //$NON-NLS-1$
+
+	/**
+	 * The editor input of the currently active editor.
+	 * @since 3.5
+	 */
+	public static final String ACTIVE_EDITOR_INPUT_NAME = "activeEditorInput"; //$NON-NLS-1$
+
+	/**
+	 * The priority given when the source includes the active editor identifier.
+	 *
+	 * @since 3.2
+	 */
+	public static final int ACTIVE_EDITOR_ID = 1 << 18;
+
+	/**
+	 * The variable name for the active editor identifier. This is for use with
+	 * the <code>ISourceProvider</code> and <code>IEvaluationContext</code>.
+	 *
+	 * @since 3.2
+	 */
+	public static final String ACTIVE_EDITOR_ID_NAME = "activeEditorId"; //$NON-NLS-1$
+
+	/**
+	 * The priority given when the source includes the active part.
+	 */
+	public static final int ACTIVE_PART = 1 << 20;
+
+	/**
+	 * The variable name for the active part. This is for use with the
+	 * <code>ISourceProvider</code> and <code>IEvaluationContext</code>.
+	 */
+	public static final String ACTIVE_PART_NAME = "activePart"; //$NON-NLS-1$
+
+	/**
+	 * The priority given when the source includes the active part id.
+	 *
+	 * @since 3.2
+	 */
+	public static final int ACTIVE_PART_ID = 1 << 22;
+
+	/**
+	 * The variable name for the active part id. This is for use with the
+	 * <code>ISourceProvider</code> and <code>IEvaluationContext</code>.
+	 *
+	 * @since 3.2
+	 */
+	public static final String ACTIVE_PART_ID_NAME = "activePartId"; //$NON-NLS-1$
+
+	/**
+	 * The priority given when the source includes the active workbench site. In
+	 * the case of nesting components, one should be careful to only activate
+	 * the most nested component.
+	 */
+	public static final int ACTIVE_SITE = 1 << 26;
+
+	/**
+	 * The variable name for the active workbench site. This is for use with the
+	 * <code>ISourceProvider</code> and <code>IEvaluationContext</code>.
+	 */
+	public static final String ACTIVE_SITE_NAME = "activeSite"; //$NON-NLS-1$
+
+	/**
+	 * The variable for the showIn selection.  This is for use with the
+	 * <code>ISourceProvider</code> and <code>IEvaluationContext</code>.
+	 * @since 3.4
+	 * @see IShowInSource
+	 */
+	public static final String SHOW_IN_SELECTION = "showInSelection"; //$NON-NLS-1$
+
+	/**
+	 * The variable for the showIn input.  This is for use with the
+	 * <code>ISourceProvider</code> and <code>IEvaluationContext</code>.
+	 * @since 3.4
+	 * @see IShowInSource
+	 */
+	public static final String SHOW_IN_INPUT = "showInInput"; //$NON-NLS-1$
+
+	/**
+	 * The priority given when the source includes the current selection.
+	 */
+	public static final int ACTIVE_CURRENT_SELECTION = 1 << 30;
+
+	/**
+	 * The variable name for the active selection. This is for use with the
+	 * <code>ISourceProvider</code> and <code>IEvaluationContext</code>.
+	 * @since 3.2
+	 */
+	public static final String ACTIVE_CURRENT_SELECTION_NAME = "selection"; //$NON-NLS-1$
+
+	/**
+	 * The priority given when the source includes the current menu.
+	 * @since 3.2
+	 */
+	public static final int ACTIVE_MENU = 1 << 31;
+
+	/**
+	 * The variable name for the active menu. This is for use with the
+	 * {@link ISourceProvider} and {@link IEvaluationContext}.
+	 * @since 3.2
+	 */
+	public static final String ACTIVE_MENU_NAME = "activeMenu"; //$NON-NLS-1$
+
+	/**
+	 * The variable name for the <b>local</b> selection, available while a
+	 * context menu is visible.
+	 *
+	 * @since 3.3
+	 */
+	public static final String ACTIVE_MENU_SELECTION_NAME = "activeMenuSelection";  //$NON-NLS-1$
+
+	/**
+	 * The variable name for the <b>local</b> editor input which is sometimes
+	 * available while a context menu is visible.
+	 *
+	 * @since 3.3
+	 */
+	public static final String ACTIVE_MENU_EDITOR_INPUT_NAME = "activeMenuEditorInput";  //$NON-NLS-1$
+
+	/**
+	 * The variable name for the active focus Control, when provided by the
+	 * IFocusService.
+	 *
+	 * @since 3.3
+	 */
+	public static final String ACTIVE_FOCUS_CONTROL_NAME = "activeFocusControl"; //$NON-NLS-1$
+
+	/**
+	 * The variable name for the active focus Control id, when provided by the
+	 * IFocusService.
+	 *
+	 * @since 3.3
+	 */
+	public static final String ACTIVE_FOCUS_CONTROL_ID_NAME = "activeFocusControlId"; //$NON-NLS-1$
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IStartup.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IStartup.java
new file mode 100644
index 0000000..909adb3
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IStartup.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+/**
+ * Plug-ins that register a startup extension will be activated after
+ * the Workbench initializes and have an opportunity to run
+ * code that can't be implemented using the normal contribution
+ * mechanisms.
+ *
+ * @since 2.0
+ */
+public interface IStartup {
+    /**
+     * Will be called in a separate thread after the workbench initializes.
+     * <p>
+     * Note that most workbench methods must be called in the UI thread
+     * since they may access SWT.  For example, to obtain the current workbench
+     * window, use:
+     * <code>
+     * <pre>
+     * final IWorkbench workbench = PlatformUI.getWorkbench();
+     * workbench.getDisplay().asyncExec(new Runnable() {
+     *   public void run() {
+     *     IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
+     *     if (window != null) {
+     *       // do something
+     *     }
+     *   }
+     * });
+     * </pre>
+     * </code>
+     * </p>
+     * @see org.eclipse.swt.widgets.Display#asyncExec
+     * @see org.eclipse.swt.widgets.Display#syncExec
+     */
+    public void earlyStartup();
+}
+
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IViewActionDelegate.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IViewActionDelegate.java
new file mode 100644
index 0000000..be1206b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IViewActionDelegate.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 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.ui;
+
+/**
+ * Interface for an action that is contributed into a view's local tool bar,
+ * pulldown menu, or popup menu. It extends <code>IActionDelegate</code>
+ * and adds an initialization method for connecting the delegate to the view it
+ * should work with.
+ */
+public interface IViewActionDelegate extends IActionDelegate {
+    /**
+     * Initializes this action delegate with the view it will work in.
+     *
+     * @param view the view that provides the context for this delegate
+     */
+    public void init(IViewPart view);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IViewLayout.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IViewLayout.java
new file mode 100644
index 0000000..22897d7
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IViewLayout.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui;
+
+/**
+ * Represents the layout info for a view or placeholder in an {@link IPageLayout}.
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IViewLayout {
+
+    /**
+     * Returns whether the view is closeable.
+     * The default is <code>true</code>.
+     *
+     * @return <code>true</code> if the view is closeable, <code>false</code> if not
+     */
+    public boolean isCloseable();
+
+    /**
+     * Sets whether the view is closeable.
+     *
+     * @param closeable <code>true</code> if the view is closeable, <code>false</code> if not
+     */
+    public void setCloseable(boolean closeable);
+
+    /**
+     * Returns whether the view is moveable.
+     * The default is <code>true</code>.
+     *
+     * @return <code>true</code> if the view is moveable, <code>false</code> if not
+     */
+    public boolean isMoveable();
+
+    /**
+     * Sets whether the view is moveable.
+     *
+     * @param moveable <code>true</code> if the view is moveable, <code>false</code> if not
+     */
+    public void setMoveable(boolean moveable);
+
+    /**
+     * Returns whether the view is a standalone view.
+     *
+     * @see IPageLayout#addStandaloneView
+     */
+    public boolean isStandalone();
+
+    /**
+     * Returns whether the view shows its title.
+     * This is only applicable to standalone views.
+     *
+     * @see IPageLayout#addStandaloneView
+     */
+    public boolean getShowTitle();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IViewPart.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IViewPart.java
new file mode 100644
index 0000000..8c86b37
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IViewPart.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+
+/**
+ * A view is a visual component within a workbench page. It is typically used to
+ * navigate a hierarchy of information (like the workspace), open an editor, or
+ * display properties for the active editor. Modifications made in a view are
+ * saved immediately (in contrast to an editor part, which conforms to a more
+ * elaborate open-save-close lifecycle).
+ * <p>
+ * Only one instance of a particular view type may exist within a workbench
+ * page. This policy is designed to simplify part management for a user.
+ * </p>
+ * <p>
+ * This interface may be implemented directly. For convenience, a base
+ * implementation is defined in <code>ViewPart</code>.
+ * </p>
+ * <p>
+ * A view is added to the workbench in two steps:
+ * <ol>
+ * <li>A view extension is contributed to the workbench registry. This
+ * extension defines the extension id and extension class.</li>
+ * <li>The view is included in the default layout for a perspective.
+ * Alternatively, the user may open the view from the Perspective menu.</li>
+ * </ol>
+ * </p>
+ * <p>
+ * Views implement the <code>IAdaptable</code> interface; extensions are
+ * managed by the platform's adapter manager.
+ * </p>
+ * <p>
+ * As of 3.4, views may optionally adapt to {@link ISizeProvider} if they have
+ * a preferred size. The default presentation will make a best effort to
+ * allocate the preferred size to a view if it is the only part in a stack. If
+ * there is more than one part in the stack, the constraints will be disabled
+ * for that stack. The size constraints are adjusted for the size of the tab and
+ * border trim. Note that this is considered to be a hint to the presentation,
+ * and not all presentations may honor size constraints.
+ * </p>
+ *
+ * @see IWorkbenchPage#showView
+ * @see org.eclipse.ui.part.ViewPart
+ * @see ISizeProvider
+ */
+public interface IViewPart extends IWorkbenchPart, IPersistable {
+    /**
+     * Returns the site for this view.
+     * This method is equivalent to <code>(IViewSite) getSite()</code>.
+     * <p>
+     * The site can be <code>null</code> while the view is being initialized.
+     * After the initialization is complete, this value must be non-<code>null</code>
+     * for the remainder of the view's life cycle.
+     * </p>
+     *
+     * @return the view site; this value may be <code>null</code> if the view
+     *         has not yet been initialized
+     */
+    public IViewSite getViewSite();
+
+    /**
+     * Initializes this view with the given view site.
+     * <p>
+     * This method is automatically called by the workbench shortly after the
+     * part is instantiated.  It marks the start of the views's lifecycle. Clients must
+     * not call this method.
+     * </p>
+     *
+     * @param site the view site
+     * @exception PartInitException if this view was not initialized successfully
+     */
+    public void init(IViewSite site) throws PartInitException;
+
+    /**
+     * Initializes this view with the given view site.  A memento is passed to
+     * the view which contains a snapshot of the views state from a previous
+     * session.  Where possible, the view should try to recreate that state
+     * within the part controls.
+     * <p>
+     * This method is automatically called by the workbench shortly after the part
+     * is instantiated.  It marks the start of the views's lifecycle. Clients must
+     * not call this method.
+     * </p>
+     *
+     * @param site the view site
+     * @param memento the IViewPart state or null if there is no previous saved state
+     * @exception PartInitException if this view was not initialized successfully
+     */
+    public void init(IViewSite site, IMemento memento) throws PartInitException;
+
+    /**
+     * Saves the object state within a memento.
+     *
+     * @param memento a memento to receive the object state
+     */
+    @Override
+	public void saveState(IMemento memento);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IViewReference.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IViewReference.java
new file mode 100644
index 0000000..d538589
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IViewReference.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+/**
+ * Defines a reference to an IViewPart.
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IViewReference extends IWorkbenchPartReference {
+
+    /**
+     * Returns the secondary ID for the view.
+     *
+     * @return the secondary ID, or <code>null</code> if there is no secondary id
+     * @see IWorkbenchPage#showView(String, String, int)
+     * @since 3.0
+     */
+    public String getSecondaryId();
+
+    /**
+     * Returns the <code>IViewPart</code> referenced by this object.
+     * Returns <code>null</code> if the view was not instantiated or
+     * it failed to be restored.  Tries to restore the view
+     * if <code>restore</code> is true.
+     */
+    public IViewPart getView(boolean restore);
+
+    /**
+     * Returns true if the view is a fast view otherwise returns false.
+     */
+    public boolean isFastView();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IViewSite.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IViewSite.java
new file mode 100644
index 0000000..6298ff4
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IViewSite.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+/**
+ * The primary interface between a view part and the workbench.
+ * <p>
+ * The workbench exposes its implemention of view part sites via this interface,
+ * which is not intended to be implemented or extended by clients.
+ * </p>
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IViewSite extends IWorkbenchPartSite {
+
+    /**
+     * Returns the action bars for this part site.
+     * Views have exclusive use of their site's action bars.
+     *
+     * @return the action bars
+     */
+    public IActionBars getActionBars();
+
+	/**
+	 * Returns the secondary id for this part site's part, or <code>null</code>
+	 * if it has none.
+	 *
+	 * @return the secondary id for this part site's part or <code>null</code>
+	 *         if it has none
+	 * @see IWorkbenchPage#showView(String, String, int)
+	 * @since 3.0
+	 */
+    public String getSecondaryId();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWindowListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWindowListener.java
new file mode 100644
index 0000000..051c5f8
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWindowListener.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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.ui;
+
+/**
+ * Interface for listening to window lifecycle events.
+ * <p>
+ * This interface may be implemented by clients.
+ * </p>
+ */
+public interface IWindowListener {
+    /**
+     * Notifies this listener that the given window has been activated.
+     * <p>
+     * <b>Note:</b> This event is not fired if no perspective is
+     * open (the window is empty).
+     * </p>
+     *
+     * @param window the window that was activated
+     */
+    public void windowActivated(IWorkbenchWindow window);
+
+    /**
+     * Notifies this listener that the given window has been deactivated.
+     * <p>
+     * <b>Note:</b> This event is not fired if no perspective is
+     * open (the window is empty).
+     * </p>
+     *
+     * @param window the window that was activated
+     */
+    public void windowDeactivated(IWorkbenchWindow window);
+
+    /**
+     * Notifies this listener that the given window has been closed.
+     *
+     * @param window the window that was closed
+     * @see IWorkbenchWindow#close
+     */
+    public void windowClosed(IWorkbenchWindow window);
+
+    /**
+     * Notifies this listener that the given window has been opened.
+     *
+     * @param window the window that was opened
+     * @see IWorkbench#openWorkbenchWindow
+     */
+    public void windowOpened(IWorkbenchWindow window);
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbench.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbench.java
new file mode 100644
index 0000000..cb9048e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbench.java
@@ -0,0 +1,668 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
+import org.eclipse.jface.operation.IRunnableContext;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.PreferenceManager;
+import org.eclipse.jface.window.IShellProvider;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.activities.IWorkbenchActivitySupport;
+import org.eclipse.ui.browser.IWorkbenchBrowserSupport;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.commands.IWorkbenchCommandSupport;
+import org.eclipse.ui.contexts.IContextService;
+import org.eclipse.ui.contexts.IWorkbenchContextSupport;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.help.IWorkbenchHelpSystem;
+import org.eclipse.ui.intro.IIntroManager;
+import org.eclipse.ui.keys.IBindingService;
+import org.eclipse.ui.operations.IWorkbenchOperationSupport;
+import org.eclipse.ui.progress.IProgressService;
+import org.eclipse.ui.services.IServiceLocator;
+import org.eclipse.ui.themes.IThemeManager;
+import org.eclipse.ui.views.IViewRegistry;
+import org.eclipse.ui.wizards.IWizardRegistry;
+
+/**
+ * A workbench is the root object for the Eclipse Platform user interface.
+ * <p>
+ * A <b>workbench</b> has one or more main windows which present to the end
+ * user information based on some underlying model, typically on resources in an
+ * underlying workspace. A workbench usually starts with a single open window,
+ * and automatically closes when its last window closes.
+ * </p>
+ * <p>
+ * Each <b>workbench window</b> has a collection of <b>pages</b>; the active
+ * page is the one that is being presented to the end user; at most one page is
+ * active in a window at a time.
+ * </p>
+ * <p>
+ * Each workbench page has a collection of <b>workbench parts</b>, of which
+ * there are two kinds: views and editors. A page's parts are arranged (tiled or
+ * stacked) for presentation on the screen. The arrangement is not fixed; the
+ * user can arrange the parts as they see fit. A <b>perspective</b> is a
+ * template for a page, capturing a collection of parts and their arrangement.
+ * </p>
+ * <p>
+ * The platform creates a workbench when the workbench plug-in is activated;
+ * since this happens at most once during the life of the running platform,
+ * there is only one workbench instance. Due to its singular nature, it is
+ * commonly referred to as <it>the</it> workbench.
+ * </p>
+ * <p>
+ * The workbench supports a few {@link IServiceLocator services} by default. If
+ * these services are used to allocate resources, it is important to remember to
+ * clean up those resources after you are done with them. Otherwise, the
+ * resources will exist until the workbench shuts down. The supported services
+ * are:
+ * </p>
+ * <ul>
+ * <li>{@link IBindingService}</li>
+ * <li>{@link ICommandService}</li>
+ * <li>{@link IContextService}</li>
+ * <li>{@link IHandlerService}</li>
+ * </ul>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ *
+ * @see org.eclipse.ui.PlatformUI#getWorkbench
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IWorkbench extends IAdaptable, IServiceLocator {
+	/**
+	 * Returns the display for this workbench.
+	 * <p>
+	 * Code should always ask the workbench for the display rather than rely on
+	 * {@link Display#getDefault Display.getDefault()}.
+	 * </p>
+	 *
+	 * @return the display to be used for all UI interactions with this
+	 *         workbench
+	 * @since 3.0
+	 */
+	public Display getDisplay();
+
+	/**
+	 * Returns the progress service for the workbench.
+	 *
+	 * @return the progress service
+	 * @since 3.0
+	 */
+	public IProgressService getProgressService();
+
+	/**
+	 * Adds a workbench listener.
+	 *
+	 * @param listener
+	 *            the workbench listener to add
+	 * @since 3.2
+	 */
+	public void addWorkbenchListener(IWorkbenchListener listener);
+
+	/**
+	 * Removes a workbench listener.
+	 *
+	 * @param listener
+	 *            the workbench listener to remove
+	 * @since 3.2
+	 */
+	public void removeWorkbenchListener(IWorkbenchListener listener);
+
+	/**
+	 * Adds a window listener.
+	 *
+	 * @param listener
+	 *            the window listener to add
+	 * @since 2.0
+	 */
+	public void addWindowListener(IWindowListener listener);
+
+	/**
+	 * Removes a window listener.
+	 *
+	 * @param listener
+	 *            the window listener to remove
+	 * @since 2.0
+	 */
+	public void removeWindowListener(IWindowListener listener);
+
+	/**
+	 * Closes this workbench and all its open windows.
+	 * <p>
+	 * If the workbench has an open editor with unsaved content, the user will
+	 * be given the opportunity to save it.
+	 * </p>
+	 *
+	 * @return <code>true</code> if the workbench was successfully closed, and
+	 *         <code>false</code> if it is still open
+	 */
+	public boolean close();
+
+	/**
+	 * Returns the currently active window for this workbench (if any). Returns
+	 * <code>null</code> if there is no active workbench window. Returns
+	 * <code>null</code> if called from a non-UI thread.
+	 *
+	 * @return the active workbench window, or <code>null</code> if there is
+	 *         no active workbench window or if called from a non-UI thread
+	 */
+	public IWorkbenchWindow getActiveWorkbenchWindow();
+
+	/**
+	 * Returns the editor registry for the workbench.
+	 *
+	 * @return the workbench editor registry
+	 */
+	public IEditorRegistry getEditorRegistry();
+
+	/**
+	 * <p>
+	 * Returns the undoable operation support for the workbench.
+	 * </p>
+	 *
+	 * @return the workbench operation support
+	 *
+	 * @since 3.1
+	 */
+	public IWorkbenchOperationSupport getOperationSupport();
+
+	/**
+	 * Returns the perspective registry for the workbench.
+	 *
+	 * @return the workbench perspective registry
+	 */
+	public IPerspectiveRegistry getPerspectiveRegistry();
+
+	/**
+	 * Returns the preference manager for the workbench.
+	 *
+	 * @return the workbench preference manager
+	 */
+	public PreferenceManager getPreferenceManager();
+
+	/**
+	 * Returns the preference store for the workbench.
+	 *
+	 * @return the workbench preference store
+	 * @since 2.0
+	 * @deprecated this returns the internal preference store for the workbench,
+	 *             which clients should not use. Use
+	 *             {@link PlatformUI#getPreferenceStore()} instead. Note that
+	 *             these preference stores are not the same. If you were
+	 *             previously storing preferences in the store returned by this
+	 *             method you should move them to your own plugin preference
+	 *             store.
+	 */
+	@Deprecated
+	public IPreferenceStore getPreferenceStore();
+
+	/**
+	 * Returns the shared images for the workbench.
+	 *
+	 * @return the shared image manager
+	 */
+	public ISharedImages getSharedImages();
+
+	/**
+	 * Returns the number of open main windows associated with this workbench.
+	 * Note that wizards and dialogs are not included in this list since they
+	 * are not considered main windows.
+	 *
+	 * @return the number of open windows
+	 * @since 3.0
+	 */
+	public int getWorkbenchWindowCount();
+
+	/**
+	 * Returns a list of the open main windows associated with this workbench.
+	 * Note that wizards and dialogs are not included in this list since they
+	 * are not considered main windows.
+	 *
+	 * @return a list of open windows
+	 */
+	public IWorkbenchWindow[] getWorkbenchWindows();
+
+	/**
+	 * Returns the working set manager for the workbench.
+	 *
+	 * @return the working set manager
+	 * @since 2.0
+	 */
+	public IWorkingSetManager getWorkingSetManager();
+
+	/**
+	 * Creates a new local working set manager. Clients of local working set
+	 * managers are responsible for calling {@link IWorkingSetManager#dispose()}
+	 * when the working sets it manages are no longer needed.
+	 *
+	 * @return the local working set manager
+	 * @since 3.1
+	 */
+	public ILocalWorkingSetManager createLocalWorkingSetManager();
+
+	/**
+	 * Creates and opens a new workbench window with one page. The perspective
+	 * of the new page is defined by the specified perspective ID. The new
+	 * window and new page become active.
+	 * <p>
+	 * <b>Note:</b> The caller is responsible to ensure the action using this
+	 * method will explicitly inform the user a new window will be opened.
+	 * Otherwise, callers are strongly recommended to use the
+	 * <code>openPerspective</code> APIs to programmatically show a
+	 * perspective to avoid confusing the user.
+	 * </p>
+	 * <p>
+	 * In most cases where this method is used the caller is tightly coupled to
+	 * a particular perspective. They define it in the registry and contribute
+	 * some user interface action to open or activate it. In situations like
+	 * this a static variable is often used to identify the perspective ID.
+	 * </p>
+	 *
+	 * @param perspectiveId
+	 *            the perspective id for the window's initial page, or
+	 *            <code>null</code> for no initial page
+	 * @param input
+	 *            the page input, or <code>null</code> if there is no current
+	 *            input. This is used to seed the input for the new page's
+	 *            views.
+	 * @return the new workbench window
+	 * @exception WorkbenchException
+	 *                if a new window and page could not be opened
+	 *
+	 * @see IWorkbench#showPerspective(String, IWorkbenchWindow, IAdaptable)
+	 */
+	public IWorkbenchWindow openWorkbenchWindow(String perspectiveId,
+			IAdaptable input) throws WorkbenchException;
+
+	/**
+	 * Creates and opens a new workbench window with one page. The perspective
+	 * of the new page is defined by the default perspective ID. The new window
+	 * and new page become active.
+	 * <p>
+	 * <b>Note:</b> The caller is responsible to ensure the action using this
+	 * method will explicitly inform the user a new window will be opened.
+	 * Otherwise, callers are strongly recommended to use the
+	 * <code>openPerspective</code> APIs to programmatically show a
+	 * perspective to avoid confusing the user.
+	 * </p>
+	 *
+	 * @param input
+	 *            the page input, or <code>null</code> if there is no current
+	 *            input. This is used to seed the input for the new page's
+	 *            views.
+	 * @return the new workbench window
+	 * @exception WorkbenchException
+	 *                if a new window and page could not be opened
+	 *
+	 * @see IWorkbench#showPerspective(String, IWorkbenchWindow, IAdaptable)
+	 */
+	public IWorkbenchWindow openWorkbenchWindow(IAdaptable input)
+			throws WorkbenchException;
+
+	/**
+	 * Closes then restarts the workbench with the same command line as used for
+	 * the previous launch.
+	 * <p>
+	 * If the workbench has an open editor with unsaved content, the user will
+	 * be given the opportunity to save it.
+	 * </p>
+	 *
+	 * @return <code>true</code> if the workbench was successfully closed, and
+	 *         <code>false</code> if it could not be closed
+	 *
+	 * @since 2.0
+	 */
+	public boolean restart();
+
+	/**
+	 * Closes then restarts this workbench using the current workspace if
+	 * <code>useCurrentWorkspace</code> is <code>true</code>. Otherwise, works
+	 * as {@link IWorkbench#restart()}.
+	 * <p>
+	 * If the workbench has an open editor with unsaved content, the user will
+	 * be given the opportunity to save it.
+	 * </p>
+	 *
+	 * @param useCurrentWorkspace
+	 *            <code>true</code> to use the current workspace while
+	 *            restarting this workbench, and <code>false</code> to restart
+	 *            the workbench with the same command line as used for the
+	 *            previous launch
+	 *
+	 * @return <code>true</code> if the workbench was successfully closed, and
+	 *         <code>false</code> if it could not be closed
+	 *
+	 * @since 3.107
+	 */
+	public boolean restart(boolean useCurrentWorkspace);
+
+	/**
+	 * Shows the specified perspective to the user. The caller should use this
+	 * method when the perspective to be shown is not dependent on the page's
+	 * input. That is, the perspective can open in any page depending on user
+	 * preferences.
+	 * <p>
+	 * The perspective may be shown in the specified window, in another existing
+	 * window, or in a new window depending on user preferences. The exact
+	 * policy is controlled by the workbench to ensure consistency to the user.
+	 * The policy is subject to change. The current policy is as follows:
+	 * <ul>
+	 * <li>If the specified window has the requested perspective open, then the
+	 * window is given focus and the perspective is shown. The page's input is
+	 * ignored.</li>
+	 * <li>If another window that has the workspace root as input and the
+	 * requested perspective open and active, then the window is given focus.
+	 * </li>
+	 * <li>Otherwise the requested perspective is opened and shown in the
+	 * specified window or in a new window depending on the current user
+	 * preference for opening perspectives, and that window is given focus.
+	 * </li>
+	 * </ul>
+	 * </p>
+	 * <p>
+	 * The workbench also defines a number of menu items to activate or open
+	 * each registered perspective. A complete list of these perspectives is
+	 * available from the perspective registry found on <code>IWorkbench</code>.
+	 * </p>
+	 *
+	 * @param perspectiveId
+	 *            the perspective ID to show
+	 * @param window
+	 *            the workbench window of the action calling this method.
+	 * @return the workbench page that the perspective was shown
+	 * @exception WorkbenchException
+	 *                if the perspective could not be shown
+	 *
+	 * @since 2.0
+	 */
+	public IWorkbenchPage showPerspective(String perspectiveId,
+			IWorkbenchWindow window) throws WorkbenchException;
+
+	/**
+	 * Shows the specified perspective to the user. The caller should use this
+	 * method when the perspective to be shown is dependent on the page's input.
+	 * That is, the perspective can only open in any page with the specified
+	 * input.
+	 * <p>
+	 * The perspective may be shown in the specified window, in another existing
+	 * window, or in a new window depending on user preferences. The exact
+	 * policy is controlled by the workbench to ensure consistency to the user.
+	 * The policy is subject to change. The current policy is as follows:
+	 * <ul>
+	 * <li>If the specified window has the requested perspective open and the
+	 * same requested input, then the window is given focus and the perspective
+	 * is shown.</li>
+	 * <li>If another window has the requested input and the requested
+	 * perspective open and active, then that window is given focus.</li>
+	 * <li>If the specified window has the same requested input but not the
+	 * requested perspective, then the window is given focus and the perspective
+	 * is opened and shown on condition that the user preference is not to open
+	 * perspectives in a new window.</li>
+	 * <li>Otherwise the requested perspective is opened and shown in a new
+	 * window, and the window is given focus.</li>
+	 * </ul>
+	 * </p>
+	 * <p>
+	 * The workbench also defines a number of menu items to activate or open
+	 * each registered perspective. A complete list of these perspectives is
+	 * available from the perspective registry found on <code>IWorkbench</code>.
+	 * </p>
+	 *
+	 * @param perspectiveId
+	 *            the perspective ID to show
+	 * @param window
+	 *            the workbench window of the action calling this method.
+	 * @param input
+	 *            the page input, or <code>null</code> if there is no current
+	 *            input. This is used to seed the input for the page's views
+	 * @return the workbench page that the perspective was shown
+	 * @exception WorkbenchException
+	 *                if the perspective could not be shown
+	 *
+	 * @since 2.0
+	 */
+	public IWorkbenchPage showPerspective(String perspectiveId,
+			IWorkbenchWindow window, IAdaptable input)
+			throws WorkbenchException;
+
+	/**
+	 * Returns the decorator manager.
+	 * <p>
+	 * Any client using the decorator manager should come up with the text and
+	 * image for the element (including any of the part's own decorations)
+	 * before calling the decorator manager. It should also add a listener to be
+	 * notified when decorations change.
+	 * </p>
+	 * <p>
+	 * Note that if the element implements <code>IAdaptable</code>,
+	 * decorators may use this mechanism to obtain an adapter (for example an
+	 * <code>IResource</code>), and derive the decoration from the adapter
+	 * rather than the element. Since the adapter may differ from the original
+	 * element, those using the decorator manager should be prepared to handle
+	 * notification that the decoration for the adapter has changed, in addition
+	 * to handling notification that the decoration for the element has changed.
+	 * That is, it needs to be able to map back from the adapter to the element.
+	 * </p>
+	 *
+	 * @return the decorator manager
+	 */
+	public IDecoratorManager getDecoratorManager();
+
+	/**
+	 * Save all dirty editors in the workbench. Opens a dialog to prompt the
+	 * user if <code>confirm</code> is true. Return true if successful. Return
+	 * false if the user has canceled the command.
+	 *
+	 * @param confirm <code>true</code> to ask the user before saving unsaved
+	 *            changes (recommended), and <code>false</code> to save
+	 *            unsaved changes without asking
+	 * @return <code>true</code> if the command succeeded, and
+	 *         <code>false</code> if the operation was canceled by the user or
+	 *         an error occurred while saving
+	 */
+	public boolean saveAllEditors(boolean confirm);
+
+	/**
+	 * Returns the element factory with the given id.
+	 *
+	 * @param factoryId
+	 *            the id of the element factory
+	 * @return the element factory, or <code>null</code> if none
+	 * @see IElementFactory
+	 * @since 3.0
+	 */
+	public IElementFactory getElementFactory(String factoryId);
+
+	/**
+	 * Returns an interface to manage activities at the workbench level.
+	 *
+	 * @return an interface to manage activities at the workbench level.
+	 *         Guaranteed not to be <code>null</code>.
+	 * @since 3.0
+	 */
+	IWorkbenchActivitySupport getActivitySupport();
+
+	/**
+	 * Returns an interface to manage commands at the workbench level.
+	 *
+	 * @return an interface to manage commands at the workbench level.
+	 *         Guaranteed not to be <code>null</code>.
+	 * @since 3.0
+	 * @deprecated Please use {@link IServiceLocator#getService(Class)} instead.
+	 * @see ICommandService
+	 * @see IHandlerService
+	 */
+	@Deprecated
+	IWorkbenchCommandSupport getCommandSupport();
+
+	/**
+	 * Returns an interface to manage contexts at the workbench level.
+	 *
+	 * @return an interface to manage contexts at the workbench level.
+	 *         Guaranteed not to be <code>null</code>.
+	 * @since 3.0
+	 * @deprecated Please use {@link IServiceLocator#getService(Class)} instead.
+	 * @see IContextService
+	 */
+	@Deprecated
+	IWorkbenchContextSupport getContextSupport();
+
+	/**
+	 * Return the theme manager for this workbench.
+	 *
+	 * @return the theme manager for this workbench.Guaranteed not to be
+	 *         <code>null</code>.
+	 * @since 3.0
+	 */
+	public IThemeManager getThemeManager();
+
+	/**
+	 * Return the intro manager for this workbench.
+	 *
+	 * @return the intro manager for this workbench. Guaranteed not to be
+	 *         <code>null</code>.
+	 * @since 3.0
+	 */
+	public IIntroManager getIntroManager();
+
+	/**
+	 * Return the help system for this workbench.
+	 *
+	 * @return the help system
+	 * @since 3.1
+	 */
+	public IWorkbenchHelpSystem getHelpSystem();
+
+	/**
+	 * Return the browser support for this workbench.
+	 *
+	 * @return the browser support system
+	 * @since 3.1
+	 */
+	public IWorkbenchBrowserSupport getBrowserSupport();
+
+	/**
+	 * Returns a boolean indicating whether the workbench is in the process of
+	 * starting. During this phase, it is not safe to make calls to other
+	 * methods of the workbench, or of objects owned by the workbench. To delay
+	 * work until after the workbench has been initialized, use {@link IStartup}
+	 * or {@link Display#asyncExec(Runnable)}.
+	 *
+	 * @return <code>true</code> if the workbench is in the process of starting,
+	 *         <code>false</code> otherwise
+	 * @since 3.5
+	 */
+	public boolean isStarting();
+
+	/**
+	 * Returns a boolean indicating whether the workbench is in the process of
+	 * closing.
+	 *
+	 * @return <code>true</code> if the workbench is in the process of
+	 *         closing, <code>false</code> otherwise
+	 * @since 3.1
+	 */
+	public boolean isClosing();
+
+	/**
+	 * <p>
+	 * Return the extension tracker for the workbench. This tracker may be used
+	 * by plug-ins to ensure responsiveness to changes to the plug-in registry.
+	 * </p>
+	 * <p>
+	 * The tracker at this level of the workbench is typically used to track
+	 * elements that persist for the life of the workbench. For example,
+	 * <code>IEditorDescriptor</code> objects fall into this category.
+	 * </p>
+	 *
+	 * @return the extension tracker
+	 * @see IWorkbenchWindow#getExtensionTracker()
+	 * @see IWorkbenchPage#getExtensionTracker()
+	 * @since 3.1
+	 */
+	public IExtensionTracker getExtensionTracker();
+
+	/**
+	 * Returns the view registry for the workbench.
+	 *
+	 * @return the workbench view registry
+	 * @since 3.1
+	 */
+	public IViewRegistry getViewRegistry();
+
+	/**
+	 * Return the new wizard registry.
+	 *
+	 * @return the new wizard registry
+	 * @since 3.1
+	 */
+	public IWizardRegistry getNewWizardRegistry();
+
+	/**
+	 * Return the import wizard registry.
+	 *
+	 * @return the import wizard registry
+	 * @since 3.1
+	 */
+	public IWizardRegistry getImportWizardRegistry();
+
+	/**
+	 * Return the export wizard registry.
+	 *
+	 * @return the export wizard registry
+	 * @since 3.1
+	 */
+	public IWizardRegistry getExportWizardRegistry();
+
+	/**
+	 * Save all dirty saveables in the workbench that match the given filter.
+	 * Opens a dialog to prompt the user if <code>confirm</code> is true.
+	 * Return true if successful. Return false if the user has canceled the
+	 * command.
+	 *
+	 * @since 3.3
+	 *
+	 * @param shellProvider the provider used to obtain a shell in prompting is
+	 *            required. Clients can use a workbench window for this.
+	 * @param runnableContext a runnable context that will be used to provide a
+	 *            progress monitor while the save is taking place. Clients can
+	 *            use a workbench window for this.
+	 * @param filter the filter used to determine if a particular dirty saveable
+	 *            needs to be saved or <code>null</code> if all dirty
+	 *            saveables should be saved.
+	 * @param confirm <code>true</code> to ask the user before saving unsaved
+	 *            changes (recommended), and <code>false</code> to save
+	 *            unsaved changes without asking
+	 * @return <code>true</code> if the command succeeded, and
+	 *         <code>false</code> if the operation was canceled by the user or
+	 *         an error occurred while saving
+	 */
+	public boolean saveAll(IShellProvider shellProvider,
+			IRunnableContext runnableContext, ISaveableFilter filter,
+			boolean confirm);
+
+	/**
+	 * Return a shell provider that can be used to get the best parenting
+	 * possible for a modal dialog. If modal shells are already created, use the
+	 * topmost modal shell as the parent to avoid two modal dialogs. If there
+	 * are no modal shells, use the shell of the active workbench window.
+	 *
+	 * @return a shell provider that provides the best parenting possible for a
+	 *         modal dialog.
+	 *
+	 * @since 3.6
+	 */
+	public IShellProvider getModalDialogShellProvider();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchActionConstants.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchActionConstants.java
new file mode 100644
index 0000000..7f23614
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchActionConstants.java
@@ -0,0 +1,927 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810, 440975, 431862
+ *******************************************************************************/
+package org.eclipse.ui;
+
+/**
+ * Action ids for standard actions, groups in the workbench menu bar, and
+ * global actions.
+ * <p>
+ * This interface contains constants only; it is not intended to be implemented
+ * or extended.
+ * </p>
+ * <h3>Standard menus</h3>
+ * <ul>
+ *   <li>File menu (<code>M_FILE</code>)</li>
+ *   <li>Edit menu (<code>M_EDIT</code>)</li>
+ *   <li>Window menu (<code>M_WINDOW</code>)</li>
+ *   <li>Help menu (<code>M_HELP</code>)</li>
+ * </ul>
+ * <h3>Standard group for adding top level menus</h3>
+ * <ul>
+ *   <li>Extra top level menu group (<code>MB_ADDITIONS</code>)</li>
+ * </ul>
+ * <h3>Global actions</h3>
+ * <ul>
+ *   <li>Undo (<code>UNDO</code>)</li>
+ *   <li>Redo (<code>REDO</code>)</li>
+ *   <li>Cut (<code>CUT</code>)</li>
+ *   <li>Copy (<code>COPY</code>)</li>
+ *   <li>Paste (<code>PASTE</code>)</li>
+ *   <li>Delete (<code>DELETE</code>)</li>
+ *   <li>Find (<code>FIND</code>)</li>
+ *   <li>Select All (<code>SELECT_ALL</code>)</li>
+ *   <li>Add Bookmark (<code>BOOKMARK</code>)</li>
+ * </ul>
+ * <h3>Standard File menu actions</h3>
+ * <ul>
+ *   <li>Start group (<code>FILE_START</code>)</li>
+ *   <li>End group (<code>FILE_END</code>)</li>
+ *   <li>New action (<code>NEW</code>)</li>
+ *   <li>Extra New-like action group (<code>NEW_EXT</code>)</li>
+ *   <li>Close action (<code>CLOSE</code>)</li>
+ *   <li>Close All action (<code>CLOSE_ALL</code>)</li>
+ *   <li>Extra Close-like action group (<code>CLOSE_EXT</code>)</li>
+ *   <li>Save action (<code>SAVE</code>)</li>
+ *   <li>Save As action (<code>SAVE_AS</code>)</li>
+ *   <li>Save All action (<code>SAVE_ALL</code>)</li>
+ *   <li>Extra Save-like action group (<code>SAVE_EXT</code>)</li>
+ *   <li>Import action (<code>IMPORT</code>)</li>
+ *   <li>Export action (<code>EXPORT</code>)</li>
+ *   <li>Extra Import-like action group (<code>IMPORT_EXT</code>)</li>
+ *   <li>Quit action (<code>QUIT</code>)</li>
+ * </ul>
+ * <h3>Standard Edit menu actions</h3>
+ * <ul>
+ *   <li>Start group (<code>EDIT_START</code>)</li>
+ *   <li>End group (<code>EDIT_END</code>)</li>
+ *   <li>Undo global action (<code>UNDO</code>)</li>
+ *   <li>Redo global action (<code>REDO</code>)</li>
+ *   <li>Extra Undo-like action group (<code>UNDO_EXT</code>)</li>
+ *   <li>Cut global action (<code>CUT</code>)</li>
+ *   <li>Copy global action (<code>COPY</code>)</li>
+ *   <li>Paste global action (<code>PASTE</code>)</li>
+ *   <li>Extra Cut-like action group (<code>CUT_EXT</code>)</li>
+ *   <li>Delete global action (<code>DELETE</code>)</li>
+ *   <li>Find global action (<code>FIND</code>)</li>
+ *   <li>Select All global action (<code>SELECT_ALL</code>)</li>
+ *   <li>Bookmark global action (<code>BOOKMARK</code>)</li>
+ * </ul>
+ * <h3>Standard Perspective menu actions</h3>
+ * <ul>
+ *   <li>Extra Perspective-like action group (<code>VIEW_EXT</code>)</li>
+ * </ul>
+ * <h3>Standard Workbench menu actions</h3>
+ * <ul>
+ *   <li>Start group (<code>WB_START</code>)</li>
+ *   <li>End group (<code>WB_END</code>)</li>
+ *   <li>Extra Build-like action group (<code>BUILD_EXT</code>)</li>
+ *   <li>Build action (<code>BUILD</code>)</li>
+ *   <li>Rebuild All action (<code>REBUILD_ALL</code>)</li>
+ * </ul>
+ * <h3>Standard Window menu actions</h3>
+ * <ul>
+ *   <li>Extra Window-like action group (<code>WINDOW_EXT</code>)</li>
+ * </ul>
+ * <h3>Standard Help menu actions</h3>
+ * <ul>
+ *   <li>Start group (<code>HELP_START</code>)</li>
+ *   <li>End group (<code>HELP_END</code>)</li>
+ *   <li>About action (<code>ABOUT</code>)</li>
+ * </ul>
+ * <h3>Standard pop-up menu groups</h3>
+ * <ul>
+ *   <li>Managing group (<code>GROUP_MANAGING</code>)</li>
+ *   <li>Reorganize group (<code>GROUP_REORGANIZE</code>)</li>
+ *   <li>Add group (<code>GROUP_ADD</code>)</li>
+ *   <li>File group (<code>GROUP_FILE</code>)</li>
+ * </ul>
+ * <p>
+ * To hook a global action handler, a view should use the following code:
+ * <code>
+ *   IAction copyHandler = ...;
+ *   view.getSite().getActionBars().setGlobalActionHandler(
+ *       IWorkbenchActionConstants.COPY,
+ *       copyHandler);
+ * </code>
+ * For editors, this should be done in the <code>IEditorActionBarContributor</code>.
+ * </p>
+ *
+ * @see org.eclipse.ui.IActionBars#setGlobalActionHandler
+ *
+ * Note: many of the remaining non-deprecated constants here are IDE-specific
+ *   and should be deprecated and moved to a constant pool at the IDE layer
+ *   (e.g. IIDEActionConstants).
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noextend This interface is not intended to be extended by clients.
+ */
+public interface IWorkbenchActionConstants {
+
+    // Standard menus:
+    /**
+     * <p>
+     * [Issue: MENU_PREFIX is "". It is used to prefix some of the other
+     * constants. There doesn't seem to be much point for this.
+     * Recommend deleting it.
+     * ]
+     * </p>
+     */
+    public static final String MENU_PREFIX = ""; //$NON-NLS-1$
+
+    /**
+     * <p>
+     * [Issue: SEP is "/". It is not used anywhere. Recommend deleting it.]
+     * </p>
+     */
+    public static final String SEP = "/"; //$NON-NLS-1$
+
+    /**
+     * Name of standard File menu (value <code>"file"</code>).
+     */
+    public static final String M_FILE = MENU_PREFIX + "file"; //$NON-NLS-1$
+
+    /**
+     * Name of standard Edit menu (value <code>"edit"</code>).
+     */
+    public static final String M_EDIT = MENU_PREFIX + "edit"; //$NON-NLS-1$
+
+    /**
+     * Name of standard View menu (value <code>"view"</code>).
+     * @deprecated Since 3.0.  This is no longer used.
+     */
+    @Deprecated
+	public static final String M_VIEW = MENU_PREFIX + "view"; //$NON-NLS-1$
+
+    /**
+     * Name of standard Workbench menu (value <code>"workbench"</code>).
+     * @deprecated Since 3.0.  This is no longer used.
+     */
+    @Deprecated
+	public static final String M_WORKBENCH = MENU_PREFIX + "workbench"; //$NON-NLS-1$
+
+    // menu reorg
+
+	/**
+	 * Name of standard Perspective menu (value <code>"perspective"</code>).
+	 *
+	 * @since 3.107
+	 */
+   public static final String M_PERSPECTIVE = MENU_PREFIX + "perspective"; //$NON-NLS-1$
+
+    /**
+     * Name of standard Navigate menu (value <code>"navigate"</code>).
+     */
+    public static final String M_NAVIGATE = MENU_PREFIX + "navigate"; //$NON-NLS-1$
+
+    /**
+     * Name of standard Project menu (value <code>"project"</code>).
+     */
+    public static final String M_PROJECT = MENU_PREFIX + "project"; //$NON-NLS-1$
+
+    // end menu reorg
+
+    /**
+     * Name of standard Window menu (value <code>"window"</code>).
+     */
+    public static final String M_WINDOW = MENU_PREFIX + "window"; //$NON-NLS-1$
+
+    /**
+     * Name of Launch window menu (value <code>"launch"</code>).
+     */
+    public static final String M_LAUNCH = MENU_PREFIX + "launch"; //$NON-NLS-1$
+
+    /**
+     * Name of standard Help menu (value <code>"help"</code>).
+     */
+    public static final String M_HELP = MENU_PREFIX + "help"; //$NON-NLS-1$
+
+    /**
+     * ID of the Project configure popup menu, can be used in
+     * menuContributions and objectContributions.
+     *
+     * @since 3.5
+     */
+    public static final String M_PROJECT_CONFIGURE = "org.eclipse.ui.projectConfigure"; //$NON-NLS-1$
+
+    // Standard area for adding top level menus:
+    /**
+     * Name of group for adding new top-level menus (value <code>"additions"</code>).
+     */
+    public static final String MB_ADDITIONS = "additions"; // Group. //$NON-NLS-1$
+
+    // Standard file actions:
+    /**
+     * File menu: name of group for start of menu (value <code>"fileStart"</code>).
+     */
+    public static final String FILE_START = "fileStart"; // Group. //$NON-NLS-1$
+
+    /**
+     * File menu: name of group for end of menu (value <code>"fileEnd"</code>).
+     */
+    public static final String FILE_END = "fileEnd"; // Group. //$NON-NLS-1$
+
+    /**
+     * File menu: name of standard New action (value <code>"new"</code>).
+     *
+     * @deprecated in 3.0. Use
+     * <code>org.eclipse.ui.ActionFactory.NEW.getId()</code>
+     * instead.
+     */
+    @Deprecated
+	public static final String NEW = "new"; //$NON-NLS-1$
+
+    /**
+     * File menu: name of group for extra New-like actions (value <code>"new.ext"</code>).
+     */
+    public static final String NEW_EXT = "new.ext"; // Group. //$NON-NLS-1$
+
+    /**
+     * File menu: name of standard Close action (value <code>"close"</code>).
+     *
+     * @deprecated in 3.0. Use {@link org.eclipse.ui.actions.ActionFactory#CLOSE
+     * ActionFactory.CLOSE.getId()} instead.
+     */
+    @Deprecated
+	public static final String CLOSE = "close"; //$NON-NLS-1$
+
+    /**
+     * File menu: name of standard Close All action (value <code>"closeAll"</code>).
+     *
+     * @deprecated in 3.0. Use {@link org.eclipse.ui.actions.ActionFactory#CLOSE_ALL
+     * ActionFactory.CLOSE_ALL.getId()} instead.
+     */
+    @Deprecated
+	public static final String CLOSE_ALL = "closeAll"; //$NON-NLS-1$
+
+    /**
+     * File menu: name of group for extra Close-like actions (value <code>"close.ext"</code>).
+     */
+    public static final String CLOSE_EXT = "close.ext"; // Group. //$NON-NLS-1$
+
+    /**
+     * File menu: name of standard Save action (value <code>"save"</code>).
+     *
+     * @deprecated in 3.0. Use {@link org.eclipse.ui.actions.ActionFactory#SAVE
+     * ActionFactory.SAVE.getId()} instead.
+     */
+    @Deprecated
+	public static final String SAVE = "save"; //$NON-NLS-1$
+
+    /**
+     * File menu: name of standard Save As action (value <code>"saveAs"</code>).
+     *
+     * @deprecated in 3.0. Use {@link org.eclipse.ui.actions.ActionFactory#SAVE_AS
+     * ActionFactory.SAVE_AS.getId()} instead.
+     */
+    @Deprecated
+	public static final String SAVE_AS = "saveAs"; //$NON-NLS-1$
+
+    /**
+     * File menu: name of standard Save All action (value <code>"saveAll"</code>).
+     *
+     * @deprecated in 3.0. Use {@link org.eclipse.ui.actions.ActionFactory#SAVE_ALL
+     * ActionFactory.SAVE_ALL.getId()} instead.
+     */
+    @Deprecated
+	public static final String SAVE_ALL = "saveAll"; //$NON-NLS-1$
+
+    /**
+     * File menu: name of group for extra Save-like actions (value <code>"save.ext"</code>).
+     */
+    public static final String SAVE_EXT = "save.ext"; // Group. //$NON-NLS-1$
+
+    /**
+     * File menu: name of standard Print global action
+     * (value <code>"print"</code>).
+     *
+     * @deprecated in 3.0. Use {@link org.eclipse.ui.actions.ActionFactory#PRINT
+     * ActionFactory.PRINT.getId()} instead.
+     */
+    @Deprecated
+	public static final String PRINT = "print"; // Global action. //$NON-NLS-1$
+
+    /**
+     * File menu: name of group for extra Print-like actions (value <code>"print.ext"</code>).
+     * @since 3.0
+     */
+    public static final String PRINT_EXT = "print.ext"; // Group. //$NON-NLS-1$
+
+    /**
+     * File menu: name of standard Import action (value <code>"import"</code>).
+     *
+     * @deprecated in 3.0. Use
+     * <code>org.eclipse.ui.ActionFactory.IMPORT.getId()</code>
+     * instead.
+     */
+    @Deprecated
+	public static final String IMPORT = "import"; //$NON-NLS-1$
+
+    /**
+     * File menu: name of standard Export action (value <code>"export"</code>).
+     *
+     * @deprecated in 3.0. Use
+     * <code>org.eclipse.ui.ActionFactory.EXPORT.getId()</code>
+     * instead.
+     */
+    @Deprecated
+	public static final String EXPORT = "export"; //$NON-NLS-1$
+
+    /**
+     * File menu: name of group for extra Import-like actions (value <code>"import.ext"</code>).
+     */
+    public static final String IMPORT_EXT = "import.ext"; // Group. //$NON-NLS-1$
+
+    /**
+     * File menu: name of "Most Recently Used File" group.
+     * (value <code>"mru"</code>).
+     */
+    public static final String MRU = "mru"; //$NON-NLS-1$
+
+    /**
+     * File menu: name of standard Quit action (value <code>"quit"</code>).
+     *
+     * @deprecated in 3.0. Use {@link org.eclipse.ui.actions.ActionFactory#QUIT
+     * ActionFactory.QUIT.getId()} instead.
+     */
+    @Deprecated
+	public static final String QUIT = "quit"; //$NON-NLS-1$
+
+    // Standard edit actions:
+    /**
+     * Edit menu: name of group for start of menu (value <code>"editStart"</code>).
+     */
+    public static final String EDIT_START = "editStart"; // Group. //$NON-NLS-1$
+
+    /**
+     * Edit menu: name of group for end of menu (value <code>"editEnd"</code>).
+     */
+    public static final String EDIT_END = "editEnd"; // Group. //$NON-NLS-1$
+
+    /**
+     * Edit menu: name of standard Undo global action
+     * (value <code>"undo"</code>).
+     *
+     * @deprecated in 3.0. Use {@link org.eclipse.ui.actions.ActionFactory#UNDO
+     * ActionFactory.UNDO.getId()} instead.
+     */
+    @Deprecated
+	public static final String UNDO = "undo"; // Global action. //$NON-NLS-1$
+
+    /**
+     * Edit menu: name of standard Redo global action
+     * (value <code>"redo"</code>).
+     *
+     * @deprecated in 3.0. Use {@link org.eclipse.ui.actions.ActionFactory#REDO
+     * ActionFactory.REDO.getId()} instead.
+     */
+    @Deprecated
+	public static final String REDO = "redo"; // Global action. //$NON-NLS-1$
+
+    /**
+     * Edit menu: name of group for extra Undo-like actions (value <code>"undo.ext"</code>).
+     */
+    public static final String UNDO_EXT = "undo.ext"; // Group. //$NON-NLS-1$
+
+    /**
+     * Edit menu: name of standard Cut global action
+     * (value <code>"cut"</code>).
+     *
+     * @deprecated in 3.0. Use {@link org.eclipse.ui.actions.ActionFactory#CUT
+     * ActionFactory.CUT.getId()} instead.
+     */
+    @Deprecated
+	public static final String CUT = "cut"; // Global action. //$NON-NLS-1$
+
+    /**
+     * Edit menu: name of standard Copy global action
+     * (value <code>"copy"</code>).
+     *
+     * @deprecated in 3.0. Use {@link org.eclipse.ui.actions.ActionFactory#COPY
+     * ActionFactory.COPY.getId()} instead.
+     */
+    @Deprecated
+	public static final String COPY = "copy"; // Global action. //$NON-NLS-1$
+
+    /**
+     * Edit menu: name of standard Paste global action
+     * (value <code>"paste"</code>).
+     *
+     * @deprecated in 3.0. Use {@link org.eclipse.ui.actions.ActionFactory#PASTE
+     * ActionFactory.PASTE.getId()} instead.
+     */
+    @Deprecated
+	public static final String PASTE = "paste"; // Global action. //$NON-NLS-1$
+
+    /**
+     * Edit menu: name of group for extra Cut-like actions (value <code>"cut.ext"</code>).
+     */
+    public static final String CUT_EXT = "cut.ext"; // Group. //$NON-NLS-1$
+
+    /**
+     * Edit menu: name of standard Delete global action
+     * (value <code>"delete"</code>).
+     *
+     * @deprecated in 3.0. Use {@link org.eclipse.ui.actions.ActionFactory#DELETE
+     * ActionFactory.DELETE.getId()} instead.
+     */
+    @Deprecated
+	public static final String DELETE = "delete"; // Global action. //$NON-NLS-1$
+
+    /**
+     * Edit menu: name of standard Find global action
+     * (value <code>"find"</code>).
+     *
+     * @deprecated in 3.0. Use {@link org.eclipse.ui.actions.ActionFactory#FIND
+     * ActionFactory.FIND.getId()} instead.
+     */
+    @Deprecated
+	public static final String FIND = "find"; // Global action. //$NON-NLS-1$
+
+    /**
+     * Edit menu: name of group for extra Find-like actions (value <code>"find.ext"</code>).
+     */
+    public static final String FIND_EXT = "find.ext"; // Group. //$NON-NLS-1$
+
+    /**
+     * Edit menu: name of standard Select All global action
+     * (value <code>"selectAll"</code>).
+     *
+     * @deprecated in 3.0. Use {@link org.eclipse.ui.actions.ActionFactory#SELECT_ALL
+     * ActionFactory.SELECT_ALL.getId()} instead.
+     */
+    @Deprecated
+	public static final String SELECT_ALL = "selectAll"; // Global action. //$NON-NLS-1$
+
+    /**
+     * Edit menu: name of standard Add Bookmark global action
+     * (value <code>"bookmark"</code>).
+     *
+     * @deprecated in 3.0. Use
+     * <code>org.eclipse.ui.ide.IDEActionFactory.BOOKMARK.getId()</code>
+     * instead.
+     */
+    @Deprecated
+	public static final String BOOKMARK = "bookmark"; // Global action. //$NON-NLS-1$
+
+    /**
+     * Edit menu: name of standard Add Task global action
+     * (value <code>"addTask"</code>).
+     *
+     * @deprecated in 3.0. Use
+     * <code>org.eclipse.ui.ide.IDEActionFactory.ADD_TASK.getId()</code>
+     * instead.
+     */
+    @Deprecated
+	public static final String ADD_TASK = "addTask"; // Global action. //$NON-NLS-1$
+
+    /**
+     * Edit menu: name of group for extra Add-like actions (value <code>"add.ext"</code>).
+     */
+    public static final String ADD_EXT = "add.ext"; // Group. //$NON-NLS-1$
+
+    // Standard workbench actions:
+    /**
+     * Workbench menu: name of group for start of menu
+     * (value <code>"wbStart"</code>).
+     */
+    public static final String WB_START = "wbStart"; // Group. //$NON-NLS-1$
+
+    /**
+     * Workbench menu: name of group for end of menu
+     * (value <code>"wbEnd"</code>).
+     */
+    public static final String WB_END = "wbEnd"; // Group. //$NON-NLS-1$
+
+    /**
+     * Workbench menu: name of group for extra Build-like actions
+     * (value <code>"build.ext"</code>).
+     */
+    public static final String BUILD_EXT = "build.ext"; // Group. //$NON-NLS-1$
+
+    /**
+     * Workbench menu: name of standard Build action
+     * (value <code>"build"</code>).
+     *
+     * @deprecated in 3.0. Use
+     * <code>org.eclipse.ui.ide.IDEActionFactory.BUILD.getId()</code>
+     * instead.
+     */
+    @Deprecated
+	public static final String BUILD = "build"; //$NON-NLS-1$
+
+    /**
+     * Workbench menu: name of standard Rebuild All action
+     * (value <code>"rebuildAll"</code>).
+     *
+     * @deprecated in 3.0. Use
+     * <code>org.eclipse.ui.ide.IDEActionFactory.REBUILD_ALL.getId()</code>
+     * instead.
+     */
+    @Deprecated
+	public static final String REBUILD_ALL = "rebuildAll"; //$NON-NLS-1$
+
+    // Workbench toolbar ids:
+    /**
+     * Workbench toolbar id for file toolbar group.
+     *
+     * @since 2.1
+     */
+    public static final String TOOLBAR_FILE = "org.eclipse.ui.workbench.file"; //$NON-NLS-1$
+
+    /**
+     * Workbench toolbar id for navigate toolbar group.
+     *
+     * @since 2.1
+     */
+    public static final String TOOLBAR_NAVIGATE = "org.eclipse.ui.workbench.navigate"; //$NON-NLS-1$
+
+    /**
+     * Workbench toolbar id for help toolbar group.
+     *
+     * @since 3.1
+     */
+    public static final String TOOLBAR_HELP = "org.eclipse.ui.workbench.help"; //$NON-NLS-1$
+
+    // Workbench toolbar group ids.  To add an item at the beginning of the group,
+    // use the GROUP id.  To add an item at the end of the group, use the EXT id.
+
+    /**
+     * Group id for pin toolbar group.
+     *
+     * @since 2.1
+     */
+    public static final String PIN_GROUP = "pin.group"; //$NON-NLS-1$
+
+    /**
+     * Group id for history toolbar group.
+     *
+     * @since 2.1
+     */
+    public static final String HISTORY_GROUP = "history.group"; //$NON-NLS-1$
+
+    /**
+     * Group id for new toolbar group.
+     *
+     * @since 2.1
+     */
+    public static final String NEW_GROUP = "new.group"; //$NON-NLS-1$
+
+    /**
+     * Group id for save group.
+     *
+     * @since 2.1
+     */
+    public static final String SAVE_GROUP = "save.group"; //$NON-NLS-1$
+
+    /**
+     * Group id for build group.
+     *
+     * @since 2.1
+     */
+    public static final String BUILD_GROUP = "build.group"; //$NON-NLS-1$
+
+    // Pop-up menu groups:
+    /**
+     * Pop-up menu: name of group for Managing actions (value <code>"group.managing"</code>).
+     */
+    public static final String GROUP_MANAGING = "group.managing"; //$NON-NLS-1$
+
+    /**
+     * Pop-up menu: name of group for Reorganize actions (value <code>"group.reorganize"</code>).
+     */
+    public static final String GROUP_REORGANIZE = "group.reorganize"; //$NON-NLS-1$
+
+    /**
+     * Pop-up menu: name of group for Add actions (value <code>"group.add"</code>).
+     */
+    public static final String GROUP_ADD = "group.add"; //$NON-NLS-1$
+
+    /**
+     * Pop-up menu: name of group for File actions (value <code>"group.file"</code>).
+     */
+    public static final String GROUP_FILE = "group.file"; //$NON-NLS-1$
+
+    /**
+     * Pop-up menu: name of group for Show In actions (value <code>"group.showIn"</code>).
+     *
+     * @since 2.1
+     */
+    public static final String GROUP_SHOW_IN = "group.showIn"; //$NON-NLS-1$
+
+    /**
+     * Coolbar: name of group for application created actions
+     *
+     * @since 3.0
+     */
+    public static final String GROUP_APP = "group.application"; //$NON-NLS-1$
+
+    /**
+     * Toolbar: name of group for editor action bars.
+     */
+    public static final String GROUP_EDITOR = "group.editor"; //$NON-NLS-1$
+
+    /**
+     * Coolbar: name of group for help actions and contributions
+     *
+     * @since 3.1
+     */
+    public static final String GROUP_HELP = "group.help"; //$NON-NLS-1$
+
+    // Standard view actions:
+    /**
+     * View menu: name of group for additional view-like items.
+     * (value <code>"additions"</code>).
+     */
+    public static final String VIEW_EXT = MB_ADDITIONS; // Group.
+
+    // Standard window actions:
+    /**
+     * Window menu: name of group for additional window-like items.
+     * (value <code>"additions"</code>).
+     */
+    public static final String WINDOW_EXT = MB_ADDITIONS; // Group.
+
+    /**
+     * Launch menu: name of group for launching additional windows.
+     * (value <code>"additions"</code>).
+     */
+    public static final String LAUNCH_EXT = MB_ADDITIONS; // Group.
+
+    // menu reorg
+    /**
+     * File menu: name of standard Revert global action
+     * (value <code>"revert"</code>).
+     *
+     * @deprecated in 3.0. Use {@link org.eclipse.ui.actions.ActionFactory#REVERT
+     * ActionFactory.REVERT.getId()} instead.
+     */
+    @Deprecated
+	public static final String REVERT = "revert"; // Global action. //$NON-NLS-1$
+
+    /**
+     * File menu: name of standard Refresh global action
+     * (value <code>"refresh"</code>).
+     *
+     * @deprecated in 3.0. Use {@link org.eclipse.ui.actions.ActionFactory#REFRESH
+     * ActionFactory.REFRESH.getId()} instead.
+     */
+    @Deprecated
+	public static final String REFRESH = "refresh"; // Global action. //$NON-NLS-1$
+
+    /**
+     * File menu: name of standard Properties global action
+     * (value <code>"properties"</code>).
+     *
+     * @deprecated in 3.0. Use {@link org.eclipse.ui.actions.ActionFactory#PROPERTIES
+     * ActionFactory.PROPERTIES.getId()} instead.
+     */
+    @Deprecated
+	public static final String PROPERTIES = "properties"; // Global action. //$NON-NLS-1$
+
+    /**
+     * Edit menu: name of standard Move global action
+     * (value <code>"move"</code>).
+     *
+     * @deprecated in 3.0. Use {@link org.eclipse.ui.actions.ActionFactory#MOVE
+     * ActionFactory.MOVE.getId()} instead.
+     */
+    @Deprecated
+	public static final String MOVE = "move"; // Global action. //$NON-NLS-1$
+
+    /**
+     * Edit menu: name of standard Rename global action
+     * (value <code>"rename"</code>).
+     *
+     * @deprecated in 3.0. Use {@link org.eclipse.ui.actions.ActionFactory#RENAME
+     * ActionFactory.RENAME.getId()} instead.
+     */
+    @Deprecated
+	public static final String RENAME = "rename"; // Global action. //$NON-NLS-1$
+
+    /**
+     * Edit menu: name of standard Add Task global action
+     * (value <code>"addTask"</code>).
+     */
+    //	public static final String ADD_TASK = "addTask";	// Global action. //$NON-NLS-1$
+
+	/**
+	 * Perspective menu: name of group for start of menu (value
+	 * <code>"perspectiveStart"</code>).
+	 *
+	 * @since 3.107
+	 */
+	public static final String PERSPECTIVE_START = "perspectiveStart"; // Group. //$NON-NLS-1$
+
+	/**
+	 * Perspective menu: name of group for end of menu (value
+	 * <code>"perspectiveStartEnd"</code> ).
+	 *
+	 * @since 3.107
+	 */
+	public static final String PERSPECTIVE_END = "perspectiveStartEnd"; // Group. //$NON-NLS-1$
+
+    /**
+     * Navigate menu: name of group for start of menu
+     * (value <code>"navStart"</code>).
+     */
+    public static final String NAV_START = "navStart"; // Group. //$NON-NLS-1$
+
+    /**
+     * Navigate menu: name of group for end of menu
+     * (value <code>"navEnd"</code>).
+     */
+    public static final String NAV_END = "navEnd"; // Group. //$NON-NLS-1$
+
+    /**
+     * File and Navigate menu: name of group for extra Open actions
+     * (value <code>"open.ext"</code>).
+     */
+    public static final String OPEN_EXT = "open.ext"; // Group. //$NON-NLS-1$
+
+    /**
+     * Navigate menu: name of group for extra Show actions
+     * (value <code>"show.ext"</code>).
+     */
+    public static final String SHOW_EXT = "show.ext"; // Group. //$NON-NLS-1$
+
+    /**
+     * Navigate menu: name of standard Go Into global action
+     * (value <code>"goInto"</code>).
+     */
+    public static final String GO_INTO = "goInto"; // Global action. //$NON-NLS-1$
+
+    /**
+     * Navigate menu: name of standard Go To submenu
+     * (value <code>"goTo"</code>).
+     */
+    public static final String GO_TO = "goTo"; //$NON-NLS-1$
+
+    /**
+     * Navigate menu: name of standard Go To Resource global action
+     * (value <code>"goToResource"</code>).
+     */
+    public static final String GO_TO_RESOURCE = "goToResource"; // Global action. //$NON-NLS-1$
+
+    /**
+     * Navigate menu: name of standard Sync With Editor global action (value
+     * <code>"syncEditor"</code>).
+     *
+     * @deprecated this action will be removed soon; use SHOW_IN instead
+     */
+    @Deprecated
+	public static final String SYNC_EDITOR = "syncEditor"; // Global action. //$NON-NLS-1$
+
+    /**
+     * Navigate menu: name of standard Show In... action
+     * (value <code>"showIn"</code>).
+     *
+     * @since 2.1
+     *
+     * @deprecated
+     */
+    @Deprecated
+	public static final String SHOW_IN = "showIn"; //$NON-NLS-1$
+
+    /**
+     * Navigate menu: name of standard Back global action
+     * (value <code>"back"</code>).
+     *
+     * @deprecated in 3.0. Use {@link org.eclipse.ui.actions.ActionFactory#BACK
+     * ActionFactory.BACK.getId()} instead.
+     */
+    @Deprecated
+	public static final String BACK = "back"; // Global action. //$NON-NLS-1$
+
+    /**
+     * Navigate menu: name of standard Forward global action
+     * (value <code>"forward"</code>).
+     *
+     * @deprecated in 3.0. Use {@link org.eclipse.ui.actions.ActionFactory#FORWARD
+     * ActionFactory.FORWARD.getId()} instead.
+     */
+    @Deprecated
+	public static final String FORWARD = "forward"; // Global action. //$NON-NLS-1$
+
+    /**
+     * Navigate menu: name of standard Up global action
+     * (value <code>"up"</code>).
+     */
+    public static final String UP = "up"; // Global action. //$NON-NLS-1$
+
+    /**
+     * Navigate menu: name of standard Next global action
+     * (value <code>"next"</code>).
+     *
+     * @deprecated in 3.0. Use {@link org.eclipse.ui.actions.ActionFactory#NEXT
+     * ActionFactory.NEXT.getId()} instead.
+     */
+    @Deprecated
+	public static final String NEXT = "next"; // Global action. //$NON-NLS-1$
+
+    /**
+     * Navigate menu: name of standard Up global action
+     * (value <code>"previous"</code>).
+     *
+     * @deprecated in 3.0. Use {@link org.eclipse.ui.actions.ActionFactory#PREVIOUS
+     * ActionFactory.PREVIOUS.getId()} instead.
+     */
+    @Deprecated
+	public static final String PREVIOUS = "previous"; // Global action. //$NON-NLS-1$
+
+    /**
+     * Project menu: name of group for start of menu
+     * (value <code>"projStart"</code>).
+     */
+    public static final String PROJ_START = "projStart"; // Group. //$NON-NLS-1$
+
+    /**
+     * Project menu: name of group for start of menu
+     * (value <code>"projEnd"</code>).
+     */
+    public static final String PROJ_END = "projEnd"; // Group. //$NON-NLS-1$
+
+    /**
+     * Project menu: name of standard Build Project global action
+     * (value <code>"buildProject"</code>).
+     *
+     * @deprecated in 3.0. Use
+     * <code>org.eclipse.ui.ide.IDEActionFactory.BUILD_PROJECT.getId()</code>
+     * instead.
+     */
+    @Deprecated
+	public static final String BUILD_PROJECT = "buildProject"; // Global action. //$NON-NLS-1$
+
+    /**
+     * Project menu: name of standard Rebuild Project global action
+     * (value <code>"rebuildProject"</code>).
+     *
+     * @deprecated in 3.0. Use
+     * <code>org.eclipse.ui.ide.IDEActionFactory.REBUILD_PROJECT.getId()</code>
+     * instead.
+     */
+    @Deprecated
+	public static final String REBUILD_PROJECT = "rebuildProject"; // Global action. //$NON-NLS-1$
+
+    /**
+     * Project menu: name of standard Open Project global action
+     * (value <code>"openProject"</code>).
+     *
+     * @deprecated in 3.0. Use
+     * <code>org.eclipse.ui.ide.IDEActionFactory.OPEN_PROJECT.getId()</code>
+     * instead.
+     */
+    @Deprecated
+	public static final String OPEN_PROJECT = "openProject"; // Global action. //$NON-NLS-1$
+
+    /**
+     * Project menu: name of standard Close Project global action
+     * (value <code>"closeProject"</code>).
+     *
+     * @deprecated in 3.0. Use
+     * <code>org.eclipse.ui.ide.IDEActionFactory.CLOSE_PROJECT.getId()</code>
+     * instead.
+     */
+    @Deprecated
+	public static final String CLOSE_PROJECT = "closeProject"; // Global action. //$NON-NLS-1$
+    // end menu reorg
+
+    // Standard help actions:
+    /**
+     * Help menu: name of group for start of menu
+     * (value <code>"helpStart"</code>).
+     */
+    public static final String HELP_START = "helpStart"; // Group. //$NON-NLS-1$
+
+    /**
+     * Help menu: name of group for end of menu
+     * (value <code>"helpEnd"</code>).
+     */
+    public static final String HELP_END = "helpEnd"; // Group. //$NON-NLS-1$
+
+    /**
+     * Help menu: name of standard About action
+     * (value <code>"about"</code>).
+     *
+     * @deprecated in 3.0. Use {@link org.eclipse.ui.actions.ActionFactory#ABOUT
+     * ActionFactory.ABOUT.getId()} instead.
+     */
+    @Deprecated
+	public static final String ABOUT = "about"; //$NON-NLS-1$
+
+    /**
+     * Standard global actions in a workbench window.
+     *
+     * @deprecated in 3.0
+     */
+    @Deprecated
+	public static final String[] GLOBAL_ACTIONS = { UNDO, REDO, CUT, COPY,
+            PASTE, PRINT, DELETE, FIND, SELECT_ALL, BOOKMARK };
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchCommandConstants.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchCommandConstants.java
new file mode 100644
index 0000000..6f777fb
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchCommandConstants.java
@@ -0,0 +1,614 @@
+/*******************************************************************************
+ * Copyright (c) 2009-2015 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:
+ *     Marc R. Hoffmann <hoffmann@mountainminds.com>
+ *         - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ui;
+
+/**
+ * Constants for all commands defined by the Eclipse workbench.
+ *
+ * @since 3.5
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IWorkbenchCommandConstants {
+
+    // File Category:
+
+    /**
+     * Id for command "New" in category "File"
+     * (value is <code>"org.eclipse.ui.newWizard"</code>).
+     */
+    public static final String FILE_NEW = "org.eclipse.ui.newWizard"; //$NON-NLS-1$
+
+	/**
+	 * Id for parameter "New Wizard" in command "New" in category "File" (value
+	 * is <code>"newWizardId"</code>). Optional.
+	 *
+	 * @since 3.6
+	 */
+	public static final String FILE_NEW_PARM_WIZARDID = "newWizardId"; //$NON-NLS-1$
+
+	/**
+	 * Id for command "Close" in category "File" (value is
+	 * <code>"org.eclipse.ui.file.close"</code>).
+	 */
+    public static final String FILE_CLOSE = "org.eclipse.ui.file.close"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Close All" in category "File"
+     * (value is <code>"org.eclipse.ui.file.closeAll"</code>).
+     */
+    public static final String FILE_CLOSE_ALL = "org.eclipse.ui.file.closeAll"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Import" in category "File"
+     * (value is <code>"org.eclipse.ui.file.import"</code>).
+     */
+    public static final String FILE_IMPORT = "org.eclipse.ui.file.import"; //$NON-NLS-1$
+
+	/**
+	 * Id for parameter "Import Wizard" in command "Import" in category "File"
+	 * (value is <code>"importWizardId"</code>). Optional.
+	 *
+	 * @since 3.6
+	 */
+	public static final String FILE_IMPORT_PARM_WIZARDID = "importWizardId"; //$NON-NLS-1$
+
+	/**
+	 * Id for command "Export" in category "File" (value is
+	 * <code>"org.eclipse.ui.file.export"</code>).
+	 */
+    public static final String FILE_EXPORT = "org.eclipse.ui.file.export"; //$NON-NLS-1$
+
+	/**
+	 * Id for parameter "Export Wizard" in command "Export" in category "File"
+	 * (value is <code>"exportWizardId"</code>). Optional.
+	 *
+	 * @since 3.6
+	 */
+	public static final String FILE_EXPORT_PARM_WIZARDID = "exportWizardId"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Save" in category "File"
+     * (value is <code>"org.eclipse.ui.file.save"</code>).
+     */
+    public static final String FILE_SAVE = "org.eclipse.ui.file.save"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Save As" in category "File"
+     * (value is <code>"org.eclipse.ui.file.saveAs"</code>).
+     */
+    public static final String FILE_SAVE_AS = "org.eclipse.ui.file.saveAs"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Save All" in category "File"
+     * (value is <code>"org.eclipse.ui.file.saveAll"</code>).
+     */
+    public static final String FILE_SAVE_ALL = "org.eclipse.ui.file.saveAll"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Print" in category "File"
+     * (value is <code>"org.eclipse.ui.file.print"</code>).
+     */
+    public static final String FILE_PRINT = "org.eclipse.ui.file.print"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Revert" in category "File"
+     * (value is <code>"org.eclipse.ui.file.revert"</code>).
+     */
+    public static final String FILE_REVERT = "org.eclipse.ui.file.revert"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Restart" in category "File"
+     * (value is <code>"org.eclipse.ui.file.restartWorkbench"</code>).
+     */
+    public static final String FILE_RESTART = "org.eclipse.ui.file.restartWorkbench"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Refresh" in category "File"
+     * (value is <code>"org.eclipse.ui.file.refresh"</code>).
+     */
+    public static final String FILE_REFRESH = "org.eclipse.ui.file.refresh"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Properties" in category "File"
+     * (value is <code>"org.eclipse.ui.file.properties"</code>).
+     */
+    public static final String FILE_PROPERTIES = "org.eclipse.ui.file.properties"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Exit" in category "File"
+     * (value is <code>"org.eclipse.ui.file.exit"</code>).
+     */
+    public static final String FILE_EXIT = "org.eclipse.ui.file.exit"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Move" in category "File"
+     * (value is <code>"org.eclipse.ui.edit.move"</code>).
+     */
+    public static final String FILE_MOVE = "org.eclipse.ui.edit.move"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Rename" in category "File"
+     * (value is <code>"org.eclipse.ui.edit.rename"</code>).
+     */
+    public static final String FILE_RENAME = "org.eclipse.ui.edit.rename"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Close Others" in category "File"
+     * (value is <code>"org.eclipse.ui.file.closeOthers"</code>).
+     */
+    public static final String FILE_CLOSE_OTHERS = "org.eclipse.ui.file.closeOthers"; //$NON-NLS-1$
+
+    // Edit Category:
+
+    /**
+     * Id for command "Undo" in category "Edit"
+     * (value is <code>"org.eclipse.ui.edit.undo"</code>).
+     */
+    public static final String EDIT_UNDO = "org.eclipse.ui.edit.undo"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Redo" in category "Edit"
+     * (value is <code>"org.eclipse.ui.edit.redo"</code>).
+     */
+    public static final String EDIT_REDO = "org.eclipse.ui.edit.redo"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Cut" in category "Edit"
+     * (value is <code>"org.eclipse.ui.edit.cut"</code>).
+     */
+    public static final String EDIT_CUT = "org.eclipse.ui.edit.cut"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Copy" in category "Edit"
+     * (value is <code>"org.eclipse.ui.edit.copy"</code>).
+     */
+    public static final String EDIT_COPY = "org.eclipse.ui.edit.copy"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Paste" in category "Edit"
+     * (value is <code>"org.eclipse.ui.edit.paste"</code>).
+     */
+    public static final String EDIT_PASTE = "org.eclipse.ui.edit.paste"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Delete" in category "Edit"
+     * (value is <code>"org.eclipse.ui.edit.delete"</code>).
+     */
+    public static final String EDIT_DELETE = "org.eclipse.ui.edit.delete"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Content Assist" in category "Edit"
+     * (value is <code>"org.eclipse.ui.edit.text.contentAssist.proposals"</code>).
+     */
+    public static final String EDIT_CONTENT_ASSIST = "org.eclipse.ui.edit.text.contentAssist.proposals"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Context Information" in category "Edit"
+     * (value is <code>"org.eclipse.ui.edit.text.contentAssist.contextInformation"</code>).
+     */
+    public static final String EDIT_CONTEXT_INFORMATION = "org.eclipse.ui.edit.text.contentAssist.contextInformation"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Select All" in category "Edit"
+     * (value is <code>"org.eclipse.ui.edit.selectAll"</code>).
+     */
+    public static final String EDIT_SELECT_ALL = "org.eclipse.ui.edit.selectAll"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Find and Replace" in category "Edit"
+     * (value is <code>"org.eclipse.ui.edit.findReplace"</code>).
+     */
+    public static final String EDIT_FIND_AND_REPLACE = "org.eclipse.ui.edit.findReplace"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Add Task" in category "Edit".
+     * (value is <code>"org.eclipse.ui.edit.addTask"</code>).
+     */
+    public static final String EDIT_ADD_TASK = "org.eclipse.ui.edit.addTask"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Add Bookmark" in category "Edit"
+     * (value is <code>"org.eclipse.ui.edit.addBookmark"</code>).
+     */
+    public static final String EDIT_ADD_BOOKMARK = "org.eclipse.ui.edit.addBookmark"; //$NON-NLS-1$
+
+    // Navigate Category:
+
+    /**
+     * Id for command "Go Into" in category "Navigate"
+     * (value is <code>"org.eclipse.ui.navigate.goInto"</code>).
+     */
+    public static final String NAVIGATE_GO_INTO = "org.eclipse.ui.navigate.goInto"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Back" in category "Navigate"
+     * (value is <code>"org.eclipse.ui.navigate.back"</code>).
+     */
+    public static final String NAVIGATE_BACK = "org.eclipse.ui.navigate.back"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Forward" in category "Navigate"
+     * (value is <code>"org.eclipse.ui.navigate.forward"</code>).
+     */
+    public static final String NAVIGATE_FORWARD = "org.eclipse.ui.navigate.forward"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Up" in category "Navigate"
+     * (value is <code>"org.eclipse.ui.navigate.up"</code>).
+     */
+    public static final String NAVIGATE_UP = "org.eclipse.ui.navigate.up"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Next" in category "Navigate"
+     * (value is <code>"org.eclipse.ui.navigate.next"</code>).
+     */
+    public static final String NAVIGATE_NEXT = "org.eclipse.ui.navigate.next"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Backward History" in category "Navigate"
+     * (value is <code>"org.eclipse.ui.navigate.backwardHistory"</code>).
+     */
+    public static final String NAVIGATE_BACKWARD_HISTORY = "org.eclipse.ui.navigate.backwardHistory"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Forward History" in category "Navigate"
+     * (value is <code>"org.eclipse.ui.navigate.forwardHistory"</code>).
+     */
+    public static final String NAVIGATE_FORWARD_HISTORY = "org.eclipse.ui.navigate.forwardHistory"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Previous" in category "Navigate"
+     * (value is <code>"org.eclipse.ui.navigate.previous"</code>).
+     */
+    public static final String NAVIGATE_PREVIOUS = "org.eclipse.ui.navigate.previous"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Toggle Link with Editor " in category "Navigate"
+     * (value is <code>"org.eclipse.ui.navigate.linkWithEditor"</code>).
+     */
+    public static final String NAVIGATE_TOGGLE_LINK_WITH_EDITOR = "org.eclipse.ui.navigate.linkWithEditor"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Next Page" in category "Navigate"
+     * (value is <code>"org.eclipse.ui.part.nextPage"</code>).
+     */
+    public static final String NAVIGATE_NEXT_PAGE = "org.eclipse.ui.part.nextPage"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Previous Page" in category "Navigate"
+     * (value is <code>"org.eclipse.ui.part.previousPage"</code>).
+     */
+    public static final String NAVIGATE_PREVIOUS_PAGE = "org.eclipse.ui.part.previousPage"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Collapse All" in category "Navigate"
+     * (value is <code>"org.eclipse.ui.navigate.collapseAll"</code>).
+     */
+    public static final String NAVIGATE_COLLAPSE_ALL = "org.eclipse.ui.navigate.collapseAll"; //$NON-NLS-1$
+
+	/**
+	 * Id for command "Expand All" in category "Navigate" (value is
+	 * <code>"org.eclipse.ui.navigate.expandAll"</code>).
+	 *
+	 * @since 3.6
+	 */
+	public static final String NAVIGATE_EXPAND_ALL = "org.eclipse.ui.navigate.expandAll"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Show In" in category "Navigate"
+     * (value is <code>"org.eclipse.ui.navigate.showIn"</code>).
+     */
+    public static final String NAVIGATE_SHOW_IN = "org.eclipse.ui.navigate.showIn"; //$NON-NLS-1$
+
+	/**
+	 * Id for parameter "Target Id" in command "Show In" in category "Navigate"
+	 * (value is <code>"org.eclipse.ui.navigate.showIn.targetId"</code>).
+	 * Required.
+	 *
+	 * @since 3.6
+	 */
+	public static final String NAVIGATE_SHOW_IN_PARM_TARGET = "org.eclipse.ui.navigate.showIn.targetId"; //$NON-NLS-1$
+
+	/**
+	 * Id for command "Show In" in category "Navigate" (value is
+	 * <code>"org.eclipse.ui.navigate.showInQuickMenu"</code>).
+	 */
+    public static final String NAVIGATE_SHOW_IN_QUICK_MENU = "org.eclipse.ui.navigate.showInQuickMenu"; //$NON-NLS-1$
+
+    // project category
+
+    /**
+     * Id for command "Build All" in category "Project".
+     * (value is <code>"org.eclipse.ui.project.buildAll"</code>).
+     */
+    public static final String PROJECT_BUILD_ALL = "org.eclipse.ui.project.buildAll"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Build Project" in category "Project".
+     * (value is <code>"org.eclipse.ui.project.buildProject"</code>).
+     */
+    public static final String PROJECT_BUILD_PROJECT = "org.eclipse.ui.project.buildProject"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Close Project" in category "Project".
+     * (value is <code>"org.eclipse.ui.project.closeProject"</code>).
+     */
+    public static final String PROJECT_CLOSE_PROJECT = "org.eclipse.ui.project.closeProject"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Close Unrelated Projects" in category "Project".
+     * (value is <code>"org.eclipse.ui.project.closeUnrelatedProjects"</code>).
+     */
+    public static final String PROJECT_CLOSE_UNRELATED_PROJECTS = "org.eclipse.ui.project.closeUnrelatedProjects"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Open Project" in category "Project".
+     * (value is <code>"org.eclipse.ui.project.openProject"</code>).
+     */
+    public static final String PROJECT_OPEN_PROJECT = "org.eclipse.ui.project.openProject"; //$NON-NLS-1$
+
+    // Window Category:
+
+    /**
+     * Id for command "New Window" in category "Window"
+     * (value is <code>"org.eclipse.ui.window.newWindow"</code>).
+     */
+    public static final String WINDOW_NEW_WINDOW = "org.eclipse.ui.window.newWindow"; //$NON-NLS-1$
+
+    /**
+     * Id for command "New Editor" in category "Window"
+     * (value is <code>"org.eclipse.ui.window.newEditor"</code>).
+     */
+    public static final String WINDOW_NEW_EDITOR = "org.eclipse.ui.window.newEditor"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Show View Menu" in category "Window"
+     * (value is <code>"org.eclipse.ui.window.showViewMenu"</code>).
+     */
+    public static final String WINDOW_SHOW_VIEW_MENU = "org.eclipse.ui.window.showViewMenu"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Activate Editor" in category "Window"
+     * (value is <code>"org.eclipse.ui.window.activateEditor"</code>).
+     */
+    public static final String WINDOW_ACTIVATE_EDITOR = "org.eclipse.ui.window.activateEditor"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Maximize Active View or Editor" in category "Window"
+     * (value is <code>"org.eclipse.ui.window.maximizePart"</code>).
+     */
+    public static final String WINDOW_MAXIMIZE_ACTIVE_VIEW_OR_EDITOR = "org.eclipse.ui.window.maximizePart"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Minimize Active View or Editor" in category "Window"
+     * (value is <code>"org.eclipse.ui.window.minimizePart"</code>).
+     */
+    public static final String WINDOW_MINIMIZE_ACTIVE_VIEW_OR_EDITOR = "org.eclipse.ui.window.minimizePart"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Next Editor" in category "Window"
+     * (value is <code>"org.eclipse.ui.window.nextEditor"</code>).
+     */
+    public static final String WINDOW_NEXT_EDITOR = "org.eclipse.ui.window.nextEditor"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Previous Editor" in category "Window"
+     * (value is <code>"org.eclipse.ui.window.previousEditor"</code>).
+     */
+    public static final String WINDOW_PREVIOUS_EDITOR = "org.eclipse.ui.window.previousEditor"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Next View" in category "Window"
+     * (value is <code>"org.eclipse.ui.window.nextView"</code>).
+     */
+    public static final String WINDOW_NEXT_VIEW = "org.eclipse.ui.window.nextView"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Previous View" in category "Window"
+     * (value is <code>"org.eclipse.ui.window.previousView"</code>).
+     */
+    public static final String WINDOW_PREVIOUS_VIEW = "org.eclipse.ui.window.previousView"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Next Perspective" in category "Window"
+     * (value is <code>"org.eclipse.ui.window.nextPerspective"</code>).
+     */
+    public static final String WINDOW_NEXT_PERSPECTIVE = "org.eclipse.ui.window.nextPerspective"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Previous Perspective" in category "Window"
+     * (value is <code>"org.eclipse.ui.window.previousPerspective"</code>).
+     */
+    public static final String WINDOW_PREVIOUS_PERSPECTIVE = "org.eclipse.ui.window.previousPerspective"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Close All Perspectives" in category "Window"
+     * (value is <code>"org.eclipse.ui.window.closeAllPerspectives"</code>).
+     */
+    public static final String WINDOW_CLOSE_ALL_PERSPECTIVES = "org.eclipse.ui.window.closeAllPerspectives"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Close Perspective" in category "Window"
+     * (value is <code>"org.eclipse.ui.window.closePerspective"</code>).
+     */
+    public static final String WINDOW_CLOSE_PERSPECTIVE = "org.eclipse.ui.window.closePerspective"; //$NON-NLS-1$
+
+	/**
+	 * Id for parameter "Perspective Id" in command "Close Perspective" in
+	 * category "Window" (value is
+	 * <code>"org.eclipse.ui.window.closePerspective.perspectiveId"</code>).
+	 * Optional.
+	 *
+	 * @since 3.6
+	 */
+	public static final String WINDOW_CLOSE_PERSPECTIVE_PARM_ID = "org.eclipse.ui.window.closePerspective.perspectiveId"; //$NON-NLS-1$
+
+	/**
+	 * Id for command "Close Part" in category "Window" (value is
+	 * <code>"org.eclipse.ui.file.closePart"</code>).
+	 */
+    public static final String WINDOW_CLOSE_PART = "org.eclipse.ui.file.closePart"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Customize Perspective" in category "Window"
+     * (value is <code>"org.eclipse.ui.window.customizePerspective"</code>).
+     */
+    public static final String WINDOW_CUSTOMIZE_PERSPECTIVE = "org.eclipse.ui.window.customizePerspective"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Pin Editor" in category "Window"
+     * (value is <code>"org.eclipse.ui.window.pinEditor"</code>).
+     */
+    public static final String WINDOW_PIN_EDITOR = "org.eclipse.ui.window.pinEditor"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Preferences" in category "Window"
+     * (value is <code>"org.eclipse.ui.window.preferences"</code>).
+     */
+    public static final String WINDOW_PREFERENCES = "org.eclipse.ui.window.preferences"; //$NON-NLS-1$
+
+	/**
+	 * Id for parameter "Preference Page Id" in command "Preferences" in
+	 * category "Window" (value is <code>"preferencePageId"</code>). Optional.
+	 *
+	 * @since 3.6
+	 */
+	public static final String WINDOW_PREFERENCES_PARM_PAGEID = "preferencePageId"; //$NON-NLS-1$
+
+	/**
+	 * Id for command "Reset Perspective" in category "Window" (value is
+	 * <code>"org.eclipse.ui.window.resetPerspective"</code>).
+	 */
+    public static final String WINDOW_RESET_PERSPECTIVE = "org.eclipse.ui.window.resetPerspective"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Save Perspective As" in category "Window"
+     * (value is <code>"org.eclipse.ui.window.savePerspective"</code>).
+     */
+    public static final String WINDOW_SAVE_PERSPECTIVE_AS = "org.eclipse.ui.window.savePerspective"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Show Key Assist" in category "Window"
+     * (value is <code>"org.eclipse.ui.window.showKeyAssist"</code>).
+     */
+    public static final String WINDOW_SHOW_KEY_ASSIST = "org.eclipse.ui.window.showKeyAssist"; //$NON-NLS-1$
+
+	/**
+	 * Id for command "Lock Toolbar" in category "Window" (value is
+	 * <code>"org.eclipse.ui.window.lockToolbar"</code>).
+	 *
+	 * @since 3.7
+	 */
+	public static final String WINDOW_LOCK_TOOLBAR = "org.eclipse.ui.window.lockToolBar"; //$NON-NLS-1$
+
+    // Help Category:
+
+    /**
+     * Id for command "Help Contents" in category "Help"
+     * (value is <code>"org.eclipse.ui.help.helpContents"</code>).
+     */
+    public static final String HELP_HELP_CONTENTS = "org.eclipse.ui.help.helpContents"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Help Search" in category "Help"
+     * (value is <code>"org.eclipse.ui.help.helpSearch"</code>).
+     */
+    public static final String HELP_HELP_SEARCH = "org.eclipse.ui.help.helpSearch"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Dynamic Help" in category "Help"
+     * (value is <code>"org.eclipse.ui.help.dynamicHelp"</code>).
+     */
+    public static final String HELP_DYNAMIC_HELP = "org.eclipse.ui.help.dynamicHelp"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Welcome" in category "Help"
+     * (value is <code>"org.eclipse.ui.help.quickStartAction"</code>).
+     */
+    public static final String HELP_WELCOME = "org.eclipse.ui.help.quickStartAction"; //$NON-NLS-1$
+
+    /**
+     * Id for command "Tips and Tricks" in category "Help"
+     * (value is <code>"org.eclipse.ui.help.tipsAndTricksAction"</code>).
+     */
+    public static final String HELP_TIPS_AND_TRICKS = "org.eclipse.ui.help.tipsAndTricksAction"; //$NON-NLS-1$
+
+    /**
+     * Id for command "About" in category "Help"
+     * (value is <code>"org.eclipse.ui.help.aboutAction"</code>).
+     */
+    public static final String HELP_ABOUT = "org.eclipse.ui.help.aboutAction"; //$NON-NLS-1$
+
+    // Views Category:
+
+    /**
+     * Id for command "Show View" in category "Views"
+     * (value is <code>"org.eclipse.ui.views.showView"</code>).
+     */
+    public static final String VIEWS_SHOW_VIEW = "org.eclipse.ui.views.showView"; //$NON-NLS-1$
+
+	/**
+	 * Id for parameter "View Id" in command "Show View" in category "Views"
+	 * (value is <code>"org.eclipse.ui.views.showView.viewId"</code>).
+	 *
+	 * @since 3.6
+	 */
+	public static final String VIEWS_SHOW_VIEW_PARM_ID = "org.eclipse.ui.views.showView.viewId"; //$NON-NLS-1$
+
+	/**
+	 * Id for parameter "Secondary Id" in command "Show View" in category
+	 * "Views" (value is
+	 * <code>"org.eclipse.ui.views.showView.secondaryId"</code>).
+	 *
+	 * @since 3.7
+	 */
+	public static final String VIEWS_SHOW_VIEW_SECONDARY_ID = "org.eclipse.ui.views.showView.secondaryId"; //$NON-NLS-1$
+
+	/**
+	 * Id for parameter "As Fastview" in command "Show View" in category "Views"
+	 * (value is <code>"org.eclipse.ui.views.showView.makeFast"</code>).
+	 * Optional.
+	 *
+	 * @since 3.6
+	 */
+	public static final String VIEWS_SHOW_VIEW_PARM_FASTVIEW = "org.eclipse.ui.views.showView.makeFast"; //$NON-NLS-1$
+
+    // Perspectives Category:
+
+    /**
+     * Id for command "Show Perspective" in category "Perspectives"
+     * (value is <code>"org.eclipse.ui.perspectives.showPerspective"</code>).
+     */
+    public static final String PERSPECTIVES_SHOW_PERSPECTIVE = "org.eclipse.ui.perspectives.showPerspective"; //$NON-NLS-1$
+
+	/**
+	 * Id for parameter "Perspective Id" in command "Show Perspective" in
+	 * category "Perspectives" (value is
+	 * <code>"org.eclipse.ui.perspectives.showPerspective.perspectiveId"</code>
+	 * ).
+	 *
+	 * @since 3.6
+	 */
+	public static final String PERSPECTIVES_SHOW_PERSPECTIVE_PARM_ID = "org.eclipse.ui.perspectives.showPerspective.perspectiveId"; //$NON-NLS-1$
+
+	/**
+	 * Id for parameter "In New Window" in command "Show Perspective" in
+	 * category "Perspectives" (value is
+	 * <code>"org.eclipse.ui.perspectives.showPerspective.newWindow"</code>).
+	 * Optional.
+	 *
+	 * @since 3.6
+	 */
+	public static final String PERSPECTIVES_SHOW_PERSPECTIVE_PARM_NEWWINDOW = "org.eclipse.ui.perspectives.showPerspective.newWindow"; //$NON-NLS-1$
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchListener.java
new file mode 100644
index 0000000..6129c4c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchListener.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+/**
+ * Interface for listening to workbench lifecycle events.
+ * <p>
+ * This interface may be implemented by clients.
+ * </p>
+ *
+ * @see IWorkbench#addWorkbenchListener
+ * @see IWorkbench#removeWorkbenchListener
+ * @since 3.2
+ */
+public interface IWorkbenchListener {
+
+    /**
+     * Notifies that the workbench is about to shut down.
+     * <p>
+     * This method is called immediately prior to workbench shutdown before any
+     * windows have been closed.
+     * </p>
+     * <p>
+     * The listener may veto a regular shutdown by returning <code>false</code>,
+     * although this will be ignored if the workbench is being forced to shut down.
+     * </p>
+     * <p>
+     * Since other workbench listeners may veto the shutdown, the listener should
+     * not dispose resources or do any other work during this notification that would
+     * leave the workbench in an inconsistent state.
+     * </p>
+     *
+     * @param workbench the workbench
+     * @param forced <code>true</code> if the workbench is being forced to shutdown,
+     *   <code>false</code> for a regular close
+     * @return <code>true</code> to allow the workbench to proceed with shutdown,
+     *   <code>false</code> to veto a non-forced shutdown
+     */
+    public boolean preShutdown(IWorkbench workbench, boolean forced);
+
+    /**
+     * Performs arbitrary finalization after the workbench stops running.
+     * <p>
+     * This method is called during workbench shutdown after all windows
+     * have been closed.
+     * </p>
+     *
+     * @param workbench the workbench
+     */
+    public void postShutdown(IWorkbench workbench);
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchPage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchPage.java
new file mode 100644
index 0000000..0ae9f98
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchPage.java
@@ -0,0 +1,1301 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
+import org.eclipse.jface.util.IPropertyChangeListener;
+
+/**
+ * A workbench page consists of an arrangement of views and editors intended to
+ * be presented together to the user in a single workbench window.
+ * <p>
+ * A page can contain 0 or more views and 0 or more editors. These views and
+ * editors are contained wholly within the page and are not shared with other
+ * pages. The layout and visible action set for the page is defined by a
+ * perspective.
+ * <p>
+ * The number of views and editors within a page is restricted to simplify part
+ * management for the user. In particular:
+ * <ul>
+ * <li>Unless a view explicitly allows for multiple instances in its plug-in
+ * declaration there will be only one instance in a given workbench page.</li>
+ * <li>Only one editor can exist for each editor input within a page.
+ * <li>
+ * </ul>
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ *
+ * @see IPerspectiveDescriptor
+ * @see IEditorPart
+ * @see IViewPart
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IWorkbenchPage extends IPartService, ISelectionService {
+	/**
+	 * An optional attribute within a workspace marker (<code>IMarker</code>)
+	 * which identifies the preferred editor type to be opened when
+	 * <code>openEditor</code> is called.
+	 *
+	 * @see #openEditor(IEditorInput, String)
+	 * @see #openEditor(IEditorInput, String, boolean)
+	 * @deprecated in 3.0 since the notion of markers this is not generally
+	 *             applicable. Use the IDE-specific constant
+	 *             <code>IDE.EDITOR_ID_ATTR</code>.
+	 */
+	@Deprecated
+	public static final String EDITOR_ID_ATTR = "org.eclipse.ui.editorID"; //$NON-NLS-1$
+
+	/**
+	 * Change event id when the perspective is reset to its original state.
+	 *
+	 * @see IPerspectiveListener
+	 */
+	public static final String CHANGE_RESET = "reset"; //$NON-NLS-1$
+
+	/**
+	 * Change event id when the perspective has completed a reset to its
+	 * original state.
+	 *
+	 * @since 3.0
+	 * @see IPerspectiveListener
+	 */
+	public static final String CHANGE_RESET_COMPLETE = "resetComplete"; //$NON-NLS-1$
+
+	/**
+	 * Change event id when one or more views are shown in a perspective.
+	 *
+	 * @see IPerspectiveListener
+	 */
+	public static final String CHANGE_VIEW_SHOW = "viewShow"; //$NON-NLS-1$
+
+	/**
+	 * Change event id when one or more views are hidden in a perspective.
+	 *
+	 * @see IPerspectiveListener
+	 */
+	public static final String CHANGE_VIEW_HIDE = "viewHide"; //$NON-NLS-1$
+
+	/**
+	 * Change event id when one or more editors are opened in a perspective.
+	 *
+	 * @see IPerspectiveListener
+	 */
+	public static final String CHANGE_EDITOR_OPEN = "editorOpen"; //$NON-NLS-1$
+
+	/**
+	 * Change event id when one or more editors are closed in a perspective.
+	 *
+	 * @see IPerspectiveListener
+	 */
+	public static final String CHANGE_EDITOR_CLOSE = "editorClose"; //$NON-NLS-1$
+
+	/**
+	 * Change event id when the editor area is shown in a perspective.
+	 *
+	 * @see IPerspectiveListener
+	 */
+	public static final String CHANGE_EDITOR_AREA_SHOW = "editorAreaShow"; //$NON-NLS-1$
+
+	/**
+	 * Change event id when the editor area is hidden in a perspective.
+	 *
+	 * @see IPerspectiveListener
+	 */
+	public static final String CHANGE_EDITOR_AREA_HIDE = "editorAreaHide"; //$NON-NLS-1$
+
+	/**
+	 * Change event id when an action set is shown in a perspective.
+	 *
+	 * @see IPerspectiveListener
+	 */
+	public static final String CHANGE_ACTION_SET_SHOW = "actionSetShow"; //$NON-NLS-1$
+
+	/**
+	 * Change event id when an action set is hidden in a perspective.
+	 *
+	 * @see IPerspectiveListener
+	 */
+	public static final String CHANGE_ACTION_SET_HIDE = "actionSetHide"; //$NON-NLS-1$
+
+	/**
+	 * Change event id when a fast view is added in a perspective.
+	 *
+	 * @see IPerspectiveListener
+	 */
+	public static final String CHANGE_FAST_VIEW_ADD = "fastViewAdd"; //$NON-NLS-1$
+
+	/**
+	 * Change event id when a fast view is removed in a perspective.
+	 *
+	 * @see IPerspectiveListener
+	 */
+	public static final String CHANGE_FAST_VIEW_REMOVE = "fastViewRemove"; //$NON-NLS-1$
+
+	/**
+	 * Change event id when the page working set was replaced
+	 *
+	 * @see IPropertyChangeListener
+	 */
+	public static final String CHANGE_WORKING_SET_REPLACE = "workingSetReplace"; //$NON-NLS-1$
+
+	/**
+	 * Change event id when the page working set list was replaced
+	 *
+	 * @see IPropertyChangeListener
+	 * @since 3.2
+	 */
+	public static final String CHANGE_WORKING_SETS_REPLACE = "workingSetsReplace"; //$NON-NLS-1$
+
+	/**
+	 * Show view mode that indicates the view should be made visible and
+	 * activated. Use of this mode has the same effect as calling
+	 * {@link #showView(String)}.
+	 *
+	 * @since 3.0
+	 */
+	public static final int VIEW_ACTIVATE = 1;
+
+	/**
+	 * Show view mode that indicates the view should be made visible. If the
+	 * view is opened in the container that contains the active view then this
+	 * has the same effect as <code>VIEW_CREATE</code>.
+	 *
+	 * @since 3.0
+	 */
+	public static final int VIEW_VISIBLE = 2;
+
+	/**
+	 * Show view mode that indicates the view should be made created but not
+	 * necessarily be made visible. It will only be made visible in the event
+	 * that it is opened in its own container. In other words, only if it is not
+	 * stacked with another view.
+	 *
+	 * @since 3.0
+	 */
+	public static final int VIEW_CREATE = 3;
+
+	/**
+	 * Editor opening match mode specifying that no matching against existing
+	 * editors should be done.
+	 *
+	 * @since 3.2
+	 */
+	public static final int MATCH_NONE = 0;
+
+	/**
+	 * Editor opening match mode specifying that the editor input should be
+	 * considered when matching against existing editors.
+	 *
+	 * @since 3.2
+	 */
+	public static final int MATCH_INPUT = 1;
+
+	/**
+	 * Editor opening match mode specifying that the editor id should be
+	 * considered when matching against existing editors.
+	 *
+	 * @since 3.2
+	 */
+	public static final int MATCH_ID = 2;
+
+	/**
+	 * State of a view in a given page when the view stack is minimized.
+	 *
+	 * @since 3.2
+	 */
+	public static final int STATE_MINIMIZED = 0;
+
+	/**
+	 * State of a view in a given page when the page is zoomed in on the view
+	 * stack.
+	 *
+	 * @since 3.2
+	 */
+	public static final int STATE_MAXIMIZED = 1;
+
+	/**
+	 * State of a view in a given page when the view stack is in it's normal
+	 * state.
+	 *
+	 * @since 3.2
+	 */
+	public static final int STATE_RESTORED = 2;
+
+	/**
+	 * Activates the given part. The part will be brought to the front and given
+	 * focus. The part must belong to this page.
+	 *
+	 * @param part
+	 *            the part to activate
+	 */
+	public void activate(IWorkbenchPart part);
+
+	/**
+	 * Adds a property change listener.
+	 *
+	 * @param listener
+	 *            the property change listener to add
+	 * @since 2.0
+	 * @deprecated client should register listeners on the instance of
+	 *             {@link org.eclipse.ui.IWorkingSetManager} returned by
+	 *             {@link org.eclipse.ui.IWorkbench#getWorkingSetManager()}
+	 *             instead.
+	 */
+	@Deprecated
+	public void addPropertyChangeListener(IPropertyChangeListener listener);
+
+	/**
+	 * Moves the given part forward in the Z order of this page so as to make it
+	 * visible, without changing which part has focus. The part must belong to
+	 * this page.
+	 *
+	 * @param part
+	 *            the part to bring forward
+	 */
+	public void bringToTop(IWorkbenchPart part);
+
+	/**
+	 * Closes this workbench page. If this page is the active one, this honor is
+	 * passed along to one of the window's other pages if possible.
+	 * <p>
+	 * If the page has an open editor with unsaved content, the user will be
+	 * given the opportunity to save it.
+	 * </p>
+	 *
+	 * @return <code>true</code> if the page was successfully closed, and
+	 *         <code>false</code> if it is still open
+	 */
+	public boolean close();
+
+	/**
+	 * Closes all of the editors belonging to this workbench page.
+	 * <p>
+	 * If the page has open editors with unsaved content and <code>save</code>
+	 * is <code>true</code>, the user will be given the opportunity to save
+	 * them.
+	 * </p>
+	 *
+	 * @param save
+	 *
+	 * @return <code>true</code> if all editors were successfully closed, and
+	 *         <code>false</code> if at least one is still open
+	 */
+	public boolean closeAllEditors(boolean save);
+
+	/**
+	 * Closes the given <code>Array</code> of editor references. The editors
+	 * must belong to this workbench page.
+	 * <p>
+	 * If any of the editors have unsaved content and <code>save</code> is
+	 * <code>true</code>, the user will be given the opportunity to save
+	 * them.
+	 * </p>
+	 *
+	 * @param editorRefs
+	 *            the editors to close
+	 * @param save
+	 *            <code>true</code> to save the editor contents if required
+	 *            (recommended), and <code>false</code> to discard any unsaved
+	 *            changes
+	 * @return <code>true</code> if the editors were successfully closed, and
+	 *         <code>false</code> if the editors are still open
+	 * @since 3.0
+	 */
+	public boolean closeEditors(IEditorReference[] editorRefs, boolean save);
+
+	/**
+	 * Closes the given editor. The editor must belong to this workbench page.
+	 * <p>
+	 * If the editor has unsaved content and <code>save</code> is
+	 * <code>true</code>, the user will be given the opportunity to save it.
+	 * </p>
+	 *
+	 * @param editor
+	 *            the editor to close
+	 * @param save
+	 *            <code>true</code> to save the editor contents if required
+	 *            (recommended), and <code>false</code> to discard any unsaved
+	 *            changes
+	 * @return <code>true</code> if the editor was successfully closed, and
+	 *         <code>false</code> if the editor is still open
+	 */
+	public boolean closeEditor(IEditorPart editor, boolean save);
+
+	/**
+	 * Returns the view in this page with the specified id. There is at most one
+	 * view in the page with the specified id.
+	 *
+	 * @param viewId
+	 *            the id of the view extension to use
+	 * @return the view, or <code>null</code> if none is found
+	 */
+	public IViewPart findView(String viewId);
+
+	/**
+	 * Returns the view reference with the specified id.
+	 *
+	 * @param viewId
+	 *            the id of the view extension to use
+	 * @return the view reference, or <code>null</code> if none is found
+	 * @since 3.0
+	 */
+	public IViewReference findViewReference(String viewId);
+
+	/**
+	 * Returns the view reference with the specified id and secondary id.
+	 *
+	 * @param viewId
+	 *            the id of the view extension to use
+	 * @param secondaryId
+	 *            the secondary id to use, or <code>null</code> for no
+	 *            secondary id
+	 * @return the view reference, or <code>null</code> if none is found
+	 * @since 3.0
+	 */
+	public IViewReference findViewReference(String viewId, String secondaryId);
+
+	/**
+	 * Returns the active editor open in this page.
+	 * <p>
+	 * This is the visible editor on the page, or, if there is more than one
+	 * visible editor, this is the one most recently brought to top.
+	 * </p>
+	 *
+	 * @return the active editor, or <code>null</code> if no editor is active
+	 */
+	public IEditorPart getActiveEditor();
+
+	/**
+	 * Returns the editor with the specified input. Returns null if there is no
+	 * opened editor with that input.
+	 *
+	 * @param input
+	 *            the editor input
+	 * @return an editor with input equals to <code>input</code>
+	 */
+	public IEditorPart findEditor(IEditorInput input);
+
+	/**
+	 * Returns an array of editor references that match the given input and/or
+	 * editor id, as specified by the given match flags. Returns an empty array
+	 * if there are no matching editors, or if matchFlags is MATCH_NONE.
+	 *
+	 * @param input
+	 *            the editor input, or <code>null</code> if MATCH_INPUT is not
+	 *            specified in matchFlags
+	 * @param editorId
+	 *            the editor id, or <code>null</code> if MATCH_ID is not
+	 *            specified in matchFlags
+	 * @param matchFlags
+	 *            a bit mask consisting of zero or more of the MATCH_* constants
+	 *            OR-ed together
+	 * @return the references for the matching editors
+	 *
+	 * @see #MATCH_NONE
+	 * @see #MATCH_INPUT
+	 * @see #MATCH_ID
+	 * @since 3.2
+	 */
+	public IEditorReference[] findEditors(IEditorInput input, String editorId,
+			int matchFlags);
+
+	/**
+	 * Returns a list of the editors open in this page.
+	 * <p>
+	 * Note that each page has its own editors; editors are never shared between
+	 * pages.
+	 * </p>
+	 *
+	 * @return a list of open editors
+	 *
+	 * @deprecated Clients are encouraged to use {@link #getEditorReferences()}
+	 *             instead. Calling this method has the side effect of restoring
+	 *             all the editors in the page which can cause plug-in
+	 *             activation.
+	 */
+	@Deprecated
+	public IEditorPart[] getEditors();
+
+	/**
+	 * Returns an array of references to open editors in this page.
+	 * <p>
+	 * Note that each page has its own editors; editors are never shared between
+	 * pages.
+	 * </p>
+	 *
+	 * @return a list of open editors
+	 */
+	public IEditorReference[] getEditorReferences();
+
+	/**
+	 * Returns a list of dirty editors in this page.
+	 *
+	 * @return a list of dirty editors
+	 */
+	public IEditorPart[] getDirtyEditors();
+
+	/**
+	 * Returns the input for this page.
+	 *
+	 * @return the input for this page, or <code>null</code> if none
+	 */
+	public IAdaptable getInput();
+
+	/**
+	 * Returns the page label. This will be a unique identifier within the
+	 * containing workbench window.
+	 *
+	 * @return the page label
+	 */
+	public String getLabel();
+
+	/**
+	 * Returns the current perspective descriptor for this page, or
+	 * <code>null</code> if there is no current perspective.
+	 *
+	 * @return the current perspective descriptor or <code>null</code>
+	 * @see #setPerspective
+	 * @see #savePerspective
+	 */
+	public IPerspectiveDescriptor getPerspective();
+
+	/**
+	 * Returns a list of the reference to views visible on this page.
+	 * <p>
+	 * Note that each page has its own views; views are never shared between
+	 * pages.
+	 * </p>
+	 *
+	 * @return a list of references to visible views
+	 */
+	public IViewReference[] getViewReferences();
+
+	/**
+	 * Returns a list of the views visible on this page.
+	 * <p>
+	 * Note that each page has its own views; views are never shared between
+	 * pages.
+	 * </p>
+	 *
+	 * @return a list of visible views
+	 *
+	 * @deprecated Clients are encouraged to use {@link #getViewReferences()}
+	 *             instead. Calling this method has the side effect of restoring
+	 *             all the views in the page which can cause plug-in activation.
+	 */
+	@Deprecated
+	public IViewPart[] getViews();
+
+	/**
+	 * Returns the workbench window of this page.
+	 *
+	 * @return the workbench window
+	 */
+	public IWorkbenchWindow getWorkbenchWindow();
+
+	/**
+	 * Returns the working set of this page.
+	 *
+	 * @return the working set of this page.
+	 * @since 2.0
+	 * @deprecated individual views should store a working set if needed
+	 */
+	@Deprecated
+	public IWorkingSet getWorkingSet();
+
+	/**
+	 * Hides an action set in this page.
+	 * <p>
+	 * In most cases where this method is used the caller is tightly coupled to
+	 * a particular action set. They define it in the registry and may make it
+	 * visible in certain scenarios by calling <code>showActionSet</code>. A
+	 * static variable is often used to identify the action set id in caller
+	 * code.
+	 * </p>
+	 *
+	 * @param actionSetID
+	 *            the action set to hide
+	 */
+	public void hideActionSet(String actionSetID);
+
+	/**
+	 * Hides the given view. The view must belong to this page.
+	 *
+	 * @param view
+	 *            the view to hide
+	 */
+	public void hideView(IViewPart view);
+
+	/**
+	 * Hides the given view that belongs to the reference, if any.
+	 *
+	 * @param view
+	 *            the references whos view is to be hidden
+	 * @since 3.0
+	 */
+	public void hideView(IViewReference view);
+
+	/**
+	 * Returns whether the specified part is visible.
+	 *
+	 * @param part
+	 *            the part to test
+	 * @return boolean <code>true</code> if part is visible
+	 */
+	public boolean isPartVisible(IWorkbenchPart part);
+
+	/**
+	 * Returns whether the page's current perspective is showing the editor
+	 * area.
+	 *
+	 * @return <code>true</code> when editor area visible, <code>false</code>
+	 *         otherwise
+	 */
+	public boolean isEditorAreaVisible();
+
+	/**
+	 * Reuses the specified editor by setting its new input.
+	 *
+	 * @param editor
+	 *            the editor to be reused
+	 * @param input
+	 *            the new input for the reusable editor
+	 */
+	public void reuseEditor(IReusableEditor editor, IEditorInput input);
+
+	/**
+	 * Opens an editor on the given input.
+	 * <p>
+	 * If this page already has an editor open on the target input that editor
+	 * is activated; otherwise, a new editor is opened. Two editor inputs,
+	 * input1 and input2, are considered the same if
+	 *
+	 * <pre>
+	 * input1.equals(input2) == true
+	 * </pre>.
+	 * </p>
+	 * <p>
+	 * The editor type is determined by mapping <code>editorId</code> to an
+	 * editor extension registered with the workbench. An editor id is passed
+	 * rather than an editor object to prevent the accidental creation of more
+	 * than one editor for the same input. It also guarantees a consistent
+	 * lifecycle for editors, regardless of whether they are created by the user
+	 * or restored from saved data.
+	 * </p>
+	 *
+	 * @param input
+	 *            the editor input
+	 * @param editorId
+	 *            the id of the editor extension to use
+	 * @return an open and active editor, or <code>null</code> if an external
+	 *         editor was opened
+	 * @exception PartInitException
+	 *                if the editor could not be created or initialized
+	 */
+	public IEditorPart openEditor(IEditorInput input, String editorId)
+			throws PartInitException;
+
+	/**
+	 * Opens an editor on the given input.
+	 * <p>
+	 * If this page already has an editor open on the target input that editor
+	 * is brought to the front; otherwise, a new editor is opened. Two editor
+	 * inputs are considered the same if they equal. See
+	 * <code>Object.equals(Object)<code>
+	 * and <code>IEditorInput</code>. If <code>activate == true</code> the editor
+	 * will be activated.
+	 * </p><p>
+	 * The editor type is determined by mapping <code>editorId</code> to an editor
+	 * extension registered with the workbench.  An editor id is passed rather than
+	 * an editor object to prevent the accidental creation of more than one editor
+	 * for the same input. It also guarantees a consistent lifecycle for editors,
+	 * regardless of whether they are created by the user or restored from saved
+	 * data.
+	 * </p>
+	 *
+	 * @param input the editor input
+	 * @param editorId the id of the editor extension to use
+	 * @param activate if <code>true</code> the editor will be activated
+	 * @return an open editor, or <code>null</code> if an external editor was opened
+	 * @exception PartInitException if the editor could not be created or initialized
+	 */
+	public IEditorPart openEditor(IEditorInput input, String editorId,
+			boolean activate) throws PartInitException;
+
+	/**
+	 * Opens an editor on the given input.
+	 * <p>
+	 * If this page already has an editor open that matches the given input
+	 * and/or editor id (as specified by the matchFlags argument), that editor
+	 * is brought to the front; otherwise, a new editor is opened. Two editor
+	 * inputs are considered the same if they equal. See
+	 * <code>Object.equals(Object)<code>
+	 * and <code>IEditorInput</code>. If <code>activate == true</code> the editor
+	 * will be activated.
+	 * </p><p>
+	 * The editor type is determined by mapping <code>editorId</code> to an editor
+	 * extension registered with the workbench.  An editor id is passed rather than
+	 * an editor object to prevent the accidental creation of more than one editor
+	 * for the same input. It also guarantees a consistent lifecycle for editors,
+	 * regardless of whether they are created by the user or restored from saved
+	 * data.
+	 * </p>
+	 *
+	 * @param input the editor input
+	 * @param editorId the id of the editor extension to use
+	 * @param activate if <code>true</code> the editor will be activated
+	 * @param matchFlags a bit mask consisting of zero or more of the MATCH_* constants OR-ed together
+	 * @return an open editor, or <code>null</code> if an external editor was opened
+	 * @exception PartInitException if the editor could not be created or initialized
+	 *
+	 * @see #MATCH_NONE
+	 * @see #MATCH_INPUT
+	 * @see #MATCH_ID
+	 * @since 3.2
+	 */
+	public IEditorPart openEditor(final IEditorInput input,
+			final String editorId, final boolean activate, final int matchFlags)
+			throws PartInitException;
+
+	/**
+	 * Removes the property change listener.
+	 *
+	 * @param listener
+	 *            the property change listener to remove
+	 * @since 2.0
+	 */
+	public void removePropertyChangeListener(IPropertyChangeListener listener);
+
+	/**
+	 * Changes the visible views, their layout, and the visible action sets
+	 * within the page to match the current perspective descriptor. This is a
+	 * rearrangement of components and not a replacement. The contents of the
+	 * current perspective descriptor are unaffected.
+	 * <p>
+	 * For more information on perspective change see
+	 * <code>setPerspective()</code>.
+	 * </p>
+	 */
+	public void resetPerspective();
+
+	/**
+	 * Saves the contents of all dirty editors belonging to this workbench page.
+	 * If there are no dirty editors this method returns without effect.
+	 * <p>
+	 * If <code>confirm</code> is <code>true</code> the user is prompted to
+	 * confirm the command.
+	 * </p>
+	 * <p>
+	 * Note that as of 3.2, this method also saves views that implement
+	 * ISaveablePart and are dirty.
+	 * </p>
+	 *
+	 * @param confirm <code>true</code> to ask the user before saving unsaved
+	 *            changes (recommended), and <code>false</code> to save
+	 *            unsaved changes without asking
+	 * @return <code>true</code> if the command succeeded, and
+	 *         <code>false</code> if the operation was canceled by the user or
+	 *         an error occurred while saving
+	 */
+	public boolean saveAllEditors(boolean confirm);
+
+	/**
+	 * Saves the contents of the given editor if dirty. If not, this method
+	 * returns without effect.
+	 * <p>
+	 * If <code>confirm</code> is <code>true</code> the user is prompted to
+	 * confirm the command. Otherwise, the save happens without prompt.
+	 * </p>
+	 * <p>
+	 * The editor must belong to this workbench page.
+	 * </p>
+	 *
+	 * @param editor
+	 *            the editor to close
+	 * @param confirm
+	 *            <code>true</code> to ask the user before saving unsaved
+	 *            changes (recommended), and <code>false</code> to save
+	 *            unsaved changes without asking
+	 * @return <code>true</code> if the command succeeded, and
+	 *         <code>false</code> if the editor was not saved
+	 */
+	public boolean saveEditor(IEditorPart editor, boolean confirm);
+
+	/**
+	 * Saves the visible views, their layout, and the visible action sets for
+	 * this page to the current perspective descriptor. The contents of the
+	 * current perspective descriptor are overwritten.
+	 */
+	public void savePerspective();
+
+	/**
+	 * Saves the visible views, their layout, and the visible action sets for
+	 * this page to the given perspective descriptor. The contents of the given
+	 * perspective descriptor are overwritten and it is made the current one for
+	 * this page.
+	 *
+	 * @param perspective
+	 *            the perspective descriptor to save to
+	 */
+	public void savePerspectiveAs(IPerspectiveDescriptor perspective);
+
+	/**
+	 * Show or hide the editor area for the page's active perspective.
+	 *
+	 * @param showEditorArea
+	 *            <code>true</code> to show the editor area,
+	 *            <code>false</code> to hide the editor area
+	 */
+	public void setEditorAreaVisible(boolean showEditorArea);
+
+	/**
+	 * Changes the visible views, their layout, and the visible action sets
+	 * within the page to match the given perspective descriptor. This is a
+	 * rearrangement of components and not a replacement. The contents of the
+	 * old perspective descriptor are unaffected.
+	 * <p>
+	 * When a perspective change occurs the old perspective is deactivated
+	 * (hidden) and cached for future reference. Then the new perspective is
+	 * activated (shown). The views within the page are shared by all existing
+	 * perspectives to make it easy for the user to switch between one
+	 * perspective and another quickly without loss of context.
+	 * </p>
+	 * <p>
+	 * During activation the action sets are modified. If an action set is
+	 * specified in the new perspective which is not visible in the old one it
+	 * will be created. If an old action set is not specified in the new
+	 * perspective it will be disposed.
+	 * </p>
+	 * <p>
+	 * The visible views and their layout within the page also change. If a view
+	 * is specified in the new perspective which is not visible in the old one a
+	 * new instance of the view will be created. If an old view is not specified
+	 * in the new perspective it will be hidden. This view may reappear if the
+	 * user selects it from the View menu or if they switch to a perspective
+	 * (which may be the old one) where the view is visible.
+	 * </p>
+	 * <p>
+	 * The open editors are not modified by this method.
+	 * </p>
+	 *
+	 * @param perspective
+	 *            the perspective descriptor
+	 */
+	public void setPerspective(IPerspectiveDescriptor perspective);
+
+	/**
+	 * Shows an action set in this page.
+	 * <p>
+	 * In most cases where this method is used the caller is tightly coupled to
+	 * a particular action set. They define it in the registry and may make it
+	 * visible in certain scenarios by calling <code>showActionSet</code>. A
+	 * static variable is often used to identify the action set id in caller
+	 * code.
+	 * </p>
+	 *
+	 * @param actionSetID
+	 *            the action set to show
+	 */
+	public void showActionSet(String actionSetID);
+
+	/**
+	 * Shows the view identified by the given view id in this page and gives it
+	 * focus. If there is a view identified by the given view id (and with no
+	 * secondary id) already open in this page, it is given focus.
+	 *
+	 * @param viewId
+	 *            the id of the view extension to use
+	 * @return the shown view
+	 * @exception PartInitException
+	 *                if the view could not be initialized
+	 */
+	public IViewPart showView(String viewId) throws PartInitException;
+
+	/**
+	 * Shows a view in this page with the given id and secondary id. The
+	 * behaviour of this method varies based on the supplied mode. If
+	 * <code>VIEW_ACTIVATE</code> is supplied, the view is given focus. If
+	 * <code>VIEW_VISIBLE</code> is supplied, then it is made visible but not
+	 * given focus. Finally, if <code>VIEW_CREATE</code> is supplied the view is
+	 * created and will only be made visible if it is not created in a folder
+	 * that already contains visible views.
+	 * <p>
+	 * This allows multiple instances of a particular view to be created. They
+	 * are disambiguated using the secondary id. If a secondary id is given, the
+	 * view must allow multiple instances by having specified
+	 * allowMultiple="true" in its extension.
+	 * </p>
+	 *
+	 * @param viewId
+	 *            the id of the view extension to use
+	 * @param secondaryId
+	 *            the secondary id to use, or <code>null</code> for no secondary
+	 *            id
+	 * @param mode
+	 *            the activation mode. Must be {@link #VIEW_ACTIVATE},
+	 *            {@link #VIEW_VISIBLE} or {@link #VIEW_CREATE}
+	 * @return a view
+	 * @exception PartInitException
+	 *                if the view could not be initialized
+	 * @exception IllegalArgumentException
+	 *                if the supplied mode is not valid
+	 * @since 3.0
+	 */
+	public IViewPart showView(String viewId, String secondaryId, int mode)
+			throws PartInitException;
+
+	/**
+	 * Returns <code>true</code> if the editor is pinned and should not be
+	 * reused.
+	 *
+	 * @param editor
+	 *            the editor to test
+	 * @return boolean whether the editor is pinned
+	 */
+	public boolean isEditorPinned(IEditorPart editor);
+
+	/**
+	 * Returns the number of open editors before reusing editors.
+	 *
+	 * @return a int
+	 *
+	 * @deprecated
+	 */
+	@Deprecated
+	public int getEditorReuseThreshold();
+
+	/**
+	 * Set the number of open editors before reusing editors. If < 0 the user
+	 * preference settings will be used.
+	 *
+	 * @param openEditors
+	 *            the threshold
+	 * @deprecated use IPageLayout.setEditorReuseThreshold(int openEditors)
+	 *             instead.
+	 */
+	@Deprecated
+	public void setEditorReuseThreshold(int openEditors);
+
+	/**
+	 * Returns the navigation history which manages a list of entries keeping
+	 * the history of places (positions, selection and editors) the user visited
+	 * making it easier to the user to move back and forward without losing
+	 * context.
+	 *
+	 * @return the navigation history
+	 * @since 2.1
+	 */
+	public INavigationHistory getNavigationHistory();
+
+	/**
+	 * Returns an array of IViewParts that are stacked with the given part in
+	 * the currently active perspective.
+	 *
+	 * @param part
+	 *            the part to test
+	 * @return the parts that are stacked with this part, including the part in
+	 *         question. <code>null</code> is returned if the part does not
+	 *         belong to this page or the part is not contained in the active
+	 *         perspective. The parts are in LRU order.
+	 * @since 3.0
+	 */
+	IViewPart[] getViewStack(IViewPart part);
+
+	/**
+	 * Returns the new wizard shortcuts associated with the current perspective.
+	 * Returns an empty array if there is no current perspective.
+	 *
+	 * @see IPageLayout#addNewWizardShortcut(String)
+	 * @return an array of wizard identifiers
+	 * @since 3.1
+	 */
+	public String[] getNewWizardShortcuts();
+
+	/**
+	 * Returns the perspective shortcuts associated with the current
+	 * perspective. Returns an empty array if there is no current perspective.
+	 *
+	 * @see IPageLayout#addPerspectiveShortcut(String)
+	 * @return an array of perspective identifiers
+	 * @since 3.1
+	 */
+	public String[] getPerspectiveShortcuts();
+
+	/**
+	 * Returns the show view shortcuts associated with the current perspective.
+	 * Returns an empty array if there is no current perspective.
+	 *
+	 * @see IPageLayout#addShowViewShortcut(String)
+	 * @return an array of view identifiers
+	 * @since 3.1
+	 */
+	public String[] getShowViewShortcuts();
+
+	/**
+	 * Returns the descriptors for the perspectives that are open in this page,
+	 * in the order in which they were opened.
+	 *
+	 * @return the open perspective descriptors, in order of opening
+	 * @since 3.1
+	 */
+	public IPerspectiveDescriptor[] getOpenPerspectives();
+
+	/**
+	 * Returns the descriptors for the perspectives that are open in this page,
+	 * in the order in which they were activated (oldest first).
+	 *
+	 * @return the open perspective descriptors, in order of activation
+	 * @since 3.1
+	 */
+	public IPerspectiveDescriptor[] getSortedPerspectives();
+
+	/**
+	 * Closes the specified perspective in this page. If the last perspective in
+	 * this page is closed, then all editors are closed. Views that are not
+	 * shown in other perspectives are closed as well. If <code>saveParts</code>
+	 * is <code>true</code>, the user will be prompted to save any unsaved
+	 * changes for parts that are being closed. The page itself is closed if
+	 * <code>closePage</code> is <code>true</code>.
+	 *
+	 * @param desc
+	 *            the descriptor of the perspective to be closed
+	 * @param saveParts
+	 *            whether the page's parts should be saved if closed
+	 * @param closePage
+	 *            whether the page itself should be closed if last perspective
+	 * @since 3.1
+	 */
+	public void closePerspective(IPerspectiveDescriptor desc,
+			boolean saveParts, boolean closePage);
+
+	/**
+	 * Closes all perspectives in this page. All editors are closed, prompting
+	 * to save any unsaved changes if <code>saveEditors</code> is
+	 * <code>true</code>. The page itself is closed if <code>closePage</code>
+	 * is <code>true</code>.
+	 *
+	 * @param saveEditors
+	 *            whether the page's editors should be saved
+	 * @param closePage
+	 *            whether the page itself should be closed
+	 * @since 3.1
+	 */
+	public void closeAllPerspectives(boolean saveEditors, boolean closePage);
+
+	/**
+	 * <p>
+	 * Return the extension tracker for the workbench. This tracker may be used
+	 * by plug-ins to ensure responsiveness to changes to the plug-in registry.
+	 * </p>
+	 * <p>
+	 * The tracker at this level of the workbench is typically used to track
+	 * elements that only exist over the lifespan of a page. For example,
+	 * <code>ViewPart</code> objects fall into this category.
+	 * </p>
+	 *
+	 * @return the extension tracker
+	 * @see IWorkbench#getExtensionTracker()
+	 * @see IWorkbenchWindow#getExtensionTracker()
+	 * @since 3.1
+	 */
+	public IExtensionTracker getExtensionTracker();
+
+	/**
+	 * Return the visible working sets for this page. Please note that this
+	 * array is not filtered by activities. Clients should attempt to ensure
+	 * that any use of this method is consistant with the currently enabled
+	 * activity set.
+	 *
+	 * @return the visible working sets for this page
+	 * @see IWorkbench#getActivitySupport()
+	 * @since 3.2
+	 */
+	public IWorkingSet[] getWorkingSets();
+
+	/**
+	 * Set the working sets for this page. Any duplicate entries will be removed
+	 * from the array by this method.
+	 *
+	 * @param sets
+	 *            the new working sets for this page. The array may be empty,
+	 *            but no element in the array may be <code>null</code>.
+	 * @since 3.2
+	 */
+	public void setWorkingSets(IWorkingSet[] sets);
+
+	/**
+	 * Return a working set that contains all of the elements contained in the
+	 * array of working sets provided by {@link #getWorkingSets()}. Should this
+	 * array or the underlying elements in any of the working sets change this
+	 * set will be updated.
+	 *
+	 * <p>
+	 * This working set is never <code>null</code>, even if there are no
+	 * working sets assigned to this page via
+	 * {@link #setWorkingSets(IWorkingSet[])}. It is recommended that any
+	 * client that uses this API be aware of this and act accordingly.
+	 * Specifically, it is recommended that any client utilizing this or any
+	 * other IWorkingSet whose {@link IWorkingSet#isAggregateWorkingSet()}
+	 * returns <code>true</code> act as if they are not using any working set
+	 * if the set is empty. These clients should also maintain an awareness of
+	 * the contents of aggregate working sets and toggle this behavior should
+	 * the contents of the aggregate either become empty or non-empty.
+	 * </p>
+	 * <p>
+	 * Example: <br/> Here we have pseudocode showing how some workingset
+	 * utilizing component could react to changes in aggregate working sets.
+	 * <br/> <code>
+	 * private IWorkingSet myWorkingSet;
+	 *
+	 * IPropertyChangeListener workingSetListener = new IPropertyChangeListener() {
+	 *	public void propertyChange(PropertyChangeEvent event) {
+	 * 		if (isMyCurrentWorkingSet(event)) {
+	 * 			if (isEmptyAggregate(myWorkingSet)) {
+	 * 				showNoSet();
+	 * 			}
+	 * 			else {
+	 * 				showSet();
+	 * 			}
+	 *		}
+	 *	}
+	 * };
+	 *
+	 * public void setWorkingSet(IWorkingSet newSet) {
+	 * 		myWorkingSet = newSet;
+	 * 		if (myWorkingSet == null || isEmptyAggregate(myWorkingSet)){
+	 * 			showNoSet();
+	 * 		}
+	 * 		else {
+	 * 			showSet();
+	 * 		}
+	 * }
+	 * </code>
+	 * </p>
+	 *
+	 * @return the aggregate working set for this page, this implements
+	 *   {@link IAggregateWorkingSet}
+	 * @see IAggregateWorkingSet
+	 * @since 3.2
+	 */
+	public IWorkingSet getAggregateWorkingSet();
+
+	/**
+	 * Returns the page "zoomed" state.
+	 *
+	 * @return <code>true</code> if the page is zoomed in the workbench
+	 *         window, <code>false</code> otherwise.
+	 * @since 3.2
+	 */
+	public boolean isPageZoomed();
+
+	/**
+	 * Zooms out the zoomed-in part. If the page does not have a zoomed part, it
+	 * does nothing.
+	 *
+	 * @since 3.2
+	 */
+	public void zoomOut();
+
+	/**
+	 * Zoom the page in on a part. If the part is already in zoom then zoom out.
+	 *
+	 * @param ref
+	 *            the workbench part to zoom in on. Must not be
+	 *            <code>null</code>.
+	 * @since 3.2
+	 */
+	public void toggleZoom(IWorkbenchPartReference ref);
+
+	/**
+	 * Returns the maximized/minimized/restored state of the given part
+	 * reference.
+	 *
+	 * @param ref
+	 *            the workbench part to query. Must not be <code>null</code>.
+	 * @return one of the STATE_* contants.
+	 * @since 3.2
+	 */
+	public int getPartState(IWorkbenchPartReference ref);
+
+	/**
+	 * Set the state of the given part reference. Setting the state of one part
+	 * can effect the state of other parts.
+	 *
+	 * @param ref
+	 *            the workbench part reference. Must not be <code>null</code>.
+	 * @param state
+	 *            one of the STATE_* constants.
+	 * @since 3.2
+	 */
+	public void setPartState(IWorkbenchPartReference ref, int state);
+
+	/**
+	 * Find the part reference for the given part. A convenience method to
+	 * quickly go from part to part reference.
+	 *
+	 * @param part
+	 *            The part to search for. It can be <code>null</code>.
+	 * @return The reference for the given part, or <code>null</code> if no
+	 *         reference can be found.
+	 * @since 3.2
+	 */
+	public IWorkbenchPartReference getReference(IWorkbenchPart part);
+
+	/**
+	 * Add back an open but non-participating editor
+	 *
+	 * @param ref
+	 *            the editor to re-add. Must be an editor removed using
+	 *            #hideEditor(IEditorReference), must not have been closed,
+	 *            and must not be <code>null</code>.
+	 * @since 3.5
+	 * @see #hideEditor(IEditorReference)
+	 */
+	public void showEditor(IEditorReference ref);
+
+	/**
+	 * Remove an open editor, turn it into a non-participating editor.
+	 * <p>
+	 * A non-participating editor will not be returned in the list of open
+	 * editors ({@link #getEditorReferences()}) and will not be visible in the
+	 * editor area. However, it will continue to participate in the save
+	 * lifecycle and may still be closed by some workbench close events.
+	 * </p>
+	 * <p>
+	 * Behaviour for hiding and showing editors from multiple stacks is not
+	 * defined (and unsupported) at this time.
+	 * </p>
+	 *
+	 * @param ref
+	 *            the editor reference to remove. It must be a current open
+	 *            editor belonging to this page, and must not be
+	 *            <code>null</code>.
+	 * @since 3.5
+	 * @see #showEditor(IEditorReference)
+	 */
+	public void hideEditor(IEditorReference ref);
+
+	/**
+	 * Opens editors for the given inputs. Only the editor constructed for the first input
+	 * gets activated.
+	 * <p>
+	 * The editor type is determined by mapping <code>editorIDs</code> to an editor
+	 * extension registered with the workbench.  An editor id is passed rather than
+	 * an editor object to prevent the accidental creation of more than one editor
+	 * for the same input. It also guarantees a consistent lifecycle for editors,
+	 * regardless of whether they are created by the user or restored from saved
+	 * data.
+	 * </p><p>
+	 * The length of the input array and editor ID arrays must be the same. The editors
+	 * are opened using pairs of { input[i], editorIDs[i] }.
+	 * </p>
+	 * @param inputs the editor inputs
+	 * @param editorIDs the IDs of the editor extensions to use, in the order of inputs
+	 * @param matchFlags a bit mask consisting of zero or more of the MATCH_* constants OR-ed together
+	 * @return references to the editors constructed for the inputs. The editors
+	 * corresponding to those reference might not be materialized.
+	 * @exception MultiPartInitException if at least one editor could not be created or initialized
+	 * @see #MATCH_NONE
+	 * @see #MATCH_INPUT
+	 * @see #MATCH_ID
+	 * @since 3.5
+	 */
+	public IEditorReference[] openEditors(final IEditorInput[] inputs, final String[] editorIDs,
+			final int matchFlags) throws MultiPartInitException;
+
+	/**
+	 * Opens editors for the given inputs. Only the editor constructed for the
+	 * given index will be activated.
+	 * <p>
+	 * There are effectively two different ways to use this method based on what
+	 * information the supplied mementos contain @see
+	 * org.eclipse.ui.IWorkbenchPage
+	 * #getEditorState(org.eclipse.ui.IEditorReference []):
+	 * <ol>
+	 * <li>
+	 * If the mementos contain the 'input' information then only the memento
+	 * itself is required since it can be used to re-create the editor input and
+	 * its editorID. If all the mementos are of this type then the inputs and
+	 * editorIDs arrays may be null.</li>
+	 * <li>
+	 * If the supplied memento only contains the editor state then both the
+	 * input and editorID must be non-null.</li>
+	 * </ol>
+	 * </p>
+	 * <p>
+	 * The editor type is determined by mapping <code>editorIDs</code> to an
+	 * editor extension registered with the workbench. An editor id is passed
+	 * rather than an editor object to prevent the accidental creation of more
+	 * than one editor for the same input. It also guarantees a consistent
+	 * lifecycle for editors, regardless of whether they are created by the user
+	 * or restored from saved data.
+	 * </p>
+	 * <p>
+	 * The length of the input array and editor ID arrays must be the same. The
+	 * editors are opened using pairs of { input[i], editorIDs[i] }.
+	 * </p>
+	 * <p>
+	 * The mementos array mat be null but if not must match the input array in
+	 * length. Entries in the mementos array may also be null if no state is
+	 * desired for that particular editor.
+	 * </p>
+	 *
+	 * @param inputs
+	 *            the editor inputs
+	 * @param editorIDs
+	 *            the IDs of the editor extensions to use, in the order of
+	 *            inputs
+	 * @param mementos
+	 *            the mementos representing the state to open the editor with.
+	 *            If the supplied memento contains the input's state as well as
+	 *            the editor's state then the corresponding entries in the
+	 *            'inputs' and 'ids' arrays may be <code>null</code> (they will
+	 *            be created from the supplied memento).
+	 *
+	 * @param matchFlags
+	 *            a bit mask consisting of zero or more of the MATCH_* constants
+	 *            OR-ed together
+	 * @param activateIndex
+	 *            the index of the editor to make active or -1 if no activation
+	 *            is desired.
+	 * @return references to the editors constructed for the inputs. The editors
+	 *         corresponding to those reference might not be materialized.
+	 * @exception MultiPartInitException
+	 *                if at least one editor could not be created or initialized
+	 * @see #MATCH_NONE
+	 * @see #MATCH_INPUT
+	 * @see #MATCH_ID
+	 * @since 3.8.2
+	 */
+	public IEditorReference[] openEditors(final IEditorInput[] inputs, final String[] editorIDs,
+			final IMemento[] mementos, final int matchFlags, final int activateIndex)
+			throws MultiPartInitException;
+
+	/**
+	 * Return an IMemento containing the current state of the editor for each of
+	 * the given references. These mementos may be used to determine the initial
+	 * state of an editor on a subsequent open.
+	 *
+	 * @param editorRefs
+	 *            The array of editor references to get the state for
+	 * @param includeInputState
+	 *            If <code>true</code> then the resulting memento will be
+	 *            contain the editor input's state as well as the editor's
+	 *            state.
+	 * @return The array of mementos. The length of the array will match that of
+	 *         the refs array.
+	 * @since 3.8.2
+	 */
+	public IMemento[] getEditorState(IEditorReference[] editorRefs, boolean includeInputState);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchPart.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchPart.java
new file mode 100644
index 0000000..49fc4d2
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchPart.java
@@ -0,0 +1,226 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * A workbench part is a visual component within a workbench page.  There
+ * are two subtypes: view and editor, as defined by <code>IViewPart</code> and
+ * <code>IEditorPart</code>.
+ * <p>
+ * A view is typically used to navigate a hierarchy of information (like the
+ * workspace), open an editor, or display properties for the active editor.
+ * Modifications made in a view are saved immediately.
+ * </p><p>
+ * An editor is typically used to edit or browse a document or input object.
+ * The input is identified using an <code>IEditorInput</code>.  Modifications made
+ * in an editor part follow an open-save-close lifecycle model.
+ * </p><p>
+ * This interface may be implemented directly.  For convenience, a base
+ * implementation is defined in <code>WorkbenchPart</code>.
+ * </p><p>
+ * The lifecycle of a workbench part is as follows:
+ * <ul>
+ * 	<li>When a part extension is created:
+ *    <ul>
+ *		<li>instantiate the part</li>
+ *		<li>create a part site</li>
+ *		<li>call <code>part.init(site)</code></li>
+ * 	  </ul>
+ *  <li>When a part becomes visible in the workbench:
+ * 	  <ul>
+ *		<li>add part to presentation by calling
+ *        <code>part.createPartControl(parent)</code> to create actual widgets</li>
+ *		<li>fire <code>partOpened</code> event to all listeners</li>
+ *	  </ul>
+ *   </li>
+ *  <li>When a part is activated or gets focus:
+ *    <ul>
+ *		<li>call <code>part.setFocus()</code></li>
+ *		<li>fire <code>partActivated</code> event to all listeners</li>
+ *	  </ul>
+ *   </li>
+ *  <li>When a part is closed:
+ *    <ul>
+ *		<li>if save is needed, do save; if it fails or is canceled return</li>
+ *		<li>if part is active, deactivate part</li>
+ *		<li>fire <code>partClosed</code> event to all listeners</li>
+ *		<li>remove part from presentation; part controls are disposed as part
+ *         of the SWT widget tree
+ *		<li>call <code>part.dispose()</code></li>
+ *	  </ul>
+ *   </li>
+ * </ul>
+ * </p>
+ * <p>
+ * After <code>createPartControl</code> has been called, the implementor may
+ * safely reference the controls created.  When the part is closed
+ * these controls will be disposed as part of an SWT composite.  This
+ * occurs before the <code>IWorkbenchPart.dispose</code> method is called.
+ * If there is a need to free SWT resources the part should define a dispose
+ * listener for its own control and free those resources from the dispose
+ * listener.  If the part invokes any method on the disposed SWT controls
+ * after this point an <code>SWTError</code> will be thrown.
+ * </p>
+ * <p>
+ * The last method called on <code>IWorkbenchPart</code> is <code>dispose</code>.
+ * This signals the end of the part lifecycle.
+ * </p>
+ * <p>
+ * An important point to note about this lifecycle is that following
+ * a call to init, createPartControl may never be called. Thus in the dispose
+ * method, implementors must not assume controls were created.
+ * </p>
+ * <p>
+ * Workbench parts implement the <code>IAdaptable</code> interface; extensions
+ * are managed by the platform's adapter manager.
+ * </p>
+ *
+ * @see IViewPart
+ * @see IEditorPart
+ */
+public interface IWorkbenchPart extends IAdaptable {
+
+    /**
+     * The property id for <code>getTitle</code>, <code>getTitleImage</code>
+     * and <code>getTitleToolTip</code>.
+     */
+    public static final int PROP_TITLE = IWorkbenchPartConstants.PROP_TITLE;
+
+    /**
+     * Adds a listener for changes to properties of this workbench part.
+     * Has no effect if an identical listener is already registered.
+     * <p>
+     * The property ids are defined in {@link IWorkbenchPartConstants}.
+     * </p>
+     *
+     * @param listener a property listener
+     */
+    public void addPropertyListener(IPropertyListener listener);
+
+    /**
+     * Creates the SWT controls for this workbench part.
+     * <p>
+     * Clients should not call this method (the workbench calls this method when
+     * it needs to, which may be never).
+     * </p>
+     * <p>
+     * For implementors this is a multi-step process:
+     * <ol>
+     *   <li>Create one or more controls within the parent.</li>
+     *   <li>Set the parent layout as needed.</li>
+     *   <li>Register any global actions with the site's <code>IActionBars</code>.</li>
+     *   <li>Register any context menus with the site.</li>
+     *   <li>Register a selection provider with the site, to make it available to
+     *     the workbench's <code>ISelectionService</code> (optional). </li>
+     * </ol>
+     * </p>
+     *
+     * @param parent the parent control
+     */
+    public void createPartControl(Composite parent);
+
+    /**
+     * Disposes of this workbench part.
+     * <p>
+     * This is the last method called on the <code>IWorkbenchPart</code>.  At this
+     * point the part controls (if they were ever created) have been disposed as part
+     * of an SWT composite.  There is no guarantee that createPartControl() has been
+     * called, so the part controls may never have been created.
+     * </p>
+     * <p>
+     * Within this method a part may release any resources, fonts, images, etc.&nbsp;
+     * held by this part.  It is also very important to deregister all listeners
+     * from the workbench.
+     * </p>
+     * <p>
+     * Clients should not call this method (the workbench calls this method at
+     * appropriate times).
+     * </p>
+     */
+    public void dispose();
+
+    /**
+     * Returns the site for this workbench part. The site can be
+     * <code>null</code> while the workbench part is being initialized. After
+     * the initialization is complete, this value must be non-<code>null</code>
+     * for the remainder of the part's life cycle.
+     *
+     * @return The part site; this value may be <code>null</code> if the part
+     *         has not yet been initialized
+     */
+    public IWorkbenchPartSite getSite();
+
+    /**
+     * Returns the title of this workbench part. If this value changes
+     * the part must fire a property listener event with
+     * <code>PROP_TITLE</code>.
+     * <p>
+     * The title is used to populate the title bar of this part's visual
+     * container.
+     * </p>
+     *
+     * @return the workbench part title (not <code>null</code>)
+     */
+    public String getTitle();
+
+    /**
+     * Returns the title image of this workbench part.  If this value changes
+     * the part must fire a property listener event with
+     * <code>PROP_TITLE</code>.
+     * <p>
+     * The title image is usually used to populate the title bar of this part's
+     * visual container. Since this image is managed by the part itself, callers
+     * must <b>not</b> dispose the returned image.
+     * </p>
+     *
+     * @return the title image
+     */
+    public Image getTitleImage();
+
+    /**
+     * Returns the title tool tip text of this workbench part.
+     * An empty string result indicates no tool tip.
+     * If this value changes the part must fire a property listener event with
+     * <code>PROP_TITLE</code>.
+     * <p>
+     * The tool tip text is used to populate the title bar of this part's
+     * visual container.
+     * </p>
+     *
+     * @return the workbench part title tool tip (not <code>null</code>)
+     */
+    public String getTitleToolTip();
+
+    /**
+	 * Removes the given property listener from this workbench part. Has no
+	 * effect if an identical listener is not registered.
+	 *
+	 * @param listener
+	 *            a property listener
+	 */
+    public void removePropertyListener(IPropertyListener listener);
+
+    /**
+     * Asks this part to take focus within the workbench. Parts must
+     * assign focus to one of the controls contained in the part's
+     * parent composite.
+     * <p>
+     * Clients should not call this method (the workbench calls this method at
+     * appropriate times).  To have the workbench activate a part, use
+     * <code>IWorkbenchPage.activate(IWorkbenchPart) instead</code>.
+     * </p>
+     */
+    public void setFocus();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchPart2.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchPart2.java
new file mode 100644
index 0000000..b31ff55
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchPart2.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui;
+
+/**
+ * Extends {@link IWorkbenchPart}, adding the name and status text properties.
+ * Prior to 3.0, a view's title was often modified to show both the part
+ * name and extra status text.  With this interface, the distinction is
+ * made more explicit.
+ *
+ * @since 3.0
+ */
+public interface IWorkbenchPart2 extends IWorkbenchPart {
+    /**
+     * Returns the name of this part. If this value changes the part must fire a
+     * property listener event with {@link IWorkbenchPartConstants#PROP_PART_NAME}.
+     *
+     * @return the name of this view, or the empty string if the name is being managed
+     * by the workbench (not <code>null</code>)
+     */
+    public String getPartName();
+
+    /**
+     * Returns the content description of this part. The content description is an optional
+     * user-readable string that describes what is currently being displayed in the part.
+     * By default, the workbench will display the content description in a line
+     * near the top of the view or editor.
+     * An empty string indicates no content description
+     * text. If this value changes the part must fire a property listener event
+     * with {@link IWorkbenchPartConstants#PROP_CONTENT_DESCRIPTION}.
+     *
+     * @return the content description of this part (not <code>null</code>)
+     */
+    public String getContentDescription();
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchPart3.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchPart3.java
new file mode 100644
index 0000000..8a19d98
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchPart3.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui;
+
+import java.util.Map;
+import org.eclipse.jface.util.IPropertyChangeListener;
+
+/**
+ * A part can provide arbitrary properties. The properties will be persisted
+ * between sessions by the part reference, and will be available from the part
+ * reference as well as the part. The properties can only be set on a part, not
+ * on the reference. The properties will be available to the IPresentablePart.
+ * <p>
+ * Setting a property must fire a PropertyChangeEvent.
+ * </p>
+ *
+ * @since 3.3
+ */
+public interface IWorkbenchPart3 extends IWorkbenchPart2 {
+	/**
+	 * Add a listener for changes in the arbitrary properties set.
+	 * <p>
+	 * <b>Note:</b> this is a different set of properties than the ones covered
+	 * by the IWorkbenchPartConstants.PROP_* constants.
+	 * </p>
+	 *
+	 * @param listener
+	 *            Must not be <code>null</code>.
+	 */
+	public void addPartPropertyListener(IPropertyChangeListener listener);
+
+	/**
+	 * Remove a change listener from the arbitrary properties set.
+	 * <p>
+	 * <b>Note:</b> this is a different set of properties than the ones covered
+	 * by the IWorkbenchPartConstants.PROP_* constants.
+	 * </p>
+	 *
+	 * @param listener
+	 *            Must not be <code>null</code>.
+	 */
+	public void removePartPropertyListener(IPropertyChangeListener listener);
+
+	/**
+	 * Return the value for the arbitrary property key, or <code>null</code>.
+	 *
+	 * @param key
+	 *            the arbitrary property. Must not be <code>null</code>.
+	 * @return the property value, or <code>null</code>.
+	 */
+	public String getPartProperty(String key);
+
+	/**
+	 * Set an arbitrary property on the part. It is the implementor's
+	 * responsibility to fire the corresponding PropertyChangeEvent.
+	 * <p>
+	 * A default implementation has been added to WorkbenchPart.
+	 * </p>
+	 *
+	 * @param key
+	 *            the arbitrary property. Must not be <code>null</code>.
+	 * @param value
+	 *            the property value. A <code>null</code> value will remove
+	 *            that property.
+	 */
+	public void setPartProperty(String key, String value);
+
+	/**
+	 * Return an unmodifiable map of the arbitrary properties. This method can
+	 * be used to save the properties during workbench save/restore.
+	 *
+	 * @return A Map of the properties. Must not be <code>null</code>.
+	 */
+	public Map<String, String> getPartProperties();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchPartConstants.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchPartConstants.java
new file mode 100644
index 0000000..8284a1b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchPartConstants.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Stefan Xenos, IBM; Chris Torrence, ITT Visual Information Solutions - bug 51580
+ *******************************************************************************/
+package org.eclipse.ui;
+
+/**
+ * This interface describes the constants used for <link>IWorkbenchPart</link> properties.
+ * <p>
+ * <b>Note:</b>This interface should not be implemented or extended.
+ * </p>
+ *
+ * @since 3.0
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IWorkbenchPartConstants {
+
+    /**
+     * The property id for <code>getTitle</code>, <code>getTitleImage</code>
+     * and <code>getTitleToolTip</code>.
+     */
+    int PROP_TITLE = 0x001;
+
+    /**
+     * The property id for <code>ISaveablePart.isDirty()</code>.
+     */
+    int PROP_DIRTY = 0x101;
+
+    /**
+     * The property id for <code>IEditorPart.getEditorInput()</code>.
+     */
+    int PROP_INPUT = 0x102;
+
+    /**
+     * The property id for <code>IWorkbenchPart2.getPartName</code>
+     */
+    int PROP_PART_NAME = 0x104;
+
+    /**
+     * The property id for <code>IWorkbenchPart2.getContentDescription()</code>
+     */
+    int PROP_CONTENT_DESCRIPTION = 0x105;
+
+    /**
+     * The property id for any method on the optional <code>ISizeProvider</code> interface
+     * @since 3.4
+     */
+    int PROP_PREFERRED_SIZE = 0x303;
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchPartDescriptor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchPartDescriptor.java
new file mode 100644
index 0000000..9fd7581
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchPartDescriptor.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+
+/**
+ * Description of a workbench part. The part descriptor contains
+ * the information needed to create part instances.
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IWorkbenchPartDescriptor {
+    /**
+     * Returns the part id.
+     *
+     * @return the id of the part
+     */
+    public String getId();
+
+    /**
+     * Returns the descriptor of the image for this part.
+     *
+     * @return the descriptor of the image to display next to this part
+     */
+    public ImageDescriptor getImageDescriptor();
+
+    /**
+     * Returns the label to show for this part.
+     *
+     * @return the part label
+     */
+    public String getLabel();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchPartReference.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchPartReference.java
new file mode 100644
index 0000000..4089825
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchPartReference.java
@@ -0,0 +1,130 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 20158 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.ui;
+
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * Implements a reference to a IWorkbenchPart.
+ * The IWorkbenchPart will not be instantiated until the part
+ * becomes visible or the API getPart is sent with true;
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IWorkbenchPartReference {
+	/**
+	 * Returns the IWorkbenchPart referenced by this object.
+	 *
+	 * @param restore
+	 *            tries to restore the part if <code>true</code>.
+	 * @return the part, or <code>null</code> if the part was not instantiated
+	 *         or it failed to be restored.
+	 */
+    public IWorkbenchPart getPart(boolean restore);
+
+    /**
+     * @see IWorkbenchPart#getTitle
+     */
+    public String getTitle();
+
+    /**
+     * @see IWorkbenchPart#getTitleImage
+     */
+    public Image getTitleImage();
+
+    /**
+     * @see IWorkbenchPart#getTitleToolTip
+     */
+    public String getTitleToolTip();
+
+    /**
+     * @see IWorkbenchPartSite#getId
+     */
+    public String getId();
+
+    /**
+     * @see IWorkbenchPart#addPropertyListener
+     */
+    public void addPropertyListener(IPropertyListener listener);
+
+    /**
+     * @see IWorkbenchPart#removePropertyListener
+     */
+    public void removePropertyListener(IPropertyListener listener);
+
+    /**
+     * Returns the workbench page that contains this part
+     */
+    public IWorkbenchPage getPage();
+
+    /**
+     * Returns the name of the part, as it should be shown in tabs.
+     *
+     * @return the part name
+     *
+     * @since 3.0
+     */
+    public String getPartName();
+
+    /**
+     * Returns the content description for the part (or the empty string if none)
+     *
+     * @return the content description for the part
+     *
+     * @since 3.0
+     */
+    public String getContentDescription();
+
+
+    /**
+     * Returns whether the part is dirty (i.e. has unsaved changes).
+     *
+     * @return <code>true</code> if the part is dirty, <code>false</code> otherwise
+     *
+     * @since 3.2 (previously existed on IEditorReference)
+     */
+    public boolean isDirty();
+
+    /**
+	 * Return an arbitrary property from the reference. If the part has been
+	 * instantiated, it just delegates to the part. If not, then it looks in its
+	 * own cache of properties. If the property is not available or the part has
+	 * never been instantiated, it can return <code>null</code>.
+	 *
+	 * @param key
+	 *            The property to return. Must not be <code>null</code>.
+	 * @return The String property, or <code>null</code>.
+	 * @since 3.3
+	 */
+    public String getPartProperty(String key);
+
+    /**
+	 * Add a listener for changes in the arbitrary properties set.
+	 *
+	 * @param listener
+	 *            Must not be <code>null</code>.
+	 * @since 3.3
+	 */
+    public void addPartPropertyListener(IPropertyChangeListener listener);
+
+    /**
+	 * Remove a listener for changes in the arbitrary properties set.
+	 *
+	 * @param listener
+	 *            Must not be <code>null</code>.
+	 * @since 3.3
+	 */
+    public void removePartPropertyListener(IPropertyChangeListener listener);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchPartSite.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchPartSite.java
new file mode 100644
index 0000000..631dead
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchPartSite.java
@@ -0,0 +1,136 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.ui.contexts.IContextService;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * The primary interface between a workbench part and the workbench.
+ * <p>
+ * This interface is not intended to be implemented or extended by clients.
+ * </p>
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IWorkbenchPartSite extends IWorkbenchSite {
+
+    /**
+     * Returns the part registry extension id for this workbench site's part.
+     * <p>
+     * The name comes from the <code>id</code> attribute in the configuration
+     * element.
+     * </p>
+     *
+     * @return the registry extension id
+     */
+    public String getId();
+
+    /**
+     * Returns the unique identifier of the plug-in that defines this workbench
+     * site's part.
+     *
+     * @return the unique identifier of the declaring plug-in
+     */
+    public String getPluginId();
+
+    /**
+     * Returns the registered name for this workbench site's part.
+     * <p>
+     * The name comes from the <code>name</code> attribute in the configuration
+     * element.
+     * </p>
+     *
+     * @return the part name
+     */
+    public String getRegisteredName();
+
+    /**
+     * Registers a pop-up menu with a particular id for extension.
+     * This method should only be called if the target part has more
+     * than one context menu to register.
+     * <p>
+     * For a detailed description of context menu registration see
+     * <code>registerContextMenu(MenuManager, ISelectionProvider);
+     * </p>
+     *
+     * @param menuId the menu id
+     * @param menuManager the menu manager
+     * @param selectionProvider the selection provider
+     */
+    public void registerContextMenu(String menuId, MenuManager menuManager,
+            ISelectionProvider selectionProvider);
+
+    /**
+     * Registers a pop-up menu with the default id for extension.
+     * The default id is defined as the part id.
+     * <p>
+     * Within the workbench one plug-in may extend the pop-up menus for a view
+     * or editor within another plug-in.  In order to be eligible for extension,
+     * the target part must publish each menu by calling <code>registerContextMenu</code>.
+     * Once this has been done the workbench will automatically insert any action
+     * extensions which exist.
+     * </p>
+     * <p>
+     * A menu id must be provided for each registered menu.  For consistency across
+     * parts the following strategy should be adopted by all part implementors.
+     * </p>
+     * <ol>
+     *		<li>If the target part has only one context menu it should be registered
+     *			with <code>id == part id</code>.  This can be done easily by calling
+     *			<code>registerContextMenu(MenuManager, ISelectionProvider)</code>.
+     *		<li>If the target part has more than one context menu a unique id should be
+     *			defined for each.  Prefix each menu id with the part id and publish these
+     *			ids within the javadoc for the target part.  Register each menu at
+     *			runtime by calling <code>registerContextMenu(String, MenuManager,
+     *			ISelectionProvider)</code>.  </li>
+     * </ol>
+     * <p>
+     * Any pop-up menu which is registered with the workbench should also define a
+     * <code>GroupMarker</code> in the registered menu with id
+     * <code>IWorkbenchActionConstants.MB_ADDITIONS</code>.  Other plug-ins will use this
+     * group as a reference point for insertion.  The marker should be defined at an
+     * appropriate location within the menu for insertion.
+     * </p>
+     *
+     * @param menuManager the menu manager
+     * @param selectionProvider the selection provider
+     */
+    public void registerContextMenu(MenuManager menuManager,
+            ISelectionProvider selectionProvider);
+
+    /**
+	 * Returns the key binding service in use.
+	 * <p>
+	 * The part will access this service to register all of its actions, to set
+	 * the active scope.
+	 * </p>
+	 *
+	 * @return the key binding service in use
+	 * @since 2.1
+	 * @deprecated Use {@link IServiceLocator#getService(Class)} instead.
+	 * @see IContextService
+	 * @see IHandlerService
+	 */
+    @Deprecated
+	public IKeyBindingService getKeyBindingService();
+
+    /**
+     * Returns the part associated with this site
+     *
+     * @since 3.1
+     *
+     * @return the part associated with this site
+     */
+    public IWorkbenchPart getPart();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchPreferenceConstants.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchPreferenceConstants.java
new file mode 100644
index 0000000..7bdd3a0
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchPreferenceConstants.java
@@ -0,0 +1,614 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Kiryl Kazakevich, Intel - bug 88359
+ *     Tonny Madsen, RCP Company - bug 201055
+ *     Mark Hoffmann <mark.hoffmann@web.de> - Fix for bug 84603
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 440136
+ *******************************************************************************/
+package org.eclipse.ui;
+
+import org.eclipse.swt.SWT;
+
+/**
+ * Preference ids exposed by the Eclipse Platform User Interface. These
+ * preference settings can be obtained from the UI plug-in's preference store.
+ * <p>
+ * <b>Note:</b>This interface should not be implemented or extended.
+ * </p>
+ *
+ * @see PlatformUI#PLUGIN_ID
+ * @see PlatformUI#getPreferenceStore()
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noextend This interface is not intended to be extended by clients.
+ */
+public interface IWorkbenchPreferenceConstants {
+
+	/**
+	 * A named preference for whether to show an editor when its input file is
+	 * selected in the Navigator (and vice versa).
+	 * <p>
+	 * Value is of type <code>boolean</code>.
+	 * </p>
+	 */
+	public static final String LINK_NAVIGATOR_TO_EDITOR = "LINK_NAVIGATOR_TO_EDITOR"; //$NON-NLS-1$
+
+	/**
+	 * A named preference for how a new perspective is opened.
+	 * <p>
+	 * Value is of type <code>String</code>. The possible values are defined
+	 * by <code>OPEN_PERSPECTIVE_WINDOW, OPEN_PERSPECTIVE_PAGE and
+	 * OPEN_PERSPECTIVE_REPLACE</code>.
+	 * </p>
+	 *
+	 * @see #OPEN_PERSPECTIVE_WINDOW
+	 * @see #OPEN_PERSPECTIVE_PAGE
+	 * @see #OPEN_PERSPECTIVE_REPLACE
+	 * @see #NO_NEW_PERSPECTIVE
+	 */
+	public static final String OPEN_NEW_PERSPECTIVE = "OPEN_NEW_PERSPECTIVE"; //$NON-NLS-1$
+
+	/**
+	 * A named preference for how a new perspective is opened when the alternate
+	 * key modifiers are pressed. The alternate key modifiers are platform
+	 * dependent.
+	 * <p>
+	 * Value is of type <code>String</code>. The possible values are defined
+	 * by <code>OPEN_PERSPECTIVE_WINDOW, OPEN_PERSPECTIVE_PAGE and
+	 * OPEN_PERSPECTIVE_REPLACE</code>.
+	 * </p>
+	 *
+	 * @deprecated Workbench no longer supports alternate key modifier to open a
+	 *             new perspective. Callers should use
+	 *             IWorkbench.showPerspective methods.
+	 */
+	@Deprecated
+	public static final String ALTERNATE_OPEN_NEW_PERSPECTIVE = "ALTERNATE_OPEN_NEW_PERSPECTIVE"; //$NON-NLS-1$
+
+	/**
+	 * A named preference for how a new perspective is opened when the shift key
+	 * modifier is pressed.
+	 * <p>
+	 * Value is of type <code>String</code>. The possible values are defined
+	 * by <code>OPEN_PERSPECTIVE_WINDOW, OPEN_PERSPECTIVE_PAGE and
+	 * OPEN_PERSPECTIVE_REPLACE</code>.
+	 * </p>
+	 *
+	 * @deprecated Workbench no longer supports shift key modifier to open a new
+	 *             perspective. Callers should use IWorkbench.showPerspective
+	 *             methods.
+	 */
+	@Deprecated
+	public static final String SHIFT_OPEN_NEW_PERSPECTIVE = "SHIFT_OPEN_NEW_PERSPECTIVE"; //$NON-NLS-1$
+
+	/**
+	 * A named preference for how a new perspective should be opened when a new
+	 * project is created.
+	 * <p>
+	 * Value is of type <code>String</code>. The possible values are defined
+	 * by the constants <code>OPEN_PERSPECTIVE_WINDOW, OPEN_PERSPECTIVE_PAGE,
+	 * OPEN_PERSPECTIVE_REPLACE, and NO_NEW_PERSPECTIVE</code>.
+	 * </p>
+	 *
+	 * @see #OPEN_PERSPECTIVE_WINDOW
+	 * @see #OPEN_PERSPECTIVE_PAGE
+	 * @see #OPEN_PERSPECTIVE_REPLACE
+	 * @see #NO_NEW_PERSPECTIVE
+	 * @deprecated in 3.0. This preference is IDE-specific, and is therefore
+	 *             found only in IDE configurations. IDE-specific tools should
+	 *             use
+	 *             <code>org.eclipse.ui.ide.IDE.Preferences.PROJECT_OPEN_NEW_PERSPECTIVE</code>
+	 *             instead.
+	 */
+	@Deprecated
+	public static final String PROJECT_OPEN_NEW_PERSPECTIVE = "PROJECT_OPEN_NEW_PERSPECTIVE"; //$NON-NLS-1$
+
+	/**
+	 * A preference value indicating that an action should open a new
+	 * perspective in a new window.
+	 *
+	 * @see #PROJECT_OPEN_NEW_PERSPECTIVE
+	 */
+	public static final String OPEN_PERSPECTIVE_WINDOW = "OPEN_PERSPECTIVE_WINDOW"; //$NON-NLS-1$
+
+	/**
+	 * A preference value indicating that an action should open a new
+	 * perspective in a new page.
+	 *
+	 * @see #PROJECT_OPEN_NEW_PERSPECTIVE
+	 * @deprecated Opening a Perspective in a new page is no longer supported
+	 *             functionality as of 2.0.
+	 */
+	@Deprecated
+	public static final String OPEN_PERSPECTIVE_PAGE = "OPEN_PERSPECTIVE_PAGE"; //$NON-NLS-1$
+
+	/**
+	 * A preference value indicating that an action should open a new
+	 * perspective by replacing the current perspective.
+	 *
+	 * @see #PROJECT_OPEN_NEW_PERSPECTIVE
+	 */
+	public static final String OPEN_PERSPECTIVE_REPLACE = "OPEN_PERSPECTIVE_REPLACE"; //$NON-NLS-1$
+
+	/**
+	 * A preference value indicating that an action should not open a new
+	 * perspective.
+	 *
+	 * @see #PROJECT_OPEN_NEW_PERSPECTIVE
+	 */
+	public static final String NO_NEW_PERSPECTIVE = "NO_NEW_PERSPECTIVE"; //$NON-NLS-1$
+
+	/**
+	 * A named preference indicating the default workbench perspective.
+	 */
+	public static final String DEFAULT_PERSPECTIVE_ID = "defaultPerspectiveId"; //$NON-NLS-1$
+
+	/**
+	 * A named preference indicating the presentation factory to use for the
+	 * workbench look and feel.
+	 */
+	public static final String PRESENTATION_FACTORY_ID = "presentationFactoryId"; //$NON-NLS-1$
+	
+	/**
+	 * A named preference indicating where the perspective bar should be docked.
+	 * The default value (when this preference is not set) is
+	 * <code>TOP_RIGHT</code>.
+	 * <p>
+	 * This preference may be one of the following values: {@link #TOP_RIGHT},
+	 * {@link #TOP_LEFT}, or {@link #LEFT}.
+	 * </p>
+	 *
+	 * @since 3.0
+	 */
+	public static String DOCK_PERSPECTIVE_BAR = "DOCK_PERSPECTIVE_BAR"; //$NON-NLS-1$
+
+	/**
+	 * A preference indication the initial size of the perspective bar. The default value is 160.
+	 * This preference only works when <code>configurer.setShowPerspectiveBar(true)</code> is set in
+	 * WorkbenchWindowAdvisor#preWindowOpen()
+	 *
+	 * This preference only uses integer values
+	 * bug 84603: [RCP] [PerspectiveBar] New API or pref to set default perspective bar size
+	 *
+	 *  @since 3.5
+	 */
+	public static String PERSPECTIVE_BAR_SIZE = "PERSPECTIVE_BAR_SIZE"; //$NON-NLS-1$
+
+	/**
+	 * A named preference indicating where the fast view bar should be docked in
+	 * a fresh workspace. This preference is meaningless after a workspace has
+	 * been setup, since the fast view bar state is then persisted in the
+	 * workbench. This preference is intended for applications that want the
+	 * initial docking location to be somewhere specific. The default value
+	 * (when this preference is not set) is the bottom.
+	 *
+	 * @see #LEFT
+	 * @see #BOTTOM
+	 * @see #RIGHT
+	 * @since 3.0
+	 */
+	public static final String INITIAL_FAST_VIEW_BAR_LOCATION = "initialFastViewBarLocation"; //$NON-NLS-1$
+
+	/**
+	 * Constant to be used when referring to the top right of the workbench
+	 * window.
+	 *
+	 * @see #DOCK_PERSPECTIVE_BAR
+	 * @since 3.0
+	 */
+	public static final String TOP_RIGHT = "topRight"; //$NON-NLS-1$
+
+	/**
+	 * Constant to be used when referring to the top left of the workbench
+	 * window.
+	 *
+	 * @see #DOCK_PERSPECTIVE_BAR
+	 * @since 3.0
+	 */
+	public static final String TOP_LEFT = "topLeft"; //$NON-NLS-1$
+
+	/**
+	 * Constant to be used when referring to the left side of the workbench
+	 * window.
+	 *
+	 * @see #DOCK_PERSPECTIVE_BAR
+	 * @see #INITIAL_FAST_VIEW_BAR_LOCATION
+	 * @since 3.0
+	 */
+	public static final String LEFT = "left"; //$NON-NLS-1$
+
+	/**
+	 * Constant to be used when referring to the bottom of the workbench window.
+	 *
+	 * @see #INITIAL_FAST_VIEW_BAR_LOCATION
+	 * @since 3.0
+	 */
+	public static final String BOTTOM = "bottom"; //$NON-NLS-1$
+
+	/**
+	 * Constant to be used when referring to the right side of the workbench
+	 * window.
+	 *
+	 * @see #INITIAL_FAST_VIEW_BAR_LOCATION
+	 * @since 3.0
+	 */
+	public static final String RIGHT = "right"; //$NON-NLS-1$
+
+	/**
+	 * A named preference indicating whether the workbench should show the
+	 * introduction component (if available) on startup.
+	 *
+	 * <p>
+	 * The default value for this preference is: <code>true</code> (show
+	 * intro)
+	 * </p>
+	 *
+	 * @see org.eclipse.ui.application.WorkbenchWindowAdvisor#openIntro()
+	 * @since 3.0
+	 */
+	public static final String SHOW_INTRO = "showIntro"; //$NON-NLS-1$
+
+	/**
+	 * A named preference for whether the workbench should show traditional
+	 * style tabs in editors and views.
+	 *
+	 * Boolean-valued: <code>true</code> if editors and views should use a
+	 * traditional style of tab and <code>false</code> if editors should show
+	 * new style tab (3.0 style)
+	 * <p>
+	 * The default value for this preference is: <code>true</code>
+	 * </p>
+	 *
+	 * @since 3.0
+	 */
+	public static String SHOW_TRADITIONAL_STYLE_TABS = "SHOW_TRADITIONAL_STYLE_TABS"; //$NON-NLS-1$
+
+	/**
+	 * A named preference for whether the workbench should show text on the
+	 * perspective bar.
+	 *
+	 * Boolean-valued: <code>true</code>, if editors should show text on the
+	 * perspective bar, <code>false</code> otherwise.
+	 * <p>
+	 * The default value for this preference is: <code>true</code> (show text
+	 * on the perspective bar)
+	 * </p>
+	 *
+	 * @since 3.0
+	 */
+	public static String SHOW_TEXT_ON_PERSPECTIVE_BAR = "SHOW_TEXT_ON_PERSPECTIVE_BAR"; //$NON-NLS-1$
+
+	/**
+	 * A named preference for whether the workbench should show the "open
+	 * perspective" button on the perspective bar.
+	 *
+	 * Boolean-valued: <code>true</code>, if editors should show "open
+	 * perspective" button on the perspective bar, <code>false</code>
+	 * otherwise.
+	 * <p>
+	 * The default value for this preference is: <code>true</code> (show "open
+	 * perspective" button on the perspective bar)
+	 * </p>
+	 *
+	 * @since 3.4
+	 */
+	public static String SHOW_OPEN_ON_PERSPECTIVE_BAR = "SHOW_OPEN_ON_PERSPECTIVE_BAR"; //$NON-NLS-1$
+
+	/**
+	 * A named preference for whether the workbench should show the "Other..."
+	 * menu item in the perspective menu.
+	 *
+	 * Boolean-valued: <code>true</code>, if editors should show text on the
+	 * "Other..." menu item, <code>false</code> otherwise.
+	 * <p>
+	 * The default value for this preference is: <code>true</code> (show the
+	 * "Other..." menu item in the perspective menu)
+	 * </p>
+	 *
+	 * @since 3.4
+	 */
+	public static String SHOW_OTHER_IN_PERSPECTIVE_MENU = "SHOW_OTHER_IN_PERSPECTIVE_MENU"; //$NON-NLS-1$
+
+	/**
+	 * A named preference for the text of the Help Contents action.
+	 *
+	 * String-valued. If not specified, <code>"&Help Contents"</code> is used.
+	 * <p>
+	 * The default value for this preference is: <code>null</code>
+	 * </p>
+	 *
+	 * @since 3.0
+	 */
+	public static String HELP_CONTENTS_ACTION_TEXT = "helpContentsActionText"; //$NON-NLS-1$
+
+	/**
+	 * A named preference for the text of the Help Search action.
+	 *
+	 * String-valued. If not specified, <code>"S&earch"</code> is used.
+	 * <p>
+	 * The default value for this preference is: <code>null</code>
+	 * </p>
+	 *
+	 * @since 3.1
+	 */
+	public static String HELP_SEARCH_ACTION_TEXT = "helpSearchActionText"; //$NON-NLS-1$
+
+	/**
+	 * A named preference for the text of the Dynamic Help action.
+	 *
+	 * String-valued. If not specified, <code>"&Dynamic Help"</code> is used.
+	 * <p>
+	 * The default value for this preference is: <code>null</code>
+	 * </p>
+	 *
+	 * @since 3.1
+	 */
+	public static String DYNAMIC_HELP_ACTION_TEXT = "dynamicHelpActionText"; //$NON-NLS-1$
+
+	/**
+	 * A named preference for enabling animations when a layout transition
+	 * occurs
+	 * <p>
+	 * The default value for this preference is: <code>true</code> (show
+	 * animations when a transition occurs)
+	 * </p>
+	 *
+	 * @since 3.1
+	 */
+	public static final String ENABLE_ANIMATIONS = "ENABLE_ANIMATIONS"; //$NON-NLS-1$
+
+	/**
+	 * A named preference that view implementors can used to determine whether
+	 * or not they should utilize colored labels.
+	 *
+	 * <p>
+	 * The default value for this preference is: <code>true</code> (show
+	 * colored labels)
+	 * </p>
+	 *
+	 * @since 3.4
+	 */
+	public static final String USE_COLORED_LABELS = "USE_COLORED_LABELS"; //$NON-NLS-1$
+
+	/**
+	 * <p>
+	 * Workbench preference id for the key configuration identifier to be
+	 * treated as the default.
+	 * </p>
+	 * <p>
+	 * The default value for this preference is
+	 * <code>"org.eclipse.ui.defaultAcceleratorConfiguration"</code>.
+	 * <p>
+	 *
+	 * @since 3.1
+	 */
+	public static final String KEY_CONFIGURATION_ID = "KEY_CONFIGURATION_ID"; //$NON-NLS-1$
+
+	/**
+	 * <p>
+	 * Workbench preference identifier for the minimum width of editor tabs. By
+	 * default, Eclipse does not define this value and allows SWT to determine
+	 * this constant. We use <code>-1</code> internally to signify "use
+	 * default".
+	 * </p>
+	 * <p>
+	 * The default value for this preference is <code>-1</code>.
+	 * </p>
+	 *
+	 * @since 3.1
+	 */
+	public static final String EDITOR_MINIMUM_CHARACTERS = "EDITOR_MINIMUM_CHARACTERS"; //$NON-NLS-1$
+
+	/**
+	 * <p>
+	 * Workbench preference identifier for the minimum width of view tabs.
+	 * </p>
+	 * <p>
+	 * The default value for this preference is <code>1</code>.
+	 * </p>
+	 *
+	 * @since 3.2
+	 */
+	public static final String VIEW_MINIMUM_CHARACTERS = "VIEW_MINIMUM_CHARACTERS"; //$NON-NLS-1$
+
+	/**
+	 * Stores whether or not system jobs are being shown.
+	 *
+	 * @since 3.1
+	 */
+	public static final String SHOW_SYSTEM_JOBS = "SHOW_SYSTEM_JOBS";//$NON-NLS-1$
+
+	/**
+	 * Workbench preference for the current theme.
+	 *
+	 * @since 3.1
+	 */
+	public static String CURRENT_THEME_ID = "CURRENT_THEME_ID"; //$NON-NLS-1$
+
+	/**
+	 * A preference value indicating whether editors should be closed before
+	 * saving the workbench state when exiting. The default is
+	 * <code>false</code>.
+	 *
+	 * @since 3.1
+	 */
+	public static final String CLOSE_EDITORS_ON_EXIT = "CLOSE_EDITORS_ON_EXIT"; //$NON-NLS-1$
+
+	/**
+	 * Stores whether or not to show progress while starting the workbench. The
+	 * default is <code>false</code>.
+	 *
+	 * @since 3.1
+	 */
+	public static final String SHOW_PROGRESS_ON_STARTUP = "SHOW_PROGRESS_ON_STARTUP"; //$NON-NLS-1$
+
+	/**
+	 * Stores whether or not to show the memory monitor in the workbench window.
+	 *
+	 * @since 3.1
+	 */
+	public static final String SHOW_MEMORY_MONITOR = "SHOW_MEMORY_MONITOR"; //$NON-NLS-1$
+
+	/**
+	 * Stores whether or not to use the window working set as the default
+	 * working set for newly created views (without previously stored state).
+	 * This is a hint that view implementors should honor.
+	 *
+	 * @since 3.2
+	 */
+	public static final String USE_WINDOW_WORKING_SET_BY_DEFAULT = "USE_WINDOW_WORKING_SET_BY_DEFAULT"; //$NON-NLS-1$
+
+	/**
+	 * Stores whether or not to show the text widget that allows type-ahead
+	 * search in the case where a FilteredTree is used to display and filter
+	 * tree items.
+	 *
+	 * @since 3.2
+	 */
+	public static final String SHOW_FILTERED_TEXTS = "SHOW_FILTERED_TEXTS"; //$NON-NLS-1$
+
+	/**
+	 * Stores whether or not views may be detached. The default is
+	 * <code>true</code>.
+	 *
+	 * @since 3.2
+	 */
+	public static final String ENABLE_DETACHED_VIEWS = "ENABLE_DETACHED_VIEWS"; //$NON-NLS-1$
+
+	/**
+	 * Stores whether or not the workbench prompts for saving when a dirty
+	 * editor or view is closed, but the Saveable objects are still open in
+	 * other parts. If <code>true</code> (default), the user will be prompted.
+	 * If <code>false</code>, there will be no prompt.
+	 *
+	 * @see Saveable
+	 * @since 3.2
+	 */
+	public static final String PROMPT_WHEN_SAVEABLE_STILL_OPEN = "PROMPT_WHEN_SAVEABLE_STILL_OPEN"; //$NON-NLS-1$
+
+	/**
+	 * Lists the extra perspectives to show in the perspective bar. The value is
+	 * a comma-separated list of perspective ids. The default is the empty
+	 * string.
+	 *
+	 * @since 3.2
+	 */
+	public static final String PERSPECTIVE_BAR_EXTRAS = "PERSPECTIVE_BAR_EXTRAS"; //$NON-NLS-1$
+
+	/**
+	 * Allows locking the trim to prevent user dragging on startup. The default
+	 * is <code>false</code>.
+	 *
+	 * @since 3.2
+	 */
+	public static final String LOCK_TRIM = "LOCK_TRIM"; //$NON-NLS-1$
+
+	/**
+	 * A named preference for providing the 3.3 presentation's min/max behaviour
+	 * <p>
+	 * The default value for this preference is: <code>false</code>; use the
+	 * 3.2 behaviour.
+	 * </p>
+	 *
+	 * @since 3.3
+	 */
+	public static final String ENABLE_NEW_MIN_MAX = "ENABLE_MIN_MAX"; //$NON-NLS-1$
+
+	/**
+	 * A named preference for disabling opening a new fast view from the fast
+	 * view bar controls ("Show View as a fast view" button or "New Fast View"
+	 * submenu).
+	 * <p>
+	 * Value is of type <code>boolean</code>.
+	 * </p>
+	 * <p>
+	 * The default is <code>false</code>.
+	 * </p>
+	 *
+	 * @since 3.3
+	 */
+	public static final String DISABLE_NEW_FAST_VIEW = "disableNewFastView"; //$NON-NLS-1$
+
+	/**
+	 * A named preference for enabling the 3.2 behavior for closing sticky
+	 * views. When not enabled a sticky view is closed in all perspectives when
+	 * the view is closed.
+	 * <p>
+	 * The default value for this preference is: <code>false</code>; use the
+	 * 3.2 behaviour.
+	 * </p>
+	 *
+	 * @since 3.3
+	 */
+	public static final String ENABLE_32_STICKY_CLOSE_BEHAVIOR = "ENABLE_32_STICKY_CLOSE_BEHAVIOR"; //$NON-NLS-1$
+
+	/**
+	 * An named preference for whether or not tabs are on the top or bottom
+	 * for views. Values are either {@link SWT#TOP} or {@link SWT#BOTTOM}.
+	 * <p>
+	 * The default value for this preference is: <code>SWT.TOP</code>.
+	 * </p>
+	 *
+	 * @since 3.4
+	 */
+	public static final String VIEW_TAB_POSITION = "VIEW_TAB_POSITION"; //$NON-NLS-1$
+
+	/**
+	 * An named preference for whether or not tabs are on the top or bottom
+	 * for editors. Values are either {@link SWT#TOP} or {@link SWT#BOTTOM}.
+	 * <p>
+	 * The default value for this preference is: <code>SWT.TOP</code>.
+	 * </p>
+	 *
+	 * @since 3.4
+	 */
+	public static final String EDITOR_TAB_POSITION = "EDITOR_TAB_POSITION"; //$NON-NLS-1$
+
+	/**
+	 * Workbench preference id for whether the workbench should show multiple
+	 * editor tabs.
+	 *
+	 * Boolean-valued: <code>true</code> if editors should show multiple
+	 * editor tabs, and <code>false</code> if editors should show a single
+	 * editor tab.
+	 * <p>
+	 * The default value for this preference is: <code>true</code>
+	 * </p>
+	 *
+	 * @since 3.4
+	 */
+	public static final String SHOW_MULTIPLE_EDITOR_TABS = "SHOW_MULTIPLE_EDITOR_TABS"; //$NON-NLS-1$
+
+	/**
+	 * Workbench preference id for whether the workbench may open editors
+	 * in-place. Note that editors will only be opened in-place if this
+	 * preference is <code>false</code> and if the current platform supports
+	 * in-place editing.
+	 *
+	 * Boolean-valued: <code>false</code> if editors may be opened in-place,
+	 * and <code>true</code> if editors should never be opened in-place.
+	 * <p>
+	 * The default value for this preference is: <code>false</code>
+	 * </p>
+	 *
+	 * @since 3.4
+	 */
+	public static final String DISABLE_OPEN_EDITOR_IN_PLACE = "DISABLE_OPEN_EDITOR_IN_PLACE"; //$NON-NLS-1$
+
+	/**
+	 * Workbench preference id for indicating the size of the list of most
+	 * recently used working sets.
+	 * <p>
+	 * Integer-valued. The default value for this preference is: <code>5</code>.
+	 * </p>
+	 *
+	 * @since 3.7
+	 */
+	public static final String RECENTLY_USED_WORKINGSETS_SIZE = "RECENTLY_USED_WORKINGSETS_SIZE"; //$NON-NLS-1$
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchPreferencePage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchPreferencePage.java
new file mode 100644
index 0000000..ccf8d0a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchPreferencePage.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import org.eclipse.jface.preference.IPreferencePage;
+
+/**
+ * Interface for workbench preference pages.
+ * <p>
+ * Clients should implement this interface and include the name of their class
+ * in an extension contributed to the workbench's preference extension point
+ * (named <code>"org.eclipse.ui.preferencePages"</code>).
+ * For example, the plug-in's XML markup might contain:
+ * <pre>
+ * &LT;extension point="org.eclipse.ui.preferencePages"&GT;
+ *      &LT;page id="com.example.myplugin.prefs"
+ *         name="Knobs"
+ *         class="com.example.myplugin.MyPreferencePage" /&GT;
+ * &LT;/extension&GT;
+ * </pre>
+ * </p>
+ */
+public interface IWorkbenchPreferencePage extends IPreferencePage {
+    /**
+     * Initializes this preference page for the given workbench.
+     * <p>
+     * This method is called automatically as the preference page is being created
+     * and initialized. Clients must not call this method.
+     * </p>
+     *
+     * @param workbench the workbench
+     */
+    void init(IWorkbench workbench);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchPropertyPage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchPropertyPage.java
new file mode 100644
index 0000000..daa60a9
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchPropertyPage.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.jface.preference.IPreferencePage;
+import org.eclipse.ui.dialogs.PropertyDialogAction;
+
+/**
+ * Interface for workbench property pages. Property pages generally show up in
+ * the workbench's Property Pages dialog.
+ * <p>
+ * Clients should implement this interface and include the name of their class
+ * in an extension contributed to the workbench's property page extension point
+ * (named <code>"org.eclipse.ui.propertyPages"</code>).
+ * For example, the plug-in's XML markup might contain:
+ * <pre>
+ * &LT;extension point="org.eclipse.ui.propertyPages"&GT;
+ *      &LT;page id="com.example.myplugin.props"
+ *         name="Knobs"
+ *         objectClass="org.eclipse.core.resources.IResource"
+ *         class="com.example.myplugin.MyPropertyPage" /&GT;
+ * &LT;/extension&GT;
+ * </pre>
+ * </p>
+ * <p>
+ * Property pages that support multiple selected objects should
+ * implement {@link IWorkbenchPropertyPageMulti} instead.
+ * </p>
+ * @see IWorkbenchPropertyPageMulti
+ */
+public interface IWorkbenchPropertyPage extends IPreferencePage {
+    /**
+     * Returns the object that owns the properties shown in this page.
+     *
+     * @return the object that owns the properties shown in this page
+     */
+    public IAdaptable getElement();
+
+    /**
+     * Sets the object that owns the properties shown in this page.
+     * The page is expected to store this object and provide it if
+     * <code>getElement</code> is called.
+     * <p> As of Eclipse 3.2 the org.eclipse.ui.propertyPages extension
+     * point now supports non IAdaptable inputs. An input
+     * that is not an IAdaptable will be wrapped in an
+     * IAdaptable by the workbench before it is forwarded
+     * to this method.
+     * </p>
+     * @see PropertyDialogAction
+     *
+     * @param element the object that owns the properties shown in this page
+     */
+    public void setElement(IAdaptable element);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchPropertyPageMulti.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchPropertyPageMulti.java
new file mode 100644
index 0000000..055c5d8
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchPropertyPageMulti.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2015 Broadcom 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:
+ *     Broadcom Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ui;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.jface.preference.IPreferencePage;
+
+/**
+ * This interface is similar to {@link IWorkbenchPropertyPage} with the addition
+ * of support for multiple selection.
+ *
+ * @see IWorkbenchPropertyPage
+ * @since 3.7
+ */
+public interface IWorkbenchPropertyPageMulti extends IPreferencePage {
+
+	/**
+	 * Sets the elements that own properties shown on this page. This method
+	 * will be called if the property page responds to multiple selection.
+	 *
+	 * @param elements
+	 *            objects that own the properties shown in this page
+	 */
+	public void setElements(IAdaptable[] elements);
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchSite.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchSite.java
new file mode 100644
index 0000000..28a54ae
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchSite.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.window.IShellProvider;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.contexts.IContextService;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.keys.IBindingService;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * The common interface between the workbench and its parts, including pages
+ * within parts.
+ * <p>
+ * The workbench site supports a few {@link IServiceLocator services} by
+ * default. If these services are used to allocate resources, it is important to
+ * remember to clean up those resources after you are done with them. Otherwise,
+ * the resources will exist until the workbench site is disposed. The supported
+ * services are:
+ * </p>
+ * <ul>
+ * <li>{@link ICommandService}</li>
+ * <li>{@link IContextService}</li>
+ * <li>{@link IHandlerService}</li>
+ * <li>{@link IBindingService}. Resources allocated through this service will
+ * not be cleaned up until the workbench shuts down.</li>
+ * </ul>
+ * <p>
+ * This interface is not intended to be implemented or extended by clients.
+ * </p>
+ *
+ * @see org.eclipse.ui.IWorkbenchPartSite
+ * @see org.eclipse.ui.part.IPageSite
+ * @since 2.0
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IWorkbenchSite extends IAdaptable, IShellProvider,
+		IServiceLocator {
+
+	/**
+	 * Returns the page containing this workbench site.
+	 *
+	 * @return the page containing this workbench site
+	 */
+	public IWorkbenchPage getPage();
+
+	/**
+	 * Returns the selection provider for this workbench site.
+	 *
+	 * @return the selection provider, or <code>null</code> if none
+	 */
+	public ISelectionProvider getSelectionProvider();
+
+	/**
+	 * Returns the shell for this workbench site. Not intended to be called from
+	 * outside the UI thread. Clients should call IWorkbench.getDisplay() to
+	 * gain access to the display rather than calling getShell().getDisplay().
+	 *
+	 * <p>
+	 * For compatibility, this method will not throw an exception if called from
+	 * outside the UI thread, but the returned Shell may be wrong.
+	 * </p>
+	 *
+	 * @return the shell for this workbench site
+	 */
+	@Override
+	public Shell getShell();
+
+	/**
+	 * Returns the workbench window containing this workbench site.
+	 *
+	 * @return the workbench window containing this workbench site
+	 */
+	public IWorkbenchWindow getWorkbenchWindow();
+
+	/**
+	 * Sets the selection provider for this workbench site.
+	 *
+	 * @param provider
+	 *            the selection provider, or <code>null</code> to clear it
+	 */
+	public void setSelectionProvider(ISelectionProvider provider);
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchWindow.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchWindow.java
new file mode 100644
index 0000000..d3d641f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchWindow.java
@@ -0,0 +1,229 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import java.lang.reflect.InvocationTargetException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
+import org.eclipse.jface.operation.IRunnableContext;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.window.IShellProvider;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.contexts.IContextService;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.keys.IBindingService;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * A workbench window is a top level window in a workbench. Visually, a
+ * workbench window has a menubar, a toolbar, a status bar, and a main area for
+ * displaying a single page consisting of a collection of views and editors.
+ * <p>
+ * Each workbench window has a collection of 0 or more pages; the active page is
+ * the one that is being presented to the end user; at most one page is active
+ * in a window at a time.
+ * </p>
+ * <p>
+ * The workbench window supports a few {@link IServiceLocator services} by
+ * default. If these services are used to allocate resources, it is important to
+ * remember to clean up those resources after you are done with them. Otherwise,
+ * the resources will exist until the workbench window is closed. The supported
+ * services are:
+ * </p>
+ * <ul>
+ * <li>{@link ICommandService}</li>
+ * <li>{@link IContextService}</li>
+ * <li>{@link IHandlerService}</li>
+ * <li>{@link IBindingService}. Resources allocated through this service will
+ * not be cleaned up until the workbench shuts down.</li>
+ * </ul>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ *
+ * @see IWorkbenchPage
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IWorkbenchWindow extends IPageService, IRunnableContext,
+		IServiceLocator, IShellProvider {
+    /**
+     * Closes this workbench window.
+     * <p>
+     * If the window has an open editor with unsaved content, the user will be
+     * given the opportunity to save it.
+     * </p>
+     *
+     * @return <code>true</code> if the window was successfully closed, and
+     *         <code>false</code> if it is still open
+     */
+    public boolean close();
+
+    /**
+     * Returns the currently active page for this workbench window.
+     *
+     * @return the active page, or <code>null</code> if none
+     */
+    @Override
+	public IWorkbenchPage getActivePage();
+
+    /**
+     * Returns a list of the pages in this workbench window.
+     * <p>
+     * Note that each window has its own pages; pages are never shared between
+     * different windows.
+     * </p>
+     *
+     * @return a list of pages
+     */
+    public IWorkbenchPage[] getPages();
+
+    /**
+     * Returns the part service which tracks part activation within this
+     * workbench window.
+     *
+     * @return the part service
+     */
+    public IPartService getPartService();
+
+    /**
+     * Returns the selection service which tracks selection within this
+     * workbench window.
+     *
+     * @return the selection service
+     */
+    public ISelectionService getSelectionService();
+
+    /**
+     * Returns this workbench window's shell.
+     *
+     * @return the shell containing this window's controls or <code>null</code>
+     *   if the shell has not been created yet or if the window has been closed
+     */
+    @Override
+	public Shell getShell();
+
+    /**
+     * Returns the workbench for this window.
+     *
+     * @return the workbench
+     */
+    public IWorkbench getWorkbench();
+
+    /**
+     * Returns whether the specified menu is an application menu as opposed to
+     * a part menu. Application menus contain items which affect the workbench
+     * or window. Part menus contain items which affect the active part (view
+     * or editor).
+     * <p>
+     * This is typically used during "in place" editing. Application menus
+     * should be preserved during menu merging. All other menus may be removed
+     * from the window.
+     * </p>
+     *
+     * @param menuId
+     *            the menu id
+     * @return <code>true</code> if the specified menu is an application
+     *         menu, and <code>false</code> if it is not
+     */
+    public boolean isApplicationMenu(String menuId);
+
+    /**
+     * Creates and opens a new workbench page. The perspective of the new page
+     * is defined by the specified perspective ID. The new page become active.
+     * <p>
+     * <b>Note:</b> Since release 2.0, a window is limited to contain at most
+     * one page. If a page exist in the window when this method is used, then
+     * another window is created for the new page. Callers are strongly
+     * recommended to use the <code>IWorkbench.showPerspective</code> APIs to
+     * programmatically show a perspective.
+     * </p>
+     *
+     * @param perspectiveId
+     *            the perspective id for the window's initial page
+     * @param input
+     *            the page input, or <code>null</code> if there is no current
+     *            input. This is used to seed the input for the new page's
+     *            views.
+     * @return the new workbench page
+     * @exception WorkbenchException
+     *                if a page could not be opened
+     *
+     * @see IWorkbench#showPerspective(String, IWorkbenchWindow, IAdaptable)
+     */
+    public IWorkbenchPage openPage(String perspectiveId, IAdaptable input)
+            throws WorkbenchException;
+
+    /**
+     * Creates and opens a new workbench page. The default perspective is used
+     * as a template for creating the page. The page becomes active.
+     * <p>
+     * <b>Note:</b> Since release 2.0, a window is limited to contain at most
+     * one page. If a page exist in the window when this method is used, then
+     * another window is created for the new page. Callers are strongly
+     * recommended to use the <code>IWorkbench.showPerspective</code> APIs to
+     * programmatically show a perspective.
+     * </p>
+     *
+     * @param input
+     *            the page input, or <code>null</code> if there is no current
+     *            input. This is used to seed the input for the new page's
+     *            views.
+     * @return the new workbench window
+     * @exception WorkbenchException
+     *                if a page could not be opened
+     *
+     * @see IWorkbench#showPerspective(String, IWorkbenchWindow, IAdaptable)
+     */
+    public IWorkbenchPage openPage(IAdaptable input) throws WorkbenchException;
+
+    /**
+     * This specialization of IRunnableContext#run(boolean, boolean,
+     * IRunnableWithProgress) blocks until the runnable has been run,
+     * regardless of the value of <code>fork</code>.
+     * It is recommended that <code>fork</code> is set to
+     * true in most cases. If <code>fork</code> is set to <code>false</code>,
+     * the runnable will run in the UI thread and it is the runnable's
+     * responsibility to call <code>Display.readAndDispatch()</code>
+     * to ensure UI responsiveness.
+     *
+     * @since 3.2
+     */
+    @Override
+	public void run(boolean fork, boolean cancelable, IRunnableWithProgress runnable) throws InvocationTargetException, InterruptedException;
+
+    /**
+	 * Sets or clears the currently active page for this workbench window.
+	 *
+	 * @param page
+	 *            the new active page, or <code>null</code> for no active page
+	 */
+    public void setActivePage(IWorkbenchPage page);
+
+    /**
+	 * <p>
+	 * Return the extension tracker for the workbench. This tracker may be used
+	 * by plug-ins to ensure responsiveness to changes to the plug-in registry.
+	 * </p>
+	 * <p>
+	 * The tracker at this level of the workbench is typically used to track
+	 * elements that persist for the life of the workbench. For example, the
+	 * action objects corresponding to new wizards contributed by plug-ins fall
+	 * into this category.
+	 * </p>
+	 *
+	 * @return the extension tracker
+	 * @see IWorkbench#getExtensionTracker()
+	 * @see IWorkbenchPage#getExtensionTracker()
+	 * @since 3.1
+	 */
+    public IExtensionTracker getExtensionTracker();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchWindowActionDelegate.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchWindowActionDelegate.java
new file mode 100644
index 0000000..4b4ab5f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchWindowActionDelegate.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+/**
+ * Interface for an action that is contributed into the workbench window menu
+ * or tool bar. It extends <code>IActionDelegate</code> and adds an
+ * initialization method for connecting the delegate to the workbench window it
+ * should work with.
+ */
+public interface IWorkbenchWindowActionDelegate extends IActionDelegate {
+    /**
+     * Disposes this action delegate.  The implementor should unhook any references
+     * to itself so that garbage collection can occur.
+     */
+    public void dispose();
+
+    /**
+     * Initializes this action delegate with the workbench window it will work in.
+     *
+     * @param window the window that provides the context for this delegate
+     */
+    public void init(IWorkbenchWindow window);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchWindowPulldownDelegate.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchWindowPulldownDelegate.java
new file mode 100644
index 0000000..8834c41
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchWindowPulldownDelegate.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Menu;
+
+/**
+ * Interface for a pulldown action that is contributed into the workbench window
+ * tool bar.  It extends <code>IWorkbenchWindowActionDelegate</code> and adds an
+ * initialization method to define the menu creator for the action.
+ */
+public interface IWorkbenchWindowPulldownDelegate extends
+        IWorkbenchWindowActionDelegate {
+    /**
+     * Returns the menu for this pull down action.  This method will only be
+     * called if the user opens the pull down menu for the action.   Note that it
+     * is the responsibility of the implementor to properly dispose of any SWT menus
+     * created by this method.
+     *
+     * @return the menu
+     */
+    public Menu getMenu(Control parent);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchWindowPulldownDelegate2.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchWindowPulldownDelegate2.java
new file mode 100644
index 0000000..56403c6
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchWindowPulldownDelegate2.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import org.eclipse.swt.widgets.Menu;
+
+/**
+ * Extension of IWorkbenchWindowPulldownDelegate that allows the delegate dropdown
+ * menu to be a child of a Menu item.  Necessary for CoolBar support.  If a coolbar
+ * group of items is not fully displayed, a chevron and a drop down menu will be
+ * used to show the group's tool items.  Therefore, a getMenu(Menu) method is necessary,
+ * since the delegate drop down menu will be a child of the chevron menu item (not
+ * the tool control).
+ */
+public interface IWorkbenchWindowPulldownDelegate2 extends
+        IWorkbenchWindowPulldownDelegate {
+    /**
+     * Returns the menu for this pull down action.  This method will only be
+     * called if the user opens the pull down menu for the action.  Note that it
+     * is the responsibility of the implementor to properly dispose of any SWT
+     * menus created by this method.
+     *
+     * @return the menu
+     */
+    public Menu getMenu(Menu parent);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchWizard.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchWizard.java
new file mode 100644
index 0000000..e06d852
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkbenchWizard.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 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.ui;
+
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.IWizard;
+
+/**
+ * Implementors represent creation wizards that are to be
+ * contributed to the workbench's creation wizard extension point.
+ *
+ * @see org.eclipse.jface.wizard.IWizard
+ */
+public interface IWorkbenchWizard extends IWizard {
+    /**
+     * Initializes this creation wizard using the passed workbench and
+     * object selection.
+     * <p>
+     * This method is called after the no argument constructor and
+     * before other methods are called.
+     * </p>
+     *
+     * @param workbench the current workbench
+     * @param selection the current object selection
+     */
+    void init(IWorkbench workbench, IStructuredSelection selection);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkingSet.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkingSet.java
new file mode 100644
index 0000000..94c2c42
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkingSet.java
@@ -0,0 +1,215 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.jface.resource.ImageDescriptor;
+
+/**
+ * A working set holds a number of IAdaptable elements.
+ * A working set is intended to group elements for presentation to
+ * the user or for operations on a set of elements.
+ *
+ * @since 2.0 initial version
+ * @since 3.0 now extends {@link org.eclipse.ui.IPersistableElement}
+ * @since 3.2 now extends {@link org.eclipse.core.runtime.IAdaptable}
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IWorkingSet extends IPersistableElement, IAdaptable {
+    /**
+     * Returns the elements that are contained in this working set.
+     * <p>
+     * This method might throw an {@link IllegalStateException} if
+     * the working set is invalid.
+     * </p>
+     * @return	the working set's elements
+     */
+    public IAdaptable[] getElements();
+
+    /**
+     * Returns the working set id. Returns <code>null</code> if no
+     * working set id has been set.
+     * This is one of the ids defined by extensions of the
+     * org.eclipse.ui.workingSets extension point.
+     * It is used by the workbench to determine the page to use in
+     * the working set edit wizard. The default resource edit page
+     * is used if this value is <code>null</code>.
+     *
+     * @return the working set id. May be <code>null</code>
+     * @since 2.1
+     */
+    public String getId();
+
+    /**
+     * Returns the working set icon.
+     * Currently, this is one of the icons specified in the extensions
+     * of the org.eclipse.ui.workingSets extension point.
+     * The extension is identified using the value returned by
+     * <code>getId()</code>.
+     * Returns <code>null</code> if no icon has been specified in the
+     * extension or if <code>getId()</code> returns <code>null</code>.
+     *
+     * @return the working set icon or <code>null</code>.
+     * @since 2.1
+     * @deprecated use {@link #getImageDescriptor()} instead
+     */
+    @Deprecated
+	public ImageDescriptor getImage();
+
+    /**
+     * Returns the working set icon.
+     * Currently, this is one of the icons specified in the extensions
+     * of the org.eclipse.ui.workingSets extension point.
+     * The extension is identified using the value returned by
+     * <code>getId()</code>.
+     * Returns <code>null</code> if no icon has been specified in the
+     * extension or if <code>getId()</code> returns <code>null</code>.
+     *
+     * @return the working set icon or <code>null</code>.
+     * @since 3.3
+     */
+    public ImageDescriptor getImageDescriptor();
+
+    /**
+     * Returns the name of the working set.
+     *
+     * @return	the name of the working set
+     */
+    public String getName();
+
+    /**
+	 * Sets the elements that are contained in this working set.
+	 *
+	 * @param elements
+	 *            the elements to set in this working set
+	 * @since 3.3 it is now recommended that all calls to this method pass
+	 *        through the results from calling
+	 *        {@link #adaptElements(IAdaptable[])} with the desired elements.
+	 */
+	public void setElements(IAdaptable[] elements);
+
+    /**
+	 * Sets the working set id. This is one of the ids defined by extensions of
+	 * the org.eclipse.ui.workingSets extension point. It is used by the
+	 * workbench to determine the page to use in the working set edit wizard.
+	 * The default resource edit page is used if this value is <code>null</code>.
+	 *
+	 * @param id
+	 *            the working set id. May be <code>null</code>
+	 * @since 2.1
+	 */
+    public void setId(String id);
+
+    /**
+     * Sets the name of the working set.
+     * The working set name should be unique.
+     * The working set name must not have leading or trailing
+     * whitespace.
+     *
+     * @param name the name of the working set
+     */
+    public void setName(String name);
+
+    /**
+     * Returns whether this working set can be edited or not. To make
+     * a working set editable the attribute <code>pageClass</code> of
+     * the extension defining a working set must be provided.
+     *
+     * @return <code>true</code> if the working set can be edited; otherwise
+     *  <code>false</code>
+     *
+     * @since 3.1
+     */
+    public boolean isEditable();
+
+    /**
+	 * Returns whether this working set should be shown in user interface
+	 * components that list working sets by name.
+	 *
+	 * @return <code>true</code> if the working set should be shown in the
+	 *         user interface; otherwise <code>false</code>
+	 *
+	 * @since 3.2
+	 */
+	public boolean isVisible();
+
+    /**
+	 * Return the name of this working set, formated for the end user. Often this value is
+	 * the same as the one returned from {@link #getName()}.
+	 *
+	 * @return the name of this working set, formated for the end user
+	 * @since 3.2
+	 */
+    public String getLabel();
+
+    /**
+	 * Set the name of this working set, formated for the end user.
+	 *
+	 * @param label
+	 *            the label for this working set. If <code>null</code> is
+	 *            supplied then the value of {@link #getName()} will be used.
+	 * @since 3.2
+	 */
+	public void setLabel(String label);
+
+	/**
+	 * Returns <code>true</code> if this working set is capable of updating
+	 * itself and reacting to changes in the state of its members. For
+	 * non-aggregate working sets this means that the working set has an
+	 * {@link IWorkingSetUpdater} installed while for aggregates it means that
+	 * all component sets have {@link IWorkingSetUpdater}s installed. Otherwise
+	 * returns <code>false</code>.
+	 *
+	 * @return whether the set is self-updating or not
+	 * @since 3.2
+	 */
+	public boolean isSelfUpdating();
+
+	/**
+	 * Returns whether this working set is an aggregate working set or not.
+	 *
+	 * <p>
+	 * It is recommended that clients of aggregate working sets treat them in a
+	 * specific way. Please see the documentation for
+	 * {@link IWorkbenchPage#getAggregateWorkingSet()} for details.
+	 * <p>
+	 * If this is true, you can cast this working set to an {@link IAggregateWorkingSet}
+	 *
+	 * @return whether this working set is an aggregate working set or not
+	 * @since 3.2
+	 */
+	public boolean isAggregateWorkingSet();
+
+	/**
+	 * Returns whether this working set is currently empty (has no elements).
+	 *
+	 * @return whether this working set is currently empty
+	 * @since 3.2
+	 */
+	public boolean isEmpty();
+
+	/**
+	 * Transforms the supplied elements into elements that are suitable for
+	 * containment in this working set. This is useful for UI elements which
+	 * wish to filter contributions to working sets based on applicability. This
+	 * is a hint, however, and is not considered when the
+	 * {@link #setElements(IAdaptable[])} method is invoked.
+	 *
+	 * @param objects
+	 *            the objects to transform
+	 * @return an array of transformed elements that be empty if no elements
+	 *         from the original array are suitable
+	 * @since 3.3
+	 * @see org.eclipse.ui.IWorkingSetElementAdapter
+	 * @see org.eclipse.ui.BasicWorkingSetElementAdapter
+	 */
+	public IAdaptable[] adaptElements(IAdaptable[] objects);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkingSetElementAdapter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkingSetElementAdapter.java
new file mode 100644
index 0000000..1e381bf
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkingSetElementAdapter.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui;
+
+import org.eclipse.core.runtime.IAdaptable;
+
+/**
+ * <p>
+ * Interface that describes a mechanism that may be provided by working set
+ * extensions to help manage the addition of elements to working sets. Instances
+ * of this class are capable of transforming possible working set content into
+ * the most applicable form.
+ * </p>
+ *
+ * <p>
+ * Usage of this interface is achieved via the <code>elementAdapterClass</code>
+ * attribute of the <code>org.eclipse.ui.workingSets</code> extension point.
+ * Usage of this interface in <code>org.eclipse.ui.workingSets</code>
+ * extensions is optional.
+ * </p>
+ *
+ * @since 3.3
+ */
+public interface IWorkingSetElementAdapter {
+
+	/**
+	 * Converts the given elements for addition to/removal from the working set.
+	 *
+	 * @param ws
+	 *            the target working set that elements should be adapted for
+	 * @param elements
+	 *            the elements to adapt
+	 * @return the (possibly adapted) elements to add to/remove from the working
+	 *         set
+	 */
+	IAdaptable[] adaptElements(IWorkingSet ws, IAdaptable[] elements);
+
+	/**
+	 * Disposes of this element adaptor.
+	 */
+	void dispose();
+}
+
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkingSetManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkingSetManager.java
new file mode 100644
index 0000000..fae04c0
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkingSetManager.java
@@ -0,0 +1,369 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Tomasz Zarna <tomasz.zarna@tasktop.com> - Bug 37183
+ *******************************************************************************/
+package org.eclipse.ui;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.dialogs.IWorkingSetEditWizard;
+import org.eclipse.ui.dialogs.IWorkingSetNewWizard;
+import org.eclipse.ui.dialogs.IWorkingSetSelectionDialog;
+
+/**
+ * A working set manager stores working sets and provides property
+ * change notification when a working set is added or removed.
+ * <p>
+ * The workbench working set manager can be accessed using
+ * <code>IWorkbench#getWorkingSetManager()</code>
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ *
+ * @see IWorkingSet
+ * @since 2.0 initial version
+ * @since 3.0 added createWorkingSet(IMemento)
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IWorkingSetManager {
+
+    /**
+     * Change event id when a working set is added
+     * newValue of the PropertyChangeEvent will be the added working set.
+     * oldValue will be null.
+     *
+     * @see IPropertyChangeListener
+     */
+    public static final String CHANGE_WORKING_SET_ADD = "workingSetAdd"; //$NON-NLS-1$
+
+    /**
+     * Change event id when a working set is removed
+     * newValue of the PropertyChangeEvent will be null.
+     * oldValue will be the removed working set.
+     *
+     * @see IPropertyChangeListener
+     */
+    public static final String CHANGE_WORKING_SET_REMOVE = "workingSetRemove"; //$NON-NLS-1$
+
+    /**
+     * Change event id when the working set contents changed
+     * newValue of the PropertyChangeEvent will be the changed working set.
+     *
+     * @see IPropertyChangeListener
+     */
+    public static final String CHANGE_WORKING_SET_CONTENT_CHANGE = "workingSetContentChange"; //$NON-NLS-1$
+
+    /**
+     * Change event id when the working set name changed.
+     * newValue of the PropertyChangeEvent will be the changed working set.
+     *
+     * @see IPropertyChangeListener
+     */
+    public static final String CHANGE_WORKING_SET_NAME_CHANGE = "workingSetNameChange"; //$NON-NLS-1$
+
+    /**
+     * Change event id when the working set label changed.
+     * newValue of the PropertyChangeEvent will be the changed working set.
+     *
+     * @see IPropertyChangeListener
+     * @since 3.2
+     */
+    public static final String CHANGE_WORKING_SET_LABEL_CHANGE = "workingSetLabelChange"; //$NON-NLS-1$
+
+    /**
+     * Change event id when a working set updater got installed.
+     * NewValue of the PropertyChangeEvent will be the installed updater.
+     * OldValue will be <code>null</code>
+     * @since 3.1
+     */
+    public static final String CHANGE_WORKING_SET_UPDATER_INSTALLED = "workingSetUpdaterInstalled"; //$NON-NLS-1$
+
+    /**
+     * Change event id when a working set updater got uninstalled.
+     * NewValue will be <code>null</code>
+     * OldValue of the PropertyChangeEvent will be the uninstalled updater.
+     * @since 3.3
+     */
+    public static final String CHANGE_WORKING_SET_UPDATER_UNINSTALLED = "workingSetUpdaterUninstalled"; //$NON-NLS-1$
+
+    /**
+     * Adds a property change listener.
+     *
+     * @param listener the property change listener to add
+     */
+    public void addPropertyChangeListener(IPropertyChangeListener listener);
+
+    /**
+     * Adds a working set to the top of the list of most recently used
+     * working sets, making it the most recently used working set.
+     * The last (oldest) item will be deleted if the list exceeds the
+     * size limit.
+     *
+     * @param workingSet the working set to add to the list of most
+     * 	recently used working sets.
+     */
+    public void addRecentWorkingSet(IWorkingSet workingSet);
+
+    /**
+     * Adds a working set to the receiver. The working set must
+     * not exist yet.
+     *
+     * @param workingSet the working set to add
+     */
+    public void addWorkingSet(IWorkingSet workingSet);
+
+    /**
+     * Creates a new working set.
+     * The working set is not added to the working set manager.
+     *
+     * @param name the name of the new working set. Should not have
+     * 	leading or trailing whitespace.
+     * @param elements the working set contents
+     * @return a new working set with the specified name and content
+     */
+    public IWorkingSet createWorkingSet(String name, IAdaptable[] elements);
+
+    /**
+	 * Create a working set that is the union of a collection of other working
+	 * sets. One connected (via
+	 * {@link IWorkingSetManager#addWorkingSet(IWorkingSet)} this working set
+	 * will be automatically updated to reflect the contents of the component
+	 * sets, should they themselves change.
+	 *
+	 * @param name
+	 *            the name of the new working set. Should not have leading or
+	 *            trailing whitespace.
+	 * @param label
+	 *            the user-friendly label the working set
+	 * @param components
+	 *            the component working sets
+	 * @return a new working set with the specified name and content
+	 *
+	 * @since 3.2
+	 */
+	public IWorkingSet createAggregateWorkingSet(String name, String label,
+			IWorkingSet[] components);
+
+    /**
+     * Re-creates and returns a working set from the state captured within the
+     * given memento.
+     *
+     * @param memento a memento containing the state for the working set
+     * @return the restored working set, or <code>null</code> if it could not be created
+     *
+     * @since 3.0
+     */
+    public IWorkingSet createWorkingSet(IMemento memento);
+
+    /**
+     * Creates a working set edit wizard for the specified working set.
+     * The working set will already be set in the wizard.
+     * The caller is responsible for creating and opening a wizard dialog.
+     *
+     * Example:
+     * <code>
+     *  IWorkingSetEditWizard wizard = workingSetManager.createWorkingSetEditWizard(workingSet);
+     *  if (wizard != null) {
+     *	  WizardDialog dialog = new WizardDialog(shell, wizard);
+     *
+     *	  dialog.create();
+     *	  if (dialog.open() == Window.OK) {
+     *		  workingSet = wizard.getSelection();
+     *    }
+     *	}
+     * </code>
+     *
+     * @param workingSet working set to create a working set edit wizard
+     * 	for.
+     * @return a working set edit wizard to edit the specified working set
+     *  or <code>null</code> if no edit wizard has been defined for the
+     *  working set. If the defined edit wizard for the working set could
+     *  not be loaded a default IResource based wizard will be returned.
+     * 	If the default edit wizard can not be loaded <code>null</code> is
+     *  returned.
+     * @since 2.1
+     */
+    public IWorkingSetEditWizard createWorkingSetEditWizard(
+            IWorkingSet workingSet);
+
+
+    /**
+     * Creates a working set new wizard. The wizard will allow creating new
+     * working sets. Returns <code>null</code> if there aren't any working set
+     * definitions that support creation of working sets.
+     * <p>
+     * Example:
+     * <code>
+     *   IWorkingSetNewWizard wizard= workingSetManager.createWorkingSetNewWizard(null);
+     *   if (wizard != null) {
+     *	     WizardDialog dialog = new WizardDialog(shell, wizard);
+     *
+     *	     dialog.create();
+     *	     if (dialog.open() == Window.OK) {
+     *		    ...
+     *       }
+     *   }
+     * </code>
+     * </p>
+     *
+     * @param workingSetIds a list of working set ids which are valid workings sets
+     *  to be created or <code>null</code> if all currently available working set types
+     *  are valid
+     *
+     * @return the working set new wizard or <code>null</code>
+     *
+     * @since 3.1
+     */
+    public IWorkingSetNewWizard createWorkingSetNewWizard(String[] workingSetIds);
+
+    /**
+     * @param parent the parent shell
+     * @return the dialog
+     * @deprecated use createWorkingSetSelectionDialog(parent, true) instead
+     */
+    @Deprecated
+	public IWorkingSetSelectionDialog createWorkingSetSelectionDialog(
+            Shell parent);
+
+    /**
+     * Creates a working set selection dialog that lists all working
+     * sets and allows the user to add, remove and edit working sets.
+     * The caller is responsible for opening the dialog with
+     * <code>IWorkingSetSelectionDialog#open</code>, and subsequently
+     * extracting the selected working sets using
+     * <code>IWorkingSetSelectionDialog#getSelection</code>.
+     *
+     * @param parentShell the parent shell of the working set selection dialog
+     * @param multi true= <code>IWorkingSetSelectionDialog#getSelection()</code>
+     *  returns the working sets chosen in the dialog as an array of working set.
+     *  false= <code>IWorkingSetSelectionDialog#getSelection()</code> returns
+     *  an array having a single aggregate working set of all working sets
+     *  selected in the dialog.
+     * @return a working set selection dialog
+     */
+    public IWorkingSetSelectionDialog createWorkingSetSelectionDialog(
+            Shell parentShell, boolean multi);
+
+    /**
+     * Creates a working set selection dialog that lists all working
+     * sets with the specified ids and allows the user to add, remove and
+     * edit working sets with the specified ids.
+     * The caller is responsible for opening the dialog with
+     * <code>IWorkingSetSelectionDialog#open</code>, and subsequently
+     * extracting the selected working sets using
+     * <code>IWorkingSetSelectionDialog#getSelection</code>.
+     *
+     * @param parentShell the parent shell of the working set selection dialog
+     * @param multi true= <code>IWorkingSetSelectionDialog#getSelection()</code>
+     *  returns the working sets chosen in the dialog as an array of working set.
+     *  false= <code>IWorkingSetSelectionDialog#getSelection()</code> returns
+     *  an array having a single aggregate working set of all working sets
+     *  selected in the dialog.
+     * @param workingsSetIds a list of working set ids which are valid workings sets
+     *  to be selected, created, removed or edited, or <code>null</code> if all currently
+     *  available working set types are valid
+     * @return a working set selection dialog
+     * @since 3.1
+     */
+    public IWorkingSetSelectionDialog createWorkingSetSelectionDialog(
+            Shell parentShell, boolean multi, String[] workingsSetIds);
+
+    /**
+     * Returns the list of most recently used working sets.
+     * The most recently used working set appears first in the list.
+     *
+     * @return the list of most recently used working sets
+     */
+    public IWorkingSet[] getRecentWorkingSets();
+
+    /**
+     * Returns the working set with the specified name.
+     * Returns null if there is no working set with that name.
+     *
+     * @param name the name of the working set to return
+     * @return the working set with the specified name.
+     */
+    public IWorkingSet getWorkingSet(String name);
+
+    /**
+	 * Returns an array of all working sets stored in the receiver. The array is
+	 * sorted by names. Any working set whose {@link IWorkingSet#isVisible()}
+	 * method returns false will not be included in this array. For a complete
+	 * list of working sets please use {@link #getAllWorkingSets()}.
+	 *
+	 * @return the working sets stored in the receiver
+	 */
+    public IWorkingSet[] getWorkingSets();
+
+    /**
+	 * Returns an array of all working sets stored in the receiver including
+	 * those that are marked as being not visible.
+	 *
+	 * @see IWorkingSet#isVisible()
+	 * @return the working sets stored in the receiver
+	 * @since 3.2
+	 */
+    public IWorkingSet[] getAllWorkingSets();
+
+    /**
+     * Removes the property change listener.
+     *
+     * @param listener the property change listener to remove
+     */
+    public void removePropertyChangeListener(IPropertyChangeListener listener);
+
+    /**
+     * Removes the working set
+     *
+     * @param workingSet the working set to remove
+     */
+    public void removeWorkingSet(IWorkingSet workingSet);
+
+    /**
+     * Disposes the working set manager.
+     *
+     * @since 3.1
+     */
+    public void dispose();
+
+    /**
+	 * Utility method that will add the <code>element</code> to each given
+	 * working set in <code>workingSets</code> if possible. This method will
+	 * invoke {@link IWorkingSet#adaptElements(IAdaptable[])} for the element on
+	 * each working set and the result of this method will be used rather than
+	 * the original element in the addition operation.
+	 *
+	 * @param element
+	 *            the element to adapt and then add to the working sets
+	 * @param workingSets
+	 *            the working sets to add the element to
+	 * @since 3.4
+	 */
+	public void addToWorkingSets(IAdaptable element, IWorkingSet[] workingSets);
+
+	/**
+	 * Sets maximum length of the recent working sets list.
+	 *
+	 * @param length
+	 *            maximum number of recent working sets to be kept in the list
+	 * @since 3.7
+	 */
+	public void setRecentWorkingSetsLength(int length);
+
+	/**
+	 * Returns the maximum length of the recent working sets list.
+	 *
+	 * @return the maximum length of the recent working sets list.
+	 * @since 3.7
+	 */
+	public int getRecentWorkingSetsLength();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkingSetUpdater.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkingSetUpdater.java
new file mode 100644
index 0000000..6672ccb
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/IWorkingSetUpdater.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+/**
+ * An <code>IWorkingSetUpdater</code> can be used to dynamically update
+ * the content of a working set.
+ * <p>
+ * A working set updater manages a set of working sets. It is contributed
+ * via the attribute <code>updaterClass</code> of the <code>
+ * org.eclipse.ui.workingSets</code> extension point. Extensions of this
+ * extension point must therefore implement this interface.
+ * </p>
+ * <p>
+ * API under construction and subject to change at any time.
+ * </p>
+ * @since 3.1
+ */
+public interface IWorkingSetUpdater {
+	/**
+	 * Adds a working set to this updater.
+	 *
+	 * @param workingSet the working set to add to this updater
+	 */
+	public void add(IWorkingSet workingSet);
+
+	/**
+	 * Removes a working set from this updater.
+	 *
+	 * @param workingSet the working set to remove
+	 *
+	 * @return <code>true</code> if the updater changed (e.g.
+	 *  the element got removed)
+	 */
+	public boolean remove(IWorkingSet workingSet);
+
+	/**
+	 * Returns <code>true</code> if the updater contains the
+	 * given working set; otherwise <code>false</code> is
+	 * returned.
+	 *
+	 * @param workingSet the parameter to check
+	 *
+	 * @return whether the updater contains the given working
+	 *  set
+	 */
+	public boolean contains(IWorkingSet workingSet);
+
+	/**
+	 * Disposes this working set updater. Implementations of this
+	 * method typically remove listeners from some delta providers.
+	 */
+	public void dispose();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/LegacyHandlerSubmissionExpression.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/LegacyHandlerSubmissionExpression.java
new file mode 100644
index 0000000..dc847e2
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/LegacyHandlerSubmissionExpression.java
@@ -0,0 +1,176 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui;
+
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.ExpressionInfo;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * <p>
+ * An expression encapsulating all of the information from legacy handler
+ * submissions.
+ * </p>
+ *
+ * @since 3.1
+ */
+public final class LegacyHandlerSubmissionExpression extends Expression {
+
+	/**
+	 * The seed for the hash code for all schemes.
+	 */
+	private static final int HASH_INITIAL = LegacyHandlerSubmissionExpression.class
+			.getName().hashCode();
+
+	/**
+	 * The identifier for the part that must be active for this expression to
+	 * evaluate to <code>true</code>. If this value is <code>null</code>,
+	 * then any part may be active.
+	 */
+	private final String activePartId;
+
+	/**
+	 * The shell that must be active for this expression to evaluate to
+	 * <code>true</code>. If this value is <code>null</code>, then any
+	 * shell may be active.
+	 */
+	private final Shell activeShell;
+
+	/**
+	 * The site that must be active for this expression to evaluate to
+	 * <code>true</code>. If this value is <code>null</code>, then any
+	 * site may be active.
+	 */
+	private final IWorkbenchPartSite activeSite;
+
+	/**
+	 * Constructs a new instance of
+	 * <code>LegacyHandlerSubmissionExpression</code>
+	 *
+	 * @param activePartId
+	 *            The part identifier to match with the active part;
+	 *            <code>null</code> if it will match any active part.
+	 * @param activeShell
+	 *            The shell to match with the active shell; <code>null</code>
+	 *            if it will match any active shell.
+	 * @param activeSite
+	 *            The site to match with the active site; <code>null</code> if
+	 *            it will match any active site.
+	 */
+	public LegacyHandlerSubmissionExpression(final String activePartId,
+			final Shell activeShell, final IWorkbenchPartSite activeSite) {
+
+		this.activePartId = activePartId;
+		this.activeShell = activeShell;
+		this.activeSite = activeSite;
+	}
+
+	/**
+	 * Collect expression info for a legacy handler submission.  Namely
+	 * the active part id and name, active shell name, active workbench
+	 * window shell name and the active site name.
+	 *
+	 * @since 3.2
+	 */
+	@Override
+	public final void collectExpressionInfo(final ExpressionInfo info) {
+		if (activePartId != null) {
+			info.addVariableNameAccess(ISources.ACTIVE_PART_ID_NAME);
+		}
+		if (activeShell != null) {
+			info.addVariableNameAccess(ISources.ACTIVE_SHELL_NAME);
+			info
+					.addVariableNameAccess(ISources.ACTIVE_WORKBENCH_WINDOW_SHELL_NAME);
+		}
+		if (activeSite != null) {
+			info.addVariableNameAccess(ISources.ACTIVE_SITE_NAME);
+		}
+	}
+
+	@Override
+	protected final int computeHashCode() {
+		int hashCode = HASH_INITIAL * HASH_FACTOR + hashCode(activePartId);
+		hashCode = hashCode * HASH_FACTOR + hashCode(activeShell);
+		hashCode = hashCode * HASH_FACTOR + hashCode(activeSite);
+		return hashCode;
+	}
+
+	@Override
+	public final boolean equals(final Object object) {
+		if (object instanceof LegacyHandlerSubmissionExpression) {
+			final LegacyHandlerSubmissionExpression that = (LegacyHandlerSubmissionExpression) object;
+			return equals(this.activePartId, that.activePartId)
+					&& equals(this.activeShell, that.activeShell)
+					&& equals(this.activeSite, that.activeSite);
+		}
+
+		return false;
+	}
+
+	/**
+	 * Evaluates this expression. This tests the three conditions against the
+	 * current state of the application (as defined by <code>context</code>).
+	 * If a condition is <code>null</code>, then it matches any possible
+	 * value (i.e., it is not tested at all).
+	 *
+	 * @param context
+	 *            The context providing the current workbench state; must not be
+	 *            <code>null</code>.
+	 * @return <code>EvaluationResult.TRUE</code> if the conditions all
+	 *         matches; <code>EvaluationResult.FALSE</code> otherwise.
+	 */
+	@Override
+	public final EvaluationResult evaluate(final IEvaluationContext context) {
+		if (activePartId != null) {
+			final Object value = context
+					.getVariable(ISources.ACTIVE_PART_ID_NAME);
+			if (!activePartId.equals(value)) {
+				return EvaluationResult.FALSE;
+			}
+		}
+
+		if (activeShell != null) {
+			Object value = context.getVariable(ISources.ACTIVE_SHELL_NAME);
+			if (!activeShell.equals(value)) {
+				value = context
+						.getVariable(ISources.ACTIVE_WORKBENCH_WINDOW_SHELL_NAME);
+				if (!activeShell.equals(value)) {
+					return EvaluationResult.FALSE;
+				}
+			}
+		}
+
+		if (activeSite != null) {
+			final Object value = context.getVariable(ISources.ACTIVE_SITE_NAME);
+			if (!activeSite.equals(value)) {
+				return EvaluationResult.FALSE;
+			}
+		}
+
+		return EvaluationResult.TRUE;
+	}
+
+	@Override
+	public final String toString() {
+		final StringBuffer buffer = new StringBuffer();
+		buffer.append("LegacyHandlerSubmission("); //$NON-NLS-1$
+		buffer.append(activeShell);
+		buffer.append(',');
+		buffer.append(activePartId);
+		buffer.append(',');
+		buffer.append(activeSite);
+		buffer.append(')');
+		return buffer.toString();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/MultiPartInitException.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/MultiPartInitException.java
new file mode 100644
index 0000000..8c2e389
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/MultiPartInitException.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2015 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.ui;
+
+/**
+ * A checked exception indicating one or more workbench parts could not be
+ * initialized correctly. The message text provides a further description of the
+ * problem.
+ *
+ * @since 3.5
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class MultiPartInitException extends WorkbenchException {
+
+	private IWorkbenchPartReference[] references;
+	private PartInitException[] exceptions;
+
+	/**
+	 * Creates a new exception object. Note that as of 3.5, this constructor
+	 * expects exactly one exception object in the given array, with all other
+	 * array positions being <code>null</code>. The restriction may be lifted in
+	 * the future, and clients of this class must not make this assumption.
+	 *
+	 * @param references
+	 * @param exceptions
+	 */
+	public MultiPartInitException(IWorkbenchPartReference[] references,
+			PartInitException[] exceptions) {
+		super(exceptions[findFirstException(exceptions)].getStatus());
+		this.references = references;
+		this.exceptions = exceptions;
+	}
+
+	/**
+	 * Returns an array of part references, containing references of parts that
+	 * were intialized correctly. Any number of elements of the returned array
+	 * may have a <code>null</code> value.
+	 *
+	 * @return the part reference array
+	 */
+	public IWorkbenchPartReference[] getReferences() {
+		return references;
+	}
+
+	/**
+	 * Returns an array of exceptions, corresponding to parts that could not be
+	 * intialized correctly. At least one element of the returned array will
+	 * have a non-<code>null</code> value.
+	 *
+	 * @return the exception array
+	 */
+	public PartInitException[] getExceptions() {
+		return exceptions;
+	}
+
+	private static int findFirstException(PartInitException[] exceptions) {
+		for (int i = 0; i < exceptions.length; i++) {
+			if (exceptions[i] != null)
+				return i;
+		}
+		throw new IllegalArgumentException();
+	}
+
+	private static final long serialVersionUID = -9138185942975165490L;
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/NavigationLocation.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/NavigationLocation.java
new file mode 100644
index 0000000..0a7d621
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/NavigationLocation.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+/**
+ * Default implementation of INavigationLocation.
+ *
+ * @since 2.1
+ */
+public abstract class NavigationLocation implements INavigationLocation {
+
+    private IWorkbenchPage page;
+
+    private IEditorInput input;
+
+    /**
+     * Constructs a NavigationLocation with its editor part.
+     *
+     * @param editorPart
+     */
+    protected NavigationLocation(IEditorPart editorPart) {
+        this.page = editorPart.getSite().getPage();
+        this.input = editorPart.getEditorInput();
+    }
+
+    /**
+     * Returns the part that the receiver holds the location for.
+     *
+     * @return IEditorPart
+     */
+    protected IEditorPart getEditorPart() {
+        if (input == null) {
+			return null;
+		}
+        return page.findEditor(input);
+    }
+
+    @Override
+	public Object getInput() {
+        return input;
+    }
+
+    @Override
+	public String getText() {
+        IEditorPart part = getEditorPart();
+        if (part == null) {
+			return ""; //$NON-NLS-1$
+		}
+        return part.getTitle();
+    }
+
+    @Override
+	public void setInput(Object input) {
+        this.input = (IEditorInput) input;
+    }
+
+    /**
+     * May be extended by clients.
+     *
+     * @see org.eclipse.ui.INavigationLocation#dispose()
+     */
+    @Override
+	public void dispose() {
+        releaseState();
+    }
+
+    /**
+     * May be extended by clients.
+     *
+     * @see org.eclipse.ui.INavigationLocation#releaseState()
+     */
+    @Override
+	public void releaseState() {
+        input = null;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/OpenAndLinkWithEditorHelper.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/OpenAndLinkWithEditorHelper.java
new file mode 100644
index 0000000..e516a71
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/OpenAndLinkWithEditorHelper.java
@@ -0,0 +1,144 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2016 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.ui;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.util.OpenStrategy;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.IOpenListener;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.OpenEvent;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredViewer;
+
+
+/**
+ * Helper for opening editors on the viewer's selection and link the selection with the editor.
+ *
+ * @since 3.5
+ */
+public abstract class OpenAndLinkWithEditorHelper {
+
+	private StructuredViewer viewer;
+
+	private boolean isLinkingEnabled;
+
+	private ISelection lastOpenSelection;
+
+	private InternalListener listener;
+
+
+	private final class InternalListener implements IOpenListener, ISelectionChangedListener, IDoubleClickListener {
+
+		@Override
+		public final void open(OpenEvent event) {
+			lastOpenSelection = event.getSelection();
+			OpenAndLinkWithEditorHelper.this.open(lastOpenSelection, OpenStrategy.activateOnOpen());
+		}
+
+		@Override
+		public void selectionChanged(SelectionChangedEvent event) {
+			final ISelection selection = event.getSelection();
+			if (isLinkingEnabled && !selection.equals(lastOpenSelection) && viewer.getControl().isFocusControl())
+				linkToEditor(selection);
+			lastOpenSelection = null;
+		}
+
+		@Override
+		public void doubleClick(DoubleClickEvent event) {
+			if (!OpenStrategy.activateOnOpen())
+				activate(event.getSelection());
+		}
+
+	}
+
+
+	/**
+	 * Creates a new helper for the given viewer.
+	 *
+	 * @param viewer the viewer
+	 */
+	public OpenAndLinkWithEditorHelper(StructuredViewer viewer) {
+		Assert.isLegal(viewer != null);
+		this.viewer = viewer;
+		listener = new InternalListener();
+		viewer.addPostSelectionChangedListener(listener);
+		viewer.addOpenListener(listener);
+		viewer.addDoubleClickListener(listener);
+	}
+
+	/**
+	 * Sets whether editor that corresponds to the viewer's selection should be brought to front.
+	 *
+	 * @param enabled <code>true</code> to enable, <code>false</code> to disable
+	 */
+	public void setLinkWithEditor(boolean enabled) {
+		isLinkingEnabled = enabled;
+	}
+
+	/**
+	 * Disposes this helper.
+	 * <p>
+	 * Clients only need to call this method if their viewer has a longer life-cycle than this helper.
+	 * </p>
+	 */
+	public void dispose() {
+		viewer.removePostSelectionChangedListener(listener);
+		viewer.removeOpenListener(listener);
+		viewer.removeDoubleClickListener(listener);
+		listener = null;
+	}
+
+	/**
+	 * Tells to activate the editor that is open on the given selection.
+	 * <p>
+	 * <strong>Note:</strong> The implementation must not open a new editor.
+	 * </p>
+	 *
+	 * @param selection the viewer's selection
+	 * @since 3.5
+	 */
+	protected abstract void activate(ISelection selection);
+
+	/**
+	 * Tells to open an editor for the given selection.
+	 *
+	 * @param selection the viewer's selection
+	 * @param activate <code>true</code> if the editor should be activated, <code>false</code>
+	 *            otherwise
+	 * @since 3.5
+	 */
+	protected abstract void open(ISelection selection, boolean activate);
+
+	/**
+	 * Tells to link the given selection to the editor that is open on the given
+	 * selection but does nothing if no matching editor can be found.
+	 * <p>
+	 * The common implementation brings that editor to front but more advanced
+	 * implementations may also select the given selection inside the editor.
+	 * </p>
+	 * <p>
+	 * <strong>Note:</strong> The implementation must not open a new editor.
+	 * </p>
+	 * <p>
+	 * The default implementation does nothing i.e. does not implement linking.
+	 * </p>
+	 *
+	 * @param selection
+	 *            the viewer's selection
+	 * @since 3.5, non-abstract since 4.3
+	 */
+	protected void linkToEditor(ISelection selection) {
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/PartInitException.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/PartInitException.java
new file mode 100644
index 0000000..47f707c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/PartInitException.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import org.eclipse.core.runtime.IStatus;
+
+/**
+ * A checked exception indicating a workbench part cannot be initialized
+ * correctly. The message text provides a further description of the problem.
+ * <p>
+ * This exception class is not intended to be subclassed by clients.
+ * </p>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class PartInitException extends WorkbenchException {
+
+    /**
+     * Generated serial version UID for this class.
+     * @since 3.1
+     */
+    private static final long serialVersionUID = 3257284721296684850L;
+
+    /**
+     * Creates a new exception with the given message.
+     *
+     * @param message the message
+     */
+    public PartInitException(String message) {
+        super(message);
+    }
+
+    /**
+     * Creates a new exception with the given message.
+     *
+     * @param message the message
+     * @param nestedException a exception to be wrapped by this PartInitException
+     */
+    public PartInitException(String message, Throwable nestedException) {
+        super(message, nestedException);
+    }
+
+    /**
+     * Creates a new exception with the given status object.  The message
+     * of the given status is used as the exception message.
+     *
+     * @param status the status object to be associated with this exception
+     */
+    public PartInitException(IStatus status) {
+        super(status);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/PerspectiveAdapter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/PerspectiveAdapter.java
new file mode 100644
index 0000000..c04f4fc
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/PerspectiveAdapter.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui;
+
+/**
+ * This adapter class provides default implementations for the methods described
+ * by the <code>IPerspectiveListener</code> interface and its extension
+ * interfaces.
+ * <p>
+ * Classes that wish to deal with events which occur as perspectives are added,
+ * removed, activated and changed, can extend this class and override only the
+ * methods which they are interested in.
+ * </p>
+ *
+ * @see org.eclipse.ui.IPerspectiveListener
+ * @see org.eclipse.ui.IPerspectiveListener2
+ * @see org.eclipse.ui.IPerspectiveListener3
+ * @see org.eclipse.ui.IPerspectiveListener4
+ * @since 3.1
+ */
+public class PerspectiveAdapter implements IPerspectiveListener4 {
+
+
+	@Override
+	public void perspectiveOpened(IWorkbenchPage page,
+			IPerspectiveDescriptor perspective) {
+		// do nothing
+	}
+
+	@Override
+	public void perspectiveClosed(IWorkbenchPage page,
+			IPerspectiveDescriptor perspective) {
+		// do nothing
+	}
+
+	@Override
+	public void perspectiveChanged(IWorkbenchPage page,
+			IPerspectiveDescriptor perspective,
+			IWorkbenchPartReference partRef, String changeId) {
+		// do nothing
+	}
+
+	@Override
+	public void perspectiveActivated(IWorkbenchPage page,
+			IPerspectiveDescriptor perspective) {
+		// do nothing
+	}
+
+	@Override
+	public void perspectiveChanged(IWorkbenchPage page,
+			IPerspectiveDescriptor perspective, String changeId) {
+		// do nothing
+	}
+
+	@Override
+	public void perspectiveDeactivated(IWorkbenchPage page,
+			IPerspectiveDescriptor perspective) {
+		// do nothing
+	}
+
+	@Override
+	public void perspectiveSavedAs(IWorkbenchPage page,
+			IPerspectiveDescriptor oldPerspective,
+			IPerspectiveDescriptor newPerspective) {
+		// do nothing
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * @since 3.2
+	 */
+	@Override
+	public void perspectivePreDeactivate(IWorkbenchPage page,
+			IPerspectiveDescriptor perspective) {
+		// do nothing
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/PlatformUI.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/PlatformUI.java
new file mode 100644
index 0000000..05ddfce
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/PlatformUI.java
@@ -0,0 +1,204 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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.ui;
+
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.rap.rwt.internal.service.ContextProvider;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.application.WorkbenchAdvisor;
+import org.eclipse.ui.internal.Workbench;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.util.PrefUtil;
+import org.eclipse.ui.testing.TestableObject;
+
+/**
+ * The central class for access to the Eclipse Platform User Interface.
+ * This class cannot be instantiated; all functionality is provided by
+ * static methods.
+ *
+ * Features provided:
+ * <ul>
+ * <li>creation of the workbench.</li>
+ * <li>access to the workbench.</li>
+ * </ul>
+ * <p>
+ *
+ * @see IWorkbench
+ */
+public final class PlatformUI {
+    /**
+     * Identifies the workbench plug-in.
+     */
+    public static final String PLUGIN_ID = "org.eclipse.rap.ui"; //$NON-NLS-1$
+    
+    // RAP [bm]: namespace of EP != bundle id
+    /**
+     * Identifies the namespace for extension points (RAP only)
+     */
+    public static final String PLUGIN_EXTENSION_NAME_SPACE = "org.eclipse.ui";  //$NON-NLS-1$
+    
+    /**
+     * Return code (value 0) indicating that the workbench terminated normally.
+     *
+     * @see #createAndRunWorkbench
+     * @since 3.0
+     */
+    public static final int RETURN_OK = 0;
+
+    /**
+     * Return code (value 1) indicating that the workbench was terminated with
+     * a call to <code>IWorkbench.restart</code>.
+     *
+     * @see #createAndRunWorkbench
+     * @see IWorkbench#restart
+     * @since 3.0
+     */
+    public static final int RETURN_RESTART = 1;
+
+    /**
+     * Return code (value 2) indicating that the workbench failed to start.
+     *
+     * @see #createAndRunWorkbench
+     * @see IWorkbench#restart
+     * @since 3.0
+     */
+    public static final int RETURN_UNSTARTABLE = 2;
+
+    /**
+     * Return code (value 3) indicating that the workbench was terminated with
+     * a call to IWorkbenchConfigurer#emergencyClose.
+     *
+     * @see #createAndRunWorkbench
+     * @since 3.0
+     */
+    public static final int RETURN_EMERGENCY_CLOSE = 3;
+
+    /**
+     * Block instantiation.
+     */
+    private PlatformUI() {
+        // do nothing
+    }
+
+    /**
+     * Returns the workbench. Fails if the workbench has not been created yet.
+     *
+     * @return the workbench
+     */
+    public static IWorkbench getWorkbench() {
+        if (Workbench.getInstance() == null) {
+            // app forgot to call createAndRunWorkbench beforehand
+            throw new IllegalStateException(WorkbenchMessages.get().PlatformUI_NoWorkbench);
+        }
+        return Workbench.getInstance();
+    }
+
+    /**
+	 * Returns whether {@link #createAndRunWorkbench createAndRunWorkbench} has
+	 * been called to create the workbench, and the workbench has yet to
+	 * terminate.
+	 * <p>
+	 * Note that this method may return <code>true</code> while the workbench
+	 * is still being initialized, so it may not be safe to call workbench API
+	 * methods even if this method returns true. See bug 49316 for details.
+	 * </p>
+	 *
+	 * @return <code>true</code> if the workbench has been created and is
+	 *         still running, and <code>false</code> if the workbench has not
+	 *         yet been created or has completed
+	 * @since 3.0
+	 */
+    public static boolean isWorkbenchRunning() {
+        // RAP [fappel]: should only called by UI-Threads. May cause trouble 
+        //                during bundle startup -> hasContext check. Think about
+        //                a better solution
+//      return Workbench.getInstance() != null
+//      && Workbench.getInstance().isRunning();
+        return    ContextProvider.hasContext()
+               && Workbench.getInstance() != null
+               && Workbench.getInstance().isRunning();
+    }
+
+    /**
+     * Creates the workbench and associates it with the given display and workbench
+     * advisor, and runs the workbench UI. This entails processing and dispatching
+     * events until the workbench is closed or restarted.
+     * <p>
+     * This method is intended to be called by the main class (the "application").
+     * Fails if the workbench UI has already been created.
+     * </p>
+     * <p>
+     * Use {@link #createDisplay createDisplay} to create the display to pass in.
+     * </p>
+     * <p>
+     * Note that this method is intended to be called by the application
+     * (<code>org.eclipse.core.boot.IPlatformRunnable</code>). It must be
+     * called exactly once, and early on before anyone else asks
+     * <code>getWorkbench()</code> for the workbench.
+     * </p>
+     *
+     * @param display the display to be used for all UI interactions with the workbench
+     * @param advisor the application-specific advisor that configures and
+     * specializes the workbench
+     * @return return code {@link #RETURN_OK RETURN_OK} for normal exit;
+     * {@link #RETURN_RESTART RETURN_RESTART} if the workbench was terminated
+     * with a call to {@link IWorkbench#restart IWorkbench.restart};
+     * {@link #RETURN_UNSTARTABLE RETURN_UNSTARTABLE} if the workbench could
+     * not be started;
+     * {@link #RETURN_EMERGENCY_CLOSE RETURN_EMERGENCY_CLOSE} if the UI quit
+     * because of an emergency; other values reserved for future use
+     * @since 3.0
+     */
+	public static int createAndRunWorkbench(Display display, WorkbenchAdvisor advisor) {
+        return Workbench.createAndRunWorkbench(display, advisor);
+    }
+
+    /**
+     * Creates the <code>Display</code> to be used by the workbench.
+     * It is the caller's responsibility to dispose the resulting <code>Display</code>,
+     * not the workbench's.
+     *
+     * @return the display
+     * @since 3.0
+     */
+    public static Display createDisplay() {
+        return Workbench.createDisplay();
+    }
+
+    /**
+     * Returns the testable object facade, for use by the test harness.
+     * <p>
+     * IMPORTANT: This method is only for use by the test harness.
+     * Applications and regular plug-ins should not call this method.
+     * </p><p>
+     * To avoid depending on the the Workbench a {@link TestableObject}
+     * can be obtained via OSGi service.
+     * </p>
+     *
+     * @return the testable object facade
+     * @since 3.0
+     */
+    public static TestableObject getTestableObject() {
+        return Workbench.getWorkbenchTestable();
+    }
+
+    /**
+     * Returns the preference store used for publicly settable workbench preferences.
+     * Constants for these preferences are defined on
+     * {@link org.eclipse.ui.IWorkbenchPreferenceConstants}.
+     *
+     * @return the workbench public preference store
+     * @since 3.0
+     */
+    public static IPreferenceStore getPreferenceStore() {
+        return PrefUtil.getAPIPreferenceStore();
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/Saveable.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/Saveable.java
new file mode 100644
index 0000000..be34868
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/Saveable.java
@@ -0,0 +1,314 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.window.IShellProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Cursor;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.internal.InternalSaveable;
+import org.eclipse.ui.internal.PartSite;
+import org.eclipse.ui.progress.IJobRunnable;
+
+/**
+ * A <code>Saveable</code> represents a unit of saveability, e.g. an editable
+ * subset of the underlying domain model that may contain unsaved changes.
+ * Different workbench parts (editors and views) may present the same saveables
+ * in different ways. This interface allows the workbench to provide more
+ * appropriate handling of operations such as saving and closing workbench
+ * parts. For example, if two editors sharing the same saveable with unsaved
+ * changes are closed simultaneously, the user is only prompted to save the
+ * changes once for the shared saveable, rather than once for each editor.
+ * <p>
+ * Workbench parts that work in terms of saveables should implement
+ * {@link ISaveablesSource}.
+ * </p>
+ *
+ * @see ISaveablesSource
+ * @since 3.2
+ */
+public abstract class Saveable extends InternalSaveable implements IAdaptable {
+
+	/**
+	 * Either {@code null} or the System's {@link SWT#CURSOR_WAIT} cursor
+	 * instance. Should never be disposed.
+	 */
+	private Cursor waitCursor;
+	private Cursor originalCursor;
+
+	/**
+	 * Attempts to show this saveable in the given page and returns
+	 * <code>true</code> on success. The default implementation does nothing
+	 * and returns <code>false</code>.
+	 *
+	 * @param page
+	 *            the workbench page in which to show this saveable
+	 * @return <code>true</code> if this saveable is now visible to the user
+	 * @since 3.3
+	 */
+	public boolean show(IWorkbenchPage page) {
+		if (page == null) {
+			// I wish it was easier to avoid warnings about unused parameters
+		}
+		return false;
+	}
+
+	/**
+	 * Returns the name of this saveable for display purposes.
+	 *
+	 * @return the model's name; never <code>null</code>.
+	 */
+	public abstract String getName();
+
+	/**
+	 * Returns the tool tip text for this saveable. This text is used to
+	 * differentiate between two inputs with the same name. For instance,
+	 * MyClass.java in folder X and MyClass.java in folder Y. The format of the
+	 * text varies between input types.
+	 *
+	 * @return the tool tip text; never <code>null</code>
+	 */
+	public abstract String getToolTipText();
+
+	/**
+	 * Returns the image descriptor for this saveable.
+	 *
+	 * @return the image descriptor for this model; may be <code>null</code>
+	 *         if there is no image
+	 */
+	public abstract ImageDescriptor getImageDescriptor();
+
+	/**
+	 * Saves the contents of this saveable.
+	 * <p>
+	 * If the save is cancelled through user action, or for any other reason,
+	 * the part should invoke <code>setCancelled</code> on the
+	 * <code>IProgressMonitor</code> to inform the caller.
+	 * </p>
+	 * <p>
+	 * This method is long-running; progress and cancellation are provided by
+	 * the given progress monitor.
+	 * </p>
+	 *
+	 * @param monitor
+	 *            the progress monitor
+	 * @throws CoreException
+	 *             if the save fails; it is the caller's responsibility to
+	 *             report the failure to the user
+	 */
+	public abstract void doSave(IProgressMonitor monitor) throws CoreException;
+
+	/**
+	 * Returns whether the contents of this saveable have changed since the last
+	 * save operation.
+	 * <p>
+	 * <b>Note:</b> this method is called frequently, for example by actions to
+	 * determine their enabled status.
+	 * </p>
+	 *
+	 * @return <code>true</code> if the contents have been modified and need
+	 *         saving, and <code>false</code> if they have not changed since
+	 *         the last save
+	 */
+	public abstract boolean isDirty();
+
+	/**
+	 * Clients must implement equals and hashCode as defined in
+	 * {@link Object#equals(Object)} and {@link Object#hashCode()}. Two
+	 * saveables should be equal if their dirty state is shared, and saving one
+	 * will save the other. If two saveables are equal, their names, tooltips,
+	 * and images should be the same because only one of them will be shown when
+	 * prompting the user to save.
+	 *
+	 * @param object
+	 * @return true if this Saveable is equal to the given object
+	 */
+	@Override
+	public abstract boolean equals(Object object);
+
+	/**
+	 * Clients must implement equals and hashCode as defined in
+	 * {@link Object#equals(Object)} and {@link Object#hashCode()}. Two
+	 * saveables should be equal if their dirty state is shared, and saving one
+	 * will save the other. If two saveables are equal, their hash codes MUST be
+	 * the same, and their names, tooltips, and images should be the same
+	 * because only one of them will be shown when prompting the user to save.
+	 * <p>
+	 * IMPORTANT: Implementers should ensure that the hashCode returned is
+	 * sufficiently unique so as not to collide with hashCodes returned by other
+	 * implementations. It is suggested that the defining plug-in's ID be used
+	 * as part of the returned hashCode, as in the following example:
+	 * </p>
+	 *
+	 * <pre>
+	 *     int PRIME = 31;
+	 *     int hash = ...; // compute the &quot;normal&quot; hash code, e.g. based on some identifier unique within the defining plug-in
+	 *     return hash * PRIME + MY_PLUGIN_ID.hashCode();
+	 * </pre>
+	 *
+	 * @return a hash code
+	 */
+	@Override
+	public abstract int hashCode();
+
+	/**
+	 * Saves this saveable, or prepares this saveable for a background save
+	 * operation. Returns null if this saveable has been successfully saved, or
+	 * a job runnable that needs to be run to complete the save in the
+	 * background. This method is called in the UI thread. If this saveable
+	 * supports saving in the background, it should do only minimal work.
+	 * However, since the job runnable returned by this method (if any) will not
+	 * run on the UI thread, this method should copy any state that can only be
+	 * accessed from the UI thread so that the job runnable will be able to
+	 * access it.
+	 * <p>
+	 * The supplied shell provider can be used from within this method and from
+	 * within the job runnable for the purpose of parenting dialogs. Care should
+	 * be taken not to open dialogs gratuitously and only if user input is
+	 * required for cases where the save cannot otherwise proceed - note that in
+	 * any given save operation, many saveable objects may be saved at the same
+	 * time. In particular, errors should be signaled by throwing an exception,
+	 * or if an error occurs while running the job runnable, an error status
+	 * should be returned.
+	 * </p>
+	 * <p>
+	 * If the foreground part of the save is cancelled through user action, or
+	 * for any other reason, the part should invoke <code>setCancelled</code>
+	 * on the <code>IProgressMonitor</code> to inform the caller. If the
+	 * background part of the save is cancelled, the job should return a
+	 * {@link IStatus#CANCEL} status.
+	 * </p>
+	 * <p>
+	 * This method is long-running; progress and cancellation are provided by
+	 * the given progress monitor.
+	 * </p>
+	 * <p>
+	 * The default implementation of this method calls
+	 * {@link #doSave(IProgressMonitor)} and returns <code>null</code>.
+	 * </p>
+	 *
+	 * @param monitor
+	 *            a progress monitor used for reporting progress and
+	 *            cancellation
+	 * @param shellProvider
+	 *            an object that can provide a shell for parenting dialogs
+	 * @return <code>null</code> if this saveable has been saved successfully,
+	 *         or a job runnable that needs to be run to complete the save in
+	 *         the background.
+	 * @throws CoreException
+	 *             if the save fails; it is the caller's responsibility to
+	 *             report the failure to the user
+	 * @since 3.3
+	 */
+	public IJobRunnable doSave(IProgressMonitor monitor,
+			IShellProvider shellProvider) throws CoreException {
+		doSave(monitor);
+		return null;
+	}
+
+	/**
+	 * Disables the UI of the given parts containing this saveable if necessary.
+	 * This method is not intended to be called by clients. A corresponding call
+	 * to
+	 * <p>
+	 * Saveables that can be saved in the background should ensure that the user
+	 * cannot make changes to their data from the UI, for example by disabling
+	 * controls, unless they are prepared to handle this case. This method is
+	 * called on the UI thread after a job runnable has been returned from
+	 * {@link #doSave(IProgressMonitor, IShellProvider)} and before
+	 * spinning the event loop. The <code>closing</code> flag indicates that
+	 * this saveable is currently being saved in response to closing a workbench
+	 * part, in which case further changes to this saveable through the UI must
+	 * be prevented.
+	 * </p>
+	 * <p>
+	 * The default implementation calls setEnabled(false) on the given parts'
+	 * composites.
+	 * </p>
+	 *
+	 * @param parts
+	 *            the workbench parts containing this saveable
+	 * @param closing
+	 *            a boolean flag indicating whether the save was triggered by a
+	 *            request to close a workbench part, and all of the given parts
+	 *            will be closed after the save operation finishes successfully.
+	 *
+	 * @since 3.3
+	 */
+	public void disableUI(IWorkbenchPart[] parts, boolean closing) {
+		for (IWorkbenchPart workbenchPart : parts) {
+			Composite paneComposite = (Composite) ((PartSite) workbenchPart.getSite()).getModel().getWidget();
+			Control[] paneChildren = paneComposite.getChildren();
+			Composite toDisable = ((Composite) paneChildren[0]);
+			toDisable.setEnabled(false);
+			if (waitCursor == null) {
+				waitCursor = workbenchPart.getSite().getWorkbenchWindow().getShell().getDisplay()
+						.getSystemCursor(SWT.CURSOR_WAIT);
+			}
+			if (waitCursor.equals(paneComposite.getCursor())) {
+				originalCursor = paneComposite.getCursor();
+				paneComposite.setCursor(waitCursor);
+			}
+		}
+	}
+
+	/**
+	 * Enables the UI of the given parts containing this saveable after a
+	 * background save operation has finished. This method is not intended to be
+	 * called by clients.
+	 * <p>
+	 * The default implementation calls setEnabled(true) on the given parts'
+	 * composites.
+	 * </p>
+	 *
+	 * @param parts
+	 *            the workbench parts containing this saveable
+	 *
+	 * @since 3.3
+	 */
+	public void enableUI(IWorkbenchPart[] parts) {
+		for (IWorkbenchPart workbenchPart : parts) {
+			Composite paneComposite = (Composite) ((PartSite) workbenchPart.getSite()).getModel().getWidget();
+			Control[] paneChildren = paneComposite.getChildren();
+			Composite toEnable = ((Composite) paneChildren[0]);
+			paneComposite.setCursor(originalCursor);
+			if (waitCursor != null) {
+				/*
+				 * waitCursor is always the System SWT.CURSOR_WAIT instance and
+				 * should never be disposed
+				 */
+				waitCursor = null;
+			}
+			toEnable.setEnabled(true);
+		}
+	}
+
+	/**
+	 * This implementation of {@link IAdaptable#getAdapter(Class)} returns
+	 * <code>null</code>. Subclasses may override. This allows two unrelated
+	 * subclasses of Saveable to implement {@link #equals(Object)} and
+	 * {@link #hashCode()} based on an underlying implementation class that is
+	 * shared by both Saveable subclasses.
+	 *
+	 * @since 3.3
+	 */
+	@Override
+	public <T> T getAdapter(Class<T> adapter) {
+		return null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/SaveablesLifecycleEvent.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/SaveablesLifecycleEvent.java
new file mode 100644
index 0000000..b3049cf
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/SaveablesLifecycleEvent.java
@@ -0,0 +1,135 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui;
+
+import java.util.EventObject;
+
+
+/**
+ * Event object describing a change to a set of Saveable objects.
+ *
+ * @since 3.2
+ */
+public class SaveablesLifecycleEvent extends EventObject {
+
+	/**
+	 * Serial version UID for this class.
+	 * <p>
+	 * Note: This class is not intended to be serialized.
+	 * </p>
+	 */
+	private static final long serialVersionUID = -3530773637989046452L;
+
+	/**
+	 * Event type constant specifying that the given saveables have been opened.
+	 */
+	public static final int POST_OPEN = 1;
+
+	/**
+	 * Event type constant specifying that the given saveables are about to be
+	 * closed. Listeners may veto the closing if isForce() is false.
+	 */
+	public static final int PRE_CLOSE = 2;
+
+	/**
+	 * Event type constant specifying that the given saveables have been closed.
+	 */
+	public static final int POST_CLOSE = 3;
+
+	/**
+	 * Event type constant specifying that the dirty state of the given saveables
+	 * has changed.
+	 */
+	public static final int DIRTY_CHANGED = 4;
+
+	private int eventType;
+
+	private Saveable[] saveables;
+
+	private boolean force;
+
+	private boolean veto = false;
+
+	/**
+	 * Creates a new SaveablesLifecycleEvent.
+	 *
+	 * @param source
+	 *            The source of the event. If an ISaveablesSource notifies
+	 *            about changes to the saveables returned by
+	 *            {@link ISaveablesSource#getSaveables()}, the source must be
+	 *            the ISaveablesSource object.
+	 * @param eventType
+	 *            the event type, currently one of POST_OPEN, PRE_CLOSE,
+	 *            POST_CLOSE, DIRTY_CHANGED
+	 * @param saveables
+	 *            The affected saveables
+	 * @param force
+	 *            true if the event type is PRE_CLOSE and this is a closed force
+	 *            that cannot be canceled.
+	 */
+	public SaveablesLifecycleEvent(Object source, int eventType,
+			Saveable[] saveables, boolean force) {
+		super(source);
+		this.eventType = eventType;
+		this.saveables = saveables;
+		this.force = force;
+	}
+
+	/**
+	 * Returns the eventType, currently one of POST_OPEN, PRE_CLOSE, POST_CLOSE,
+	 * DIRTY_CHANGED. Listeners should silently ignore unknown event types since
+	 * new event types might be added in the future.
+	 *
+	 * @return the eventType
+	 */
+	public int getEventType() {
+		return eventType;
+	}
+
+	/**
+	 * Returns the affected saveables.
+	 *
+	 * @return the saveables
+	 */
+	public Saveable[] getSaveables() {
+		return saveables;
+	}
+
+	/**
+	 * Returns the veto. This value is ignored for POST_OPEN,POST_CLOSE, and
+	 * DIRTY_CHANGED.
+	 *
+	 * @return Returns the veto.
+	 */
+	public boolean isVeto() {
+		return veto;
+	}
+
+	/**
+	 * @param veto
+	 *            The veto to set.
+	 */
+	public void setVeto(boolean veto) {
+		this.veto = veto;
+	}
+
+	/**
+	 * Sets the force flag. This value is ignored for POST_OPEN, POST_CLOSE, and
+	 * DIRTY_CHANGED.
+	 *
+	 * @return Returns the force.
+	 */
+	public boolean isForce() {
+		return force;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/SelectionEnabler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/SelectionEnabler.java
new file mode 100644
index 0000000..96e6c44
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/SelectionEnabler.java
@@ -0,0 +1,521 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.ui.actions.SimpleWildcardTester;
+import org.eclipse.ui.internal.ActionExpression;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.util.Util;
+import org.eclipse.ui.model.IWorkbenchAdapter;
+import org.osgi.framework.Bundle;
+
+/**
+ * Determines the enablement status given a selection. This calculation is done
+ * based on the definition of the <code>enablesFor</code> attribute,
+ * <code>enablement</code> element, and the <code>selection</code> element
+ * found in the <code>IConfigurationElement</code> provided.
+ * <p>
+ * This class can be instantiated by clients. It is not intended to be extended.
+ * </p>
+ *
+ * @since 3.0
+ *
+ * Note: The dependency on org.eclipse.jface.text for ITextSelection must be
+ * severed It may be possible to do with IActionFilter generic workbench
+ * registers IActionFilter for "size" property against IStructuredSelection
+ * workbench text registers IActionFilter for "size" property against
+ * ITextSelection code here: sel.getAdapter(IActionFilter.class) As an interim
+ * solution, use reflection to access selections implementing ITextSelection
+ */
+public final class SelectionEnabler {
+
+	/* package */static class SelectionClass {
+		public String className;
+
+		public String nameFilter;
+
+		public boolean recursive;
+	}
+
+	public static final int ANY_NUMBER = -2;
+
+	/**
+	 * The constant integer hash code value meaning the hash code has not yet
+	 * been computed.
+	 */
+	private static final int HASH_CODE_NOT_COMPUTED = -1;
+
+	/**
+	 * A factor for computing the hash code for all schemes.
+	 */
+	private static final int HASH_FACTOR = 89;
+
+	/**
+	 * The seed for the hash code for all schemes.
+	 */
+	private static final int HASH_INITIAL = SelectionEnabler.class.getName()
+			.hashCode();
+
+	/**
+	 * Cached value of <code>org.eclipse.jface.text.ITextSelection.class</code>;
+	 * <code>null</code> if not initialized or not present.
+	 */
+	private static Class iTextSelectionClass = null;
+
+	/**
+	 * Hard-wired id of the JFace text plug-in (not on pre-req chain).
+	 */
+	private static final String JFACE_TEXT_PLUG_IN = "org.eclipse.jface.text"; //$NON-NLS-1$
+
+	public static final int MULTIPLE = -5;
+
+	public static final int NONE = -4;
+
+	public static final int NONE_OR_ONE = -3;
+
+	public static final int ONE_OR_MORE = -1;
+
+	/**
+	 * Hard-wired fully qualified name of the text selection class (not on
+	 * pre-req chain).
+	 */
+	private static final String TEXT_SELECTION_CLASS = "org.eclipse.jface.text.ITextSelection"; //$NON-NLS-1$
+
+	/**
+	 * Indicates whether the JFace text plug-in is even around. Without the
+	 * JFace text plug-in, text selections are moot.
+	 */
+	private static boolean textSelectionPossible = true;
+
+	public static final int UNKNOWN = 0;
+
+	/**
+	 * Returns <code>ITextSelection.class</code> or <code>null</code> if the
+	 * class is not available.
+	 *
+	 * @return <code>ITextSelection.class</code> or <code>null</code> if
+	 *         class not available
+	 * @since 3.0
+	 */
+	private static Class getTextSelectionClass() {
+		if (iTextSelectionClass != null) {
+			// tried before and succeeded
+			return iTextSelectionClass;
+		}
+		if (!textSelectionPossible) {
+			// tried before and failed
+			return null;
+		}
+
+		// JFace text plug-in is not on prereq chain of generic wb plug-in
+		// hence: ITextSelection.class won't compile
+		// and Class.forName("org.eclipse.jface.text.ITextSelection") won't find
+		// it need to be trickier...
+		Bundle bundle = Platform.getBundle(JFACE_TEXT_PLUG_IN);
+		if (bundle == null || bundle.getState() == Bundle.UNINSTALLED) {
+			// JFace text plug-in is not around, or has already
+			// been removed, assume that it will never be around
+			textSelectionPossible = false;
+			return null;
+		}
+
+		// plug-in is around
+		// it's not our job to activate the plug-in
+		if (bundle.getState() == Bundle.INSTALLED) {
+			// assume it might come alive later
+			textSelectionPossible = true;
+			return null;
+		}
+
+		try {
+			Class c = bundle.loadClass(TEXT_SELECTION_CLASS);
+			// remember for next time
+			iTextSelectionClass = c;
+			return iTextSelectionClass;
+		} catch (ClassNotFoundException e) {
+			// unable to load ITextSelection - sounds pretty serious
+			// treat as if JFace text plug-in were unavailable
+			textSelectionPossible = false;
+			return null;
+		}
+	}
+
+	/**
+	 * Verifies that the given name matches the given wildcard filter. Returns
+	 * true if it does.
+	 *
+	 * @param name
+	 * @param filter
+	 * @return <code>true</code> if there is a match
+	 */
+	public static boolean verifyNameMatch(String name, String filter) {
+		return SimpleWildcardTester.testWildcardIgnoreCase(filter, name);
+	}
+
+	private List classes = new ArrayList();
+
+	private ActionExpression enablementExpression;
+
+	/**
+	 * The hash code for this object. This value is computed lazily, and marked
+	 * as invalid when one of the values on which it is based changes.
+	 */
+	private transient int hashCode = HASH_CODE_NOT_COMPUTED;
+
+	private int mode = UNKNOWN;
+
+	/**
+	 * Create a new instance of the receiver.
+	 *
+	 * @param configElement
+	 */
+	public SelectionEnabler(IConfigurationElement configElement) {
+		super();
+		if (configElement == null) {
+			throw new IllegalArgumentException();
+		}
+		parseClasses(configElement);
+	}
+
+	@Override
+	public final boolean equals(final Object object) {
+		if (object instanceof SelectionEnabler) {
+			final SelectionEnabler that = (SelectionEnabler) object;
+			return Util.equals(this.classes, that.classes)
+					&& Util.equals(this.enablementExpression,
+							that.enablementExpression)
+					&& Util.equals(this.mode, that.mode);
+		}
+
+		return false;
+	}
+
+	/**
+	 * Computes the hash code for this object based on the id.
+	 *
+	 * @return The hash code for this object.
+	 */
+	@Override
+	public final int hashCode() {
+		if (hashCode == HASH_CODE_NOT_COMPUTED) {
+			hashCode = HASH_INITIAL * HASH_FACTOR + Util.hashCode(classes);
+			hashCode = hashCode * HASH_FACTOR
+					+ Util.hashCode(enablementExpression);
+			hashCode = hashCode * HASH_FACTOR + Util.hashCode(mode);
+			if (hashCode == HASH_CODE_NOT_COMPUTED) {
+				hashCode++;
+			}
+		}
+		return hashCode;
+	}
+
+	/**
+	 * Returns true if given structured selection matches the conditions
+	 * specified in the registry for this action.
+	 */
+	private boolean isEnabledFor(ISelection sel) {
+		Object obj = sel;
+		int count = sel.isEmpty() ? 0 : 1;
+
+		if (verifySelectionCount(count) == false) {
+			return false;
+		}
+
+		// Compare selection to enablement expression.
+		if (enablementExpression != null) {
+			return enablementExpression.isEnabledFor(obj);
+		}
+
+		// Compare selection to class requirements.
+		if (classes.isEmpty()) {
+			return true;
+		}
+		if (obj instanceof IAdaptable) {
+			IAdaptable element = (IAdaptable) obj;
+			if (verifyElement(element) == false) {
+				return false;
+			}
+		} else {
+			return false;
+		}
+
+		return true;
+	}
+
+	/**
+	 * Returns true if given text selection matches the conditions specified in
+	 * the registry for this action.
+	 */
+	private boolean isEnabledFor(ISelection sel, int count) {
+		if (verifySelectionCount(count) == false) {
+			return false;
+		}
+
+		// Compare selection to enablement expression.
+		if (enablementExpression != null) {
+			return enablementExpression.isEnabledFor(sel);
+		}
+
+		// Compare selection to class requirements.
+		if (classes.isEmpty()) {
+			return true;
+		}
+		for (int i = 0; i < classes.size(); i++) {
+			SelectionClass sc = (SelectionClass) classes.get(i);
+			if (verifyClass(sel, sc.className)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Returns true if given structured selection matches the conditions
+	 * specified in the registry for this action.
+	 */
+	private boolean isEnabledFor(IStructuredSelection ssel) {
+		int count = ssel.size();
+
+		if (verifySelectionCount(count) == false) {
+			return false;
+		}
+
+		// Compare selection to enablement expression.
+		if (enablementExpression != null) {
+			return enablementExpression.isEnabledFor(ssel);
+		}
+
+		// Compare selection to class requirements.
+		if (classes.isEmpty()) {
+			return true;
+		}
+		for (Iterator elements = ssel.iterator(); elements.hasNext();) {
+			Object obj = elements.next();
+			if (obj instanceof IAdaptable) {
+				IAdaptable element = (IAdaptable) obj;
+				if (verifyElement(element) == false) {
+					return false;
+				}
+			} else {
+				return false;
+			}
+		}
+
+		return true;
+	}
+
+	/**
+	 * Check if the receiver is enabled for the given selection.
+	 *
+	 * @param selection
+	 * @return <code>true</code> if the given selection matches the conditions
+	 *         specified in <code>IConfirgurationElement</code>.
+	 */
+	public boolean isEnabledForSelection(ISelection selection) {
+		// Optimize it.
+		if (mode == UNKNOWN) {
+			return false;
+		}
+
+		// Handle undefined selections.
+		if (selection == null) {
+			selection = StructuredSelection.EMPTY;
+		}
+
+		// According to the dictionary, a selection is "one that
+		// is selected", or "a collection of selected things".
+		// In reflection of this, we deal with one or a collection.
+
+		// special case: structured selections
+		if (selection instanceof IStructuredSelection) {
+			return isEnabledFor((IStructuredSelection) selection);
+		}
+
+		// special case: text selections
+		// Code should read
+		// if (selection instanceof ITextSelection) {
+		// int count = ((ITextSelection) selection).getLength();
+		// return isEnabledFor(selection, count);
+		// }
+		// use Java reflection to avoid dependence of org.eclipse.jface.text
+		// which is in an optional part of the generic workbench
+		Class tselClass = getTextSelectionClass();
+		if (tselClass != null && tselClass.isInstance(selection)) {
+			try {
+				Method m = tselClass.getDeclaredMethod(
+						"getLength", new Class[0]); //$NON-NLS-1$
+				Object r = m.invoke(selection, new Object[0]);
+				if (r instanceof Integer) {
+					return isEnabledFor(selection, ((Integer) r).intValue());
+				}
+				// should not happen - but enable if it does
+				return true;
+			} catch (NoSuchMethodException e) {
+				// should not happen - fall through if it does
+			} catch (IllegalAccessException e) {
+				// should not happen - fall through if it does
+			} catch (InvocationTargetException e) {
+				// should not happen - fall through if it does
+			}
+		}
+
+		// all other cases
+		return isEnabledFor(selection);
+	}
+
+	/**
+	 * Parses registry element to extract mode and selection elements that will
+	 * be used for verification.
+	 */
+	private void parseClasses(IConfigurationElement config) {
+		// Get enables for.
+		String enablesFor = config
+				.getAttribute(IWorkbenchRegistryConstants.ATT_ENABLES_FOR);
+		if (enablesFor == null) {
+			enablesFor = "*"; //$NON-NLS-1$
+		}
+		if (enablesFor.equals("*")) { //$NON-NLS-1$
+			mode = ANY_NUMBER;
+		} else if (enablesFor.equals("?")) { //$NON-NLS-1$
+			mode = NONE_OR_ONE;
+		} else if (enablesFor.equals("!")) { //$NON-NLS-1$
+			mode = NONE;
+		} else if (enablesFor.equals("+")) { //$NON-NLS-1$
+			mode = ONE_OR_MORE;
+		} else if (enablesFor.equals("multiple") //$NON-NLS-1$
+				|| enablesFor.equals("2+")) { //$NON-NLS-1$
+			mode = MULTIPLE;
+		} else {
+			try {
+				mode = Integer.parseInt(enablesFor);
+			} catch (NumberFormatException e) {
+				mode = UNKNOWN;
+			}
+		}
+
+		// Get enablement block.
+		IConfigurationElement[] children = config
+				.getChildren(IWorkbenchRegistryConstants.TAG_ENABLEMENT);
+		if (children.length > 0) {
+			enablementExpression = new ActionExpression(children[0]);
+			return;
+		}
+
+		// Get selection block.
+		children = config
+				.getChildren(IWorkbenchRegistryConstants.TAG_SELECTION);
+		if (children.length > 0) {
+			classes = new ArrayList();
+			for (IConfigurationElement sel : children) {
+				String cname = sel
+						.getAttribute(IWorkbenchRegistryConstants.ATT_CLASS);
+				String name = sel
+						.getAttribute(IWorkbenchRegistryConstants.ATT_NAME);
+				SelectionClass sclass = new SelectionClass();
+				sclass.className = cname;
+				sclass.nameFilter = name;
+				classes.add(sclass);
+			}
+		}
+	}
+
+	/**
+	 * Verifies if the element is an instance of a class with a given class
+	 * name. If direct match fails, implementing interfaces will be tested, then
+	 * recursively all superclasses and their interfaces.
+	 */
+	private boolean verifyClass(Object element, String className) {
+		Class eclass = element.getClass();
+		Class clazz = eclass;
+		boolean match = false;
+		while (clazz != null) {
+			// test the class itself
+			if (clazz.getName().equals(className)) {
+				match = true;
+				break;
+			}
+			// test all the interfaces it implements
+			Class[] interfaces = clazz.getInterfaces();
+			for (Class currentInterface : interfaces) {
+				if (currentInterface.getName().equals(className)) {
+					match = true;
+					break;
+				}
+			}
+			if (match == true) {
+				break;
+			}
+			// get the superclass
+			clazz = clazz.getSuperclass();
+		}
+		return match;
+	}
+
+	/**
+	 * Verifies if the given element matches one of the selection requirements.
+	 * Element must at least pass the type test, and optionally wildcard name
+	 * match.
+	 */
+	private boolean verifyElement(IAdaptable element) {
+		if (classes.isEmpty()) {
+			return true;
+		}
+		for (int i = 0; i < classes.size(); i++) {
+			SelectionClass sc = (SelectionClass) classes.get(i);
+			if (verifyClass(element, sc.className) == false) {
+				continue;
+			}
+			if (sc.nameFilter == null) {
+				return true;
+			}
+			IWorkbenchAdapter de = Adapters.adapt(element, IWorkbenchAdapter.class);
+			if ((de != null)
+					&& verifyNameMatch(de.getLabel(element), sc.nameFilter)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Compare selection count with requirements.
+	 */
+	private boolean verifySelectionCount(int count) {
+		if (count > 0 && mode == NONE) {
+			return false;
+		}
+		if (count == 0 && mode == ONE_OR_MORE) {
+			return false;
+		}
+		if (count > 1 && mode == NONE_OR_ONE) {
+			return false;
+		}
+		if (count < 2 && mode == MULTIPLE) {
+			return false;
+		}
+		if (mode > 0 && count != mode) {
+			return false;
+		}
+		return true;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/SubActionBars.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/SubActionBars.java
new file mode 100644
index 0000000..6da9230
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/SubActionBars.java
@@ -0,0 +1,625 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *******************************************************************************/
+package org.eclipse.ui;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.core.commands.common.EventManager;
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.ExpressionInfo;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.IStatusLineManager;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.action.SubMenuManager;
+import org.eclipse.jface.action.SubStatusLineManager;
+import org.eclipse.jface.action.SubToolBarManager;
+import org.eclipse.jface.commands.ActionHandler;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.ui.handlers.IHandlerActivation;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.internal.EditorActionBars;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.actions.CommandAction;
+import org.eclipse.ui.internal.handlers.CommandLegacyActionWrapper;
+import org.eclipse.ui.internal.handlers.IActionCommandMappingService;
+import org.eclipse.ui.internal.services.SourcePriorityNameMapping;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * Generic implementation of the <code>IActionBars</code> interface.
+ */
+public class SubActionBars extends EventManager implements IActionBars {
+
+	/**
+	 * The expression to use when contributing handlers through
+	 * {@link #setGlobalActionHandler(String, IAction)}}. This ensures that
+	 * handlers contributed through {@link SubActionBars} are given priority
+	 * over handlers contributed to the {@link IHandlerService}.
+	 */
+	private static final Expression EXPRESSION = new Expression() {
+		@Override
+		public final EvaluationResult evaluate(final IEvaluationContext context) {
+			return EvaluationResult.TRUE;
+		}
+
+		@Override
+		public final void collectExpressionInfo(final ExpressionInfo info) {
+			info
+					.addVariableNameAccess(SourcePriorityNameMapping.LEGACY_LEGACY_NAME);
+		}
+	};
+
+	/**
+	 * Property constant for changes to action handlers.
+	 */
+	public static final String P_ACTION_HANDLERS = "org.eclipse.ui.internal.actionHandlers"; //$NON-NLS-1$
+
+	private Map actionHandlers;
+
+	private boolean actionHandlersChanged;
+
+	/**
+	 * A map of handler activations ({@link IHandlerActivation} indexed by
+	 * action id ({@link String}) indexed by service locator ({@link IServiceLocator}).
+	 * This value is <code>null</code> if there are no activations.
+	 */
+	private Map activationsByActionIdByServiceLocator;
+
+	private boolean active = false;
+
+	private SubMenuManager menuMgr;
+
+	private IActionBars parent;
+
+	/**
+	 * A service locator appropriate for this action bar. This value is never
+	 * <code>null</code>. It must be capable of providing a
+	 * {@link IHandlerService}.
+	 */
+	private IServiceLocator serviceLocator;
+
+	private SubStatusLineManager statusLineMgr;
+
+	private SubToolBarManager toolBarMgr;
+
+	private Map actionIdByCommandId = new HashMap();
+
+	/**
+	 * Construct a new <code>SubActionBars</code> object. The service locator
+	 * will simply be the service locator of the parent.
+	 *
+	 * @param parent
+	 *            The parent of this action bar; must not be <code>null</code>.
+	 */
+	public SubActionBars(final IActionBars parent) {
+		this(parent, null);
+	}
+
+	/**
+	 * Constructs a new instance of <code>SubActionBars</code>.
+	 *
+	 * @param parent
+	 *            The parent of this action bar; must not be <code>null</code>.
+	 * @param serviceLocator
+	 *            The service locator for this action bar; should not be
+	 *            <code>null</code>.
+	 *
+	 * @since 3.2
+	 */
+	public SubActionBars(final IActionBars parent,
+			final IServiceLocator serviceLocator) {
+		if (parent == null) {
+			throw new NullPointerException("The parent cannot be null"); //$NON-NLS-1$
+		}
+
+		this.parent = parent;
+		this.serviceLocator = serviceLocator;
+	}
+
+	/**
+	 * Activate the contributions.
+	 */
+	public void activate() {
+		activate(true);
+	}
+
+	/**
+	 * Activate the contributions.
+	 * <p>
+	 * Workaround for toolbar layout flashing when editors contribute large
+	 * amounts of items. In this case we want to force the items to be
+	 * visible/hidden only when required, otherwise just change the enablement
+	 * state.
+	 * </p>
+	 */
+	public void activate(boolean forceVisibility) {
+		setActive(true);
+	}
+
+	/**
+	 * Adds a property change listener. Has no effect if an identical listener
+	 * is already registered.
+	 *
+	 * @param listener
+	 *            a property change listener
+	 */
+	public void addPropertyChangeListener(IPropertyChangeListener listener) {
+		addListenerObject(listener);
+	}
+
+	/**
+	 * Sets the active flag. Clients should not call this method directly unless
+	 * they are overriding the setActive() method.
+	 */
+	protected final void basicSetActive(boolean active) {
+		this.active = active;
+	}
+
+	/**
+	 * Clear the global action handlers.
+	 */
+	@Override
+	public void clearGlobalActionHandlers() {
+		if (actionHandlers != null) {
+			actionHandlers.clear();
+			actionHandlersChanged = true;
+		}
+
+		if (activationsByActionIdByServiceLocator != null) {
+			// Clean up the activations.
+			final Iterator activationItr = activationsByActionIdByServiceLocator
+					.entrySet().iterator();
+			while (activationItr.hasNext()) {
+				final Map.Entry value = (Map.Entry) activationItr.next();
+				final IServiceLocator locator = (IServiceLocator) value
+						.getKey();
+				final IHandlerService service = locator
+						.getService(IHandlerService.class);
+				final Map activationsByActionId = (Map) value.getValue();
+				Collection activations = activationsByActionId.values();
+				if (service != null) {
+					service.deactivateHandlers(activations);
+				}
+
+				for (Object activation : activations) {
+					((IHandlerActivation) activation).getHandler().dispose();
+				}
+			}
+			activationsByActionIdByServiceLocator.clear();
+		}
+	}
+
+	/**
+	 * Returns a new sub menu manager.
+	 *
+	 * @param parent
+	 *            the parent menu manager
+	 * @return the menu manager
+	 */
+	protected SubMenuManager createSubMenuManager(IMenuManager parent) {
+		return new SubMenuManager(parent);
+	}
+
+	/**
+	 * Returns a new sub toolbar manager.
+	 *
+	 * @param parent
+	 *            the parent toolbar manager
+	 * @return the tool bar manager
+	 */
+	protected SubToolBarManager createSubToolBarManager(IToolBarManager parent) {
+		return new SubToolBarManager(parent);
+	}
+
+	/**
+	 * Deactivate the contributions.
+	 */
+	public void deactivate() {
+		deactivate(true);
+	}
+
+	/**
+	 * Deactivate the contributions.
+	 * <p>
+	 * Workaround for menubar/toolbar layout flashing when editors have many
+	 * contributions. In this case we want to force the contributions to be
+	 * visible/hidden only when required, otherwise just change the enablement
+	 * state.
+	 * </p>
+	 */
+	public void deactivate(boolean forceHide) {
+		setActive(false);
+	}
+
+	/**
+	 * Dispose the contributions.
+	 */
+	public void dispose() {
+		clearGlobalActionHandlers();
+		if (menuMgr != null) {
+			menuMgr.dispose();
+			menuMgr.disposeManager();
+		}
+		if (statusLineMgr != null) {
+			statusLineMgr.disposeManager();
+		}
+		if (toolBarMgr != null) {
+			toolBarMgr.disposeManager();
+		}
+		clearListeners();
+	}
+
+	/**
+	 * Notifies any property change listeners if the global action handlers have
+	 * changed
+	 */
+	protected void fireActionHandlersChanged() {
+		if (actionHandlersChanged) {
+			// Doesn't actually pass the old and new values
+			firePropertyChange(new PropertyChangeEvent(this, P_ACTION_HANDLERS,
+					null, null));
+			actionHandlersChanged = false;
+		}
+	}
+
+	/**
+	 * Notifies any property change listeners that a property has changed. Only
+	 * listeners registered at the time this method is called are notified.
+	 *
+	 * @param event
+	 *            the property change event
+	 *
+	 * @see IPropertyChangeListener#propertyChange
+	 */
+	protected void firePropertyChange(PropertyChangeEvent event) {
+		Object[] listeners = getListeners();
+		for (Object listener : listeners) {
+			((IPropertyChangeListener) listener).propertyChange(event);
+		}
+	}
+
+	/**
+	 * Return whether the manager is currently active or not.
+	 */
+	protected final boolean getActive() {
+		return active;
+	}
+
+	/**
+	 * Get the handler for a window action.
+	 *
+	 * @param actionID
+	 *            an action ID declared in the registry
+	 * @return an action handler which implements the action ID, or
+	 *         <code>null</code> if none is registered.
+	 */
+	@Override
+	public IAction getGlobalActionHandler(String actionID) {
+		if (actionHandlers == null) {
+			return null;
+		}
+		return (IAction) actionHandlers.get(actionID);
+	}
+
+	/**
+	 * Returns the complete list of active global action handlers. If there are
+	 * no global action handlers registered return null.
+	 */
+	public Map getGlobalActionHandlers() {
+		return actionHandlers;
+	}
+
+	/**
+	 * Returns the abstract menu manager. If items are added or removed from the
+	 * manager be sure to call <code>updateActionBars</code>.
+	 *
+	 * @return the menu manager
+	 */
+	@Override
+	public IMenuManager getMenuManager() {
+		if (menuMgr == null) {
+			menuMgr = createSubMenuManager(parent.getMenuManager());
+			menuMgr.setVisible(active);
+		}
+		return menuMgr;
+	}
+
+	/**
+	 * Return the parent action bar manager.
+	 */
+	protected final IActionBars getParent() {
+		return parent;
+	}
+
+	/**
+	 * Answer the service locator for this action bar.
+	 *
+	 * @return an <code>IServiceLocater</code> or the parents if
+	 *     the receiver does not have one
+	 *
+	 * @since 3.2
+	 */
+	@Override
+	public final IServiceLocator getServiceLocator() {
+		if (serviceLocator != null) {
+			return serviceLocator;
+		}
+
+		return parent.getServiceLocator();
+	}
+
+	/**
+	 * Returns the status line manager. If items are added or removed from the
+	 * manager be sure to call <code>updateActionBars</code>.
+	 *
+	 * @return the status line manager
+	 */
+	@Override
+	public IStatusLineManager getStatusLineManager() {
+		if (statusLineMgr == null) {
+			statusLineMgr = new SubStatusLineManager(parent
+					.getStatusLineManager());
+			statusLineMgr.setVisible(active);
+		}
+		return statusLineMgr;
+	}
+
+	/**
+	 * Returns the tool bar manager. If items are added or removed from the
+	 * manager be sure to call <code>updateActionBars</code>.
+	 *
+	 * @return the tool bar manager
+	 */
+	@Override
+	public IToolBarManager getToolBarManager() {
+		if (toolBarMgr == null) {
+			toolBarMgr = createSubToolBarManager(parent.getToolBarManager());
+			toolBarMgr.setVisible(active);
+		}
+		return toolBarMgr;
+	}
+
+	/**
+	 * Return whether the sub menu manager has been created yet.
+	 */
+	protected final boolean isSubMenuManagerCreated() {
+		return menuMgr != null;
+	}
+
+	/**
+	 * Return whether the sub status line manager has been created yet.
+	 */
+	protected final boolean isSubStatusLineManagerCreated() {
+		return statusLineMgr != null;
+	}
+
+	/**
+	 * Return whether the sub toolbar manager has been created yet.
+	 */
+	protected final boolean isSubToolBarManagerCreated() {
+		return toolBarMgr != null;
+	}
+
+	/**
+	 * Notification that the target part for the action bars has changed.
+	 */
+	public void partChanged(IWorkbenchPart part) {
+	}
+
+	/**
+	 * Removes the given property change listener. Has no effect if an identical
+	 * listener is not registered.
+	 *
+	 * @param listener
+	 *            a property change listener
+	 */
+	public void removePropertyChangeListener(IPropertyChangeListener listener) {
+		removeListenerObject(listener);
+	}
+
+	/**
+	 * Activate / deactivate the contributions.
+	 */
+	protected void setActive(boolean set) {
+		active = set;
+		if (menuMgr != null) {
+			menuMgr.setVisible(set);
+		}
+
+		if (statusLineMgr != null) {
+			statusLineMgr.setVisible(set);
+		}
+
+		if (toolBarMgr != null) {
+			toolBarMgr.setVisible(set);
+		}
+	}
+
+	/**
+	 * Add a handler for a window action.
+	 *
+	 * @param actionID
+	 *            an action ID declared in the registry
+	 * @param handler
+	 *            an action which implements the action ID. <code>null</code>
+	 *            may be passed to deregister a handler.
+	 */
+	@Override
+	public void setGlobalActionHandler(String actionID, IAction handler) {
+		if (actionID == null) {
+			/*
+			 * Bug 124061. It used to be invalid to pass null as an action id,
+			 * but some people still did it. Handle this case by trapping the
+			 * exception and logging it.
+			 */
+			WorkbenchPlugin
+					.log("Cannot set the global action handler for a null action id"); //$NON-NLS-1$
+			return;
+		}
+
+		if (handler instanceof CommandLegacyActionWrapper) {
+        	// this is a registration of a fake action for an already
+			// registered handler
+			WorkbenchPlugin
+					.log("Cannot feed a CommandLegacyActionWrapper back into the system"); //$NON-NLS-1$
+			return;
+		}
+
+		if (handler instanceof CommandAction) {
+			// we unfortunately had to allow these out into the wild, but they
+			// still must not feed back into the system
+			return;
+		}
+
+		if (handler != null) {
+			// Update the action handlers.
+			if (actionHandlers == null) {
+				actionHandlers = new HashMap(11);
+			}
+			actionHandlers.put(actionID, handler);
+
+			// Add a mapping from this action id to the command id.
+			if (serviceLocator != null) {
+				String commandId = null;
+				final IActionCommandMappingService mappingService = serviceLocator
+						.getService(IActionCommandMappingService.class);
+				if (mappingService != null) {
+					commandId = mappingService.getCommandId(actionID);
+				}
+				if (commandId == null) {
+					commandId = handler.getActionDefinitionId();
+				}
+
+				// Update the handler activations.
+				final IHandlerService service = serviceLocator
+						.getService(IHandlerService.class);
+				Map activationsByActionId = null;
+				if (activationsByActionIdByServiceLocator == null) {
+					activationsByActionIdByServiceLocator = new WeakHashMap();
+					activationsByActionId = new HashMap();
+					activationsByActionIdByServiceLocator.put(serviceLocator,
+							activationsByActionId);
+				} else {
+					activationsByActionId = (Map) activationsByActionIdByServiceLocator
+							.get(serviceLocator);
+					if (activationsByActionId == null) {
+						activationsByActionId = new HashMap();
+						activationsByActionIdByServiceLocator.put(
+								serviceLocator, activationsByActionId);
+					} else if (activationsByActionId.containsKey(actionID)) {
+						final Object value = activationsByActionId
+								.remove(actionID);
+						if (value instanceof IHandlerActivation) {
+							final IHandlerActivation activation = (IHandlerActivation) value;
+							actionIdByCommandId.remove(activation.getCommandId());
+							if (service != null) {
+								service.deactivateHandler(activation);
+							}
+							activation.getHandler().dispose();
+						}
+					} else if (commandId != null
+							&& actionIdByCommandId.containsKey(commandId)) {
+						final Object value = activationsByActionId
+								.remove(actionIdByCommandId.remove(commandId));
+						if (value instanceof IHandlerActivation) {
+							final IHandlerActivation activation = (IHandlerActivation) value;
+							if (service != null) {
+								service.deactivateHandler(activation);
+							}
+							activation.getHandler().dispose();
+						}
+					}
+				}
+
+				if (commandId != null) {
+					actionIdByCommandId.put(commandId, actionID);
+					// Register this as a handler with the given definition id.
+					// the expression gives the setGlobalActionHandler() a
+					// priority.
+					final IHandler actionHandler = new ActionHandler(handler);
+					Expression handlerExpression = EXPRESSION;
+					//XXX add new API in next release to avoid down-casting (bug 137091)
+					if (this instanceof EditorActionBars) {
+						handlerExpression = ((EditorActionBars)this).getHandlerExpression();
+					}
+					if (service != null) {
+						final IHandlerActivation activation = service
+								.activateHandler(commandId, actionHandler,
+										handlerExpression);
+						activationsByActionId.put(actionID, activation);
+					}
+				}
+			}
+
+		} else {
+			if (actionHandlers != null) {
+				actionHandlers.remove(actionID);
+			}
+
+			// Remove the handler activation.
+			if (serviceLocator != null) {
+				final IHandlerService service = serviceLocator
+						.getService(IHandlerService.class);
+				if (activationsByActionIdByServiceLocator != null) {
+					final Map activationsByActionId = (Map) activationsByActionIdByServiceLocator
+							.get(serviceLocator);
+					if ((activationsByActionId != null)
+							&& (activationsByActionId.containsKey(actionID))) {
+						final Object value = activationsByActionId
+								.remove(actionID);
+						if (value instanceof IHandlerActivation) {
+							final IHandlerActivation activation = (IHandlerActivation) value;
+							actionIdByCommandId.remove(activation.getCommandId());
+							service.deactivateHandler(activation);
+							activation.getHandler().dispose();
+						}
+					}
+				}
+			}
+		}
+		actionHandlersChanged = true;
+	}
+
+	/**
+	 * Sets the service locator for this action bar.
+	 *
+	 * @param locator
+	 *            The new locator; must not be <code>null</code>.
+	 *
+	 * @since 3.2
+	 */
+	protected final void setServiceLocator(final IServiceLocator locator) {
+		if (locator == null) {
+			throw new NullPointerException("The service locator cannot be null"); //$NON-NLS-1$
+		}
+		this.serviceLocator = locator;
+	}
+
+	/**
+	 * Commits all UI changes. This should be called after additions or
+	 * subtractions have been made to a menu, status line, or toolbar.
+	 */
+	@Override
+	public void updateActionBars() {
+		parent.updateActionBars();
+		fireActionHandlersChanged();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/SubActionBars2.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/SubActionBars2.java
new file mode 100644
index 0000000..e7de0f9
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/SubActionBars2.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import org.eclipse.jface.action.ICoolBarManager;
+import org.eclipse.jface.action.SubCoolBarManager;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * A implementation of the extended <code>IActionBars2</code> interface. This
+ * sub class provides a sub cool bar manager for plugins to contribute multiple
+ * cool items.
+ *
+ * @since 3.0
+ */
+public class SubActionBars2 extends SubActionBars implements IActionBars2 {
+	private SubCoolBarManager coolBarMgr = null;
+
+	/**
+	 * Constucts a sub action bars object using an IActionBars2 parent.
+	 *
+	 * @param parent
+	 *            the action bars to virtualize; must not be <code>null</code>.
+	 */
+	public SubActionBars2(final IActionBars2 parent) {
+		this(parent, parent.getServiceLocator());
+	}
+
+	/**
+	 * Constucts a sub action bars object using an IActionBars2 parent.
+	 *
+	 * @param parent
+	 *            the action bars to virtualize; must not be <code>null</code>.
+	 * @param serviceLocator
+	 *            The service locator for this action bar; must not be
+	 *            <code>null</code>.
+	 *
+	 * @since 3.2
+	 */
+	public SubActionBars2(final IActionBars2 parent,
+			final IServiceLocator serviceLocator) {
+		super(parent, serviceLocator);
+	}
+
+	/**
+	 * Returns the casted parent of the sub action bars. This method can return
+	 * an IActionBars2 since it can only accept IActionBars2 in the constructor.
+	 *
+	 * @return the casted parent.
+	 */
+	protected IActionBars2 getCastedParent() {
+		return (IActionBars2) getParent();
+	}
+
+	/**
+	 * Returns a new sub coolbar manager.
+	 *
+	 * @param parent
+	 *            the parent coolbar manager
+	 * @return the cool bar manager
+	 */
+	protected SubCoolBarManager createSubCoolBarManager(ICoolBarManager parent) {
+		return new SubCoolBarManager(parent);
+	}
+
+	@Override
+	public ICoolBarManager getCoolBarManager() {
+		if (coolBarMgr == null) {
+			coolBarMgr = createSubCoolBarManager(getCastedParent()
+					.getCoolBarManager());
+			coolBarMgr.setVisible(getActive());
+		}
+		return coolBarMgr;
+	}
+
+	@Override
+	protected void setActive(boolean value) {
+		super.setActive(value);
+		if (coolBarMgr != null) {
+			coolBarMgr.setVisible(value);
+		}
+	}
+
+	@Override
+	public void dispose() {
+		super.dispose();
+		if (coolBarMgr != null) {
+			coolBarMgr.removeAll();
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/WorkbenchEncoding.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/WorkbenchEncoding.java
new file mode 100644
index 0000000..95821f0
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/WorkbenchEncoding.java
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.registry.RegistryReader;
+
+/**
+ * WorkbenchEncoding is a utility class for plug-ins that want to use the list
+ * of encodings defined by default in the workbench.
+ *
+ * @since 3.1
+ */
+public class WorkbenchEncoding {
+
+	/**
+	 * The method for java.nio.charset.Charset.isSupported(String), or <code>null</code>
+	 * if not present.  Reflection is used here to allow compilation against JCL Foundation (bug 80053).
+	 */
+	private static Method CharsetIsSupportedMethod = null;
+
+	static {
+		try {
+			Class charsetClass = Class.forName("java.nio.charset.Charset"); //$NON-NLS-1$
+			CharsetIsSupportedMethod = charsetClass.getMethod("isSupported", new Class[] { String.class }); //$NON-NLS-1$
+		}
+		catch (Exception e) {
+			// ignore
+		}
+
+	}
+
+	private static class EncodingsRegistryReader extends RegistryReader {
+
+		private List encodings;
+
+		/**
+		 * Create a new instance of the receiver.
+		 * @param definedEncodings
+		 */
+		public EncodingsRegistryReader(List definedEncodings) {
+			super();
+			encodings = definedEncodings;
+		}
+
+		@Override
+		protected boolean readElement(IConfigurationElement element) {
+			String name = element.getAttribute(IWorkbenchRegistryConstants.ATT_NAME);
+			if (name != null) {
+				encodings.add(name);
+			}
+			return true;
+		}
+	}
+
+	/**
+	 * Get the default encoding from the virtual machine.
+	 *
+	 * @return String
+	 */
+	public static String getWorkbenchDefaultEncoding() {
+		return System.getProperty("file.encoding", "UTF-8");//$NON-NLS-1$ //$NON-NLS-2$
+	}
+
+	/**
+	 * Return the list of encodings defined using the org.eclipse.ui.encodings
+	 * extension point.
+	 *
+	 * @return List of String
+	 */
+	public static List getDefinedEncodings() {
+		List definedEncodings = Collections.synchronizedList(new ArrayList());
+		EncodingsRegistryReader reader = new EncodingsRegistryReader(definedEncodings);
+
+		reader.readRegistry(Platform.getExtensionRegistry(), PlatformUI.PLUGIN_EXTENSION_NAME_SPACE,
+				IWorkbenchRegistryConstants.PL_ENCODINGS);
+
+		//Make it an array in case of concurrency issues with Iterators
+		String[] encodings = new String[definedEncodings.size()];
+		List invalid = new ArrayList();
+		definedEncodings.toArray(encodings);
+		for (int i = 0; i < encodings.length; i++) {
+			if (!isSupported(encodings[i])) {
+				invalid.add(encodings[i]);
+			}
+		}
+
+		Iterator invalidIterator = invalid.iterator();
+		while (invalidIterator.hasNext()) {
+			String next = (String) invalidIterator.next();
+			WorkbenchPlugin.log(NLS.bind(WorkbenchMessages.get().WorkbenchEncoding_invalidCharset,  next ));
+			definedEncodings.remove(next);
+
+		}
+
+		return definedEncodings;
+	}
+
+	/**
+	 * Returns whether the given encoding is supported in the current runtime.
+	 *
+	 * @param encoding the encoding to test
+	 * @return <code>true</code> if supported or if its support could not be determined,
+	 *   <code>false</code> if not supported
+	 */
+	private static boolean isSupported(String encoding) {
+		if (CharsetIsSupportedMethod == null) {
+			return true;
+		}
+		try {
+			Object o = CharsetIsSupportedMethod.invoke(null, new Object[] { encoding });
+			return Boolean.TRUE.equals(o);
+		} catch (IllegalArgumentException e) {
+		    //fall through
+		} catch (IllegalAccessException e) {
+			// fall through
+		} catch (InvocationTargetException e) {
+			// Method.invoke can throw InvocationTargetException if there is
+			// an exception in the invoked method.
+			// Charset.isSupported() is specified to throw IllegalCharsetNameException only
+			// which we want to return false for.
+			return false;
+		}
+		return true;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/WorkbenchException.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/WorkbenchException.java
new file mode 100644
index 0000000..52aeebe
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/WorkbenchException.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+/**
+ * A checked exception indicating a recoverable error occured internal to the
+ * workbench. The status provides a further description of the problem.
+ * <p>
+ * This exception class is not intended to be subclassed by clients.
+ * </p>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class WorkbenchException extends CoreException {
+
+    /**
+     * Generated serial version UID for this class.
+     * @since 3.1
+     */
+    private static final long serialVersionUID = 3258125864872129078L;
+
+    /**
+     * Creates a new exception with the given message.
+     *
+     * @param message the message
+     */
+    public WorkbenchException(String message) {
+        this(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0, message, null));
+    }
+
+    /**
+     * Creates a new exception with the given message.
+     *
+     * @param message the message
+     * @param nestedException an exception to be wrapped by this WorkbenchException
+     */
+    public WorkbenchException(String message, Throwable nestedException) {
+        this(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0, message,
+                nestedException));
+    }
+
+    /**
+     * Creates a new exception with the given status object.  The message
+     * of the given status is used as the exception message.
+     *
+     * @param status the status object to be associated with this exception
+     */
+    public WorkbenchException(IStatus status) {
+        super(status);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/XMLMemento.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/XMLMemento.java
new file mode 100644
index 0000000..822591f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/XMLMemento.java
@@ -0,0 +1,748 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.w3c.dom.Attr;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Text;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+
+/**
+ * This class represents the default implementation of the
+ * <code>IMemento</code> interface.
+ * <p>
+ * This class is not intended to be extended by clients.
+ * </p>
+ *
+ * @see IMemento
+ */
+public final class XMLMemento implements IMemento {
+    private Document factory;
+
+    private Element element;
+
+    /**
+     * Creates a <code>Document</code> from the <code>Reader</code>
+     * and returns a memento on the first <code>Element</code> for reading
+     * the document.
+     * <p>
+     * Same as calling createReadRoot(reader, null)
+     * </p>
+     *
+     * @param reader the <code>Reader</code> used to create the memento's document
+     * @return a memento on the first <code>Element</code> for reading the document
+     * @throws WorkbenchException if IO problems, invalid format, or no element.
+     */
+    public static XMLMemento createReadRoot(Reader reader)
+            throws WorkbenchException {
+        return createReadRoot(reader, null);
+    }
+
+    /**
+     * Creates a <code>Document</code> from the <code>Reader</code>
+     * and returns a memento on the first <code>Element</code> for reading
+     * the document.
+     *
+     * @param reader the <code>Reader</code> used to create the memento's document
+     * @param baseDir the directory used to resolve relative file names
+     * 		in the XML document. This directory must exist and include the
+     * 		trailing separator. The directory format, including the separators,
+     * 		must be valid for the platform. Can be <code>null</code> if not
+     * 		needed.
+     * @return a memento on the first <code>Element</code> for reading the document
+     * @throws WorkbenchException if IO problems, invalid format, or no element.
+     */
+    public static XMLMemento createReadRoot(Reader reader, String baseDir)
+            throws WorkbenchException {
+        String errorMessage = null;
+        Exception exception = null;
+
+        try {
+            DocumentBuilderFactory factory = DocumentBuilderFactory
+                    .newInstance();
+            DocumentBuilder parser = factory.newDocumentBuilder();
+            InputSource source = new InputSource(reader);
+            if (baseDir != null) {
+				source.setSystemId(baseDir);
+			}
+
+			parser.setErrorHandler(new ErrorHandler() {
+				/**
+				 * @throws SAXException
+				 */
+				@Override
+				public void warning(SAXParseException exception) throws SAXException {
+					// ignore
+				}
+
+				/**
+				 * @throws SAXException
+				 */
+				@Override
+				public void error(SAXParseException exception) throws SAXException {
+					// ignore
+				}
+
+				@Override
+				public void fatalError(SAXParseException exception) throws SAXException {
+					throw exception;
+				}
+			});
+
+            Document document = parser.parse(source);
+            NodeList list = document.getChildNodes();
+            for (int i = 0; i < list.getLength(); i++) {
+                Node node = list.item(i);
+                if (node instanceof Element) {
+					return new XMLMemento(document, (Element) node);
+				}
+            }
+        } catch (ParserConfigurationException e) {
+            exception = e;
+            errorMessage = WorkbenchMessages.get().XMLMemento_parserConfigError;
+        } catch (IOException e) {
+            exception = e;
+            errorMessage = WorkbenchMessages.get().XMLMemento_ioError;
+        } catch (SAXException e) {
+            exception = e;
+            errorMessage = WorkbenchMessages.get().XMLMemento_formatError;
+        }
+
+        String problemText = null;
+        if (exception != null) {
+			problemText = exception.getMessage();
+		}
+        if (problemText == null || problemText.length() == 0) {
+			problemText = errorMessage != null ? errorMessage
+                    : WorkbenchMessages.get().XMLMemento_noElement;
+		}
+        throw new WorkbenchException(problemText, exception);
+    }
+
+    /**
+	 * Returns a root memento for writing a document.
+	 *
+	 * @param type
+	 *            the element node type to create on the document
+	 * @return the root memento for writing a document
+	 * @throws DOMException
+	 */
+	public static XMLMemento createWriteRoot(String type) throws DOMException {
+        Document document;
+        try {
+            document = DocumentBuilderFactory.newInstance()
+                    .newDocumentBuilder().newDocument();
+            Element element = document.createElement(type);
+            document.appendChild(element);
+            return new XMLMemento(document, element);
+        } catch (ParserConfigurationException e) {
+//            throw new Error(e);
+            throw new Error(e.getMessage());
+        }
+    }
+
+    /**
+     * Creates a memento for the specified document and element.
+     * <p>
+     * Clients should use <code>createReadRoot</code> and
+     * <code>createWriteRoot</code> to create the initial
+     * memento on a document.
+     * </p>
+     *
+     * @param document the document for the memento
+     * @param element the element node for the memento
+     */
+    public XMLMemento(Document document, Element element) {
+        super();
+        this.factory = document;
+        this.element = element;
+    }
+
+	/**
+	 * Creates a new child of this memento with the given type.
+	 * <p>
+	 * The <code>getChild</code> and <code>getChildren</code> methods are used
+	 * to retrieve children of a given type.
+	 * </p>
+	 *
+	 * @param type
+	 *            the type
+	 * @return a new child memento
+	 * @see #getChild
+	 * @see #getChildren
+	 * @throws DOMException
+	 *             if the child cannot be created
+	 */
+	@Override
+	public IMemento createChild(String type) throws DOMException {
+        Element child = factory.createElement(type);
+        element.appendChild(child);
+        return new XMLMemento(factory, child);
+    }
+
+	/**
+	 * Creates a new child of this memento with the given type and id. The id is
+	 * stored in the child memento (using a special reserved key,
+	 * <code>TAG_ID</code>) and can be retrieved using <code>getId</code>.
+	 * <p>
+	 * The <code>getChild</code> and <code>getChildren</code> methods are used
+	 * to retrieve children of a given type.
+	 * </p>
+	 *
+	 * @param type
+	 *            the type
+	 * @param id
+	 *            the child id
+	 * @return a new child memento with the given type and id
+	 * @see #getID
+	 * @throws DOMException
+	 *             if the child cannot be created
+	 */
+	@Override
+	public IMemento createChild(String type, String id) throws DOMException {
+        Element child = factory.createElement(type);
+        child.setAttribute(TAG_ID, id == null ? "" : id); //$NON-NLS-1$
+        element.appendChild(child);
+        return new XMLMemento(factory, child);
+    }
+
+	/**
+	 * Create a copy of the child node and append it to this node.
+	 *
+	 * @param child
+	 * @return An IMenento for the new child node.
+	 * @throws DOMException
+	 *             if the child cannot be created
+	 */
+	public IMemento copyChild(IMemento child) throws DOMException {
+        Element childElement = ((XMLMemento) child).element;
+        Element newElement = (Element) factory.importNode(childElement, true);
+        element.appendChild(newElement);
+        return new XMLMemento(factory, newElement);
+    }
+
+    @Override
+	public IMemento getChild(String type) {
+
+        // Get the nodes.
+        NodeList nodes = element.getChildNodes();
+        int size = nodes.getLength();
+        if (size == 0) {
+			return null;
+		}
+
+        // Find the first node which is a child of this node.
+        for (int nX = 0; nX < size; nX++) {
+            Node node = nodes.item(nX);
+            if (node instanceof Element) {
+                Element element = (Element) node;
+                if (element.getNodeName().equals(type)) {
+					return new XMLMemento(factory, element);
+				}
+            }
+        }
+
+        // A child was not found.
+        return null;
+    }
+
+	@Override
+	public IMemento[] getChildren() {
+
+		// Get the nodes.
+		final NodeList nodes = element.getChildNodes();
+		int size = nodes.getLength();
+		if (size == 0) {
+			return new IMemento[0];
+		}
+
+		// Extract each node with given type.
+		ArrayList list = new ArrayList(size);
+		for (int nX = 0; nX < size; nX++) {
+			final Node node = nodes.item(nX);
+			if (node instanceof Element)
+				list.add(node);
+		}
+
+		// Create a memento for each node.
+		size = list.size();
+		IMemento[] results = new IMemento[size];
+		for (int x = 0; x < size; x++) {
+			results[x] = new XMLMemento(factory, (Element) list.get(x));
+		}
+		return results;
+	}
+
+    @Override
+	public IMemento[] getChildren(String type) {
+
+        // Get the nodes.
+        NodeList nodes = element.getChildNodes();
+        int size = nodes.getLength();
+        if (size == 0) {
+			return new IMemento[0];
+		}
+
+        // Extract each node with given type.
+        ArrayList list = new ArrayList(size);
+        for (int nX = 0; nX < size; nX++) {
+            Node node = nodes.item(nX);
+            if (node instanceof Element) {
+                Element element = (Element) node;
+                if (element.getNodeName().equals(type)) {
+					list.add(element);
+				}
+            }
+        }
+
+        // Create a memento for each node.
+        size = list.size();
+        IMemento[] results = new IMemento[size];
+        for (int x = 0; x < size; x++) {
+            results[x] = new XMLMemento(factory, (Element) list.get(x));
+        }
+        return results;
+    }
+
+    @Override
+	public Float getFloat(String key) {
+        Attr attr = element.getAttributeNode(key);
+        if (attr == null) {
+			return null;
+		}
+        String strValue = attr.getValue();
+        try {
+            return new Float(strValue);
+        } catch (NumberFormatException e) {
+            WorkbenchPlugin.log("Memento problem - Invalid float for key: " //$NON-NLS-1$
+                    + key + " value: " + strValue, e); //$NON-NLS-1$
+            return null;
+        }
+    }
+
+	/**
+	 * @since 3.4
+	 */
+	@Override
+	public String getType() {
+		return element.getNodeName();
+	}
+
+    @Override
+	public String getID() {
+        return element.getAttribute(TAG_ID);
+    }
+
+    @Override
+	public Integer getInteger(String key) {
+        Attr attr = element.getAttributeNode(key);
+        if (attr == null) {
+			return null;
+		}
+        String strValue = attr.getValue();
+        try {
+			return Integer.valueOf(strValue);
+        } catch (NumberFormatException e) {
+            WorkbenchPlugin
+                    .log("Memento problem - invalid integer for key: " + key //$NON-NLS-1$
+                            + " value: " + strValue, e); //$NON-NLS-1$
+            return null;
+        }
+    }
+
+    @Override
+	public String getString(String key) {
+        Attr attr = element.getAttributeNode(key);
+        if (attr == null) {
+			return null;
+		}
+        return attr.getValue();
+    }
+
+	/**
+	 * @since 3.4
+	 */
+	@Override
+	public Boolean getBoolean(String key) {
+        Attr attr = element.getAttributeNode(key);
+        if (attr == null) {
+			return null;
+		}
+        return Boolean.valueOf(attr.getValue());
+	}
+
+	/**
+	 * Returns the data of the Text node of the memento. Each memento is allowed
+	 * only one Text node.
+	 *
+	 * @return the data of the Text node of the memento, or <code>null</code> if
+	 *         the memento has no Text node.
+	 * @since 2.0
+	 * @throws DOMException
+	 *             if the text node is too big
+	 */
+	@Override
+	public String getTextData() throws DOMException {
+        Text textNode = getTextNode();
+        if (textNode != null) {
+            return textNode.getData();
+        }
+        return null;
+    }
+
+	/**
+	 * @since 3.4
+	 */
+	@Override
+	public String[] getAttributeKeys() {
+		NamedNodeMap map = element.getAttributes();
+		int size = map.getLength();
+		String[] attributes = new String[size];
+		for (int i = 0; i < size; i++) {
+			Node node = map.item(i);
+			attributes[i] = node.getNodeName();
+		}
+		return attributes;
+	}
+
+    /**
+     * Returns the Text node of the memento. Each memento is allowed only
+     * one Text node.
+     *
+     * @return the Text node of the memento, or <code>null</code> if
+     * the memento has no Text node.
+     */
+    private Text getTextNode() {
+        // Get the nodes.
+        NodeList nodes = element.getChildNodes();
+        int size = nodes.getLength();
+        if (size == 0) {
+			return null;
+		}
+        for (int nX = 0; nX < size; nX++) {
+            Node node = nodes.item(nX);
+            if (node instanceof Text) {
+                return (Text) node;
+            }
+        }
+        // a Text node was not found
+        return null;
+    }
+
+    /**
+	 * Places the element's attributes into the document.
+	 *
+	 * @param copyText
+	 *            true if the first text node should be copied
+	 * @throws DOMException
+	 *             if the attributes or children cannot be copied to this node.
+	 */
+	private void putElement(Element element, boolean copyText) throws DOMException {
+        NamedNodeMap nodeMap = element.getAttributes();
+        int size = nodeMap.getLength();
+        for (int i = 0; i < size; i++) {
+            Attr attr = (Attr) nodeMap.item(i);
+            putString(attr.getName(), attr.getValue());
+        }
+
+        NodeList nodes = element.getChildNodes();
+        size = nodes.getLength();
+        // Copy first text node (fixes bug 113659).
+        // Note that text data will be added as the first child (see putTextData)
+        boolean needToCopyText = copyText;
+        for (int i = 0; i < size; i++) {
+            Node node = nodes.item(i);
+            if (node instanceof Element) {
+                XMLMemento child = (XMLMemento) createChild(node.getNodeName());
+                child.putElement((Element) node, true);
+            } else if (node instanceof Text && needToCopyText) {
+                putTextData(((Text) node).getData());
+                needToCopyText = false;
+            }
+        }
+    }
+
+	/**
+	 * Sets the value of the given key to the given floating point number.
+	 *
+	 * @param key
+	 *            the key
+	 * @param f
+	 *            the value
+	 * @throws DOMException
+	 *             if the attribute cannot be set
+	 */
+	@Override
+	public void putFloat(String key, float f) throws DOMException {
+        element.setAttribute(key, String.valueOf(f));
+    }
+
+	/**
+	 * Sets the value of the given key to the given integer.
+	 *
+	 * @param key
+	 *            the key
+	 * @param n
+	 *            the value
+	 * @throws DOMException
+	 *             if the attribute cannot be set
+	 */
+	@Override
+	public void putInteger(String key, int n) throws DOMException {
+        element.setAttribute(key, String.valueOf(n));
+    }
+
+	/**
+	 * Copy the attributes and children from <code>memento</code> to the
+	 * receiver.
+	 *
+	 * @param memento
+	 *            the IMemento to be copied.
+	 * @throws DOMException
+	 *             if the attributes or children cannot be copied to this node.
+	 */
+	@Override
+	public void putMemento(IMemento memento) throws DOMException {
+    	// Do not copy the element's top level text node (this would overwrite the existing text).
+    	// Text nodes of children are copied.
+        putElement(((XMLMemento) memento).element, false);
+    }
+
+	/**
+	 * Sets the value of the given key to the given string.
+	 *
+	 * @param key
+	 *            the key
+	 * @param value
+	 *            the value
+	 * @throws DOMException
+	 *             if the attribute cannot be set
+	 */
+	@Override
+	public void putString(String key, String value) throws DOMException {
+        if (value == null) {
+			return;
+		}
+        element.setAttribute(key, value);
+    }
+
+	/**
+	 * Sets the value of the given key to the given boolean value.
+	 *
+	 * @param key
+	 *            the key
+	 * @param value
+	 *            the value
+	 * @since 3.4
+	 * @throws DOMException
+	 *             if the attribute cannot be set
+	 */
+	@Override
+	public void putBoolean(String key, boolean value) throws DOMException {
+		element.setAttribute(key, value ? "true" : "false"); //$NON-NLS-1$ //$NON-NLS-2$
+	}
+
+	/**
+	 * Sets the memento's Text node to contain the given data. Creates the Text
+	 * node if none exists. If a Text node does exist, it's current contents are
+	 * replaced. Each memento is allowed only one text node.
+	 *
+	 * @param data
+	 *            the data to be placed on the Text node
+	 * @since 2.0
+	 * @throws DOMException
+	 *             if the text node cannot be created under this node.
+	 */
+	@Override
+	public void putTextData(String data) throws DOMException {
+        Text textNode = getTextNode();
+        if (textNode == null) {
+            textNode = factory.createTextNode(data);
+			// Always add the text node as the first child (fixes bug 93718)
+			element.insertBefore(textNode, element.getFirstChild());
+        } else {
+            textNode.setData(data);
+        }
+    }
+
+    /**
+     * Saves this memento's document current values to the
+     * specified writer.
+     *
+     * @param writer the writer used to save the memento's document
+     * @throws IOException if there is a problem serializing the document to the stream.
+     */
+    public void save(Writer writer) throws IOException {
+    	DOMWriter out = new DOMWriter(writer);
+        try {
+        	out.print(element);
+    	} finally {
+    		out.close();
+    	}
+	}
+
+	@Override
+	public String toString() {
+		try {
+			StringWriter writer = new StringWriter();
+			save(writer);
+			return writer.toString();
+		} catch (IOException e) {
+			return super.toString();
+		}
+	}
+
+	/**
+     * A simple XML writer.  Using this instead of the javax.xml.transform classes allows
+     * compilation against JCL Foundation (bug 80053).
+     */
+    private static final class DOMWriter extends PrintWriter {
+
+    	/* constants */
+    	private static final String XML_VERSION = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"; //$NON-NLS-1$
+
+    	/**
+    	 * Creates a new DOM writer on the given output writer.
+    	 *
+    	 * @param output the output writer
+    	 */
+    	public DOMWriter(Writer output) {
+    		super(output);
+    		println(XML_VERSION);
+    	}
+
+    	/**
+    	 * Prints the given element.
+    	 *
+    	 * @param element the element to print
+    	 */
+        public void print(Element element) {
+        	// Ensure extra whitespace is not emitted next to a Text node,
+        	// as that will result in a situation where the restored text data is not the
+        	// same as the saved text data.
+        	boolean hasChildren = element.hasChildNodes();
+        	startTag(element, hasChildren);
+        	if (hasChildren) {
+	        	boolean prevWasText = false;
+	        	NodeList children = element.getChildNodes();
+	    		for (int i = 0; i < children.getLength(); i++) {
+	    			Node node = children.item(i);
+	    			if (node instanceof Element) {
+	    				if (!prevWasText) {
+	    					println();
+	    				}
+	    				print((Element) children.item(i));
+	    				prevWasText = false;
+	    			}
+	    			else if (node instanceof Text) {
+	    				print(getEscaped(node.getNodeValue()));
+	    				prevWasText = true;
+	    			}
+	    		}
+	    		if (!prevWasText) {
+	    			println();
+	    		}
+	    		endTag(element);
+        	}
+    	}
+
+    	private void startTag(Element element, boolean hasChildren) {
+    		StringBuffer sb = new StringBuffer();
+    		sb.append("<"); //$NON-NLS-1$
+    		sb.append(element.getTagName());
+    		NamedNodeMap attributes = element.getAttributes();
+   			for (int i = 0;  i < attributes.getLength(); i++) {
+   				Attr attribute = (Attr)attributes.item(i);
+				sb.append(" "); //$NON-NLS-1$
+				sb.append(attribute.getName());
+				sb.append("=\""); //$NON-NLS-1$
+				sb.append(getEscaped(String.valueOf(attribute.getValue())));
+				sb.append("\""); //$NON-NLS-1$
+   			}
+   			sb.append(hasChildren ? ">" : "/>"); //$NON-NLS-1$ //$NON-NLS-2$
+   			print(sb.toString());
+    	}
+
+    	private void endTag(Element element) {
+    		StringBuffer sb = new StringBuffer();
+    		sb.append("</"); //$NON-NLS-1$
+    		sb.append(element.getNodeName());
+    		sb.append(">"); //$NON-NLS-1$
+   			print(sb.toString());
+    	}
+
+    	private static void appendEscapedChar(StringBuffer buffer, char c) {
+    		String replacement = getReplacement(c);
+    		if (replacement != null) {
+    			buffer.append('&');
+    			buffer.append(replacement);
+    			buffer.append(';');
+    		} else if (c==9 || c==10 || c==13 || c>=32){
+    			buffer.append(c);
+    		}
+    	}
+
+    	private static String getEscaped(String s) {
+    		StringBuffer result = new StringBuffer(s.length() + 10);
+    		for (int i = 0; i < s.length(); ++i) {
+				appendEscapedChar(result, s.charAt(i));
+			}
+    		return result.toString();
+    	}
+
+    	private static String getReplacement(char c) {
+    		// Encode special XML characters into the equivalent character references.
+			// The first five are defined by default for all XML documents.
+			// The next three (#xD, #xA, #x9) are encoded to avoid them
+			// being converted to spaces on deserialization
+			// (fixes bug 93720)
+    		switch (c) {
+    			case '<' :
+    				return "lt"; //$NON-NLS-1$
+    			case '>' :
+    				return "gt"; //$NON-NLS-1$
+    			case '"' :
+    				return "quot"; //$NON-NLS-1$
+    			case '\'' :
+    				return "apos"; //$NON-NLS-1$
+    			case '&' :
+    				return "amp"; //$NON-NLS-1$
+				case '\r':
+					return "#x0D"; //$NON-NLS-1$
+				case '\n':
+					return "#x0A"; //$NON-NLS-1$
+				case '\u0009':
+					return "#x09"; //$NON-NLS-1$
+    		}
+    		return null;
+    	}
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/about/IInstallationPageContainer.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/about/IInstallationPageContainer.java
new file mode 100644
index 0000000..d70f3e0
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/about/IInstallationPageContainer.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2015 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.ui.about;
+
+import org.eclipse.swt.widgets.Button;
+
+/**
+ * Interface for a container that hosts one or more installation pages (
+ * {@link InstallationPage}).
+ *
+ * @noimplement This interface is not intended to be implemented by clients.
+ *
+ * @since 3.5
+ */
+public interface IInstallationPageContainer {
+
+	/**
+	 * Register a button as belonging to a particular page in the container. The
+	 * container will manage the placement and visibility of the page's buttons.
+	 *
+	 * @param page
+	 *            the page that created the button
+	 * @param button
+	 *            the button to be managed
+	 *
+	 */
+	public void registerPageButton(InstallationPage page, Button button);
+
+	/**
+	 * Closes any modal containers that were used to launch this installation
+	 * page. This method should be used when a page is launching a long-running
+	 * task (such as a background job) that requires progress indication, in
+	 * order to allow platform progress indication to behave as expected.
+	 */
+	public void closeModalContainers();
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/about/ISystemSummarySection.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/about/ISystemSummarySection.java
new file mode 100644
index 0000000..d9b752c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/about/ISystemSummarySection.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.about;
+
+import java.io.PrintWriter;
+
+/**
+ * Extensions to <code>org.eclipse.ui.systemSummaryExtensions</code> must provide
+ * an implementation of this interface.  The class must provide a default
+ * constructor.  A new instance of the class will be created each time the system
+ * summary is created.
+ *
+ * @since 3.0
+ */
+public interface ISystemSummarySection {
+    /**
+     * A method that puts the section's information into the system summary's
+     * configuration details log.
+     * @param writer puts information into the system summary
+     */
+    public void write(PrintWriter writer);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/about/InstallationPage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/about/InstallationPage.java
new file mode 100644
index 0000000..317c526
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/about/InstallationPage.java
@@ -0,0 +1,170 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2015 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.ui.about;
+
+import org.eclipse.jface.dialogs.DialogPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * Abstract base implementation for an installation dialog page.
+ * <p>
+ * Clients should extend this class and include the name of the subclass in an
+ * extension contributed to the workbench's installation pages extension point
+ * (named <code>"org.eclipse.ui.installationPages"</code>). For example, the
+ * plug-in's XML markup might contain:
+ *
+ * <pre>
+ * &LT;extension point="org.eclipse.ui.installationPages"&GT;
+ *      &LT;page id="com.example.myplugin.installInfo"
+ *         name="Example Details"
+ *         class="com.example.myplugin.MyInstallationPage" /&GT;
+ * &LT;/extension&GT;
+ * </pre>
+ *
+ * </p>
+ *
+ * @since 3.5
+ */
+public abstract class InstallationPage extends DialogPage {
+
+	private IInstallationPageContainer container;
+
+	/**
+	 * Sets or clears the message for this page.
+	 * <p>
+	 * This message has no effect when the receiver is used in an
+	 * IInstallationPageContainer.
+	 * </p>
+	 *
+	 * @param newMessage
+	 *            the message, or <code>null</code> to clear the message
+	 */
+	@Override
+	public void setMessage(String newMessage) {
+		super.setMessage(newMessage);
+	}
+
+	/**
+	 * Sets the message for this page with an indication of what type of message
+	 * it is.
+	 * <p>
+	 * The valid message types are one of <code>NONE</code>,
+	 * <code>INFORMATION</code>,<code>WARNING</code>, or <code>ERROR</code>.
+	 * </p>
+	 * <p>
+	 * This message has no effect when the receiver is used in an
+	 * IInstallationPageContainer.
+	 * </p>
+	 *
+	 * @param newMessage
+	 *            the message, or <code>null</code> to clear the message
+	 * @param newType
+	 *            the message type
+	 */
+	@Override
+	public void setMessage(String newMessage, int newType) {
+		super.setMessage(newMessage, newType);
+	}
+
+	/**
+	 * Set the page container that is hosting this page. This method is
+	 * typically called by the container itself so that the pages have access to
+	 * the container when registering buttons using
+	 * {@link IInstallationPageContainer#registerPageButton(InstallationPage, Button)}
+	 * or performing other container-related tasks.
+	 *
+	 * @param container
+	 *            the container that is hosting the page.
+	 */
+	public void setPageContainer(IInstallationPageContainer container) {
+		this.container = container;
+	}
+
+	/**
+	 * Create the buttons that belong to this page using the specified parent.
+	 *
+	 * @param parent
+	 *            the parent to use for the buttons.
+	 *
+	 * @see #createButton(Composite, int, String)
+	 * @see #buttonPressed(int)
+	 */
+	public void createPageButtons(Composite parent) {
+		// By default, there are no page-specific buttons
+	}
+
+	/**
+	 * Creates a new button with the given id.
+	 * <p>
+	 * This method creates a standard push button, registers it for selection
+	 * events, and registers it as a button belonging to this page. Subclasses
+	 * should not make any assumptions about the visibility, layout, or
+	 * presentation of this button inside the dialog.
+	 * </p>
+	 *
+	 * @param parent
+	 *            the parent composite
+	 * @param id
+	 *            the id of the button (see <code>IDialogConstants.*_ID</code>
+	 *            constants for standard dialog button ids)
+	 * @param label
+	 *            the label from the button
+	 * @return the new button
+	 *
+	 * @see #createPageButtons(Composite)
+	 * @see #buttonPressed(int)
+	 */
+	protected Button createButton(Composite parent, int id, String label) {
+		Button button = new Button(parent, SWT.PUSH);
+		button.setText(label);
+		button.setData(Integer.valueOf(id));
+		button.addSelectionListener(new SelectionAdapter()
+        {
+		    /** {@inheritDoc} */
+		    @Override
+		    public void widgetSelected(SelectionEvent event)
+		    {
+		        buttonPressed(((Integer) event.widget.getData()).intValue());
+		    }
+        });
+		container.registerPageButton(this, button);
+		return button;
+	}
+
+	/**
+	 * Notifies that this page's button with the given id has been pressed.
+	 * Subclasses should extend this method to handle the buttons created in
+	 * {@link #createButton(Composite, int, String)}
+	 *
+	 * @param buttonId
+	 *            the id of the button that was pressed (see
+	 *            <code>IDialogConstants.*_ID</code> constants)
+	 */
+	protected void buttonPressed(int buttonId) {
+	}
+
+	/**
+	 * Get the page container that is hosting this page. This method is
+	 * typically used when registering buttons using
+	 * {@link IInstallationPageContainer#registerPageButton(InstallationPage, Button)}
+	 * or performing other container-related tasks.
+	 *
+	 * @return the container that is hosting the page.
+	 */
+	protected IInstallationPageContainer getPageContainer() {
+		return container;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/about/package.html b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/about/package.html
new file mode 100644
index 0000000..b5cee3b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/about/package.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <meta name="Author" content="IBM">
+   <meta name="GENERATOR" content="Mozilla/4.5 [en] (WinNT; I) [Netscape]">
+   <title>Package-level Javadoc</title>
+</head>
+<body>
+Application programming interfaces for interaction with
+and extension of the Eclipse Platform About dialog.
+<h2>
+Package Specification
+</h2>
+Provides interfaces for customizing the content of the About
+dialog.
+</body>
+</html>
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/ActionContext.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/ActionContext.java
new file mode 100644
index 0000000..c4e66d9
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/ActionContext.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.actions;
+
+import org.eclipse.jface.viewers.ISelection;
+
+/**
+ * An <code>ActionContext</code> represents the context used to determine
+ * which actions are added by an <code>ActionGroup</code>, and what their
+ * enabled state should be.
+ * <p>
+ * This class encapsulates a selection and an input element.
+ * Clients may subclass this class to add more information to the context.
+ * </p>
+ */
+public class ActionContext {
+
+    /**
+     * The selection.
+     */
+    private ISelection selection;
+
+    /**
+     * The input element.
+     */
+    private Object input;
+
+    /**
+     * Creates a new action context with the given selection.
+     */
+    public ActionContext(ISelection selection) {
+        setSelection(selection);
+    }
+
+    /**
+     * Returns the selection.
+     */
+    public ISelection getSelection() {
+        return selection;
+    }
+
+    /**
+     * Sets the selection.
+     */
+    public void setSelection(ISelection selection) {
+        this.selection = selection;
+    }
+
+    /**
+     * Returns the input element.
+     */
+    public Object getInput() {
+        return input;
+    }
+
+    /**
+     * Sets the input element.
+     *
+     * @param input
+     */
+    public void setInput(Object input) {
+        this.input = input;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/ActionDelegate.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/ActionDelegate.java
new file mode 100644
index 0000000..f5feb6a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/ActionDelegate.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2014 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.ui.actions;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.ui.IActionDelegate2;
+
+/**
+ * Abstract base implementation of <code>IActionDelegate</code> and
+ * <code>IActionDelegate2</code> for a client delegate action.
+ * <p>
+ * Subclasses should reimplement <code>runWithEvent</code> or <code>run</code>
+ * methods to do the action's work, and may reimplement
+ * <code>selectionChanged</code> to react to selection changes in the workbench.
+ * </p>
+ */
+public abstract class ActionDelegate implements IActionDelegate2 {
+    /**
+     * The <code>ActionDelegate</code> implementation of this
+     * <code>IActionDelegate</code> method does nothing. Subclasses may
+     * reimplement.
+     * <p>
+     * <b>Note:</b> This method is not called directly by the proxy action. Only
+     * by the default implementation of <code>runWithEvent</code> of this
+     * abstract class.
+     */
+    @Override
+	public void run(IAction action) {
+    }
+
+    /**
+     * The <code>ActionDelegate</code> implementation of this
+     * <code>IActionDelegate</code> method does nothing. Subclasses may
+     * reimplement.
+     */
+    @Override
+	public void selectionChanged(IAction action, ISelection selection) {
+    }
+
+    /**
+     * The <code>ActionDelegate</code> implementation of this
+     * <code>IActionDelegate2</code> method does nothing. Subclasses may
+     * reimplement.
+     */
+    @Override
+	public void init(IAction action) {
+    }
+
+    /**
+     * The <code>ActionDelegate</code> implementation of this
+     * <code>IActionDelegate2</code> method does nothing. Subclasses may
+     * reimplement.
+     */
+    @Override
+	public void dispose() {
+    }
+
+    /**
+     * The <code>ActionDelegate</code> implementation of this
+     * <code>IActionDelegate2</code> method redirects to the <code>run</code>
+     * method. Subclasses may reimplement.
+     */
+    @Override
+	public void runWithEvent(IAction action, Event event) {
+        run(action);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/ActionFactory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/ActionFactory.java
new file mode 100644
index 0000000..499826e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/ActionFactory.java
@@ -0,0 +1,1721 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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
+ *     Tobias Baumann <tobbaumann@gmail.com> - Bug 428323 - Correct lock tool bar action definition
+ *******************************************************************************/
+package org.eclipse.ui.actions;
+
+import org.eclipse.core.runtime.IProduct;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.internal.CloseAllSavedAction;
+import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.NavigationHistoryAction;
+import org.eclipse.ui.internal.OpenPreferencesAction;
+import org.eclipse.ui.internal.ToggleEditorsVisibilityAction;
+import org.eclipse.ui.internal.Workbench;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.actions.CommandAction;
+import org.eclipse.ui.internal.actions.DynamicHelpAction;
+import org.eclipse.ui.internal.actions.HelpContentsAction;
+import org.eclipse.ui.internal.actions.HelpSearchAction;
+import org.eclipse.ui.internal.intro.IntroDescriptor;
+import org.eclipse.ui.internal.intro.IntroMessages;
+
+/**
+ * Access to standard actions provided by the workbench.
+ * <p>
+ * Most of the functionality of this class is provided by static methods and
+ * fields. Example usage:
+ *
+ * <pre>
+ * MenuManager menu = ...;
+ * ActionFactory.IWorkbenchAction closeEditorAction
+ *    = ActionFactory.CLOSE.create(window);
+ * menu.add(closeEditorAction);
+ * </pre>
+ * </p>
+ * <p>
+ * Clients may declare other classes that provide additional application-specific
+ * action factories.
+ * </p>
+ *
+ * @since 3.0
+ */
+public abstract class ActionFactory {
+
+    /**
+     * Interface for a workbench action.
+     */
+    public interface IWorkbenchAction extends IAction {
+        /**
+         * Disposes of this action. Once disposed, this action cannot be used.
+         * This operation has no effect if the action has already been
+         * disposed.
+         */
+        public void dispose();
+    }
+
+    private static class WorkbenchCommandAction extends CommandAction implements
+			IWorkbenchAction {
+		/**
+		 * @param commandIdIn
+		 * @param window
+		 */
+		public WorkbenchCommandAction(String commandIdIn,
+				IWorkbenchWindow window) {
+			super(window, commandIdIn);
+		}
+	}
+
+	/**
+	 * Workbench action (id: "about", commandId: "org.eclipse.ui.help.aboutAction"): Displays the
+	 * About dialog. This action maintains its enablement state.
+	 */
+    public static final ActionFactory ABOUT = new ActionFactory("about", //$NON-NLS-1$
+    		IWorkbenchCommandConstants.HELP_ABOUT) {
+
+		@Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+			if (window == null) {
+				throw new IllegalArgumentException();
+			}
+
+			WorkbenchCommandAction action = new WorkbenchCommandAction(
+					getCommandId(), window);
+
+			action.setId(getId());
+			IProduct product = Platform.getProduct();
+			String productName = null;
+			if (product != null) {
+				productName = product.getName();
+			}
+			if (productName == null) {
+				productName = ""; //$NON-NLS-1$
+			}
+
+			action.setText(NLS.bind(WorkbenchMessages.get().AboutAction_text,
+					productName));
+			action.setToolTipText(NLS.bind(
+					WorkbenchMessages.get().AboutAction_toolTip, productName));
+			window.getWorkbench().getHelpSystem().setHelp(action,
+					IWorkbenchHelpContextIds.ABOUT_ACTION);
+			return action;
+		}
+	};
+
+	/**
+	 * Workbench action (id: "activateEditor", commandId: "org.eclipse.ui.window.activateEditor"):
+	 * Activate the most recently used editor. This action maintains its enablement state.
+	 */
+    public static final ActionFactory ACTIVATE_EDITOR = new ActionFactory(
+            "activateEditor", IWorkbenchCommandConstants.WINDOW_ACTIVATE_EDITOR) {//$NON-NLS-1$
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+			if (window == null) {
+				throw new IllegalArgumentException();
+			}
+			WorkbenchCommandAction action = new WorkbenchCommandAction(
+					getCommandId(), window);
+			action.setId(getId());
+			action.setText(WorkbenchMessages.get().ActivateEditorAction_text);
+			action
+					.setToolTipText(WorkbenchMessages.get().ActivateEditorAction_toolTip);
+			return action;
+		}
+    };
+
+	/**
+	 * Workbench action (id: "back", commandId: "org.eclipse.ui.navigate.back"): Back. This action
+	 * is a {@link RetargetAction} with id "back". This action maintains its enablement state.
+	 */
+    public static final ActionFactory BACK = new ActionFactory("back", //$NON-NLS-1$
+    		IWorkbenchCommandConstants.NAVIGATE_BACK) {
+
+		@Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            RetargetAction action = new LabelRetargetAction(getId(), WorkbenchMessages.get().Workbench_back);
+            action.setToolTipText(WorkbenchMessages.get().Workbench_backToolTip);
+            window.getPartService().addPartListener(action);
+            action.setActionDefinitionId(getCommandId());
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "backardHistory", commandId: "org.eclipse.ui.navigate.backwardHistory"):
+	 * Backward in the navigation history. This action maintains its enablement state.
+	 */
+    public static final ActionFactory BACKWARD_HISTORY = new ActionFactory(
+            "backardHistory", IWorkbenchCommandConstants.NAVIGATE_BACKWARD_HISTORY) {//$NON-NLS-1$
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            IWorkbenchAction action = new NavigationHistoryAction(window, false);
+            action.setId(getId());
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "close", commandId: "org.eclipse.ui.file.close"): Close the active
+	 * editor. This action maintains its enablement state.
+	 */
+    public static final ActionFactory CLOSE = new ActionFactory("close",//$NON-NLS-1$
+    		IWorkbenchCommandConstants.FILE_CLOSE) {
+
+		@Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+			WorkbenchCommandAction action = new WorkbenchCommandAction(
+					getCommandId(), window);
+            action.setId(getId());
+            action.setText(WorkbenchMessages.get().CloseEditorAction_text);
+            action.setToolTipText(WorkbenchMessages.get().CloseEditorAction_toolTip);
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "closeAll", commandId: "org.eclipse.ui.file.closeAll"): Close all open
+	 * editors. This action maintains its enablement state.
+	 */
+    public static final ActionFactory CLOSE_ALL = new ActionFactory("closeAll",//$NON-NLS-1$
+    		IWorkbenchCommandConstants.FILE_CLOSE_ALL) {
+
+		@Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+			WorkbenchCommandAction action = new WorkbenchCommandAction(
+					getCommandId(), window);
+            action.setId(getId());
+            action.setText(WorkbenchMessages.get().CloseAllAction_text);
+            action.setToolTipText(WorkbenchMessages.get().CloseAllAction_toolTip);
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "closeOthers", commandId: "org.eclipse.ui.file.closeOthers"): Close all
+	 * editors except the one that is active. This action maintains its enablement state.
+	 *
+	 * @since 3.2
+	 */
+    public static final ActionFactory CLOSE_OTHERS = new ActionFactory("closeOthers",//$NON-NLS-1$
+    		IWorkbenchCommandConstants.FILE_CLOSE_OTHERS) {
+
+		@Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+			if (window == null) {
+				throw new IllegalArgumentException();
+			}
+			WorkbenchCommandAction action = new WorkbenchCommandAction(
+					getCommandId(), window);
+			action.setId(getId());
+			action.setText(WorkbenchMessages.get().CloseOthersAction_text);
+			action.setToolTipText(WorkbenchMessages.get().CloseOthersAction_toolTip);
+			return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "closeAllPerspectives", commandId: "org.eclipse.ui.window.closeAllPerspectives"):
+	 * Closes all perspectives. This action maintains its enablement state.
+	 */
+    public static final ActionFactory CLOSE_ALL_PERSPECTIVES = new ActionFactory(
+            "closeAllPerspectives", IWorkbenchCommandConstants.WINDOW_CLOSE_ALL_PERSPECTIVES) {//$NON-NLS-1$
+
+		@Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+			WorkbenchCommandAction action = new WorkbenchCommandAction(
+					getCommandId(), window);
+
+            action.setId(getId());
+            action.setText(WorkbenchMessages.get().CloseAllPerspectivesAction_text);
+            action.setToolTipText(WorkbenchMessages.get().CloseAllPerspectivesAction_toolTip);
+            window.getWorkbench().getHelpSystem().setHelp(action, IWorkbenchHelpContextIds.CLOSE_ALL_PAGES_ACTION);
+
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "closeAllSaved"): Close all open editors except those with unsaved
+	 * changes. This action maintains its enablement state.
+	 */
+    public static final ActionFactory CLOSE_ALL_SAVED = new ActionFactory(
+            "closeAllSaved") {//$NON-NLS-1$
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            IWorkbenchAction action = new CloseAllSavedAction(window);
+            action.setId(getId());
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "closePerspective", commandId: "org.eclipse.ui.window.closePerspective"):
+	 * Closes the current perspective. This action maintains its enablement state.
+	 */
+    public static final ActionFactory CLOSE_PERSPECTIVE = new ActionFactory(
+    "closePerspective", IWorkbenchCommandConstants.WINDOW_CLOSE_PERSPECTIVE) {//$NON-NLS-1$
+
+    	@Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+    		if (window == null) {
+    			throw new IllegalArgumentException();
+    		}
+    		WorkbenchCommandAction action = new WorkbenchCommandAction(
+    				getCommandId(), window);
+
+    		action.setId(getId());
+    		action.setText(WorkbenchMessages.get().
+    				ClosePerspectiveAction_text);
+    		action.setToolTipText(WorkbenchMessages.get().
+    				ClosePerspectiveAction_toolTip);
+    		window.getWorkbench().getHelpSystem().setHelp(action,
+    				IWorkbenchHelpContextIds.CLOSE_PAGE_ACTION);
+    		return action;
+    	}
+    };
+
+	/**
+	 * Workbench action (id: "intro", commandId: "org.eclipse.ui.help.quickStartAction"): Activate
+	 * the introduction extension. This action should not be instantiated if no intro is provided.
+	 * Use code like:
+	 *
+	 * <pre>
+	 * if (window.getWorkbench().getIntroManager().hasIntro()) {
+	 * 	introAction= ActionFactory.INTRO.create(window);
+	 * 	register(introAction);
+	 * }
+	 * </pre>
+	 */
+    public static final ActionFactory INTRO = new ActionFactory("intro", //$NON-NLS-1$
+    		IWorkbenchCommandConstants.HELP_WELCOME) {
+
+		@Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+
+			WorkbenchCommandAction action = new WorkbenchCommandAction(getCommandId(), window);
+
+			action.setId(getId());
+			action.setText(IntroMessages.Intro_action_text);
+			window.getWorkbench().getHelpSystem()
+					.setHelp(action, IWorkbenchHelpContextIds.INTRO_ACTION);
+			IntroDescriptor introDescriptor = ((Workbench) window.getWorkbench())
+					.getIntroDescriptor();
+			if (introDescriptor != null) {
+				action.setImageDescriptor(introDescriptor.getImageDescriptor());
+				String labelOverride = introDescriptor.getLabelOverride();
+				if (labelOverride != null) {
+					action.setText(labelOverride);
+				}
+			}
+
+			return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "copy", commandId: "org.eclipse.ui.edit.copy"): Copy. This action is a
+	 * {@link RetargetAction} with id "copy". This action maintains its enablement state.
+	 */
+    public static final ActionFactory COPY = new ActionFactory("copy", //$NON-NLS-1$
+    		IWorkbenchCommandConstants.EDIT_COPY) {
+
+		@Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            RetargetAction action = new RetargetAction(getId(),WorkbenchMessages.get().Workbench_copy);
+            action.setToolTipText(WorkbenchMessages.get().Workbench_copyToolTip);
+            window.getPartService().addPartListener(action);
+            action.setActionDefinitionId(getCommandId());
+            ISharedImages sharedImages = window.getWorkbench()
+                    .getSharedImages();
+            action.setImageDescriptor(sharedImages
+                    .getImageDescriptor(ISharedImages.IMG_TOOL_COPY));
+            action.setDisabledImageDescriptor(sharedImages
+                    .getImageDescriptor(ISharedImages.IMG_TOOL_COPY_DISABLED));
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "cut", commandId: "org.eclipse.ui.edit.cut"): Cut. This action is a
+	 * {@link RetargetAction} with id "cut". This action maintains its enablement state.
+	 */
+    public static final ActionFactory CUT = new ActionFactory("cut", //$NON-NLS-1$
+    		IWorkbenchCommandConstants.EDIT_CUT) {
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            RetargetAction action = new RetargetAction(getId(),WorkbenchMessages.get().Workbench_cut);
+            action.setToolTipText(WorkbenchMessages.get().Workbench_cutToolTip);
+            window.getPartService().addPartListener(action);
+            action.setActionDefinitionId(getCommandId());
+            ISharedImages sharedImages = window.getWorkbench()
+                    .getSharedImages();
+            action.setImageDescriptor(sharedImages
+                    .getImageDescriptor(ISharedImages.IMG_TOOL_CUT));
+            action.setDisabledImageDescriptor(sharedImages
+                    .getImageDescriptor(ISharedImages.IMG_TOOL_CUT_DISABLED));
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "delete", commandId: "org.eclipse.ui.edit.delete"): Delete. This action
+	 * is a {@link RetargetAction} with id "delete". This action maintains its enablement state.
+	 */
+    public static final ActionFactory DELETE = new ActionFactory("delete", //$NON-NLS-1$
+    		IWorkbenchCommandConstants.EDIT_DELETE) {
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            RetargetAction action = new RetargetAction(getId(),WorkbenchMessages.get().Workbench_delete);
+            action.setToolTipText(WorkbenchMessages.get().Workbench_deleteToolTip);
+            window.getPartService().addPartListener(action);
+            action.setActionDefinitionId(getCommandId());
+            action.enableAccelerator(false);
+            window.getWorkbench().getHelpSystem().setHelp(action,
+                    IWorkbenchHelpContextIds.DELETE_RETARGET_ACTION);
+            ISharedImages sharedImages = window.getWorkbench()
+                    .getSharedImages();
+            action.setImageDescriptor(sharedImages
+                    .getImageDescriptor(ISharedImages.IMG_TOOL_DELETE));
+            action
+                    .setDisabledImageDescriptor(sharedImages
+                            .getImageDescriptor(ISharedImages.IMG_TOOL_DELETE_DISABLED));
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "editActionSets", commandId: "org.eclipse.ui.window.customizePerspective"):
+	 * Edit the action sets. This action maintains its enablement state.
+	 */
+    public static final ActionFactory EDIT_ACTION_SETS = new ActionFactory(
+            "editActionSets", IWorkbenchCommandConstants.WINDOW_CUSTOMIZE_PERSPECTIVE) {//$NON-NLS-1$
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+			WorkbenchCommandAction action = new WorkbenchCommandAction(
+					getCommandId(), window);
+            action.setId(getId());
+            action.setText(WorkbenchMessages.get().EditActionSetsAction_text);
+            action.setToolTipText(WorkbenchMessages.get().EditActionSetsAction_toolTip);
+            window.getWorkbench().getHelpSystem().setHelp(action,
+    				IWorkbenchHelpContextIds.EDIT_ACTION_SETS_ACTION);
+
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "export", commandId: "org.eclipse.ui.file.export"): Opens the export
+	 * wizard. This action maintains its enablement state.
+	 */
+    public static final ActionFactory EXPORT = new ActionFactory("export", //$NON-NLS-1$
+    		IWorkbenchCommandConstants.FILE_EXPORT) {
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+
+			WorkbenchCommandAction action = new WorkbenchCommandAction(
+					getCommandId(), window);
+            action.setId(getId());
+            action.setText(WorkbenchMessages.get().ExportResourcesAction_fileMenuText);
+            action.setToolTipText(WorkbenchMessages.get().ExportResourcesAction_toolTip);
+            window.getWorkbench().getHelpSystem().setHelp(action,
+    				IWorkbenchHelpContextIds.EXPORT_ACTION);
+            action.setImageDescriptor(WorkbenchImages
+                    .getImageDescriptor(IWorkbenchGraphicConstants.IMG_ETOOL_EXPORT_WIZ));
+            return action;
+        }
+
+    };
+
+	/**
+	 * Workbench action (id: "find", commandId: "org.eclipse.ui.edit.findReplace"): Find. This
+	 * action is a {@link RetargetAction} with id "find". This action maintains its enablement
+	 * state.
+	 */
+    public static final ActionFactory FIND = new ActionFactory("find", //$NON-NLS-1$
+    		IWorkbenchCommandConstants.EDIT_FIND_AND_REPLACE) {
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            RetargetAction action = new RetargetAction(getId(),WorkbenchMessages.get().Workbench_findReplace);
+            action.setToolTipText(WorkbenchMessages.get().Workbench_findReplaceToolTip);
+            window.getPartService().addPartListener(action);
+            action.setActionDefinitionId(getCommandId());
+            // Find's images are commented out due to a conflict with Search.
+            // See bug 16412.
+            //		action.setImageDescriptor(WorkbenchImages.getImageDescriptor(IWorkbenchGraphicConstants.IMG_ETOOL_SEARCH_SRC));
+            //		action.setDisabledImageDescriptor(WorkbenchImages.getImageDescriptor(IWorkbenchGraphicConstants.IMG_ETOOL_SEARCH_SRC_DISABLED));
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "forward", commandId: "org.eclipse.ui.navigate.forward"): Forward. This
+	 * action is a {@link RetargetAction} with id "forward". This action maintains its enablement
+	 * state.
+	 */
+    public static final ActionFactory FORWARD = new ActionFactory("forward", //$NON-NLS-1$
+    		IWorkbenchCommandConstants.NAVIGATE_FORWARD) {
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            RetargetAction action = new LabelRetargetAction(getId(),WorkbenchMessages.get().Workbench_forward);
+            action.setToolTipText(WorkbenchMessages.get().Workbench_forwardToolTip);
+            window.getPartService().addPartListener(action);
+            action.setActionDefinitionId(getCommandId());
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "forwardHistory", commandId: "org.eclipse.ui.navigate.forwardHistory"):
+	 * Forward in the navigation history. This action maintains its enablement state.
+	 */
+    public static final ActionFactory FORWARD_HISTORY = new ActionFactory(
+            "forwardHistory", IWorkbenchCommandConstants.NAVIGATE_FORWARD_HISTORY) {//$NON-NLS-1$
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            IWorkbenchAction action = new NavigationHistoryAction(window, true);
+            action.setId(getId());
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "goInto", commandId: "org.eclipse.ui.navigate.goInto"): Go Into. This
+	 * action is a {@link RetargetAction} with id "goInto". This action maintains its enablement
+	 * state.
+	 */
+    public static final ActionFactory GO_INTO = new ActionFactory("goInto", //$NON-NLS-1$
+    		IWorkbenchCommandConstants.NAVIGATE_GO_INTO) {
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            RetargetAction action = new LabelRetargetAction(getId(),WorkbenchMessages.get().Workbench_goInto);
+            action.setToolTipText(WorkbenchMessages.get().Workbench_goIntoToolTip);
+            window.getPartService().addPartListener(action);
+            action.setActionDefinitionId(getCommandId());
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "import", commandId: "org.eclipse.ui.file.import"): Opens the import
+	 * wizard. This action maintains its enablement state.
+	 */
+    public static final ActionFactory IMPORT = new ActionFactory("import", //$NON-NLS-1$
+    		IWorkbenchCommandConstants.FILE_IMPORT) {
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+
+			WorkbenchCommandAction action = new WorkbenchCommandAction(
+					getCommandId(), window);
+            action.setId(getId());
+            action.setText(WorkbenchMessages.get().ImportResourcesAction_text);
+            action.setToolTipText(WorkbenchMessages.get().ImportResourcesAction_toolTip);
+            window.getWorkbench().getHelpSystem().setHelp(action,
+    				IWorkbenchHelpContextIds.IMPORT_ACTION);
+            action.setImageDescriptor(WorkbenchImages
+                    .getImageDescriptor(IWorkbenchGraphicConstants.IMG_ETOOL_IMPORT_WIZ));
+            return action;
+
+        }
+    };
+
+	/**
+	 * Workbench action (id: "lockToolBar"): Lock/unlock the workbench window
+	 * tool bar. This action maintains its enablement state.
+	 */
+	public static final ActionFactory LOCK_TOOL_BAR = new ActionFactory("lockToolBar", //$NON-NLS-1$
+			IWorkbenchCommandConstants.WINDOW_LOCK_TOOLBAR) {
+
+		@Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+			if (window == null) {
+				throw new IllegalArgumentException();
+			}
+			WorkbenchCommandAction action = new WorkbenchCommandAction(getCommandId(), window);
+			action.setId(getId());
+			action.setToolTipText(WorkbenchMessages.get().LockToolBarAction_toolTip);
+			window.getWorkbench().getHelpSystem()
+					.setHelp(action, IWorkbenchHelpContextIds.LOCK_TOOLBAR_ACTION);
+			return action;
+		}
+    };
+
+	/**
+	 * Workbench action (id: "maximize", commandId:
+	 * "org.eclipse.ui.window.maximizePart"): Maximize/restore the active part.
+	 * This action maintains its enablement state.
+	 *
+	 * @deprecated you should not use this field, kept for compatibility
+	 *             reasons. use instead the command
+	 *             {@code org.eclipse.ui.window.maximizePart}.
+	 */
+	@Deprecated
+    public static final ActionFactory MAXIMIZE = new ActionFactory("maximize", //$NON-NLS-1$
+    		IWorkbenchCommandConstants.WINDOW_MAXIMIZE_ACTIVE_VIEW_OR_EDITOR) {
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            WorkbenchCommandAction action = new WorkbenchCommandAction(
+					getCommandId(), window);
+            action.setId(getId());
+            action.setToolTipText(WorkbenchMessages.get().MaximizePartAction_toolTip);
+            window.getWorkbench().getHelpSystem().setHelp(action,
+    				IWorkbenchHelpContextIds.MAXIMIZE_PART_ACTION);
+
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "minimize", commandId:
+	 * "org.eclipse.ui.window.minimizePart"): Minimizes the active part. This
+	 * action maintains its enablement state.
+	 *
+	 * @since 3.1
+	 * @deprecated you should not use this field, that is kept for compatibility
+	 *             reasons. use instead the command
+	 *             {@code org.eclipse.ui.window.minimizePart}.
+	 */
+	@Deprecated
+    public static final ActionFactory MINIMIZE = new ActionFactory("minimize", //$NON-NLS-1$
+    		IWorkbenchCommandConstants.WINDOW_MINIMIZE_ACTIVE_VIEW_OR_EDITOR) {
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            WorkbenchCommandAction action = new WorkbenchCommandAction(
+					getCommandId(), window);
+			action.setId(getId());
+			action.setToolTipText(WorkbenchMessages.get().MinimizePartAction_toolTip);
+			window.getWorkbench().getHelpSystem().setHelp(action,
+					IWorkbenchHelpContextIds.MINIMIZE_PART_ACTION);
+			return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "move", commandId: "org.eclipse.ui.edit.move"): Move. This action is a
+	 * {@link RetargetAction} with id "move". This action maintains its enablement state.
+	 */
+    public static final ActionFactory MOVE = new ActionFactory("move", //$NON-NLS-1$
+    		IWorkbenchCommandConstants.FILE_MOVE) {
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            RetargetAction action = new RetargetAction(getId(),WorkbenchMessages.get().Workbench_move);
+            action.setToolTipText(WorkbenchMessages.get().Workbench_moveToolTip);
+            window.getPartService().addPartListener(action);
+            action.setActionDefinitionId(getCommandId());
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "new", commandId: "org.eclipse.ui.newWizard"): Opens the new wizard
+	 * dialog. This action maintains its enablement state.
+	 */
+    public static final ActionFactory NEW = new ActionFactory("new", //$NON-NLS-1$
+    		IWorkbenchCommandConstants.FILE_NEW) {
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+			WorkbenchCommandAction action = new WorkbenchCommandAction(
+					getCommandId(), window);
+            action.setId(getId());
+            ISharedImages images = window.getWorkbench().getSharedImages();
+            action.setImageDescriptor(images
+                    .getImageDescriptor(ISharedImages.IMG_TOOL_NEW_WIZARD));
+            action.setDisabledImageDescriptor(images
+                    .getImageDescriptor(ISharedImages.IMG_TOOL_NEW_WIZARD_DISABLED));
+            action.setText(WorkbenchMessages.get().NewWizardAction_text);
+            action.setToolTipText(WorkbenchMessages.get().NewWizardAction_toolTip);
+            window.getWorkbench().getHelpSystem().setHelp(action,
+    				IWorkbenchHelpContextIds.NEW_ACTION);
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "newWizardDropDown"): Drop-down action which shows shows the new wizard
+	 * drop down, or opens the new wizard dialog when pressed. For use in the toolbar. This action
+	 * maintains its enablement state.
+	 *
+	 * @since 3.1
+	 */
+    public static final ActionFactory NEW_WIZARD_DROP_DOWN = new ActionFactory(
+            "newWizardDropDown") { //$NON-NLS-1$
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            IWorkbenchAction action = new NewWizardDropDownAction(window);
+            action.setId(getId());
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "next", commandId: "org.eclipse.ui.navigate.next"): Next. This action
+	 * is a {@link RetargetAction} with id "next". This action maintains its enablement state.
+	 */
+    public static final ActionFactory NEXT = new ActionFactory("next", //$NON-NLS-1$
+    		IWorkbenchCommandConstants.NAVIGATE_NEXT) {
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            RetargetAction action = new LabelRetargetAction(getId(),WorkbenchMessages.get().Workbench_next);
+            action.setToolTipText(WorkbenchMessages.get().Workbench_nextToolTip);
+            window.getPartService().addPartListener(action);
+            action.setActionDefinitionId(getCommandId());
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "nextEditor", commandId: "org.eclipse.ui.window.nextEditor"): Next
+	 * editor. This action maintains its enablement state.
+	 * <p>
+	 * <code>NEXT_EDITOR</code> and <code>PREVIOUS_EDITOR</code> form a cycle action pair. For a
+	 * given window, use {@link ActionFactory#linkCycleActionPair
+	 * ActionFactory.linkCycleActionPair</code>} to connect the two.
+	 * </p>
+	 */
+    public static final ActionFactory NEXT_EDITOR = new ActionFactory(
+            "nextEditor", IWorkbenchCommandConstants.WINDOW_NEXT_EDITOR) {//$NON-NLS-1$
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+			if (window == null) {
+				throw new IllegalArgumentException();
+			}
+			IWorkbenchAction action = new WorkbenchCommandAction(
+					getCommandId(), window);
+
+			action.setId(getId());
+			action.setText(WorkbenchMessages.get().CycleEditorAction_next_text);
+			action.setToolTipText(WorkbenchMessages.get().CycleEditorAction_next_toolTip);
+            // @issue missing action ids
+			window.getWorkbench().getHelpSystem().setHelp(action,
+					IWorkbenchHelpContextIds.CYCLE_EDITOR_FORWARD_ACTION);
+
+			return action;
+		}
+    };
+
+	/**
+	 * Workbench action (id: "nextPart", commandId: "org.eclipse.ui.window.nextView"): Next part.
+	 * This action maintains its enablement state.
+	 * <p>
+	 * <code>NEXT_PART</code> and <code>PREVIOUS_PART</code> form a cycle action pair. For a given
+	 * window, use {@link ActionFactory#linkCycleActionPair
+	 * ActionFactory.linkCycleActionPair</code>} to connect the two.
+	 * </p>
+	 */
+    public static final ActionFactory NEXT_PART = new ActionFactory("nextPart", //$NON-NLS-1$
+    		IWorkbenchCommandConstants.WINDOW_NEXT_VIEW) {
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+			WorkbenchCommandAction action = new WorkbenchCommandAction(
+					getCommandId(), window);
+            action.setId(getId());
+            action.setText(WorkbenchMessages.get().CyclePartAction_next_text);
+			action.setToolTipText(WorkbenchMessages.get().CyclePartAction_next_toolTip);
+			// @issue missing action ids
+			window.getWorkbench().getHelpSystem().setHelp(action,
+					IWorkbenchHelpContextIds.CYCLE_PART_FORWARD_ACTION);
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "nextPerspective", commandId: "org.eclipse.ui.window.nextPerspective"):
+	 * Next perspective. This action maintains its enablement state.
+	 * <p>
+	 * <code>NEXT_PERSPECTIVE</code> and <code>PREVIOUS_PERSPECTIVE</code> form a cycle action pair.
+	 * For a given window, use {@link ActionFactory#linkCycleActionPair
+	 * ActionFactory.linkCycleActionPair</code>} to connect the two.
+	 * </p>
+	 */
+    public static final ActionFactory NEXT_PERSPECTIVE = new ActionFactory(
+            "nextPerspective", IWorkbenchCommandConstants.WINDOW_NEXT_PERSPECTIVE) {//$NON-NLS-1$
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+			WorkbenchCommandAction action = new WorkbenchCommandAction(
+					getCommandId(), window);
+            action.setId(getId());
+            action.setText(WorkbenchMessages.get().CyclePerspectiveAction_next_text);
+            action.setToolTipText(WorkbenchMessages.get().CyclePerspectiveAction_next_toolTip);
+            // @issue missing action ids
+            window.getWorkbench().getHelpSystem().setHelp(action,
+					IWorkbenchHelpContextIds.CYCLE_PERSPECTIVE_FORWARD_ACTION);
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "openNewWindow", commandId: "org.eclipse.ui.window.newWindow"): Open a
+	 * new workbench window. This action maintains its enablement state.
+	 */
+    public static final ActionFactory OPEN_NEW_WINDOW = new ActionFactory(
+            "openNewWindow", IWorkbenchCommandConstants.WINDOW_NEW_WINDOW) {//$NON-NLS-1$
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+			WorkbenchCommandAction action = new WorkbenchCommandAction(
+					getCommandId(), window);
+            action.setId(getId());
+            action.setText(WorkbenchMessages.get().OpenInNewWindowAction_text);
+            action.setToolTipText(WorkbenchMessages.get().OpenInNewWindowAction_toolTip);
+            window.getWorkbench().getHelpSystem().setHelp(action,
+            		IWorkbenchHelpContextIds.OPEN_NEW_WINDOW_ACTION);
+            return action;
+        }
+
+    };
+
+	/**
+	 * Workbench action (id: "paste", commandId: "org.eclipse.ui.edit.paste"): Paste. This action is
+	 * a {@link RetargetAction} with id "paste". This action maintains its enablement state.
+	 */
+    public static final ActionFactory PASTE = new ActionFactory("paste", //$NON-NLS-1$
+    		IWorkbenchCommandConstants.EDIT_PASTE) {
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            RetargetAction action = new RetargetAction(getId(),WorkbenchMessages.get().Workbench_paste);
+            action.setToolTipText(WorkbenchMessages.get().Workbench_pasteToolTip);
+            window.getPartService().addPartListener(action);
+            action.setActionDefinitionId(getCommandId());
+            ISharedImages sharedImages = window.getWorkbench()
+                    .getSharedImages();
+            action.setImageDescriptor(sharedImages
+                    .getImageDescriptor(ISharedImages.IMG_TOOL_PASTE));
+            action.setDisabledImageDescriptor(sharedImages
+                    .getImageDescriptor(ISharedImages.IMG_TOOL_PASTE_DISABLED));
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "preferences", commandId: "org.eclipse.ui.window.preferences"):
+	 * Displays the Preferences dialog. This action maintains its enablement state.
+	 */
+    public static final ActionFactory PREFERENCES = new ActionFactory(
+            "preferences", IWorkbenchCommandConstants.WINDOW_PREFERENCES) {//$NON-NLS-1$
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            IWorkbenchAction action = new OpenPreferencesAction(window);
+            action.setId(getId());
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "previous", commandId: "org.eclipse.ui.navigate.previous"): Previous.
+	 * This action is a {@link RetargetAction} with id "previous". This action maintains its
+	 * enablement state.
+	 */
+    public static final ActionFactory PREVIOUS = new ActionFactory("previous", //$NON-NLS-1$
+    		IWorkbenchCommandConstants.NAVIGATE_PREVIOUS) {
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            RetargetAction action = new LabelRetargetAction(getId(),WorkbenchMessages.get().Workbench_previous);
+            action.setToolTipText(WorkbenchMessages.get().Workbench_previousToolTip);
+            window.getPartService().addPartListener(action);
+            action.setActionDefinitionId(getCommandId());
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "previousEditor", commandId: "org.eclipse.ui.window.previousEditor"):
+	 * Previous editor. This action maintains its enablement state.
+	 * <p>
+	 * <code>NEXT_EDITOR</code> and <code>PREVIOUS_EDITOR</code> form a cycle action pair. For a
+	 * given window, use {@link ActionFactory#linkCycleActionPair
+	 * ActionFactory.linkCycleActionPair</code>} to connect the two.
+	 * </p>
+	 */
+    public static final ActionFactory PREVIOUS_EDITOR = new ActionFactory(
+            "previousEditor", IWorkbenchCommandConstants.WINDOW_PREVIOUS_EDITOR) {//$NON-NLS-1$
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+			IWorkbenchAction action = new WorkbenchCommandAction(
+					getCommandId(), window);
+            action.setId(getId());
+            action.setText(WorkbenchMessages.get().CycleEditorAction_prev_text);
+            action.setToolTipText(WorkbenchMessages.get().CycleEditorAction_prev_toolTip);
+            // @issue missing action ids
+            window.getWorkbench().getHelpSystem().setHelp(action,
+					IWorkbenchHelpContextIds.CYCLE_EDITOR_BACKWARD_ACTION);
+
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "previousPart", commandId: "org.eclipse.ui.window.previousView"):
+	 * Previous part. This action maintains its enablement state.
+	 * <p>
+	 * <code>NEXT_PART</code> and <code>PREVIOUS_PART</code> form a cycle action pair. For a given
+	 * window, use {@link ActionFactory#linkCycleActionPair
+	 * ActionFactory.linkCycleActionPair</code>} to connect the two.
+	 * </p>
+	 */
+    public static final ActionFactory PREVIOUS_PART = new ActionFactory(
+            "previousPart", IWorkbenchCommandConstants.WINDOW_PREVIOUS_VIEW) {//$NON-NLS-1$
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+			WorkbenchCommandAction action = new WorkbenchCommandAction(
+					getCommandId(), window);
+            action.setId(getId());
+			action.setText(WorkbenchMessages.get().CyclePartAction_prev_text);
+			action.setToolTipText(WorkbenchMessages.get().CyclePartAction_prev_toolTip);
+			// @issue missing action ids
+			window.getWorkbench().getHelpSystem().setHelp(action,
+					IWorkbenchHelpContextIds.CYCLE_PART_BACKWARD_ACTION);
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "previousPerspective", commandId: "org.eclipse.ui.window.previousPerspective"):
+	 * Previous perspective. This action maintains its enablement state.
+	 * <p>
+	 * <code>NEXT_PERSPECTIVE</code> and <code>PREVIOUS_PERSPECTIVE</code> form a cycle action pair.
+	 * For a given window, use {@link ActionFactory#linkCycleActionPair
+	 * ActionFactory.linkCycleActionPair</code>} to connect the two.
+	 * </p>
+	 */
+    public static final ActionFactory PREVIOUS_PERSPECTIVE = new ActionFactory(
+            "previousPerspective", IWorkbenchCommandConstants.WINDOW_PREVIOUS_PERSPECTIVE) {//$NON-NLS-1$
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+			WorkbenchCommandAction action = new WorkbenchCommandAction(
+					getCommandId(), window);
+            action.setId(getId());
+            action.setText(WorkbenchMessages.get().CyclePerspectiveAction_prev_text);
+            action.setToolTipText(WorkbenchMessages.get().CyclePerspectiveAction_prev_toolTip);
+            // @issue missing action ids
+            window.getWorkbench().getHelpSystem().setHelp(action,
+					IWorkbenchHelpContextIds.CYCLE_PERSPECTIVE_BACKWARD_ACTION);
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "print", commandId: "org.eclipse.ui.file.print"): Print. This action is
+	 * a {@link RetargetAction} with id "print". This action maintains its enablement state.
+	 */
+    public static final ActionFactory PRINT = new ActionFactory("print", //$NON-NLS-1$
+    		IWorkbenchCommandConstants.FILE_PRINT) {
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            RetargetAction action = new RetargetAction(getId(),WorkbenchMessages.get().Workbench_print);
+            action.setToolTipText(WorkbenchMessages.get().Workbench_printToolTip);
+            window.getPartService().addPartListener(action);
+            action.setActionDefinitionId(getCommandId());
+            action
+                    .setImageDescriptor(WorkbenchImages
+                            .getImageDescriptor(ISharedImages.IMG_ETOOL_PRINT_EDIT));
+            action
+                    .setDisabledImageDescriptor(WorkbenchImages
+                            .getImageDescriptor(ISharedImages.IMG_ETOOL_PRINT_EDIT_DISABLED));
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "properties", commandId: "org.eclipse.ui.file.properties"): Properties.
+	 * This action is a {@link RetargetAction} with id "properties". This action maintains its
+	 * enablement state.
+	 */
+    public static final ActionFactory PROPERTIES = new ActionFactory(
+            "properties", IWorkbenchCommandConstants.FILE_PROPERTIES) {//$NON-NLS-1$
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            RetargetAction action = new RetargetAction(getId(),WorkbenchMessages.get().Workbench_properties);
+            action.setToolTipText(WorkbenchMessages.get().Workbench_propertiesToolTip);
+            window.getPartService().addPartListener(action);
+            action.setActionDefinitionId(getCommandId());
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "quit", commandId: "org.eclipse.ui.file.exit"): Quit (close the
+	 * workbench). This action maintains its enablement state.
+	 */
+    public static final ActionFactory QUIT = new ActionFactory("quit", //$NON-NLS-1$
+    		IWorkbenchCommandConstants.FILE_EXIT) {
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+			WorkbenchCommandAction action = new WorkbenchCommandAction(
+					getCommandId(), window);
+            action.setId(getId());
+            action.setText(WorkbenchMessages.get().Exit_text);
+            action.setToolTipText(WorkbenchMessages.get().Exit_toolTip);
+            window.getWorkbench().getHelpSystem().setHelp(action,
+    				IWorkbenchHelpContextIds.QUIT_ACTION);
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "redo", commandId: "org.eclipse.ui.edit.redo"): Redo. This action is a
+	 * {@link RetargetAction} with id "redo". This action maintains its enablement state.
+	 */
+    public static final ActionFactory REDO = new ActionFactory("redo", //$NON-NLS-1$
+    		IWorkbenchCommandConstants.EDIT_REDO) {
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            LabelRetargetAction action = new LabelRetargetAction(getId(),WorkbenchMessages.get().Workbench_redo);
+            action.setToolTipText(WorkbenchMessages.get().Workbench_redoToolTip);
+            window.getPartService().addPartListener(action);
+            action.setActionDefinitionId(getCommandId());
+            ISharedImages sharedImages = window.getWorkbench()
+                    .getSharedImages();
+            action.setImageDescriptor(sharedImages
+                    .getImageDescriptor(ISharedImages.IMG_TOOL_REDO));
+            action.setDisabledImageDescriptor(sharedImages
+                    .getImageDescriptor(ISharedImages.IMG_TOOL_REDO_DISABLED));
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "refresh", commandId: "org.eclipse.ui.file.refresh"): Refresh. This
+	 * action is a {@link RetargetAction} with id "refresh". This action maintains its enablement
+	 * state.
+	 */
+    public static final ActionFactory REFRESH = new ActionFactory("refresh", //$NON-NLS-1$
+    		IWorkbenchCommandConstants.FILE_REFRESH) {
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            RetargetAction action = new RetargetAction(getId(),WorkbenchMessages.get().Workbench_refresh);
+            action.setToolTipText(WorkbenchMessages.get().Workbench_refreshToolTip);
+            window.getPartService().addPartListener(action);
+            action.setActionDefinitionId(getCommandId());
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "rename", commandId: "org.eclipse.ui.edit.rename"): Rename. This action
+	 * is a {@link RetargetAction} with id "rename". This action maintains its enablement state.
+	 */
+    public static final ActionFactory RENAME = new ActionFactory("rename", //$NON-NLS-1$
+    		IWorkbenchCommandConstants.FILE_RENAME) {
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            RetargetAction action = new RetargetAction(getId(),WorkbenchMessages.get().Workbench_rename);
+            action.setToolTipText(WorkbenchMessages.get().Workbench_renameToolTip);
+            window.getPartService().addPartListener(action);
+            action.setActionDefinitionId(getCommandId());
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "resetPerspective", commandId: "org.eclipse.ui.window.resetPerspective"):
+	 * Resets the current perspective. This action maintains its enablement state.
+	 */
+    public static final ActionFactory RESET_PERSPECTIVE = new ActionFactory(
+            "resetPerspective", IWorkbenchCommandConstants.WINDOW_RESET_PERSPECTIVE) {//$NON-NLS-1$
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+			if (window == null) {
+				throw new IllegalArgumentException();
+			}
+			WorkbenchCommandAction action = new WorkbenchCommandAction(getCommandId(), window);
+
+			action.setId(getId());
+			action.setText(WorkbenchMessages.get().ResetPerspective_text);
+			action.setToolTipText(WorkbenchMessages.get().ResetPerspective_toolTip);
+			window.getWorkbench().getHelpSystem()
+					.setHelp(action, IWorkbenchHelpContextIds.RESET_PERSPECTIVE_ACTION);
+			return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "revert", commandId: "org.eclipse.ui.file.revert"): Revert. This action
+	 * is a {@link RetargetAction} with id "revert". This action maintains its enablement state.
+	 */
+    public static final ActionFactory REVERT = new ActionFactory("revert", //$NON-NLS-1$
+    		IWorkbenchCommandConstants.FILE_REVERT) {
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            RetargetAction action = new RetargetAction(getId(),WorkbenchMessages.get().Workbench_revert);
+            action.setToolTipText(WorkbenchMessages.get().Workbench_revertToolTip);
+            window.getPartService().addPartListener(action);
+            action.setActionDefinitionId(getCommandId());
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "save", commandId: "org.eclipse.ui.file.save"): Save the active editor.
+	 * This action maintains its enablement state.
+	 */
+    public static final ActionFactory SAVE = new ActionFactory("save", //$NON-NLS-1$
+    		IWorkbenchCommandConstants.FILE_SAVE) {
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+			WorkbenchCommandAction action = new WorkbenchCommandAction(getCommandId(), window);
+			action.setText(WorkbenchMessages.get().SaveAction_text);
+			action.setToolTipText(WorkbenchMessages.get().SaveAction_toolTip);
+            action.setId(getId());
+			window.getWorkbench().getHelpSystem()
+					.setHelp(action, IWorkbenchHelpContextIds.SAVE_ACTION);
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "saveAll", commandId: "org.eclipse.ui.file.saveAll"): Save all open
+	 * editors with unsaved changes. This action maintains its enablement state.
+	 */
+    public static final ActionFactory SAVE_ALL = new ActionFactory("saveAll", //$NON-NLS-1$
+    		IWorkbenchCommandConstants.FILE_SAVE_ALL) {
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+			IWorkbenchAction action = new WorkbenchCommandAction(getCommandId(), window);
+			action.setText(WorkbenchMessages.get().SaveAll_text);
+			action.setToolTipText(WorkbenchMessages.get().SaveAll_toolTip);
+			window.getWorkbench().getHelpSystem()
+					.setHelp(action, IWorkbenchHelpContextIds.SAVE_ALL_ACTION);
+            action.setId(getId());
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "saveAs", commandId: "org.eclipse.ui.file.saveAs"): Save As for the
+	 * active editor. This action maintains its enablement state.
+	 */
+    public static final ActionFactory SAVE_AS = new ActionFactory("saveAs", //$NON-NLS-1$
+    		IWorkbenchCommandConstants.FILE_SAVE_AS) {
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+			IWorkbenchAction action = new WorkbenchCommandAction(getCommandId(), window);
+			action.setText(WorkbenchMessages.get().SaveAs_text);
+			action.setToolTipText(WorkbenchMessages.get().SaveAs_toolTip);
+			window.getWorkbench().getHelpSystem()
+					.setHelp(action, IWorkbenchHelpContextIds.SAVE_AS_ACTION);
+            action.setId(getId());
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "savePerspective", commandId: "org.eclipse.ui.window.savePerspective"):
+	 * Save the current perspective. This action maintains its enablement state.
+	 */
+    public static final ActionFactory SAVE_PERSPECTIVE = new ActionFactory(
+            "savePerspective", IWorkbenchCommandConstants.WINDOW_SAVE_PERSPECTIVE_AS) {//$NON-NLS-1$
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+			if (window == null) {
+				throw new IllegalArgumentException();
+			}
+			WorkbenchCommandAction action = new WorkbenchCommandAction(getCommandId(), window);
+
+			action.setId(getId());
+			action.setText(WorkbenchMessages.get().SavePerspective_text);
+			action.setToolTipText(WorkbenchMessages.get().SavePerspective_toolTip);
+			window.getWorkbench().getHelpSystem()
+					.setHelp(action, IWorkbenchHelpContextIds.SAVE_PERSPECTIVE_ACTION);
+			return action;
+		}
+    };
+
+	/**
+	 * Workbench action (id: "selectAll", commandId: "org.eclipse.ui.edit.selectAll"): Select All.
+	 * This action is a {@link RetargetAction} with id "selectAll". This action maintains its
+	 * enablement state.
+	 */
+    public static final ActionFactory SELECT_ALL = new ActionFactory(
+            "selectAll", IWorkbenchCommandConstants.EDIT_SELECT_ALL) {//$NON-NLS-1$
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            RetargetAction action = new RetargetAction(getId(),WorkbenchMessages.get().Workbench_selectAll);
+            action.setToolTipText(WorkbenchMessages.get().Workbench_selectAllToolTip);
+            window.getPartService().addPartListener(action);
+            action.setActionDefinitionId(getCommandId());
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "showEditor"): Show/hide the editor area. This action maintains its
+	 * enablement state.
+	 */
+    public static final ActionFactory SHOW_EDITOR = new ActionFactory(
+            "showEditor") {//$NON-NLS-1$
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            IWorkbenchAction action = new ToggleEditorsVisibilityAction(window);
+            action.setId(getId());
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "showOpenEditors"): Show a list of open (and recently closed) editors.
+	 * This action maintains its enablement state.
+	 */
+    public static final ActionFactory SHOW_OPEN_EDITORS = new ActionFactory(
+            "showOpenEditors") {//$NON-NLS-1$
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            WorkbenchCommandAction action = new WorkbenchCommandAction("org.eclipse.ui.window.switchToEditor", window); //$NON-NLS-1$
+            action.setId(getId());
+            action.setText(WorkbenchMessages.get().WorkbenchEditorsAction_label);
+            // @issue missing action id
+            window.getWorkbench().getHelpSystem().setHelp(action,
+    				IWorkbenchHelpContextIds.WORKBENCH_EDITORS_ACTION);
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "showWorkbookEditors"): Shows a list of open editors in the current or
+	 * last active workbook.
+	 */
+    public static final ActionFactory SHOW_WORKBOOK_EDITORS = new ActionFactory(
+            "showWorkBookEditors") {//$NON-NLS-1$
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+
+            WorkbenchCommandAction action = new WorkbenchCommandAction("org.eclipse.ui.window.openEditorDropDown", window); //$NON-NLS-1$
+            action.setId(getId());
+            action.setText(WorkbenchMessages.get().WorkbookEditorsAction_label);
+
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "showQuickAccess"): Shows a list of UI elements like editors, views,
+	 * perspectives etc.
+	 *
+	 * @since 3.3
+	 */
+	public static final ActionFactory SHOW_QUICK_ACCESS = new ActionFactory(
+			"showQuickAccess") { //$NON-NLS-1$
+
+		@Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+			WorkbenchCommandAction action = new WorkbenchCommandAction("org.eclipse.ui.window.quickAccess", window); //$NON-NLS-1$
+			action.setId(getId());
+			action.setText(WorkbenchMessages.get().QuickAccessAction_text);
+			action.setToolTipText(WorkbenchMessages.get().QuickAccessAction_toolTip);
+			return action;
+		}
+
+	};
+
+	/**
+	 * Workbench action (id: "showPartPaneMenu"): Show the part pane menu. This action maintains its
+	 * enablement state.
+	 */
+    public static final ActionFactory SHOW_PART_PANE_MENU = new ActionFactory(
+            "showPartPaneMenu") {//$NON-NLS-1$
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            WorkbenchCommandAction action=new WorkbenchCommandAction("org.eclipse.ui.window.showSystemMenu",window); //$NON-NLS-1$
+            action.setId(getId());
+            action.setText(WorkbenchMessages.get().ShowPartPaneMenuAction_text);
+            action.setToolTipText(WorkbenchMessages.get().ShowPartPaneMenuAction_toolTip);
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "showViewMenu", commandId: "org.eclipse.ui.window.showViewMenu"): Show
+	 * the view menu. This action maintains its enablement state.
+	 */
+    public static final ActionFactory SHOW_VIEW_MENU = new ActionFactory(
+            "showViewMenu", IWorkbenchCommandConstants.WINDOW_SHOW_VIEW_MENU) {//$NON-NLS-1$
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+			WorkbenchCommandAction action = new WorkbenchCommandAction(
+					getCommandId(), window);
+            action.setId(getId());
+            action.setText(WorkbenchMessages.get().ShowViewMenuAction_text);
+            action.setToolTipText(WorkbenchMessages.get().ShowViewMenuAction_toolTip);
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "undo", commandId: "org.eclipse.ui.edit.undo"): Undo. This action is a
+	 * {@link RetargetAction} with id "undo". This action maintains its enablement state.
+	 */
+    public static final ActionFactory UNDO = new ActionFactory("undo", //$NON-NLS-1$
+    		IWorkbenchCommandConstants.EDIT_UNDO) {
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            LabelRetargetAction action = new LabelRetargetAction(getId(),WorkbenchMessages.get().Workbench_undo);
+            action.setToolTipText(WorkbenchMessages.get().Workbench_undoToolTip);
+            window.getPartService().addPartListener(action);
+            action.setActionDefinitionId(getCommandId());
+            ISharedImages sharedImages = window.getWorkbench()
+                    .getSharedImages();
+            action.setImageDescriptor(sharedImages
+                    .getImageDescriptor(ISharedImages.IMG_TOOL_UNDO));
+            action.setDisabledImageDescriptor(sharedImages
+                    .getImageDescriptor(ISharedImages.IMG_TOOL_UNDO_DISABLED));
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "up", commandId: "org.eclipse.ui.navigate.up"): Up. This action is a
+	 * {@link RetargetAction} with id "up". This action maintains its enablement state.
+	 */
+    public static final ActionFactory UP = new ActionFactory("up", //$NON-NLS-1$
+    		IWorkbenchCommandConstants.NAVIGATE_UP) {
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            RetargetAction action = new LabelRetargetAction(getId(),WorkbenchMessages.get().Workbench_up);
+            action.setToolTipText(WorkbenchMessages.get().Workbench_upToolTip);
+            window.getPartService().addPartListener(action);
+            action.setActionDefinitionId(getCommandId());
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "helpContents", commandId: "org.eclipse.ui.help.helpContents"): Open
+	 * the help contents. This action is always enabled.
+	 */
+    public static final ActionFactory HELP_CONTENTS = new ActionFactory(
+            "helpContents", IWorkbenchCommandConstants.HELP_HELP_CONTENTS) {//$NON-NLS-1$
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            IWorkbenchAction action = new HelpContentsAction(window);
+            action.setId(getId());
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "helpSearch", commandId: "org.eclipse.ui.help.helpSearch"): Open the
+	 * help search. This action is always enabled.
+	 *
+	 * @since 3.1
+	 */
+    public static final ActionFactory HELP_SEARCH = new ActionFactory(
+            "helpSearch", IWorkbenchCommandConstants.HELP_HELP_SEARCH) {//$NON-NLS-1$
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            IWorkbenchAction action = new HelpSearchAction(window);
+            action.setId(getId());
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "dynamicHelp", commandId: "org.eclipse.ui.help.dynamicHelp"): Open the
+	 * dynamic help. This action is always enabled.
+	 *
+	 * @since 3.1
+	 */
+    public static final ActionFactory DYNAMIC_HELP = new ActionFactory(
+            "dynamicHelp", IWorkbenchCommandConstants.HELP_DYNAMIC_HELP) {//$NON-NLS-1$
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            IWorkbenchAction action = new DynamicHelpAction(window);
+            action.setId(getId());
+            return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "openPerspectiveDialog", commandId: "org.eclipse.ui.perspectives.showPerspective"):
+	 * Open the Open Perspective dialog. This action is always enabled.
+	 *
+	 * @since 3.1
+	 */
+    public static final ActionFactory OPEN_PERSPECTIVE_DIALOG = new ActionFactory(
+            "openPerspectiveDialog", IWorkbenchCommandConstants.PERSPECTIVES_SHOW_PERSPECTIVE) {//$NON-NLS-1$
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+			if (window == null) {
+				throw new IllegalArgumentException();
+			}
+
+			WorkbenchCommandAction action = new WorkbenchCommandAction(
+					getCommandId(), window);
+			action.setId(getId());
+	        action.setText(WorkbenchMessages.get().OpenPerspectiveDialogAction_text);
+	        action.setToolTipText(WorkbenchMessages.get().OpenPerspectiveDialogAction_tooltip);
+	        action.setImageDescriptor(WorkbenchImages.getImageDescriptor(
+	              IWorkbenchGraphicConstants.IMG_ETOOL_NEW_PAGE));
+
+			return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "newEditor", commandId: "org.eclipse.ui.window.newEditor"): Open a new
+	 * editor on the active editor's input. This action maintains its enablement state.
+	 *
+	 * @since 3.1
+	 */
+    public static final ActionFactory NEW_EDITOR = new ActionFactory(
+            "newEditor", IWorkbenchCommandConstants.WINDOW_NEW_EDITOR) {//$NON-NLS-1$
+
+        @Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+
+			WorkbenchCommandAction action = new WorkbenchCommandAction(
+					getCommandId(), window);
+			action.setId(getId());
+			action.setText(WorkbenchMessages.get().NewEditorAction_text);
+			action.setToolTipText(WorkbenchMessages.get().NewEditorAction_tooltip);
+
+			return action;
+        }
+    };
+
+	/**
+	 * Workbench action (id: "toggleCoolbar"): Toggle the visibility of the coolbar and perspective
+	 * switcher. This will only enable visibility of the coolbar and perspective bar if the window
+	 * advisor creating the window allowed for their visibility initially.
+	 *
+	 * @since 3.3
+	 */
+	public static final ActionFactory TOGGLE_COOLBAR = new ActionFactory(
+			"toggleCoolbar") { //$NON-NLS-1$
+
+		@Override
+		public IWorkbenchAction create(IWorkbenchWindow window) {
+			if (window == null) {
+				throw new IllegalArgumentException();
+			}
+			WorkbenchCommandAction action = new WorkbenchCommandAction(
+					"org.eclipse.ui.ToggleCoolbarAction", window); //$NON-NLS-1$
+			action.setId(getId());
+			// set the default text - this will be updated by the handler
+			action.setText(WorkbenchMessages.get().ToggleCoolbarVisibilityAction_hide_text);
+			action.setToolTipText(WorkbenchMessages.get().ToggleCoolbarVisibilityAction_toolTip);
+			return action;
+		}
+	};
+
+    /**
+	 * Establishes bi-direction connections between the forward and backward
+	 * actions of a cycle pair.
+	 * <p>
+	 * Example usage:
+	 *
+	 * <pre>
+	 * ActionFactory.IWorkbenchAction nextEditorAction = ActionFactory.NEXT_EDITOR
+	 * 		.create(window);
+	 * ActionFactory.IWorkbenchAction previousEditorAction = ActionFactory.PREVIOUS_EDITOR
+	 * 		.create(window);
+	 * ActionFactory.linkCycleActionPair(nextEditorAction, previousEditorAction);
+	 * </pre>
+	 *
+	 * </p>
+	 *
+	 * @param next
+	 *            the action that moves forward
+	 * @param previous
+	 *            the action that moves backward
+	 */
+    public static void linkCycleActionPair(IWorkbenchAction next,
+            IWorkbenchAction previous) {
+    }
+
+    /**
+     * Id of actions created by this action factory.
+     */
+    private final String actionId;
+
+    /**
+     * Optional ID for this action.
+     */
+    private final String commandId;
+
+    /**
+     * Creates a new workbench action factory with the given id.
+     *
+     * @param actionId
+     *            the id of actions created by this action factory
+     */
+    protected ActionFactory(String actionId) {
+    	this(actionId, null);
+    }
+
+	/**
+	 * Create a new workbench action factory with the given IDs.
+	 *
+	 * @param actionId
+	 *            the id of actions created by this action factory
+	 * @param commandId
+	 *            the matching command id
+	 * @since 3.5
+	 */
+    protected ActionFactory(String actionId, String commandId) {
+    	this.actionId = actionId;
+    	this.commandId = commandId;
+    }
+
+    /**
+     * Creates a new standard action for the given workbench window. The action
+     * has an id as specified by the particular factory.
+     * <p>
+     * Actions automatically register listeners against the workbench window so
+     * that they can keep their enablement state up to date. Ordinarily, the
+     * window's references to these listeners will be dropped automatically
+     * when the window closes. However, if the client needs to get rid of an
+     * action while the window is still open, the client must call
+     * {@link IWorkbenchAction#dispose dispose}to give the action an
+     * opportunity to deregister its listeners and to perform any other
+     * cleanup.
+     * </p>
+     *
+     * @param window
+     *            the workbench window
+     * @return the workbench action
+     */
+    public abstract IWorkbenchAction create(IWorkbenchWindow window);
+
+    /**
+     * Returns the id of this action factory.
+     *
+     * @return the id of actions created by this action factory
+     */
+    public String getId() {
+        return actionId;
+    }
+
+	/**
+	 * Return the command id of this action factory.
+	 *
+	 * @return the command id of the action created by this action factory. May
+	 *         be <code>null</code>.
+	 * @since 3.5
+	 */
+    public String getCommandId() {
+    	return commandId;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/ActionGroup.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/ActionGroup.java
new file mode 100644
index 0000000..2add3da
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/ActionGroup.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.actions;
+
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.ui.IActionBars;
+
+/**
+ * An <code>ActionGroup</code> represents a group of actions
+ * which are added to a context menu, or the action bars of a part, together.
+ * The group is given a context which can be used to determine which actions
+ * are added, and what their enabled state should be.
+ * <p>
+ * This class is intended only as a convenience for managing groups of actions.
+ * Clients are not required to use this class in order to add actions to context
+ * menus or action bars.
+ * </p>
+ * <p>
+ * Clients should subclass this class and extend or override the appropriate fill methods.
+ * </p>
+ *
+ * @since 2.0
+ */
+public abstract class ActionGroup {
+
+    /**
+     * The action context, used to determine which actions are added,
+     * and what their enabled state should be.
+     */
+    private ActionContext context;
+
+    /**
+     * Returns the context used to determine which actions are added,
+     * and what their enabled state should be.
+     */
+    public ActionContext getContext() {
+        return context;
+    }
+
+    /**
+     * Sets the context used to determine which actions are added,
+     * and what their enabled state should be.
+     *
+     * @param context the context to use
+     */
+    public void setContext(ActionContext context) {
+        this.context = context;
+    }
+
+    /**
+     * Adds the applicable actions to a context menu,
+     * based on the state of the <code>ActionContext</code>.
+     * <p>
+     * The default implementation does nothing.
+     * Subclasses may override or extend this method.
+     * </p>
+     *
+     * @param menu the context menu manager
+     */
+    public void fillContextMenu(IMenuManager menu) {
+        // do nothing
+    }
+
+    /**
+     * Adds the applicable actions to a part's action bars,
+     * including setting any global action handlers.
+     * <p>
+     * The default implementation does nothing.
+     * Subclasses may override or extend this method.
+     * </p>
+     *
+     * @param actionBars the part's action bars
+     */
+    public void fillActionBars(IActionBars actionBars) {
+        // do nothing
+    }
+
+    /**
+     * Updates the state of the actions added to the action bars,
+     * including any global action handlers,
+     * based on the state of the <code>ActionContext</code>.
+     * <p>
+     * The default implementation does nothing.
+     * Subclasses may override or extend this method.
+     * </p>
+     */
+    public void updateActionBars() {
+        // do nothing
+    }
+
+    /**
+     * This method is called by the user of an action group to signal that the group is
+     * no longer needed. Subclasses typically implement this method to deregister
+     * any listeners or to free other resources.
+     * <p>
+     * The default implementation calls <code>setContext(null)</code>.
+     * Subclasses may extend this method.
+     * </p>
+     */
+    public void dispose() {
+        setContext(null);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/BaseNewWizardMenu.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/BaseNewWizardMenu.java
new file mode 100644
index 0000000..f453317
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/BaseNewWizardMenu.java
@@ -0,0 +1,259 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Andreas Buchen <andreas.buchen@sap.com> - Bug 206584
+ *******************************************************************************/
+package org.eclipse.ui.actions;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IRegistryChangeListener;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.ActionContributionItem;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.activities.WorkbenchActivityHelper;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.WorkbenchWindow;
+import org.eclipse.ui.internal.actions.NewWizardShortcutAction;
+import org.eclipse.ui.wizards.IWizardDescriptor;
+
+/**
+ * A <code>BaseNewWizardMenu</code> is used to populate a menu manager with
+ * New Wizard actions for the current perspective's new wizard shortcuts,
+ * including an Other... action to open the new wizard dialog.
+ * <p>
+ * <strong>Note:</strong> Clients must dispose this menu when it is no longer required.
+ * </p>
+ *
+ * @since 3.1
+ */
+public class BaseNewWizardMenu extends CompoundContributionItem {
+    /*
+     * @issue Should be possible to implement this class entirely using public
+     * API. Cases to be fixed: WorkbenchWindow, NewWizardShortcutAction
+     *  Suggestions:
+     * - add the ability to update the submenus of a window
+     */
+
+    private final Map actions = new HashMap(21);
+
+    private final IExtensionChangeHandler configListener = new IExtensionChangeHandler() {
+
+        @Override
+		public void removeExtension(IExtension source, Object[] objects) {
+            for (Object object : objects) {
+                if (object instanceof NewWizardShortcutAction) {
+                    actions.values().remove(object);
+                }
+            }
+        }
+
+        @Override
+		public void addExtension(IExtensionTracker tracker, IExtension extension) {
+            // Do nothing
+        }
+    };
+
+    /**
+     * TODO: should this be done with an addition listener?
+     */
+    private final IRegistryChangeListener registryListener = event -> {
+	    // reset the reader.
+	    // TODO This is expensive.  Can we be more selective?
+	    if (getParent() != null) {
+	        getParent().markDirty();
+	    }
+	};
+
+    private ActionFactory.IWorkbenchAction showDlgAction;
+
+    private IWorkbenchWindow workbenchWindow;
+
+    /**
+     * Creates a new wizard shortcut menu for the IDE.
+     * <p>
+     * <strong>Note:</strong> Clients must dispose this menu when it is no longer required.
+     * </p>
+     *
+     * @param window
+     *            the window containing the menu
+     * @param id
+     *            the contribution item identifier, or <code>null</code>
+     */
+    public BaseNewWizardMenu(IWorkbenchWindow window, String id) {
+        super(id);
+        Assert.isNotNull(window);
+        this.workbenchWindow = window;
+        showDlgAction = ActionFactory.NEW.create(window);
+        registerListeners();
+        // indicate that a new wizards submenu has been created
+		if (window instanceof WorkbenchWindow) {
+			((WorkbenchWindow) window)
+					.addSubmenu(WorkbenchWindow.NEW_WIZARD_SUBMENU);
+		}
+    }
+
+    /**
+     * Adds the items to show to the given list.
+     *
+     * @param list the list to add items to
+     */
+    protected void addItems(List list) {
+        if (addShortcuts(list)) {
+            list.add(new Separator());
+        }
+        list.add(new ActionContributionItem(getShowDialogAction()));
+    }
+
+    /**
+     * Adds the new wizard shortcuts for the current perspective to the given list.
+     *
+     * @param list the list to add items to
+     * @return <code>true</code> if any items were added, <code>false</code> if none were added
+     */
+    protected boolean addShortcuts(List list) {
+        boolean added = false;
+        IWorkbenchPage page = workbenchWindow.getActivePage();
+        if (page != null) {
+            String[] wizardIds = page.getNewWizardShortcuts();
+            for (String wizardId : wizardIds) {
+                IAction action = getAction(wizardId);
+                if (action != null) {
+                    if (!WorkbenchActivityHelper.filterItem(action)) {
+                        list.add(new ActionContributionItem(action));
+                        added = true;
+                    }
+                }
+            }
+        }
+        return added;
+    }
+
+    @Override
+	public void dispose() {
+        if (workbenchWindow != null) {
+            super.dispose();
+            unregisterListeners();
+            showDlgAction.dispose();
+            showDlgAction = null;
+            workbenchWindow = null;
+        }
+    }
+
+	/*
+	 * Returns the action for the given wizard id, or null if not found.
+	 */
+    private IAction getAction(String id) {
+        // Keep a cache, rather than creating a new action each time,
+        // so that image caching in ActionContributionItem works.
+        IAction action = (IAction) actions.get(id);
+        if (action == null) {
+            IWizardDescriptor wizardDesc = WorkbenchPlugin.getDefault()
+					.getNewWizardRegistry().findWizard(id);
+            if (wizardDesc != null) {
+                action = new NewWizardShortcutAction(workbenchWindow,
+						wizardDesc);
+				actions.put(id, action);
+				IConfigurationElement element = Adapters.adapt(wizardDesc, IConfigurationElement.class);
+				if (element != null) {
+					workbenchWindow.getExtensionTracker().registerObject(
+							element.getDeclaringExtension(), action,
+							IExtensionTracker.REF_WEAK);
+				}
+            }
+        }
+        return action;
+    }
+
+    @Override
+	protected IContributionItem[] getContributionItems() {
+        ArrayList list = new ArrayList();
+        if (workbenchWindow != null && workbenchWindow.getActivePage() != null
+                && workbenchWindow.getActivePage().getPerspective() != null) {
+            addItems(list);
+        } else {
+            String text = WorkbenchMessages.get().Workbench_noApplicableItems;
+            Action dummyAction = new Action(text) {
+                // dummy inner class; no methods
+            };
+            dummyAction.setEnabled(false);
+            list.add(new ActionContributionItem(dummyAction));
+        }
+        return (IContributionItem[]) list.toArray(new IContributionItem[list.size()]);
+    }
+
+    /**
+     * Returns the "Other..." action, used to show the new wizards dialog.
+     *
+     * @return the action used to show the new wizards dialog
+     */
+    protected IAction getShowDialogAction() {
+        return showDlgAction;
+    }
+
+    /**
+     * Returns the window in which this menu appears.
+     *
+     * @return the window in which this menu appears
+     */
+    protected IWorkbenchWindow getWindow() {
+        return workbenchWindow;
+    }
+
+    /**
+     * Registers listeners.
+     *
+     * @since 3.1
+     */
+    private void registerListeners() {
+        Platform.getExtensionRegistry().addRegistryChangeListener(
+                registryListener);
+        workbenchWindow.getExtensionTracker().registerHandler(
+				configListener,  null);
+    }
+
+    /**
+     * Returns whether the new wizards registry has a non-empty category with
+     * the given identifier.
+     *
+     * @param categoryId
+     *            the identifier for the category
+     * @return <code>true</code> if there is a non-empty category with the
+     *         given identifier, <code>false</code> otherwise
+     */
+    protected boolean registryHasCategory(String categoryId) {
+    	return WorkbenchPlugin.getDefault().getNewWizardRegistry()
+				.findCategory(categoryId) != null;
+    }
+
+    /**
+     * Unregisters listeners.
+     *
+     * @since 3.1
+     */
+    private void unregisterListeners() {
+        Platform.getExtensionRegistry().removeRegistryChangeListener(
+                registryListener);
+        workbenchWindow.getExtensionTracker().unregisterHandler(configListener);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/BaseSelectionListenerAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/BaseSelectionListenerAction.java
new file mode 100644
index 0000000..1161176
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/BaseSelectionListenerAction.java
@@ -0,0 +1,177 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.actions;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.widgets.Event;
+
+/**
+ * The abstract superclass for actions that listen to selection change events.
+ * This implementation tracks the current selection (see
+ * <code>getStructuredSelection</code>) and provides a convenient place to
+ * monitor selection changes that could affect the availability of the action.
+ * <p>
+ * Subclasses must implement the following <code>IAction</code> method:
+ * <ul>
+ *   <li><code>run</code> - to do the action's work</li>
+ * </ul>
+ * </p>
+ * <p>
+ * Subclasses may extend the <code>updateSelection</code> method to update
+ * the action determine its availability based on the current selection.
+ * </p>
+ * <p>
+ * The object instantiating the subclass is responsible for registering
+ * the instance with a selection provider. Alternatively, the object can
+ * notify the subclass instance directly of a selection change using the
+ * methods:
+ * <ul>
+ *   <li><code>selectionChanged(IStructuredSelection)</code> - passing the selection</li>
+ *   <li><code>selectionChanged(ISelectionChangedEvent)</code> - passing the selection change event</li>
+ * </ul>
+ * </p>
+ * @since 3.0
+ */
+public abstract class BaseSelectionListenerAction extends Action implements
+        ISelectionChangedListener {
+    /**
+     * The current selection.
+     */
+    private IStructuredSelection selection = new StructuredSelection();
+
+    /**
+     * Running flag:  <code>true</code> iff the action is running.
+     */
+    private boolean running = false;
+
+    /**
+     * The deferred selection.  Any selection change that occurs
+     * while the action is running is held here until the run is complete.
+     */
+    private IStructuredSelection deferredSelection = null;
+
+    /**
+     * Creates a new action with the given text.
+     *
+     * @param text the string used as the text for the action,
+     *   or <code>null</code> if there is no text
+     */
+    protected BaseSelectionListenerAction(String text) {
+        super(text);
+    }
+
+    /**
+     * Clears any cached state associated with the selection.
+     * Called when the selection changes.
+     * <p>
+     * The <code>BaseSelectionListenerAction</code> implementation of this method
+     * does nothing. Subclasses may override.
+     * </p>
+     */
+    protected void clearCache() {
+        // do nothing
+    }
+
+    /**
+     * Returns the current structured selection in the workbench, or an empty
+     * selection if nothing is selected or if selection does not include
+     * objects (for example, raw text).
+     *
+     * @return the current structured selection in the workbench
+     */
+    public IStructuredSelection getStructuredSelection() {
+        return selection;
+    }
+
+    /**
+     * Notifies this action that the given structured selection has changed.
+     * <p>
+     * The <code>BaseSelectionListenerAction</code> implementation of this method
+     * records the given selection for future reference and calls
+     * <code>updateSelection</code>, updating the enable state of this action
+     * based on the outcome. Subclasses should override <code>updateSelection</code>
+     * to react to selection changes.
+     * </p>
+     *
+     * @param selection the new selection
+     */
+    public final void selectionChanged(IStructuredSelection selection) {
+        // Ignore any incoming selection change while the action is running,
+        // otherwise the action can have unpredictable results, including lost
+        // data, if it operates on a different selection than what it initially
+        // validated.
+        // See Bug 60606 [Navigator] (data loss) Navigator deletes/moves the wrong file
+        if (running) {
+            deferredSelection = selection;
+            return;
+        }
+        this.selection = selection;
+        clearCache();
+        setEnabled(updateSelection(selection));
+    }
+
+    /**
+     * The <code>BaseSelectionListenerAction</code> implementation of this
+     * <code>ISelectionChangedListener</code> method calls
+     * <code>selectionChanged(IStructuredSelection)</code> assuming the selection is
+     * a structured one. Subclasses should override the <code>updateSelection</code>
+     * method to react to selection changes.
+     */
+    @Override
+	public final void selectionChanged(SelectionChangedEvent event) {
+        ISelection selection = event.getSelection();
+        if (selection instanceof IStructuredSelection) {
+			selectionChanged((IStructuredSelection) selection);
+		} else {
+			selectionChanged(StructuredSelection.EMPTY);
+		}
+    }
+
+    /**
+     * Updates this action in response to the given selection.
+     * <p>
+     * The <code>BaseSelectionListenerAction</code> implementation of this method
+     * returns <code>true</code>. Subclasses may extend to react to selection
+     * changes; however, if the super method returns <code>false</code>, the
+     * overriding method must also return <code>false</code>.
+     * </p>
+     *
+     * @param selection the new selection
+     * @return <code>true</code> if the action should be enabled for this selection,
+     *   and <code>false</code> otherwise
+     */
+    protected boolean updateSelection(IStructuredSelection selection) {
+        return true;
+    }
+
+    @Override
+	public void runWithEvent(Event event) {
+        // Set the running flag during the run so that selection changes are deferred.
+        // See selectionChanged(IStructuredSelection) for more details.
+        running = true;
+        try {
+            run();
+        } finally {
+            running = false;
+            IStructuredSelection s = deferredSelection;
+            deferredSelection = null;
+            if (s != null) {
+                selectionChanged(s);
+            }
+        }
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/CommandNotMappedException.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/CommandNotMappedException.java
new file mode 100644
index 0000000..c4067dd
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/CommandNotMappedException.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.actions;
+
+import org.eclipse.core.commands.common.CommandException;
+
+/**
+ * Indicates that an action has no command mapping. The declaration can be
+ * updated to include a definitionId.
+ *
+ * @since 3.3
+ */
+public class CommandNotMappedException extends CommandException {
+
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * @param message
+	 */
+	public CommandNotMappedException(String message) {
+		super(message);
+	}
+
+	/**
+	 * @param message
+	 * @param cause
+	 */
+	public CommandNotMappedException(String message, Throwable cause) {
+		super(message, cause);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/CompoundContributionItem.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/CompoundContributionItem.java
new file mode 100644
index 0000000..33b11f8
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/CompoundContributionItem.java
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.actions;
+
+import org.eclipse.jface.action.ContributionItem;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.IContributionManager;
+import org.eclipse.jface.action.IMenuListener;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.swt.widgets.Menu;
+
+/**
+ * A compound contribution is a contribution item consisting of a
+ * dynamic list of contribution items.
+ *
+ * @since 3.1
+ */
+public abstract class CompoundContributionItem extends ContributionItem {
+
+    private IMenuListener menuListener = manager -> manager.markDirty();
+
+    private IContributionItem[] oldItems;
+
+    /**
+     * Creates a compound contribution item with a <code>null</code> id.
+     */
+    protected CompoundContributionItem() {
+        super();
+    }
+
+    /**
+     * Creates a compound contribution item with the given (optional) id.
+     *
+     * @param id the contribution item identifier, or <code>null</code>
+     */
+    protected CompoundContributionItem(String id) {
+        super(id);
+    }
+
+    @Override
+	public void fill(Menu menu, int index) {
+        if (index == -1) {
+			index = menu.getItemCount();
+		}
+
+        IContributionItem[] items = getContributionItemsToFill();
+		if (index > menu.getItemCount()) {
+			index = menu.getItemCount();
+		}
+        for (IContributionItem item : items) {
+            int oldItemCount = menu.getItemCount();
+            if (item.isVisible()) {
+                item.fill(menu, index);
+            }
+            int newItemCount = menu.getItemCount();
+            int numAdded = newItemCount - oldItemCount;
+            index += numAdded;
+        }
+    }
+
+    /**
+	 * Return a list of contributions items that will replace this item in the
+	 * parent manager. The list must contain new contribution items every call
+	 * since the old ones will be disposed.
+	 *
+	 * @return an array list of items to display. Must not be <code>null</code>.
+	 */
+    protected abstract IContributionItem[] getContributionItems();
+
+    private IContributionItem[] getContributionItemsToFill() {
+		disposeOldItems();
+		oldItems = getContributionItems();
+		return oldItems;
+	}
+
+	private void disposeOldItems() {
+        if (oldItems != null) {
+            for (IContributionItem oldItem : oldItems) {
+                oldItem.dispose();
+            }
+            oldItems = null;
+        }
+    }
+
+    @Override
+	public boolean isDirty() {
+		return true;
+    }
+
+    @Override
+	public boolean isDynamic() {
+        return true;
+    }
+
+
+    @Override
+	public void setParent(IContributionManager parent) {
+        if (getParent() instanceof IMenuManager) {
+            IMenuManager menuMgr = (IMenuManager) getParent();
+            menuMgr.removeMenuListener(menuListener);
+        }
+        if (parent instanceof IMenuManager) {
+            IMenuManager menuMgr = (IMenuManager) parent;
+            menuMgr.addMenuListener(menuListener);
+        }
+        super.setParent(parent);
+    }
+
+	@Override
+	public void dispose() {
+		disposeOldItems();
+		super.dispose();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/ContributedAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/ContributedAction.java
new file mode 100644
index 0000000..fef787c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/ContributedAction.java
@@ -0,0 +1,278 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *******************************************************************************/
+
+package org.eclipse.ui.actions;
+
+import java.util.Collections;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.core.commands.IHandler2;
+import org.eclipse.core.commands.NotEnabledException;
+import org.eclipse.core.commands.NotHandledException;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.core.expressions.EvaluationContext;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.e4.core.commands.EHandlerService;
+import org.eclipse.e4.core.commands.internal.HandlerServiceImpl;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.IPartListener;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.internal.actions.CommandAction;
+import org.eclipse.ui.internal.handlers.ActionDelegateHandlerProxy;
+import org.eclipse.ui.internal.handlers.E4HandlerProxy;
+import org.eclipse.ui.internal.handlers.IActionCommandMappingService;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.services.IWorkbenchLocationService;
+import org.eclipse.ui.part.MultiPageEditorSite;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * For a declarative editor action, see if we can link it to a command.
+ * <p>
+ * This is a legacy bridge class, and should not be used outside of the Eclipse
+ * SDK. Please use menu contributions to display a command in a menu or toolbar.
+ * </p>
+ * <p>
+ * <b>Note:</b> Clients may instantiate.
+ * </p>
+ *
+ * @since 3.3
+ */
+public final class ContributedAction extends CommandAction {
+	private IEvaluationContext appContext;
+
+	private IHandler partHandler;
+
+	private boolean localHandler = false;
+
+	private IPartListener partListener;
+
+	/**
+	 * Create an action that can call a command.
+	 *
+	 * @param locator
+	 *            The appropriate service locator to use. If you use a part site
+	 *            as your locator, this action will be tied to your part.
+	 * @param element
+	 *            the contributed action element
+	 */
+	public ContributedAction(IServiceLocator locator,
+			IConfigurationElement element) throws CommandNotMappedException {
+
+		String actionId = element
+				.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+		String commandId = element
+				.getAttribute(IWorkbenchRegistryConstants.ATT_DEFINITION_ID);
+
+		// TODO throw some more exceptions here :-)
+
+		String contributionId = null;
+		if (commandId == null) {
+
+			Object obj = element.getParent();
+			if (obj instanceof IConfigurationElement) {
+				contributionId = ((IConfigurationElement) obj)
+						.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+				if (contributionId == null) {
+					throw new CommandNotMappedException("Action " //$NON-NLS-1$
+							+ actionId + " configuration element invalid"); //$NON-NLS-1$
+				}
+			}
+			// legacy bridge part
+			IActionCommandMappingService mapping = locator
+					.getService(IActionCommandMappingService.class);
+			if (mapping == null) {
+				throw new CommandNotMappedException(
+						"No action mapping service available"); //$NON-NLS-1$
+			}
+
+			commandId = mapping.getCommandId(mapping.getGeneratedCommandId(
+					contributionId, actionId));
+		}
+		// what, still no command?
+		if (commandId == null) {
+			throw new CommandNotMappedException("Action " + actionId //$NON-NLS-1$
+					+ " in contribution " + contributionId //$NON-NLS-1$
+					+ " not mapped to a command"); //$NON-NLS-1$
+		}
+
+		init(locator, commandId, null);
+
+		if (locator instanceof IWorkbenchPartSite) {
+			updateSiteAssociations((IWorkbenchPartSite) locator, commandId,
+					actionId, element);
+		}
+
+		setId(actionId);
+	}
+
+	private void updateSiteAssociations(IWorkbenchPartSite site,
+			String commandId, String actionId, IConfigurationElement element) {
+		IWorkbenchLocationService wls = site
+				.getService(IWorkbenchLocationService.class);
+		IWorkbench workbench = wls.getWorkbench();
+		IWorkbenchWindow window = wls.getWorkbenchWindow();
+		IHandlerService serv = workbench
+				.getService(IHandlerService.class);
+		appContext = new EvaluationContext(serv.getCurrentState(),
+				Collections.EMPTY_LIST);
+
+		// set up the appContext as we would want it.
+		appContext.addVariable(ISources.ACTIVE_CURRENT_SELECTION_NAME,
+				StructuredSelection.EMPTY);
+		appContext.addVariable(ISources.ACTIVE_PART_NAME, site.getPart());
+		appContext.addVariable(ISources.ACTIVE_PART_ID_NAME, site.getId());
+		appContext.addVariable(ISources.ACTIVE_SITE_NAME, site);
+		if (site instanceof IEditorSite) {
+			appContext.addVariable(ISources.ACTIVE_EDITOR_NAME, site.getPart());
+			appContext
+					.addVariable(ISources.ACTIVE_EDITOR_ID_NAME, site.getId());
+		}
+		appContext.addVariable(ISources.ACTIVE_WORKBENCH_WINDOW_NAME, window);
+		appContext.addVariable(ISources.ACTIVE_WORKBENCH_WINDOW_SHELL_NAME,
+				window.getShell());
+
+		partHandler = lookUpHandler(site, commandId);
+		if (partHandler == null) {
+			localHandler = true;
+			// if we can't find the handler, then at least we can
+			// call the action delegate run method
+			partHandler = new ActionDelegateHandlerProxy(element,
+					IWorkbenchRegistryConstants.ATT_CLASS, actionId,
+					getParameterizedCommand(), site.getWorkbenchWindow(), null,
+					null, null);
+		}
+		if (site instanceof MultiPageEditorSite) {
+			IHandlerService siteServ = site
+					.getService(IHandlerService.class);
+			siteServ.activateHandler(commandId, partHandler);
+		}
+
+		if (getParameterizedCommand() != null) {
+			getParameterizedCommand().getCommand().removeCommandListener(
+					getCommandListener());
+		}
+		site.getPage().addPartListener(getPartListener());
+	}
+
+	private IHandler lookUpHandler(IServiceLocator site, String commandId) {
+		HandlerServiceImpl impl = (HandlerServiceImpl) site.getService(EHandlerService.class);
+		IEclipseContext c = impl.getContext();
+		Object h = HandlerServiceImpl.lookUpHandler(c, commandId);
+		if (h instanceof E4HandlerProxy) {
+			return ((E4HandlerProxy) h).getHandler();
+		}
+		return null;
+	}
+
+	@Override
+	public void runWithEvent(Event event) {
+		if (partHandler != null && getParameterizedCommand() != null) {
+			IHandler oldHandler = getParameterizedCommand().getCommand()
+					.getHandler();
+			try {
+				getParameterizedCommand().getCommand().setHandler(partHandler);
+				getParameterizedCommand().executeWithChecks(event, appContext);
+			} catch (ExecutionException e) {
+				// TODO some logging, perhaps?
+			} catch (NotDefinedException e) {
+				// TODO some logging, perhaps?
+			} catch (NotEnabledException e) {
+				// TODO some logging, perhaps?
+			} catch (NotHandledException e) {
+				// TODO some logging, perhaps?
+			} finally {
+				getParameterizedCommand().getCommand().setHandler(oldHandler);
+			}
+		} else {
+			super.runWithEvent(event);
+		}
+	}
+
+	@Override
+	public boolean isEnabled() {
+		if (partHandler != null) {
+			if (partHandler instanceof IHandler2) {
+				((IHandler2) partHandler).setEnabled(appContext);
+			}
+			return partHandler.isEnabled();
+		}
+		return false;
+	}
+
+	private IPartListener getPartListener() {
+		if (partListener == null) {
+			final IWorkbenchPartSite site = (IWorkbenchPartSite) appContext
+					.getVariable(ISources.ACTIVE_SITE_NAME);
+
+			final IWorkbenchPart currentPart;
+			if (site instanceof MultiPageEditorSite) {
+				currentPart = ((MultiPageEditorSite) site).getMultiPageEditor();
+			} else {
+				currentPart = site.getPart();
+			}
+
+			partListener = new IPartListener() {
+				@Override
+				public void partActivated(IWorkbenchPart part) {
+				}
+
+				@Override
+				public void partBroughtToTop(IWorkbenchPart part) {
+				}
+
+				@Override
+				public void partClosed(IWorkbenchPart part) {
+					if (part == currentPart) {
+						ContributedAction.this.disposeAction();
+					}
+				}
+
+				@Override
+				public void partDeactivated(IWorkbenchPart part) {
+				}
+
+				@Override
+				public void partOpened(IWorkbenchPart part) {
+				}
+			};
+		}
+		return partListener;
+	}
+
+	// TODO make public in 3.4
+	private void disposeAction() {
+		if (appContext != null) {
+			if (localHandler) {
+				partHandler.dispose();
+			}
+			if (partListener != null) {
+				IWorkbenchPartSite site = (IWorkbenchPartSite) appContext
+						.getVariable(ISources.ACTIVE_SITE_NAME);
+				site.getPage().removePartListener(partListener);
+				partListener = null;
+			}
+			appContext = null;
+			partHandler = null;
+		}
+		dispose();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/ContributionItemFactory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/ContributionItemFactory.java
new file mode 100644
index 0000000..6585ed5
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/ContributionItemFactory.java
@@ -0,0 +1,262 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *     Andrey Loskutov <loskutov@gmx.de> - Bug 445538
+ *******************************************************************************/
+package org.eclipse.ui.actions;
+
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.internal.ChangeToPerspectiveMenu;
+import org.eclipse.ui.internal.IPreferenceConstants;
+import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
+import org.eclipse.ui.internal.ReopenEditorMenu;
+import org.eclipse.ui.internal.ShowInMenu;
+import org.eclipse.ui.internal.ShowViewMenu;
+import org.eclipse.ui.internal.SwitchToWindowMenu;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.actions.HelpSearchContributionItem;
+import org.eclipse.ui.menus.CommandContributionItem;
+import org.eclipse.ui.menus.CommandContributionItemParameter;
+
+/**
+ * Access to standard contribution items provided by the workbench.
+ * <p>
+ * Most of the functionality of this class is provided by
+ * static methods and fields.
+ * Example usage:
+ * <pre>
+ * MenuManager menu = ...;
+ * IContributionItem reEdit
+ * 	  = ContributionItemFactory.REOPEN_EDITORS.create(window);
+ * menu.add(reEdit);
+ * </pre>
+ * </p>
+ * <p>
+ * Clients may declare subclasses that provide additional application-specific
+ * contribution item factories.
+ * </p>
+ *
+ * @since 3.0
+ */
+public abstract class ContributionItemFactory {
+
+    /**
+     * Id of contribution items created by this factory.
+     */
+    private final String contributionItemId;
+
+    /**
+     * Creates a new workbench contribution item factory with the given id.
+     *
+     * @param contributionItemId the id of contribution items created by this factory
+     */
+    protected ContributionItemFactory(String contributionItemId) {
+        this.contributionItemId = contributionItemId;
+    }
+
+    /**
+     * Creates a new standard contribution item for the given workbench window.
+     * <p>
+     * A typical contribution item automatically registers listeners against the
+     * workbench window so that it can keep its enablement state up to date.
+     * Ordinarily, the window's references to these listeners will be dropped
+     * automatically when the window closes. However, if the client needs to get
+     * rid of a contribution item while the window is still open, the client must
+     * call IContributionItem#dispose to give the item an
+     * opportunity to deregister its listeners and to perform any other cleanup.
+     * </p>
+     *
+     * @param window the workbench window
+     * @return the workbench contribution item
+     */
+    public abstract IContributionItem create(IWorkbenchWindow window);
+
+    /**
+     * Returns the id of this contribution item factory.
+     *
+     * @return the id of contribution items created by this factory
+     */
+    public String getId() {
+        return contributionItemId;
+    }
+
+	/**
+	 * Workbench action (id "pinEditor"): Toggle whether the editor is pinned.
+	 * This action maintains its enablement state.
+	 */
+	public static final ContributionItemFactory PIN_EDITOR = new ContributionItemFactory(
+			"pinEditor") { //$NON-NLS-1$
+		private static final String COMMAND_ID = IWorkbenchCommandConstants.WINDOW_PIN_EDITOR;
+
+		@Override
+		public IContributionItem create(final IWorkbenchWindow window) {
+			if (window == null) {
+				throw new IllegalArgumentException();
+			}
+
+			CommandContributionItemParameter parameter = new CommandContributionItemParameter(
+					window,
+					COMMAND_ID,
+					COMMAND_ID,
+					null,
+					WorkbenchImages
+							.getImageDescriptor(IWorkbenchGraphicConstants.IMG_ETOOL_PIN_EDITOR),
+					WorkbenchImages
+							.getImageDescriptor(IWorkbenchGraphicConstants.IMG_ETOOL_PIN_EDITOR_DISABLED),
+					null, null, null, WorkbenchMessages.get().PinEditorAction_toolTip, // Local workaround for http://bugs.eclipse.org/387583
+					CommandContributionItem.STYLE_CHECK, null, false);
+			final CommandContributionItem action = new CommandContributionItem(parameter);
+			action.setVisible(WorkbenchPlugin.getDefault().getPreferenceStore()
+					.getBoolean(IPreferenceConstants.REUSE_EDITORS_BOOLEAN));
+			return action;
+		}
+	};
+
+    /**
+     * Workbench contribution item (id "openWindows"): A list of windows
+     * currently open in the workbench. Selecting one of the items makes the
+     * corresponding window the active window.
+     * This action dynamically maintains the list of windows.
+     */
+    public static final ContributionItemFactory OPEN_WINDOWS = new ContributionItemFactory(
+            "openWindows") { //$NON-NLS-1$
+
+        @Override
+		public IContributionItem create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            return new SwitchToWindowMenu(window, getId(), true);
+        }
+    };
+
+    /**
+     * Workbench contribution item (id "viewsShortlist"): A list of views
+     * available to be opened in the window, arranged as a shortlist of
+     * promising views and an "Other" subitem. Selecting
+     * one of the items opens the corresponding view in the active window.
+     * This action dynamically maintains the view shortlist.
+     */
+    public static final ContributionItemFactory VIEWS_SHORTLIST = new ContributionItemFactory(
+            "viewsShortlist") { //$NON-NLS-1$
+
+        @Override
+		public IContributionItem create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            return new ShowViewMenu(window, getId());
+        }
+    };
+
+    /**
+     * Workbench contribution item (id "viewsShowIn"): A list of views
+     * available to be opened in the window, arranged as a list of
+     * alternate views to show the same item currently selected. Selecting
+     * one of the items opens the corresponding view in the active window.
+     * This action dynamically maintains the view list.
+     */
+    public static final ContributionItemFactory VIEWS_SHOW_IN = new ContributionItemFactory(
+            "viewsShowIn") { //$NON-NLS-1$
+
+        @Override
+		public IContributionItem create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+
+            ShowInMenu showInMenu = new ShowInMenu();
+            showInMenu.setId(getId());
+            showInMenu.initialize(window);
+			return showInMenu;
+        }
+    };
+
+    /**
+     * Workbench contribution item (id "reopenEditors"): A list of recent
+     * editors (with inputs) available to be reopened in the window. Selecting
+     * one of the items reopens the corresponding editor on its input in the
+     * active window. This action dynamically maintains the list of editors.
+     */
+    public static final ContributionItemFactory REOPEN_EDITORS = new ContributionItemFactory(
+            "reopenEditors") { //$NON-NLS-1$
+
+        @Override
+		public IContributionItem create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            return new ReopenEditorMenu(window, getId(), true);
+        }
+    };
+
+    /**
+     * Workbench contribution item (id "perspectivesShortlist"): A list of
+     * perspectives available to be opened, arranged as a shortlist of
+     * promising perspectives and an "Other" subitem. Selecting
+     * one of the items makes the corresponding perspective active. Should a
+     * new perspective need to be opened, a workbench user preference controls
+     * whether the prespective is opened in the active window or a new window.
+     * This action dynamically maintains the perspectives shortlist.
+     */
+    public static final ContributionItemFactory PERSPECTIVES_SHORTLIST = new ContributionItemFactory(
+            "perspectivesShortlist") { //$NON-NLS-1$
+
+        @Override
+		public IContributionItem create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            return new ChangeToPerspectiveMenu(window, getId());
+        }
+    };
+
+    /**
+     * Workbench contribution item (id "newWizardShortlist"): A list of
+     * new item wizards available to be opened, arranged as a shortlist of
+     * promising new item wizards and an "Other" subitem. Selecting
+     * one of the items invokes the corresponding new item wizard.
+     * This action dynamically maintains the new item wizard shortlist.
+     * @since 3.1
+     */
+    public static final ContributionItemFactory NEW_WIZARD_SHORTLIST = new ContributionItemFactory(
+            "newWizardShortlist") { //$NON-NLS-1$
+
+        @Override
+		public IContributionItem create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            return new BaseNewWizardMenu(window, getId());
+        }
+    };
+
+    /**
+     * Workbench contribution item (id "helpSearch"): An editable field
+     * for entering help search queries.
+     * @since 3.1
+     */
+    public static final ContributionItemFactory HELP_SEARCH = new ContributionItemFactory(
+            "helpSearch") {//$NON-NLS-1$
+        @Override
+		public IContributionItem create(IWorkbenchWindow window) {
+            if (window == null) {
+                throw new IllegalArgumentException();
+            }
+            return new HelpSearchContributionItem(window, getId());
+        }
+    };
+
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/ExportResourcesAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/ExportResourcesAction.java
new file mode 100644
index 0000000..74d7b8e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/ExportResourcesAction.java
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.actions;
+
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchMessages;
+
+/**
+ * Action representing a generic export operation.
+ * <p>
+ * This class may be instantiated. It is not intended to be subclassed.
+ * </p>
+ * <p>
+ * This method automatically registers listeners so that it can keep its
+ * enablement state up to date. Ordinarily, the window's references to these
+ * listeners will be dropped automatically when the window closes. However,
+ * if the client needs to get rid of an action while the window is still open,
+ * the client must call IWorkbenchAction#dispose to give the
+ * action an opportunity to deregister its listeners and to perform any other
+ * cleanup.
+ * </p>
+ * <p>
+ * Note: Despite the name, an export operation can deal with things other than
+ * resources; the current name was retained for historical reasons.
+ * </p>
+ *
+ * @since 2.0
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class ExportResourcesAction extends BaseSelectionListenerAction
+        implements ActionFactory.IWorkbenchAction {
+    /**
+     * Reference to the WorkbenchCommandAction that executes the Export Wizard.
+     */
+    private ActionFactory.IWorkbenchAction action;
+
+    /**
+     * The workbench window; or <code>null</code> if this
+     * action has been <code>dispose</code>d.
+     */
+    private IWorkbenchWindow workbenchWindow;
+
+    /**
+     * Create a new instance of this class.
+     *
+     * @param window the window
+     */
+    public ExportResourcesAction(IWorkbenchWindow window) {
+        this(window, WorkbenchMessages.get().ExportResourcesAction_text);
+    }
+
+    /**
+     * Create a new instance of this class.
+     *
+     * @param window the window
+     * @param label the label
+     */
+    public ExportResourcesAction(IWorkbenchWindow window, String label) {
+        super(label);
+        if (window == null) {
+            throw new IllegalArgumentException();
+        }
+
+        this.workbenchWindow = window;
+        action = ActionFactory.EXPORT.create(window);
+
+        setText(action.getText());
+        setToolTipText(action.getToolTipText());
+        setId(action.getId());
+        setActionDefinitionId(action.getActionDefinitionId());
+        window.getWorkbench().getHelpSystem().setHelp(this,
+				IWorkbenchHelpContextIds.EXPORT_ACTION);
+        setImageDescriptor(action.getImageDescriptor());
+    }
+
+    /**
+     * Create a new instance of this class
+     *
+     * @param workbench the workbench
+     * @deprecated use the constructor <code>ExportResourcesAction(IWorkbenchWindow)</code>
+     */
+    @Deprecated
+	public ExportResourcesAction(IWorkbench workbench) {
+        this(workbench.getActiveWorkbenchWindow());
+    }
+
+    /**
+     * Create a new instance of this class.
+     *
+     * @param workbench the workbench
+     * @param label the label
+     * @deprecated use the constructor <code>ExportResourcesAction(IWorkbenchWindow, String)</code>
+     */
+    @Deprecated
+	public ExportResourcesAction(IWorkbench workbench, String label) {
+        this(workbench.getActiveWorkbenchWindow(), label);
+    }
+
+    /**
+     * Invoke the Export wizards selection Wizard.
+     */
+    @Override
+	public void run() {
+        if (workbenchWindow == null) {
+            // action has been disposed
+            return;
+        }
+        action.run();
+    }
+
+    /**
+     * Sets the current selection.
+     * In for backwards compatability. Use selectionChanged() instead.
+     * @param selection the new selection
+     * @deprecated
+     */
+    @Deprecated
+	public void setSelection(IStructuredSelection selection) {
+        selectionChanged(selection);
+    }
+
+	@Override
+	public void dispose() {
+		workbenchWindow = null;
+		if (action!=null) {
+			action.dispose();
+		}
+		action = null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/ImportResourcesAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/ImportResourcesAction.java
new file mode 100644
index 0000000..3e3dfba
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/ImportResourcesAction.java
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.actions;
+
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchMessages;
+
+/**
+ * Action representing a generic import operation.
+ * <p>
+ * This class may be instantiated. It is not intended to be subclassed.
+ * </p>
+ * <p>
+ * This method automatically registers listeners so that it can keep its
+ * enablement state up to date. Ordinarily, the window's references to these
+ * listeners will be dropped automatically when the window closes. However,
+ * if the client needs to get rid of an action while the window is still open,
+ * the client must call IWorkbenchAction#dispose to give the
+ * action an opportunity to deregister its listeners and to perform any other
+ * cleanup.
+ *
+ * </p>
+ * <p>
+ * Note: Despite the name, an import operation can deal with things other than
+ * resources; the current name was retained for historical reasons.
+ * </p>
+ *
+ * @since 2.0
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class ImportResourcesAction extends BaseSelectionListenerAction
+        implements ActionFactory.IWorkbenchAction {
+    /**
+     * Reference to the WorkbenchCommandAction that executes the Import Wizard.
+     */
+    private ActionFactory.IWorkbenchAction action;
+
+    /**
+     * The workbench window; or <code>null</code> if this
+     * action has been <code>dispose</code>d.
+     */
+    private IWorkbenchWindow workbenchWindow;
+
+    /**
+     * Create a new instance of this class.
+     *
+     * @param window the window
+     */
+    public ImportResourcesAction(IWorkbenchWindow window) {
+        super(WorkbenchMessages.get().ImportResourcesAction_text);
+        if (window == null) {
+            throw new IllegalArgumentException();
+        }
+
+        this.workbenchWindow = window;
+        action = ActionFactory.IMPORT.create(window);
+
+        setText(action.getText());
+        setToolTipText(action.getToolTipText());
+        setId(action.getId());
+        setActionDefinitionId(action.getActionDefinitionId());
+        window.getWorkbench().getHelpSystem().setHelp(this,
+				IWorkbenchHelpContextIds.IMPORT_ACTION);
+        setImageDescriptor(action.getImageDescriptor());
+    }
+
+    /**
+     * Create a new instance of this class
+     *
+     * @param workbench the workbench
+     * @deprecated use the constructor <code>ImportResourcesAction(IWorkbenchWindow)</code>
+     */
+    @Deprecated
+	public ImportResourcesAction(IWorkbench workbench) {
+        this(workbench.getActiveWorkbenchWindow());
+    }
+
+    /**
+     * Invoke the Import wizards selection Wizard.
+     */
+    @Override
+	public void run() {
+        if (workbenchWindow == null) {
+            // action has been disposed
+            return;
+        }
+
+        action.run();
+    }
+
+    /**
+     * Sets the current selection.
+     * In for backwards compatability. Use selectionChanged() instead.
+     * @param selection the new selection
+     * @deprecated
+     */
+    @Deprecated
+	public void setSelection(IStructuredSelection selection) {
+        selectionChanged(selection);
+    }
+
+    @Override
+	public void dispose() {
+    	workbenchWindow = null;
+    	if (action!=null) {
+    	action.dispose();
+    	}
+    	action = null;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/LabelRetargetAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/LabelRetargetAction.java
new file mode 100644
index 0000000..5a45a7e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/LabelRetargetAction.java
@@ -0,0 +1,195 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.actions;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.LegacyActionTools;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.util.PropertyChangeEvent;
+
+/**
+ * A <code>LabelRetargetAction</code> extends the behavior of
+ * RetargetAction.  It will track the enable state, label, and
+ * tool tip text of the target action..
+ * <p>
+ * This class may be instantiated. It is not intented to be subclassed.
+ * </p>
+ *
+ * @since 2.0
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class LabelRetargetAction extends RetargetAction {
+    private String defaultText;
+
+    private String defaultToolTipText;
+
+    private ImageDescriptor defaultHoverImage;
+
+    private ImageDescriptor defaultImage;
+
+    private ImageDescriptor defaultDisabledImage;
+
+    private String acceleratorText;
+
+    /**
+     * Constructs a LabelRetargetAction with the given action id and text.
+     *
+     * @param actionID the retargetable action id
+     * @param text the action's text, or <code>null</code> if there is no text
+     */
+    public LabelRetargetAction(String actionID, String text) {
+        this(actionID, text, IAction.AS_UNSPECIFIED);
+    }
+
+    /**
+     * Constructs a RetargetAction with the given action id, text and style.
+     *
+     * @param actionID the retargetable action id
+     * @param text the action's text, or <code>null</code> if there is no text
+     * @param style one of <code>AS_PUSH_BUTTON</code>, <code>AS_CHECK_BOX</code>,
+     * 		<code>AS_DROP_DOWN_MENU</code>, <code>AS_RADIO_BUTTON</code>, and
+     * 		<code>AS_UNSPECIFIED</code>.
+     * @since 3.0
+     */
+    public LabelRetargetAction(String actionID, String text, int style) {
+        super(actionID, text, style);
+        this.defaultText = text;
+        this.defaultToolTipText = text;
+        acceleratorText = LegacyActionTools.extractAcceleratorText(text);
+    }
+
+    /**
+     * The action handler has changed.  Update self.
+     */
+    @Override
+	protected void propagateChange(PropertyChangeEvent event) {
+        super.propagateChange(event);
+        String prop = event.getProperty();
+        if (prop.equals(IAction.TEXT)) {
+            String str = (String) event.getNewValue();
+            super.setText(appendAccelerator(str));
+        } else if (prop.equals(IAction.TOOL_TIP_TEXT)) {
+            String str = (String) event.getNewValue();
+            super.setToolTipText(str);
+        } else if (prop.equals(IAction.IMAGE)) {
+            updateImages(getActionHandler());
+        }
+    }
+
+    /**
+     * Sets the action handler.  Update self.
+     */
+    @Override
+	protected void setActionHandler(IAction handler) {
+        // Run the default behavior.
+        super.setActionHandler(handler);
+
+        // Now update the label, tooltip and images.
+        if (handler == null) {
+            super.setText(defaultText);
+            super.setToolTipText(defaultToolTipText);
+        } else {
+            // If no text is specified by the handler, use the default text.  Fixes 22529.
+            String handlerText = handler.getText();
+            if (handlerText == null || handlerText.length() == 0) {
+                handlerText = defaultText;
+            }
+            super.setText(appendAccelerator(handlerText));
+            super.setToolTipText(handler.getToolTipText());
+        }
+        updateImages(handler);
+    }
+
+    @Override
+	public void setDisabledImageDescriptor(ImageDescriptor image) {
+        super.setDisabledImageDescriptor(image);
+        defaultDisabledImage = image;
+    }
+
+    @Override
+	public void setHoverImageDescriptor(ImageDescriptor image) {
+        super.setHoverImageDescriptor(image);
+        defaultHoverImage = image;
+    }
+
+    @Override
+	public void setImageDescriptor(ImageDescriptor image) {
+        super.setImageDescriptor(image);
+        defaultImage = image;
+    }
+
+    /**
+     * Sets the action's label text to the given value.
+     */
+    @Override
+	public void setText(String text) {
+        super.setText(text);
+        acceleratorText = LegacyActionTools.extractAcceleratorText(text);
+        defaultText = text;
+    }
+
+    /**
+     * Sets the tooltip text to the given text.
+     * The value <code>null</code> clears the tooltip text.
+     */
+    @Override
+	public void setToolTipText(String text) {
+        super.setToolTipText(text);
+        defaultToolTipText = text;
+    }
+
+    /**
+     * Ensures the accelerator is correct in the text (handlers are not
+     * allowed to change the accelerator).
+     */
+    private String appendAccelerator(String newText) {
+        if (newText == null) {
+			return null;
+		}
+
+        // Remove any accelerator
+        String str = removeAcceleratorText(newText);
+        // Append our accelerator
+        if (acceleratorText != null) {
+			str = str + '\t' + acceleratorText;
+		} else if (str != newText) {
+			str = str + '\t';
+		}
+        return str;
+    }
+
+    /**
+     * Updates the images for this action based on the given handler.
+     */
+    private void updateImages(IAction handler) {
+        if (handler == null) {
+            super.setHoverImageDescriptor(defaultHoverImage);
+            super.setImageDescriptor(defaultImage);
+            super.setDisabledImageDescriptor(defaultDisabledImage);
+        } else {
+            // use the default images if the handler has no images set
+            ImageDescriptor hoverImage = handler.getHoverImageDescriptor();
+            ImageDescriptor image = handler.getImageDescriptor();
+            ImageDescriptor disabledImage = handler
+                    .getDisabledImageDescriptor();
+            if (hoverImage != null || image != null || disabledImage != null) {
+                super.setHoverImageDescriptor(hoverImage);
+                super.setImageDescriptor(image);
+                super.setDisabledImageDescriptor(disabledImage);
+            } else {
+                super.setHoverImageDescriptor(defaultHoverImage);
+                super.setImageDescriptor(defaultImage);
+                super.setDisabledImageDescriptor(defaultDisabledImage);
+            }
+        }
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/NewWizardAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/NewWizardAction.java
new file mode 100644
index 0000000..20be388
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/NewWizardAction.java
@@ -0,0 +1,223 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.actions;
+
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.LegacyResourceSupport;
+import org.eclipse.ui.internal.PerspectiveTracker;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.dialogs.NewWizard;
+
+/**
+ * Invoke the resource creation wizard selection Wizard.
+ * <p>
+ * This class may be instantiated; it is not intended to be subclassed.
+ * </p>
+ * <p>
+ * This method automatically registers listeners so that it can keep its
+ * enablement state up to date. Ordinarily, the window's references to these
+ * listeners will be dropped automatically when the window closes. However,
+ * if the client needs to get rid of an action while the window is still open,
+ * the client must call #dispose() to give the
+ * action an opportunity to deregister its listeners and to perform any other
+ * cleanup.
+ * </p>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class NewWizardAction extends Action implements
+        ActionFactory.IWorkbenchAction {
+
+    /**
+     * The wizard dialog width
+     */
+    private static final int SIZING_WIZARD_WIDTH = 500;
+
+    /**
+     * The wizard dialog height
+     */
+    private static final int SIZING_WIZARD_HEIGHT = 500;
+
+    /**
+     * The id of the category to show or <code>null</code> to
+     * show all the categories.
+     */
+    private String categoryId = null;
+
+	/**
+	 * The title of the wizard window or <code>null</code> to use the default
+	 * wizard window title.
+	 */
+	private String windowTitle = null;
+
+    /**
+     * The workbench window; or <code>null</code> if this
+     * action has been <code>dispose</code>d.
+     */
+    private IWorkbenchWindow workbenchWindow;
+
+    /**
+     * Tracks perspective activation, to update this action's
+     * enabled state.
+     */
+    private PerspectiveTracker tracker;
+
+    /**
+     * Create a new instance of this class.
+     * @param window
+     */
+    public NewWizardAction(IWorkbenchWindow window) {
+        super(WorkbenchMessages.get().NewWizardAction_text);
+        if (window == null) {
+            throw new IllegalArgumentException();
+        }
+        this.workbenchWindow = window;
+        tracker = new PerspectiveTracker(window, this);
+        // @issues should be IDE-specific images
+        ISharedImages images = PlatformUI.getWorkbench().getSharedImages();
+        setImageDescriptor(images
+                .getImageDescriptor(ISharedImages.IMG_TOOL_NEW_WIZARD));
+        setDisabledImageDescriptor(images
+                .getImageDescriptor(ISharedImages.IMG_TOOL_NEW_WIZARD_DISABLED));
+        setToolTipText(WorkbenchMessages.get().NewWizardAction_toolTip);
+        PlatformUI.getWorkbench().getHelpSystem().setHelp(this,
+				IWorkbenchHelpContextIds.NEW_ACTION);
+    }
+
+    /**
+     * Create a new instance of this class
+     *
+     * @deprecated use the constructor <code>NewWizardAction(IWorkbenchWindow)</code>
+     */
+    @Deprecated
+	public NewWizardAction() {
+        this(PlatformUI.getWorkbench().getActiveWorkbenchWindow());
+    }
+
+    /**
+     * Returns the id of the category of wizards to show
+     * or <code>null</code> to show all categories.
+     * @return String
+     */
+    public String getCategoryId() {
+        return categoryId;
+    }
+
+    /**
+     * Sets the id of the category of wizards to show
+     * or <code>null</code> to show all categories.
+     * @param id
+     */
+    public void setCategoryId(String id) {
+        categoryId = id;
+    }
+
+	/**
+	 * <p>
+	 * Sets the title of the wizard window
+	 * <p>
+	 *
+	 * <p>
+	 * If the title of the wizard window is <code>null</code>, the default
+	 * wizard window title will be used.
+	 * </p>
+	 *
+	 * @param windowTitle
+	 *            The title of the wizard window, otherwise <code>null</code>
+	 *            (default wizard window title).
+	 *
+	 * @since 3.6
+	 */
+	public void setWizardWindowTitle(String windowTitle) {
+		this.windowTitle = windowTitle;
+	}
+
+    @Override
+	public void run() {
+        if (workbenchWindow == null) {
+            // action has been disposed
+            return;
+        }
+        NewWizard wizard = new NewWizard();
+        wizard.setCategoryId(categoryId);
+		wizard.setWindowTitle(windowTitle);
+
+        ISelection selection = workbenchWindow.getSelectionService()
+                .getSelection();
+        IStructuredSelection selectionToPass = StructuredSelection.EMPTY;
+        if (selection instanceof IStructuredSelection) {
+            selectionToPass = (IStructuredSelection) selection;
+        } else {
+            // @issue the following is resource-specific legacy code
+            // Build the selection from the IFile of the editor
+            Class resourceClass = LegacyResourceSupport.getResourceClass();
+            if (resourceClass != null) {
+                IWorkbenchPart part = workbenchWindow.getPartService()
+                        .getActivePart();
+                if (part instanceof IEditorPart) {
+                    IEditorInput input = ((IEditorPart) part).getEditorInput();
+					Object resource = Adapters.adapt(input, resourceClass);
+                    if (resource != null) {
+                        selectionToPass = new StructuredSelection(resource);
+                    }
+                }
+            }
+        }
+
+        wizard.init(workbenchWindow.getWorkbench(), selectionToPass);
+
+        IDialogSettings workbenchSettings = WorkbenchPlugin.getDefault()
+                .getDialogSettings();
+        IDialogSettings wizardSettings = workbenchSettings
+                .getSection("NewWizardAction"); //$NON-NLS-1$
+        if (wizardSettings == null) {
+			wizardSettings = workbenchSettings.addNewSection("NewWizardAction"); //$NON-NLS-1$
+		}
+        wizard.setDialogSettings(wizardSettings);
+        wizard.setForcePreviousAndNextButtons(true);
+
+        Shell parent = workbenchWindow.getShell();
+        WizardDialog dialog = new WizardDialog(parent, wizard);
+        dialog.create();
+        dialog.getShell().setSize(
+                Math.max(SIZING_WIZARD_WIDTH, dialog.getShell().getSize().x),
+                SIZING_WIZARD_HEIGHT);
+        PlatformUI.getWorkbench().getHelpSystem().setHelp(dialog.getShell(),
+				IWorkbenchHelpContextIds.NEW_WIZARD);
+        dialog.open();
+    }
+
+    @Override
+	public void dispose() {
+        if (workbenchWindow == null) {
+            // action has already been disposed
+            return;
+        }
+        tracker.dispose();
+        workbenchWindow = null;
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/NewWizardDropDownAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/NewWizardDropDownAction.java
new file mode 100644
index 0000000..2863487
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/NewWizardDropDownAction.java
@@ -0,0 +1,178 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.actions;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.ActionContributionItem;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.IMenuCreator;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.internal.PerspectiveTracker;
+import org.eclipse.ui.internal.WorkbenchMessages;
+
+/**
+ * Action which, when run, will open the new wizard dialog.
+ * In addition, it has a drop-down showing the new wizard shortcuts
+ * associated with the current perspective.
+ * <p>
+ * This class may be instantiated; it is not intended to be subclassed.
+ * </p>
+ *
+ * @since 3.1
+ */
+public class NewWizardDropDownAction extends Action implements
+        ActionFactory.IWorkbenchAction {
+
+    /**
+     * The workbench window; or <code>null</code> if this
+     * action has been <code>dispose</code>d.
+     */
+    private IWorkbenchWindow workbenchWindow;
+
+    /**
+     * Tracks perspective activation, to update this action's
+     * enabled state.
+     */
+    private PerspectiveTracker tracker;
+
+    private ActionFactory.IWorkbenchAction showDlgAction;
+
+    private IContributionItem newWizardMenu;
+
+    private IMenuCreator menuCreator = new IMenuCreator() {
+
+        private MenuManager dropDownMenuMgr;
+
+        /**
+         * Creates the menu manager for the drop-down.
+         */
+        private void createDropDownMenuMgr() {
+            if (dropDownMenuMgr == null) {
+                dropDownMenuMgr = new MenuManager();
+                dropDownMenuMgr.add(newWizardMenu);
+            }
+        }
+
+        @Override
+		public Menu getMenu(Control parent) {
+            createDropDownMenuMgr();
+            return dropDownMenuMgr.createContextMenu(parent);
+        }
+
+        @Override
+		public Menu getMenu(Menu parent) {
+            createDropDownMenuMgr();
+            Menu menu = new Menu(parent);
+            IContributionItem[] items = dropDownMenuMgr.getItems();
+            for (IContributionItem item : items) {
+                IContributionItem newItem = item;
+                if (item instanceof ActionContributionItem) {
+                    newItem = new ActionContributionItem(
+                            ((ActionContributionItem) item).getAction());
+                }
+                newItem.fill(menu, -1);
+            }
+            return menu;
+        }
+
+        @Override
+		public void dispose() {
+			if (dropDownMenuMgr != null) {
+				// remove the wizard menu before disposing the menu manager, the
+				// wizard menu is a workbench action and it should only be
+				// disposed when the workbench window itself is disposed,
+				// IMenuCreators will be disposed when the action is disposed,
+				// we do not want this, the menu's disposal will be handled when
+				// the owning action (NewWizardDropDownAction) is disposed, see
+				// bug 309716
+				dropDownMenuMgr.remove(newWizardMenu);
+
+				dropDownMenuMgr.dispose();
+				dropDownMenuMgr = null;
+			}
+        }
+    };
+
+    /**
+     * Create a new <code>NewWizardDropDownAction</code>, with the default
+     * action for opening the new wizard dialog, and the default contribution item
+     * for populating the drop-down menu.
+     *
+     * @param window the window in which this action appears
+     */
+    public NewWizardDropDownAction(IWorkbenchWindow window) {
+        this(window, ActionFactory.NEW.create(window), ContributionItemFactory.NEW_WIZARD_SHORTLIST.create(window));
+    }
+
+    /**
+     * Create a new <code>NewWizardDropDownAction</code>.
+     *
+     * @param window the window in which this action appears
+     * @param showDlgAction the action to delegate to when this action is run directly,
+     *   rather than being dropped down
+     * @param newWizardMenu the contribution item that adds the contents to the drop-down menu
+     */
+    public NewWizardDropDownAction(IWorkbenchWindow window,
+            ActionFactory.IWorkbenchAction showDlgAction,
+            IContributionItem newWizardMenu) {
+        super(WorkbenchMessages.get().NewWizardDropDown_text);
+        if (window == null) {
+            throw new IllegalArgumentException();
+        }
+        this.workbenchWindow = window;
+        this.showDlgAction = showDlgAction;
+        this.newWizardMenu = newWizardMenu;
+        tracker = new PerspectiveTracker(window, this);
+
+        setToolTipText(showDlgAction.getToolTipText());
+
+        ISharedImages sharedImages = window.getWorkbench()
+                .getSharedImages();
+        setImageDescriptor(sharedImages
+                .getImageDescriptor(ISharedImages.IMG_TOOL_NEW_WIZARD));
+        setDisabledImageDescriptor(sharedImages
+                .getImageDescriptor(ISharedImages.IMG_TOOL_NEW_WIZARD_DISABLED));
+
+        setMenuCreator(menuCreator);
+    }
+
+
+    @Override
+	public void dispose() {
+        if (workbenchWindow == null) {
+            // action has already been disposed
+            return;
+        }
+        tracker.dispose();
+        showDlgAction.dispose();
+        newWizardMenu.dispose();
+        menuCreator.dispose();
+        workbenchWindow = null;
+    }
+
+    /**
+     * Runs the action, which opens the New wizard dialog.
+     */
+    @Override
+	public void run() {
+        if (workbenchWindow == null) {
+            // action has been disposed
+            return;
+        }
+        showDlgAction.run();
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/OpenInNewWindowAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/OpenInNewWindowAction.java
new file mode 100644
index 0000000..d7395b2
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/OpenInNewWindowAction.java
@@ -0,0 +1,123 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.actions;
+
+import org.eclipse.core.runtime.IAdaptable;
+
+import org.eclipse.jface.action.Action;
+
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.WorkbenchException;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.Workbench;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+/**
+ * Opens a new window. The initial perspective
+ * for the new window will be the same type as
+ * the active perspective in the window which this
+ * action is running in. The default input for the
+ * new window's page is application-specific.
+ */
+public class OpenInNewWindowAction extends Action implements
+        ActionFactory.IWorkbenchAction {
+
+    /**
+     * The workbench window; or <code>null</code> if this
+     * action has been <code>dispose</code>d.
+     */
+    private IWorkbenchWindow workbenchWindow;
+
+    private IAdaptable pageInput;
+
+    /**
+     * Creates a new <code>OpenInNewWindowAction</code>. Sets
+     * the new window page's input to be an application-specific
+     * default.
+     *
+     * @param window the workbench window containing this action
+     */
+    public OpenInNewWindowAction(IWorkbenchWindow window) {
+        this(window, ((Workbench) window.getWorkbench()).getDefaultPageInput());
+		setActionDefinitionId(IWorkbenchCommandConstants.WINDOW_NEW_WINDOW);
+    }
+
+    /**
+     * Creates a new <code>OpenInNewWindowAction</code>.
+     *
+     * @param window the workbench window containing this action
+     * @param input the input for the new window's page
+     */
+    public OpenInNewWindowAction(IWorkbenchWindow window, IAdaptable input) {
+        super(WorkbenchMessages.get().OpenInNewWindowAction_text);
+        if (window == null) {
+            throw new IllegalArgumentException();
+        }
+        this.workbenchWindow = window;
+        // @issue missing action id
+        setToolTipText(WorkbenchMessages.get().OpenInNewWindowAction_toolTip);
+        pageInput = input;
+        window.getWorkbench().getHelpSystem().setHelp(this,
+				IWorkbenchHelpContextIds.OPEN_NEW_WINDOW_ACTION);
+    }
+
+    /**
+     * Set the input to use for the new window's page.
+     *
+     * @param input the input
+     */
+    public void setPageInput(IAdaptable input) {
+        pageInput = input;
+    }
+
+    /**
+     * The implementation of this <code>IAction</code> method
+     * opens a new window. The initial perspective
+     * for the new window will be the same type as
+     * the active perspective in the window which this
+     * action is running in.
+     */
+    @Override
+	public void run() {
+        if (workbenchWindow == null) {
+            // action has been disposed
+            return;
+        }
+        try {
+            String perspId;
+
+            IWorkbenchPage page = workbenchWindow.getActivePage();
+            if (page != null && page.getPerspective() != null) {
+				perspId = page.getPerspective().getId();
+			} else {
+				perspId = workbenchWindow.getWorkbench()
+                        .getPerspectiveRegistry().getDefaultPerspective();
+			}
+
+            workbenchWindow.getWorkbench().openWorkbenchWindow(perspId,
+                    pageInput);
+        } catch (WorkbenchException e) {
+			StatusUtil.handleStatus(e.getStatus(),
+					WorkbenchMessages.get().OpenInNewWindowAction_errorTitle
+							+ ": " + e.getMessage(), //$NON-NLS-1$
+					StatusManager.SHOW);
+        }
+    }
+
+    @Override
+	public void dispose() {
+        workbenchWindow = null;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/OpenNewPageMenu.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/OpenNewPageMenu.java
new file mode 100644
index 0000000..ce3c411
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/OpenNewPageMenu.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.actions;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.WorkbenchException;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+/**
+ * A menu for page creation in the workbench.
+ * <p>
+ * An <code>OpenNewPageMenu</code> is used to populate a menu with
+ * "Open Page" actions.  One item is added for each shortcut perspective,
+ * as defined by the product ini.  If the user selects one of these items a new page is
+ * created in the workbench with the given perspective.
+ * </p><p>
+ * The visible perspectives within the menu may also be updated dynamically to
+ * reflect user preference.
+ * </p><p>
+ * The input for the page is determined by the value of <code>pageInput</code>.
+ * The input should be passed into the constructor of this class or set using
+ * the <code>setPageInput</code> method.
+ * </p><p>
+ * This class may be instantiated; it is not intended to be subclassed.
+ * </p>
+ * @deprecated Workbench no longer exposes the concept of "pages" in the
+ * 		user ui model. See IWorkbench.showPerspective methods.
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+@Deprecated
+public class OpenNewPageMenu extends PerspectiveMenu {
+    private IAdaptable pageInput;
+
+    /**
+     * Constructs a new instance of <code>OpenNewPageMenu</code>.
+     * <p>
+     * If this method is used be sure to set the page input by invoking
+     * <code>setPageInput</code>.  The page input is required when the user
+     * selects an item in the menu.  At that point the menu will attempt to
+     * open a new page with the selected perspective and page input.  If there
+     * is no page input an error dialog will be opened.
+     * </p>
+     *
+     * @param window the window where a new page is created if an item within
+     *		the menu is selected
+     */
+    public OpenNewPageMenu(IWorkbenchWindow window) {
+        this(window, null);
+    }
+
+    /**
+     * Constructs a new instance of <code>OpenNewPageMenu</code>.
+     *
+     * @param window the window where a new page is created if an item within
+     *		the menu is selected
+     * @param input the page input
+     */
+    public OpenNewPageMenu(IWorkbenchWindow window, IAdaptable input) {
+        super(window, "Open New Page Menu");//$NON-NLS-1$
+        this.pageInput = input;
+    }
+
+    @Override
+	protected void run(IPerspectiveDescriptor desc) {
+        // Verify page input.
+        if (pageInput == null) {
+			StatusUtil.handleStatus(
+					WorkbenchMessages.get().OpenNewPageMenu_dialogTitle + ": " + //$NON-NLS-1$
+							WorkbenchMessages.get().OpenNewPageMenu_unknownPageInput,
+					StatusManager.SHOW);
+			return;
+        }
+
+        // Open the page.
+        try {
+            getWindow().openPage(desc.getId(), pageInput);
+        } catch (WorkbenchException e) {
+        	StatusUtil.handleStatus(
+					WorkbenchMessages.get().OpenNewPageMenu_dialogTitle + ": " + //$NON-NLS-1$
+							e.getMessage(), e, StatusManager.SHOW);
+        }
+    }
+
+    /**
+     * Sets the page input.
+     *
+     * @param input the page input
+     */
+    public void setPageInput(IAdaptable input) {
+        pageInput = input;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/OpenNewWindowMenu.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/OpenNewWindowMenu.java
new file mode 100644
index 0000000..9b8d053
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/OpenNewWindowMenu.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.actions;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.WorkbenchException;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+/**
+ * A menu for window creation in the workbench.
+ * <p>
+ * An <code>OpenNewWindowMenu</code> is used to populate a menu with
+ * "Open Window" actions.  One item is added for each shortcut perspective,
+ * as defined by the product ini.  If the user selects one of these items a new window is
+ * created in the workbench with the given perspective.
+ * </p><p>
+ * The visible perspectives within the menu may also be updated dynamically to
+ * reflect user preference.
+ * </p><p>
+ * The input for the page is determined by the value of <code>pageInput</code>.
+ * The input should be passed into the constructor of this class or set using
+ * the <code>setPageInput</code> method.
+ * </p><p>
+ * This class may be instantiated; it is not intended to be subclassed.
+ * </p>
+ * @deprecated See IWorkbench.showPerspective methods.
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+@Deprecated
+public class OpenNewWindowMenu extends PerspectiveMenu {
+    private IAdaptable pageInput;
+
+    /**
+     * Constructs a new instance of <code>OpenNewPageMenu</code>.
+     * <p>
+     * If this method is used be sure to set the page input by invoking
+     * <code>setPageInput</code>.  The page input is required when the user
+     * selects an item in the menu.  At that point the menu will attempt to
+     * open a new page with the selected perspective and page input.  If there
+     * is no page input an error dialog will be opened.
+     * </p>
+     *
+     * @param window the window where a new page is created if an item within
+     *		the menu is selected
+     */
+    public OpenNewWindowMenu(IWorkbenchWindow window) {
+        this(window, null);
+    }
+
+    /**
+     * Constructs a new instance of <code>OpenNewPageMenu</code>.
+     *
+     * @param window the window where a new page is created if an item within
+     *		the menu is selected
+     * @param input the page input
+     */
+    public OpenNewWindowMenu(IWorkbenchWindow window, IAdaptable input) {
+        super(window, "Open New Page Menu");//$NON-NLS-1$
+        this.pageInput = input;
+    }
+
+	/**
+	 * Opens a new window with a particular perspective and input.
+	 */
+    @Override
+	protected void run(IPerspectiveDescriptor desc) {
+        // Verify page input.
+        if (pageInput == null) {
+        	StatusUtil.handleStatus(
+					WorkbenchMessages.get().OpenNewWindowMenu_dialogTitle + ": " + //$NON-NLS-1$
+							WorkbenchMessages.get().OpenNewWindowMenu_unknownInput,
+					StatusManager.SHOW);
+			return;
+        }
+
+        // Open the page.
+        try {
+            getWindow().getWorkbench().openWorkbenchWindow(desc.getId(),
+                    pageInput);
+        } catch (WorkbenchException e) {
+			StatusUtil.handleStatus(
+					WorkbenchMessages.get().OpenNewWindowMenu_dialogTitle + ": " + //$NON-NLS-1$
+							e.getMessage(), e, StatusManager.SHOW);
+		}
+    }
+
+    /**
+     * Sets the page input.
+     *
+     * @param input the page input
+     */
+    public void setPageInput(IAdaptable input) {
+        pageInput = input;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/OpenPerspectiveAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/OpenPerspectiveAction.java
new file mode 100644
index 0000000..313e4a6
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/OpenPerspectiveAction.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.actions;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.IPluginContribution;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.util.Util;
+
+/**
+ * Opens a perspective.
+ *
+ * @since 3.1
+ */
+public final class OpenPerspectiveAction extends Action implements
+        IPluginContribution {
+
+    /**
+     * The perspective menu that will handle the execution of this action. This
+     * allows subclasses of <code>PerspectiveMenu</code> to define custom
+     * behaviour for these actions. This value should not be <code>null</code>.
+     */
+    private final PerspectiveMenu callback;
+
+    /**
+     * The descriptor for the perspective that this action should open. This
+     * value is never <code>null</code>.
+     */
+    private final IPerspectiveDescriptor descriptor;
+
+    /**
+     * Constructs a new instance of <code>OpenPerspectiveAction</code>
+     *
+     * @param window
+     *            The workbench window in which this action is created; should
+     *            not be <code>null</code>.
+     * @param descriptor
+     *            The descriptor for the perspective that this action should
+     *            open; must not be <code>null</code>.
+     * @param callback
+     *            The perspective menu who will handle the actual execution of
+     *            this action; should not be <code>null</code>.
+     */
+    public OpenPerspectiveAction(final IWorkbenchWindow window,
+            final IPerspectiveDescriptor descriptor,
+            final PerspectiveMenu callback) {
+        super(Util.ZERO_LENGTH_STRING);
+
+        this.descriptor = descriptor;
+        this.callback = callback;
+
+        final String label = descriptor.getLabel();
+        setText(label);
+        setToolTipText(label);
+        setImageDescriptor(descriptor.getImageDescriptor());
+
+        window.getWorkbench().getHelpSystem().setHelp(this,
+                IWorkbenchHelpContextIds.OPEN_PERSPECTIVE_ACTION);
+    }
+
+
+    @Override
+	public final void runWithEvent(final Event event) {
+        callback.run(descriptor, new SelectionEvent(event));
+    }
+
+    @Override
+	public String getLocalId() {
+        return descriptor.getId();
+    }
+
+    @Override
+	public String getPluginId() {
+        return descriptor instanceof IPluginContribution ? ((IPluginContribution) descriptor)
+                .getPluginId()
+                : null;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/OpenPerspectiveMenu.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/OpenPerspectiveMenu.java
new file mode 100644
index 0000000..569c606
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/OpenPerspectiveMenu.java
@@ -0,0 +1,179 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.actions;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.IWorkbenchPreferenceConstants;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.WorkbenchException;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.internal.util.PrefUtil;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+/**
+ * A menu for window creation in the workbench.
+ * <p>
+ * An <code>OpenPerspectiveMenu</code> is used to populate a menu with
+ * actions that will open a new perspective. If the user selects one of
+ * these items either a new page is added to the workbench, a new
+ * workbench window is created with the chosen perspective or the current
+ * perspective will be replaced with the new onw.
+ * </p><p>
+ * The visible perspectives within the menu may also be updated dynamically to
+ * reflect user preference.
+ * </p><p>
+ * The input for the page is determined by the value of <code>pageInput</code>.
+ * The input should be passed into the constructor of this class or set using
+ * the <code>setPageInput</code> method.
+ * </p><p>
+ * This class may be instantiated; it is not intended to be subclassed.
+ * </p>
+ * @deprecated  See IWorkbench.showPerspective methods.
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+@Deprecated
+public class OpenPerspectiveMenu extends PerspectiveMenu {
+    private IAdaptable pageInput;
+
+    private IMenuManager parentMenuManager;
+
+    private boolean replaceEnabled = true;
+
+    private static String PAGE_PROBLEMS_TITLE = WorkbenchMessages.get().OpenPerspectiveMenu_pageProblemsTitle;
+
+    private static String PAGE_PROBLEMS_MESSAGE = WorkbenchMessages.get().OpenPerspectiveMenu_errorUnknownInput;
+
+    /**
+     * Constructs a new menu.
+     */
+    public OpenPerspectiveMenu(IMenuManager menuManager, IWorkbenchWindow window) {
+        this(window);
+        this.parentMenuManager = menuManager;
+    }
+
+    /**
+     * Constructs a new instance of <code>OpenNewPageMenu</code>.
+     * <p>
+     * If this method is used be sure to set the page input by invoking
+     * <code>setPageInput</code>.  The page input is required when the user
+     * selects an item in the menu.  At that point the menu will attempt to
+     * open a new page with the selected perspective and page input.  If there
+     * is no page input an error dialog will be opened.
+     * </p>
+     *
+     * @param window the window where a new page is created if an item within
+     *		the menu is selected
+     */
+    public OpenPerspectiveMenu(IWorkbenchWindow window) {
+        this(window, null);
+        showActive(true);
+    }
+
+    /**
+     * Constructs a new instance of <code>OpenNewPageMenu</code>.
+     *
+     * @param window the window where a new page is created if an item within
+     *		the menu is selected
+     * @param input the page input
+     */
+    public OpenPerspectiveMenu(IWorkbenchWindow window, IAdaptable input) {
+        super(window, "Open New Page Menu");//$NON-NLS-1$
+        this.pageInput = input;
+    }
+
+    /**
+     * Return whether or not the menu can be run. Answer true unless the current mode
+     * is replace and the replaceEnabled flag is false.
+     */
+    private boolean canRun() {
+        if (openPerspectiveSetting().equals(
+                IWorkbenchPreferenceConstants.OPEN_PERSPECTIVE_REPLACE)) {
+			return replaceEnabled;
+		}
+        return true;
+    }
+
+    /**
+     * Return the current perspective setting.
+     */
+    private String openPerspectiveSetting() {
+        return PrefUtil.getAPIPreferenceStore().getString(
+                IWorkbenchPreferenceConstants.OPEN_NEW_PERSPECTIVE);
+    }
+
+    /**
+     * Runs an action for a particular perspective. Opens the perspective supplied
+     * in a new window or a new page depending on the workbench preference.
+     *
+     * @param desc the selected perspective
+     */
+    @Override
+	protected void run(IPerspectiveDescriptor desc) {
+        openPage(desc, 0);
+    }
+
+    /**
+     * Runs an action for a particular perspective. Check for shift or control events
+     * to decide which event to run.
+     *
+     * @param desc the selected perspective
+     * @param event the event sent along with the selection callback
+     */
+    @Override
+	protected void run(IPerspectiveDescriptor desc, SelectionEvent event) {
+        openPage(desc, event.stateMask);
+    }
+
+    private void openPage(IPerspectiveDescriptor desc, int keyStateMask) {
+        // Verify page input.
+        if (pageInput == null) {
+			StatusUtil.handleStatus(PAGE_PROBLEMS_TITLE
+					+ ": " + PAGE_PROBLEMS_MESSAGE, StatusManager.SHOW); //$NON-NLS-1$
+			return;
+        }
+
+        // Open the page.
+        try {
+            getWindow().getWorkbench().showPerspective(desc.getId(),
+                    getWindow(), pageInput);
+        } catch (WorkbenchException e) {
+			StatusUtil.handleStatus(
+					PAGE_PROBLEMS_TITLE + ": " + e.getMessage(), e,  //$NON-NLS-1$
+					StatusManager.SHOW);
+		}
+    }
+
+    /**
+     * Sets the page input.
+     *
+     * @param input the page input
+     */
+    public void setPageInput(IAdaptable input) {
+        pageInput = input;
+    }
+
+    /**
+     * Set whether replace menu item is enabled within its parent menu.
+     */
+    public void setReplaceEnabled(boolean isEnabled) {
+        if (replaceEnabled != isEnabled) {
+            replaceEnabled = isEnabled;
+            if (canRun() && parentMenuManager != null) {
+				parentMenuManager.update(true);
+			}
+        }
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/PartEventAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/PartEventAction.java
new file mode 100644
index 0000000..a697728
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/PartEventAction.java
@@ -0,0 +1,136 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.actions;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.ui.IPartListener;
+import org.eclipse.ui.IWorkbenchPart;
+
+/**
+ * The abstract superclass for actions that listen to part activation and
+ * open/close events. This implementation tracks the active part (see
+ * <code>getActivePart</code>) and provides a convenient place to monitor
+ * part lifecycle events that could affect the availability of the action.
+ * <p>
+ * Subclasses must implement the following <code>IAction</code> method:
+ * <ul>
+ *   <li><code>run</code> - to do the action's work</li>
+ * </ul>
+ * </p>
+ * <p>
+ * Subclasses may extend any of the <code>IPartListener</code> methods if the
+ * action availablity needs to be recalculated:
+ * <ul>
+ *   <li><code>partActivated</code></li>
+ *   <li><code>partDeactivated</code></li>
+ *   <li><code>partOpened</code></li>
+ *   <li><code>partClosed</code></li>
+ *   <li><code>partBroughtToTop</code></li>
+ * </ul>
+ * </p>
+ * <p>
+ * Although this method implements the <code>IPartListener</code> interface,
+ * it does NOT register itself.
+ * </p>
+ */
+public abstract class PartEventAction extends Action implements IPartListener {
+
+    /**
+     * The active part, or <code>null</code> if none.
+     */
+    private IWorkbenchPart activePart;
+
+    /**
+     * Creates a new action with the given text.
+     *
+     * @param text the action's text, or <code>null</code> if there is no text
+     */
+    protected PartEventAction(String text) {
+        super(text);
+    }
+
+    /**
+     * Creates a new action with the given text and style.
+     *
+     * @param text the action's text, or <code>null</code> if there is no text
+     * @param style one of <code>AS_PUSH_BUTTON</code>, <code>AS_CHECK_BOX</code>,
+     * 		<code>AS_DROP_DOWN_MENU</code>, <code>AS_RADIO_BUTTON</code>, and
+     * 		<code>AS_UNSPECIFIED</code>
+     * @since 3.0
+     */
+    protected PartEventAction(String text, int style) {
+        super(text, style);
+    }
+
+    /**
+     * Returns the currently active part in the workbench.
+     *
+     * @return currently active part in the workbench, or <code>null</code> if none
+     */
+    public IWorkbenchPart getActivePart() {
+        return activePart;
+    }
+
+    /**
+     * The <code>PartEventAction</code> implementation of this
+     * <code>IPartListener</code> method records that the given part is active.
+     * Subclasses may extend this method if action availability has to be
+     * recalculated.
+     */
+    @Override
+	public void partActivated(IWorkbenchPart part) {
+        activePart = part;
+    }
+
+    /**
+     * The <code>PartEventAction</code> implementation of this
+     * <code>IPartListener</code> method does nothing. Subclasses should extend
+     * this method if action availability has to be recalculated.
+     */
+    @Override
+	public void partBroughtToTop(IWorkbenchPart part) {
+        // do nothing
+    }
+
+    /**
+     * The <code>PartEventAction</code> implementation of this
+     * <code>IPartListener</code> method clears the active part if it just closed.
+     * Subclasses may extend this method if action availability has to be
+     * recalculated.
+     */
+    @Override
+	public void partClosed(IWorkbenchPart part) {
+        if (part == activePart) {
+			activePart = null;
+		}
+    }
+
+    /**
+     * The <code>PartEventAction</code> implementation of this
+     * <code>IPartListener</code> method records that there is no active part.
+     * Subclasses may extend this method if action availability has to be
+     * recalculated.
+     */
+    @Override
+	public void partDeactivated(IWorkbenchPart part) {
+        activePart = null;
+    }
+
+    /**
+     * The <code>PartEventAction</code> implementation of this
+     * <code>IPartListener</code> method does nothing. Subclasses should extend
+     * this method if action availability has to be recalculated.
+     */
+    @Override
+	public void partOpened(IWorkbenchPart part) {
+        // do nothing
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/PerspectiveMenu.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/PerspectiveMenu.java
new file mode 100644
index 0000000..8e34382
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/PerspectiveMenu.java
@@ -0,0 +1,394 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Tonny Madsen, RCP Company - bug 201055
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *******************************************************************************/
+package org.eclipse.ui.actions;
+
+import com.ibm.icu.text.Collator;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.NotEnabledException;
+import org.eclipse.core.commands.NotHandledException;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.ContributionItem;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.IMenuListener;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.IPerspectiveRegistry;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPreferenceConstants;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.activities.WorkbenchActivityHelper;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.util.PrefUtil;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+/**
+ * A menu for perspective selection.
+ * <p>
+ * A <code>PerspectiveMenu</code> is used to populate a menu with
+ * perspective shortcut items.  If the user selects one of these items
+ * an action is performed for the selected perspective.
+ * </p><p>
+ * The visible perspective items within the menu are dynamic and reflect the
+ * available set generated by each subclass. The default available set consists
+ * of the perspective shortcut list of the current perspective.
+ * </p><p>
+ * This class is abstract.  Subclasses must implement the <code>run</code> method,
+ * which performs a specialized action for the selected perspective.
+ * </p>
+ */
+public abstract class PerspectiveMenu extends ContributionItem {
+    /**
+     * @since 3.4
+	 * @deprecated As of 3.5, replaced by {@link IWorkbenchCommandConstants#PERSPECTIVES_SHOW_PERSPECTIVE}
+	 */
+	@Deprecated
+	protected static final String SHOW_PERSP_ID = IWorkbenchCommandConstants.PERSPECTIVES_SHOW_PERSPECTIVE;
+
+	private IPerspectiveRegistry reg;
+
+    private IWorkbenchWindow window;
+
+    private boolean showActive = false;
+
+    private boolean dirty = true;
+
+    private IMenuListener menuListener = manager -> {
+	    manager.markDirty();
+	    dirty = true;
+	};
+
+    private Comparator comparator = new Comparator() {
+        private Collator collator = Collator.getInstance();
+
+        @Override
+		public int compare(Object ob1, Object ob2) {
+            IPerspectiveDescriptor d1 = (IPerspectiveDescriptor) ob1;
+            IPerspectiveDescriptor d2 = (IPerspectiveDescriptor) ob2;
+            return collator.compare(d1.getLabel(), d2.getLabel());
+        }
+    };
+
+    /**
+     * The translatable message to show when there are no perspectives.
+     *
+     * @since 3.1
+     */
+    private static final String NO_TARGETS_MSG = WorkbenchMessages.get().Workbench_showInNoPerspectives;
+
+    /**
+     * The map of perspective identifiers (String) to actions
+     * (OpenPerspectiveAction). This map may be empty, but it is never
+     * <code>null</code>.
+     *
+     * @since 3.1
+     */
+    private Map actions = new HashMap();
+
+    /**
+     * The action for that allows the user to choose any perspective to open.
+     *
+     * @since 3.1
+     */
+    private Action openOtherAction = new Action(WorkbenchMessages.get().PerspectiveMenu_otherItem) {
+        @Override
+		public final void runWithEvent(final Event event) {
+            runOther(new SelectionEvent(event));
+        }
+    };
+
+
+    /**
+     * Constructs a new instance of <code>PerspectiveMenu</code>.
+     *
+     * @param window the window containing this menu
+     * @param id the menu id
+     */
+    public PerspectiveMenu(IWorkbenchWindow window, String id) {
+        super(id);
+        this.window = window;
+        reg = window.getWorkbench().getPerspectiveRegistry();
+		openOtherAction
+				.setActionDefinitionId(IWorkbenchCommandConstants.PERSPECTIVES_SHOW_PERSPECTIVE);
+    }
+
+    @Override
+	public void fill(Menu menu, int index) {
+        if (getParent() instanceof MenuManager) {
+			((MenuManager) getParent()).addMenuListener(menuListener);
+		}
+
+        if (!dirty) {
+			return;
+		}
+
+        final MenuManager manager = new MenuManager();
+        fillMenu(manager);
+        final IContributionItem items[] = manager.getItems();
+        if (items.length == 0) {
+            MenuItem item = new MenuItem(menu, SWT.NONE, index++);
+            item.setText(NO_TARGETS_MSG);
+            item.setEnabled(false);
+        } else {
+            for (IContributionItem item : items) {
+                item.fill(menu, index++);
+            }
+        }
+        dirty = false;
+    }
+
+    /**
+     * Fills the given menu manager with all the open perspective actions
+     * appropriate for the currently active perspective. Filtering is applied to
+     * the actions based on the activities and capabilities mechanism.
+     *
+     * @param manager
+     *            The menu manager that should receive the menu items; must not
+     *            be <code>null</code>.
+     * @since 3.1
+     */
+    private final void fillMenu(final MenuManager manager) {
+        // Clear out the manager so that we have a blank slate.
+        manager.removeAll();
+
+        // Collect and sort perspective descriptors.
+        final List persps = getPerspectiveItems();
+        Collections.sort(persps, comparator);
+
+        /*
+         * Convert the perspective descriptors to actions, and filter out
+         * actions using the activity/capability mechanism.
+         */
+        final List actions = new ArrayList(persps.size());
+        for (Iterator i = persps.iterator(); i.hasNext();) {
+            final IPerspectiveDescriptor descriptor = (IPerspectiveDescriptor) i
+                    .next();
+            final IAction action = getAction(descriptor.getId());
+            if (action != null) {
+                if (WorkbenchActivityHelper.filterItem(action)) {
+					continue;
+				}
+                actions.add(action);
+            }
+        }
+
+        // Go through and add each of the actions to the menu manager.
+        for (Iterator i = actions.iterator(); i.hasNext();) {
+            manager.add((IAction) i.next());
+        }
+
+        if (PrefUtil
+                .getAPIPreferenceStore()
+                .getBoolean(
+                        IWorkbenchPreferenceConstants.SHOW_OTHER_IN_PERSPECTIVE_MENU)) {
+        	// Add a separator and then "Other..."
+        	if (actions.size() > 0) {
+				manager.add(new Separator());
+			}
+			manager.add(openOtherAction);
+        }
+    }
+
+    /**
+     * Returns the action for the given perspective id. This is a lazy cache. If
+     * the action does not already exist, then it is created. If there is no
+     * perspective with the given identifier, then the action is not created.
+     *
+     * @param id
+     *            The identifier of the perspective for which the action should
+     *            be retrieved.
+     * @return The action for the given identifier; or <code>null</code> if
+     *         there is no perspective with the given identifier.
+     * @since 3.1
+     */
+    private final IAction getAction(final String id) {
+        IAction action = (IAction) actions.get(id);
+        if (action == null) {
+            IPerspectiveDescriptor descriptor = reg.findPerspectiveWithId(id);
+            if (descriptor != null) {
+                action = new OpenPerspectiveAction(window, descriptor, this);
+                action.setActionDefinitionId(id);
+                actions.put(id, action);
+            }
+        }
+        return action;
+    }
+
+    /*
+     * Returns the perspective shortcut items for the active perspective.
+     *
+     * @return a list of <code>IPerspectiveDescriptor</code> items
+     */
+    private ArrayList getPerspectiveShortcuts() {
+		ArrayList list = new ArrayList();
+
+        IWorkbenchPage page = window.getActivePage();
+        if (page == null) {
+			return list;
+		}
+
+        String[] ids = page.getPerspectiveShortcuts();
+
+		for (String perspectiveId : ids) {
+			IPerspectiveDescriptor desc = reg.findPerspectiveWithId(perspectiveId);
+            if (desc != null && !list.contains(desc)) {
+                if (WorkbenchActivityHelper.filterItem(desc)) {
+					continue;
+				}
+                list.add(desc);
+            }
+        }
+
+        return list;
+    }
+
+    /**
+     * Returns the available list of perspectives to display in the menu.
+     * <p>
+     * By default, the list contains the perspective shortcuts
+     * for the current perspective.
+     * </p><p>
+     * Subclasses can override this method to return a different list.
+     * </p>
+     *
+     * @return an <code>ArrayList<code> of perspective items <code>IPerspectiveDescriptor</code>
+     */
+    protected ArrayList getPerspectiveItems() {
+        /* Allow the user to see all the perspectives they have
+         * selected via Customize Perspective. Bugzilla bug #23445 */
+        ArrayList shortcuts = getPerspectiveShortcuts();
+        ArrayList list = new ArrayList(shortcuts.size());
+
+        // Add perspective shortcuts from the active perspective
+        int size = shortcuts.size();
+        for (int i = 0; i < size; i++) {
+            if (!list.contains(shortcuts.get(i))) {
+                list.add(shortcuts.get(i));
+            }
+        }
+
+        return list;
+    }
+
+    /**
+     * Returns whether the menu item representing the active perspective
+     * will have a check mark.
+     *
+     * @return <code>true</code> if a check mark is shown, <code>false</code> otherwise
+     */
+    protected boolean getShowActive() {
+        return showActive;
+    }
+
+    /**
+     * Returns the window for this menu.
+     *
+     * @return the window
+     */
+    protected IWorkbenchWindow getWindow() {
+        return window;
+    }
+
+    @Override
+	public boolean isDirty() {
+        return dirty;
+    }
+
+    @Override
+	public boolean isDynamic() {
+        return true;
+    }
+
+    /**
+     * Runs an action for a particular perspective.  The behavior of the
+     * action is defined by the subclass.
+     *
+     * @param desc the selected perspective
+     */
+    protected abstract void run(IPerspectiveDescriptor desc);
+
+    /**
+     * Runs an action for a particular perspective. The behavior of the action
+     * is defined by the subclass. By default, this just calls
+     * <code>run(IPerspectiveDescriptor)</code>.
+     *
+     * @param desc
+     *            the selected perspective
+     * @param event
+     *            SelectionEvent - the event send along with the selection
+     *            callback
+     */
+    protected void run(IPerspectiveDescriptor desc, SelectionEvent event) {
+        //Do a run without the event by default
+        run(desc);
+    }
+
+	/**
+	 * Show the "other" dialog, select a perspective, and run it. Pass on the selection event should
+	 * the menu need it.
+	 *
+	 * @param event the selection event
+	 */
+    void runOther(SelectionEvent event) {
+		IHandlerService handlerService = window
+				.getService(IHandlerService.class);
+		try {
+			handlerService.executeCommand(IWorkbenchCommandConstants.PERSPECTIVES_SHOW_PERSPECTIVE, null);
+		} catch (ExecutionException e) {
+			StatusManager.getManager().handle(
+					new Status(IStatus.WARNING, WorkbenchPlugin.PI_WORKBENCH,
+							"Failed to execute " + IWorkbenchCommandConstants.PERSPECTIVES_SHOW_PERSPECTIVE, e)); //$NON-NLS-1$
+		} catch (NotDefinedException e) {
+			StatusManager.getManager().handle(
+					new Status(IStatus.WARNING, WorkbenchPlugin.PI_WORKBENCH,
+							"Failed to execute " + IWorkbenchCommandConstants.PERSPECTIVES_SHOW_PERSPECTIVE, e)); //$NON-NLS-1$
+		} catch (NotEnabledException e) {
+			StatusManager.getManager().handle(
+					new Status(IStatus.WARNING, WorkbenchPlugin.PI_WORKBENCH,
+							"Failed to execute " + IWorkbenchCommandConstants.PERSPECTIVES_SHOW_PERSPECTIVE, e)); //$NON-NLS-1$
+		} catch (NotHandledException e) {
+			StatusManager.getManager().handle(
+					new Status(IStatus.WARNING, WorkbenchPlugin.PI_WORKBENCH,
+							"Failed to execute " + IWorkbenchCommandConstants.PERSPECTIVES_SHOW_PERSPECTIVE, e)); //$NON-NLS-1$
+		}
+	}
+
+    /**
+     * Sets the showActive flag.  If <code>showActive == true</code> then the
+     * active perspective is hilighted with a check mark.
+     *
+     * @param b the new showActive flag
+     */
+    protected void showActive(boolean b) {
+        showActive = b;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/QuickMenuCreator.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/QuickMenuCreator.java
new file mode 100644
index 0000000..7eb617d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/QuickMenuCreator.java
@@ -0,0 +1,299 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.actions;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+
+/**
+ * Abstract class that is capable of creating a context menu. It will try and
+ * open the menu close to the current selection, or under the mouse pointer if
+ * that's not possible.
+ *
+ * @since 3.3
+ */
+public abstract class QuickMenuCreator {
+
+	private static final int CHAR_INDENT = 3;
+
+	/**
+	 * Create and open the context menu.
+	 */
+	public void createMenu() {
+		final Display display = Display.getCurrent();
+		if (display == null) {
+			return;
+		}
+		Control focus = display.getFocusControl();
+		if (focus == null || focus.isDisposed()) {
+			return;
+		}
+
+		MenuManager menu = new MenuManager();
+		fillMenu(menu);
+		final Menu quickMenu = menu.createContextMenu(focus.getShell());
+		Point location = computeMenuLocation(focus);
+		if (location == null) {
+			return;
+		}
+		quickMenu.setLocation(location);
+		quickMenu.addListener(SWT.Hide, event -> {
+			if (!display.isDisposed()) {
+				display.asyncExec(() -> {
+					if (!quickMenu.isDisposed()) {
+						quickMenu.dispose();
+					}
+				});
+			}
+		});
+		quickMenu.setVisible(true);
+	}
+
+	/**
+	 * Create the contents of the context menu.
+	 *
+	 * @param menu
+	 *            the menu to fill
+	 */
+	protected abstract void fillMenu(IMenuManager menu);
+
+	/**
+	 * Determine the optimal point for this menu to appear.
+	 *
+	 * @param focus
+	 *            the focus control
+	 * @return the optimal placement
+	 * @since 3.5
+	 */
+	protected Point computeMenuLocation(Control focus) {
+		Point cursorLocation = focus.getDisplay().getCursorLocation();
+		Rectangle clientArea = null;
+		Point result = null;
+		// RAP [rh] StyledText missing
+//				if (focus instanceof StyledText) {
+//					StyledText styledText = (StyledText) focus;
+//					clientArea = styledText.getClientArea();
+//					result = computeMenuLocation(styledText);
+//				} else 
+		if (focus instanceof Tree) {
+			Tree tree = (Tree) focus;
+			clientArea = tree.getClientArea();
+			result = computeMenuLocation(tree);
+		} else if (focus instanceof Table) {
+			Table table = (Table) focus;
+			clientArea = table.getClientArea();
+			result = computeMenuLocation(table);
+		}
+		if (result == null) {
+			result = focus.toControl(cursorLocation);
+		}
+		if (clientArea != null && !clientArea.contains(result)) {
+			result = new Point(clientArea.x + clientArea.width / 2,
+					clientArea.y + clientArea.height / 2);
+		}
+		Rectangle shellArea = focus.getShell().getClientArea();
+		if (!shellArea.contains(focus.getShell().toControl(
+				focus.toDisplay(result)))) {
+			result = new Point(shellArea.x + shellArea.width / 2, shellArea.y
+					+ shellArea.height / 2);
+		}
+		return focus.toDisplay(result);
+	}
+
+	// RAP [rh] StyledText missing	
+//		/**
+//		 * Hook to compute the menu location if the focus widget is a styled text
+//		 * widget.
+//		 * 
+//		 * @param text
+//		 *            the styled text widget that has the focus
+//		 * 
+//		 * @return a widget relative position of the menu to pop up or
+//		 *         <code>null</code> if now position inside the widget can be
+//		 *         computed
+//		 * @since 3.5
+//		 */
+//		protected Point computeMenuLocation(StyledText text) {
+//			Point result = text.getLocationAtOffset(text.getCaretOffset());
+//			result.y += text.getLineHeight(text.getCaretOffset());
+//			if (!text.getClientArea().contains(result)) {
+//				return null;
+//			}
+//			return result;
+//		}
+
+	/**
+	 * Hook to compute the menu location if the focus widget is a tree widget.
+	 *
+	 * @param tree
+	 *            the tree widget that has the focus
+	 *
+	 * @return a widget relative position of the menu to pop up or
+	 *         <code>null</code> if now position inside the widget can be
+	 *         computed
+	 * @since 3.5
+	 */
+	protected Point computeMenuLocation(Tree tree) {
+		TreeItem[] items = tree.getSelection();
+		Rectangle clientArea = tree.getClientArea();
+		switch (items.length) {
+		case 0:
+			return null;
+		case 1:
+			Rectangle bounds = items[0].getBounds();
+			Rectangle intersect = clientArea.intersection(bounds);
+			if (intersect != null && intersect.height == bounds.height) {
+				return new Point(Math.max(0, bounds.x
+						+ getAvarageCharWith(tree) * CHAR_INDENT), bounds.y
+						+ bounds.height);
+			}
+			return null;
+
+		default:
+			Rectangle[] rectangles = new Rectangle[items.length];
+			for (int i = 0; i < rectangles.length; i++) {
+				rectangles[i] = items[i].getBounds();
+			}
+			Point cursorLocation = tree.getDisplay().getCursorLocation();
+			Point result = findBestLocation(getIncludedPositions(rectangles,
+					clientArea), tree.toControl(cursorLocation));
+			if (result != null) {
+				result.x = result.x + getAvarageCharWith(tree) * CHAR_INDENT;
+			}
+			return result;
+		}
+	}
+
+	/**
+	 * Hook to compute the menu location if the focus widget is a table widget.
+	 *
+	 * @param table
+	 *            the table widget that has the focus
+	 *
+	 * @return a widget relative position of the menu to pop up or
+	 *         <code>null</code> if now position inside the widget can be
+	 *         computed
+	 * @since 3.5
+	 */
+	protected Point computeMenuLocation(Table table) {
+		TableItem[] items = table.getSelection();
+		Rectangle clientArea = table.getClientArea();
+		switch (items.length) {
+		case 0: {
+			return null;
+		}
+		case 1: {
+			Rectangle bounds = items[0].getBounds(0);
+			Rectangle iBounds = items[0].getImageBounds(0);
+			Rectangle intersect = clientArea.intersection(bounds);
+			if (intersect != null && intersect.height == bounds.height) {
+				return new Point(Math.max(0, bounds.x + iBounds.width
+						+ getAvarageCharWith(table) * CHAR_INDENT), bounds.y
+						+ bounds.height);
+			}
+			return null;
+
+		}
+		default: {
+			Rectangle[] rectangles = new Rectangle[items.length];
+			for (int i = 0; i < rectangles.length; i++) {
+				rectangles[i] = items[i].getBounds(0);
+			}
+			Rectangle iBounds = items[0].getImageBounds(0);
+			Point cursorLocation = table.getDisplay().getCursorLocation();
+			Point result = findBestLocation(getIncludedPositions(rectangles,
+					clientArea), table.toControl(cursorLocation));
+			if (result != null) {
+				result.x = result.x + iBounds.width + getAvarageCharWith(table)
+						* CHAR_INDENT;
+			}
+			return result;
+		}
+		}
+	}
+
+	private Point[] getIncludedPositions(Rectangle[] rectangles,
+			Rectangle widgetBounds) {
+		List result = new ArrayList();
+		for (Rectangle rectangle : rectangles) {
+			Rectangle intersect = widgetBounds.intersection(rectangle);
+			if (intersect != null && intersect.height == rectangle.height) {
+				result.add(new Point(intersect.x, intersect.y
+						+ intersect.height));
+			}
+		}
+		return (Point[]) result.toArray(new Point[result.size()]);
+	}
+
+	private Point findBestLocation(Point[] points, Point relativeCursor) {
+		Point result = null;
+		double bestDist = Double.MAX_VALUE;
+		for (Point point : points) {
+			int a = 0;
+			int b = 0;
+			if (point.x > relativeCursor.x) {
+				a = point.x - relativeCursor.x;
+			} else {
+				a = relativeCursor.x - point.x;
+			}
+			if (point.y > relativeCursor.y) {
+				b = point.y - relativeCursor.y;
+			} else {
+				b = relativeCursor.y - point.y;
+			}
+			double dist = Math.sqrt(a * a + b * b);
+			if (dist < bestDist) {
+				result = point;
+				bestDist = dist;
+			}
+		}
+		return result;
+	}
+
+	private int getAvarageCharWith(Control control) {
+		GC gc = null;
+		try {
+			gc = new GC(control);
+			return gc.getFontMetrics().getAverageCharWidth();
+		} finally {
+			if (gc != null) {
+				gc.dispose();
+			}
+		}
+	}
+
+	/**
+	 * Dispose of this quick menu creator. Subclasses should ensure that they
+	 * call this method.
+	 *
+	 * @deprecated As of 3.5 this is not necessary as the SWT Menu created in
+	 *             {@link #createMenu()} will be disposed shortly after the
+	 *             SWT.Hide event.
+	 */
+	@Deprecated
+	public void dispose() {
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/RetargetAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/RetargetAction.java
new file mode 100644
index 0000000..a3ff4d5
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/RetargetAction.java
@@ -0,0 +1,320 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.actions;
+
+import org.eclipse.core.commands.IHandlerAttributes;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.swt.events.HelpListener;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.SubActionBars;
+import org.eclipse.ui.internal.PartSite;
+
+/**
+ * A <code>RetargetAction</code> tracks the active part in the workbench.
+ * Each RetargetAction has an ID.  If the active part provides an action
+ * handler for the ID the enable and check state of the RetargetAction
+ * is determined from the enable and check state of the handler.  If the
+ * active part does not provide an action handler then this action is
+ * disabled.
+ * </p>
+ * <p>
+ * <b>Note:</b> instances of this class add themselves as listeners to their
+ * action handler. It is important for the creator of a retarget action to call
+ * dispose when the action is no longer needed. This will ensure that the
+ * listener is removed.
+ * </p>
+ * <p>
+ * This class may be instantiated. It is not intented to be subclassed.
+ * </p>
+ *
+ * @since 2.0
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class RetargetAction extends PartEventAction implements
+        ActionFactory.IWorkbenchAction {
+
+    /**
+     * The help listener assigned to this action, or <code>null</code> if none.
+     */
+    private HelpListener localHelpListener;
+
+    private boolean enableAccelerator = true;
+
+    private IAction handler;
+
+    private IPropertyChangeListener propertyChangeListener = event -> RetargetAction.this.propagateChange(event);
+
+    /**
+     * Constructs a RetargetAction with the given action id and text.
+     *
+     * @param actionID the retargetable action id
+     * @param text the action's text, or <code>null</code> if there is no text
+     */
+    public RetargetAction(String actionID, String text) {
+        this(actionID, text, IAction.AS_UNSPECIFIED);
+    }
+
+    /**
+     * Constructs a RetargetAction with the given action id, text and style.
+     *
+     * @param actionID the retargetable action id
+     * @param text the action's text, or <code>null</code> if there is no text
+     * @param style one of <code>AS_PUSH_BUTTON</code>, <code>AS_CHECK_BOX</code>,
+     * 		<code>AS_DROP_DOWN_MENU</code>, <code>AS_RADIO_BUTTON</code>, and
+     * 		<code>AS_UNSPECIFIED</code>
+     * @since 3.0
+     */
+    public RetargetAction(String actionID, String text, int style) {
+        super(text, style);
+        setId(actionID);
+        setEnabled(false);
+        super.setHelpListener(e -> {
+		    HelpListener listener = null;
+		    if (handler != null) {
+		        // if we have a handler, see if it has a help listener
+		        listener = handler.getHelpListener();
+		        if (listener == null) {
+					// use our own help listener
+		            listener = localHelpListener;
+				}
+		    }
+		    if (listener != null) {
+				// pass on the event
+		        listener.helpRequested(e);
+			}
+		});
+    }
+
+    /**
+     * Disposes of the action and any resources held.
+     */
+    @Override
+	public void dispose() {
+        if (handler != null) {
+            handler.removePropertyChangeListener(propertyChangeListener);
+            handler = null;
+        }
+        IWorkbenchPart part = getActivePart();
+        if (part != null) {
+            IWorkbenchPartSite site = part.getSite();
+            SubActionBars bars = (SubActionBars) ((PartSite) site).getActionBars();
+            bars.removePropertyChangeListener(propertyChangeListener);
+        }
+    }
+
+    /**
+     * Enables the accelerator for this action.
+     *
+     * @param b the new enable state
+     */
+    public void enableAccelerator(boolean b) {
+        enableAccelerator = b;
+    }
+
+    @Override
+	public int getAccelerator() {
+        if (enableAccelerator) {
+			return super.getAccelerator();
+		}
+        return 0;
+    }
+
+    /**
+     * A workbench part has been activated. Try to connect
+     * to it.
+     *
+     * @param part the workbench part that has been activated
+     */
+    @Override
+	public void partActivated(IWorkbenchPart part) {
+        super.partActivated(part);
+        IWorkbenchPartSite site = part.getSite();
+        SubActionBars bars = (SubActionBars) ((PartSite) site).getActionBars();
+        bars.addPropertyChangeListener(propertyChangeListener);
+        setActionHandler(bars.getGlobalActionHandler(getId()));
+    }
+
+    /**
+     * A workbench part has been closed.
+     *
+     * @param part the workbench part that has been closed
+     */
+    @Override
+	public void partClosed(IWorkbenchPart part) {
+        IWorkbenchPart activePart = part.getSite().getPage().getActivePart();
+        if (activePart != null) {
+			// We are going to get a part activated message so don't bother setting the
+            // action handler to null. This prevents enablement flash in the toolbar
+            return;
+		}
+        if (part == getActivePart()) {
+			setActionHandler(null);
+		}
+        super.partClosed(part);
+    }
+
+    /**
+     * A workbench part has been deactivated. Disconnect from it.
+     *
+     * @param part the workbench part that has been deactivated
+     */
+    @Override
+	public void partDeactivated(IWorkbenchPart part) {
+        super.partDeactivated(part);
+        IWorkbenchPartSite site = part.getSite();
+        SubActionBars bars = (SubActionBars) ((PartSite) site).getActionBars();
+        bars.removePropertyChangeListener(propertyChangeListener);
+
+        IWorkbenchPart activePart = part.getSite().getPage().getActivePart();
+        if (activePart != null) {
+			// We are going to get a part activated message so don't bother setting the
+            // action handler to null. This prevents enablement flash in the toolbar
+            return;
+		}
+
+        setActionHandler(null);
+    }
+
+    /**
+     * Either the action handler itself has changed, or the configured action
+     * handlers on the action bars have changed. Update self.
+     */
+    protected void propagateChange(PropertyChangeEvent event) {
+        if (event.getProperty().equals(IAction.ENABLED)) {
+            Boolean bool = (Boolean) event.getNewValue();
+            setEnabled(bool.booleanValue());
+        } else if (event.getProperty().equals(IAction.CHECKED)) {
+            Boolean bool = (Boolean) event.getNewValue();
+            setChecked(bool.booleanValue());
+        } else if (event.getProperty().equals(SubActionBars.P_ACTION_HANDLERS)) {
+            if (event.getSource() instanceof IActionBars) {
+                IActionBars bars = (IActionBars) event.getSource();
+                setActionHandler(bars.getGlobalActionHandler(getId()));
+            }
+        }
+    }
+
+    /**
+     * Invoked when an action occurs.
+     */
+    @Override
+	public void run() {
+        if (handler != null) {
+			handler.run();
+		}
+    }
+
+    /**
+     * Invoked when an action occurs.
+     */
+    @Override
+	public void runWithEvent(Event event) {
+        if (handler != null) {
+			handler.runWithEvent(event);
+		}
+    }
+
+    /**
+     * Returns the action handler. This method was made public in 3.0.
+     *
+     * @return The current action handling this retargettable action. This
+     *         handler will be <code>null</code> if there is no current
+     *         handler.
+     */
+    public IAction getActionHandler() {
+        return handler;
+    }
+
+    @Override
+	public final boolean isHandled() {
+        return (handler != null);
+    }
+
+    /**
+     * Sets the action handler.
+     */
+    protected void setActionHandler(IAction newHandler) {
+        // Optimize.
+        if (newHandler == handler) {
+			return;
+		}
+
+        // Clear old action.
+        if (handler != null) {
+            handler.removePropertyChangeListener(propertyChangeListener);
+            handler = null;
+        }
+
+        // Set new action.
+		IAction oldHandler = handler;
+        handler = newHandler;
+        if (handler == null) {
+            setEnabled(false);
+            if (getStyle() == AS_CHECK_BOX || getStyle() == AS_RADIO_BUTTON) {
+                setChecked(false);
+            }
+        } else {
+            setEnabled(handler.isEnabled());
+            if (getStyle() == AS_CHECK_BOX || getStyle() == AS_RADIO_BUTTON) {
+                setChecked(handler.isChecked());
+            }
+            handler.addPropertyChangeListener(propertyChangeListener);
+        }
+
+		// Notify listeners that the handler has changed.
+        firePropertyChange(IHandlerAttributes.ATTRIBUTE_HANDLED, oldHandler,
+                newHandler);
+    }
+
+    @Override
+	public void setChecked(boolean checked) {
+        super.setChecked(checked);
+        // This call may come from the SWT control event handler
+        // itself, so notify the handler action to keep things
+        // in sync.
+        if (handler != null) {
+			handler.setChecked(checked);
+		}
+    }
+
+    /**
+     * The <code>RetargetAction</code> implementation of this method declared on
+     * <code>IAction</code> stores the help listener in a local field. The
+     * supplied listener is only used if there is no hanlder.
+     */
+    @Override
+	public void setHelpListener(HelpListener listener) {
+        localHelpListener = listener;
+    }
+
+	/**
+	 * Returns a string representation of this action.
+	 *
+	 * @return A string representation of this action.
+	 *
+	 * @since 3.2
+	 */
+	@Override
+	public final String toString() {
+		final StringBuffer buffer = new StringBuffer();
+
+		buffer.append("RetargetAction("); //$NON-NLS-1$
+		buffer.append(getId());
+		buffer.append(')');
+
+		return buffer.toString();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/SelectionProviderAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/SelectionProviderAction.java
new file mode 100644
index 0000000..5ef4791
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/SelectionProviderAction.java
@@ -0,0 +1,149 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.actions;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+
+/**
+ * The abstract superclass for actions that listen to selection changes
+ * from a particular selection provider. This implementation splits the current
+ * selection along structured/unstructured lines, providing a convenient place
+ * to monitor selection changes that require adjusting action state.
+ * <p>
+ * Subclasses must implement the following <code>IAction</code> method:
+ * <ul>
+ *   <li><code>run</code> - to do the action's work</li>
+ * </ul>
+ * </p>
+ * <p>
+ * Subclasses may reimplement either of the following methods:
+ * <ul>
+ *   <li><code>selectionChanged(IStructuredSelection)</code></li>
+ *   <li><code>selectionChanged(ISelection)</code></li>
+ * </ul>
+ * </p>
+ */
+public abstract class SelectionProviderAction extends Action implements
+        ISelectionChangedListener {
+
+    /**
+     * The selection provider that is the target of this action.
+     */
+    private ISelectionProvider provider;
+
+    /**
+     * Creates a new action with the given text that monitors selection changes
+     * within the given selection provider.
+     * The resulting action is added as a listener on the selection provider.
+     *
+     * @param provider the selection provider that will provide selection notification
+     * @param text the string used as the text for the action,
+     *   or <code>null</code> if there is no text
+     */
+    protected SelectionProviderAction(ISelectionProvider provider, String text) {
+        super(text);
+        this.provider = provider;
+        provider.addSelectionChangedListener(this);
+    }
+
+    /**
+     * Disposes this action by removing it as a listener from the selection provider.
+     * This must be called by the creator of the action when the action is no longer needed.
+     */
+    public void dispose() {
+        provider.removeSelectionChangedListener(this);
+    }
+
+    /**
+     * Returns the current selection in the selection provider.
+     *
+     * @return the current selection in the selection provider
+     */
+    public ISelection getSelection() {
+        return provider.getSelection();
+    }
+
+    /**
+     * Returns the selection provider that is the target of this action.
+     *
+     * @return the target selection provider of this action
+     */
+    public ISelectionProvider getSelectionProvider() {
+        return provider;
+    }
+
+    /**
+     * Returns the current structured selection in the selection provider, or an
+     * empty selection if nothing is selected or if selection does not include
+     * objects (for example, raw text).
+     *
+     * @return the current structured selection in the selection provider
+     */
+    public IStructuredSelection getStructuredSelection() {
+        ISelection selection = provider.getSelection();
+        if (selection instanceof IStructuredSelection) {
+			return (IStructuredSelection) selection;
+		} else {
+			return new StructuredSelection();
+		}
+    }
+
+    /**
+     * Notifies this action that the given (non-structured) selection has changed
+     * in the selection provider.
+     * <p>
+     * The <code>SelectionProviderAction</code> implementation of this method
+     * does nothing. Subclasses may reimplement to react to this selection change.
+     * </p>
+     *
+     * @param selection the new selection
+     */
+    public void selectionChanged(ISelection selection) {
+    }
+
+    /**
+     * Notifies this action that the given structured selection has changed
+     * in the selection provider.
+     * <p>
+     * The <code>SelectionProviderAction</code> implementation of this method
+     * does nothing. Subclasses may reimplement to react to this selection change.
+     * </p>
+     *
+     * @param selection the new selection
+     */
+    public void selectionChanged(IStructuredSelection selection) {
+        // Hook in subclass.
+    }
+
+    /**
+     * The <code>SelectionProviderAction</code> implementation of this
+     * <code>ISelectionChangedListener</code> method calls
+     * <code>selectionChanged(IStructuredSelection)</code> if the selection is
+     * a structured selection but <code>selectionChanged(ISelection)</code> if it is
+     * not. Subclasses should override either of those methods method to react to
+     * selection changes.
+     */
+    @Override
+	public final void selectionChanged(SelectionChangedEvent event) {
+        ISelection selection = event.getSelection();
+        if (selection instanceof IStructuredSelection) {
+			selectionChanged((IStructuredSelection) selection);
+		} else {
+			selectionChanged(selection);
+		}
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/SimpleWildcardTester.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/SimpleWildcardTester.java
new file mode 100644
index 0000000..ad08a49
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/SimpleWildcardTester.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 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.ui.actions;
+
+/**
+ * Implements an algorithm for very simple pattern matching in a string.
+ * There is only one feature: "*" may be used at the start or the end of the
+ * pattern to represent "one or more characters".
+ */
+public final class SimpleWildcardTester {
+    /**
+     * Returns whether a string matches a particular pattern.
+     *
+     * @param pattern the input pattern
+     * @param str the string to test
+     * @return <code>true</code> if a match occurs; <code>false</code>otherwise.
+     */
+    public static boolean testWildcard(String pattern, String str) {
+        if (pattern.equals("*")) {//$NON-NLS-1$
+            return true;
+        } else if (pattern.startsWith("*")) {//$NON-NLS-1$
+            if (pattern.endsWith("*")) {//$NON-NLS-1$
+                if (pattern.length() == 2) {
+					return true;
+				}
+                return str.indexOf(pattern.substring(1, pattern.length() - 1)) >= 0;
+            }
+            return str.endsWith(pattern.substring(1));
+        } else if (pattern.endsWith("*")) {//$NON-NLS-1$
+            return str.startsWith(pattern.substring(0, pattern.length() - 1));
+        } else {
+            return str.equals(pattern);
+        }
+    }
+
+    /**
+     * Returns whether a string matches a particular pattern.  Both string and
+     * pattern are converted to lower case before pattern matching occurs.
+     *
+     * @param pattern the input pattern
+     * @param str the string to test
+     * @return <code>true</code> if a match occurs; <code>false</code>otherwise.
+     */
+    public static boolean testWildcardIgnoreCase(String pattern, String str) {
+
+        //If str is null there was no extension to test
+        if (str == null) {
+			return false;
+		}
+        pattern = pattern.toLowerCase();
+        str = str.toLowerCase();
+        return testWildcard(pattern, str);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/WorkingSetFilterActionGroup.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/WorkingSetFilterActionGroup.java
new file mode 100644
index 0000000..3708e69
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/WorkingSetFilterActionGroup.java
@@ -0,0 +1,249 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.actions;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IWorkbenchActionConstants;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPreferenceConstants;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.IWorkingSet;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkingSetComparator;
+import org.eclipse.ui.internal.WorkingSetMenuContributionItem;
+import org.eclipse.ui.internal.actions.ClearWorkingSetAction;
+import org.eclipse.ui.internal.actions.EditWorkingSetAction;
+import org.eclipse.ui.internal.actions.SelectWorkingSetAction;
+import org.eclipse.ui.internal.util.Util;
+
+/**
+ * Adds working set filter actions (set / clear / edit)
+ *
+ * @since 2.1
+ */
+public class WorkingSetFilterActionGroup extends ActionGroup {
+    private static final String TAG_WORKING_SET_NAME = "workingSetName"; //$NON-NLS-1$
+
+    /**
+     * Indicates if working set was changed
+     */
+    public static final String CHANGE_WORKING_SET = "changeWorkingSet"; //$NON-NLS-1$
+
+    private static final String START_SEPARATOR_ID = "workingSetGroupStartSeparator"; //$NON-NLS-1$
+
+    private static final String SEPARATOR_ID = "workingSetGroupSeparator"; //$NON-NLS-1$
+
+	private static final String WORKING_SET_ACTION_GROUP = "workingSetActionGroup"; //$NON-NLS-1$
+
+    private IWorkingSet workingSet = null;
+
+    private ClearWorkingSetAction clearWorkingSetAction;
+
+    private SelectWorkingSetAction selectWorkingSetAction;
+
+    private EditWorkingSetAction editWorkingSetAction;
+
+    private IPropertyChangeListener workingSetUpdater;
+
+    private IMenuManager menuManager;
+
+	private IWorkbenchWindow workbenchWindow;
+
+	private IWorkbenchPage page;
+
+	private boolean allowWindowWorkingSetByDefault;
+
+	private CompoundContributionItem mruList;
+
+    /**
+	 * Creates a new instance of the receiver.
+	 *
+	 * @param shell
+	 *            shell to open dialogs and wizards on
+	 * @param workingSetUpdater
+	 *            property change listener notified when a working set is set
+	 * @since 3.2 Please note that it is expected that clients treat any
+	 *        selected working sets whose
+	 *        {@link IWorkingSet#isAggregateWorkingSet()} method returns
+	 *        <code>true</code> somewhat differently from traditional working
+	 *        sets. Please see the documentation for
+	 *        {@link IWorkbenchPage#getAggregateWorkingSet()} for details.
+	 */
+    public WorkingSetFilterActionGroup(Shell shell,
+            IPropertyChangeListener workingSetUpdater) {
+        Assert.isNotNull(shell);
+
+        this.workingSetUpdater = workingSetUpdater;
+        clearWorkingSetAction = new ClearWorkingSetAction(this);
+        selectWorkingSetAction = new SelectWorkingSetAction(this, shell);
+        editWorkingSetAction = new EditWorkingSetAction(this, shell);
+        mruList = new CompoundContributionItem() {
+
+			@Override
+			protected IContributionItem[] getContributionItems() {
+				IWorkingSet[] workingSets = PlatformUI.getWorkbench()
+						.getWorkingSetManager().getRecentWorkingSets();
+				List items = new ArrayList(workingSets.length);
+				List sortedWorkingSets = Arrays.asList(workingSets);
+				Collections.sort(sortedWorkingSets, new WorkingSetComparator());
+
+				int mruMenuCount = 0;
+				for (Iterator i = sortedWorkingSets.iterator(); i.hasNext();) {
+					IWorkingSet workingSet = (IWorkingSet) i.next();
+					if (workingSet != null) {
+						IContributionItem item = new WorkingSetMenuContributionItem(
+								++mruMenuCount,
+								WorkingSetFilterActionGroup.this, workingSet);
+						items.add(item);
+					}
+				}
+				return (IContributionItem[]) items
+						.toArray(new IContributionItem[items.size()]);
+			}
+        };
+
+        workbenchWindow = Util.getWorkbenchWindowForShell(shell);
+        allowWindowWorkingSetByDefault = false;
+		// set the default working set to be that of the window.
+		page = workbenchWindow.getActivePage();
+		if (page == null) {
+			IWorkbenchPage[] pages = workbenchWindow.getPages();
+			if (pages.length > 0) {
+				page = pages[0];
+			}
+		}
+    }
+
+    @Override
+	public void fillActionBars(IActionBars actionBars) {
+        menuManager = actionBars.getMenuManager();
+
+        if(menuManager.find(IWorkbenchActionConstants.MB_ADDITIONS) != null)
+        	menuManager.insertAfter(IWorkbenchActionConstants.MB_ADDITIONS, new Separator(WORKING_SET_ACTION_GROUP));
+        else
+        	menuManager.add(new Separator(WORKING_SET_ACTION_GROUP));
+
+        menuManager.appendToGroup(WORKING_SET_ACTION_GROUP, selectWorkingSetAction);
+        menuManager.appendToGroup(WORKING_SET_ACTION_GROUP, clearWorkingSetAction);
+        menuManager.appendToGroup(WORKING_SET_ACTION_GROUP, editWorkingSetAction);
+        menuManager.appendToGroup(WORKING_SET_ACTION_GROUP, new Separator(START_SEPARATOR_ID));
+        menuManager.appendToGroup(WORKING_SET_ACTION_GROUP, mruList);
+        menuManager.appendToGroup(WORKING_SET_ACTION_GROUP, new Separator(SEPARATOR_ID));
+    }
+
+
+	@Override
+	public void fillContextMenu(IMenuManager menuManager) {
+		menuManager.add(selectWorkingSetAction);
+		menuManager.add(clearWorkingSetAction);
+		menuManager.add(editWorkingSetAction);
+		menuManager.add(new Separator());
+        menuManager.add(mruList);
+		menuManager.add(new Separator(SEPARATOR_ID));
+	}
+
+    /**
+     * Returns the working set which is currently selected.
+     *
+     * @return the working set which is currently selected.
+     */
+    public IWorkingSet getWorkingSet() {
+        return workingSet;
+    }
+
+    /**
+     * Sets the current working set.
+     *
+     * @param newWorkingSet the new working set
+     */
+    public void setWorkingSet(IWorkingSet newWorkingSet) {
+        IWorkingSet oldWorkingSet = workingSet;
+
+        workingSet = newWorkingSet;
+        // Update action
+        clearWorkingSetAction.setEnabled(newWorkingSet != null);
+        editWorkingSetAction.setEnabled(newWorkingSet != null && newWorkingSet.isEditable());
+
+        firePropertyChange(newWorkingSet, oldWorkingSet);
+    }
+
+    /**
+     * Fire the property change to the updater if there is one available.
+     *
+     * @param newWorkingSet the new working set
+     * @param oldWorkingSet the previous working set
+     * @since 3.2
+     */
+	private void firePropertyChange(IWorkingSet newWorkingSet, IWorkingSet oldWorkingSet) {
+		// Update viewer
+        if (workingSetUpdater != null) {
+            workingSetUpdater.propertyChange(new PropertyChangeEvent(this,
+                    WorkingSetFilterActionGroup.CHANGE_WORKING_SET,
+                    oldWorkingSet, newWorkingSet));
+        }
+	}
+
+	/**
+	 * Saves the state of the filter actions in a memento.
+	 *
+	 * @param memento
+	 *            the memento
+	 * @since 3.3
+	 */
+	public void saveState(IMemento memento) {
+		if (workingSet != null) {
+			memento.putString(TAG_WORKING_SET_NAME, workingSet.getName());
+		} else {
+			memento.putString(TAG_WORKING_SET_NAME, ""); //$NON-NLS-1$
+		}
+	}
+
+	/**
+	 * Restores the state of the filter actions from a memento.
+	 * <p>
+	 * Note: This method does not refresh the viewer.
+	 * </p>
+	 *
+	 * @param memento
+	 * @since 3.3
+	 */
+	public void restoreState(IMemento memento) {
+		String workingSetName = memento.getString(TAG_WORKING_SET_NAME);
+		if (workingSetName != null && workingSetName.length() > 0) {
+			setWorkingSet(PlatformUI.getWorkbench().getWorkingSetManager().getWorkingSet(workingSetName));
+		} else if (page != null && useWindowWorkingSetByDefault()) {
+			setWorkingSet(page.getAggregateWorkingSet());
+		}
+	}
+
+	private boolean useWindowWorkingSetByDefault() {
+		return allowWindowWorkingSetByDefault
+				&& PlatformUI
+						.getPreferenceStore()
+						.getBoolean(
+								IWorkbenchPreferenceConstants.USE_WINDOW_WORKING_SET_BY_DEFAULT);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/package.html b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/package.html
new file mode 100644
index 0000000..05c521c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/actions/package.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <meta name="Author" content="IBM">
+   <meta name="GENERATOR" content="Mozilla/4.5 [en] (WinNT; I) [Netscape]">
+   <title>Package-level Javadoc</title>
+</head>
+<body>
+Classes for actions and operations used in a workbench
+window, page, or part in the Eclipse Platform User Interface.
+<h2>
+Package Specification</h2>
+Actions for resource management, project build and workbench page management
+are provided to encourage a standard look and feel across views and editors
+contributed by independent system vendors. Base classes are also provided
+for selection oriented actions which enable or disable based upon selection
+in a part or viewer. These should be used by ISV's to define actions for
+menus, toolbars, and context menus.
+<p>Action which leads to resource modification should take advantage of
+the <tt>WorkspaceModifyOperation</tt> classes.&nbsp; These classes are
+used to defer events which typically occur as a result of workspace changes
+(such as the firing of resource deltas, performance of autobuilds, etc.)
+until the outermost operation has successfully completed.&nbsp; This deferral
+leads to an optimized, faster execution of resource modification because
+fewer deltas and autobuilds are performed.
+</body>
+</html>
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/ActivitiesPreferencePage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/ActivitiesPreferencePage.java
new file mode 100644
index 0000000..105569b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/ActivitiesPreferencePage.java
@@ -0,0 +1,153 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.activities;
+
+import java.util.Hashtable;
+import java.util.Properties;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExecutableExtension;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.ui.internal.IPreferenceConstants;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.activities.ws.ActivityEnabler;
+import org.eclipse.ui.internal.activities.ws.ActivityMessages;
+
+/**
+ * Preference page that allows configuration of the activity set. This page may
+ * be used by product developers to provide basic ability to tweak the enabled
+ * activity set. You may provide the certain strings to this class via method #2
+ * of {@link org.eclipse.core.runtime.IExecutableExtension}.
+ *
+ * @see #ACTIVITY_NAME
+ * @see #ACTIVITY_PROMPT_BUTTON
+ * @see #ACTIVITY_PROMPT_BUTTON_TOOLTIP
+ * @since 3.1
+ */
+public final class ActivitiesPreferencePage extends PreferencePage implements
+        IWorkbenchPreferencePage, IExecutableExtension {
+
+	/**
+	 * The name to use for the activities.  Ie: "Capabilities".
+	 */
+    public static final String ACTIVITY_NAME = "activityName"; //$NON-NLS-1$
+
+	/**
+	 * The label to be used for the prompt button. Ie: "&Prompt when enabling capabilities".
+	 */
+    public static final String ACTIVITY_PROMPT_BUTTON = "activityPromptButton"; //$NON-NLS-1$
+
+	/**
+	 * The tooltip to be used for the prompt button. Ie: "Prompt when a feature is first used that requires enablement of capabilities".
+	 */
+    public static final String ACTIVITY_PROMPT_BUTTON_TOOLTIP = "activityPromptButtonTooltip"; //$NON-NLS-1$
+
+	private Button activityPromptButton;
+
+    private IWorkbench workbench;
+
+    private ActivityEnabler enabler;
+
+    private Properties strings = new Properties();
+
+    private IMutableActivityManager workingCopy;
+
+    /**
+     * Create the prompt for activity enablement.
+     *
+     * @param composite the parent
+     */
+    protected void createActivityPromptPref(Composite composite) {
+        activityPromptButton = new Button(composite, SWT.CHECK);
+        activityPromptButton.setText(strings.getProperty(ACTIVITY_PROMPT_BUTTON, ActivityMessages.activityPromptButton));
+        activityPromptButton.setToolTipText(strings.getProperty(ACTIVITY_PROMPT_BUTTON_TOOLTIP, ActivityMessages.activityPromptToolTip));
+
+        setActivityButtonState();
+    }
+
+    /**
+     * Sets the state of the activity prompt button from preferences.
+     */
+    private void setActivityButtonState() {
+        activityPromptButton.setSelection(getPreferenceStore().getBoolean(
+                IPreferenceConstants.SHOULD_PROMPT_FOR_ENABLEMENT));
+    }
+
+    @Override
+	protected Control createContents(Composite parent) {
+    	initializeDialogUnits(parent);
+
+        Composite composite = new Composite(parent, SWT.NONE);
+        GridLayout layout = new GridLayout();
+        layout.marginHeight = 0;
+        layout.marginWidth = 0;
+		layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
+		layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
+        composite.setLayout(layout);
+
+        createActivityPromptPref(composite);
+        GridData data = new GridData(GridData.FILL_HORIZONTAL);
+        activityPromptButton.setLayoutData(data);
+
+        data = new GridData(GridData.FILL_BOTH);
+        workingCopy = workbench.getActivitySupport().createWorkingCopy();
+        enabler = new ActivityEnabler(workingCopy, strings);
+        enabler.createControl(composite).setLayoutData(data);
+
+        Dialog.applyDialogFont(composite);
+
+        return composite;
+    }
+
+    @Override
+	public void init(IWorkbench aWorkbench) {
+        this.workbench = aWorkbench;
+        setPreferenceStore(WorkbenchPlugin.getDefault().getPreferenceStore());
+    }
+
+    @Override
+	public boolean performOk() {
+        enabler.updateActivityStates();
+        workbench.getActivitySupport().setEnabledActivityIds(workingCopy.getEnabledActivityIds());
+
+        getPreferenceStore().setValue(
+                IPreferenceConstants.SHOULD_PROMPT_FOR_ENABLEMENT,
+                activityPromptButton.getSelection());
+
+        return true;
+    }
+
+    @Override
+	protected void performDefaults() {
+        enabler.restoreDefaults();
+        activityPromptButton.setSelection(getPreferenceStore()
+                .getDefaultBoolean(
+                        IPreferenceConstants.SHOULD_PROMPT_FOR_ENABLEMENT));
+        super.performDefaults();
+    }
+
+	@Override
+	public void setInitializationData(IConfigurationElement config, String propertyName, Object data) {
+		if (data instanceof Hashtable) {
+			strings.putAll((Hashtable)data);
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/ActivityCategoryPreferencePage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/ActivityCategoryPreferencePage.java
new file mode 100644
index 0000000..140241b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/ActivityCategoryPreferencePage.java
@@ -0,0 +1,570 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2016 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.ui.activities;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExecutableExtension;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.jface.resource.DeviceResourceException;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.jface.viewers.CheckboxTableViewer;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.LabelProviderChangedEvent;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.IPreferenceConstants;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.OverlayIcon;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.activities.InternalActivityHelper;
+import org.eclipse.ui.internal.activities.ws.ActivityEnabler;
+import org.eclipse.ui.internal.activities.ws.ActivityMessages;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+/**
+ * Activities preference page that primarily shows categories and can optionally
+ * show an advanced dialog that allows fine-tune adjustmenet of activities. This
+ * page may be used by product developers to provide basic ability to tweak the
+ * enabled activity set. You may provide certain strings to this class via
+ * method #2 of {@link org.eclipse.core.runtime.IExecutableExtension}.
+ *
+ * @see #ACTIVITY_NAME
+ * @see #ALLOW_ADVANCED
+ * @see #CAPTION_MESSAGE
+ * @see #CATEGORY_NAME
+ * @see #ACTIVITY_PROMPT_BUTTON
+ * @see #ACTIVITY_PROMPT_BUTTON_TOOLTIP
+ *
+ * @since 3.1
+ */
+public final class ActivityCategoryPreferencePage extends PreferencePage implements
+        IWorkbenchPreferencePage, IExecutableExtension {
+
+    /**
+     * The name to use for the activities.  Ie: "Capabilities".
+     */
+    public static final String ACTIVITY_NAME = "activityName"; //$NON-NLS-1$
+
+    /**
+     * The parameter to use if you want the page to show the allow button. Must
+     * be true or false.
+     */
+    public static final String ALLOW_ADVANCED = "allowAdvanced"; //$NON-NLS-1$
+
+    /**
+     * The string to use for the message at the top of the preference page.
+     */
+    public static final String CAPTION_MESSAGE = "captionMessage"; //$NON-NLS-1$
+
+    /**
+     * The name to use for the activity categories.  Ie: "Roles".
+     */
+    public static final String CATEGORY_NAME = "categoryName"; //$NON-NLS-1$
+
+    /**
+     * The label to be used for the prompt button. Ie: "&Prompt when enabling capabilities".
+     */
+    public static final String ACTIVITY_PROMPT_BUTTON = "activityPromptButton"; //$NON-NLS-1$
+
+    /**
+     * The tooltip to be used for the prompt button. Ie: "Prompt when a feature is first used that requires enablement of capabilities".
+     */
+    public static final String ACTIVITY_PROMPT_BUTTON_TOOLTIP = "activityPromptButtonTooltip"; //$NON-NLS-1$
+
+    private class CategoryLabelProvider extends LabelProvider implements
+            ITableLabelProvider, IActivityManagerListener {
+
+        private LocalResourceManager manager = new LocalResourceManager(
+                JFaceResources.getResources());
+
+        private ImageDescriptor lockDescriptor;
+
+        private boolean decorate;
+
+        /**
+         * @param decorate
+         */
+        public CategoryLabelProvider(boolean decorate) {
+            this.decorate = decorate;
+            lockDescriptor = AbstractUIPlugin.imageDescriptorFromPlugin(
+                    PlatformUI.PLUGIN_ID, "icons/full/ovr16/lock_ovr.png"); //$NON-NLS-1$
+        }
+
+		@Override
+        public Image getColumnImage(Object element, int columnIndex) {
+            ICategory category = (ICategory) element;
+            ImageDescriptor descriptor = PlatformUI.getWorkbench()
+                    .getActivitySupport().getImageDescriptor(category);
+            if (descriptor != null) {
+                try {
+                    if (decorate) {
+                        if (isLocked(category)) {
+                            ImageData originalImageData = descriptor
+                                    .getImageData();
+                            OverlayIcon overlay = new OverlayIcon(
+                                    descriptor, lockDescriptor, new Point(
+                                            originalImageData.width,
+                                            originalImageData.height));
+                            return manager.createImage(overlay);
+                        }
+                    }
+
+                    return manager.createImage(descriptor);
+                } catch (DeviceResourceException e) {
+                    WorkbenchPlugin.log(e);
+                }
+            }
+            return null;
+        }
+
+        @Override
+		public String getText(Object element) {
+            String name = null;
+            ICategory category = (ICategory) element;
+            try {
+                name = category.getName();
+            } catch (NotDefinedException e) {
+                name = category.getId();
+            }
+            if (decorate && isLocked(category)) {
+                name = NLS.bind(ActivityMessages.ActivitiesPreferencePage_lockedMessage, name);
+            }
+            return name;
+        }
+
+		@Override
+        public String getColumnText(Object element, int columnIndex) {
+        	return getText(element);
+        }
+
+        @Override
+		public void dispose() {
+            super.dispose();
+            manager.dispose();
+        }
+
+		@Override
+        public void activityManagerChanged(
+                ActivityManagerEvent activityManagerEvent) {
+            if (activityManagerEvent.haveEnabledActivityIdsChanged()) {
+                updateCategoryCheckState();
+                fireLabelProviderChanged(new LabelProviderChangedEvent(this));
+            }
+        }
+    }
+
+    private class CategoryContentProvider implements IStructuredContentProvider {
+		@Override
+        public Object[] getElements(Object inputElement) {
+            // convert to category objects
+            return WorkbenchActivityHelper.resolveCategories(workingCopy, (Set) inputElement);
+        }
+		
+		@Override
+        public void dispose() {
+
+        }
+
+        @Override
+        public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+
+        }
+    }
+
+    private class EmptyCategoryFilter extends ViewerFilter {
+
+        @Override
+		public boolean select(Viewer viewer, Object parentElement,
+				Object element) {
+			ICategory category = (ICategory) element;
+			if (InternalActivityHelper.getActivityIdsForCategory(workingCopy,
+					category).isEmpty()) {
+				return false;
+			}
+			return true;
+		}
+    }
+
+    protected IWorkbench workbench;
+
+    private CheckboxTableViewer categoryViewer;
+
+    private TableViewer dependantViewer;
+
+    private Text descriptionText;
+
+    private IMutableActivityManager workingCopy;
+
+    private Button activityPromptButton;
+
+    private boolean allowAdvanced = false;
+
+    private Properties strings = new Properties();
+
+	private ActivityEnabler enabler;
+
+    @Override
+	protected Control createContents(Composite parent) {
+    	initializeDialogUnits(parent);
+
+        Composite composite = new Composite(parent, SWT.NONE);
+        GridLayout layout = new GridLayout(2, false);
+        layout.marginHeight = layout.marginWidth = 0;
+        layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
+        layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
+        composite.setLayout(layout);
+        Label label = new Label(composite, SWT.WRAP);
+        label
+                .setText(strings.getProperty(CAPTION_MESSAGE, ActivityMessages.ActivitiesPreferencePage_captionMessage));
+        GridData data = new GridData(GridData.FILL_HORIZONTAL);
+        data.widthHint = 400;
+        data.horizontalSpan = 2;
+        label.setLayoutData(data);
+        label = new Label(composite, SWT.NONE); //spacer
+        data = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
+        data.horizontalSpan = 2;
+        label.setLayoutData(data);
+        createPromptButton(composite);
+
+		workbench.getHelpSystem().setHelp(parent, IWorkbenchHelpContextIds.CAPABILITY_PREFERENCE_PAGE);
+
+		if (allowAdvanced) {
+			enabler = new ActivityEnabler(workingCopy, strings);
+			Control enablerControl = enabler.createControl(composite);
+			enablerControl.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+			Dialog.applyDialogFont(composite);
+			return composite;
+		}
+
+        createCategoryArea(composite);
+        createDetailsArea(composite);
+        createButtons(composite);
+
+
+        Dialog.applyDialogFont(composite);
+
+        return composite;
+    }
+
+    /**
+     * @param composite
+     */
+    private void createPromptButton(Composite composite) {
+        activityPromptButton = new Button(composite, SWT.CHECK);
+        activityPromptButton.setText(strings.getProperty(ACTIVITY_PROMPT_BUTTON, ActivityMessages.activityPromptButton));
+        activityPromptButton.setToolTipText(strings.getProperty(ACTIVITY_PROMPT_BUTTON_TOOLTIP, ActivityMessages.activityPromptToolTip));
+        GridData data = new GridData();
+        data.horizontalSpan = 2;
+        activityPromptButton.setLayoutData(data);
+        activityPromptButton.setSelection(getPreferenceStore()
+                .getBoolean(
+                        IPreferenceConstants.SHOULD_PROMPT_FOR_ENABLEMENT));
+    }
+
+    private void createButtons(final Composite parent) {
+        Composite composite = new Composite(parent, SWT.NONE);
+        GridLayout layout = new GridLayout(4, false);
+        layout.marginHeight = layout.marginWidth = 0;
+        layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
+        layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
+        composite.setLayout(layout);
+        GridData data = new GridData(GridData.FILL_HORIZONTAL);
+        data.horizontalSpan = 2;
+        composite.setLayoutData(data);
+
+        Button enableAll = new Button(composite, SWT.PUSH);
+		enableAll.addSelectionListener(new SelectionAdapter()
+        {
+		    public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {
+		        workingCopy.setEnabledActivityIds(workingCopy.getDefinedActivityIds());
+		    }
+        });
+        enableAll.setText(ActivityMessages.ActivityEnabler_selectAll);
+        setButtonLayoutData(enableAll);
+
+        Button disableAll = new Button(composite, SWT.PUSH);
+        disableAll.addSelectionListener(new SelectionAdapter()
+        {
+            public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {
+                workingCopy.setEnabledActivityIds(Collections.EMPTY_SET);
+            }
+        });
+        disableAll.setText(ActivityMessages.ActivityEnabler_deselectAll);
+        setButtonLayoutData(disableAll);
+
+    }
+
+    /**
+     * @param parent
+     */
+    private void createDetailsArea(Composite parent) {
+        Composite composite = new Composite(parent, SWT.NONE);
+        GridLayout layout = new GridLayout();
+        layout.marginHeight = layout.marginWidth = 0;
+        layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
+        layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
+        composite.setLayout(layout);
+        composite.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+        new Label(composite, SWT.NONE).setText(ActivityMessages.ActivityEnabler_description);
+        descriptionText = new Text(composite, SWT.WRAP | SWT.READ_ONLY | SWT.BORDER);
+        GridData data = new GridData(GridData.FILL_BOTH);
+        data.heightHint = 100;
+        data.widthHint = 200;
+        descriptionText.setLayoutData(data);
+
+        new Label(composite, SWT.NONE).setText(ActivityMessages.ActivitiesPreferencePage_requirements);
+        dependantViewer = new TableViewer(composite, SWT.BORDER);
+        dependantViewer.getControl().setLayoutData(
+                new GridData(GridData.FILL_BOTH));
+        dependantViewer.setContentProvider(new CategoryContentProvider());
+        dependantViewer.addFilter(new EmptyCategoryFilter());
+        dependantViewer.setLabelProvider(new CategoryLabelProvider(false));
+        dependantViewer.setInput(Collections.EMPTY_SET);
+    }
+
+    /**
+     * @param parent
+     */
+    private void createCategoryArea(Composite parent) {
+        Composite composite = new Composite(parent, SWT.NONE);
+        GridLayout layout = new GridLayout();
+        layout.marginHeight = layout.marginWidth = 0;
+        layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
+        layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
+        composite.setLayout(layout);
+        GridData data = new GridData(GridData.FILL_BOTH);
+        data.widthHint = 200;
+        composite.setLayoutData(data);
+        Label label = new Label(composite, SWT.NONE);
+        label.setText(strings.getProperty(CATEGORY_NAME, ActivityMessages.ActivityEnabler_categories));
+        Table table = new Table(composite, SWT.CHECK | SWT.BORDER | SWT.SINGLE);
+        table.addSelectionListener(new SelectionAdapter()
+        {
+            public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {
+        	if (e.detail == SWT.CHECK) {
+        		TableItem tableItem = (TableItem) e.item;
+
+        		ICategory category = (ICategory) tableItem.getData();
+        		if (isLocked(category)) {
+        			tableItem.setChecked(true);
+        			e.doit = false; // veto the check
+        			return;
+        		}
+				Set activitySet = WorkbenchActivityHelper.getActivityIdsForCategory(category);
+        		if (tableItem.getChecked()) {
+        			activitySet.addAll(workingCopy.getEnabledActivityIds());
+        		} else {
+        			HashSet newSet = new HashSet(workingCopy.getEnabledActivityIds());
+        			newSet.removeAll(activitySet);
+        			activitySet = newSet;
+        		}
+
+        		workingCopy.setEnabledActivityIds(activitySet);
+        		updateCategoryCheckState(); // even though we're reacting to
+        		// a check change we may need to
+        		// refresh a greying change.
+        		// Just process the whole thing.
+        	}
+            }
+        });
+        categoryViewer = new CheckboxTableViewer(table);
+		categoryViewer.getControl().setLayoutData(new GridData(GridData.FILL_BOTH));
+        categoryViewer.setContentProvider(new CategoryContentProvider());
+        CategoryLabelProvider categoryLabelProvider = new CategoryLabelProvider(true);
+        workingCopy.addActivityManagerListener(categoryLabelProvider);
+        categoryViewer.setLabelProvider(categoryLabelProvider);
+        categoryViewer.setComparator(new ViewerComparator());
+        categoryViewer.addFilter(new EmptyCategoryFilter());
+
+		categoryViewer.addSelectionChangedListener(event -> {
+			ICategory element = (ICategory) ((IStructuredSelection) event.getSelection()).getFirstElement();
+			setDetails(element);
+		});
+        categoryViewer.setInput(workingCopy.getDefinedCategoryIds());
+
+		updateCategoryCheckState();
+    }
+
+	/**
+	 * Updates the check and grey state of the categories in the category viewer.
+	 *
+	 * @since 3.2
+	 */
+	private void updateCategoryCheckState() {
+		ICategory[] enabledCategories = getEnabledCategories();
+		ICategory[] partiallyEnabledCategories = getPartialCategories();
+		Object[] allChecked = new Object[enabledCategories.length
+				+ partiallyEnabledCategories.length];
+		System.arraycopy(enabledCategories, 0, allChecked, 0, enabledCategories.length);
+		System.arraycopy(partiallyEnabledCategories, 0, allChecked, enabledCategories.length, partiallyEnabledCategories.length);
+		categoryViewer.setCheckedElements(allChecked);
+		categoryViewer.setGrayedElements(partiallyEnabledCategories);
+	}
+
+    private ICategory[] getPartialCategories() {
+		return WorkbenchActivityHelper.resolveCategories(workingCopy,
+				InternalActivityHelper
+						.getPartiallyEnabledCategories(workingCopy));
+	}
+
+	private ICategory[] getEnabledCategories() {
+		return WorkbenchActivityHelper.resolveCategories(workingCopy,
+				InternalActivityHelper.getEnabledCategories(workingCopy));
+	}
+
+    protected void setDetails(ICategory category) {
+        if (category == null) {
+            clearDetails();
+            return;
+        }
+        Set categories = null;
+        if (WorkbenchActivityHelper.isEnabled(workingCopy, category.getId())) {
+            categories = WorkbenchActivityHelper.getDisabledCategories(
+                    workingCopy, category.getId());
+
+        } else {
+            categories = WorkbenchActivityHelper.getEnabledCategories(
+                    workingCopy, category.getId());
+        }
+
+        categories = WorkbenchActivityHelper.getContainedCategories(
+                workingCopy, category.getId());
+        dependantViewer.setInput(categories);
+        try {
+            descriptionText.setText(category.getDescription());
+        } catch (NotDefinedException e) {
+            descriptionText.setText(""); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Clear the details area.
+     */
+    protected void clearDetails() {
+        dependantViewer.setInput(Collections.EMPTY_SET);
+        descriptionText.setText(""); //$NON-NLS-1$
+    }
+
+	@Override
+    public void init(IWorkbench workbench) {
+        this.workbench = workbench;
+        workingCopy = workbench.getActivitySupport().createWorkingCopy();
+        setPreferenceStore(WorkbenchPlugin.getDefault().getPreferenceStore());
+    }
+
+    /**
+     * Return whether the category is locked.
+     *
+     * @param category
+     *            the category to test
+     * @return whether the category is locked
+     */
+    protected boolean isLocked(ICategory category) {
+        return !WorkbenchActivityHelper.getDisabledCategories(workingCopy,
+                category.getId()).isEmpty();
+    }
+
+    @Override
+	public boolean performOk() {
+		if (allowAdvanced) {
+			enabler.updateActivityStates();
+		}
+
+        workbench.getActivitySupport().setEnabledActivityIds(
+                workingCopy.getEnabledActivityIds());
+        getPreferenceStore().setValue(
+                IPreferenceConstants.SHOULD_PROMPT_FOR_ENABLEMENT,
+                activityPromptButton.getSelection());
+        return true;
+    }
+
+    @Override
+	protected void performDefaults() {
+        super.performDefaults();
+        activityPromptButton.setSelection(getPreferenceStore()
+                .getDefaultBoolean(
+                        IPreferenceConstants.SHOULD_PROMPT_FOR_ENABLEMENT));
+		if (allowAdvanced) {
+			enabler.restoreDefaults();
+			return;
+		}
+
+        Set defaultEnabled = new HashSet();
+        Set activityIds = workingCopy.getDefinedActivityIds();
+        for (Iterator i = activityIds.iterator(); i.hasNext();) {
+            String activityId = (String) i.next();
+            IActivity activity = workingCopy.getActivity(activityId);
+            try {
+                if (activity.isDefaultEnabled()) {
+                    defaultEnabled.add(activityId);
+                }
+            } catch (NotDefinedException e) {
+                // this can't happen - we're iterating over defined activities.
+            }
+        }
+
+        workingCopy.setEnabledActivityIds(defaultEnabled);
+    }
+
+	@Override
+    public void setInitializationData(IConfigurationElement config,
+            String propertyName, Object data) {
+        if (data instanceof Hashtable) {
+            Hashtable table = (Hashtable)data;
+            allowAdvanced = Boolean.valueOf((String) table.remove(ALLOW_ADVANCED)).booleanValue();
+            strings.putAll(table);
+        }
+    }
+
+    @Override
+	public void dispose() {
+		if ((workingCopy != null) && (!allowAdvanced)) {
+				workingCopy.removeActivityManagerListener((CategoryLabelProvider) categoryViewer.getLabelProvider());
+    	}
+    	super.dispose();
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/ActivityEvent.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/ActivityEvent.java
new file mode 100644
index 0000000..4e55ea6
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/ActivityEvent.java
@@ -0,0 +1,195 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.activities;
+
+/**
+ * An instance of this class describes changes to an instance of
+ * <code>IActivity</code>.  This class does not give details as to the
+ * specifics of a change, only that the given property on the source object has
+ * changed.
+ * <p>
+ * This class is not intended to be extended by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @see IActivityListener#activityChanged(ActivityEvent)
+ */
+public final class ActivityEvent {
+    private IActivity activity;
+
+    private boolean activityRequirementBindingsChanged;
+
+    private boolean activityPatternBindingsChanged;
+
+    private boolean definedChanged;
+
+    private boolean enabledChanged;
+
+    private boolean defaultEnabledChanged;
+
+    private boolean nameChanged;
+
+    private boolean descriptionChanged;
+
+    /**
+     * Creates a new instance of this class. Since 3.1 this method will assume
+     * that the default enabled state has not changed.
+     *
+     * @param activity
+     *            the instance of the interface that changed.
+     * @param activityRequirementBindingsChanged
+     *            <code>true</code>, iff the activityRequirementBindings
+     *            property changed.
+     * @param activityPatternBindingsChanged
+     *            <code>true</code>, iff the activityPatternBindings property
+     *            changed.
+     * @param definedChanged
+     *            <code>true</code>, iff the defined property changed.
+     * @param descriptionChanged
+     *            <code>true</code>, iff the description property changed.
+     * @param enabledChanged
+     *            <code>true</code>, iff the enabled property changed.
+     * @param nameChanged
+     *            <code>true</code>, iff the name property changed.
+     */
+    public ActivityEvent(IActivity activity,
+            boolean activityRequirementBindingsChanged,
+            boolean activityPatternBindingsChanged, boolean definedChanged,
+            boolean descriptionChanged, boolean enabledChanged,
+            boolean nameChanged) {
+
+        this(activity,
+                activityRequirementBindingsChanged,
+                activityPatternBindingsChanged,
+                definedChanged,
+                descriptionChanged,
+                enabledChanged,
+                nameChanged,
+                false);
+    }
+
+    /**
+     * Creates a new instance of this class.
+     *
+     * @param activity
+     *        the instance of the interface that changed.
+     * @param activityRequirementBindingsChanged
+     *        <code>true</code>, iff the activityRequirementBindings property changed.
+     * @param activityPatternBindingsChanged
+     *        <code>true</code>, iff the activityPatternBindings property changed.
+     * @param definedChanged
+     *        <code>true</code>, iff the defined property changed.
+     * @param descriptionChanged
+     * 		  <code>true</code>, iff the description property changed.
+     * @param enabledChanged
+     *      <code>true</code>, iff the enabled property changed.
+     * @param nameChanged
+     *        <code>true</code>, iff the name property changed.
+     * @param defaultEnabledChanged
+     * 		  <code>true</code>, iff the default enabled property changed.
+     * @since 3.1
+     */
+    public ActivityEvent(IActivity activity,
+            boolean activityRequirementBindingsChanged,
+            boolean activityPatternBindingsChanged, boolean definedChanged,
+            boolean descriptionChanged, boolean enabledChanged,
+            boolean nameChanged,
+            boolean defaultEnabledChanged) {
+        if (activity == null) {
+			throw new NullPointerException();
+		}
+
+        this.activity = activity;
+        this.activityRequirementBindingsChanged = activityRequirementBindingsChanged;
+        this.activityPatternBindingsChanged = activityPatternBindingsChanged;
+        this.definedChanged = definedChanged;
+        this.enabledChanged = enabledChanged;
+        this.nameChanged = nameChanged;
+        this.descriptionChanged = descriptionChanged;
+        this.defaultEnabledChanged = defaultEnabledChanged;
+    }
+
+
+    /**
+     * Returns the instance of the interface that changed.
+     *
+     * @return the instance of the interface that changed. Guaranteed not to be
+     *         <code>null</code>.
+     */
+    public IActivity getActivity() {
+        return activity;
+    }
+
+    /**
+     * Returns whether or not the defined property changed.
+     *
+     * @return <code>true</code>, iff the defined property changed.
+     */
+    public boolean hasDefinedChanged() {
+        return definedChanged;
+    }
+
+    /**
+     * Returns whether or not the enabled property changed.
+     *
+     * @return <code>true</code>, iff the enabled property changed.
+     */
+    public boolean hasEnabledChanged() {
+        return enabledChanged;
+    }
+
+    /**
+     * Returns whether or not the default enabled property changed.
+     *
+     * @return <code>true</code>, iff the default enabled property changed.
+     * @since 3.1
+     */
+    public boolean hasDefaultEnabledChanged() {
+        return defaultEnabledChanged;
+    }
+
+    /**
+     * Returns whether or not the name property changed.
+     *
+     * @return <code>true</code>, iff the name property changed.
+     */
+    public boolean hasNameChanged() {
+        return nameChanged;
+    }
+
+    /**
+     * Returns whether or not the description property changed.
+     *
+     * @return <code>true</code>, iff the description property changed.
+     */
+    public boolean hasDescriptionChanged() {
+        return descriptionChanged;
+    }
+
+    /**
+     * Returns whether or not the activityRequirementBindings property changed.
+     *
+     * @return <code>true</code>, iff the activityRequirementBindings property changed.
+     */
+    public boolean haveActivityRequirementBindingsChanged() {
+        return activityRequirementBindingsChanged;
+    }
+
+    /**
+     * Returns whether or not the activityPatternBindings property changed.
+     *
+     * @return <code>true</code>, iff the activityPatternBindings property changed.
+     */
+    public boolean haveActivityPatternBindingsChanged() {
+        return activityPatternBindingsChanged;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/ActivityManagerEvent.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/ActivityManagerEvent.java
new file mode 100644
index 0000000..686dbe1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/ActivityManagerEvent.java
@@ -0,0 +1,216 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.activities;
+
+import java.util.Set;
+
+import org.eclipse.ui.internal.util.Util;
+
+/**
+ * An instance of this class describes changes to an instance of
+ * <code>IActivityManager</code>.  This class does not give details as to the
+ * specifics of a change, only that the given property on the source object has
+ * changed.
+ *
+ * <p>
+ * This class is not intended to be extended by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @see IActivityManagerListener#activityManagerChanged(ActivityManagerEvent)
+ */
+public final class ActivityManagerEvent {
+    private IActivityManager activityManager;
+
+    private boolean definedActivityIdsChanged;
+
+    private boolean definedCategoryIdsChanged;
+
+    private boolean enabledActivityIdsChanged;
+
+    /**
+     * The set of activity identifiers (strings) that were defined before the
+     * change occurred. If the defined activities did not changed, then this
+     * value is <code>null</code>.
+     */
+    private final Set previouslyDefinedActivityIds;
+
+    /**
+     * The set of category identifiers (strings) that were defined before the
+     * change occurred. If the defined category did not changed, then this value
+     * is <code>null</code>.
+     */
+    private final Set previouslyDefinedCategoryIds;
+
+    /**
+     * The set of activity identifiers (strings) that were enabled before the
+     * change occurred. If the enabled activities did not changed, then this
+     * value is <code>null</code>.
+     */
+    private final Set previouslyEnabledActivityIds;
+
+    /**
+     * Creates a new instance of this class.
+     *
+     * @param activityManager
+     *            the instance of the interface that changed.
+     * @param definedActivityIdsChanged
+     *            <code>true</code>, iff the definedActivityIds property
+     *            changed.
+     * @param definedCategoryIdsChanged
+     *            <code>true</code>, iff the definedCategoryIds property
+     *            changed.
+     * @param enabledActivityIdsChanged
+     *            <code>true</code>, iff the enabledActivityIds property
+     *            changed.
+     * @param previouslyDefinedActivityIds
+     *            the set of identifiers to previously defined activities. This
+     *            set may be empty. If this set is not empty, it must only
+     *            contain instances of <code>String</code>. This set must be
+     *            <code>null</code> if definedActivityIdsChanged is
+     *            <code>false</code> and must not be null if
+     *            definedActivityIdsChanged is <code>true</code>.
+     * @param previouslyDefinedCategoryIds
+     *            the set of identifiers to previously defined category. This
+     *            set may be empty. If this set is not empty, it must only
+     *            contain instances of <code>String</code>. This set must be
+     *            <code>null</code> if definedCategoryIdsChanged is
+     *            <code>false</code> and must not be null if
+     *            definedCategoryIdsChanged is <code>true</code>.
+     * @param previouslyEnabledActivityIds
+     *            the set of identifiers to previously enabled activities. This
+     *            set may be empty. If this set is not empty, it must only
+     *            contain instances of <code>String</code>. This set must be
+     *            <code>null</code> if enabledActivityIdsChanged is
+     *            <code>false</code> and must not be null if
+     *            enabledActivityIdsChanged is <code>true</code>.
+     */
+    public ActivityManagerEvent(IActivityManager activityManager,
+            boolean definedActivityIdsChanged,
+            boolean definedCategoryIdsChanged,
+            boolean enabledActivityIdsChanged,
+            final Set previouslyDefinedActivityIds,
+            final Set previouslyDefinedCategoryIds,
+            final Set previouslyEnabledActivityIds) {
+        if (activityManager == null) {
+			throw new NullPointerException();
+		}
+
+        if (!definedActivityIdsChanged && previouslyDefinedActivityIds != null) {
+			throw new IllegalArgumentException();
+		}
+
+        if (!definedCategoryIdsChanged && previouslyDefinedCategoryIds != null) {
+			throw new IllegalArgumentException();
+		}
+
+        if (!enabledActivityIdsChanged && previouslyEnabledActivityIds != null) {
+			throw new IllegalArgumentException();
+		}
+
+        if (definedActivityIdsChanged) {
+            this.previouslyDefinedActivityIds = Util.safeCopy(
+                    previouslyDefinedActivityIds, String.class);
+        } else {
+            this.previouslyDefinedActivityIds = null;
+        }
+
+        if (definedCategoryIdsChanged) {
+            this.previouslyDefinedCategoryIds = Util.safeCopy(
+                    previouslyDefinedCategoryIds, String.class);
+        } else {
+            this.previouslyDefinedCategoryIds = null;
+        }
+
+        if (enabledActivityIdsChanged) {
+            this.previouslyEnabledActivityIds = Util.safeCopy(
+                    previouslyEnabledActivityIds, String.class);
+        } else {
+            this.previouslyEnabledActivityIds = null;
+        }
+
+        this.activityManager = activityManager;
+        this.definedActivityIdsChanged = definedActivityIdsChanged;
+        this.definedCategoryIdsChanged = definedCategoryIdsChanged;
+        this.enabledActivityIdsChanged = enabledActivityIdsChanged;
+    }
+
+    /**
+     * Returns the instance of the interface that changed.
+     *
+     * @return the instance of the interface that changed. Guaranteed not to be
+     *         <code>null</code>.
+     */
+    public IActivityManager getActivityManager() {
+        return activityManager;
+    }
+
+    /**
+     * Returns the activity identifiers that were previously defined.
+     *
+     * @return The set of defined activity identifiers before the changed; may
+     *         be empty, but never <code>null</code>. This set will only
+     *         contain strings.
+     */
+    public final Set getPreviouslyDefinedActivityIds() {
+        return previouslyDefinedActivityIds;
+    }
+
+    /**
+     * Returns the category identifiers that were previously defined.
+     *
+     * @return The set of defined category identifiers before the changed; may
+     *         be empty, but never <code>null</code>. This set will only
+     *         contain strings.
+     */
+    public final Set getPreviouslyDefinedCategoryIds() {
+        return previouslyDefinedCategoryIds;
+    }
+
+    /**
+     * Returns the activity identifiers that were previously enabled.
+     *
+     * @return The set of enabled activity identifiers before the changed; may
+     *         be empty, but never <code>null</code>. This set will only
+     *         contain strings.
+     */
+    public final Set getPreviouslyEnabledActivityIds() {
+        return previouslyEnabledActivityIds;
+    }
+
+    /**
+     * Returns whether or not the definedActivityIds property changed.
+     *
+     * @return <code>true</code>, iff the definedActivityIds property changed.
+     */
+    public boolean haveDefinedActivityIdsChanged() {
+        return definedActivityIdsChanged;
+    }
+
+    /**
+     * Returns whether or not the definedCategoryIds property changed.
+     *
+     * @return <code>true</code>, iff the definedCategoryIds property changed.
+     */
+    public boolean haveDefinedCategoryIdsChanged() {
+        return definedCategoryIdsChanged;
+    }
+
+    /**
+     * Returns whether or not the enabledActivityIds property changed.
+     *
+     * @return <code>true</code>, iff the enabledActivityIds property changed.
+     */
+    public boolean haveEnabledActivityIdsChanged() {
+        return enabledActivityIdsChanged;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/CategoryEvent.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/CategoryEvent.java
new file mode 100644
index 0000000..072b54f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/CategoryEvent.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.activities;
+
+/**
+ * An instance of this class describes changes to an instance of
+ * <code>ICategory</code>.  This class does not give details as to the
+ * specifics of a change, only that the given property on the source object has
+ * changed.
+ *
+ * <p>
+ * This class is not intended to be extended by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @see ICategoryListener#categoryChanged(CategoryEvent)
+ */
+public final class CategoryEvent {
+    private ICategory category;
+
+    private boolean categoryActivityBindingsChanged;
+
+    private boolean definedChanged;
+
+    private boolean nameChanged;
+
+    private boolean descriptionChanged;
+
+    /**
+     * Creates a new instance of this class.
+     *
+     * @param category
+     *        the instance of the interface that changed.
+     * @param categoryActivityBindingsChanged
+     *        <code>true</code>, iff the categoryActivityBindings property changed.
+     * @param definedChanged
+     *        <code>true</code>, iff the defined property changed.
+     * @param descriptionChanged
+     *        <code>true</code>, iff the description property changed.
+     * @param nameChanged
+     *        <code>true</code>, iff the name property changed.
+     */
+    public CategoryEvent(ICategory category,
+            boolean categoryActivityBindingsChanged, boolean definedChanged,
+            boolean descriptionChanged, boolean nameChanged) {
+        if (category == null) {
+			throw new NullPointerException();
+		}
+
+        this.category = category;
+        this.categoryActivityBindingsChanged = categoryActivityBindingsChanged;
+        this.definedChanged = definedChanged;
+        this.nameChanged = nameChanged;
+        this.descriptionChanged = descriptionChanged;
+    }
+
+    /**
+     * Returns the instance of the interface that changed.
+     *
+     * @return the instance of the interface that changed. Guaranteed not to be
+     *         <code>null</code>.
+     */
+    public ICategory getCategory() {
+        return category;
+    }
+
+    /**
+     * Returns whether or not the defined property changed.
+     *
+     * @return <code>true</code>, iff the defined property changed.
+     */
+    public boolean hasDefinedChanged() {
+        return definedChanged;
+    }
+
+    /**
+     * Returns whether or not the name property changed.
+     *
+     * @return <code>true</code>, iff the name property changed.
+     */
+    public boolean hasNameChanged() {
+        return nameChanged;
+    }
+
+    /**
+     * Returns whether or not the description property changed.
+     *
+     * @return <code>true</code>, iff the description property changed.
+     */
+    public boolean hasDescriptionChanged() {
+        return descriptionChanged;
+    }
+
+    /**
+     * Returns whether or not the categoryActivityBindings property changed.
+     *
+     * @return <code>true</code>, iff the categoryActivityBindings property changed.
+     */
+    public boolean haveCategoryActivityBindingsChanged() {
+        return categoryActivityBindingsChanged;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/IActivity.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/IActivity.java
new file mode 100644
index 0000000..b472238
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/IActivity.java
@@ -0,0 +1,182 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.activities;
+
+import java.util.Set;
+
+import org.eclipse.core.expressions.Expression;
+
+/**
+ * An instance of this interface is an activity as defined by the extension
+ * point <code>org.eclipse.ui.activities</code>.
+ *
+ * <p>
+ * An instance of this interface can be obtained from an instance of
+ * <code>IActivityManager</code> for any identifier, whether or not an activity
+ * with that identifier is defined in the extension registry.
+ * </p>
+ *
+ * <p>
+ * The handle-based nature of this API allows it to work well with runtime
+ * plugin activation and deactivation, which can cause dynamic changes to the
+ * extension registry.  A client may get an <code>IActivity</code> handle that
+ * is currently undefined ({@link #isDefined()} equals <code>false</code>) and
+ * listen for it to become defined.
+ * </p>
+ *
+ * <p>
+ * This interface is not intended to be extended or implemented by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @see IActivityManager
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IActivity extends Comparable {
+
+    /**
+     * Registers an instance of <code>IActivityListener</code> to listen for
+     * changes to properties of this instance.
+     *
+     * @param activityListener
+     *            the instance to register. Must not be <code>null</code>.
+     *            If an attempt is made to register an instance which is
+     *            already registered with this instance, no operation is
+     *            performed.
+     */
+    void addActivityListener(IActivityListener activityListener);
+
+    /**
+     * Returns the set of activity requirement bindings for this instance.
+     * <p>
+     * This method will return all activity requirement bindings for this
+     * instance, whether or not this instance is defined.
+     * </p>
+     * <p>
+     * Notification is sent to all registered listeners if this property
+     * changes.
+     * </p>
+     *
+     * @return the set of activity requirement bindings. This set may be empty,
+     *         but is guaranteed not to be <code>null</code>. If this set is
+     *         not empty, it is guaranteed to only contain instances of
+     * 		   <code>IActivityRequirementBinding</code>.
+     * @see IActivityRequirementBinding
+     */
+    Set getActivityRequirementBindings();
+
+    /**
+     * Returns the set of activity pattern bindings for this instance.
+     * <p>
+     * This method will return all activity pattern bindings for this instance,
+     * whether or not this instance is defined.
+     * </p>
+     * <p>
+     * Notification is sent to all registered listeners if this property
+     * changes.
+     * </p>
+     *
+     * @return the set of activity pattern bindings. This set may be empty, but
+     *         is guaranteed not to be <code>null</code>. If this set is not
+     *        empty, it is guaranteed to only contain instances of <code>IActivityPatternBinding</code>.
+     * @see IActivityPatternBinding
+     */
+    Set getActivityPatternBindings();
+
+    /**
+     * Returns the identifier of this instance.
+     *
+     * @return the identifier of this instance. Guaranteed not to be <code>null</code>.
+     */
+    String getId();
+
+    /**
+     * Returns the name of this instance suitable for display to the user.
+     * <p>
+     * Notification is sent to all registered listeners if this property
+     * changes.
+     * </p>
+     *
+     * @return the name of this instance. Guaranteed not to be <code>null</code>.
+     * @throws NotDefinedException
+     *             if this instance is not defined.
+     */
+    String getName() throws NotDefinedException;
+
+    /**
+     * Returns the description of this instance suitable for display to the user.
+     * <p>
+     * Notification is sent to all registered listeners if this property
+     * changes.
+     * </p>
+     *
+     * @return the description of this instance. Guaranteed not to be <code>null</code>.
+     * @throws NotDefinedException
+     *             if this instance is not defined.
+     */
+    String getDescription() throws NotDefinedException;
+
+    /**
+     * Returns whether or not this instance is defined.  A defined activity
+     * may have a name, description and bindings (both pattern and relational).
+     * <p>
+     * Notification is sent to all registered listeners if this property
+     * changes.
+     * </p>
+     *
+     * @return <code>true</code>, iff this instance is defined.
+     */
+    boolean isDefined();
+
+    /**
+     * Returns whether or not this instance is enabled.
+     * <p>
+     * Notification is sent to all registered listeners if this property
+     * changes.
+     * </p>
+     *
+     * @return <code>true</code>, iff this instance is enabled.
+     */
+    boolean isEnabled();
+
+    /**
+     * Returns whether or not this instance should be enabled by default.
+     *
+     * @return <code>true</code>, iff this instance should be enabled by default.
+     * @throws NotDefinedException
+     *             if this instance is not defined.
+     * @since 3.1
+     */
+    boolean isDefaultEnabled() throws NotDefinedException;
+
+    /**
+     * Removes an instance of <code>IActivityListener</code> listening
+     * for changes to properties of this instance.
+     *
+     * @param activityListener
+     *            the instance to remove. Must not be <code>null</code>.
+     *            If an attempt is made to remove an instance which is not
+     *            already registered with this instance, no operation is
+     *            performed.
+     */
+    void removeActivityListener(IActivityListener activityListener);
+
+    /**
+	 * Return an expression used to enable and disable this activity. If the
+	 * expression is not <code>null</code>, this activity will be entirely
+	 * controlled by the expression state.
+	 *
+	 * @return The core expression, or <code>null</code>
+	 * @since 3.4
+	 */
+    Expression getExpression();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/IActivityListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/IActivityListener.java
new file mode 100644
index 0000000..8c7fd0c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/IActivityListener.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.activities;
+
+/**
+ * An instance of this interface can be used by clients to receive notification
+ * of changes to one or more instances of <code>IActivity</code>.
+ * <p>
+ * This interface may be implemented by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @see IActivity#addActivityListener(IActivityListener)
+ * @see IActivity#removeActivityListener(IActivityListener)
+ */
+public interface IActivityListener {
+
+    /**
+     * Notifies that one or more properties of an instance of <code>IActivity</code>
+     * have changed. Specific details are described in the <code>ActivityEvent</code>.
+     *
+     * @param activityEvent
+     *            the activity event. Guaranteed not to be <code>null</code>.
+     */
+    void activityChanged(ActivityEvent activityEvent);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/IActivityManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/IActivityManager.java
new file mode 100644
index 0000000..2164592
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/IActivityManager.java
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.activities;
+
+import java.util.Set;
+
+/**
+ * An instance of this interface allows clients to manage activities, as
+ * defined by the extension point <code>org.eclipse.ui.activities</code>.
+ * <p>
+ * This interface is not intended to be extended or implemented by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IActivityManager {
+
+    /**
+     * Registers an instance of <code>IActivityManagerListener</code> to
+     * listen for changes to properties of this instance.
+     *
+     * @param activityManagerListener
+     *            the instance to register. Must not be <code>null</code>.
+     *            If an attempt is made to register an instance which is
+     *            already registered with this instance, no operation is
+     *            performed.
+     */
+    void addActivityManagerListener(
+            IActivityManagerListener activityManagerListener);
+
+    /**
+     * Returns an instance of <code>IActivity</code> given an identifier.
+     *
+     * @param activityId
+     *            an identifier. Must not be <code>null</code>
+     * @return an instance of <code>IActivity</code>.
+     */
+    IActivity getActivity(String activityId);
+
+    /**
+     * Returns an instance of <code>ICategory</code> given an identifier.
+     *
+     * @param categoryId
+     *            an identifier. Must not be <code>null</code>
+     * @return an instance of <code>ICategory</code>.
+     */
+    ICategory getCategory(String categoryId);
+
+    /**
+     * Returns the set of identifiers to defined activities.
+     * <p>
+     * Notification is sent to all registered listeners if this property
+     * changes.
+     * </p>
+     *
+     * @return the set of identifiers to defined activities. This set may be
+     *         empty, but is guaranteed not to be <code>null</code>. If this
+     *         set is not empty, it is guaranteed to only contain instances of
+     *         <code>String</code>.
+     */
+    Set getDefinedActivityIds();
+
+    /**
+     * Returns the set of identifiers to defined categories.
+     * <p>
+     * Notification is sent to all registered listeners if this property
+     * changes.
+     * </p>
+     *
+     * @return the set of identifiers to defined categories. This set may be
+     *         empty, but is guaranteed not to be <code>null</code>. If this
+     *         set is not empty, it is guaranteed to only contain instances of
+     *         <code>String</code>.
+     */
+    Set getDefinedCategoryIds();
+
+    /**
+     * Returns the set of identifiers to enabled activities.
+     * <p>
+     * Notification is sent to all registered listeners if this property
+     * changes.
+     * </p>
+     *
+     * @return the set of identifiers to enabled activities. This set may be
+     *         empty, but is guaranteed not to be <code>null</code>. If this
+     *         set is not empty, it is guaranteed to only contain instances of
+     *         <code>String</code>.
+     */
+    Set getEnabledActivityIds();
+
+    /**
+     * Returns an instance of <code>IIdentifier</code> given an identifier.
+     *
+     * @param identifierId
+     *            an identifier. Must not be <code>null</code>
+     * @return an instance of <code>IIdentifier</code>.
+     */
+    IIdentifier getIdentifier(String identifierId);
+
+    /**
+     * Removes an instance of <code>IActivityManagerListener</code>
+     * listening for changes to properties of this instance.
+     *
+     * @param activityManagerListener
+     *            the instance to remove. Must not be <code>null</code>.
+     *            If an attempt is made to remove an instance which is not
+     *            already registered with this instance, no operation is
+     *            performed.
+     */
+    void removeActivityManagerListener(
+            IActivityManagerListener activityManagerListener);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/IActivityManagerListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/IActivityManagerListener.java
new file mode 100644
index 0000000..19291ef
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/IActivityManagerListener.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.activities;
+
+/**
+ * An instance of this interface can be used by clients to receive notification
+ * of changes to one or more instances of <code>IActivityManager</code>.
+ * <p>
+ * This interface may be implemented by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @see IActivityManager#addActivityManagerListener(IActivityManagerListener)
+ * @see IActivityManager#removeActivityManagerListener(IActivityManagerListener)
+ */
+public interface IActivityManagerListener {
+
+    /**
+     * Notifies that one or more properties of an instance of <code>IActivityManager</code>
+     * have changed. Specific details are described in the <code>ActivityManagerEvent</code>.
+     *
+     * @param activityManagerEvent
+     *            the activity manager event. Guaranteed not to be <code>null</code>.
+     */
+    void activityManagerChanged(ActivityManagerEvent activityManagerEvent);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/IActivityPatternBinding.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/IActivityPatternBinding.java
new file mode 100644
index 0000000..9c52e8d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/IActivityPatternBinding.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.activities;
+
+import java.util.regex.Pattern;
+
+/**
+ * An instance of this interface represents a binding between an activity and a
+ * regular expression pattern.  It's typically unnecessary to use this interface
+ * directly.  Rather, clients wishing to test strings against activity patterns
+ * should use instances of <code>IIdentifier</code>.
+ * <p>
+ * This interface is not intended to be extended or implemented by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @see IActivity
+ * @see IIdentifier
+ * @see IActivityManager#getIdentifier(String)
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IActivityPatternBinding extends Comparable {
+
+    /**
+     * Returns the identifier of the activity represented in this binding.
+     *
+     * @return the identifier of the activity represented in this binding.
+     *         Guaranteed not to be <code>null</code>.
+     */
+    String getActivityId();
+
+    /**
+	 * Returns the pattern represented in this binding. This pattern should
+	 * conform to the regular expression syntax described by the
+	 * <code>java.util.regex.Pattern</code> class. If
+	 * {@link #isEqualityPattern()} is <code>true</code> a Pattern will be
+	 * generated based on the escaped version of the String returned by
+	 * {@link #getString()}.
+	 *
+	 * @return the pattern. Guaranteed not to be <code>null</code>.
+	 */
+	Pattern getPattern();
+
+    /**
+	 * If {@link #isEqualityPattern()} is <code>true</code> this will return
+	 * the raw <em>pattern</em> string. Otherwise it will return the string
+	 * version of the compiled pattern.
+	 *
+	 * @return The raw <em>pattern</em> string, or the string version of the
+	 *         compiled pattern, depending on {@link #isEqualityPattern()}.
+	 * @since 3.4
+	 */
+	String getString();
+
+	/**
+	 * Answers whether or not the pattern should be treated as a regular string
+	 * or a regular expression. If <code>true</code>, this pattern binding
+	 * will represent an equality match between the pattern and a target ID
+	 * rather than a regular expression match.
+	 *
+	 * @return whether the pattern should be treated as regular string
+	 * @since 3.4
+	 */
+	boolean isEqualityPattern();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/IActivityRequirementBinding.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/IActivityRequirementBinding.java
new file mode 100644
index 0000000..8576822
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/IActivityRequirementBinding.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.activities;
+
+/**
+ * An instance of this interface represents a binding between two activities.
+ * The relationship can be interpreted as 'activity needs requiredActivity to
+ * be enabled'.
+ * Enablement of the activity requires enablement of the required activity.
+ *
+ * <p>
+ * This interface is not intended to be extended or implemented by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @see IActivity
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IActivityRequirementBinding extends Comparable {
+
+    /**
+     * Returns the identifier of the activity represented in this
+     * binding.
+     *
+     * @return the identifier of the activity represented in this
+     *         binding. Guaranteed not to be <code>null</code>.
+     */
+    String getActivityId();
+
+    /**
+     * Returns the identifier of the required activity represented in this
+     * binding.  The enablement of the activity described by {@link #getActivityId()}
+     * requires the enablement of this activity.
+     *
+     * @return the identifier of the required activity represented in this
+     *         binding. Guaranteed not to be <code>null</code>.
+     */
+    String getRequiredActivityId();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/ICategory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/ICategory.java
new file mode 100644
index 0000000..8a3c3bf
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/ICategory.java
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.activities;
+
+import java.util.Set;
+
+/**
+ * An instance of this interface is a category as defined by the extension
+ * point <code>org.eclipse.ui.activities</code>.
+ * <p>
+ * An instance of this interface can be obtained from an instance of
+ * <code>IActivityManager</code> for any identifier, whether or not a category
+ * with that identifier is defined in the extension registry.
+ * </p>
+ * <p>
+ * The handle-based nature of this API allows it to work well with runtime
+ * plugin activation and deactivation, which can cause dynamic changes to the
+ * extension registry.
+ * </p>
+ * <p>
+ * This interface is not intended to be extended or implemented by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @see IActivityManager
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface ICategory extends Comparable {
+
+    /**
+     * Registers an instance of <code>ICategoryListener</code> to listen for
+     * changes to properties of this instance.
+     *
+     * @param categoryListener
+     *            the instance to register. Must not be <code>null</code>.
+     *            If an attempt is made to register an instance which is
+     *            already registered with this instance, no operation is
+     *            performed.
+     */
+    void addCategoryListener(ICategoryListener categoryListener);
+
+    /**
+     * Returns the set of category activity bindings for this instance.
+     * <p>
+     * This method will return all category activity bindings for this
+     * instance, whether or not this instance is defined.
+     * </p>
+     * <p>
+     * Notification is sent to all registered listeners if this property
+     * changes.
+     * </p>
+     *
+     * @return the set of category activity bindings. This set may be empty,
+     *         but is guaranteed not to be <code>null</code>. If this set is
+     *         not empty, it is guaranteed to only contain instances of <code>ICategoryActivityBinding</code>.
+     * @see ICategoryActivityBinding
+     */
+    Set getCategoryActivityBindings();
+
+    /**
+     * Returns the identifier of this instance.
+     *
+     * @return the identifier of this instance. Guaranteed not to be <code>null</code>.
+     */
+    String getId();
+
+    /**
+     * Returns the name of this instance suitable for display to the user.
+     * <p>
+     * Notification is sent to all registered listeners if this property
+     * changes.
+     * </p>
+     *
+     * @return the name of this instance. Guaranteed not to be <code>null</code>.
+     * @throws NotDefinedException
+     *             if this instance is not defined.
+     */
+    String getName() throws NotDefinedException;
+
+    /**
+     * Returns the description of this instance suitable for display to the user.
+     * <p>
+     * Notification is sent to all registered listeners if this property
+     * changes.
+     * </p>
+     *
+     * @return the description of this instance. Guaranteed not to be <code>null</code>.
+     * @throws NotDefinedException
+     *             if this instance is not defined.
+     */
+    String getDescription() throws NotDefinedException;
+
+    /**
+     * Returns whether or not this instance is defined.
+     * <p>
+     * Notification is sent to all registered listeners if this property
+     * changes.
+     * </p>
+     *
+     * @return <code>true</code>, iff this instance is defined.
+     */
+    boolean isDefined();
+
+    /**
+     * Removes an instance of <code>ICategoryListener</code> listening
+     * for changes to properties of this instance.
+     *
+     * @param categoryListener
+     *            the instance to remove. Must not be <code>null</code>.
+     *            If an attempt is made to remove an instance which is not
+     *            already registered with this instance, no operation is
+     *            performed.
+     */
+    void removeCategoryListener(ICategoryListener categoryListener);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/ICategoryActivityBinding.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/ICategoryActivityBinding.java
new file mode 100644
index 0000000..f35d538
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/ICategoryActivityBinding.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.activities;
+
+/**
+ * An instance of this interface represents a binding between a category and an
+ * activity.
+ *
+ * <p>
+ * This interface is not intended to be extended or implemented by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @see IActivity
+ * @see ICategory
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface ICategoryActivityBinding extends Comparable {
+
+    /**
+     * Returns the identifier of the activity represented in this binding.
+     *
+     * @return the identifier of the activity represented in this binding.
+     *         Guaranteed not to be <code>null</code>.
+     */
+    String getActivityId();
+
+    /**
+     * Returns the identifier of the category represented in this binding.
+     *
+     * @return the identifier of the category represented in this binding.
+     *         Guaranteed not to be <code>null</code>.
+     */
+    String getCategoryId();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/ICategoryListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/ICategoryListener.java
new file mode 100644
index 0000000..456de3d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/ICategoryListener.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.activities;
+
+/**
+ * An instance of this interface can be used by clients to receive notification
+ * of changes to one or more instances of <code>ICategory</code>.
+ *
+ * <p>
+ * This interface may be implemented by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @see ICategory#addCategoryListener(ICategoryListener)
+ * @see ICategory#removeCategoryListener(ICategoryListener)
+ */
+public interface ICategoryListener {
+
+    /**
+     * Notifies that one or more properties of an instance of <code>ICategory</code>
+     * have changed. Specific details are described in the <code>CategoryEvent</code>.
+     *
+     * @param categoryEvent
+     *            the category event. Guaranteed not to be <code>null</code>.
+     */
+    void categoryChanged(CategoryEvent categoryEvent);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/IIdentifier.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/IIdentifier.java
new file mode 100644
index 0000000..09c8244
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/IIdentifier.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.activities;
+
+import java.util.Set;
+
+/**
+ * An instance of this interface can be obtained from an instance of
+ * <code>IActivityManager</code>for any identifier.
+ * <p>
+ * An <code>IIdentifier</code> is an object that offers an easy means to
+ * determine if a given string matches the pattern bindings of any IActivity
+ * objects.  Additionaly, one may query if an identifier is enabled.  An
+ * identifier is always considered enabled unless it matches only disabled activities.
+ * </p>
+ * <p>
+ * The handle-based nature of this API allows it to work well with runtime
+ * plugin activation and deactivation, which can cause dynamic changes to the
+ * extension registry.
+ * </p>
+ * <p>
+ * This interface is not intended to be extended or implemented by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @see IActivityManager#getIdentifier(String)
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IIdentifier extends Comparable {
+
+    /**
+     * Registers an instance of <code>IIdentifierListener</code> to listen
+     * for changes to properties of this instance.
+     *
+     * @param identifierListener
+     *            the instance to register. Must not be <code>null</code>.
+     *            If an attempt is made to register an instance which is
+     *            already registered with this instance, no operation is
+     *            performed.
+     */
+    void addIdentifierListener(IIdentifierListener identifierListener);
+
+    /**
+     * Returns the set of activity ids that this instance matches.  Each
+     * activity in this set will have at least one pattern binding that matches
+     * the string returned by {@link #getId()}.
+     * <p>
+     * Notification is sent to all registered listeners if this property
+     * changes.
+     * </p>
+     *
+     * @return the set of activity ids that this instance matches. This set may
+     *         be empty, but is guaranteed not to be <code>null</code>. If
+     *         this set is not empty, it is guaranteed to only contain
+     *         instances of <code>String</code>.
+     */
+    Set getActivityIds();
+
+    /**
+     * Returns the identifier of this instance.
+     *
+     * @return the identifier of this instance. Guaranteed not to be <code>null</code>.
+     */
+    String getId();
+
+    /**
+     * Returns whether or not this instance is enabled.  An identifier is always
+     * considered enabled unless it matches only disabled activities.
+     *
+     * <p>
+     * Notification is sent to all registered listeners if this property
+     * changes.
+     * </p>
+     *
+     * @return <code>true</code>, iff this instance is enabled.
+     */
+    boolean isEnabled();
+
+    /**
+     * Removes an instance of <code>IIdentifierListener</code> listening
+     * for changes to properties of this instance.
+     *
+     * @param identifierListener
+     *            the instance to remove. Must not be <code>null</code>.
+     *            If an attempt is made to remove an instance which is not
+     *            already registered with this instance, no operation is
+     *            performed.
+     */
+    void removeIdentifierListener(IIdentifierListener identifierListener);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/IIdentifierListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/IIdentifierListener.java
new file mode 100644
index 0000000..747a7e9
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/IIdentifierListener.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.activities;
+
+/**
+ * An instance of this interface can be used by clients to receive notification
+ * of changes to one or more instances of <code>IIdentifier</code>.
+ * <p>
+ * This interface may be implemented by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @see IIdentifier#addIdentifierListener(IIdentifierListener)
+ * @see IIdentifier#removeIdentifierListener(IIdentifierListener)
+ */
+public interface IIdentifierListener {
+
+    /**
+     * Notifies that one or more properties of an instance of <code>IIdentifier</code>
+     * have changed. Specific details are described in the <code>IdentifierEvent</code>.
+     *
+     * @param identifierEvent
+     *            the identifier event. Guaranteed not to be <code>null</code>.
+     */
+    void identifierChanged(IdentifierEvent identifierEvent);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/IMutableActivityManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/IMutableActivityManager.java
new file mode 100644
index 0000000..348e661
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/IMutableActivityManager.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.activities;
+
+import java.util.Set;
+
+/**
+ * An instance of this interface allows clients to manage activities, as
+ * defined by the extension point <code>org.eclipse.ui.activities</code>.
+ * <p>
+ * This interface extends <code>IActivityManager</code> by granting the ability
+ * to alter the set of currently enabled activities.
+ * </p>
+ * <p>
+ * This interface is not intended to be extended or implemented by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IMutableActivityManager extends IActivityManager {
+
+    /**
+     * Sets the set of identifiers to enabled activities.
+     *
+     * @param enabledActivityIds
+     *            the set of identifiers to enabled activities. This set may be
+     *            empty, but it must not be <code>null</code>. If this set
+     *            is not empty, it must only contain instances of <code>String</code>.
+     */
+    void setEnabledActivityIds(Set enabledActivityIds);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/ITriggerPoint.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/ITriggerPoint.java
new file mode 100644
index 0000000..dc45876
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/ITriggerPoint.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.activities;
+
+/**
+ * A trigger point represents a place within the Workbench that has the
+ * potential to enable activities. Instances of this class may be obtained from
+ * {@link org.eclipse.ui.activities.ITriggerPointManager#getTriggerPoint(String)}.
+ * Instances of this interface are passed as a parameter to
+ * {@link org.eclipse.ui.activities.ITriggerPointAdvisor#allow(ITriggerPoint, IIdentifier)}
+ * and may be used by the advisor to determine policy.
+ * <p>
+ * This interface is not intended to be extended or implemented by clients.
+ * </p>
+ *
+ * @see org.eclipse.ui.activities.ITriggerPointAdvisor
+ * @see org.eclipse.ui.activities.ITriggerPointManager
+ * @since 3.1
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface ITriggerPoint {
+
+	/**
+	 * The interactive hint key.  Value <code>"interactive"</code>.
+	 */
+	public static final String HINT_INTERACTIVE = "interactive"; //$NON-NLS-1$
+
+	/**
+	 * A hint key for activities that are enabled based on core expressions.
+	 *
+	 * @since 3.4
+	 */
+	public static final String HINT_PRE_UI = "pre_UI"; //$NON-NLS-1$
+
+	/**
+	 * Return the id of this trigger point.
+	 *
+	 * @return the id
+	 */
+	String getId();
+
+	/**
+	 * Return the hint with the given key defined on this trigger point.
+	 *
+	 * @param key the hint key
+	 * @return the hint
+	 */
+	String getStringHint(String key);
+
+
+	/**
+     * Return the hint with the given key defined on this trigger point as
+     * interpreted as a <code>boolean</code>.
+     *
+     * @param key the hint key
+     * @return the hint
+     * @see Boolean#valueOf(java.lang.String)
+     */
+	boolean getBooleanHint(String key);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/ITriggerPointAdvisor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/ITriggerPointAdvisor.java
new file mode 100644
index 0000000..d40f03d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/ITriggerPointAdvisor.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.activities;
+
+import java.util.Set;
+
+/**
+ * The trigger point advisor is a mechanism provided by the workbench that is
+ * consulted whenever code that is considered a trigger point is hit. It is the
+ * role of the advisor to determine what, if any, activities should be enabled
+ * as a consequence of this action. The advisor also has the option of vetoing
+ * the operation.
+ *
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ *
+ * @since 3.1
+ * @see org.eclipse.ui.activities.ITriggerPoint
+ */
+public interface ITriggerPointAdvisor {
+
+	/**
+	 * Answer whether the activities bound to the identifier should be enabled
+	 * when triggered by the provided trigger point.
+	 *
+	 * @param triggerPoint
+	 *            the trigger point to test
+	 * @param identifier
+	 *            the identifier to test against the trigger point
+	 * @return the set of activities that should be enabled if this the
+	 *         contribution represented by this identifier is to be used. If
+	 *         this is not <code>null</code>, the caller can proceed with
+	 *         usage of the contribution provided that the collection of
+	 *         activities is enabled. If this is <code>null</code>, the
+	 *         caller should assume that the operation involving the
+	 *         contribution should be aborted. If this method returns the empty
+	 *         set then the operation can proceed without any changes to
+	 *         activity enablement state. Please note that it is the callers
+	 *         responsibility to ensure that the Set returned by this method is
+	 *         actually enabled - after setting the enabled state of the
+	 *         required activities the change should be verified by consulting
+	 *         {@link IActivityManager#getEnabledActivityIds()}.
+	 */
+	Set allow(ITriggerPoint triggerPoint, IIdentifier identifier);
+
+	/**
+	 * Calculate the identifier's enabled state for a combination of activities
+	 * with and without enabled when core expressions.
+	 *
+	 * @param activityManager
+	 *            the activity manager
+	 * @param identifier
+	 *            the identifier to update
+	 *
+	 * @return <code>true</code> if this identifier should be enabled,
+	 *         <code>false</code> otherwise
+	 * @since 3.4
+	 */
+	boolean computeEnablement(IActivityManager activityManager, IIdentifier identifier);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/ITriggerPointManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/ITriggerPointManager.java
new file mode 100644
index 0000000..2cc5fd0
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/ITriggerPointManager.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.activities;
+
+import java.util.Set;
+
+/**
+ * Contains a collection of known trigger points. An instance of this class may
+ * be obtained from
+ * {@link org.eclipse.ui.activities.IWorkbenchActivitySupport#getTriggerPointManager()}.
+ * <p>
+ * This interface is not intended to be extended or implemented by clients.
+ * </p>
+ *
+ * @see org.eclipse.ui.activities.ITriggerPoint
+ * @since 3.1
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface ITriggerPointManager {
+
+	/**
+     * Constant representing the id of an unknown trigger point. Used by clients
+     * of {@link WorkbenchActivityHelper#allowUseOf(Object)} for trigger point
+     * determination logic.
+     */
+	public static final String UNKNOWN_TRIGGER_POINT_ID = "org.eclipse.ui.internal.UnknownTriggerPoint"; //$NON-NLS-1$
+
+	/**
+	 * Return the trigger point with the given id.
+	 *
+	 * @param id the trigger point id
+	 * @return the trigger point or <code>null</code>
+	 */
+	ITriggerPoint getTriggerPoint(String id);
+
+	/**
+	 * Return the set of defined trigger point ids.
+	 *
+	 * @return the defined ids.  Never <code>null</code> but may be empty.
+	 */
+	Set getDefinedTriggerPointIds();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/IWorkbenchActivitySupport.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/IWorkbenchActivitySupport.java
new file mode 100644
index 0000000..159b0a4
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/IWorkbenchActivitySupport.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.activities;
+
+import java.util.Set;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+
+/**
+ * An instance of this interface provides support for managing
+ * <code>IWorkbench</code> activities.  An instance of this interface may be
+ * obtained via {@link org.eclipse.ui.IWorkbench#getActivitySupport()}.
+ * <p>
+ * This interface is not intended to be extended or implemented by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IWorkbenchActivitySupport {
+
+    /**
+     * Returns the activity manager for the workbench.
+     *
+     * @return the activity manager for the workbench. Guaranteed not to be
+     *         <code>null</code>.
+     */
+    IActivityManager getActivityManager();
+
+    /**
+     * Sets the set of identifiers to enabled activities.
+     *
+     * @param enabledActivityIds
+     *            the set of identifiers to enabled activities. This set may be
+     *            empty, but it must not be <code>null</code>. If this set
+     *            is not empty, it must only contain instances of <code>String</code>.
+     */
+    void setEnabledActivityIds(Set enabledActivityIds);
+
+    /**
+     * Return the image associated with this activity.
+     *
+     * @param activity the activity
+     * @return the image associated with this activity.  Never <code>null</code>.
+     * @since 3.1
+     */
+    ImageDescriptor getImageDescriptor(IActivity activity);
+
+    /**
+     * Return the image associated with this category.
+     *
+     * @param category the category
+     * @return the image associated with this category.  Never <code>null</code>.
+     * @since 3.1
+     */
+    ImageDescriptor getImageDescriptor(ICategory category);
+
+	/**
+	 * Return the trigger point manager for this instance.
+	 *
+	 * @return the trigger point manager.  Never <code>null</code>.
+	 * @since 3.1
+	 */
+	ITriggerPointManager getTriggerPointManager();
+
+    /**
+     * Return a copy of the current activity set. This copy will contain all
+     * activity and category definitions that the workbench activity manager
+     * contains, and will have the same enabled state. It will not have the same
+     * listeners. This is useful for user interfaces that wish to modify the
+     * activity enablement state (such as preference pages).
+     *
+     * @return a copy of the current activity set
+     * @since 3.1
+     */
+    IMutableActivityManager createWorkingCopy();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/IdentifierEvent.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/IdentifierEvent.java
new file mode 100644
index 0000000..f132cf9
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/IdentifierEvent.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.activities;
+
+/**
+ * An instance of this class describes changes to an instance of
+ * <code>IIdentifier</code>.  This class does not give details as to the
+ * specifics of a change, only that the given property on the source object has
+ * changed.
+ *
+ * <p>
+ * This class is not intended to be extended by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @see IIdentifierListener#identifierChanged(IdentifierEvent)
+ */
+public final class IdentifierEvent {
+    private boolean activityIdsChanged;
+
+    private boolean enabledChanged;
+
+    private IIdentifier identifier;
+
+    /**
+     * Creates a new instance of this class.
+     *
+     * @param identifier
+     *            the instance of the interface that changed.
+     * @param activityIdsChanged
+     *            <code>true</code>, iff the activityIds property changed.
+     * @param enabledChanged
+     *            <code>true</code>, iff the enabled property changed.
+     */
+    public IdentifierEvent(IIdentifier identifier, boolean activityIdsChanged,
+            boolean enabledChanged) {
+        if (identifier == null) {
+			throw new NullPointerException();
+		}
+
+        this.identifier = identifier;
+        this.activityIdsChanged = activityIdsChanged;
+        this.enabledChanged = enabledChanged;
+    }
+
+    /**
+     * Returns the instance of the interface that changed.
+     *
+     * @return the instance of the interface that changed. Guaranteed not to be
+     *         <code>null</code>.
+     */
+    public IIdentifier getIdentifier() {
+        return identifier;
+    }
+
+    /**
+     * Returns whether or not the activityIds property changed.
+     *
+     * @return <code>true</code>, iff the activityIds property changed.
+     */
+    public boolean hasActivityIdsChanged() {
+        return activityIdsChanged;
+    }
+
+    /**
+     * Returns whether or not the enabled property changed.
+     *
+     * @return <code>true</code>, iff the enabled property changed.
+     */
+    public boolean hasEnabledChanged() {
+        return enabledChanged;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/NotDefinedException.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/NotDefinedException.java
new file mode 100644
index 0000000..7641d63
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/NotDefinedException.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.activities;
+
+/**
+ * Signals that an attempt was made to access the properties of an undefined
+ * object.
+ *
+ * <p>
+ * This class is not intended to be extended by clients.
+ * </p>
+ *
+ * @see IActivity
+ * @see ICategory
+ * @since 3.0
+ */
+public final class NotDefinedException extends Exception {
+
+    /**
+     * Generated serial version UID for this class.
+     * @since 3.1
+     */
+    private static final long serialVersionUID = 4050201929596811061L;
+
+    /**
+     * Creates a new instance of this class with no specified detail message.
+     */
+    public NotDefinedException() {
+        //no-op
+    }
+
+    /**
+     * Creates a new instance of this class with the specified detail message.
+     *
+     * @param s
+     *            the detail message.
+     */
+    public NotDefinedException(String s) {
+        super(s);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/WorkbenchActivityHelper.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/WorkbenchActivityHelper.java
new file mode 100644
index 0000000..5916c1e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/WorkbenchActivityHelper.java
@@ -0,0 +1,677 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ *******************************************************************************/
+package org.eclipse.ui.activities;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.eclipse.ui.IPluginContribution;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.activities.ws.WorkbenchActivitySupport;
+
+/**
+ * A utility class that contains helpful methods for interacting with the
+ * activities API.
+ *
+ * @since 3.0
+ */
+public final class WorkbenchActivityHelper {
+	/**
+	 * The ID of the trigger point that only returns activities with core
+	 * expressions.
+	 *
+	 * @since 3.4
+	 */
+	public static final String TRIGGER_PRE_UI_POINT = "org.eclipse.ui.workbenchModel"; //$NON-NLS-1$
+
+	private static ITriggerPoint getTriggerPoint(String id) {
+		return PlatformUI.getWorkbench().getActivitySupport()
+				.getTriggerPointManager().getTriggerPoint(id);
+	}
+
+	/**
+	 * Return the identifier that maps to the given contribution.
+	 *
+	 * @param contribution
+	 *            the contribution
+	 * @return the identifier
+	 * @since 3.1
+	 */
+	public static IIdentifier getIdentifier(IPluginContribution contribution) {
+		IWorkbenchActivitySupport workbenchActivitySupport = PlatformUI
+				.getWorkbench().getActivitySupport();
+		IIdentifier identifier = workbenchActivitySupport.getActivityManager()
+				.getIdentifier(createUnifiedId(contribution));
+		return identifier;
+	}
+
+	/**
+	 * Answers whether a given contribution is allowed to be used based on
+	 * activity enablement. If it is currently disabled, then a dialog is opened
+	 * and the user is prompted to activate the requried activities. If the user
+	 * declines their activation then false is returned. In all other cases
+	 * <code>true</code> is returned.
+	 *
+	 * @param object
+	 *            the contribution to test.
+	 * @return whether the contribution is allowed to be used based on activity
+	 *         enablement.
+	 * @deprecated
+	 * @see #allowUseOf(ITriggerPoint, Object)
+	 */
+	@Deprecated
+	public static boolean allowUseOf(Object object) {
+		return allowUseOf(PlatformUI.getWorkbench().getActivitySupport()
+				.getTriggerPointManager().getTriggerPoint(
+						ITriggerPointManager.UNKNOWN_TRIGGER_POINT_ID), object);
+	}
+
+	/**
+	 * Answers whether a given contribution is allowed to be used based on
+	 * activity enablement. If it is currently disabled, then a dialog is opened
+	 * and the user is prompted to activate the required activities. If the user
+	 * declines their activation then false is returned. In all other cases
+	 * <code>true</code> is returned.
+	 *
+	 * @param triggerPoint
+	 *            the trigger point being hit
+	 * @param object
+	 *            the contribution to test.
+	 * @return whether the contribution is allowed to be used based on activity
+	 *         enablement.
+	 */
+	public static boolean allowUseOf(ITriggerPoint triggerPoint, Object object) {
+		if (!isFiltering()) {
+			return true;
+		}
+		if (triggerPoint == null) {
+			return true;
+		}
+		if (object instanceof IPluginContribution) {
+			IPluginContribution contribution = (IPluginContribution) object;
+			IIdentifier identifier = getIdentifier(contribution);
+			return allow(triggerPoint, identifier);
+		}
+		return true;
+	}
+
+	/**
+	 * Restrict the use of the object only if it is matched by an activity with
+	 * a core expression. A normal disabled activity will not restrict the use
+	 * of this object.
+	 *
+	 * @param object
+	 *            the object to restrict
+	 * @return <code>true</code> if this object is matched by a disabled
+	 *         activity with an expression.
+	 * @since 3.4
+	 */
+	public static boolean restrictUseOf(Object object) {
+		return !allowUseOf(getTriggerPoint(TRIGGER_PRE_UI_POINT), object);
+	}
+
+	/**
+	 * Answers whether a given identifier is enabled. If it is not enabled, then
+	 * a dialog is opened and the user is prompted to enable the associated
+	 * activities.
+	 *
+	 * @param triggerPoint
+	 *            the trigger point to test
+	 * @param identifier
+	 *            the identifier to test.
+	 * @return whether the identifier is enabled.
+	 */
+	private static boolean allow(ITriggerPoint triggerPoint,
+			IIdentifier identifier) {
+		if (identifier.isEnabled()) {
+			return true;
+		}
+
+		ITriggerPointAdvisor advisor = ((WorkbenchActivitySupport) PlatformUI
+				.getWorkbench().getActivitySupport()).getTriggerPointAdvisor();
+		Set<?> activitiesToEnable = advisor.allow(triggerPoint, identifier);
+
+		if (activitiesToEnable == null) {
+			return false;
+		}
+
+		if (activitiesToEnable.isEmpty()) {
+			// no activities required to be enabled for this trigger point -
+			// allow use unconditionally.
+			return true;
+		}
+
+		enableActivities(activitiesToEnable);
+		// only allow the operation if all the activities we needed to enabled
+		// are now enabled. this means if something has an expression bound
+		// activity that is not currently enabled this call will always return
+		// false - trying to manually set such an activity will always fail.
+		Set<?> newEnabled = PlatformUI.getWorkbench().getActivitySupport().getActivityManager()
+				.getEnabledActivityIds();
+		return newEnabled.containsAll(activitiesToEnable);
+	}
+
+	/**
+	 * Utility method to create a <code>String</code> containing the plugin
+	 * and extension ids of a contribution. This will have the form
+	 *
+	 * <pre>
+	 * pluginId / extensionId
+	 * </pre>. If the IPluginContribution does not define a plugin id then the
+	 * extension id alone is returned.
+	 *
+	 * @param contribution
+	 *            the contribution to use
+	 * @return the unified id
+	 */
+	public static final String createUnifiedId(IPluginContribution contribution) {
+		final String pluginId = contribution.getPluginId();
+		if (pluginId != null) {
+			return pluginId + '/' + contribution.getLocalId();
+		}
+		return contribution.getLocalId();
+	}
+
+	/**
+	 * Enables the set of activities.
+	 *
+	 * @param activities
+	 *            the activities to enable
+	 */
+	private static void enableActivities(Collection activities) {
+		IWorkbenchActivitySupport activitySupport = PlatformUI.getWorkbench()
+				.getActivitySupport();
+		Set<?> newSet = new HashSet(activitySupport.getActivityManager().getEnabledActivityIds());
+		newSet.addAll(activities);
+		activitySupport.setEnabledActivityIds(newSet);
+	}
+
+	/**
+	 * Answers whether the provided object should be filtered from the UI based
+	 * on activity state. Returns <code>false</code> except when the object is
+	 * an instance of <code>IPluginContribution</code> whos unified id matches
+	 * an <code>IIdentifier</code> that is currently disabled.
+	 *
+	 * @param object
+	 *            the object to test
+	 * @return whether the object should be filtered
+	 * @see #createUnifiedId(IPluginContribution)
+	 */
+	public static final boolean filterItem(Object object) {
+		if (object instanceof IPluginContribution) {
+			IPluginContribution contribution = (IPluginContribution) object;
+			IWorkbenchActivitySupport workbenchActivitySupport = PlatformUI
+					.getWorkbench().getActivitySupport();
+			IIdentifier identifier = workbenchActivitySupport
+					.getActivityManager().getIdentifier(
+							createUnifiedId(contribution));
+			if (!identifier.isEnabled()) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Returns whether the UI is set up to filter contributions. This is the
+	 * case if there are defined activities.
+	 *
+	 * @return whether the UI is set up to filter contributions
+	 */
+	public static final boolean isFiltering() {
+		return !PlatformUI.getWorkbench().getActivitySupport()
+				.getActivityManager().getDefinedActivityIds().isEmpty();
+	}
+
+	/**
+	 * Return a list of category ids that will become implicity enabled if the
+	 * given category becomes enabled Note that the set returned by this set
+	 * represents the delta of categories that would be enabled - if the
+	 * category is already enabled then it is omitted.
+	 *
+	 * @param activityManager
+	 *            the activity manager to test against
+	 * @param categoryId
+	 *            the category to be enabled
+	 * @return a list of category ids that will become implicity enabled if the
+	 *         given category becomes enabled
+	 * @since 3.1
+	 */
+	public static Set getEnabledCategories(IActivityManager activityManager,
+			String categoryId) {
+		ICategory category = activityManager.getCategory(categoryId);
+		if (!category.isDefined()) {
+			return Collections.EMPTY_SET;
+		}
+
+		Set<?> activities = expandActivityDependencies(getActivityIdsForCategory(category));
+		Set<String> otherEnabledCategories = new HashSet<>();
+		Set<?> definedCategoryIds = activityManager.getDefinedCategoryIds();
+		for (Object name : definedCategoryIds) {
+			String otherCategoryId = (String) name;
+			if (otherCategoryId.equals(categoryId)) {
+				continue;
+			}
+			ICategory otherCategory = activityManager
+					.getCategory(otherCategoryId);
+			Set<?> otherCategoryActivityIds = expandActivityDependencies(getActivityIdsForCategory(otherCategory));
+			if (activityManager.getEnabledActivityIds().containsAll(
+					otherCategoryActivityIds)) {
+				continue;
+			}
+			if (activities.containsAll(otherCategoryActivityIds)) {
+				otherEnabledCategories.add(otherCategoryId);
+			}
+
+		}
+		return otherEnabledCategories;
+	}
+
+	/**
+	 * Return the expanded activities for the given activity set. This will
+	 * resolve all activity requirement bindings.
+	 *
+	 * @param baseActivities
+	 *            the set of activities to expand
+	 * @return the expanded activities
+	 * @since 3.1
+	 */
+	public static Set expandActivityDependencies(Set baseActivities) {
+		Set<Object> extendedActivities = new HashSet<>();
+		for (Iterator<?> i = baseActivities.iterator(); i.hasNext();) {
+			String activityId = (String) i.next();
+			Set<?> requiredActivities = getRequiredActivityIds(activityId);
+			extendedActivities.addAll(requiredActivities);
+		}
+		extendedActivities.addAll(baseActivities);
+		return extendedActivities;
+	}
+
+	/**
+	 * Return the activities required for this activity.
+	 *
+	 * @param activityId
+	 *            the activity id
+	 * @return the activities required for this activity
+	 * @since 3.1
+	 */
+	public static Set getRequiredActivityIds(String activityId) {
+		IActivityManager manager = PlatformUI.getWorkbench()
+				.getActivitySupport().getActivityManager();
+		IActivity activity = manager.getActivity(activityId);
+		if (!activity.isDefined()) {
+			return Collections.EMPTY_SET;
+		}
+		Set<?> requirementBindings = activity.getActivityRequirementBindings();
+		if (requirementBindings.isEmpty()) {
+			return Collections.EMPTY_SET;
+		}
+
+		Set<Object> requiredActivities = new HashSet<>(3);
+		for (Object name : requirementBindings) {
+			IActivityRequirementBinding binding = (IActivityRequirementBinding) name;
+			requiredActivities.add(binding.getRequiredActivityId());
+			requiredActivities.addAll(getRequiredActivityIds(binding.getRequiredActivityId()));
+		}
+		return requiredActivities;
+	}
+
+	/**
+	 * Return the activities directly required by a given category.
+	 *
+	 * @param category
+	 *            the category
+	 * @return the activities directly required by a given category
+	 * @since 3.1
+	 */
+	public static Set getActivityIdsForCategory(ICategory category) {
+		Set<?> bindings = category.getCategoryActivityBindings();
+		Set<String> activityIds = new HashSet<>();
+		for (Object name : bindings) {
+			ICategoryActivityBinding binding = (ICategoryActivityBinding) name;
+			activityIds.add(binding.getActivityId());
+		}
+		return activityIds;
+	}
+
+	/**
+	 * Return a list of category ids that will become implicity disabled if the
+	 * given category becomes disabled Note that the set returned by this set
+	 * represents the delta of categories that would be enabled - if the
+	 * category is already enabled then it is omitted.
+	 *
+	 * @param activityManager
+	 *            the activity manager to test against
+	 * @param categoryId
+	 *            the category to be enabled
+	 * @return a list of category ids that will become implicity enabled if the
+	 *         given category becomes enabled
+	 * @since 3.1
+	 */
+	public static Set getDisabledCategories(IActivityManager activityManager,
+			String categoryId) {
+		ICategory category = activityManager.getCategory(categoryId);
+		if (!category.isDefined()) {
+			return Collections.EMPTY_SET;
+		}
+
+		Set<?> activities = expandActivityDependencies(getActivityIdsForCategory(category));
+		Set<String> otherDisabledCategories = new HashSet<>();
+		Set<?> definedCategoryIds = activityManager.getDefinedCategoryIds();
+		for (Object name : definedCategoryIds) {
+			String otherCategoryId = (String) name;
+			if (otherCategoryId.equals(categoryId)) {
+				continue;
+			}
+			ICategory otherCategory = activityManager
+					.getCategory(otherCategoryId);
+			Set<?> otherCategoryActivityIds = expandActivityDependencies(getActivityIdsForCategory(otherCategory));
+
+			if (otherCategoryActivityIds.isEmpty()) {
+				continue;
+			}
+
+			if (!activities.containsAll(otherCategoryActivityIds)) {
+				continue;
+			}
+
+			if (activityManager.getEnabledActivityIds().containsAll(
+					otherCategoryActivityIds)) {
+				otherDisabledCategories.add(otherCategoryId);
+			}
+
+		}
+		return otherDisabledCategories;
+	}
+
+	/**
+	 * Return a list of category ids that are implicitly contained within the
+	 * given category.
+	 *
+	 * @param activityManager
+	 *            the activity manager to test agaisnt
+	 * @param categoryId
+	 *            the category to be enabled
+	 * @return a list of category ids that will become implicity enabled if the
+	 *         given category becomes enabled
+	 * @since 3.1
+	 */
+	public static final Set getContainedCategories(
+			IActivityManager activityManager, String categoryId) {
+		ICategory category = activityManager.getCategory(categoryId);
+		if (!category.isDefined()) {
+			return Collections.EMPTY_SET;
+		}
+
+		Set<?> activities = expandActivityDependencies(getActivityIdsForCategory(category));
+		Set<String> containedCategories = new HashSet<>();
+		Set<?> definedCategoryIds = activityManager.getDefinedCategoryIds();
+		for (Object name : definedCategoryIds) {
+			String otherCategoryId = (String) name;
+			if (otherCategoryId.equals(categoryId)) {
+				continue;
+			}
+			ICategory otherCategory = activityManager
+					.getCategory(otherCategoryId);
+			Set<?> otherCategoryActivityIds = expandActivityDependencies(getActivityIdsForCategory(otherCategory));
+
+			if (otherCategoryActivityIds.isEmpty()) {
+				continue;
+			}
+
+			if (activities.containsAll(otherCategoryActivityIds)) {
+				containedCategories.add(otherCategoryId);
+			}
+
+		}
+		return containedCategories;
+
+	}
+
+	/**
+	 * Return the set of enabled categories. An enabled category is one in which
+	 * all contained activities are enabled.
+	 *
+	 * @param activityManager
+	 *            the activity manager to test against
+	 * @return the set of enabled categories.
+	 * @since 3.1
+	 */
+	public static Set getEnabledCategories(IActivityManager activityManager) {
+
+		Set<?> definedCategoryIds = activityManager.getDefinedCategoryIds();
+		Set<String> enabledCategories = new HashSet<>();
+		for (Object name : definedCategoryIds) {
+			String categoryId = (String) name;
+			if (isEnabled(activityManager, categoryId)) {
+				enabledCategories.add(categoryId);
+			}
+		}
+		return enabledCategories;
+	}
+
+	/**
+	 * Return the set of partially enabled categories.
+	 *
+	 * @param activityManager
+	 *            the activity manager to test against
+	 * @return the set of partially enabled categories
+	 * @since 3.2
+	 */
+	public static Set getPartiallyEnabledCategories(
+			IActivityManager activityManager) {
+		Set<?> definedCategoryIds = activityManager.getDefinedCategoryIds();
+		Set<String> partialCategories = new HashSet<>();
+		for (Object name : definedCategoryIds) {
+			String categoryId = (String) name;
+			if (isPartiallyEnabled(activityManager, categoryId)) {
+				partialCategories.add(categoryId);
+			}
+		}
+
+		return partialCategories;
+	}
+
+	/**
+	 * Returns whether the given category is partially enabled. A partially
+	 * enabled category is one in which the number of enabled activites is both
+	 * non-zero and less than the total number of activities in the category.
+	 *
+	 * @param activityManager
+	 *            the activity manager to test against
+	 * @param categoryId
+	 *            the category id
+	 * @return whether the category is enabled
+	 * @since 3.2
+	 */
+	public static boolean isPartiallyEnabled(IActivityManager activityManager,
+			String categoryId) {
+		Set<?> activityIds = getActivityIdsForCategory(activityManager.getCategory(categoryId));
+		int foundCount = 0;
+		for (Object name : activityIds) {
+			String activityId = (String) name;
+			if (activityManager.getEnabledActivityIds().contains(activityId)) {
+				foundCount++;
+			}
+		}
+
+		return foundCount > 0 && foundCount != activityIds.size();
+	}
+
+	/**
+	 * Return the number of enabled categories that this activity belongs to.
+	 *
+	 * @param activityManager
+	 *            the activity manager to test against *
+	 * @param activityId
+	 *            the activity id to query on
+	 * @return the set of enabled category ids that this activity belongs to
+	 * @since 3.1
+	 */
+	public static Set getEnabledCategoriesForActivity(
+			IActivityManager activityManager, String activityId) {
+		Set<String> enabledCategoriesForActivity = new HashSet<>();
+		Set<?> enabledCategories = getEnabledCategories(activityManager);
+		for (Object name : enabledCategories) {
+			String categoryId = (String) name;
+			if (getActivityIdsForCategory(
+					activityManager.getCategory(categoryId)).contains(
+					activityId)) {
+				enabledCategoriesForActivity.add(categoryId);
+			}
+		}
+		return enabledCategoriesForActivity;
+	}
+
+	/**
+	 * Returns whether the given category is enabled. A category is enabled if
+	 * all of its activities are enabled.
+	 *
+	 * @param activityManager
+	 *            the activity manager to test against
+	 * @param categoryId
+	 *            the category id
+	 * @return whether the category is enabled
+	 * @since 3.1
+	 */
+	public static boolean isEnabled(IActivityManager activityManager,
+			String categoryId) {
+
+		ICategory category = activityManager.getCategory(categoryId);
+		if (category.isDefined()) {
+			Set<?> activityIds = getActivityIdsForCategory(category);
+			if (activityManager.getEnabledActivityIds().containsAll(activityIds)) {
+				return true;
+			}
+		}
+
+		return false;
+	}
+
+	/**
+	 * Resolve the collection of category ids to an array of
+	 * <code>ICategory</code> objects.
+	 *
+	 * @param activityManager
+	 *            the activity manager to test against
+	 * @param categoryIds
+	 *            the category ids
+	 * @return the array of category ids resolved to <code>ICategory</code>
+	 *         objects
+	 * @since 3.1
+	 */
+	public static ICategory[] resolveCategories(
+			IMutableActivityManager activityManager, Set categoryIds) {
+		ICategory[] categories = new ICategory[categoryIds.size()];
+		String[] categoryIdArray = (String[]) categoryIds.toArray(new String[categoryIds.size()]);
+		for (int i = 0; i < categoryIdArray.length; i++) {
+			categories[i] = activityManager.getCategory(categoryIdArray[i]);
+		}
+		return categories;
+	}
+
+	/**
+	 * Fills and returns the second argument with those objects of the first
+	 * argument that pass the {@link #restrictUseOf(Object)} test.
+	 *
+	 * @param toBeFiltered the input collection
+	 * @param result the collection to which objects passing the test should be added
+	 * @return the <code>result</code> collection for convenience
+	 *
+	 * @since 3.4
+	 */
+	public static Collection restrictCollection(Collection toBeFiltered, Collection result) {
+		for (Iterator<?> iterator = toBeFiltered.iterator(); iterator.hasNext();) {
+			Object item = iterator.next();
+			if (!restrictUseOf(item)) {
+				result.add(item);
+			}
+		}
+		return result;
+	}
+
+	/**
+	 * Returns an array with those objects of the argument array that pass the
+	 * {@link #restrictUseOf(Object)} test.
+	 *
+	 * @param array
+	 *            the input array
+	 * @return a new array of the same type as the argument array, containing
+	 *         objects that pass the test
+	 *
+	 * @since 3.4
+	 */
+	public static Object[] restrictArray(Object[] array) {
+		ArrayList<Object> list = new ArrayList<>(array.length);
+		for (int i = 0; i < array.length; i++) {
+			if (!restrictUseOf(array[i])) {
+				list.add(array[i]);
+			}
+		}
+		return list.toArray((Object[]) Array.newInstance(array.getClass()
+				.getComponentType(), list.size()));
+	}
+
+	/**
+	 * Fills and returns the second argument with those objects of the first
+	 * argument that pass the {@link #filterItem(Object)} test.
+	 *
+	 * @param toBeFiltered the input collection
+	 * @param result the collection to which objects passing the test should be added
+	 * @return the <code>result</code> collection for convenience
+	 *
+	 * @since 3.4
+	 */
+	public static Collection filterCollection(Collection toBeFiltered, Collection result) {
+		for (Iterator<?> iterator = toBeFiltered.iterator(); iterator.hasNext();) {
+			Object item = iterator.next();
+			if (!filterItem(item)) {
+				result.add(item);
+			}
+		}
+		return result;
+	}
+
+	/**
+	 * Returns an array with those objects of the argument array that pass the
+	 * {@link #filterItem(Object)} test.
+	 *
+	 * @param array
+	 *            the input array
+	 * @return a new array of the same type as the argument array, containing
+	 *         objects that pass the test
+	 *
+	 * @since 3.4
+	 */
+	public static Object[] filterArray(Object[] array) {
+		ArrayList<Object> list = new ArrayList<>(array.length);
+		for (int i = 0; i < array.length; i++) {
+			if (!filterItem(array[i])) {
+				list.add(array[i]);
+			}
+		}
+		return list.toArray((Object[]) Array.newInstance(array.getClass()
+				.getComponentType(), list.size()));
+	}
+
+	/**
+	 * Not intended to be instantiated.
+	 */
+	private WorkbenchActivityHelper() {
+		// no-op
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/WorkbenchTriggerPointAdvisor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/WorkbenchTriggerPointAdvisor.java
new file mode 100644
index 0000000..6da155b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/WorkbenchTriggerPointAdvisor.java
@@ -0,0 +1,216 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.activities;
+
+import java.util.Collections;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExecutableExtension;
+import org.eclipse.jface.window.Window;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.IPreferenceConstants;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.activities.ws.EnablementDialog;
+import org.eclipse.ui.internal.util.PrefUtil;
+import org.eclipse.ui.internal.util.Util;
+
+/**
+ *
+ * Workbench implementation prompts the user with a dialog unless they've said
+ * that they don't want to be prompted. You may provide the certain strings to
+ * this class via method #2 of
+ * {@link org.eclipse.core.runtime.IExecutableExtension}. This is provided as
+ * API so that non-SDK Eclipse applications can reuse and augment the default
+ * SDK trigger point behaviour.
+ *
+ * @see #PROCEED_MULTI
+ * @see #PROCEED_SINGLE
+ * @see #DONT_ASK
+ * @see #NO_DETAILS
+ * @since 3.1
+ */
+public class WorkbenchTriggerPointAdvisor implements ITriggerPointAdvisor,
+        IExecutableExtension {
+
+	/**
+	 * The string to be used when prompting to proceed with multiple activities.
+	 * Ie: "Enable the selected activities?"
+	 */
+	public static String PROCEED_MULTI = "proceedMulti"; //$NON-NLS-1$
+
+	/**
+	 * The string to be used when prompting to proceed with a single activity.
+	 * Ie: "Enable the required activity?"
+	 */
+	public static String PROCEED_SINGLE = "proceedSingle"; //$NON-NLS-1$
+
+	/**
+	 * The string to be used to label the "don't ask" button.
+	 * Ie: "&Always enable activities and don't ask me again"
+	 */
+	public static String DONT_ASK = "dontAsk"; //$NON-NLS-1$
+
+	/**
+	 * The string to be used when no activities are selected and Details are shown.
+	 * Ie: "Select an activity to view its description."
+	 */
+	public static String NO_DETAILS = "noDetails"; //$NON-NLS-1$
+
+
+	private Properties strings = new Properties();
+
+	/**
+	 * Create a new instance of this advisor.
+	 */
+	public WorkbenchTriggerPointAdvisor() {
+		super();
+	}
+
+	@Override
+	public Set allow(ITriggerPoint triggerPoint, IIdentifier identifier) {
+
+		if (triggerPoint.getBooleanHint(ITriggerPoint.HINT_PRE_UI)) {
+			IActivityManager activityManager = PlatformUI.getWorkbench()
+					.getActivitySupport().getActivityManager();
+			Iterator iterator = identifier.getActivityIds().iterator();
+			while (iterator.hasNext()) {
+				String id = (String) iterator.next();
+				IActivity activity = activityManager.getActivity(id);
+				if (activity.getExpression() != null) {
+					if (!activity.isEnabled())
+						// if we have any disabled expression activities we
+						// should disallow immediately
+						return null;
+				}
+			}
+			// if we have no disabled expression activities just return the
+			// empty set. This will allow the use of the given object but will
+			// not result in any activity activation.
+			return Collections.EMPTY_SET;
+		}
+
+        if (!PrefUtil.getInternalPreferenceStore().getBoolean(
+                IPreferenceConstants.SHOULD_PROMPT_FOR_ENABLEMENT)) {
+            return identifier.getActivityIds();
+        }
+
+		//If it's a non-interactive point activate all activities
+		if (!triggerPoint.getBooleanHint(ITriggerPoint.HINT_INTERACTIVE)) {
+			return identifier.getActivityIds();
+		}
+
+        EnablementDialog dialog = new EnablementDialog(Util.getShellToParentOn(), identifier
+                .getActivityIds(), strings);
+        if (dialog.open() == Window.OK) {
+            Set activities = dialog.getActivitiesToEnable();
+            if (dialog.getDontAsk()) {
+				PrefUtil.getInternalPreferenceStore().setValue(
+						IPreferenceConstants.SHOULD_PROMPT_FOR_ENABLEMENT,
+						false);
+				WorkbenchPlugin.getDefault().savePluginPreferences();
+			}
+
+            return activities;
+        }
+
+		return null;
+	}
+
+	@Override
+	public void setInitializationData(IConfigurationElement config, String propertyName, Object data) {
+		if (data instanceof Hashtable) {
+			strings.putAll((Hashtable)data);
+		}
+	}
+
+	/**
+	 * This implementation of
+	 * {@link ITriggerPointAdvisor#computeEnablement(IActivityManager, IIdentifier)}
+	 * calls
+	 * {@link #doComputeEnablement(IActivityManager, IIdentifier, boolean)} with
+	 * a boolean argument of <code>false</code>. Subclasses that wish to
+	 * disable identifiers if there is at least one disabled expression-based
+	 * activity should override this method and call
+	 * {@link #doComputeEnablement(IActivityManager, IIdentifier, boolean)} with
+	 * a boolean argument of <code>true</code>.
+	 *
+	 * Subclasses may override.
+	 *
+	 * @param activityManager
+	 *            the activity manager
+	 * @param identifier
+	 *            the identifier to update
+	 *
+	 * @return <code>true</code> if this identifier should be enabled,
+	 *         <code>false</code> otherwise
+	 * @since 3.4
+	 *
+	 * @see WorkbenchTriggerPointAdvisor#doComputeEnablement(IActivityManager,
+	 *      IIdentifier, boolean)
+	 */
+	@Override
+	public boolean computeEnablement(IActivityManager activityManager, IIdentifier identifier) {
+		return doComputeEnablement(activityManager, identifier, false);
+	}
+
+	/**
+	 * Helper method for determining whether an identifier should be enabled.
+	 * Returns <code>true</code> if there is no applicable activity for the
+	 * given identifier. Otherwise, if the boolean argument <code>
+	 * disabledExpressionActivitiesTakePrecedence</code> is
+	 * <code>false</code>, returns true if any of the applicable activities
+	 * is enabled. If the boolean argument is <code>true</code>, this method
+	 * returns <code>false</code> if there is at least one disabled
+	 * expression-based activity; and it returns <code>true</code> if there
+	 * are no disabled expression-based activities and there is at least one
+	 * applicable activity that is enabled.
+	 * @param activityManager the activity manager
+	 * @param identifier
+	 *            the identifier to update
+	 * @param disabledExpressionActivitiesTakePrecedence
+	 *
+	 * @return <code>true</code> if this identifier should be enabled,
+	 *         <code>false</code> otherwise
+	 * @since 3.4
+	 */
+	protected boolean doComputeEnablement(IActivityManager activityManager,
+			IIdentifier identifier, boolean disabledExpressionActivitiesTakePrecedence) {
+		final Set activityIds = identifier.getActivityIds();
+		if (activityIds.size() == 0) {
+			return true;
+		}
+
+		boolean matchesAtLeastOneEnabled = false;
+		boolean matchesDisabledExpressionActivitiesWithPrecedence = false;
+		for (Iterator iterator = activityIds.iterator(); iterator.hasNext();) {
+			String activityId = (String) iterator.next();
+			IActivity activity = activityManager.getActivity(activityId);
+
+			if (activity.isEnabled()) {
+				if (!disabledExpressionActivitiesTakePrecedence) {
+					return true;
+				}
+				matchesAtLeastOneEnabled = true;
+			} else {
+				if (disabledExpressionActivitiesTakePrecedence && activity.getExpression() != null) {
+					matchesDisabledExpressionActivitiesWithPrecedence = true;
+				}
+			}
+
+		}
+
+		return !matchesDisabledExpressionActivitiesWithPrecedence && matchesAtLeastOneEnabled;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/package.html b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/package.html
new file mode 100644
index 0000000..218021b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/activities/package.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <meta name="Author" content="IBM">
+   <title>Package-level Javadoc</title>
+</head>
+<body>
+Application programming interfaces for interaction
+with and extension of the Eclipse Platform User Interface.
+<h2>Package Specification</h2>
+This package provides application programming interfaces for interaction
+with activities.  Activities are objects that may be enabled or disabled and 
+contain bindings to various regular expressions.  Activities are used by the 
+workbench to filter selected contributions from the users view untill such a 
+time that they express interest in using them.
+</body>
+</html>
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/application/ActionBarAdvisor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/application/ActionBarAdvisor.java
new file mode 100644
index 0000000..5722c8c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/application/ActionBarAdvisor.java
@@ -0,0 +1,352 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *******************************************************************************/
+package org.eclipse.ui.application;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.ICoolBarManager;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.IStatusLineManager;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.ActionFactory;
+import org.eclipse.ui.actions.RetargetAction;
+import org.eclipse.ui.internal.handlers.IActionCommandMappingService;
+
+/**
+ * Public base class for configuring the action bars of a workbench window.
+ * <p>
+ * An application should declare a subclass of <code>ActionBarAdvisor</code>
+ * and override methods to configure a window's action bars to suit the needs of the
+ * particular application.
+ * </p>
+ * <p>
+ * The following advisor methods are called at strategic points in the
+ * workbench's lifecycle (all occur within the dynamic scope of the call
+ * to {@link PlatformUI#createAndRunWorkbench PlatformUI.createAndRunWorkbench}):
+ * <ul>
+ * <li><code>fillActionBars</code> - called after <code>WorkbenchWindowAdvisor.preWindowOpen</code>
+ * to configure a window's action bars</li>
+ * </ul>
+ * </p>
+ *
+ * @see WorkbenchWindowAdvisor#createActionBarAdvisor(IActionBarConfigurer)
+ *
+ * @since 3.1
+ */
+public class ActionBarAdvisor {
+
+    /**
+     * Bit flag for {@link #fillActionBars fillActionBars} indicating that the
+     * operation is not filling the action bars of an actual workbench window,
+     * but rather a proxy (used for perspective customization).
+     */
+    public static final int FILL_PROXY = 0x01;
+
+    /**
+     * Bit flag for {@link #fillActionBars fillActionBars} indicating that the
+     * operation is supposed to fill (or describe) the workbench window's menu
+     * bar.
+     */
+    public static final int FILL_MENU_BAR = 0x02;
+
+    /**
+     * Bit flag for {@link #fillActionBars fillActionBars} indicating that the
+     * operation is supposed to fill (or describe) the workbench window's cool
+     * bar.
+     */
+    public static final int FILL_COOL_BAR = 0x04;
+
+    /**
+     * Bit flag for {@link #fillActionBars fillActionBars} indicating that the
+     * operation is supposed to fill (or describe) the workbench window's status
+     * line.
+     */
+    public static final int FILL_STATUS_LINE = 0x08;
+
+
+    private IActionBarConfigurer actionBarConfigurer;
+
+    private Map actions = new HashMap();
+
+    /**
+     * Creates a new action bar advisor to configure a workbench
+     * window's action bars via the given action bar configurer.
+     *
+     * @param configurer the action bar configurer
+     */
+    public ActionBarAdvisor(IActionBarConfigurer configurer) {
+        Assert.isNotNull(configurer);
+        actionBarConfigurer = configurer;
+    }
+
+    /**
+     * Returns the action bar configurer.
+     *
+     * @return the action bar configurer
+     */
+    protected IActionBarConfigurer getActionBarConfigurer() {
+        return actionBarConfigurer;
+    }
+
+    /**
+     * Configures the action bars using the given action bar configurer.
+     * Under normal circumstances, <code>flags</code> does not include
+     * <code>FILL_PROXY</code>, meaning this is a request to fill the action
+     * bars of the corresponding workbench window; the
+     * remaining flags indicate which combination of
+     * the menu bar (<code>FILL_MENU_BAR</code>),
+     * the tool bar (<code>FILL_COOL_BAR</code>),
+     * and the status line (<code>FILL_STATUS_LINE</code>) are to be filled.
+     * <p>
+     * If <code>flags</code> does include <code>FILL_PROXY</code>, then this
+     * is a request to describe the actions bars of the given workbench window
+     * (which will already have been filled);
+     * again, the remaining flags indicate which combination of the menu bar,
+     * the tool bar, and the status line are to be described.
+     * The actions included in the proxy action bars can be the same instances
+     * as in the actual window's action bars. Calling <code>ActionFactory</code>
+     * to create new action instances is not recommended, because these
+     * actions internally register listeners with the window and there is no
+     * opportunity to dispose of these actions.
+     * </p>
+     * <p>
+     * This method is called just after {@link WorkbenchWindowAdvisor#preWindowOpen()}.
+     * Clients must not call this method directly (although super calls are okay).
+     * The default implementation calls <code>makeActions</code> if
+     * <code>FILL_PROXY</code> is specified, then calls <code>fillMenuBar</code>,
+     * <code>fillCoolBar</code>, and <code>fillStatusLine</code>
+     * if the corresponding flags are specified.
+     * </p>
+     * <p>
+     * Subclasses may override, but it is recommended that they override the
+     * methods mentioned above instead.
+     * </p>
+     *
+     * @param flags bit mask composed from the constants
+     * {@link #FILL_MENU_BAR FILL_MENU_BAR},
+     * {@link #FILL_COOL_BAR FILL_COOL_BAR},
+     * {@link #FILL_STATUS_LINE FILL_STATUS_LINE},
+     * and {@link #FILL_PROXY FILL_PROXY}
+     */
+    public void fillActionBars(int flags) {
+        if ((flags & FILL_PROXY) == 0) {
+            makeActions(actionBarConfigurer.getWindowConfigurer().getWindow());
+        }
+        if ((flags & FILL_MENU_BAR) != 0) {
+            fillMenuBar(actionBarConfigurer.getMenuManager());
+        }
+        if ((flags & FILL_COOL_BAR) != 0) {
+            fillCoolBar(actionBarConfigurer.getCoolBarManager());
+        }
+        if ((flags & FILL_STATUS_LINE) != 0) {
+            fillStatusLine(actionBarConfigurer.getStatusLineManager());
+        }
+    }
+
+    /**
+     * Instantiates the actions used in the fill methods.
+     * Use {@link #register(IAction)} to register the action with the key binding service
+     * and add it to the list of actions to be disposed when the window is closed.
+     *
+     * @param window the window containing the action bars
+     */
+    protected void makeActions(IWorkbenchWindow window) {
+        // do nothing
+    }
+
+    /**
+     * Registers the given action with the key binding service
+     * (by calling {@link IActionBarConfigurer#registerGlobalAction(IAction)}),
+     * and adds it to the list of actions to be disposed when the window is closed.
+     * <p>
+     * In order to participate in key bindings, the action must have an action
+     * definition id (aka command id), and a corresponding command extension.
+     * See the <code>org.eclipse.ui.commands</code> extension point documentation
+     * for more details.
+     * </p>
+     *
+     * @param action the action to register, this cannot be <code>null</code>
+     *
+     * @see IAction#setActionDefinitionId(String)
+     * @see #disposeAction(IAction)
+     */
+    protected void register(IAction action) {
+    	Assert.isNotNull(action, "Action must not be null"); //$NON-NLS-1$
+        String id = action.getId();
+        Assert.isNotNull(id, "Action must not have null id"); //$NON-NLS-1$
+		if (action instanceof RetargetAction) {
+			String definitionId = action.getActionDefinitionId();
+			if (definitionId != null) {
+				IActionCommandMappingService mapping = getActionBarConfigurer()
+						.getWindowConfigurer().getWindow()
+						.getService(IActionCommandMappingService.class);
+				if (mapping != null) {
+					mapping.map(id, definitionId);
+				}
+			}
+		} else {
+			getActionBarConfigurer().registerGlobalAction(action);
+		}
+		actions.put(id, action);
+    }
+
+    /**
+     * Returns the action with the given id, or <code>null</code> if not found.
+     *
+     * @param id the action id
+     * @return the action with the given id, or <code>null</code> if not found
+     * @see IAction#getId()
+     */
+    protected IAction getAction(String id) {
+        return (IAction) actions.get(id);
+    }
+
+    /**
+     * Fills the menu bar with the main menus for the window.
+     * <p>
+     * The default implementation does nothing.
+     * Subclasses may override.
+     * </p>
+     *
+     * @param menuBar the menu manager for the menu bar
+     */
+    protected void fillMenuBar(IMenuManager menuBar) {
+        // do nothing
+    }
+
+    /**
+     * Fills the cool bar with the main toolbars for the window.
+     * <p>
+     * The default implementation does nothing.
+     * Subclasses may override.
+     * </p>
+     *
+     * @param coolBar the cool bar manager
+     */
+    protected void fillCoolBar(ICoolBarManager coolBar) {
+        // do nothing
+    }
+
+    /**
+     * Fills the status line with the main status line contributions
+     * for the window.
+     * <p>
+     * The default implementation does nothing.
+     * Subclasses may override.
+     * </p>
+     *
+     * @param statusLine the status line manager
+     */
+    protected void fillStatusLine(IStatusLineManager statusLine) {
+        // do nothing
+    }
+
+    /**
+     * Returns whether the menu with the given id is an application menu of the
+     * given window. This is used during OLE "in place" editing.  Application
+     * menus should be preserved during menu merging. All other menus may be
+     * removed from the window.
+     * <p>
+     * The default implementation returns false. Subclasses may override.
+     * </p>
+     *
+     * @param menuId the menu id
+     * @return <code>true</code> for application menus, and <code>false</code>
+     * for part-specific menus
+     */
+    public boolean isApplicationMenu(String menuId) {
+        // default: not an application menu
+        return false;
+    }
+
+    /**
+     * Disposes this action bar advisor.
+     * Called when the window is being closed.
+     * This should dispose any allocated resources and remove any added listeners.
+     * <p>
+     * The default implementation calls <code>disposeActions()</code>.
+     * Subclasses may extend.
+     * </p>
+     */
+    public void dispose() {
+        disposeActions();
+    }
+
+    /**
+     * Disposes all actions added via <code>register(IAction)</code>
+     * using <code>disposeAction(IAction)</code>.
+     */
+    protected void disposeActions() {
+        for (Iterator i = actions.values().iterator(); i.hasNext();) {
+            IAction action = (IAction) i.next();
+            disposeAction(action);
+        }
+        actions.clear();
+    }
+
+    /**
+     * Disposes the given action.
+     * <p>
+     * The default implementation checks whether the action is an instance
+     * of <code>ActionFactory.IWorkbenchAction</code> and calls its
+     * <code>dispose()</code> method if so.
+     * Subclasses may extend.
+     * </p>
+     *
+     * @param action the action to dispose
+     */
+    protected void disposeAction(IAction action) {
+        if (action instanceof ActionFactory.IWorkbenchAction) {
+            ((ActionFactory.IWorkbenchAction) action).dispose();
+        }
+    }
+
+	/**
+	 * Saves arbitrary application-specific state information
+     * for this action bar advisor.
+     * <p>
+     * The default implementation simply returns an OK status.
+     * Subclasses may extend or override.
+     * </p>
+	 *
+	 * @param memento the memento in which to save the advisor's state
+	 * @return a status object indicating whether the save was successful
+	 * @since 3.1
+	 */
+	public IStatus saveState(IMemento memento) {
+		return Status.OK_STATUS;
+	}
+
+	/**
+	 * Restores arbitrary application-specific state information
+     * for this action bar advisor.
+     * <p>
+     * The default implementation simply returns an OK status.
+     * Subclasses may extend or override.
+     * </p>
+	 *
+     * @param memento the memento from which to restore the advisor's state
+	 * @return a status object indicating whether the restore was successful
+	 * @since 3.1
+	 */
+	public IStatus restoreState(IMemento memento) {
+		return Status.OK_STATUS;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/application/DisplayAccess.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/application/DisplayAccess.java
new file mode 100644
index 0000000..015e4ad
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/application/DisplayAccess.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2015 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.ui.application;
+
+import org.eclipse.ui.internal.UISynchronizer;
+
+/**
+ * This class provides static methods that help RCP applications interact with
+ * the Display.
+ *
+ * @since 3.4
+ */
+public final class DisplayAccess {
+
+	/**
+	 * <p>
+	 * This method allows threads spawned early in the workbench startup process
+	 * to access the Display via the
+	 * {@link org.eclipse.swt.widgets.Display#asyncExec(Runnable)} and
+	 * {@link org.eclipse.swt.widgets.Display#syncExec(Runnable)} methods.
+	 * Without invoking this method from a given thread subsequent calls to the
+	 * above Display methods will behave as follows:
+	 * </p>
+	 *
+	 * <ul>
+	 * <li>runnables posted to
+	 * {@link org.eclipse.swt.widgets.Display#asyncExec(Runnable)} will not be
+	 * invoked until after the Workbench is fully restored.</li>
+	 * <li>calls made to
+	 * {@link org.eclipse.swt.widgets.Display#syncExec(Runnable)} will block
+	 * until the Workbench is fully restored.</li>
+	 * </ul>
+	 *
+	 * <p>
+	 * This method MUST NOT be called from threads created by the workbench. If
+	 * invoked from any thread owned by the Workbench this method will throw an
+	 * {@link IllegalStateException}.
+	 * </p>
+	 *
+	 * <p>
+	 * It is recommended that this method be used from ALL threads that touch
+	 * the display during the startup process, even those that may have been
+	 * created in the main application class.
+	 * </p>
+	 *
+	 * <p>
+	 * This method has no effect after the workbench has been restored.
+	 * </p>
+	 *
+	 * @throws IllegalStateException
+	 *             thrown if invoked from a thread created by the workbench.
+	 */
+	public static void accessDisplayDuringStartup() {
+		UISynchronizer.overrideThread.set(Boolean.TRUE);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/application/IActionBarConfigurer.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/application/IActionBarConfigurer.java
new file mode 100644
index 0000000..341f853
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/application/IActionBarConfigurer.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.application;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.ICoolBarManager;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.IStatusLineManager;
+
+/**
+ * Interface providing special access for configuring the action bars
+ * of a workbench window.
+ * <p>
+ * Note that these objects are only available to the main application
+ * (the plug-in that creates and owns the workbench).
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ *
+ * @see org.eclipse.ui.application.WorkbenchAdvisor#fillActionBars
+ * @since 3.0
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IActionBarConfigurer {
+
+    /**
+     * Returns the workbench window configurer for the window
+     * containing this configurer's action bars.
+     *
+     * @return the workbench window configurer
+     * @since 3.1
+     */
+    public IWorkbenchWindowConfigurer getWindowConfigurer();
+
+
+    /**
+     * Returns the menu manager for the main menu bar of a workbench window.
+     *
+     * @return the menu manager
+     */
+    public IMenuManager getMenuManager();
+
+    /**
+     * Returns the status line manager of a workbench window.
+     *
+     * @return the status line manager
+     */
+    public IStatusLineManager getStatusLineManager();
+
+    /**
+     * Returns the cool bar manager of the workbench window.
+     *
+     * @return the cool bar manager
+     */
+    public ICoolBarManager getCoolBarManager();
+
+    /**
+     * Register the action as a global action with a workbench
+     * window.
+     * <p>
+     * For a workbench retarget action
+     * ({@link org.eclipse.ui.actions.RetargetAction RetargetAction})
+     * to work, it must be registered.
+     * You should also register actions that will participate
+     * in custom key bindings.
+     * </p>
+     *
+     * @param action the global action
+     * @see org.eclipse.ui.actions.RetargetAction
+     */
+    public void registerGlobalAction(IAction action);
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/application/IWorkbenchConfigurer.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/application/IWorkbenchConfigurer.java
new file mode 100644
index 0000000..07e55db
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/application/IWorkbenchConfigurer.java
@@ -0,0 +1,261 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 440136
+ *******************************************************************************/
+package org.eclipse.ui.application;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.window.WindowManager;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.WorkbenchException;
+
+/**
+ * Interface providing special access for configuring the workbench.
+ * <p>
+ * Note that these objects are only available to the main application
+ * (the plug-in that creates and owns the workbench).
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ *
+ * @see WorkbenchAdvisor#initialize
+ * @since 3.0
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IWorkbenchConfigurer {
+
+    /**
+     * Restore status code indicating that the saved state
+     * could not be restored, but that startup should continue
+     * with a reset state.
+     *
+     * @see #restoreState
+     */
+    public static final int RESTORE_CODE_RESET = 1;
+
+    /**
+     * Restore status code indicating that the saved state
+     * could not be restored, and that the application
+     * must exit immediately without modifying any previously
+     * saved workbench state.
+     */
+    public static final int RESTORE_CODE_EXIT = 2;
+
+    /**
+     * Returns the underlying workbench.
+     *
+     * @return the workbench
+     */
+    public IWorkbench getWorkbench();
+
+    /**
+     * Returns whether the workbench state should be saved on close and
+     * restored on subsequent open.
+     * <p>
+     * The initial value is <code>false</code>.
+     * </p>
+     *
+     * @return <code>true</code> to save and restore workbench state, or
+     * 	<code>false</code> to forget current workbench state on close.
+     */
+    public boolean getSaveAndRestore();
+
+    /**
+     * Sets whether the workbench state should be saved on close and
+     * restored on subsequent open.
+     *
+     * @param enabled <code>true</code> to save and restore workbench state, or
+     * 	<code>false</code> to forget current workbench state on close.
+     */
+    public void setSaveAndRestore(boolean enabled);
+
+	/**
+	 * Restores a workbench window from the given memento.
+	 *
+	 * @param memento the memento from which to restore the window's state
+	 * @return the configurer for the restored window
+	 * @throws WorkbenchException if an error occurred during the restore
+     * @see IWorkbenchWindowConfigurer#saveState(IMemento)
+	 * @since 3.1
+	 */
+	public IWorkbenchWindowConfigurer restoreWorkbenchWindow(IMemento memento)
+			throws WorkbenchException;
+
+    /**
+     * Returns the workbench window manager.
+     *
+     * @return the workbench window manager
+     *
+     * Note:IWorkbenchWindow is implemented using JFace's Window (and therefore uses WindowManager),
+     *   but this is an implementation detail
+     */
+    public WindowManager getWorkbenchWindowManager();
+
+    /**
+     * Declares a workbench image.
+     * <p>
+     * The workbench remembers the given image descriptor under the given name,
+     * and makes the image available to plug-ins via
+     * {@link IWorkbench#getSharedImages() IWorkbench.getSharedImages()}.
+     * For "shared" images, the workbench remembers the image descriptor and
+     * will manages the image object create from it; clients retrieve "shared"
+     * images via
+     * {@link org.eclipse.ui.ISharedImages#getImage ISharedImages.getImage()}.
+     * For the other, "non-shared" images, the workbench remembers only the
+     * image descriptor; clients retrieve the image descriptor via
+     * {@link org.eclipse.ui.ISharedImages#getImageDescriptor
+     * ISharedImages.getImageDescriptor()} and are entirely
+     * responsible for managing the image objects they create from it.
+     * (This is made confusing by the historical fact that the API interface
+     *  is called "ISharedImages".)
+     * </p>
+     *
+     * @param symbolicName the symbolic name of the image
+     * @param descriptor the image descriptor
+     * @param shared <code>true</code> if this is a shared image, and
+     * <code>false</code> if this is not a shared image
+     * @see org.eclipse.ui.ISharedImages#getImage
+     * @see org.eclipse.ui.ISharedImages#getImageDescriptor
+     */
+    public void declareImage(String symbolicName, ImageDescriptor descriptor,
+            boolean shared);
+
+    /**
+     * Forces the workbench to close due to an emergency. This method should
+     * only be called when the workbench is in dire straights and cannot
+     * continue, and cannot even risk a normal workbench close (think "out of
+     * memory" or "unable to create shell"). When this method is called, an
+     * abbreviated workbench shutdown sequence is performed (less critical
+     * steps may be skipped). The workbench advisor is still called; however,
+     * it must not attempt to communicate with the user. While an emergency
+     * close is in progress, <code>emergencyClosing</code> returns
+     * <code>true</code>. Workbench advisor methods should always check this
+     * flag before communicating with the user.
+     *
+     * @see #emergencyClosing
+     */
+    public void emergencyClose();
+
+    /**
+     * Returns whether the workbench is being closed due to an emergency.
+     * When this method returns <code>true</code>, the workbench is in dire
+     * straights and cannot continue. Indeed, things are so bad that we cannot
+     * even risk a normal workbench close. Workbench advisor methods should
+     * always check this flag before attempting to communicate with the user.
+     *
+     * @return <code>true</code> if the workbench is in the process of being
+     * closed under emergency conditions, and <code>false</code> otherwise
+     */
+    public boolean emergencyClosing();
+
+    /**
+     * Returns an object that can be used to configure the given window.
+     *
+     * @param window a workbench window
+     * @return a workbench window configurer
+     */
+    public IWorkbenchWindowConfigurer getWindowConfigurer(
+            IWorkbenchWindow window);
+
+    /**
+     * Returns the data associated with the workbench at the given key.
+     *
+     * @param key the key
+     * @return the data, or <code>null</code> if there is no data at the given
+     * key
+     */
+    public Object getData(String key);
+
+    /**
+     * Sets the data associated with the workbench at the given key.
+     *
+     * @param key the key
+     * @param data the data, or <code>null</code> to delete existing data
+     */
+    public void setData(String key, Object data);
+
+    /**
+     * Restores the workbench state saved from the previous session, if any.
+     * This includes any open windows and their open perspectives, open views
+     * and editors, layout information, and any customizations to the open
+     * perspectives.
+     * <p>
+     * This is typically called from the advisor's <code>openWindows()</code>
+     * method.
+     * </p>
+     *
+     * @return a status object indicating whether the restore was successful
+     * @see #RESTORE_CODE_RESET
+     * @see #RESTORE_CODE_EXIT
+     * @see WorkbenchAdvisor#openWindows
+     */
+    public IStatus restoreState();
+
+    /**
+     * Opens the first time window, using the default perspective and
+     * default page input.
+     * <p>
+     * This is typically called from the advisor's <code>openWindows()</code>
+     * method.
+     * </p>
+     *
+     * @see WorkbenchAdvisor#openWindows
+     */
+    public void openFirstTimeWindow();
+
+    /**
+	 * Returns <code>true</code> if the workbench should exit when the last
+	 * window is closed, <code>false</code> if the window should just be
+	 * closed, leaving the workbench (and its event loop) running.
+	 * <p>
+	 * If <code>true</code>, the last window's state is saved before closing,
+	 * so that it will be restored in the next session. This applies only if
+	 * {@link #getSaveAndRestore() returns <code>true</code>}).
+	 * </p>
+	 * <p>
+	 * If <code>false</code>, the window is simply closed, losing its state.
+	 * </p>
+	 * <p>
+	 * If the workbench is left running, it can be closed using
+	 * {@link IWorkbench#close()}, or a new window can be opened using
+	 * {@link IWorkbench#openWorkbenchWindow(String, IAdaptable)}.
+	 * </p>
+	 * <p>
+	 * The initial value is <code>true</code>.
+	 * </p>
+	 *
+	 * @return <code>true</code> if the workbench will exit when the last
+	 *         window is closed, <code>false</code> if the window should just
+	 *         be closed
+	 * @since 3.1
+	 */
+    public boolean getExitOnLastWindowClose();
+
+    /**
+	 * Sets whether the workbench should exit when the last window is closed, or
+	 * whether the window should just be closed, leaving the workbench (and its
+	 * event loop) running.
+	 * <p>
+	 * For more details, see {@link #getExitOnLastWindowClose()}.
+	 * </p>
+	 *
+	 * @param enabled
+	 *            <code>true</code> if the workbench should exit when the last
+	 *            window is closed, <code>false</code> if the window should
+	 *            just be closed
+	 * @since 3.1
+	 */
+    public void setExitOnLastWindowClose(boolean enabled);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/application/IWorkbenchWindowConfigurer.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/application/IWorkbenchWindowConfigurer.java
new file mode 100644
index 0000000..a51cd1a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/application/IWorkbenchWindowConfigurer.java
@@ -0,0 +1,397 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 440136
+ *     Denis Zygann <d.zygann@web.de> - Bug 457390
+ *******************************************************************************/
+package org.eclipse.ui.application;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.swt.dnd.DropTargetListener;
+import org.eclipse.swt.dnd.Transfer;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IWorkbenchWindow;
+
+/**
+ * Interface providing special access for configuring workbench windows.
+ * <p>
+ * Window configurer objects are in 1-1 correspondence with the workbench
+ * windows they configure. Clients may use <code>get/setData</code> to
+ * associate arbitrary state with the window configurer object.
+ * </p>
+ * <p>
+ * Note that these objects are only available to the main application
+ * (the plug-in that creates and owns the workbench).
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ *
+ * @see IWorkbenchConfigurer#getWindowConfigurer
+ * @see WorkbenchAdvisor#preWindowOpen
+ * @since 3.0
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IWorkbenchWindowConfigurer {
+    /**
+     * Returns the underlying workbench window.
+     *
+     * @return the workbench window
+     */
+    public IWorkbenchWindow getWindow();
+
+    /**
+     * Returns the workbench configurer.
+     *
+     * @return the workbench configurer
+     */
+    public IWorkbenchConfigurer getWorkbenchConfigurer();
+
+    /**
+     * Returns the action bar configurer for this workbench
+     * window.
+     *
+     * @return the action bar configurer
+     */
+    public IActionBarConfigurer getActionBarConfigurer();
+
+    /**
+     * Returns the title of the underlying workbench window.
+     *
+     * @return the window title
+     */
+    public String getTitle();
+
+    /**
+     * Sets the title of the underlying workbench window.
+     *
+     * @param title the window title
+     */
+    public void setTitle(String title);
+
+    /**
+     * Returns whether the underlying workbench window has a menu bar.
+     * <p>
+     * The initial value is <code>true</code>.
+     * </p>
+     *
+     * @return <code>true</code> for a menu bar, and <code>false</code>
+     * for no menu bar
+     */
+    public boolean getShowMenuBar();
+
+    /**
+     * Sets whether the underlying workbench window has a menu bar.
+     *
+     * @param show <code>true</code> for a menu bar, and <code>false</code>
+     * for no menu bar
+     */
+    public void setShowMenuBar(boolean show);
+
+    /**
+     * Returns whether the underlying workbench window has a cool bar.
+     * <p>
+     * The initial value is <code>true</code>.
+     * </p>
+     *
+     * @return <code>true</code> for a cool bar, and <code>false</code>
+     * for no cool bar
+     */
+    public boolean getShowCoolBar();
+
+    /**
+     * Sets whether the underlying workbench window has a cool bar.
+     *
+     * @param show <code>true</code> for a cool bar, and <code>false</code>
+     * for no cool bar
+     */
+    public void setShowCoolBar(boolean show);
+
+    /**
+     * Returns whether the underlying workbench window has a status line.
+     * <p>
+     * The initial value is <code>true</code>.
+     * </p>
+     *
+     * @return <code>true</code> for a status line, and <code>false</code>
+     * for no status line
+     */
+    public boolean getShowStatusLine();
+
+    /**
+     * Sets whether the underlying workbench window has a status line.
+     *
+     * @param show <code>true</code> for a status line, and <code>false</code>
+     * for no status line
+     */
+    public void setShowStatusLine(boolean show);
+
+    /**
+     * Returns whether the underlying workbench window has a perspective bar (the
+     * perspective bar provides buttons to quickly switch between perspectives).
+     * <p>
+     * The initial value is <code>false</code>.
+     * </p>
+     *
+     * @return <code>true</code> for a perspective bar, and <code>false</code>
+     * for no perspective bar
+     */
+    public boolean getShowPerspectiveBar();
+
+    /**
+     * Sets whether the underlying workbench window has a perspective bar (the
+     * perspective bar provides buttons to quickly switch between perspectives).
+     *
+     * @param show <code>true</code> for a perspective bar, and
+     * <code>false</code> for no perspective bar
+     */
+    public void setShowPerspectiveBar(boolean show);
+
+    /**
+     * Returns whether the underlying workbench window has fast view bars.
+     * <p>
+     * The initial value is <code>false</code>.
+     * </p>
+     *
+     * @return <code>true</code> for fast view bars, and
+     * <code>false</code> for no fast view bars
+     * @deprecated discontinued support for fast views
+     */
+    @Deprecated
+    public boolean getShowFastViewBars();
+
+    /**
+     * Sets whether the underlying workbench window has fast view bars.
+     *
+     * @param enable <code>true</code> for fast view bars, and
+     * <code>false</code> for no fast view bars
+     * @deprecated discontinued support for fast views
+     */
+    @Deprecated
+    public void setShowFastViewBars(boolean enable);
+
+    /**
+     * Returns whether the underlying workbench window has a progress indicator.
+     * <p>
+     * The initial value is <code>false</code>.
+     * </p>
+     *
+     * @return <code>true</code> for a progress indicator, and <code>false</code>
+     * for no progress indicator
+     */
+    public boolean getShowProgressIndicator();
+
+    /**
+     * Sets whether the underlying workbench window has a progress indicator.
+     *
+     * @param show <code>true</code> for a progress indicator, and <code>false</code>
+     * for no progress indicator
+     */
+    public void setShowProgressIndicator(boolean show);
+
+    /**
+     * Returns the style bits to use for the window's shell when it is created.
+     * The default is <code>SWT.SHELL_TRIM</code>.
+     *
+     * @return the shell style bits
+     */
+    public int getShellStyle();
+
+    /**
+     * Sets the style bits to use for the window's shell when it is created.
+     * This method has no effect after the shell is created.
+     * That is, it must be called within the <code>preWindowOpen</code>
+     * callback on <code>WorkbenchAdvisor</code>.
+     * <p>
+     * For more details on the applicable shell style bits, see the
+     * documentation for {@link org.eclipse.swt.widgets.Shell}.
+     * </p>
+     *
+     * @param shellStyle the shell style bits
+     */
+    public void setShellStyle(int shellStyle);
+
+    /**
+     * Returns the size to use for the window's shell when it is created.
+     *
+     * @return the initial size to use for the shell
+     */
+    public Point getInitialSize();
+
+    /**
+     * Sets the size to use for the window's shell when it is created.
+     * This method has no effect after the shell is created.
+     * That is, it must be called within the <code>preWindowOpen</code>
+     * callback on <code>WorkbenchAdvisor</code>.
+     *
+     * @param initialSize the initial size to use for the shell
+     */
+    public void setInitialSize(Point initialSize);
+
+    /**
+     * Returns the data associated with this workbench window at the given key.
+     *
+     * @param key the key
+     * @return the data, or <code>null</code> if there is no data at the given
+     * key
+     */
+    public Object getData(String key);
+
+    /**
+     * Sets the data associated with this workbench window at the given key.
+     *
+     * @param key the key
+     * @param data the data, or <code>null</code> to delete existing data
+     */
+    public void setData(String key, Object data);
+
+    /**
+     * Adds the given drag and drop <code>Transfer</code> type to the ones
+     * supported for drag and drop on the editor area of this workbench window.
+     * <p>
+     * The workbench advisor would ordinarily call this method from the
+     * <code>preWindowOpen</code> callback.
+     * A newly-created workbench window supports no drag and drop transfer
+     * types. Adding <code>EditorInputTransfer.getInstance()</code>
+     * enables <code>IEditorInput</code>s to be transferred.
+     * </p>
+     * <p>
+     * Note that drag and drop to the editor area requires adding one or more
+     * transfer types (using <code>addEditorAreaTransfer</code>) and
+     * configuring a drop target listener
+     * (with <code>configureEditorAreaDropListener</code>)
+     * capable of handling any of those transfer types.
+     * </p>
+     *
+     * @param transfer a drag and drop transfer object
+     * @see #configureEditorAreaDropListener
+     * @see org.eclipse.ui.part.EditorInputTransfer
+     */
+    public void addEditorAreaTransfer(Transfer transfer);
+
+    /**
+     * Configures the drop target listener for the editor area of this workbench window.
+     * <p>
+     * The workbench advisor ordinarily calls this method from the
+     * <code>preWindowOpen</code> callback.
+     * A newly-created workbench window has no configured drop target listener for its
+     * editor area.
+     * </p>
+     * <p>
+     * Note that drag and drop to the editor area requires adding one or more
+     * transfer types (using <code>addEditorAreaTransfer</code>) and
+     * configuring a drop target listener
+     * (with <code>configureEditorAreaDropListener</code>)
+     * capable of handling any of those transfer types.
+     * </p>
+     *
+     * @param dropTargetListener the drop target listener that will handle
+     * requests to drop an object on to the editor area of this window
+     *
+     * @see #addEditorAreaTransfer
+     */
+    public void configureEditorAreaDropListener(
+            DropTargetListener dropTargetListener);
+
+    /**
+	 * Creates the menu bar for the window's shell.
+	 * <p>
+	 * This should only be called if the advisor is defining custom window
+	 * contents in <code>createWindowContents</code>, and may only be called
+	 * once. The caller must set it in the shell using
+	 * <code>Shell.setMenuBar(Menu)</code> but must not make add, remove or
+	 * change items in the result. The menu bar is populated by the window's
+	 * menu manager. The application can add to the menu manager in the
+	 * advisor's <code>fillActionBars</code> method instead.
+	 * </p>
+	 *
+	 * @return the menu bar, suitable for setting in the shell
+	 * @deprecated This method is no longer used. Applications now define
+	 *             workbench window contents in their application model.
+	 */
+	@Deprecated
+    public Menu createMenuBar();
+
+    /**
+	 * Creates the cool bar control.
+	 * <p>
+	 * This should only be called if the advisor is defining custom window
+	 * contents in <code>createWindowContents</code>, and may only be called
+	 * once. The caller must lay out the cool bar appropriately within the
+	 * parent, but must not add, remove or change items in the result (hence the
+	 * return type of <code>Control</code>). The cool bar is populated by the
+	 * window's cool bar manager. The application can add to the cool bar
+	 * manager in the advisor's <code>fillActionBars</code> method instead.
+	 * </p>
+	 *
+	 * @param parent
+	 *            the parent composite
+	 * @return the cool bar control, suitable for laying out in the parent
+	 * @deprecated This method is no longer used. Applications now define
+	 *             workbench window contents in their application model.
+	 */
+	@Deprecated
+    public Control createCoolBarControl(Composite parent);
+
+    /**
+	 * Creates the status line control.
+	 * <p>
+	 * This should only be called if the advisor is defining custom window
+	 * contents in <code>createWindowContents</code>, and may only be called
+	 * once. The caller must lay out the status line appropriately within the
+	 * parent, but must not add, remove or change items in the result (hence the
+	 * return type of <code>Control</code>). The status line is populated by the
+	 * window's status line manager. The application can add to the status line
+	 * manager in the advisor's <code>fillActionBars</code> method instead.
+	 * </p>
+	 *
+	 * @param parent
+	 *            the parent composite
+	 * @return the status line control, suitable for laying out in the parent
+	 * @deprecated This method is no longer used. Applications now define
+	 *             workbench window contents in their application model.
+	 */
+	@Deprecated
+    public Control createStatusLineControl(Composite parent);
+
+    /**
+	 * Creates the page composite, in which the window's pages, and their views
+	 * and editors, appear.
+	 * <p>
+	 * This should only be called if the advisor is defining custom window
+	 * contents in <code>createWindowContents</code>, and may only be called
+	 * once. The caller must lay out the page composite appropriately within the
+	 * parent, but must not add, remove or change items in the result (hence the
+	 * return type of <code>Control</code>). The page composite is populated by
+	 * the workbench.
+	 * </p>
+	 *
+	 * @param parent
+	 *            the parent composite
+	 * @return the page composite, suitable for laying out in the parent
+	 * @deprecated This method is no longer used. Applications now define
+	 *             workbench window contents in their application model.
+	 */
+	@Deprecated
+    public Control createPageComposite(Composite parent);
+
+	/**
+	 * Saves the current state of the window using the specified memento.
+	 *
+	 * @param memento the memento in which to save the window's state
+	 * @return a status object indicating whether the save was successful
+     * @see IWorkbenchConfigurer#restoreWorkbenchWindow(IMemento)
+	 * @since 3.1
+	 */
+	public IStatus saveState(IMemento memento);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/application/WorkbenchAdvisor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/application/WorkbenchAdvisor.java
new file mode 100644
index 0000000..df28c43
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/application/WorkbenchAdvisor.java
@@ -0,0 +1,893 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.application;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IWorkbenchPreferenceConstants;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.WorkbenchException;
+import org.eclipse.ui.internal.StartupThreading;
+import org.eclipse.ui.internal.StartupThreading.StartupRunnable;
+import org.eclipse.ui.internal.UISynchronizer;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.WorkbenchWindowConfigurer;
+import org.eclipse.ui.internal.application.CompatibilityWorkbenchWindowAdvisor;
+import org.eclipse.ui.internal.util.PrefUtil;
+import org.eclipse.ui.model.ContributionComparator;
+import org.eclipse.ui.model.IContributionService;
+import org.eclipse.ui.statushandlers.AbstractStatusHandler;
+import org.eclipse.ui.statushandlers.StatusManager;
+import org.eclipse.ui.statushandlers.WorkbenchErrorHandler;
+
+/**
+ * Public base class for configuring the workbench.
+ * <p>
+ * Note that the workbench advisor object is created in advance of creating the
+ * workbench. However, by the time the workbench starts calling methods on this
+ * class, <code>PlatformUI.getWorkbench</code> is guaranteed to have been
+ * properly initialized.
+ * </p>
+ * <p>
+ * Example of creating and running a workbench (in an
+ * <code>IPlatformRunnable</code>):
+ *
+ * <pre>
+ * <code>
+ *           public class MyApplication implements IPlatformRunnable {
+ *             public Object run(Object args) {
+ *               WorkbenchAdvisor workbenchAdvisor = new MyWorkbenchAdvisor();
+ *               Display display = PlatformUI.createDisplay();
+ *               int returnCode = PlatformUI.createAndRunWorkbench(display, workbenchAdvisor);
+ *               if (returnCode == PlatformUI.RETURN_RESTART) {
+ *                  return IPlatformRunnable.EXIT_RESTART;
+ *               } else {
+ *                  return IPlatformRunnable.EXIT_OK;
+ *             }
+ *           }
+ * </code>
+ * </pre>
+ *
+ * </p>
+ * <p>
+ * An application should declare a subclass of <code>WorkbenchAdvisor</code>
+ * and override methods to configure the workbench to suit the needs of the
+ * particular application.
+ * </p>
+ * <p>
+ * The following advisor methods are called at strategic points in the
+ * workbench's lifecycle (all occur within the dynamic scope of the call to
+ * {@link PlatformUI#createAndRunWorkbench PlatformUI.createAndRunWorkbench}):
+ * <ul>
+ * <li><code>initialize</code> - called first; before any windows; use to
+ * register things</li>
+ * <li><code>preStartup</code> - called second; after initialize but before
+ * first window is opened; use to temporarily disable things during startup or
+ * restore</li>
+ * <li><code>postStartup</code> - called third; after first window is opened;
+ * use to reenable things temporarily disabled in previous step</li>
+ * <li><code>postRestore</code> - called after the workbench and its windows
+ * has been recreated from a previously saved state; use to adjust the restored
+ * workbench</li>
+ * <li><code>preWindowOpen</code> - called as each window is being opened;
+ * use to configure aspects of the window other than actions bars </li>
+ * <li><code>fillActionBars</code> - called after <code>preWindowOpen</code>
+ * to configure a window's action bars</li>
+ * <li><code>postWindowRestore</code> - called after a window has been
+ * recreated from a previously saved state; use to adjust the restored window</li>
+ * <li><code>postWindowCreate</code> - called after a window has been
+ * created, either from an initial state or from a restored state; used to
+ * adjust the window</li>
+ * <li><code>openIntro</code> - called immediately before a window is opened
+ * in order to create the introduction component, if any.</li>
+ * <li><code>postWindowOpen</code> - called after a window has been opened;
+ * use to hook window listeners, etc.</li>
+ * <li><code>preWindowShellClose</code> - called when a window's shell is
+ * closed by the user; use to pre-screen window closings</li>
+ * <li><code>eventLoopException</code> - called to handle the case where the
+ * event loop has crashed; use to inform the user that things are not well</li>
+ * <li><code>eventLoopIdle</code> - called when there are currently no more
+ * events to be processed; use to perform other work or to yield until new
+ * events enter the queue</li>
+ * <li><code>preShutdown</code> - called immediately prior to workbench
+ * shutdown before any windows have been closed; allows the advisor to veto the
+ * shutdown</li>
+ * <li><code>postShutdown</code> - called last; after event loop has
+ * terminated and all windows have been closed; use to deregister things
+ * registered during initialize</li>
+ * </ul>
+ * </p>
+ *
+ * @since 3.0
+ */
+public abstract class WorkbenchAdvisor {
+
+	/**
+	 * Bit flag for {@link #fillActionBars fillActionBars} indicating that the
+	 * operation is not filling the action bars of an actual workbench window,
+	 * but rather a proxy (used for perspective customization).
+	 *
+	 * @deprecated use {@link ActionBarAdvisor#FILL_PROXY instead}
+	 */
+	@Deprecated
+	public static final int FILL_PROXY = ActionBarAdvisor.FILL_PROXY;
+
+	/**
+	 * Bit flag for {@link #fillActionBars fillActionBars} indicating that the
+	 * operation is supposed to fill (or describe) the workbench window's menu
+	 * bar.
+	 *
+	 * @deprecated use {@link ActionBarAdvisor#FILL_MENU_BAR instead}
+	 */
+	@Deprecated
+	public static final int FILL_MENU_BAR = ActionBarAdvisor.FILL_MENU_BAR;
+
+	/**
+	 * Bit flag for {@link #fillActionBars fillActionBars} indicating that the
+	 * operation is supposed to fill (or describe) the workbench window's cool
+	 * bar.
+	 *
+	 * @deprecated use {@link ActionBarAdvisor#FILL_COOL_BAR instead}
+	 */
+	@Deprecated
+	public static final int FILL_COOL_BAR = ActionBarAdvisor.FILL_COOL_BAR;
+
+	/**
+	 * Bit flag for {@link #fillActionBars fillActionBars} indicating that the
+	 * operation is supposed to fill (or describe) the workbench window's status
+	 * line.
+	 *
+	 * @deprecated use {@link ActionBarAdvisor#FILL_STATUS_LINE instead}
+	 */
+	@Deprecated
+	public static final int FILL_STATUS_LINE = ActionBarAdvisor.FILL_STATUS_LINE;
+
+	/**
+	 * The workbench configurer.
+	 */
+	private IWorkbenchConfigurer workbenchConfigurer;
+
+	/**
+	 * The workbench error handler.
+	 */
+	private AbstractStatusHandler workbenchErrorHandler;
+
+	private boolean introOpened;
+
+	/**
+	 * Creates and initializes a new workbench advisor instance.
+	 */
+	protected WorkbenchAdvisor() {
+		// do nothing
+	}
+
+	/**
+	 * Remembers the configurer and calls <code>initialize</code>.
+	 * <p>
+	 * For internal use by the workbench only.
+	 * </p>
+	 *
+	 * @param configurer
+	 *            an object for configuring the workbench
+	 */
+	public final void internalBasicInitialize(IWorkbenchConfigurer configurer) {
+		if (workbenchConfigurer != null) {
+			throw new IllegalStateException();
+		}
+		this.workbenchConfigurer = configurer;
+		initialize(configurer);
+	}
+
+	/**
+	 * Performs arbitrary initialization before the workbench starts running.
+	 * <p>
+	 * This method is called during workbench initialization prior to any
+	 * windows being opened. Clients must not call this method directly
+	 * (although super calls are okay). The default implementation does nothing.
+	 * Subclasses may override. Typical clients will use the configurer passed
+	 * in to tweak the workbench. If further tweaking is required in the future,
+	 * the configurer may be obtained using <code>getWorkbenchConfigurer</code>.
+	 * </p>
+	 *
+	 * @param configurer
+	 *            an object for configuring the workbench
+	 */
+	public void initialize(IWorkbenchConfigurer configurer) {
+		// do nothing
+	}
+
+	/**
+	 * Returns the workbench configurer for the advisor. Can be
+	 * <code>null</code> if the advisor is not initialized yet.
+	 *
+	 * @return the workbench configurer, or <code>null</code> if the advisor
+	 *         is not initialized yet
+	 */
+	protected IWorkbenchConfigurer getWorkbenchConfigurer() {
+		return workbenchConfigurer;
+	}
+
+	/**
+	 * Returns the workbench error handler for the advisor.
+	 *
+	 * @return the workbench error handler
+	 * @since 3.3
+	 */
+	public synchronized AbstractStatusHandler getWorkbenchErrorHandler() {
+		if (workbenchErrorHandler == null) {
+			workbenchErrorHandler = new WorkbenchErrorHandler();
+		}
+		return workbenchErrorHandler;
+	}
+
+	/**
+	 * Performs arbitrary actions just before the first workbench window is
+	 * opened (or restored).
+	 * <p>
+	 * This method is called after the workbench has been initialized and just
+	 * before the first window is about to be opened. Clients must not call this
+	 * method directly (although super calls are okay). The default
+	 * implementation does nothing. Subclasses may override.
+	 * </p>
+	 */
+	public void preStartup() {
+		// do nothing
+	}
+
+	/**
+	 * Performs arbitrary actions after the workbench windows have been opened
+	 * (or restored), but before the main event loop is run.
+	 * <p>
+	 * This method is called just after the windows have been opened. Clients
+	 * must not call this method directly (although super calls are okay). The
+	 * default implementation does nothing. Subclasses may override. It is okay
+	 * to call <code>IWorkbench.close()</code> from this method.
+	 * </p>
+	 */
+	public void postStartup() {
+		// do nothing
+	}
+
+	/**
+	 * Performs arbitrary finalization before the workbench is about to shut
+	 * down.
+	 * <p>
+	 * This method is called immediately prior to workbench shutdown before any
+	 * windows have been closed. Clients must not call this method directly
+	 * (although super calls are okay). The default implementation returns
+	 * <code>true</code>. Subclasses may override.
+	 * </p>
+	 * <p>
+	 * The advisor may veto a regular shutdown by returning <code>false</code>,
+	 * although this will be ignored if the workbench is being forced to shut
+	 * down.
+	 * </p>
+	 *
+	 * @return <code>true</code> to allow the workbench to proceed with
+	 *         shutdown, <code>false</code> to veto a non-forced shutdown
+	 */
+	public boolean preShutdown() {
+		return true;
+	}
+
+	/**
+	 * Performs arbitrary finalization after the workbench stops running.
+	 * <p>
+	 * This method is called during workbench shutdown after all windows have
+	 * been closed. Clients must not call this method directly (although super
+	 * calls are okay). The default implementation does nothing. Subclasses may
+	 * override.
+	 * </p>
+	 */
+	public void postShutdown() {
+		// do nothing
+	}
+
+	/**
+	 * Performs arbitrary actions when the event loop crashes (the code that
+	 * handles a UI event throws an exception that is not caught).
+	 * <p>
+	 * This method is called when the code handling a UI event throws an
+	 * exception. In a perfectly functioning application, this method would
+	 * never be called. In practice, it comes into play when there are bugs in
+	 * the code that trigger unchecked runtime exceptions. It is also activated
+	 * when the system runs short of memory, etc. Fatal errors (ThreadDeath) are
+	 * not passed on to this method, as there is nothing that could be done.
+	 * </p>
+	 * <p>
+	 * Clients must not call this method directly (although super calls are
+	 * okay). The default implementation logs the problem so that it does not go
+	 * unnoticed. Subclasses may override or extend this method. It is generally
+	 * a bad idea to override with an empty method, and you should be especially
+	 * careful when handling Errors.
+	 * </p>
+	 *
+	 * @param exception
+	 *            the uncaught exception that was thrown inside the UI event
+	 *            loop
+	 */
+	public void eventLoopException(Throwable exception) {
+		// Protection from client doing super(null) call
+		if (exception == null) {
+			return;
+		}
+
+		try {
+			StatusManager.getManager().handle(
+					new Status(IStatus.ERROR, WorkbenchPlugin.PI_WORKBENCH,
+							"Unhandled event loop exception", exception)); //$NON-NLS-1$
+
+			if (WorkbenchPlugin.DEBUG) {
+				exception.printStackTrace();
+			}
+		} catch (Throwable e) {
+			// One of the log listeners probably failed. Core should have logged
+			// the
+			// exception since its the first listener.
+			System.err.println("Error while logging event loop exception:"); //$NON-NLS-1$
+			exception.printStackTrace();
+			System.err.println("Logging exception:"); //$NON-NLS-1$
+			e.printStackTrace();
+		}
+	}
+
+	/**
+	 * Performs arbitrary work or yields when there are no events to be
+	 * processed.
+	 * <p>
+	 * This method is called when there are currently no more events on the
+	 * queue to be processed at the moment.
+	 * </p>
+	 * <p>
+	 * Clients must not call this method directly (although super calls are
+	 * okay). The default implementation yields until new events enter the
+	 * queue. Subclasses may override or extend this method. It is generally a
+	 * bad idea to override with an empty method. It is okay to call
+	 * <code>IWorkbench.close()</code> from this method.
+	 * </p>
+	 *
+	 * @param display
+	 *            the main display of the workbench UI
+	 */
+	public void eventLoopIdle(Display display) {
+		// default: yield cpu until new events enter the queue
+		display.sleep();
+	}
+
+	/**
+	 * Creates a new workbench window advisor for configuring a new workbench
+	 * window via the given workbench window configurer. Clients should override
+	 * to provide their own window configurer. This method replaces all the
+	 * other window and action bar lifecycle methods on the workbench advisor.
+	 * <p>
+	 * The default implementation creates a window advisor that calls back to
+	 * the legacy window and action bar lifecycle methods on the workbench
+	 * advisor, for backwards compatibility with 3.0.
+	 * </p>
+	 *
+	 * @param configurer
+	 *            the workbench window configurer
+	 * @return a new workbench window advisor
+	 * @since 3.1
+	 */
+	public WorkbenchWindowAdvisor createWorkbenchWindowAdvisor(
+			IWorkbenchWindowConfigurer configurer) {
+		return new CompatibilityWorkbenchWindowAdvisor(this, configurer);
+	}
+
+	/**
+	 * Performs arbitrary actions before the given workbench window is opened.
+	 * <p>
+	 * This method is called before the window's controls have been created.
+	 * Clients must not call this method directly (although super calls are
+	 * okay). The default implementation does nothing. Subclasses may override.
+	 * Typical clients will use the configurer passed in to tweak the workbench
+	 * window in an application-specific way; however, filling the window's menu
+	 * bar, tool bar, and status line must be done in
+	 * {@link #fillActionBars fillActionBars}, which is called immediately
+	 * after this method is called.
+	 * </p>
+	 *
+	 * @param configurer
+	 *            an object for configuring the particular workbench window
+	 *            being opened
+	 *
+	 * @deprecated since 3.1, override
+	 *             {@link WorkbenchWindowAdvisor#preWindowOpen()} instead
+	 * @see #createWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer)
+	 */
+	@Deprecated
+	public void preWindowOpen(IWorkbenchWindowConfigurer configurer) {
+		// do nothing
+	}
+
+	/**
+	 * Configures the action bars using the given action bar configurer. Under
+	 * normal circumstances, <code>flags</code> does not include
+	 * <code>FILL_PROXY</code>, meaning this is a request to fill the
+	 * actions\ bars of the given workbench window; the remaining flags indicate
+	 * which combination of the menu bar (<code>FILL_MENU_BAR</code>), the
+	 * tool bar (<code>FILL_COOL_BAR</code>), and the status line (<code>FILL_STATUS_LINE</code>)
+	 * are to be filled.
+	 * <p>
+	 * If <code>flags</code> does include <code>FILL_PROXY</code>, then
+	 * this is a request to describe the actions bars of the given workbench
+	 * window (which will already have been filled); again, the remaining flags
+	 * indicate which combination of the menu bar, the tool bar, and the status
+	 * line are to be described. The actions included in the proxy action bars
+	 * can be the same instances as in the actual window's action bars. Calling
+	 * <code>ActionFactory</code> to create new action instances is not
+	 * recommended, because these actions internally register listeners with the
+	 * window and there is no opportunity to dispose of these actions.
+	 * </p>
+	 * <p>
+	 * This method is called just after {@link #preWindowOpen preWindowOpen}.
+	 * Clients must not call this method directly (although super calls are
+	 * okay). The default implementation does nothing. Subclasses may override.
+	 * </p>
+	 *
+	 * @param window
+	 *            the workbench window
+	 * @param configurer
+	 *            the action bar configurer object
+	 * @param flags
+	 *            bit mask composed from the constants
+	 *            {@link #FILL_MENU_BAR FILL_MENU_BAR},
+	 *            {@link #FILL_COOL_BAR FILL_COOL_BAR},
+	 *            {@link #FILL_STATUS_LINE FILL_STATUS_LINE}, and
+	 *            {@link #FILL_PROXY FILL_PROXY} Note: should 1st param be
+	 *            IWorkbenchWindowConfigurer to be more consistent with other
+	 *            methods? Note: suggest adding ActionBuilder as API, to
+	 *            encapsulate the action building outside of the advisor, and to
+	 *            handle the common pattern of hanging onto the action builder
+	 *            in order to properly handle FILL_PROXY
+	 *
+	 * @deprecated since 3.1, override
+	 *             {@link ActionBarAdvisor#fillActionBars(int)} instead
+	 * @see #createWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer)
+	 * @see WorkbenchWindowAdvisor#createActionBarAdvisor(IActionBarConfigurer)
+	 */
+	@Deprecated
+	public void fillActionBars(IWorkbenchWindow window,
+			IActionBarConfigurer configurer, int flags) {
+		// do nothing by default
+	}
+
+	/**
+	 * Performs arbitrary actions after the given workbench window has been
+	 * restored, but before it is opened.
+	 * <p>
+	 * This method is called after a previously-saved window have been
+	 * recreated. This method is not called when a new window is created from
+	 * scratch. This method is never called when a workbench is started for the
+	 * very first time, or when workbench state is not saved or restored.
+	 * Clients must not call this method directly (although super calls are
+	 * okay). The default implementation does nothing. Subclasses may override.
+	 * It is okay to call <code>IWorkbench.close()</code> from this method.
+	 * </p>
+	 *
+	 * @param configurer
+	 *            an object for configuring the particular workbench window just
+	 *            restored
+	 *
+	 * @deprecated since 3.1, override
+	 *             {@link WorkbenchWindowAdvisor#postWindowRestore()} instead
+	 * @see #createWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer)
+	 */
+	@Deprecated
+	public void postWindowRestore(IWorkbenchWindowConfigurer configurer)
+			throws WorkbenchException {
+		// do nothing
+	}
+
+	/**
+	 * Opens the introduction componenet.
+	 * <p>
+	 * Clients must not call this method directly (although super calls are
+	 * okay). The default implementation opens the intro in the first window
+	 * provided the preference IWorkbenchPreferences.SHOW_INTRO is
+	 * <code>true</code>. If an intro is shown then this preference will be
+	 * set to <code>false</code>. Subsequently, and intro will be shown only
+	 * if <code>WorkbenchConfigurer.getSaveAndRestore()</code> returns
+	 * <code>true</code> and the introduction was visible on last shutdown.
+	 * Subclasses may override.
+	 * </p>
+	 *
+	 * @param configurer
+	 *            configurer an object for configuring the particular workbench
+	 *            window just created
+	 *
+	 * @deprecated since 3.1, override
+	 *             {@link WorkbenchWindowAdvisor#openIntro()} instead
+	 * @see #createWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer)
+	 */
+	@Deprecated
+	public void openIntro(IWorkbenchWindowConfigurer configurer) {
+		if (introOpened) {
+			return;
+		}
+
+		introOpened = true;
+
+		boolean showIntro = PrefUtil.getAPIPreferenceStore().getBoolean(
+				IWorkbenchPreferenceConstants.SHOW_INTRO);
+
+		if (!showIntro) {
+			return;
+		}
+
+		if (getWorkbenchConfigurer().getWorkbench().getIntroManager()
+				.hasIntro()) {
+			PrefUtil.getAPIPreferenceStore().setValue(
+					IWorkbenchPreferenceConstants.SHOW_INTRO, false);
+			PrefUtil.saveAPIPrefs();
+
+			getWorkbenchConfigurer().getWorkbench().getIntroManager()
+					.showIntro(configurer.getWindow(), false);
+		}
+	}
+
+	/**
+	 * Performs arbitrary actions after the given workbench window has been
+	 * created (possibly after being restored), but has not yet been opened.
+	 * <p>
+	 * This method is called after a new window has been created from scratch,
+	 * or when a previously-saved window has been restored. In the latter case,
+	 * this method is called after <code>postWindowRestore</code>. Clients
+	 * must not call this method directly (although super calls are okay). The
+	 * default implementation does nothing. Subclasses may override.
+	 * </p>
+	 *
+	 * @param configurer
+	 *            an object for configuring the particular workbench window just
+	 *            created
+	 *
+	 * @deprecated since 3.1, override
+	 *             {@link WorkbenchWindowAdvisor#postWindowCreate()} instead
+	 * @see #createWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer)
+	 */
+	@Deprecated
+	public void postWindowCreate(IWorkbenchWindowConfigurer configurer) {
+		// do nothing
+	}
+
+	/**
+	 * Performs arbitrary actions after the given workbench window has been
+	 * opened (possibly after being restored).
+	 * <p>
+	 * This method is called after a window has been opened. This method is
+	 * called after a new window has been created from scratch, or when a
+	 * previously-saved window has been restored. Clients must not call this
+	 * method directly (although super calls are okay). The default
+	 * implementation does nothing. Subclasses may override.
+	 * </p>
+	 *
+	 * @param configurer
+	 *            an object for configuring the particular workbench window just
+	 *            opened
+	 *
+	 * @deprecated since 3.1, override
+	 *             {@link WorkbenchWindowAdvisor#postWindowOpen()} instead
+	 * @see #createWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer)
+	 */
+	@Deprecated
+	public void postWindowOpen(IWorkbenchWindowConfigurer configurer) {
+		// do nothing
+	}
+
+	/**
+	 * Performs arbitrary actions as the given workbench window's shell is being
+	 * closed directly, and possibly veto the close.
+	 * <p>
+	 * This method is called from a ShellListener associated with the workbench
+	 * window. It is not called when the window is being closed for other
+	 * reasons. Clients must not call this method directly (although super calls
+	 * are okay). The default implementation does nothing. Subclasses may
+	 * override. Typical clients may use the configurer passed in to access the
+	 * workbench window being closed. If this method returns <code>false</code>,
+	 * then the user's request to close the shell is ignored. This gives the
+	 * workbench advisor an opportunity to query the user and/or veto the
+	 * closing of a window under some circumstances.
+	 * </p>
+	 *
+	 * @param configurer
+	 *            an object for configuring the particular workbench window
+	 *            whose shell is being closed
+	 * @return <code>true</code> to allow the window to close, and
+	 *         <code>false</code> to prevent the window from closing
+	 * @see org.eclipse.ui.IWorkbenchWindow#close
+	 *
+	 * @deprecated since 3.1, override
+	 *             {@link WorkbenchWindowAdvisor#preWindowShellClose()} instead
+	 * @see #createWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer)
+	 */
+	@Deprecated
+	public boolean preWindowShellClose(IWorkbenchWindowConfigurer configurer) {
+		// do nothing, but allow the close() to proceed
+		return true;
+	}
+
+	/**
+	 * Performs arbitrary actions after the given workbench window is closed.
+	 * <p>
+	 * This method is called after the window's controls have been disposed.
+	 * Clients must not call this method directly (although super calls are
+	 * okay). The default implementation does nothing. Subclasses may override.
+	 * Typical clients will use the configurer passed in to tweak the workbench
+	 * window in an application-specific way.
+	 * </p>
+	 *
+	 * @param configurer
+	 *            an object for configuring the particular workbench window
+	 *            being closed
+	 *
+	 * @deprecated since 3.1, override
+	 *             {@link WorkbenchWindowAdvisor#postWindowClose()} instead
+	 * @see #createWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer)
+	 */
+	@Deprecated
+	public void postWindowClose(IWorkbenchWindowConfigurer configurer) {
+		// do nothing
+	}
+
+	/**
+	 * Returns whether the menu with the given id is an application menu of the
+	 * given window. This is used during OLE "in place" editing. Application
+	 * menus should be preserved during menu merging. All other menus may be
+	 * removed from the window.
+	 * <p>
+	 * The default implementation returns false. Subclasses may override.
+	 * </p>
+	 *
+	 * @param configurer
+	 *            an object for configuring the workbench window
+	 * @param menuId
+	 *            the menu id
+	 * @return <code>true</code> for application menus, and <code>false</code>
+	 *         for part-specific menus
+	 *
+	 * @deprecated since 3.1, override
+	 *             {@link ActionBarAdvisor#isApplicationMenu(String)} instead
+	 * @see WorkbenchWindowAdvisor#createActionBarAdvisor(IActionBarConfigurer)
+	 */
+	@Deprecated
+	public boolean isApplicationMenu(IWorkbenchWindowConfigurer configurer,
+			String menuId) {
+		// default: not an application menu
+		return false;
+	}
+
+	/**
+	 * Returns the default input for newly created workbench pages when the
+	 * input is not explicitly specified.
+	 * <p>
+	 * The default implementation returns <code>null</code>. Subclasses may
+	 * override.
+	 * </p>
+	 *
+	 * @return the default input for a new workbench window page, or
+	 *         <code>null</code> if none
+	 *
+	 * @see #createWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer)
+	 */
+	public IAdaptable getDefaultPageInput() {
+		// default: no input
+		return null;
+	}
+
+	/**
+	 * Returns the id of the perspective to use for the initial workbench
+	 * window, or <code>null</code> if no initial perspective should be shown
+	 * in the initial workbench window.
+	 * <p>
+	 * This method is called during startup when the workbench is creating the
+	 * first new window. Subclasses must implement.
+	 * </p>
+	 * <p>
+	 * If the {@link IWorkbenchPreferenceConstants#DEFAULT_PERSPECTIVE_ID}
+	 * preference is specified, it supercedes the perspective specified here.
+	 * </p>
+	 *
+	 * @return the id of the perspective for the initial window, or
+	 *         <code>null</code> if no initial perspective should be shown
+	 */
+	public abstract String getInitialWindowPerspectiveId();
+
+	/**
+	 * Returns the id of the preference page that should be presented most
+	 * prominently.
+	 * <p>
+	 * The default implementation returns <code>null</code>. Subclasses may
+	 * override.
+	 * </p>
+	 *
+	 * @return the id of the preference page, or <code>null</code> if none
+	 */
+	public String getMainPreferencePageId() {
+		// default: no opinion
+		return null;
+	}
+
+	/**
+	 * Creates the contents of the window.
+	 * <p>
+	 * The default implementation adds a menu bar, a cool bar, a status line, a
+	 * perspective bar, and a fast view bar. The visibility of these controls
+	 * can be configured using the <code>setShow*</code> methods on
+	 * <code>IWorkbenchWindowConfigurer</code>.
+	 * </p>
+	 * <p>
+	 * Subclasses may override to define custom window contents and layout, but
+	 * must call <code>IWorkbenchWindowConfigurer.createPageComposite</code>.
+	 * </p>
+	 *
+	 * @param configurer
+	 *            the window configurer
+	 * @param shell
+	 *            the window's shell
+	 * @see IWorkbenchWindowConfigurer#createMenuBar
+	 * @see IWorkbenchWindowConfigurer#createCoolBarControl
+	 * @see IWorkbenchWindowConfigurer#createStatusLineControl
+	 * @see IWorkbenchWindowConfigurer#createPageComposite
+	 *
+	 * @deprecated since 3.1, override
+	 *             {@link WorkbenchWindowAdvisor#createWindowContents(Shell)}
+	 *             instead
+	 * @see #createWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer)
+	 */
+	@Deprecated
+	public void createWindowContents(IWorkbenchWindowConfigurer configurer,
+			Shell shell) {
+		((WorkbenchWindowConfigurer) configurer).createDefaultContents(shell);
+	}
+
+	private volatile boolean initDone = false;
+
+	/**
+	 * Opens the workbench windows on startup. The default implementation tries
+	 * to restore the previously saved workbench state using
+	 * <code>IWorkbenchConfigurer.restoreWorkbenchState()</code>. If there
+	 * was no previously saved state, or if the restore failed, then a
+	 * first-time window is opened using
+	 * <code>IWorkbenchConfigurer.openFirstTimeWindow</code>.
+	 *
+	 * @return <code>true</code> to proceed with workbench startup, or
+	 *         <code>false</code> to exit
+	 */
+	public boolean openWindows() {
+		final Display display = PlatformUI.getWorkbench().getDisplay();
+		final boolean result [] = new boolean[1];
+
+		// spawn another init thread.  For API compatibility We guarantee this method is called from
+		// the UI thread but it could take enough time to disrupt progress reporting.
+		// spawn a new thread to do the grunt work of this initialization and spin the event loop
+		// ourselves just like it's done in Workbench.
+
+		final Throwable [] error = new Throwable[1];
+		Thread initThread = new Thread() {
+			@Override
+			public void run() {
+				try {
+					//declare us to be a startup thread so that our syncs will be executed
+					UISynchronizer.startupThread.set(Boolean.TRUE);
+					final IWorkbenchConfigurer [] myConfigurer = new IWorkbenchConfigurer[1];
+					StartupThreading.runWithoutExceptions(new StartupRunnable() {
+
+						@Override
+						public void runWithException() throws Throwable {
+							myConfigurer[0] = getWorkbenchConfigurer();
+
+						}});
+
+					IStatus status = myConfigurer[0].restoreState();
+					if (!status.isOK()) {
+						if (status.getCode() == IWorkbenchConfigurer.RESTORE_CODE_EXIT) {
+							result[0] = false;
+							return;
+						}
+						if (status.getCode() == IWorkbenchConfigurer.RESTORE_CODE_RESET) {
+							myConfigurer[0].openFirstTimeWindow();
+						}
+					}
+					result[0] = true;
+				} catch (Throwable e) {
+					error[0] = e;
+				}
+				finally {
+					initDone = true;
+					yield();
+					try {
+						Thread.sleep(5);
+					} catch (InterruptedException e) {
+						// this is a no-op in this case.
+					}
+					display.wake();
+				}
+			}};
+			RWT.getUISession(display).exec(initThread);
+
+		while (true) {
+			if (!display.readAndDispatch()) {
+				if (initDone)
+					break;
+				display.sleep();
+			}
+
+		}
+
+			// can only be a runtime or error
+			if (error[0] instanceof Error)
+				throw (Error)error[0];
+			else if (error[0] instanceof RuntimeException)
+				throw (RuntimeException)error[0];
+
+			return result[0];
+	}
+
+	/**
+	 * Saves arbitrary application-specific state information for this workbench
+	 * advisor.
+	 * <p>
+	 * The default implementation simply returns an OK status. Subclasses may
+	 * extend or override.
+	 * </p>
+	 *
+	 * @param memento
+	 *            the memento in which to save the advisor's state
+	 * @return a status object indicating whether the save was successful
+	 * @since 3.1
+	 */
+	public IStatus saveState(IMemento memento) {
+		return Status.OK_STATUS;
+	}
+
+	/**
+	 * Restores arbitrary application-specific state information for this
+	 * workbench advisor.
+	 * <p>
+	 * The default implementation simply returns an OK status. Subclasses may
+	 * extend or override.
+	 * </p>
+	 *
+	 * @param memento
+	 *            the memento from which to restore the advisor's state
+	 * @return a status object indicating whether the restore was successful
+	 * @since 3.1
+	 */
+	public IStatus restoreState(IMemento memento) {
+		return Status.OK_STATUS;
+	}
+
+	/**
+	 * Return the contribution comparator for the particular type of
+	 * contribution. The default implementation of this class returns a
+	 * comparator that sorts the items by label.
+	 *
+	 * The contributionType may be one of the constants in
+	 * {@link IContributionService} or it can be a value defined by the user.
+	 *
+	 * @param contributionType
+	 *            the contribution type
+	 * @return the comparator, must not return <code>null</code>
+	 * @see IContributionService#getComparatorFor(String)
+	 * @since 3.4
+	 */
+	public ContributionComparator getComparatorFor(String contributionType) {
+		return new ContributionComparator();
+	}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/application/WorkbenchWindowAdvisor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/application/WorkbenchWindowAdvisor.java
new file mode 100644
index 0000000..d87dd8d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/application/WorkbenchWindowAdvisor.java
@@ -0,0 +1,359 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.application;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IWorkbenchPreferenceConstants;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.WorkbenchException;
+import org.eclipse.ui.actions.ActionFactory;
+import org.eclipse.ui.internal.WorkbenchWindowConfigurer;
+import org.eclipse.ui.internal.util.PrefUtil;
+import org.eclipse.ui.intro.IIntroManager;
+
+/**
+ * Public base class for configuring a workbench window.
+ * <p>
+ * The workbench window advisor object is created in response to a workbench
+ * window being created (one per window), and is used to configure the window.
+ * </p>
+ * <p>
+ * An application should declare a subclass of <code>WorkbenchWindowAdvisor</code>
+ * and override methods to configure workbench windows to suit the needs of the
+ * particular application.
+ * </p>
+ * <p>
+ * The following advisor methods are called at strategic points in the
+ * workbench window's lifecycle (as with the workbench advisor, all occur
+ * within the dynamic scope of the call to
+ * {@link PlatformUI#createAndRunWorkbench PlatformUI.createAndRunWorkbench}):
+ * <ul>
+ * <li><code>preWindowOpen</code> - called as the window is being opened;
+ *  use to configure aspects of the window other than actions bars</li>
+ * <li><code>postWindowRestore</code> - called after the window has been
+ * recreated from a previously saved state; use to adjust the restored
+ * window</li>
+ * <li><code>postWindowCreate</code> -  called after the window has been created,
+ * either from an initial state or from a restored state;  used to adjust the
+ * window</li>
+ * <li><code>openIntro</code> - called immediately before the window is opened in
+ * order to create the introduction component, if any.</li>
+ * <li><code>postWindowOpen</code> - called after the window has been
+ * opened; use to hook window listeners, etc.</li>
+ * <li><code>preWindowShellClose</code> - called when the window's shell
+ * is closed by the user; use to pre-screen window closings</li>
+ * </ul>
+ * </p>
+ *
+ * @since 3.1
+ */
+public class WorkbenchWindowAdvisor {
+
+    private IWorkbenchWindowConfigurer windowConfigurer;
+
+    /**
+     * Creates a new workbench window advisor for configuring a workbench
+     * window via the given workbench window configurer.
+     *
+     * @param configurer an object for configuring the workbench window
+     */
+    public WorkbenchWindowAdvisor(IWorkbenchWindowConfigurer configurer) {
+        Assert.isNotNull(configurer);
+        this.windowConfigurer = configurer;
+    }
+
+    /**
+     * Returns the workbench window configurer.
+     *
+     * @return the workbench window configurer
+     */
+    protected IWorkbenchWindowConfigurer getWindowConfigurer() {
+        return windowConfigurer;
+    }
+
+    /**
+     * Performs arbitrary actions before the window is opened.
+     * <p>
+     * This method is called before the window's controls have been created.
+     * Clients must not call this method directly (although super calls are okay).
+     * The default implementation does nothing. Subclasses may override.
+     * Typical clients will use the window configurer to tweak the
+     * workbench window in an application-specific way; however, filling the
+     * window's menu bar, tool bar, and status line must be done in
+     * {@link ActionBarAdvisor#fillActionBars}, which is called immediately
+     * after this method is called.
+     * </p>
+     */
+    public void preWindowOpen() {
+        // do nothing
+    }
+
+    /**
+     * Creates a new action bar advisor to configure the action bars of the window
+     * via the given action bar configurer.
+     * The default implementation returns a new instance of {@link ActionBarAdvisor}.
+     *
+     * @param configurer the action bar configurer for the window
+     * @return the action bar advisor for the window
+     */
+    public ActionBarAdvisor createActionBarAdvisor(IActionBarConfigurer configurer) {
+        return new ActionBarAdvisor(configurer);
+    }
+
+    /**
+     * Performs arbitrary actions after the window has been restored,
+     * but before it is opened.
+     * <p>
+     * This method is called after a previously-saved window has been
+     * recreated. This method is not called when a new window is created from
+     * scratch. This method is never called when a workbench is started for the
+     * very first time, or when workbench state is not saved or restored.
+     * Clients must not call this method directly (although super calls are okay).
+     * The default implementation does nothing. Subclasses may override.
+     * It is okay to call <code>IWorkbench.close()</code> from this method.
+     * </p>
+     *
+     * @exception WorkbenchException thrown if there are any errors to report
+     *   from post-restoration of the window
+     */
+    public void postWindowRestore() throws WorkbenchException {
+        // do nothing
+    }
+
+	/**
+	 * Close any empty editor stacks that may have been left open when the
+	 * Workbench Window shut down. May be called from
+	 * {@link #postWindowRestore()} in the subclass but is not called by
+	 * default.
+	 *
+	 * @since 3.7
+	 */
+	protected void cleanUpEditorArea() {
+		// TODO this might not be relevent to 4.1 but we need the API call
+		// anyway
+	}
+
+    /**
+     * Opens the introduction componenet.
+     * <p>
+     * Clients must not call this method directly (although super calls are okay).
+     * The default implementation opens the intro in the first window provided
+     * if the preference IWorkbenchPreferences.SHOW_INTRO is <code>true</code>.  If
+     * an intro is shown then this preference will be set to <code>false</code>.
+     * Subsequently, and intro will be shown only if
+     * <code>WorkbenchConfigurer.getSaveAndRestore()</code> returns
+     * <code>true</code> and the introduction was visible on last shutdown.
+     * Subclasses may override.
+     * </p>
+     */
+    public void openIntro() {
+        // TODO: Refactor this into an IIntroManager.openIntro(IWorkbenchWindow) call
+
+        // introOpened flag needs to be global
+        IWorkbenchConfigurer wbConfig = getWindowConfigurer().getWorkbenchConfigurer();
+        final String key = "introOpened"; //$NON-NLS-1$
+        Boolean introOpened = (Boolean) wbConfig.getData(key);
+        if (introOpened != null && introOpened.booleanValue()) {
+			return;
+		}
+
+        wbConfig.setData(key, Boolean.TRUE);
+
+        boolean showIntro = PrefUtil.getAPIPreferenceStore().getBoolean(
+                IWorkbenchPreferenceConstants.SHOW_INTRO);
+
+        IIntroManager introManager = wbConfig.getWorkbench().getIntroManager();
+
+        boolean hasIntro = introManager.hasIntro();
+        boolean isNewIntroContentAvailable = introManager.isNewContentAvailable();
+
+		if (hasIntro && (showIntro || isNewIntroContentAvailable)) {
+			PrefUtil.getAPIPreferenceStore().setValue(
+					IWorkbenchPreferenceConstants.SHOW_INTRO, false);
+			PrefUtil.saveAPIPrefs();
+
+            introManager
+                    .showIntro(getWindowConfigurer().getWindow(), false);
+        }
+    }
+
+    /**
+     * Performs arbitrary actions after the window has been created (possibly
+     * after being restored), but has not yet been opened.
+     * <p>
+     * This method is called after the window has been created from scratch,
+     * or when it has been restored from a previously-saved window.  In the latter case,
+     * this method is called after <code>postWindowRestore</code>.
+     * Clients must not call this method directly (although super calls are okay).
+     * The default implementation does nothing. Subclasses may override.
+     * </p>
+     */
+    public void postWindowCreate() {
+        // do nothing
+    }
+
+    /**
+     * Performs arbitrary actions after the window has been opened (possibly
+     * after being restored).
+     * <p>
+     * This method is called after the window has been opened. This method is
+     * called after the window has been created from scratch, or when
+     * it has been restored from a previously-saved window.
+     * Clients must not call this method directly (although super calls are okay).
+     * The default implementation does nothing. Subclasses may override.
+     * </p>
+     */
+    public void postWindowOpen() {
+        // do nothing
+    }
+
+    /**
+	 * Performs arbitrary actions as the window's shell is being closed
+	 * directly, and possibly veto the close.
+	 * <p>
+	 * This method is called from a ShellListener associated with the window,
+	 * for example when the user clicks the window's close button. It is not
+	 * called when the window is being closed for other reasons, such as if the
+	 * user exits the workbench via the {@link ActionFactory#QUIT} action.
+	 * Clients must not call this method directly (although super calls are
+	 * okay). If this method returns <code>false</code>, then the user's
+	 * request to close the shell is ignored. This gives the workbench advisor
+	 * an opportunity to query the user and/or veto the closing of a window
+	 * under some circumstances.
+	 * </p>
+	 *
+	 * @return <code>true</code> to allow the window to close, and
+	 *         <code>false</code> to prevent the window from closing
+	 * @see org.eclipse.ui.IWorkbenchWindow#close
+	 * @see WorkbenchAdvisor#preShutdown()
+	 */
+	public boolean preWindowShellClose() {
+		// do nothing, but allow the close() to proceed
+		return true;
+	}
+
+    /**
+	 * Performs arbitrary actions after the window is closed.
+	 * <p>
+	 * This method is called after the window's controls have been disposed.
+	 * Clients must not call this method directly (although super calls are
+	 * okay). The default implementation does nothing. Subclasses may override.
+	 * </p>
+	 */
+    public void postWindowClose() {
+        // do nothing
+    }
+
+    /**
+	 * Creates the contents of the window.
+	 * <p>
+	 * The default implementation adds a menu bar, a cool bar, a status line, a
+	 * perspective bar, and a fast view bar. The visibility of these controls
+	 * can be configured using the <code>setShow*</code> methods on
+	 * <code>IWorkbenchWindowConfigurer</code>.
+	 * </p>
+	 * <p>
+	 * Subclasses may override to define custom window contents and layout, but
+	 * must call <code>IWorkbenchWindowConfigurer.createPageComposite</code>.
+	 * </p>
+	 *
+	 * @param shell
+	 *            the window's shell
+	 * @see IWorkbenchWindowConfigurer#createMenuBar
+	 * @see IWorkbenchWindowConfigurer#createCoolBarControl
+	 * @see IWorkbenchWindowConfigurer#createStatusLineControl
+	 * @see IWorkbenchWindowConfigurer#createPageComposite
+	 * @deprecated This method is no longer used. Applications now define
+	 *             workbench window contents in their application model.
+	 */
+	@Deprecated
+    public void createWindowContents(Shell shell) {
+        ((WorkbenchWindowConfigurer) getWindowConfigurer()).createDefaultContents(shell);
+    }
+
+    /**
+	 * Creates and returns the control to be shown when the window has no open
+	 * pages. If <code>null</code> is returned, the default window background is
+	 * shown.
+	 * <p>
+	 * The default implementation returns <code>null</code>. Subclasses may
+	 * override.
+	 * </p>
+	 *
+	 * @param parent
+	 *            the parent composite
+	 * @return the control or <code>null</code>
+	 * @deprecated This method is no longer used. Applications now define
+	 *             workbench window contents in their application model.
+	 */
+	@Deprecated
+	public Control createEmptyWindowContents(Composite parent) {
+        return null;
+    }
+
+	/**
+	 * Returns <code>true</code> if the given folder in the given perspective
+	 * should remain visible even after all parts in it have been closed by the
+	 * user. The default is <code>false</code>. The return value for a certain
+	 * combination of perspective id and folder id must not change over time.
+	 *
+	 * @param perspectiveId
+	 *            the perspective id
+	 * @param folderId
+	 *            the folder id
+	 * @return <code>true</code> if the given folder should be durable
+	 *
+	 * @since 3.5
+	 */
+	public boolean isDurableFolder(String perspectiveId, String folderId) {
+		return false;
+	}
+
+    /**
+     * Disposes any resources allocated by this window advisor.
+     * This is the last method called on this window advisor by the workbench.
+     * The default implementation does nothing.
+     * Subclasses may extend.
+     */
+    public void dispose() {
+        // do nothing.
+    }
+
+	/**
+	 * Saves arbitrary application specific state information.
+	 *
+	 * @param memento the storage area for object's state
+	 * @return a status object indicating whether the save was successful
+	 * @since 3.1
+	 */
+	public IStatus saveState(IMemento memento) {
+		// do nothing
+		return Status.OK_STATUS;
+	}
+
+	/**
+	 * Restores arbitrary application specific state information.
+	 *
+	 * @param memento the storage area for object's state
+	 * @return a status object indicating whether the restore was successful
+	 * @since 3.1
+	 */
+	public IStatus restoreState(IMemento memento) {
+		// do nothing
+		return Status.OK_STATUS;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/application/package.html b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/application/package.html
new file mode 100644
index 0000000..30e0242
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/application/package.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<meta name="Author" content="IBM">
+<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
+<meta name="ProgId" content="FrontPage.Editor.Document">
+<title>Package-level Javadoc</title>
+</head>
+
+<body>
+
+Application-level APIs for configuring and controling the Eclipse Platform User
+Interface.
+<h2>Package Specification</h2>
+This package provides APIs that allow the main plug-in (the
+&quot;application&quot;) to configure and control the Eclipse Platform User
+Interface, most notably the workbench. These APIs are not of interest to normal
+Eclipse plug-ins.
+
+</body>
+
+</html>
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/branding/IBundleGroupConstants.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/branding/IBundleGroupConstants.java
new file mode 100644
index 0000000..86f873e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/branding/IBundleGroupConstants.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.branding;
+
+/**
+ * These constants define the set of properties that the UI expects to
+ * be available via <code>IBundleGroup.getProperty(String)</code>.
+ *
+ * @since 3.0
+ * @see org.eclipse.core.runtime.IBundleGroup#getProperty(String)
+ */
+public interface IBundleGroupConstants {
+
+    /**
+     * The text to show in an "about features" dialog.
+     */
+    public static final String ABOUT_TEXT = "aboutText"; //$NON-NLS-1$
+
+    /**
+     * An image which can be shown in an "about features" dialog (32x32).
+     * <p>
+     * The value is a fully qualified valid URL.
+     * </p>
+     */
+    public static final String FEATURE_IMAGE = "featureImage"; //$NON-NLS-1$
+
+    /**
+     * A help reference for the feature's tips and tricks page (optional).
+     */
+    public static final String TIPS_AND_TRICKS_HREF = "tipsAndTricksHref"; //$NON-NLS-1$
+
+    /**
+     * The feature's welcome page (special XML-based format).
+     * <p>
+     * The value is a fully qualified valid URL.
+     * </p>
+     * Products designed to run "headless" typically would not have such a page.
+     */
+    public static final String WELCOME_PAGE = "welcomePage"; //$NON-NLS-1$
+
+    /**
+     * The id of a perspective in which to show the welcome page
+     * (optional).
+     */
+    public static final String WELCOME_PERSPECTIVE = "welcomePerspective"; //$NON-NLS-1$
+
+    /**
+     * The URL of the license page for the feature (optional).
+     * <p>
+     * The value is a fully qualified valid URL.
+     * </p>
+     */
+    public static final String LICENSE_HREF = "licenseHref"; //$NON-NLS-1$
+
+	/**
+	 * The feature's branding bundle id (optional).
+	 *
+	 * @since 3.5
+	 */
+	public static final String BRANDING_BUNDLE_ID = "brandingBundleId"; //$NON-NLS-1$
+
+	/**
+	 * The feature's branding bundle version (optional).
+	 *
+	 * @since 3.5
+	 */
+	public static final String BRANDING_BUNDLE_VERSION = "brandingBundleVersion"; //$NON-NLS-1$
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/branding/IProductConstants.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/branding/IProductConstants.java
new file mode 100644
index 0000000..ba97f3d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/branding/IProductConstants.java
@@ -0,0 +1,170 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.branding;
+
+/**
+ * These constants define the set of properties that the UI expects to
+ * be available via <code>IProduct.getProperty(String)</code>.
+ *
+ * @since 3.0
+ * @see org.eclipse.core.runtime.IProduct#getProperty(String)
+ */
+public interface IProductConstants {
+    /**
+     * The SWT application name, used to initialize the SWT Display.
+     * <p>
+     * This value is used to refer to the application in .XDefaults
+     * files on X server based window systems such as Motif.
+     * </p>
+     * <p>
+     * To obtain a human-readable name for the product, use
+     * <code>IProduct.getName()</code>.
+     * </p>
+     * @see org.eclipse.swt.widgets.Display#setAppName
+     */
+    public static final String APP_NAME = "appName"; //$NON-NLS-1$
+
+    /**
+     * The text to show in an "about" dialog for this product.
+     * Products designed to run "headless" typically would not
+     * have such text.
+     */
+    public static final String ABOUT_TEXT = "aboutText"; //$NON-NLS-1$
+
+    /**
+     * An image which can be shown in an "about" dialog for this
+     * product. Products designed to run "headless" typically would not
+     * have such an image.
+     * <p>
+     * The value is either a fully qualified valid URL or a path relative
+     * to the product's defining bundle.
+     * </p>
+     * <p>
+     * A full-sized product image (no larger than 500x330 pixels) is
+     * shown without the "aboutText" blurb.  A half-sized product image
+     * (no larger than 250x330 pixels) is shown with the "aboutText"
+     * blurb beside it.
+     * </p>
+     */
+    public static final String ABOUT_IMAGE = "aboutImage"; //$NON-NLS-1$
+
+    /**
+     * A file for customizing default preference
+     * values for a product. The value is interpreted as either a
+     * URL or a bundle-relative path by the runtime. This is not referenced
+     * from the workbench.
+     * <p>
+     * The contents must be the same format as a
+     * {@link java.util.Properties} file with the key/value pairs being:
+     * <pre>
+     * qualifier/key=value
+     * </pre>
+     * Where <code>qualifier</code> is typically the bundle id.
+     * </p>
+     */
+    public static final String PREFERENCE_CUSTOMIZATION = "preferenceCustomization"; //$NON-NLS-1$
+
+    /**
+     * An image to be used as the window icon for this product (16x16).
+     * Products designed to run "headless" typically would not have such an image.
+     * <p>
+     * The value is either a fully qualified valid URL or a path relative
+     * to the product's defining bundle.
+     * </p>
+     * <p>
+     * If the <code>WINDOW_IMAGES</code> property is given, then it supercedes
+     * this one.
+     * </p>
+     * @deprecated use WINDOW_IMAGES instead (see recommendations there)
+     */
+    @Deprecated
+	public static final String WINDOW_IMAGE = "windowImage"; //$NON-NLS-1$
+
+    /**
+     * An array of one or more images to be used for this product.  The
+     * expectation is that the array will contain the same image rendered
+     * at different sizes (16x16 and 32x32).
+     * Products designed to run "headless" typically would not have such images.
+     * <p>
+     * The value is a comma-separated list of paths, where each path is either
+     * a fully qualified valid URL or a path relative to the product's defining bundle.
+     * </p>
+     * <p>
+     * If this property is given, then it supercedes <code>WINDOW_IMAGE</code>.
+     * </p>
+     * <p>
+     * It is recommended that products use <code>WINDOW_IMAGES</code> rather than
+     * <code>WINDOW_IMAGE</code>, and specify both a 16x16 image and a 32x32 image,
+     * to ensure that different sizes of the image are available for different uses
+     * in the OS.  For example, on Windows, the 16x16 image is used in the corner of
+     * the window and in the task tray, but the 32x32 image is used in the Alt+Tab
+     * application switcher.
+     * </p>
+     */
+    public static final String WINDOW_IMAGES = "windowImages"; //$NON-NLS-1$
+
+    /**
+     * The product's welcome page (special XML-based format).
+     * <p>
+     * The value is either a fully qualified valid URL or a path relative
+     * to the product's defining bundle.
+     * </p>
+     * <p>
+     * Products designed to run "headless" typically would not have such
+     * a page. Use of this property is discouraged in 3.0, the new
+     * <code>org.eclipse.ui.intro</code> extension point should be used instead.
+     * </p>
+     */
+    public static final String WELCOME_PAGE = "welcomePage"; //$NON-NLS-1$
+
+    /**
+     * The rectangle relative to the splash image's top left corner where
+     * the progress bar for reporting progress at startup should be shown.
+     * Products designed to run "headless" typically would not define this
+     * property.
+     * <p>
+     * The value is a comma-separated list of four integer values, specifying
+     * x, y, width, and height of the rectangle in pixel coordinates.
+     * </p>
+     * @since 3.2
+     * @see org.eclipse.ui.IWorkbenchPreferenceConstants#SHOW_PROGRESS_ON_STARTUP
+     */
+    public static final String STARTUP_PROGRESS_RECT = "startupProgressRect"; //$NON-NLS-1$
+
+    /**
+     * The rectangle relative to the splash image's top left corner where
+     * messages for reporting progress at startup should be shown.
+     * Products designed to run "headless" typically would not define this
+     * property.
+     * <p>
+     * The value is a comma-separated list of four integer values, specifying
+     * x, y, width, and height of the rectangle in pixel coordinates.
+     * </p>
+     * @since 3.2
+     * @see org.eclipse.ui.IWorkbenchPreferenceConstants#SHOW_PROGRESS_ON_STARTUP
+     */
+    public static final String STARTUP_MESSAGE_RECT = "startupMessageRect"; //$NON-NLS-1$
+
+    /**
+     * The foreground color to be used when reporting progress at startup.
+     * Products designed to run "headless" typically would not define this
+     * property.
+     * <p>
+     * The value is a six-digit hexadecimal number. The first two digits
+     * specify the red component of the color, the next two digits the
+     * green component, and the last two digits the blue component.
+     * </p>
+     * @since 3.2
+     * @see org.eclipse.ui.IWorkbenchPreferenceConstants#SHOW_PROGRESS_ON_STARTUP
+     */
+    public static final String STARTUP_FOREGROUND_COLOR = "startupForegroundColor"; //$NON-NLS-1$
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/branding/package.html b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/branding/package.html
new file mode 100644
index 0000000..b755b52
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/branding/package.html
@@ -0,0 +1,19 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <meta name="Author" content="IBM">
+   <meta name="GENERATOR" content="Mozilla/4.5 [en] (WinNT; I) [Netscape]">
+   <title>Package-level Javadoc</title>
+</head>
+<body>
+<p>Classes for branding support.</p>
+<h2>
+Package Specification</h2>
+<p>
+This package has API to public branding and product constants.  These
+constants are used when branding RCP applications.
+</p>
+
+</body>
+</html>
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/browser/AbstractWebBrowser.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/browser/AbstractWebBrowser.java
new file mode 100644
index 0000000..296b868
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/browser/AbstractWebBrowser.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.browser;
+
+/**
+ * Clients that supply implementation of the workbench browser support should
+ * extend this class for web browser instances they manage. Clients should not
+ * implement the <code>IWebBrowser</code> interface.
+ *
+ * @since 3.1
+ */
+public abstract class AbstractWebBrowser implements IWebBrowser {
+	private String id;
+
+	/**
+	 * The constructor that accepts the unique browser identifier.
+	 *
+	 * @param id
+	 *            the unique browser identifier
+	 */
+	public AbstractWebBrowser(String id) {
+		this.id = id;
+	}
+
+	@Override
+	public String getId() {
+		return id;
+	}
+
+	@Override
+	public boolean close() {
+		return false;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/browser/AbstractWorkbenchBrowserSupport.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/browser/AbstractWorkbenchBrowserSupport.java
new file mode 100644
index 0000000..3931684
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/browser/AbstractWorkbenchBrowserSupport.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.browser;
+
+import org.eclipse.ui.PartInitException;
+
+/**
+ * Implements <code>IWorkbenchBrowserSupport</code> while leaving some methods
+ * to the implementors. Classes that extend this abstract class are meant to be
+ * contributed via 'org.eclipse.ui.browserSupport' extension point.
+ *
+ * @since 3.1
+ */
+public abstract class AbstractWorkbenchBrowserSupport implements
+		IWorkbenchBrowserSupport {
+
+	private static final String SHARED_EXTERNAL_BROWSER_ID = "org.eclipse.ui.externalBrowser"; //$NON-NLS-1$
+
+	/**
+	 * The default constructor.
+	 */
+	public AbstractWorkbenchBrowserSupport() {
+	}
+
+	@Override
+	public IWebBrowser getExternalBrowser() throws PartInitException {
+		return createBrowser(AS_EXTERNAL, SHARED_EXTERNAL_BROWSER_ID, null,
+				null);
+	}
+
+	@Override
+	public boolean isInternalWebBrowserAvailable() {
+		return false;
+	}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/browser/IWebBrowser.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/browser/IWebBrowser.java
new file mode 100644
index 0000000..467b08a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/browser/IWebBrowser.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.browser;
+
+import java.net.URL;
+import org.eclipse.ui.PartInitException;
+
+/**
+ * An opened Web browser instance (either internal or external).
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ *
+ * @since 3.1
+ * @see IWorkbenchBrowserSupport
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+
+public interface IWebBrowser {
+	/**
+	 * Returns the unique identifier of this browser. If an id has been supplied
+	 * to the browser support when the instance was created, it will be used.
+	 * Otherwise, a generated id will be provided to the browser that is
+	 * guaranteed to be unique.
+	 *
+	 * @return a unique identifier of this browser instance
+	 */
+	String getId();
+
+	/**
+	 * Opens a URL on this Web browser instance.
+	 * <p>
+	 * <b>NOTE</b> This method must be called from the current UI thread
+	 * </p>
+	 *
+	 * @param url
+	 *            the URL to display
+	 * @exception PartInitException
+	 *                if the browser fails to navigate to the provided url for
+	 *                any reason
+	 */
+	void openURL(URL url) throws PartInitException;
+
+	/**
+	 * Closes this browser instance.
+	 * <p>
+	 * <b>NOTE</b> This method must be called from the current UI thread
+	 * </p>
+	 *
+	 * @return <code>true</code> if the browser was closed or <code>false</code>
+	 *         if the operation failed or is not supported.
+	 */
+	boolean close();
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/browser/IWorkbenchBrowserSupport.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/browser/IWorkbenchBrowserSupport.java
new file mode 100644
index 0000000..6be8d33
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/browser/IWorkbenchBrowserSupport.java
@@ -0,0 +1,187 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.browser;
+
+import org.eclipse.ui.PartInitException;
+
+/**
+ * Web browser support. This class allows you to open URLs using internal or
+ * external Web browsers. Implementers may provide varying levels of support.
+ * The most rudimentary support that must be provided is to open URLs in an
+ * external web browser window. Everything else is a hint that browser support
+ * implementation may choose to honor but is not required (although a good
+ * implementation should aspire to support all the styles if possible on the
+ * given platform).
+ * <p>
+ * The support has a two-phase approach to opening URLs. A browser instance is
+ * created first, then <code>openURL</code> is called on it. This provides for
+ * browser instance reuse for as long as needed. The step of creating the
+ * browser instance encourages reuse itself by not creating new instances of
+ * browsers if one with the same id is already open. It also makes it possible
+ * to reuse browser instances restored after workbench is restarted.
+ * <p>
+ * The simplest way to open a URL is:
+ *
+ * <pre>
+ * IWorkbenchSupport.createBrowser(&quot;myId&quot;).openURL(url);
+ * </pre>
+ *
+ * <p>
+ * The call above will show the provided URL by reusing the browser instance
+ * with the matching id, or creating a new one if one does not exist already.
+ * <p>
+ * When more advanced control over the behavior of a browser instance is
+ * required, it is recommended to create the instance first, then reuse it as
+ * needed.
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ *
+ * @see IWebBrowser
+ * @since 3.1
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noextend This interface is not intended to be extended by clients.
+ */
+
+public interface IWorkbenchBrowserSupport {
+	/**
+	 * Style parameter (value 1&lt;&lt;1) indicating that the address combo and
+	 * 'Go' button will created for the browser. This style is ignored if the
+	 * support is forced to open the browser as external.
+	 */
+	int LOCATION_BAR = 1 << 1;
+
+	/**
+	 * Style parameter (value 1&lt;&lt;2) indicating that the navigation bar for
+	 * navigating web pages will be created for the web browser. This style is
+	 * ignored if the support is forced to open the browser as external.
+	 */
+	int NAVIGATION_BAR = 1 << 2;
+
+	/**
+	 * Style constant (value 1&lt;&lt;3) indicating that status will be tracked
+	 * and shown for the browser (page loading progress, text messages etc.).
+	 */
+	int STATUS = 1 << 3;
+
+	/**
+	 * Style constant (value 1&lt;&lt;4) indicating that the internal web
+	 * browser will reopen after restarting the workbench (if used). In
+	 * addition, the URLs will appear in the MRU list.
+	 */
+	int PERSISTENT = 1 << 4;
+
+	/**
+	 * Style constant (value 1&lt;&lt;5) indicating that the internal web
+	 * browser will be hosted in a workbench editor area. This is just a hint -
+	 * implementers of the browser support may not honor it.
+	 */
+	int AS_EDITOR = 1 << 5;
+
+	/**
+	 * Style constant (value 1&lt;&lt;6) indicating that the internal web
+	 * browser will be hosted in a workbench view. This is just a hint -
+	 * implementers of the browser support may not honor it.
+	 */
+	int AS_VIEW = 1 << 6;
+
+	/**
+	 * Style constant (value 1&lt;&lt;7) indicating that the external web
+	 * browser must be used even if the implementation supports internal
+	 * browsers and the user didn't set the preference to external browsers.
+	 */
+	int AS_EXTERNAL = 1 << 7;
+
+	/**
+	 * Creates the new web browser instance. If the user has chosen to use the
+	 * internal Web browser, the given style bits (see class header for values)
+	 * will be used to open the browser.
+	 * <p>
+	 * The method will reuse an existing browser instance if the same
+	 * <code>browserId</code> value is passed to it. A persisted browser
+	 * instance restored upon startup can be accessed this way. If
+	 * <code>null</code> is passed as a browserId, a unique id will be
+	 * generated each time method is called.
+	 * <p>
+	 * If the user has chosen not to use the internal browser or it is not
+	 * available on the current platform, an external browser will be used and
+	 * all style parameters will be ignored.
+	 * </p>
+	 *
+	 * @param style
+	 *            the style display constants. Style constants should be
+	 *            bitwise-ORed together.
+	 * @param browserId
+	 *            if an instance of a browser with the same id is already
+	 *            opened, it will be returned instead of creating a new one.
+	 *            Passing <code>null</code> will create a new instance with a
+	 *            generated id every time.
+	 * @param name
+	 *            a name used for the presentation of the internal browser
+	 * @param tooltip
+	 *            a tooltip used for the presentation of the internal browser
+	 * @return the browser instance that can be used to open the URL. Clients
+	 *         intending to reuse the instance for all the URLs should cache the
+	 *         instance and call IWebBrowser#openURL() on it. Clients are
+	 *         responsible for closing the browser instance when not needed.
+	 * @exception PartInitException
+	 *                if the operation failed for some reason
+	 */
+	IWebBrowser createBrowser(int style, String browserId, String name,
+			String tooltip) throws PartInitException;
+
+	/**
+	 * Creates the new web browser instance. This is a simplified method that
+	 * creates the instance using default values for style, name and tooltip
+	 * parameters. The method can be used to quickly open the URL by calling
+	 * <code>createBrowser(id).openURL(url)</code>.
+	 * <p>
+	 *
+	 * @param browserId
+	 *            if an instance of a browser with the same id is already
+	 *            opened, it will be returned instead of creating a new one.
+	 *            Passing <code>null</code> will create a new instance with a
+	 *            generated id every time.
+	 * @return the browser instance that can be used to open the URL. Clients
+	 *         intending to reuse the instance for all the URLs should cache the
+	 *         instance and call IWebBrowser#openURL() on it. Clients are
+	 *         responsible for closing the browser instance when not needed.
+	 * @exception PartInitException
+	 *                if the operation failed for some reason
+	 */
+	IWebBrowser createBrowser(String browserId) throws PartInitException;
+
+	/**
+	 * Returns a shared instance of the external web browser. Clients can use it
+	 * to share one external browser. The external browser that will be used is
+	 * subject to browser support implementation. A suggested implementation is
+	 * to use the operating system's default browser. Implementations that offer
+	 * users a choice of the web browser should honour the users choice of
+	 * external browser, with the initial selection being the system default
+	 * browser.
+	 *
+	 * @return the shared instance of the external browser
+	 * @exception PartInitException
+	 *                if the operation failed for some reason
+	 */
+	IWebBrowser getExternalBrowser() throws PartInitException;
+
+	/**
+	 * Tests whether web browser as an SWT widget can be created in this
+	 * workbench instance. If this method returns <code>false</code>,
+	 * <code>createBrowser</code> would ignore browser styles
+	 * <code>AS_EDITOR</code> and <code>AS_VIEW</code> and always create an
+	 * external browser.
+	 *
+	 * @return <code>true</code> if internal web browser can be created on
+	 *         this platform, <code>false</code> otherwise.
+	 */
+	boolean isInternalWebBrowserAvailable();
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/browser/package.html b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/browser/package.html
new file mode 100644
index 0000000..cb20fd5
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/browser/package.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<meta name="Author" content="IBM">
+<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
+<meta name="ProgId" content="FrontPage.Editor.Document">
+<title>Package-level Javadoc</title>
+</head>
+
+<body>
+
+Web browser support APIs for opening URLs from Eclipse
+applications
+<h2>Package Specification</h2>
+This package provides APIs that allow Eclipse plug-ins
+to create instances of Web browsers and open URLs in them.
+Browser support is pluggable and the APIs in this package
+provide a common interface for using the currently active
+support.
+</body>
+
+</html>
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/AbstractHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/AbstractHandler.java
new file mode 100644
index 0000000..00c0b00
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/AbstractHandler.java
@@ -0,0 +1,246 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.commands;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.HandlerEvent;
+import org.eclipse.core.commands.IHandlerAttributes;
+
+/**
+ * This class is a partial implementation of <code>IHandler</code>. This
+ * abstract implementation provides support for handler listeners. You should
+ * subclass from this method unless you want to implement your own listener
+ * support. Subclasses should call
+ * {@link AbstractHandler#fireHandlerChanged(HandlerEvent)}when the handler
+ * changes. Subclasses should also override
+ * {@link AbstractHandler#getAttributeValuesByName()}if they have any
+ * attributes.
+ *
+ * @since 3.0
+ * @deprecated Please use the "org.eclipse.core.commands" plug-in instead.
+ * @see org.eclipse.core.commands.AbstractHandler
+ */
+@Deprecated
+@SuppressWarnings({ "rawtypes", "unchecked" })
+public abstract class AbstractHandler extends
+        org.eclipse.core.commands.AbstractHandler implements IHandler {
+
+    /**
+     * Those interested in hearing about changes to this instance of
+     * <code>IHandler</code>. This member is null iff there are
+     * no listeners attached to this handler. (Most handlers don't
+     * have any listeners, and this optimization saves some memory.)
+     */
+	private List handlerListeners;
+
+    /**
+     * @see IHandler#addHandlerListener(IHandlerListener)
+     */
+	@Override
+	@Deprecated
+	public void addHandlerListener(IHandlerListener handlerListener) {
+        if (handlerListener == null) {
+			throw new NullPointerException();
+		}
+        if (handlerListeners == null) {
+			handlerListeners = new ArrayList();
+		}
+        if (!handlerListeners.contains(handlerListener)) {
+			handlerListeners.add(handlerListener);
+		}
+    }
+
+    /**
+     * The default implementation does nothing. Subclasses who attach listeners
+     * to other objects are encouraged to detach them in this method.
+     *
+     * @see org.eclipse.ui.commands.IHandler#dispose()
+     */
+	@Override
+	@Deprecated
+    public void dispose() {
+        // Do nothing.
+    }
+
+	@Override
+	@Deprecated
+    public Object execute(final ExecutionEvent event) throws ExecutionException {
+        try {
+            return execute(event.getParameters());
+        } catch (final org.eclipse.ui.commands.ExecutionException e) {
+            throw new ExecutionException(e.getMessage(), e.getCause());
+        }
+    }
+
+    /**
+     * Fires an event to all registered listeners describing changes to this
+     * instance.
+     *
+     * @param handlerEvent
+     *            the event describing changes to this instance. Must not be
+     *            <code>null</code>.
+     */
+	@Override
+	@Deprecated
+    protected void fireHandlerChanged(HandlerEvent handlerEvent) {
+        super.fireHandlerChanged(handlerEvent);
+
+        if (handlerListeners != null) {
+            final boolean attributesChanged = handlerEvent.isEnabledChanged()
+                    || handlerEvent.isHandledChanged();
+            final Map previousAttributes;
+            if (attributesChanged) {
+                previousAttributes = new HashMap();
+                previousAttributes.putAll(getAttributeValuesByName());
+                if (handlerEvent.isEnabledChanged()) {
+                	Boolean disabled = !isEnabled() ? Boolean.TRUE: Boolean.FALSE;
+                    previousAttributes
+                            .put("enabled", disabled); //$NON-NLS-1$
+                }
+                if (handlerEvent.isHandledChanged()) {
+                	Boolean notHandled = !isHandled() ? Boolean.TRUE: Boolean.FALSE;
+                    previousAttributes.put(
+                            IHandlerAttributes.ATTRIBUTE_HANDLED, notHandled);
+                }
+            } else {
+                previousAttributes = null;
+            }
+            final org.eclipse.ui.commands.HandlerEvent legacyEvent = new org.eclipse.ui.commands.HandlerEvent(
+                    this, attributesChanged, previousAttributes);
+
+            for (int i = 0; i < handlerListeners.size(); i++) {
+                ((org.eclipse.ui.commands.IHandlerListener) handlerListeners
+                        .get(i)).handlerChanged(legacyEvent);
+            }
+        }
+    }
+
+	@Deprecated
+    protected void fireHandlerChanged(
+            final org.eclipse.ui.commands.HandlerEvent handlerEvent) {
+        if (handlerEvent == null) {
+			throw new NullPointerException();
+		}
+
+        if (handlerListeners != null) {
+            for (int i = 0; i < handlerListeners.size(); i++) {
+				((org.eclipse.ui.commands.IHandlerListener) handlerListeners
+                        .get(i)).handlerChanged(handlerEvent);
+			}
+        }
+
+        if (super.hasListeners()) {
+            final boolean enabledChanged;
+            final boolean handledChanged;
+            if (handlerEvent.haveAttributeValuesByNameChanged()) {
+                Map previousAttributes = handlerEvent
+                        .getPreviousAttributeValuesByName();
+
+                Object attribute = previousAttributes.get("enabled"); //$NON-NLS-1$
+                if (attribute instanceof Boolean) {
+                    enabledChanged = ((Boolean) attribute).booleanValue();
+                } else {
+                    enabledChanged = false;
+                }
+
+                attribute = previousAttributes
+                        .get(IHandlerAttributes.ATTRIBUTE_HANDLED);
+                if (attribute instanceof Boolean) {
+                    handledChanged = ((Boolean) attribute).booleanValue();
+                } else {
+                    handledChanged = false;
+                }
+            } else {
+                enabledChanged = false;
+                handledChanged = true;
+            }
+            final HandlerEvent newEvent = new HandlerEvent(this,
+                    enabledChanged, handledChanged);
+            super.fireHandlerChanged(newEvent);
+        }
+    }
+
+    /**
+     * This simply return an empty map. The default implementation has no
+     * attributes.
+     *
+     * @see IHandler#getAttributeValuesByName()
+     */
+	@Override
+	@Deprecated
+    public Map getAttributeValuesByName() {
+        return Collections.EMPTY_MAP;
+    }
+
+    /**
+     * Returns true iff there is one or more IHandlerListeners attached to this
+     * AbstractHandler.
+     *
+     * @return true iff there is one or more IHandlerListeners attached to this
+     *         AbstractHandler
+     * @since 3.1
+     */
+	@Override
+	@Deprecated
+    protected final boolean hasListeners() {
+        return super.hasListeners() || handlerListeners != null;
+    }
+
+	@Override
+	@Deprecated
+    public boolean isEnabled() {
+        final Object handled = getAttributeValuesByName().get("enabled"); //$NON-NLS-1$
+        if (handled instanceof Boolean) {
+            return ((Boolean) handled).booleanValue();
+        }
+
+        return false;
+    }
+
+	@Override
+	@Deprecated
+    public boolean isHandled() {
+        final Object handled = getAttributeValuesByName().get(
+                IHandlerAttributes.ATTRIBUTE_HANDLED);
+        if (handled instanceof Boolean) {
+            return ((Boolean) handled).booleanValue();
+        }
+
+        return false;
+    }
+
+    /**
+     * @see IHandler#removeHandlerListener(IHandlerListener)
+     */
+	@Override
+	@Deprecated
+	public void removeHandlerListener(IHandlerListener handlerListener) {
+        if (handlerListener == null) {
+			throw new NullPointerException();
+		}
+        if (handlerListeners == null) {
+            return;
+        }
+
+        if (handlerListeners != null) {
+			handlerListeners.remove(handlerListener);
+		}
+        if (handlerListeners.isEmpty()) {
+            handlerListeners = null;
+        }
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/ActionHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/ActionHandler.java
new file mode 100644
index 0000000..c7e4c1c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/ActionHandler.java
@@ -0,0 +1,265 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.commands;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import org.eclipse.core.commands.IHandlerAttributes;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.ui.actions.RetargetAction;
+
+/**
+ * This class adapts instances of <code>IAction</code> to
+ * <code>IHandler</code>.
+ *
+ * @since 3.0
+ * @deprecated Please use the "org.eclipse.core.commands" plug-in instead.
+ * @see org.eclipse.jface.commands.ActionHandler
+ */
+@Deprecated
+@SuppressWarnings("all")
+public final class ActionHandler extends AbstractHandler {
+
+    /**
+     * The attribute name for the checked property of the wrapped action. This
+     * indicates whether the action should be displayed with as a checked check
+     * box.
+     */
+    private final static String ATTRIBUTE_CHECKED = "checked"; //$NON-NLS-1$
+
+    /**
+     * The attribute name for the enabled property of the wrapped action.
+     */
+    private final static String ATTRIBUTE_ENABLED = "enabled"; //$NON-NLS-1$
+
+    /**
+     * <p>
+     * The name of the attribute indicating whether the wrapped instance of
+     * <code>RetargetAction</code> has a handler.
+     * </p>
+     */
+    private final static String ATTRIBUTE_HANDLED = IHandlerAttributes.ATTRIBUTE_HANDLED;
+
+    /**
+     * The attribute name for the identifier of the wrapped action. This is the
+     * action identifier, and not the command identifier.
+     */
+    private final static String ATTRIBUTE_ID = "id"; //$NON-NLS-1$
+
+    /**
+     * The attribute name for the visual style of the wrapped action. The style
+     * can be things like a pull-down menu, a check box, a radio button or a
+     * push button.
+     */
+    private final static String ATTRIBUTE_STYLE = "style"; //$NON-NLS-1$
+
+    /**
+     * The wrapped action. This value is never <code>null</code>.
+     */
+    private final IAction action;
+
+    /**
+     * The map of attributes values. The keys are <code>String</code> values
+     * of the attribute names (given above). The values can be any type of
+     * <code>Object</code>.
+     *
+     * This map is always null if there are no IHandlerListeners registered.
+     *
+     */
+    private Map attributeValuesByName;
+
+    /**
+     * The property change listener hooked on to the action. This is initialized
+     * when the first listener is attached to this handler, and is removed when
+     * the handler is disposed or the last listener is removed.
+     */
+    private IPropertyChangeListener propertyChangeListener;
+
+    /**
+     * Creates a new instance of this class given an instance of
+     * <code>IAction</code>.
+     *
+     * @param action
+     *            the action. Must not be <code>null</code>.
+     */
+	@Deprecated
+    public ActionHandler(IAction action) {
+        if (action == null) {
+			throw new NullPointerException();
+		}
+
+        this.action = action;
+    }
+
+    /**
+     * @see org.eclipse.ui.commands.IHandler#addHandlerListener(org.eclipse.ui.commands.IHandlerListener)
+     * @since 3.1
+     */
+	@Override
+	@Deprecated
+    public void addHandlerListener(IHandlerListener handlerListener) {
+        if (!hasListeners()) {
+            attachListener();
+        }
+
+        super.addHandlerListener(handlerListener);
+    }
+
+    /**
+     * When a listener is attached to this handler, then this registers a
+     * listener with the underlying action.
+     *
+     * @since 3.1
+     */
+    private final void attachListener() {
+        if (propertyChangeListener == null) {
+            attributeValuesByName = getAttributeValuesByNameFromAction();
+
+            propertyChangeListener = propertyChangeEvent -> {
+               String property = propertyChangeEvent.getProperty();
+               if (IAction.ENABLED.equals(property)
+			    || IAction.CHECKED.equals(property)
+			    || IHandlerAttributes.ATTRIBUTE_HANDLED
+			            .equals(property)) {
+
+			Map previousAttributeValuesByName = attributeValuesByName;
+			attributeValuesByName = getAttributeValuesByNameFromAction();
+			if (!attributeValuesByName
+			        .equals(previousAttributeValuesByName)) {
+				fireHandlerChanged(new HandlerEvent(
+			            ActionHandler.this, true,
+			            previousAttributeValuesByName));
+			}
+               }
+            };
+        }
+
+        this.action.addPropertyChangeListener(propertyChangeListener);
+    }
+
+    /**
+     * When no more listeners are registered, then this is used to removed the
+     * property change listener from the underlying action.
+     *
+     * @since 3.1
+     *
+     */
+    private final void detachListener() {
+        this.action.removePropertyChangeListener(propertyChangeListener);
+        propertyChangeListener = null;
+        attributeValuesByName = null;
+    }
+
+    /**
+     * Removes the property change listener from the action.
+     *
+     * @see org.eclipse.ui.commands.IHandler#dispose()
+     */
+	@Override
+	@Deprecated
+    public void dispose() {
+        if (hasListeners()) {
+            action.removePropertyChangeListener(propertyChangeListener);
+        }
+    }
+
+
+	@Override
+	@Deprecated
+    public Object execute(Map parameterValuesByName) throws ExecutionException {
+        if ((action.getStyle() == IAction.AS_CHECK_BOX)
+                || (action.getStyle() == IAction.AS_RADIO_BUTTON)) {
+			action.setChecked(!action.isChecked());
+		}
+        try {
+            action.runWithEvent(new Event());
+        } catch (Exception e) {
+            throw new ExecutionException(
+                    "While executing the action, an exception occurred", e); //$NON-NLS-1$
+        }
+        return null;
+    }
+
+    /**
+     * Returns the action associated with this handler
+     *
+     * @return the action associated with this handler (not null)
+     * @since 3.1
+     */
+	@Deprecated
+    public IAction getAction() {
+        return action;
+    }
+
+	@Override
+	@Deprecated
+    public Map getAttributeValuesByName() {
+        if (attributeValuesByName == null) {
+            return getAttributeValuesByNameFromAction();
+        }
+
+        return attributeValuesByName;
+    }
+
+    /**
+     * An accessor for the attribute names from the action. This reads out all
+     * of the attributes from an action into a local map.
+     *
+     * @return A map of the attribute values indexed by the attribute name. The
+     *         attributes names are strings, but the values can by any object.
+     *
+     */
+    private Map getAttributeValuesByNameFromAction() {
+        Map map = new HashMap();
+        map.put(ATTRIBUTE_CHECKED, action.isChecked() ? Boolean.TRUE
+                : Boolean.FALSE);
+        map.put(ATTRIBUTE_ENABLED, action.isEnabled() ? Boolean.TRUE
+                : Boolean.FALSE);
+        boolean handled = true;
+        if (action instanceof RetargetAction) {
+            RetargetAction retargetAction = (RetargetAction) action;
+            handled = retargetAction.getActionHandler() != null;
+        }
+        map.put(ATTRIBUTE_HANDLED, handled ? Boolean.TRUE : Boolean.FALSE);
+        map.put(ATTRIBUTE_ID, action.getId());
+		map.put(ATTRIBUTE_STYLE, Integer.valueOf(action.getStyle()));
+        return Collections.unmodifiableMap(map);
+    }
+
+    /**
+     * @see org.eclipse.ui.commands.IHandler#removeHandlerListener(org.eclipse.ui.commands.IHandlerListener)
+     * @since 3.1
+     */
+	@Override
+	@Deprecated
+    public void removeHandlerListener(IHandlerListener handlerListener) {
+        super.removeHandlerListener(handlerListener);
+
+        if (!hasListeners()) {
+            detachListener();
+        }
+    }
+
+	@Override
+	@Deprecated
+	public final String toString() {
+		final StringBuffer buffer = new StringBuffer();
+
+		buffer.append("ActionHandler(action="); //$NON-NLS-1$
+		buffer.append(action);
+		buffer.append(')');
+
+		return buffer.toString();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/CategoryEvent.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/CategoryEvent.java
new file mode 100644
index 0000000..3e0cfc0
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/CategoryEvent.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.commands;
+
+/**
+ * An instance of this class describes changes to an instance of
+ * <code>ICategory</code>.
+ * <p>
+ * This class is not intended to be extended by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @see org.eclipse.ui.commands.ICategoryListener#categoryChanged(CategoryEvent)
+ * @deprecated Please use the "org.eclipse.core.commands" plug-in instead.
+ * @see org.eclipse.core.commands.CategoryEvent
+ */
+@Deprecated
+public final class CategoryEvent {
+
+    /**
+     * The category that has changed; this value is never <code>null</code>.
+     */
+    private final ICategory category;
+
+    /**
+     * Whether the defined state of the category has changed.
+     */
+    private final boolean definedChanged;
+
+    /**
+     * Whether the name of the category has changed.
+     */
+    private final boolean nameChanged;
+
+    /**
+     * Creates a new instance of this class.
+     *
+     * @param category
+     *            the instance of the interface that changed.
+     * @param definedChanged
+     *            true, iff the defined property changed.
+     * @param nameChanged
+     *            true, iff the name property changed.
+     */
+	@Deprecated
+    public CategoryEvent(ICategory category, boolean definedChanged,
+            boolean nameChanged) {
+        if (category == null) {
+			throw new NullPointerException();
+		}
+
+        this.category = category;
+        this.definedChanged = definedChanged;
+        this.nameChanged = nameChanged;
+    }
+
+    /**
+     * Returns the instance of the interface that changed.
+     *
+     * @return the instance of the interface that changed. Guaranteed not to be
+     *         <code>null</code>.
+     */
+	@Deprecated
+    public ICategory getCategory() {
+        return category;
+    }
+
+    /**
+     * Returns whether or not the defined property changed.
+     *
+     * @return true, iff the defined property changed.
+     */
+	@Deprecated
+    public boolean hasDefinedChanged() {
+        return definedChanged;
+    }
+
+    /**
+     * Returns whether or not the name property changed.
+     *
+     * @return true, iff the name property changed.
+     */
+	@Deprecated
+    public boolean hasNameChanged() {
+        return nameChanged;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/CommandEvent.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/CommandEvent.java
new file mode 100644
index 0000000..db2c4bd
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/CommandEvent.java
@@ -0,0 +1,237 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.commands;
+
+import java.util.Collections;
+import java.util.Map;
+import org.eclipse.ui.internal.util.Util;
+
+/**
+ * An instance of this class describes changes to an instance of
+ * <code>ICommand</code>.
+ * <p>
+ * This class is not intended to be extended by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @see ICommandListener#commandChanged(CommandEvent)
+ * @deprecated Please use the "org.eclipse.core.commands" plug-in instead.
+ * @see org.eclipse.core.commands.CommandEvent
+ */
+@Deprecated
+@SuppressWarnings("all")
+public final class CommandEvent {
+
+    /**
+     * Whether the attributes of the command have changed.  These are name and
+     * value pairs representing properties of the command.
+     */
+    private final boolean attributeValuesByNameChanged;
+
+    /**
+     * Whether the category identifier has changed.
+     */
+    private final boolean categoryIdChanged;
+
+    /**
+     * The command that has changed; this value is never <code>null</code>.
+     */
+    private final ICommand command;
+
+    /**
+     * Whether the defined state of the command has changed.
+     */
+    private final boolean definedChanged;
+
+    /**
+     * Whether the description of the command has changed.
+     */
+    private final boolean descriptionChanged;
+
+    /**
+     * Whether the command has either gained or lost a handler.
+     */
+    private final boolean handledChanged;
+
+    /**
+     * Whether the key bindings for the command have changed.
+     */
+    private final boolean keySequenceBindingsChanged;
+
+    /**
+     * Whether the name of the command has changed.
+     */
+    private final boolean nameChanged;
+
+    /**
+     * The map of attributes before the change.  This is a map of attribute name
+     * (strings) to values (any object).
+     */
+    private Map previousAttributeValuesByName;
+
+    /**
+     * Creates a new instance of this class.
+     *
+     * @param command
+     *            the instance of the interface that changed.
+     * @param attributeValuesByNameChanged
+     *            true, iff the attributeValuesByName property changed.
+     * @param categoryIdChanged
+     *            true, iff the categoryId property changed.
+     * @param definedChanged
+     *            true, iff the defined property changed.
+     * @param descriptionChanged
+     *            true, iff the description property changed.
+     * @param handledChanged
+     *            true, iff the handled property changed.
+     * @param keySequenceBindingsChanged
+     *            true, iff the keySequenceBindings property changed.
+     * @param nameChanged
+     *            true, iff the name property changed.
+     * @param previousAttributeValuesByName
+     *            the map of previous attribute values by name. This map may be
+     *            empty. If this map is not empty, it's collection of keys must
+     *            only contain instances of <code>String</code>. This map
+     *            must be <code>null</code> if attributeValuesByNameChanged is
+     *            <code>false</code> and must not be null if
+     *            attributeValuesByNameChanged is <code>true</code>.
+     */
+    public CommandEvent(ICommand command, boolean attributeValuesByNameChanged,
+            boolean categoryIdChanged, boolean definedChanged,
+            boolean descriptionChanged, boolean handledChanged,
+            boolean keySequenceBindingsChanged, boolean nameChanged,
+            Map previousAttributeValuesByName) {
+        if (command == null) {
+			throw new NullPointerException();
+		}
+
+        if (!attributeValuesByNameChanged
+                && previousAttributeValuesByName != null) {
+			throw new IllegalArgumentException();
+		}
+
+        if (attributeValuesByNameChanged) {
+        	if (previousAttributeValuesByName == null) {
+				this.previousAttributeValuesByName = Collections.EMPTY_MAP;
+			} else {
+				this.previousAttributeValuesByName = Util.safeCopy(
+						previousAttributeValuesByName, String.class,
+						Object.class, false, true);
+			}
+        }
+
+        this.command = command;
+        this.attributeValuesByNameChanged = attributeValuesByNameChanged;
+        this.categoryIdChanged = categoryIdChanged;
+        this.definedChanged = definedChanged;
+        this.descriptionChanged = descriptionChanged;
+        this.handledChanged = handledChanged;
+        this.keySequenceBindingsChanged = keySequenceBindingsChanged;
+        this.nameChanged = nameChanged;
+    }
+
+    /**
+     * Returns the instance of the interface that changed.
+     *
+     * @return the instance of the interface that changed. Guaranteed not to be
+     *         <code>null</code>.
+     */
+	@Deprecated
+    public ICommand getCommand() {
+        return command;
+    }
+
+    /**
+     * Returns the map of previous attribute values by name.
+     *
+     * @return the map of previous attribute values by name. This map may be
+     *         empty. If this map is not empty, it's collection of keys is
+     *         guaranteed to only contain instances of <code>String</code>.
+     *         This map is guaranteed to be <code>null</code> if
+     *         haveAttributeValuesByNameChanged() is <code>false</code> and is
+     *         guaranteed to not be null if haveAttributeValuesByNameChanged()
+     *         is <code>true</code>.
+     */
+	@Deprecated
+    public Map getPreviousAttributeValuesByName() {
+        return previousAttributeValuesByName;
+    }
+
+    /**
+     * Returns whether or not the categoryId property changed.
+     *
+     * @return true, iff the categoryId property changed.
+     */
+	@Deprecated
+    public boolean hasCategoryIdChanged() {
+        return categoryIdChanged;
+    }
+
+    /**
+     * Returns whether or not the defined property changed.
+     *
+     * @return true, iff the defined property changed.
+     */
+	@Deprecated
+    public boolean hasDefinedChanged() {
+        return definedChanged;
+    }
+
+    /**
+     * Returns whether or not the description property changed.
+     *
+     * @return true, iff the description property changed.
+     */
+	@Deprecated
+    public boolean hasDescriptionChanged() {
+        return descriptionChanged;
+    }
+
+    /**
+     * Returns whether or not the handled property changed.
+     *
+     * @return true, iff the handled property changed.
+     */
+	@Deprecated
+    public boolean hasHandledChanged() {
+        return handledChanged;
+    }
+
+    /**
+     * Returns whether or not the name property changed.
+     *
+     * @return true, iff the name property changed.
+     */
+	@Deprecated
+    public boolean hasNameChanged() {
+        return nameChanged;
+    }
+
+    /**
+     * Returns whether or not the attributeValuesByName property changed.
+     *
+     * @return true, iff the attributeValuesByName property changed.
+     */
+	@Deprecated
+    public boolean haveAttributeValuesByNameChanged() {
+        return attributeValuesByNameChanged;
+    }
+
+    /**
+     * Returns whether or not the keySequenceBindings property changed.
+     *
+     * @return true, iff the keySequenceBindings property changed.
+     */
+	@Deprecated
+    public boolean haveKeySequenceBindingsChanged() {
+        return keySequenceBindingsChanged;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/CommandException.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/CommandException.java
new file mode 100644
index 0000000..1be0245
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/CommandException.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.commands;
+
+/**
+ * Signals that an exception occurred within the command architecture.
+ * <p>
+ * This class is not intended to be extended by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @deprecated Please use the "org.eclipse.core.commands" plug-in instead.
+ * @see org.eclipse.core.commands.common.CommandException
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+@Deprecated
+@SuppressWarnings("all")
+public abstract class CommandException extends Exception {
+
+	/**
+	 * Generated serial version UID for this class.
+	 *
+	 * @since 3.4
+	 */
+	private static final long serialVersionUID= 1776879459633730964L;
+
+
+	private Throwable cause;
+
+    /**
+     * Creates a new instance of this class with the specified detail message.
+     *
+     * @param message
+     *            the detail message.
+     */
+	@Deprecated
+    public CommandException(String message) {
+        super(message);
+    }
+
+    /**
+     * Creates a new instance of this class with the specified detail message
+     * and cause.
+     *
+     * @param message
+     *            the detail message.
+     * @param cause
+     *            the cause.
+     */
+	@Deprecated
+    public CommandException(String message, Throwable cause) {
+        super(message);
+        // don't pass the cause to super, to allow compilation against JCL Foundation
+        this.cause = cause;
+    }
+
+    /**
+     * Returns the cause of this throwable or <code>null</code> if the
+     * cause is nonexistent or unknown.
+     *
+     * @return the cause or <code>null</code>
+     * @since 3.1
+     */
+	@Override
+	@Deprecated
+    public Throwable getCause() {
+        return cause;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/CommandManagerEvent.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/CommandManagerEvent.java
new file mode 100644
index 0000000..2e917db
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/CommandManagerEvent.java
@@ -0,0 +1,319 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.commands;
+
+import java.util.Set;
+import org.eclipse.ui.internal.util.Util;
+
+/**
+ * An instance of this class describes changes to an instance of
+ * <code>ICommandManager</code>.
+ * <p>
+ * This class is not intended to be extended by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @see ICommandManagerListener#commandManagerChanged(CommandManagerEvent)
+ * @see org.eclipse.core.commands.CommandManagerEvent
+ * @deprecated Please use the "org.eclipse.core.commands" plug-in instead.
+ */
+@Deprecated
+@SuppressWarnings("all")
+public final class CommandManagerEvent {
+
+    /**
+     * Whether the set of active contexts has changed.
+     */
+    private final boolean activeContextIdsChanged;
+
+    /**
+     * Whether the active key configuration has changed.
+     */
+    private final boolean activeKeyConfigurationIdChanged;
+
+    /**
+     * Whether the locale has changed.
+     */
+    private final boolean activeLocaleChanged;
+
+    /**
+     * Whether the platform has changed.
+     */
+    private final boolean activePlatformChanged;
+
+    /**
+     * Whether the command manager has changed.
+     */
+    private final ICommandManager commandManager;
+
+    /**
+     * Whether the list of defined categories has changed.
+     */
+    private final boolean definedCategoryIdsChanged;
+
+    /**
+     * Whether the list of defined commands has changed.
+     */
+    private final boolean definedCommandIdsChanged;
+
+    /**
+     * Whether the list of defined key configurations has changed.
+     */
+    private final boolean definedKeyConfigurationIdsChanged;
+
+    /**
+     * The set of the defined categories before the change occurred.  This is a
+     * set of strings (category identifiers).
+     */
+    private final Set previouslyDefinedCategoryIds;
+
+    /**
+     * The set of the defined commands before the change occurred.  This is a
+     * set of strings (command identifiers).
+     */
+    private final Set previouslyDefinedCommandIds;
+
+    /**
+     * The set of the defined key configurations before the change occurred.
+     * This is a set of strings (key configuration identifiers).
+     */
+    private final Set previouslyDefinedKeyConfigurationIds;
+
+    /**
+     * Creates a new instance of this class.
+     *
+     * @param commandManager
+     *            the instance of the interface that changed.
+     * @param activeContextIdsChanged
+     *            true, iff the activeContextIdsChanged property changed.
+     * @param activeKeyConfigurationIdChanged
+     *            true, iff the activeKeyConfigurationIdChanged property
+     *            changed.
+     * @param activeLocaleChanged
+     *            true, iff the activeLocaleChanged property changed.
+     * @param activePlatformChanged
+     *            true, iff the activePlatformChanged property changed.
+     * @param definedCategoryIdsChanged
+     *            true, iff the definedCategoryIdsChanged property changed.
+     * @param definedCommandIdsChanged
+     *            true, iff the definedCommandIdsChanged property changed.
+     * @param definedKeyConfigurationIdsChanged
+     *            true, iff the definedKeyConfigurationIdsChanged property
+     *            changed.
+     * @param previouslyDefinedCategoryIds
+     *            the set of identifiers to previously defined categories. This
+     *            set may be empty. If this set is not empty, it must only
+     *            contain instances of <code>String</code>. This set must be
+     *            <code>null</code> if definedCategoryIdsChanged is
+     *            <code>false</code> and must not be null if
+     *            definedCategoryIdsChanged is <code>true</code>.
+     * @param previouslyDefinedCommandIds
+     *            the set of identifiers to previously defined commands. This
+     *            set may be empty. If this set is not empty, it must only
+     *            contain instances of <code>String</code>. This set must be
+     *            <code>null</code> if definedCommandIdsChanged is
+     *            <code>false</code> and must not be null if
+     *            definedContextIdsChanged is <code>true</code>.
+     * @param previouslyDefinedKeyConfigurationIds
+     *            the set of identifiers to previously defined key
+     *            configurations. This set may be empty. If this set is not
+     *            empty, it must only contain instances of <code>String</code>.
+     *            This set must be <code>null</code> if
+     *            definedKeyConfigurationIdsChanged is <code>false</code> and
+     *            must not be null if definedKeyConfigurationIdsChanged is
+     *            <code>true</code>.
+     */
+    public CommandManagerEvent(ICommandManager commandManager,
+            boolean activeContextIdsChanged,
+            boolean activeKeyConfigurationIdChanged,
+            boolean activeLocaleChanged, boolean activePlatformChanged,
+            boolean definedCategoryIdsChanged,
+            boolean definedCommandIdsChanged,
+            boolean definedKeyConfigurationIdsChanged,
+            Set previouslyDefinedCategoryIds, Set previouslyDefinedCommandIds,
+            Set previouslyDefinedKeyConfigurationIds) {
+        if (commandManager == null) {
+			throw new NullPointerException();
+		}
+
+        if (!definedCategoryIdsChanged && previouslyDefinedCategoryIds != null) {
+			throw new IllegalArgumentException();
+		}
+
+        if (!definedCommandIdsChanged && previouslyDefinedCommandIds != null) {
+			throw new IllegalArgumentException();
+		}
+
+        if (!definedKeyConfigurationIdsChanged
+                && previouslyDefinedKeyConfigurationIds != null) {
+			throw new IllegalArgumentException();
+		}
+
+        if (definedCategoryIdsChanged) {
+            this.previouslyDefinedCategoryIds = Util.safeCopy(
+                    previouslyDefinedCategoryIds, String.class);
+        } else {
+            this.previouslyDefinedCategoryIds = null;
+        }
+
+        if (definedCommandIdsChanged) {
+            this.previouslyDefinedCommandIds = Util.safeCopy(
+                    previouslyDefinedCommandIds, String.class);
+        } else {
+            this.previouslyDefinedCommandIds = null;
+        }
+
+        if (definedKeyConfigurationIdsChanged) {
+            this.previouslyDefinedKeyConfigurationIds = Util.safeCopy(
+                    previouslyDefinedKeyConfigurationIds, String.class);
+        } else {
+            this.previouslyDefinedKeyConfigurationIds = null;
+        }
+
+        this.commandManager = commandManager;
+        this.activeContextIdsChanged = activeContextIdsChanged;
+        this.activeKeyConfigurationIdChanged = activeKeyConfigurationIdChanged;
+        this.activeLocaleChanged = activeLocaleChanged;
+        this.activePlatformChanged = activePlatformChanged;
+        this.definedCategoryIdsChanged = definedCategoryIdsChanged;
+        this.definedCommandIdsChanged = definedCommandIdsChanged;
+        this.definedKeyConfigurationIdsChanged = definedKeyConfigurationIdsChanged;
+    }
+
+    /**
+     * Returns the instance of the interface that changed.
+     *
+     * @return the instance of the interface that changed. Guaranteed not to be
+     *         <code>null</code>.
+     */
+	@Deprecated
+    public ICommandManager getCommandManager() {
+        return commandManager;
+    }
+
+    /**
+     * Returns the set of identifiers to previously defined categories.
+     *
+     * @return the set of identifiers to previously defined categories. This set
+     *         may be empty. If this set is not empty, it is guaranteed to only
+     *         contain instances of <code>String</code>. This set is
+     *         guaranteed to be <code>null</code> if
+     *         haveDefinedCategoryIdsChanged() is <code>false</code> and is
+     *         guaranteed to not be null if haveDefinedCategoryIdsChanged() is
+     *         <code>true</code>.
+     */
+	@Deprecated
+    public Set getPreviouslyDefinedCategoryIds() {
+        return previouslyDefinedCategoryIds;
+    }
+
+    /**
+     * Returns the set of identifiers to previously defined commands.
+     *
+     * @return the set of identifiers to previously defined commands. This set
+     *         may be empty. If this set is not empty, it is guaranteed to only
+     *         contain instances of <code>String</code>. This set is
+     *         guaranteed to be <code>null</code> if
+     *         haveDefinedCommandIdsChanged() is <code>false</code> and is
+     *         guaranteed to not be null if haveDefinedCommandIdsChanged() is
+     *         <code>true</code>.
+     */
+	@Deprecated
+    public Set getPreviouslyDefinedCommandIds() {
+        return previouslyDefinedCommandIds;
+    }
+
+    /**
+     * Returns the set of identifiers to previously defined key conigurations.
+     *
+     * @return the set of identifiers to previously defined key configurations.
+     *         This set may be empty. If this set is not empty, it is guaranteed
+     *         to only contain instances of <code>String</code>. This set is
+     *         guaranteed to be <code>null</code> if
+     *         haveDefinedKeyConfigurationIdsChanged() is <code>false</code>
+     *         and is guaranteed to not be null if
+     *         haveDefinedKeyConfigurationIdsChanged() is <code>true</code>.
+     */
+	@Deprecated
+    public Set getPreviouslyDefinedKeyConfigurationIds() {
+        return previouslyDefinedKeyConfigurationIds;
+    }
+
+    /**
+     * Returns whether or not the activeKeyConfigurationId property changed.
+     *
+     * @return true, iff the activeKeyConfigurationId property changed.
+     */
+	@Deprecated
+    public boolean hasActiveKeyConfigurationIdChanged() {
+        return activeKeyConfigurationIdChanged;
+    }
+
+    /**
+     * Returns whether or not the activeLocale property changed.
+     *
+     * @return true, iff the activeLocale property changed.
+     */
+	@Deprecated
+    public boolean hasActiveLocaleChanged() {
+        return activeLocaleChanged;
+    }
+
+    /**
+     * Returns whether or not the activePlatform property changed.
+     *
+     * @return true, iff the activePlatform property changed.
+     */
+	@Deprecated
+    public boolean hasActivePlatformChanged() {
+        return activePlatformChanged;
+    }
+
+    /**
+     * Returns whether or not the activeContextIds property changed.
+     *
+     * @return true, iff the activeContextIds property changed.
+     */
+	@Deprecated
+    public boolean haveActiveContextIdsChanged() {
+        return activeContextIdsChanged;
+    }
+
+    /**
+     * Returns whether or not the definedCategoryIds property changed.
+     *
+     * @return true, iff the definedCategoryIds property changed.
+     */
+	@Deprecated
+    public boolean haveDefinedCategoryIdsChanged() {
+        return definedCategoryIdsChanged;
+    }
+
+    /**
+     * Returns whether or not the definedCommandIds property changed.
+     *
+     * @return true, iff the definedCommandIds property changed.
+     */
+	@Deprecated
+    public boolean haveDefinedCommandIdsChanged() {
+        return definedCommandIdsChanged;
+    }
+
+    /**
+     * Returns whether or not the definedKeyConfigurationIds property changed.
+     *
+     * @return true, iff the definedKeyConfigurationIds property changed.
+     */
+	@Deprecated
+    public boolean haveDefinedKeyConfigurationIdsChanged() {
+        return definedKeyConfigurationIdsChanged;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/ExecutionException.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/ExecutionException.java
new file mode 100644
index 0000000..cbdccac
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/ExecutionException.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.commands;
+
+/**
+ * Signals that an exception occured during the execution of a command.
+ * <p>
+ * This class is not intended to be extended by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @deprecated Please use the "org.eclipse.core.commands" plug-in instead.
+ * @see org.eclipse.core.commands.ExecutionException
+ */
+@Deprecated
+@SuppressWarnings("all")
+public final class ExecutionException extends CommandException {
+
+    /**
+     * Generated serial version UID for this class.
+     *
+     * @since 3.1
+     */
+    private static final long serialVersionUID = 3258130262767448120L;
+
+    /**
+     * Creates a new instance of this class with the specified detail message
+     * and cause.
+     *
+     * @param message
+     *            the detail message.
+     * @param cause
+     *            the cause.
+     */
+    public ExecutionException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Constructs a new instance of <code>ExecutionException</code> using an
+     * instance of the new <code>ExecutionException</code>.
+     *
+     * @param e
+     *            The exception from which this exception should be created;
+     *            must not be <code>null</code>.
+     * @since 3.1
+     */
+    public ExecutionException(final org.eclipse.core.commands.ExecutionException e) {
+        super(e.getMessage(), e);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/ExtensionParameterValues.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/ExtensionParameterValues.java
new file mode 100644
index 0000000..899c9f9
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/ExtensionParameterValues.java
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.commands;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import org.eclipse.core.commands.IParameterValues;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExecutableExtension;
+
+/**
+ * <p>
+ * A generic implementation of <code>IParameterValues</code> that takes advantage
+ * of the <code>IExecutableExtension</code> mechanism.  The parameter values and names can be
+ * specified purely in XML.  This can be done as follows:
+ * </p>
+ * <p><pre><code>
+ *     &lt;command
+ *    		name="%name"
+ *     		description="%description"
+ *     		categoryId="categoryId"
+ *     		id="commandId"&gt;
+ *     		&lt;parameter
+ *     			id="parameterId"
+ *     			name="%parameterName"&gt;
+ *     				&lt;values class="org.eclipse.ui.commands.ExtensionParameterValues"&gt;
+ *     					&lt;parameter name="%parameterName1" value="parameterValue1" /&gt;
+ *     					&lt;parameter name="%parameterName2" value="parameterValue2" /&gt;
+ *     					&lt;parameter name="%parameterName3" value="parameterValue3" /&gt;
+ *     				&lt;/values&gt;
+ *          &lt;/parameter&gt;
+ *     &lt;/command&gt;
+ * </code></pre></p>
+ *
+ * @since 3.1
+ */
+public final class ExtensionParameterValues implements IParameterValues,
+		IExecutableExtension {
+
+	/**
+	 * The delimiter between elements if the name-value pairs are specified in a
+	 * single string.
+	 */
+	public static final String DELIMITER = ","; //$NON-NLS-1$
+
+	/**
+	 * The parameter values for this instance. This is initialization when the
+	 * executable extension is created. For example,
+	 */
+	private Map parameterValues = null;
+
+	@Override
+	public Map getParameterValues() {
+		return parameterValues;
+	}
+
+	@Override
+	public final void setInitializationData(final IConfigurationElement config,
+			final String propertyName, final Object data) {
+		if (data == null) {
+			parameterValues = Collections.EMPTY_MAP;
+
+		} else if (data instanceof String) {
+			parameterValues = new HashMap();
+			final StringTokenizer tokenizer = new StringTokenizer(
+					(String) data, DELIMITER);
+			while (tokenizer.hasMoreTokens()) {
+				final String name = tokenizer.nextToken();
+				if (tokenizer.hasMoreTokens()) {
+					final String value = tokenizer.nextToken();
+					parameterValues.put(name, value);
+				}
+			}
+			parameterValues = Collections.unmodifiableMap(parameterValues);
+
+		} else if (data instanceof Hashtable) {
+			parameterValues = Collections.unmodifiableMap((Hashtable) data);
+
+		}
+
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/HandlerEvent.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/HandlerEvent.java
new file mode 100644
index 0000000..d3e691c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/HandlerEvent.java
@@ -0,0 +1,144 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.commands;
+
+import java.util.Map;
+import org.eclipse.ui.internal.util.Util;
+
+/**
+ * An instance of this class describes changes to an instance of
+ * <code>IHandler</code>.
+ * <p>
+ * This class is not intended to be extended by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @see IHandlerListener#handlerChanged(HandlerEvent)
+ * @deprecated Please use the "org.eclipse.core.commands" plug-in instead.
+ */
+@Deprecated
+@SuppressWarnings("all")
+public final class HandlerEvent {
+
+    /**
+     * Whether the attributes of the handler changed.
+     */
+    private final boolean attributeValuesByNameChanged;
+
+    /**
+     * The handler that changed; this value is never <code>null</code>.
+     */
+    private final IHandler handler;
+
+    /**
+     * This is the cached result of getPreviousAttributeValuesByName. It is
+     * computed the first time getPreviousAttributeValuesByName is called.
+     */
+    private Map previousAttributeValuesByName;
+
+    /**
+     * The map of previous attributes, if they changed.  If they did not change,
+     * then this value is <code>null</code>.  The map's keys are the attribute
+     * names (strings), and its value are any object.
+     *
+     * This is the original map passed into the constructor. This object always
+     * returns a copy of this map, not the original. However the constructor of
+     * this object is called very frequently and the map is rarely requested,
+     * so we only copy the map the first time it is requested.
+     *
+     * @since 3.1
+     */
+    private final Map originalPreviousAttributeValuesByName;
+
+    /**
+     * Creates a new instance of this class.
+     *
+     * @param handler
+     *            the instance of the interface that changed.
+     * @param attributeValuesByNameChanged
+     *            true, iff the attributeValuesByName property changed.
+     * @param previousAttributeValuesByName
+     *            the map of previous attribute values by name. This map may be
+     *            empty. If this map is not empty, it's collection of keys must
+     *            only contain instances of <code>String</code>. This map
+     *            must be <code>null</code> if attributeValuesByNameChanged is
+     *            <code>false</code> and must not be null if
+     *            attributeValuesByNameChanged is <code>true</code>.
+     */
+	@Deprecated
+    public HandlerEvent(IHandler handler, boolean attributeValuesByNameChanged,
+            Map previousAttributeValuesByName) {
+        if (handler == null) {
+			throw new NullPointerException();
+		}
+
+        if (!attributeValuesByNameChanged
+                && previousAttributeValuesByName != null) {
+			throw new IllegalArgumentException();
+		}
+
+        if (attributeValuesByNameChanged) {
+            this.originalPreviousAttributeValuesByName = previousAttributeValuesByName;
+        } else {
+            this.originalPreviousAttributeValuesByName = null;
+        }
+
+        this.handler = handler;
+        this.attributeValuesByNameChanged = attributeValuesByNameChanged;
+    }
+
+    /**
+     * Returns the instance of the interface that changed.
+     *
+     * @return the instance of the interface that changed. Guaranteed not to be
+     *         <code>null</code>.
+     */
+	@Deprecated
+    public IHandler getHandler() {
+        return handler;
+    }
+
+    /**
+     * Returns the map of previous attribute values by name.
+     *
+     * @return the map of previous attribute values by name. This map may be
+     *         empty. If this map is not empty, it's collection of keys is
+     *         guaranteed to only contain instances of <code>String</code>.
+     *         This map is guaranteed to be <code>null</code> if
+     *         haveAttributeValuesByNameChanged() is <code>false</code> and is
+     *         guaranteed to not be null if haveAttributeValuesByNameChanged()
+     *         is <code>true</code>.
+     */
+	@Deprecated
+    public Map getPreviousAttributeValuesByName() {
+        if (originalPreviousAttributeValuesByName == null) {
+            return null;
+        }
+
+        if (previousAttributeValuesByName == null) {
+            previousAttributeValuesByName = Util.safeCopy(
+                    originalPreviousAttributeValuesByName, String.class, Object.class,
+                    false, true);
+        }
+
+        return previousAttributeValuesByName;
+    }
+
+    /**
+     * Returns whether or not the attributeValuesByName property changed.
+     *
+     * @return true, iff the attributeValuesByName property changed.
+     */
+	@Deprecated
+    public boolean haveAttributeValuesByNameChanged() {
+        return attributeValuesByNameChanged;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/HandlerSubmission.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/HandlerSubmission.java
new file mode 100644
index 0000000..bf7a282
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/HandlerSubmission.java
@@ -0,0 +1,255 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.commands;
+
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.internal.util.Util;
+
+/**
+ * </p>
+ * An instance of this class represents a request to handle a command. A handler
+ * submission specifies a list of conditions under which it would be appropriate
+ * for a particular command to have a particular handler. These conditions
+ * include things like the active part or the active shell. So, it is possible
+ * to say things like: "when my part is active, please consider calling these
+ * classes when you want to perform a cut, copy or paste".
+ * </p>
+ * <p>
+ * The workbench considers all of the submissions it has received and choses the
+ * ones it views as the best possible match.
+ * </p>
+ * <p>
+ * This class is not intended to be extended by clients.
+ * </p>
+ * <p>
+ * Note: this class has a natural ordering that is inconsistent with equals.
+ * </p>
+ *
+ * @since 3.0
+ * @see org.eclipse.ui.commands.IWorkbenchCommandSupport
+ * @deprecated Please use <code>IHandlerService.activateHandler</code>
+ *             instead.
+ * @see org.eclipse.ui.handlers.IHandlerService
+ */
+@Deprecated
+@SuppressWarnings("all")
+public final class HandlerSubmission implements Comparable {
+
+    /**
+     * The part identifier for the part that should be active before this
+     * submission can be considered.  This value can be <code>null</code>, which
+     * indicates that it should match any part.
+     */
+    private final String activePartId;
+
+    /**
+     * The shell that must be active before this submission can be considered.
+     * This value can be <code>null</code>, which indicates that it should match
+     * any shell.
+     */
+    private final Shell activeShell;
+
+    /**
+     * The workbench site that must be active before this submission can be
+     * considered.  This value can be <code>null</code>, which indicates that it
+     * should match an workbench part site.
+     */
+    private final IWorkbenchPartSite activeWorkbenchPartSite;
+
+    /**
+     * The identifier for the command which the submitted handler handles.  This
+     * value cannot be <code>null</code>.
+     */
+    private final String commandId;
+
+    /**
+     * The handler being submitted.  This value cannot be <code>null</code>.
+     */
+    private final IHandler handler;
+
+    /**
+     * The priority for this submission.  In the event of all other factors
+     * being equal, the priority will be considered in an attempt to resolve
+     * conflicts.  This value cannot be <code>null</code>.
+     */
+    private final Priority priority;
+
+    /**
+     * A lazily computed cache of the string representation of this submission.
+     * This value is computed once; before it is computed, it is
+     * <code>null</code>.
+     */
+    private transient String string;
+
+    /**
+     * Creates a new instance of this class.
+     *
+     * @param activePartId
+     *            the identifier of the part that must be active for this
+     *            request to be considered. May be <code>null</code>.
+     * @param activeShell
+     *            the shell that must be active for this request to be
+     *            considered. May be <code>null</code>.
+     * @param activeWorkbenchPartSite
+     *            the workbench part site of the part that must be active for
+     *            this request to be considered. May be <code>null</code>.
+     * @param commandId
+     *            the identifier of the command to be handled. Must not be
+     *            <code>null</code>.
+     * @param handler
+     *            the handler. Must not be <code>null</code>.
+     * @param priority
+     *            the priority. Must not be <code>null</code>.
+     */
+	@Deprecated
+    public HandlerSubmission(String activePartId, Shell activeShell,
+            IWorkbenchPartSite activeWorkbenchPartSite, String commandId,
+            IHandler handler, Priority priority) {
+        if (commandId == null || handler == null || priority == null) {
+			throw new NullPointerException();
+		}
+
+        this.activePartId = activePartId;
+        this.activeShell = activeShell;
+        this.activeWorkbenchPartSite = activeWorkbenchPartSite;
+        this.commandId = commandId;
+        this.handler = handler;
+        this.priority = priority;
+    }
+
+    /**
+     * @see Comparable#compareTo(java.lang.Object)
+     */
+	@Override
+	@Deprecated
+    public int compareTo(Object object) {
+        HandlerSubmission castedObject = (HandlerSubmission) object;
+        int compareTo = Util.compare(activeWorkbenchPartSite,
+                castedObject.activeWorkbenchPartSite);
+
+        if (compareTo == 0) {
+            compareTo = Util.compare(activePartId, castedObject.activePartId);
+
+            if (compareTo == 0) {
+                compareTo = Util.compare(activeShell, castedObject.activeShell);
+
+                if (compareTo == 0) {
+                    compareTo = Util.compare(priority, castedObject.priority);
+
+                    if (compareTo == 0) {
+                        compareTo = Util.compare(commandId,
+                                castedObject.commandId);
+
+                        if (compareTo == 0) {
+							compareTo = Util.compare(handler,
+                                    castedObject.handler);
+						}
+                    }
+                }
+            }
+        }
+
+        return compareTo;
+    }
+
+    /**
+     * Returns the identifier of the part that must be active for this request
+     * to be considered.
+     *
+     * @return the identifier of the part that must be active for this request
+     *         to be considered. May be <code>null</code>.
+     */
+	@Deprecated
+    public String getActivePartId() {
+        return activePartId;
+    }
+
+    /**
+     * Returns the shell that must be active for this request to be considered.
+     *
+     * @return the shell that must be active for this request to be considered.
+     *         May be <code>null</code>.
+     */
+	@Deprecated
+    public Shell getActiveShell() {
+        return activeShell;
+    }
+
+    /**
+     * Returns the workbench part site of the part that must be active for this
+     * request to be considered.
+     *
+     * @return the workbench part site of the part that must be active for this
+     *         request to be considered. May be <code>null</code>.
+     */
+	@Deprecated
+    public IWorkbenchPartSite getActiveWorkbenchPartSite() {
+        return activeWorkbenchPartSite;
+    }
+
+    /**
+     * Returns the identifier of the command to be handled.
+     *
+     * @return the identifier of the command to be handled. Guaranteed not to be
+     *         <code>null</code>.
+     */
+	@Deprecated
+    public String getCommandId() {
+        return commandId;
+    }
+
+    /**
+     * Returns the handler.
+     *
+     * @return the handler. Guaranteed not to be <code>null</code>.
+     */
+	@Deprecated
+    public IHandler getHandler() {
+        return handler;
+    }
+
+    /**
+     * Returns the priority.
+     *
+     * @return the priority. Guaranteed not to be <code>null</code>.
+     */
+	@Deprecated
+    public Priority getPriority() {
+        return priority;
+    }
+
+    /**
+     * @see Object#toString()
+     */
+    @Override
+	public String toString() {
+        if (string == null) {
+            final StringBuffer stringBuffer = new StringBuffer();
+            stringBuffer.append("[activePartId="); //$NON-NLS-1$
+            stringBuffer.append(activePartId);
+            stringBuffer.append(",activeShell="); //$NON-NLS-1$
+            stringBuffer.append(activeShell);
+            stringBuffer.append(",activeWorkbenchSite="); //$NON-NLS-1$
+            stringBuffer.append(activeWorkbenchPartSite);
+            stringBuffer.append(",commandId="); //$NON-NLS-1$
+            stringBuffer.append(commandId);
+            stringBuffer.append(",handler="); //$NON-NLS-1$
+            stringBuffer.append(handler);
+            stringBuffer.append(",priority="); //$NON-NLS-1$
+            stringBuffer.append(priority);
+            stringBuffer.append(']');
+            string = stringBuffer.toString();
+        }
+
+        return string;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/ICategory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/ICategory.java
new file mode 100644
index 0000000..842821c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/ICategory.java
@@ -0,0 +1,140 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.commands;
+
+/**
+ * <p>
+ * A category is a grouping of commands by functional area. For example, in the
+ * Eclipse workbench, "Text Editing" is a category containing various commands
+ * related to text editing. A category's primary functionality is to control the
+ * display of commands to the user. When appropriate, commands displayed to the
+ * user (e.g., keys preference page) will be grouped by category.
+ * </p>
+ * <p>
+ * An instance of <code>ICategory</code> is a handle representing a category
+ * as defined by the extension point <code>org.eclipse.ui.commands</code>.
+ * The identifier of the handle is identifier of the category being represented.
+ * </p>
+ * <p>
+ * An instance of <code>ICategory</code> can be obtained from an instance of
+ * <code>ICommandManager</code> for any identifier, whether or not a category
+ * with that identifier defined in the plugin registry.
+ * </p>
+ * <p>
+ * The handle-based nature of this API allows it to work well with runtime
+ * plugin activation and deactivation, which causes dynamic changes to the
+ * plugin registry, and therefore, potentially, dynamic changes to the set of
+ * category definitions.
+ * </p>
+ * <p>
+ * This interface is not intended to be extended or implemented by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @see ICategoryListener
+ * @see ICommandManager
+ * @see org.eclipse.core.commands.Category
+ * @deprecated Please use the "org.eclipse.core.commands" plug-in instead.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+@Deprecated
+@SuppressWarnings("all")
+public interface ICategory extends Comparable {
+
+    /**
+     * Registers an instance of <code>ICategoryListener</code> to listen for
+     * changes to attributes of this instance.
+     *
+     * @param categoryListener
+     *            the instance of <code>ICategoryListener</code> to register.
+     *            Must not be <code>null</code>. If an attempt is made to
+     *            register an instance of <code>ICategoryListener</code>
+     *            which is already registered with this instance, no operation
+     *            is performed.
+     */
+	@Deprecated
+    void addCategoryListener(ICategoryListener categoryListener);
+
+    /**
+     * <p>
+     * Returns the description of the category represented by this handle,
+     * suitable for display to the user.
+     * </p>
+     * <p>
+     * Notification is sent to all registered listeners if this attribute
+     * changes.
+     * </p>
+     *
+     * @return the description of the category represented by this handle.
+     *         Guaranteed not to be <code>null</code>.
+     * @throws NotDefinedException
+     *             if the category represented by this handle is not defined.
+     */
+	@Deprecated
+    String getDescription() throws NotDefinedException;
+
+    /**
+     * Returns the identifier of this handle.
+     *
+     * @return the identifier of this handle. Guaranteed not to be <code>null</code>.
+     */
+	@Deprecated
+    String getId();
+
+    /**
+     * <p>
+     * Returns the name of the category represented by this handle, suitable
+     * for display to the user.
+     * </p>
+     * <p>
+     * Notification is sent to all registered listeners if this attribute
+     * changes.
+     * </p>
+     *
+     * @return the name of the category represented by this handle. Guaranteed
+     *         not to be <code>null</code>.
+     * @throws NotDefinedException
+     *             if the category represented by this handle is not defined.
+     */
+	@Deprecated
+    String getName() throws NotDefinedException;
+
+    /**
+     * <p>
+     * Returns whether or not the category represented by this handle is
+     * defined.
+     * </p>
+     * <p>
+     * Notification is sent to all registered listeners if this attribute
+     * changes.
+     * </p>
+     *
+     * @return <code>true</code>, iff the category represented by this
+     *         handle is defined.
+     */
+	@Deprecated
+    boolean isDefined();
+
+    /**
+     * Unregisters an instance of <code>ICategoryListener</code> listening
+     * for changes to attributes of this instance.
+     *
+     * @param categoryListener
+     *            the instance of <code>ICategoryListener</code> to
+     *            unregister. Must not be <code>null</code>. If an attempt
+     *            is made to unregister an instance of <code>ICategoryListener</code>
+     *            which is not already registered with this instance, no
+     *            operation is performed.
+     */
+	@Deprecated
+    void removeCategoryListener(ICategoryListener categoryListener);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/ICategoryListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/ICategoryListener.java
new file mode 100644
index 0000000..96f7939
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/ICategoryListener.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.commands;
+
+/**
+ * <p>
+ * An instance of <code>ICategoryListener</code> can be used by clients to
+ * receive notification of changes to one or more instances of
+ * <code>ICategory</code>.
+ * </p>
+ * <p>
+ * This interface may be implemented by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @see CategoryEvent
+ * @see org.eclipse.ui.commands.ICategory#addCategoryListener(ICategoryListener)
+ * @see org.eclipse.ui.commands.ICategory#removeCategoryListener(ICategoryListener)
+ * @see org.eclipse.core.commands.ICategoryListener
+ * @deprecated Please use the "org.eclipse.core.commands" plug-in instead.
+ */
+@Deprecated
+@SuppressWarnings("all")
+public interface ICategoryListener {
+
+    /**
+     * Notifies that one or more attributes of an instance of
+     * <code>ICategory</code> have changed. Specific details are described in
+     * the <code>CategoryEvent</code>.
+     *
+     * @param categoryEvent
+     *            the category event. Guaranteed not to be <code>null</code>.
+     */
+	@Deprecated
+    void categoryChanged(CategoryEvent categoryEvent);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/ICommand.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/ICommand.java
new file mode 100644
index 0000000..0e4b386
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/ICommand.java
@@ -0,0 +1,224 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.commands;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>
+ * An instance of <code>ICommand</code> is a handle representing a command as
+ * defined by the extension point <code>org.eclipse.ui.commands</code>. The
+ * identifier of the handle is identifier of the command being represented.
+ * </p>
+ * <p>
+ * An instance of <code>ICommand</code> can be obtained from an instance of
+ * <code>ICommandManager</code> for any identifier, whether or not a command
+ * with that identifier defined in the plugin registry.
+ * </p>
+ * <p>
+ * The handle-based nature of this API allows it to work well with runtime
+ * plugin activation and deactivation. If a command is defined, that means that
+ * its corresponding plug-in is active. If the plug-in is then deactivated, the
+ * command will still exist but it will be undefined. An attempts to use an
+ * undefined command will result in a <code>NotDefinedException</code> being
+ * thrown.
+ * </p>
+ * <p>
+ * This interface is not intended to be extended or implemented by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @see ICommandListener
+ * @see ICommandManager
+ * @see org.eclipse.core.commands.Command
+ * @deprecated Please use the "org.eclipse.core.commands" plug-in instead.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+@Deprecated
+@SuppressWarnings("all")
+public interface ICommand extends Comparable {
+
+    /**
+     * Registers an instance of <code>ICommandListener</code> to listen for
+     * changes to attributes of this instance.
+     *
+     * @param commandListener
+     *            the instance of <code>ICommandListener</code> to register.
+     *            Must not be <code>null</code>. If an attempt is made to
+     *            register an instance of <code>ICommandListener</code> which
+     *            is already registered with this instance, no operation is
+     *            performed.
+     */
+	@Deprecated
+    void addCommandListener(ICommandListener commandListener);
+
+    /**
+     * Executes with the map of parameter values by name.
+     *
+     * @param parameterValuesByName
+     *            the map of parameter values by name. Reserved for future use,
+     *            must be <code>null</code>.
+     * @return the result of the execution. Reserved for future use, must be
+     *         <code>null</code>.
+     * @throws ExecutionException
+     *             if an exception occurred during execution.
+     * @throws NotHandledException
+     *             if this is not handled.
+     */
+	@Deprecated
+    Object execute(Map parameterValuesByName) throws ExecutionException,
+            NotHandledException;
+
+    /**
+     * Returns the map of attribute values by name.
+     * <p>
+     * Notification is sent to all registered listeners if this property
+     * changes.
+     * </p>
+     *
+     * @return the map of attribute values by name. This map may be empty, but
+     *         is guaranteed not to be <code>null</code>. If this map is not
+     *         empty, its collection of keys is guaranteed to only contain
+     *         instances of <code>String</code>.
+     * @throws NotHandledException
+     *             if this is not handled.
+     */
+	@Deprecated
+    Map getAttributeValuesByName() throws NotHandledException;
+
+    /**
+     * <p>
+     * Returns the identifier of the category of the command represented by this
+     * handle.
+     * </p>
+     * <p>
+     * Notification is sent to all registered listeners if this attribute
+     * changes.
+     * </p>
+     *
+     * @return the identifier of the category of the command represented by this
+     *         handle. May be <code>null</code>.
+     * @throws NotDefinedException
+     *             if the command represented by this handle is not defined.
+     */
+	@Deprecated
+    String getCategoryId() throws NotDefinedException;
+
+    /**
+     * <p>
+     * Returns the description of the command represented by this handle,
+     * suitable for display to the user.
+     * </p>
+     * <p>
+     * Notification is sent to all registered listeners if this attribute
+     * changes.
+     * </p>
+     *
+     * @return the description of the command represented by this handle.
+     *         Guaranteed not to be <code>null</code>.
+     * @throws NotDefinedException
+     *             if the command represented by this handle is not defined.
+     */
+	@Deprecated
+    String getDescription() throws NotDefinedException;
+
+    /**
+     * Returns the identifier of this handle.
+     *
+     * @return the identifier of this handle. Guaranteed not to be
+     *         <code>null</code>.
+     */
+	@Deprecated
+    String getId();
+
+    /**
+     * <p>
+     * Returns the list of key sequence bindings for this handle. This method
+     * will return all key sequence bindings for this handle's identifier,
+     * whether or not the command represented by this handle is defined.
+     * </p>
+     * <p>
+     * Notification is sent to all registered listeners if this attribute
+     * changes.
+     * </p>
+     *
+     * @return the list of key sequence bindings. This list may be empty, but is
+     *         guaranteed not to be <code>null</code>. If this list is not
+     *         empty, it is guaranteed to only contain instances of
+     *         <code>IKeySequenceBinding</code>.
+     */
+    List getKeySequenceBindings();
+
+    /**
+     * <p>
+     * Returns the name of the command represented by this handle, suitable for
+     * display to the user.
+     * </p>
+     * <p>
+     * Notification is sent to all registered listeners if this attribute
+     * changes.
+     * </p>
+     *
+     * @return the name of the command represented by this handle. Guaranteed
+     *         not to be <code>null</code>.
+     * @throws NotDefinedException
+     *             if the command represented by this handle is not defined.
+     */
+	@Deprecated
+    String getName() throws NotDefinedException;
+
+    /**
+     * <p>
+     * Returns whether or not the command represented by this handle is defined.
+     * </p>
+     * <p>
+     * Notification is sent to all registered listeners if this attribute
+     * changes.
+     * </p>
+     *
+     * @return <code>true</code>, iff the command represented by this handle
+     *         is defined.
+     */
+	@Deprecated
+    boolean isDefined();
+
+    /**
+     * <p>
+     * Returns whether or not this command is handled. A command is handled if
+     * it currently has an <code>IHandler</code> instance associated with it.
+     * A command needs a handler to carry out the {@link ICommand#execute(Map)}
+     * method.
+     * </p>
+     * <p>
+     * Notification is sent to all registered listeners if this attribute
+     * changes.
+     * </p>
+     *
+     * @return <code>true</code>, iff this command is enabled.
+     */
+	@Deprecated
+    boolean isHandled();
+
+    /**
+     * Unregisters an instance of <code>ICommandListener</code> listening for
+     * changes to attributes of this instance.
+     *
+     * @param commandListener
+     *            the instance of <code>ICommandListener</code> to unregister.
+     *            Must not be <code>null</code>. If an attempt is made to
+     *            unregister an instance of <code>ICommandListener</code>
+     *            which is not already registered with this instance, no
+     *            operation is performed.
+     */
+	@Deprecated
+    void removeCommandListener(ICommandListener commandListener);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/ICommandImageService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/ICommandImageService.java
new file mode 100644
index 0000000..f06e1d8
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/ICommandImageService.java
@@ -0,0 +1,133 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.commands;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.internal.commands.CommandImageManager;
+import org.eclipse.ui.services.IDisposable;
+
+/**
+ * <p>
+ * Provides a look-up facility for images associated with commands.
+ * </p>
+ * <p>
+ * The <em>type</em> of an image indicates the state of the associated command
+ * within the user interface. The supported types are: <code>TYPE_DEFAULT</code>
+ * (to be used for an enabled command), <code>TYPE_DISABLED</code> (to be used
+ * for a disabled command) and <code>TYPE_HOVER</code> (to be used for an
+ * enabled command over which the mouse is hovering).
+ * </p>
+ * <p>
+ * The <em>style</em> of an image is an arbitrary string used to distinguish
+ * between sets of images associated with a command. For example, a command may
+ * appear in the menus as the default style. However, in the toolbar, the
+ * command is simply the default action for a toolbar drop down item. As such,
+ * perhaps a different image style is appropriate. The classic case is the "Run
+ * Last Launched" command, which appears in the menu and the toolbar, but with
+ * different icons in each location.
+ * </p>
+ * <p>
+ * We currently support a default image style (none) and an image style of
+ * IMAGE_STYLE_TOOLBAR.
+ * </p>
+ *
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noextend This interface is not intended to be extended by clients.
+ *
+ * @since 3.4
+ */
+public interface ICommandImageService extends IDisposable {
+
+	/**
+	 * The type of image to display in the default case.
+	 */
+	public static final int TYPE_DEFAULT = CommandImageManager.TYPE_DEFAULT;
+
+	/**
+	 * The type of image to display if the corresponding command is disabled.
+	 */
+	public static final int TYPE_DISABLED = CommandImageManager.TYPE_DISABLED;
+
+	/**
+	 * The type of image to display if the mouse is hovering over the command
+	 * and the command is enabled.
+	 */
+	public static final int TYPE_HOVER = CommandImageManager.TYPE_HOVER;
+
+	/**
+	 * The default image style. This is provided when no style is requested or
+	 * when the requested style is unavailable. (Value is <b>null</b>)
+	 */
+	public static final String IMAGE_STYLE_DEFAULT = null;
+
+	/**
+	 * The image style used for commands in a toolbar. This is useful if you
+	 * want the icon for the command in the toolbar to be different than the one
+	 * that is displayed with menu items. (Value is <b>toolbar</b>)
+	 */
+	public static final String IMAGE_STYLE_TOOLBAR = "toolbar"; //$NON-NLS-1$
+
+	/**
+	 * Retrieves the default image associated with the given command in the
+	 * default style.
+	 *
+	 * @param commandId
+	 *            The identifier to find; must not be <code>null</code>.
+	 * @return An image appropriate for the given command; may be
+	 *         <code>null</code>.
+	 */
+	public ImageDescriptor getImageDescriptor(String commandId);
+
+	/**
+	 * Retrieves the image of the given type associated with the given command
+	 * in the default style.
+	 *
+	 * @param commandId
+	 *            The identifier to find; must not be <code>null</code>.
+	 *
+	 * @param type
+	 *            The type of image to retrieve. This value must be one of the
+	 *            <code>TYPE</code> constants defined in this interface.
+	 * @return An image appropriate for the given command; <code>null</code>
+	 *         if the given image type cannot be found.
+	 */
+	public ImageDescriptor getImageDescriptor(String commandId, int type);
+
+	/**
+	 * Retrieves the image of the given type associated with the given command
+	 * in the given style.
+	 *
+	 * @param commandId
+	 *            The identifier to find; must not be <code>null</code>.
+	 * @param type
+	 *            The type of image to retrieve. This value must be one of the
+	 *            <code>TYPE</code> constants defined in this interface.
+	 * @param style
+	 *            The style of the image to retrieve; may be <code>null</code>.
+	 * @return An image appropriate for the given command; <code>null</code>
+	 *         if the given image style and type cannot be found.
+	 */
+	public ImageDescriptor getImageDescriptor(String commandId, int type,
+			String style);
+
+	/**
+	 * Retrieves the default image associated with the given command in the
+	 * given style.
+	 *
+	 * @param commandId
+	 *            The identifier to find; must not be <code>null</code>.
+	 * @param style
+	 *            The style of the image to retrieve; may be <code>null</code>.
+	 * @return An image appropriate for the given command; <code>null</code>
+	 *         if the given image style cannot be found.
+	 */
+	public ImageDescriptor getImageDescriptor(String commandId, String style);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/ICommandListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/ICommandListener.java
new file mode 100644
index 0000000..c676948
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/ICommandListener.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.commands;
+
+/**
+ * An instance of this interface can be used by clients to receive notification
+ * of changes to one or more instances of <code>ICommand</code>.
+ * <p>
+ * This interface may be implemented by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @see ICommand#addCommandListener(ICommandListener)
+ * @see ICommand#removeCommandListener(ICommandListener)
+ * @see org.eclipse.core.commands.ICommandListener
+ * @deprecated Please use the "org.eclipse.core.commands" plug-in instead.
+ */
+@Deprecated
+@SuppressWarnings("all")
+public interface ICommandListener {
+
+    /**
+     * Notifies that one or more properties of an instance of <code>ICommand</code>
+     * have changed. Specific details are described in the <code>CommandEvent</code>.
+     *
+     * @param commandEvent
+     *            the command event. Guaranteed not to be <code>null</code>.
+     */
+	@Deprecated
+    void commandChanged(CommandEvent commandEvent);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/ICommandManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/ICommandManager.java
new file mode 100644
index 0000000..6b767f7
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/ICommandManager.java
@@ -0,0 +1,258 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.commands;
+
+import java.util.Map;
+import java.util.Set;
+import org.eclipse.ui.keys.KeySequence;
+
+/**
+ * <p>
+ * An instance of <code>ICommandManager</code> can be used to obtain instances
+ * of <code>ICommand</code>, as well as manage whether or not those instances
+ * are active or inactive, enabled or disabled.
+ * </p>
+ * <p>
+ * This interface is not intended to be extended or implemented by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @see org.eclipse.ui.commands.ICommand
+ * @see org.eclipse.ui.commands.ICommandManagerListener
+ * @see org.eclipse.core.commands.CommandManager
+ * @deprecated Please use the "org.eclipse.core.commands" plug-in instead.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+@Deprecated
+@SuppressWarnings("all")
+public interface ICommandManager {
+
+    /**
+     * Registers an instance of <code>ICommandManagerListener</code> to listen
+     * for changes to attributes of this instance.
+     *
+     * @param commandManagerListener
+     *            the instance of <code>ICommandManagerListener</code> to
+     *            register. Must not be <code>null</code>. If an attempt is
+     *            made to register an instance of
+     *            <code>ICommandManagerListener</code> which is already
+     *            registered with this instance, no operation is performed.
+     */
+	@Deprecated
+    void addCommandManagerListener(
+            ICommandManagerListener commandManagerListener);
+
+    /**
+     * Returns the set of identifiers to active contexts.
+     * <p>
+     * Notification is sent to all registered listeners if this property
+     * changes.
+     * </p>
+     *
+     * @return the set of identifiers to active contexts. This set may be
+     *         empty, but is guaranteed not to be <code>null</code>. If this
+     *         set is not empty, it is guaranteed to only contain instances of
+     *         <code>String</code>.
+     */
+	@Deprecated
+    Set getActiveContextIds();
+
+    /**
+     * Returns the active key configuration.
+     * <p>
+     * Notification is sent to all registered listeners if this property
+     * changes.
+     * </p>
+     *
+     * @return the active key configuration identifier. This set may be empty,
+     *         but it is guaranteed to not be <code>null</code>. If this set
+     *         is not empty, it is guaranteed to only contains instances of
+     *         <code>String</code>.
+     */
+	@Deprecated
+    String getActiveKeyConfigurationId();
+
+    /**
+     * Returns the active locale. While this property tends to be simply the
+     * result of {@link java.util.Locale#getDefault()}, it may also be changed
+     * at runtime by different implementations of command manager.
+     * <p>
+     * Notification is sent to all registered listeners if this property
+     * changes.
+     * </p>
+     *
+     * @return the active locale. May be <code>null</code>.
+     */
+	@Deprecated
+    String getActiveLocale();
+
+    /**
+     * Returns the active platform. While this property tends to be simply the
+     * result of {@link org.eclipse.swt.SWT#getPlatform()}, it may also be
+     * changed at runtime by different implementations of command manager.
+     * <p>
+     * Notification is sent to all registered listeners if this property
+     * changes.
+     * </p>
+     *
+     * @return the active platform. May be <code>null</code>.
+     */
+	@Deprecated
+    String getActivePlatform();
+
+    /**
+     * Returns a handle to a category given an identifier.
+     *
+     * @param categoryId
+     *            an identifier. Must not be <code>null</code>
+     * @return a handle to a category.
+     */
+	@Deprecated
+    ICategory getCategory(String categoryId);
+
+    /**
+     * Returns a handle to a command given an identifier.
+     *
+     * @param commandId
+     *            an identifier. Must not be <code>null</code>
+     * @return a handle to a command; never <code>null</code>.
+     */
+	@Deprecated
+    ICommand getCommand(String commandId);
+
+    /**
+     * <p>
+     * Returns the set of identifiers to defined categories.
+     * </p>
+     * <p>
+     * Notification is sent to all registered listeners if this attribute
+     * changes.
+     * </p>
+     *
+     * @return the set of identifiers to defined categories. This set may be
+     *         empty, but is guaranteed not to be <code>null</code>. If this
+     *         set is not empty, it is guaranteed to only contain instances of
+     *         <code>String</code>.
+     */
+	@Deprecated
+    Set getDefinedCategoryIds();
+
+    /**
+     * <p>
+     * Returns the set of identifiers to defined commands.
+     * </p>
+     * <p>
+     * Notification is sent to all registered listeners if this attribute
+     * changes.
+     * </p>
+     *
+     * @return the set of identifiers to defined commands. This set may be
+     *         empty, but is guaranteed not to be <code>null</code>. If this
+     *         set is not empty, it is guaranteed to only contain instances of
+     *         <code>String</code>.
+     */
+	@Deprecated
+    Set getDefinedCommandIds();
+
+    /**
+     * <p>
+     * Returns the set of identifiers to defined key configurations.
+     * </p>
+     * <p>
+     * Notification is sent to all registered listeners if this attribute
+     * changes.
+     * </p>
+     *
+     * @return the set of identifiers to defined key configurations. This set
+     *         may be empty, but is guaranteed not to be <code>null</code>.
+     *         If this set is not empty, it is guaranteed to only contain
+     *         instances of <code>String</code>.
+     */
+	@Deprecated
+    Set getDefinedKeyConfigurationIds();
+
+    /**
+     * Returns a handle to a key configuration given an identifier.
+     *
+     * @param keyConfigurationId
+     *            an identifier. Must not be <code>null</code>
+     * @return a handle to a key configuration.
+     */
+	@Deprecated
+    IKeyConfiguration getKeyConfiguration(String keyConfigurationId);
+
+    /**
+     * Finds all of the commands which have key bindings that start with the
+     * given key sequence.
+     *
+     * @param keySequence
+     *            The prefix to look for; must not be <code>null</code>.
+     * @return A map of all of the matching key sequences (
+     *         <code>KeySequence</code>) to command identifiers (
+     *         <code>String</code>). This map may be empty, but it is never
+     *         <code>null</code>.
+     */
+	@Deprecated
+    Map getPartialMatches(KeySequence keySequence);
+
+    /**
+     * Finds the command which has the given key sequence as one of its key
+     * bindings.
+     *
+     * @param keySequence
+     *            The key binding to look for; must not be <code>null</code>.
+     * @return The command id for the matching command, if any;
+     *         <code>null</code> if none.
+     */
+	@Deprecated
+    String getPerfectMatch(KeySequence keySequence);
+
+    /**
+     * Checks to see whether there are any commands which have key bindings that
+     * start with the given key sequence.
+     *
+     * @param keySequence
+     *            The prefix to look for; must not be <code>null</code>.
+     * @return <code>true</code> if at least one command has a key binding
+     *         that starts with <code>keySequence</code>;<code>false</code>
+     *         otherwise.
+     */
+	@Deprecated
+    boolean isPartialMatch(KeySequence keySequence);
+
+    /**
+     * Checks to see if there is a command with the given key sequence as one of
+     * its key bindings.
+     *
+     * @param keySequence
+     *            The key binding to look for; must not be <code>null</code>.
+     * @return <code>true</code> if a command has a matching key binding;
+     *         <code>false</code> otherwise.
+     */
+	@Deprecated
+    boolean isPerfectMatch(KeySequence keySequence);
+
+    /**
+     * Unregisters an instance of <code>ICommandManagerListener</code>
+     * listening for changes to attributes of this instance.
+     *
+     * @param commandManagerListener
+     *            the instance of <code>ICommandManagerListener</code> to
+     *            unregister. Must not be <code>null</code>. If an attempt is
+     *            made to unregister an instance of
+     *            <code>ICommandManagerListener</code> which is not already
+     *            registered with this instance, no operation is performed.
+     */
+	@Deprecated
+    void removeCommandManagerListener(
+            ICommandManagerListener commandManagerListener);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/ICommandManagerListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/ICommandManagerListener.java
new file mode 100644
index 0000000..22af48b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/ICommandManagerListener.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.commands;
+
+/**
+ * An instance of this interface can be used by clients to receive notification
+ * of changes to one or more instances of <code>ICommandManager</code>.
+ * <p>
+ * This interface may be implemented by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @see ICommandManager#addCommandManagerListener(ICommandManagerListener)
+ * @see ICommandManager#removeCommandManagerListener(ICommandManagerListener)
+ * @deprecated Please use the "org.eclipse.core.commands" plug-in instead.
+ * @see org.eclipse.core.commands.ICommandManagerListener
+ */
+@Deprecated
+@SuppressWarnings("all")
+public interface ICommandManagerListener {
+
+    /**
+     * Notifies that one or more properties of an instance of
+     * <code>ICommandManager</code> have changed. Specific details are
+     * described in the <code>CommandManagerEvent</code>.
+     *
+     * @param commandManagerEvent
+     *            the commandManager event. Guaranteed not to be
+     *            <code>null</code>.
+     */
+	@Deprecated
+    void commandManagerChanged(CommandManagerEvent commandManagerEvent);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/ICommandService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/ICommandService.java
new file mode 100644
index 0000000..e6bed82
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/ICommandService.java
@@ -0,0 +1,378 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.commands;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.eclipse.core.commands.Category;
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.CommandManager;
+import org.eclipse.core.commands.IExecutionListener;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.core.commands.ParameterType;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.commands.SerializationException;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.ui.menus.UIElement;
+import org.eclipse.ui.services.IDisposable;
+
+/**
+ * <p>
+ * Provides services related to the command architecture within the workbench.
+ * This service can be used to access the set of commands and command
+ * categories.
+ * </p>
+ * <p>
+ * This service can be acquired from your service locator:
+ * <pre>
+ * 	ICommandService service = (ICommandService) getSite().getService(ICommandService.class);
+ * </pre>
+ * <ul>
+ * <li>This service is available globally.</li>
+ * </ul>
+ * </p>
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noextend This interface is not intended to be extended by clients.
+ *
+ * @since 3.1
+ */
+public interface ICommandService extends IDisposable {
+
+	/**
+	 * The identifier of the category in which all auto-generated commands will
+	 * appear. This value must never be <code>null</code>.
+	 *
+	 * @since 3.2
+	 */
+	public static final String AUTOGENERATED_CATEGORY_ID = CommandManager.AUTOGENERATED_CATEGORY_ID;
+
+	/**
+	 * Adds an execution listener to the command service. This listener will be
+	 * notified as commands are executed.
+	 * <p>
+	 * <b>Note:</b> listeners should be removed when no longer necessary. If
+	 * not, they will be removed when the IServiceLocator used to acquire this
+	 * service is disposed.
+	 * </p>
+	 *
+	 * @param listener
+	 *            The listener to add; must not be <code>null</code>.
+	 * @see #removeExecutionListener(IExecutionListener)
+	 */
+	public void addExecutionListener(IExecutionListener listener);
+
+	/**
+	 * Sets the name and description of the category for uncategorized commands.
+	 * This is the category that will be returned if
+	 * {@link #getCategory(String)} is called with <code>null</code>.
+	 *
+	 * @param name
+	 *            The name of the category for uncategorized commands; must not
+	 *            be <code>null</code>.
+	 * @param description
+	 *            The description of the category for uncategorized commands;
+	 *            may be <code>null</code>.
+	 * @since 3.2
+	 */
+	public void defineUncategorizedCategory(String name, String description);
+
+	/**
+	 * <p>
+	 * Returns a {@link ParameterizedCommand} with a command and
+	 * parameterizations as specified in the provided
+	 * <code>serializedParameterizedCommand</code> string. The
+	 * <code>serializedParameterizedCommand</code> must use the format
+	 * returned by {@link ParameterizedCommand#serialize()} and described in the
+	 * Javadoc for that method.
+	 * </p>
+	 * <p>
+	 * If a parameter id encoded in the
+	 * <code>serializedParameterizedCommand</code> does not exist in the
+	 * encoded command, that parameter id and value are ignored. A given
+	 * parameter id should not be used more than once in
+	 * <code>serializedParameterizedCommand</code>. This will not result in
+	 * an exception, but the value of the parameter when the command is executed
+	 * cannot be specified here.
+	 * </p>
+	 * <p>
+	 * This method will never return <code>null</code>, however it may throw
+	 * an exception if there is a problem processing the serialization string or
+	 * the encoded command is undefined.
+	 * </p>
+	 *
+	 * @param serializedParameterizedCommand
+	 *            a <code>String</code> representing a command id and
+	 *            parameter ids and values
+	 * @return a <code>ParameterizedCommand</code> with the command and
+	 *         parameterizations encoded in the
+	 *         <code>serializedParameterizedCommand</code>
+	 * @throws NotDefinedException
+	 *             if the command indicated in
+	 *             <code>serializedParameterizedCommand</code> is not defined
+	 * @throws SerializationException
+	 *             if there is an error deserializing
+	 *             <code>serializedParameterizedCommand</code>
+	 * @see ParameterizedCommand#serialize()
+	 * @see CommandManager#deserialize(String)
+	 * @since 3.2
+	 */
+	public ParameterizedCommand deserialize(
+			String serializedParameterizedCommand) throws NotDefinedException,
+			SerializationException;
+
+	/**
+	 * Retrieves the category with the given identifier. If no such category
+	 * exists, then an undefined category with the given id is created.
+	 *
+	 * @param categoryId
+	 *            The identifier to find. If the category is <code>null</code>,
+	 *            then a category suitable for uncategorized items is defined
+	 *            and returned.
+	 * @return A category with the given identifier, either defined or
+	 *         undefined.
+	 */
+	public Category getCategory(String categoryId);
+
+	/**
+	 * Retrieves the command with the given identifier. If no such command
+	 * exists, then an undefined command with the given id is created.
+	 *
+	 * @param commandId
+	 *            The identifier to find; must not be <code>null</code>.
+	 * @return A command with the given identifier, either defined or undefined.
+	 */
+	public Command getCommand(String commandId);
+
+	/**
+	 * Returns the collection of all of the defined categories in the workbench.
+	 *
+	 * @return The collection of categories (<code>Category</code>) that are
+	 *         defined; never <code>null</code>, but may be empty.
+	 * @since 3.2
+	 */
+	public Category[] getDefinedCategories();
+
+	/**
+	 * Returns the collection of the identifiers for all of the defined
+	 * categories in the workbench.
+	 *
+	 * @return The collection of category identifiers (<code>String</code>)
+	 *         that are defined; never <code>null</code>, but may be empty.
+	 */
+	public Collection getDefinedCategoryIds();
+
+	/**
+	 * Returns the collection of the identifiers for all of the defined commands
+	 * in the workbench.
+	 *
+	 * @return The collection of command identifiers (<code>String</code>)
+	 *         that are defined; never <code>null</code>, but may be empty.
+	 */
+	public Collection getDefinedCommandIds();
+
+	/**
+	 * Returns the collection of all of the defined commands in the workbench.
+	 *
+	 * @return The collection of commands (<code>Command</code>) that are
+	 *         defined; never <code>null</code>, but may be empty.
+	 * @since 3.2
+	 */
+	public Command[] getDefinedCommands();
+
+	/**
+	 * Returns the collection of the identifiers for all of the defined command
+	 * parameter types in the workbench.
+	 *
+	 * @return The collection of command parameter type identifiers (<code>String</code>)
+	 *         that are defined; never <code>null</code>, but may be empty.
+	 * @since 3.2
+	 */
+	public Collection getDefinedParameterTypeIds();
+
+	/**
+	 * Returns the collection of all of the defined command parameter types in
+	 * the workbench.
+	 *
+	 * @return The collection of command parameter types (<code>ParameterType</code>)
+	 *         that are defined; never <code>null</code>, but may be empty.
+	 * @since 3.2
+	 */
+	public ParameterType[] getDefinedParameterTypes();
+
+	/**
+	 * Gets the help context identifier for a particular command. The command's
+	 * handler is first checked for a help context identifier. If the handler
+	 * does not have a help context identifier, then the help context identifier
+	 * for the command is returned. If neither has a help context identifier,
+	 * then <code>null</code> is returned.
+	 *
+	 * @param command
+	 *            The command for which the help context should be retrieved;
+	 *            must not be <code>null</code>.
+	 * @return The help context identifier to use for the given command; may be
+	 *         <code>null</code>.
+	 * @throws NotDefinedException
+	 *             If the given command is not defined.
+	 * @since 3.2
+	 */
+	public String getHelpContextId(Command command) throws NotDefinedException;
+
+	/**
+	 * Gets the help context identifier for a particular command. The command's
+	 * handler is first checked for a help context identifier. If the handler
+	 * does not have a help context identifier, then the help context identifier
+	 * for the command is returned. If neither has a help context identifier,
+	 * then <code>null</code> is returned.
+	 *
+	 * @param commandId
+	 *            The identifier of the command for which the help context
+	 *            should be retrieved; must not be <code>null</code>.
+	 * @return The help context identifier to use for the given command; may be
+	 *         <code>null</code>.
+	 * @throws NotDefinedException
+	 *             If the command with the given identifier is not defined.
+	 * @since 3.2
+	 */
+	public String getHelpContextId(String commandId) throws NotDefinedException;
+
+	/**
+	 * Retrieves the command parameter type with the given identifier. If no
+	 * such parameter type exists, then an undefined parameter type with the
+	 * given id is created.
+	 *
+	 * @param parameterTypeId
+	 *            The identifier to find; must not be <code>null</code>.
+	 * @return A command parameter type with the given identifier, either
+	 *         defined or undefined.
+	 * @since 3.2
+	 */
+	public ParameterType getParameterType(String parameterTypeId);
+
+	/**
+	 * <p>
+	 * Reads the command information from the registry and the preferences. This
+	 * will overwrite any of the existing information in the command service.
+	 * This method is intended to be called during start-up. When this method
+	 * completes, this command service will reflect the current state of the
+	 * registry and preference store.
+	 * </p>
+	 */
+	public void readRegistry();
+
+	/**
+	 * Removes an execution listener from the command service.
+	 *
+	 * @param listener
+	 *            The listener to remove; must not be <code>null</code>.
+	 */
+	public void removeExecutionListener(IExecutionListener listener);
+
+	/**
+	 * Sets the help context identifier to associate with a particular handler.
+	 *
+	 * @param handler
+	 *            The handler with which to register a help context identifier;
+	 *            must not be <code>null</code>.
+	 * @param helpContextId
+	 *            The help context identifier to register; may be
+	 *            <code>null</code> if the help context identifier should be
+	 *            removed.
+	 * @since 3.2
+	 */
+	public void setHelpContextId(IHandler handler, String helpContextId);
+
+	/**
+	 * Register that this element accepts callbacks for this parameterized
+	 * command.
+	 * <p>
+	 * <b>Note:</b> elements should be removed when no longer necessary. If
+	 * not, they will be removed when the IServiceLocator used to acquire this
+	 * service is disposed.
+	 * </p>
+	 *
+	 * @param command
+	 *            The parameterized command that is already specialized. Must
+	 *            not be <code>null</code>.
+	 * @param element
+	 *            The callback to register for this specialized command
+	 *            instance. Must not be <code>null</code>.
+	 * @return A reference for the registered element that can be used to
+	 *         unregister it.
+	 * @throws NotDefinedException
+	 *             If the command included in the ParameterizedCommand is not
+	 *             defined, or the element is <code>null</code>.
+	 * @since 3.3
+	 * @see #unregisterElement(IElementReference)
+	 */
+	public IElementReference registerElementForCommand(
+			ParameterizedCommand command, UIElement element)
+			throws NotDefinedException;
+
+	/**
+	 * Re-register a callback element provided by the ICommandService. This
+	 * element reference must not currently be held by the ICommandService. i.e.
+	 * it must have been removed using
+	 * {@link #unregisterElement(IElementReference)}.
+	 * <p>
+	 * <b>Note:</b> elements should be removed when no longer necessary. If
+	 * not, they will be removed when the IServiceLocator used to acquire this
+	 * service is disposed.
+	 * </p>
+	 *
+	 * @param elementReference
+	 *            The reference to re-register. Must not be <code>null</code>.
+	 * @since 3.3
+	 * @see #unregisterElement(IElementReference)
+	 */
+	public void registerElement(IElementReference elementReference);
+
+	/**
+	 * Unregister an element callback. It will be removed from the
+	 * ICommandService. The same service that is used to register an element for
+	 * a command <b>must</b> be used to unregister the element.
+	 *
+	 * @param elementReference
+	 *            The callback reference that was provided by the command
+	 *            service on registration. Must not be <code>null</code>.
+	 * @since 3.3
+	 */
+	public void unregisterElement(IElementReference elementReference);
+
+	/**
+	 * Refresh any elements registered against the command with the given id.
+	 * It allows the active handler the opportunity to provide user feedback. If
+	 * the command is parameterized, some of the parameters can be specified to
+	 * help narrow down which elements to refresh.
+	 * <p>
+	 * The service locator used in registering the element can also be used to
+	 * scope the search. For example: if you wanted all elements for your
+	 * command but only within the part's workbench window, you could use:
+	 *
+	 * <pre>
+	 * Map filter = new HashMap();
+	 * filter.put(IServiceScopes.WINDOW_SCOPE, getSite().getPage()
+	 * 		.getWorkbenchWindow());
+	 * commandService.refreshElements(commandId, filter);
+	 * </pre>
+	 *
+	 * </p>
+	 *
+	 * @param commandId
+	 *            The command id to refresh if it has registered eleemnts.
+	 * @param filter
+	 *            key-value pairs that can narrow down the callbacks to return.
+	 *            The parameters are <b>AND</b>ed together. This may be
+	 *            <code>null</code>.
+	 * @since 3.3
+	 */
+	public void refreshElements(String commandId, Map filter);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/IElementReference.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/IElementReference.java
new file mode 100644
index 0000000..db6c6ed
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/IElementReference.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.commands;
+
+import java.util.Map;
+
+import org.eclipse.ui.menus.UIElement;
+
+/**
+ * the ICommandService will return a reference for all callbacks that are
+ * registered. This reference can be used to unregister the specific callback.
+ * <p>
+ * Similar in functionality to an IHandlerActivation.  This interface should
+ * not be implemented or extended by clients.
+ * </p>
+ *
+ * @since 3.3
+ */
+public interface IElementReference {
+	/**
+	 * The command id that this callback was registered against.
+	 *
+	 * @return The command id. Will not be <code>null</code>.
+	 */
+	public String getCommandId();
+
+	/**
+	 * The callback that was registered.
+	 *
+	 * @return Adapts to provide appropriate user feedback. Will not be
+	 *         <code>null</code>.
+	 */
+	public UIElement getElement();
+
+	/**
+	 * Parameters that help scope this callback registration. For example, it
+	 * can include parameters from the ParameterizedCommand. Callers should not
+	 * change the map that is returned.
+	 *
+	 * @return scoping parameters. Will not be <code>null</code>.
+	 */
+	public Map getParameters();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/IElementUpdater.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/IElementUpdater.java
new file mode 100644
index 0000000..1da8cb9
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/IElementUpdater.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.commands;
+
+import java.util.Map;
+
+import org.eclipse.ui.menus.UIElement;
+
+/**
+ * An IHandler for a command that expects to provide feedback through the
+ * registered element mechanism must implement this interface.
+ *
+ * @since 3.3
+ *
+ */
+public interface IElementUpdater {
+	/**
+	 * Whenever the elements for a command are refreshed, this method is called
+	 * on the active handler for that command.
+	 * <p>
+	 * <b>Note:</b> Handlers must never cache the element, which can disappear
+	 * or be replaced at any time. Everybody should go through the
+	 * ICommandService refreshElements(*) method.
+	 * </p>
+	 *
+	 * @param element
+	 *            An element for a specific UI element. Will not be
+	 *            <code>null</code>.
+	 * @param parameters
+	 *            Any parameters registered with the callback. Will not be
+	 *            <code>null</code>, but it may be empty.
+	 */
+	public void updateElement(UIElement element, Map parameters);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/IHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/IHandler.java
new file mode 100644
index 0000000..fff5bfe
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/IHandler.java
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.commands;
+
+import java.util.Map;
+
+/**
+ * A handler is the pluggable piece of a command that handles execution. Each
+ * command can have zero or more handlers associated with it (in general), of
+ * which only one will be active at any given moment in time. When the command
+ * is asked to execute, it will simply pass that request on to its active
+ * handler, if any.
+ * <p>
+ * This interface is not intended to be extended by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @deprecated Please use the "org.eclipse.core.commands" plug-in instead.
+ * @see org.eclipse.core.commands.IHandler
+ */
+@Deprecated
+@SuppressWarnings("all")
+public interface IHandler {
+
+    /**
+     * Registers an instance of <code>IHandlerListener</code> to listen for
+     * changes to properties of this instance.
+     *
+     * @param handlerListener
+     *            the instance to register. Must not be <code>null</code>. If
+     *            an attempt is made to register an instance which is already
+     *            registered with this instance, no operation is performed.
+     */
+	@Deprecated
+    void addHandlerListener(IHandlerListener handlerListener);
+
+    /**
+     * Disposes of this handler. This method is run once when the object is no
+     * longer referenced. This can be used as an opportunity to unhook listeners
+     * from other objects.
+     */
+	@Deprecated
+    public void dispose();
+
+    /**
+     * Executes with the map of parameter values by name.
+     *
+     * @param parameterValuesByName
+     *            the map of parameter values by name. Reserved for future use,
+     *            must be <code>null</code>.
+     * @return the result of the execution. Reserved for future use, must be
+     *         <code>null</code>.
+     * @throws ExecutionException
+     *             if an exception occurred during execution.
+     */
+	@Deprecated
+    Object execute(Map parameterValuesByName) throws ExecutionException;
+
+    /**
+     * Returns the map of attribute values by name.
+     * <p>
+     * Notification is sent to all registered listeners if this property
+     * changes.
+     * </p>
+     *
+     * @return the map of attribute values by name. This map may be empty, but
+     *         is guaranteed not to be <code>null</code>. If this map is not
+     *         empty, its collection of keys is guaranteed to only contain
+     *         instances of <code>String</code>.
+     */
+	@Deprecated
+    Map getAttributeValuesByName();
+
+    /**
+     * Unregisters an instance of <code>IPropertyListener</code> listening for
+     * changes to properties of this instance.
+     *
+     * @param handlerListener
+     *            the instance to unregister. Must not be <code>null</code>.
+     *            If an attempt is made to unregister an instance which is not
+     *            already registered with this instance, no operation is
+     *            performed.
+     */
+	@Deprecated
+    void removeHandlerListener(IHandlerListener handlerListener);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/IHandlerListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/IHandlerListener.java
new file mode 100644
index 0000000..ea7f027
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/IHandlerListener.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.commands;
+
+/**
+ * An instance of this interface can be used by clients to receive notification
+ * of changes to one or more instances of <code>IHandler</code>.
+ * <p>
+ * This interface may be implemented by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @see IHandler#addHandlerListener(IHandlerListener)
+ * @see IHandler#removeHandlerListener(IHandlerListener)
+ * @deprecated Please use the "org.eclipse.core.commands" plug-in instead.
+ * @see org.eclipse.core.commands.IHandlerListener
+ */
+@Deprecated
+@SuppressWarnings("all")
+public interface IHandlerListener {
+
+    /**
+     * Notifies that one or more properties of an instance of
+     * <code>IHandler</code> have changed. Specific details are described in
+     * the <code>HandlerEvent</code>.
+     *
+     * @param handlerEvent
+     *            the handler event. Guaranteed not to be <code>null</code>.
+     */
+	@Deprecated
+    void handlerChanged(HandlerEvent handlerEvent);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/IKeyConfiguration.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/IKeyConfiguration.java
new file mode 100644
index 0000000..db6613c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/IKeyConfiguration.java
@@ -0,0 +1,177 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.commands;
+
+/**
+ * <p>
+ * An instance of <code>IKeyConfiguration</code> is a handle representing a
+ * key configuration as defined by the extension point
+ * <code>org.eclipse.ui.commands</code>. The identifier of the handle is
+ * identifier of the key configuration being represented.
+ * </p>
+ * <p>
+ * An instance of <code>IKeyConfiguration</code> can be obtained from an
+ * instance of <code>ICommandManager</code> for any identifier, whether or not
+ * a key configuration with that identifier defined in the plugin registry.
+ * </p>
+ * <p>
+ * The handle-based nature of this API allows it to work well with runtime
+ * plugin activation and deactivation. If a key configuration is defined, that
+ * means that its corresponding plug-in is active. If the plug-in is then
+ * deactivated, the configuration will still exist but it will be undefined.
+ * An attempt to use an undefined key configuration will result in a
+ * <code>NotDefinedException</code> being thrown.
+ * </p>
+ * <p>
+ * This interface is not intended to be extended or implemented by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @see IKeyConfigurationListener
+ * @see ICommandManager
+ * @see org.eclipse.jface.bindings.Scheme
+ * @deprecated Please use the bindings support in the "org.eclipse.jface"
+ * plug-in instead.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+@Deprecated
+@SuppressWarnings("all")
+public interface IKeyConfiguration extends Comparable {
+
+    /**
+     * Registers an instance of <code>IKeyConfigurationListener</code> to
+     * listen for changes to attributes of this instance.
+     *
+     * @param keyConfigurationListener
+     *            the instance of <code>IKeyConfigurationListener</code> to
+     *            register. Must not be <code>null</code>. If an attempt is
+     *            made to register an instance of <code>IKeyConfigurationListener</code>
+     *            which is already registered with this instance, no operation
+     *            is performed.
+     */
+	@Deprecated
+    void addKeyConfigurationListener(
+            IKeyConfigurationListener keyConfigurationListener);
+
+    /**
+     * <p>
+     * Returns the description of the key configuration represented by this
+     * handle, suitable for display to the user.
+     * </p>
+     * <p>
+     * Notification is sent to all registered listeners if this attribute
+     * changes.
+     * </p>
+     *
+     * @return the description of the key configuration represented by this
+     *         handle. Guaranteed not to be <code>null</code>.
+     * @throws NotDefinedException
+     *             if the key configuration represented by this handle is not
+     *             defined.
+     */
+	@Deprecated
+    String getDescription() throws NotDefinedException;
+
+    /**
+     * Returns the identifier of this handle.
+     *
+     * @return the identifier of this handle. Guaranteed not to be
+     *         <code>null</code>.
+     */
+	@Deprecated
+    String getId();
+
+    /**
+     * <p>
+     * Returns the name of the key configuration represented by this handle,
+     * suitable for display to the user.
+     * </p>
+     * <p>
+     * Notification is sent to all registered listeners if this attribute
+     * changes.
+     * </p>
+     *
+     * @return the name of the key configuration represented by this handle.
+     *         Guaranteed not to be <code>null</code>.
+     * @throws NotDefinedException
+     *             if the key configuration represented by this handle is not
+     *             defined.
+     */
+	@Deprecated
+    String getName() throws NotDefinedException;
+
+    /**
+     * <p>
+     * Returns the identifier of the parent of the key configuration
+     * represented by this handle.
+     * </p>
+     * <p>
+     * Notification is sent to all registered listeners if this attribute
+     * changes.
+     * </p>
+     *
+     * @return the identifier of the parent of the key configuration
+     *         represented by this handle. May be <code>null</code>.
+     * @throws NotDefinedException
+     *             if the key configuration represented by this handle is not
+     *             defined.
+     */
+	@Deprecated
+    String getParentId() throws NotDefinedException;
+
+    /**
+     * <p>
+     * Returns whether or not this command is active. Instances of
+     * <code>ICommand</code> are activated and deactivated by the instance of
+     * <code>ICommandManager</code> from whence they were brokered.
+     * </p>
+     * <p>
+     * Notification is sent to all registered listeners if this attribute
+     * changes.
+     * </p>
+     *
+     * @return <code>true</code>, iff this command is active.
+     */
+	@Deprecated
+    boolean isActive();
+
+    /**
+     * <p>
+     * Returns whether or not the key configuration represented by this handle
+     * is defined.
+     * </p>
+     * <p>
+     * Notification is sent to all registered listeners if this attribute
+     * changes.
+     * </p>
+     *
+     * @return <code>true</code>, iff the key configuration represented by
+     *         this handle is defined.
+     */
+	@Deprecated
+    boolean isDefined();
+
+    /**
+     * Unregisters an instance of <code>IKeyConfigurationListener</code>
+     * listening for changes to attributes of this instance.
+     *
+     * @param keyConfigurationListener
+     *            the instance of <code>IKeyConfigurationListener</code> to
+     *            unregister. Must not be <code>null</code>. If an attempt is
+     *            made to unregister an instance of
+     *            <code>IKeyConfigurationListener</code> which is not already
+     *            registered with this instance, no operation is performed.
+     */
+	@Deprecated
+    void removeKeyConfigurationListener(
+            IKeyConfigurationListener keyConfigurationListener);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/IKeyConfigurationListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/IKeyConfigurationListener.java
new file mode 100644
index 0000000..9fb0b32
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/IKeyConfigurationListener.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.commands;
+
+/**
+ * <p>
+ * An instance of <code>IKeyConfigurationListener</code> can be used by
+ * clients to receive notification of changes to one or more instances of
+ * <code>IKeyConfiguration</code>.
+ * </p>
+ * <p>
+ * This interface may be implemented by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @see IKeyConfiguration#addKeyConfigurationListener(IKeyConfigurationListener)
+ * @see IKeyConfiguration#removeKeyConfigurationListener(IKeyConfigurationListener)
+ * @see org.eclipse.ui.commands.KeyConfigurationEvent
+ * @deprecated Please use the bindings support in the "org.eclipse.jface"
+ * plug-in instead.
+ * @see org.eclipse.jface.bindings.ISchemeListener
+ */
+@Deprecated
+@SuppressWarnings("all")
+public interface IKeyConfigurationListener {
+
+    /**
+     * Notifies that one or more attributes of an instance of <code>IKeyConfiguration</code>
+     * have changed. Specific details are described in the <code>KeyConfigurationEvent</code>.
+     *
+     * @param keyConfigurationEvent
+     *            the keyConfiguration event. Guaranteed not to be <code>null</code>.
+     */
+	@Deprecated
+    void keyConfigurationChanged(KeyConfigurationEvent keyConfigurationEvent);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/IKeySequenceBinding.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/IKeySequenceBinding.java
new file mode 100644
index 0000000..e1437d2
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/IKeySequenceBinding.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.commands;
+
+import org.eclipse.ui.keys.KeySequence;
+
+/**
+ * <p>
+ * An instance of <code>IKeySequenceBinding</code> represents a binding
+ * between a command and a key sequence. This is a wrapper for the a key
+ * sequence.
+ * </p>
+ * <p>
+ * This interface is not intended to be extended or implemented by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @see org.eclipse.ui.commands.ICommand
+ * @deprecated Please use the bindings support in the "org.eclipse.jface"
+ * plug-in instead.
+ * @see org.eclipse.jface.bindings.keys.KeyBinding
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+@Deprecated
+@SuppressWarnings("all")
+public interface IKeySequenceBinding extends Comparable {
+
+    /**
+     * Returns the key sequence represented in this binding.
+     *
+     * @return the key sequence. Guaranteed not to be <code>null</code>.
+     */
+	@Deprecated
+    KeySequence getKeySequence();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/IWorkbenchCommandSupport.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/IWorkbenchCommandSupport.java
new file mode 100644
index 0000000..8ca1d31
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/IWorkbenchCommandSupport.java
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.commands;
+
+import java.util.Collection;
+
+/**
+ * An instance of this interface provides support for managing commands at the
+ * <code>IWorkbench</code> level.
+ * <p>
+ * This interface is not intended to be extended or implemented by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @deprecated Please use <code>ICommandService</code> and
+ *             <code>IHandlerService</code> instead.
+ * @see org.eclipse.ui.commands.ICommandService
+ * @see org.eclipse.ui.handlers.IHandlerService
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+@Deprecated
+@SuppressWarnings("all")
+public interface IWorkbenchCommandSupport {
+
+	/**
+	 * Adds a single handler submissions for consideration by the workbench. The
+	 * submission indicates to the workbench a set of conditions under which the
+	 * handler should become active. The workbench, however, ultimately decides
+	 * which handler becomes active (in the event of conflicts or changes in
+	 * state). This could cause the handlers for one or more commands to change.
+	 *
+	 * @param handlerSubmission
+	 *            The submission to be added; must not be <code>null</code>.
+	 */
+	@Deprecated
+	void addHandlerSubmission(HandlerSubmission handlerSubmission);
+
+	/**
+	 * Adds a collection of handler submissions for consideration by the
+	 * workbench. The submission indicates to the workbench a set of conditions
+	 * under which the handler should become active. The workbench, however,
+	 * ultimately decides which handler becomes active (in the event of
+	 * conflicts or changes in state). This could cause the handlers for one or
+	 * more commands to change.
+	 *
+	 * @param handlerSubmissions
+	 *            The submissions to be added; must not be <code>null</code>,
+	 *            and must contain zero or more instances of
+	 *            <code>HandlerSubmission</code>.
+	 */
+	@Deprecated
+	void addHandlerSubmissions(Collection handlerSubmissions);
+
+	/**
+	 * Returns the command manager for the workbench.
+	 *
+	 * @return the command manager for the workbench. Guaranteed not to be
+	 *         <code>null</code>.
+	 */
+	@Deprecated
+	ICommandManager getCommandManager();
+
+	/**
+	 * Removes a single handler submission from consideration by the workbench.
+	 * The handler submission must be the same as the one added (not just
+	 * equivalent). This could cause the handlers for one or more commands to
+	 * change.
+	 *
+	 * @param handlerSubmission
+	 *            The submission to be removed; must not be <code>null</code>.
+	 */
+	@Deprecated
+	void removeHandlerSubmission(HandlerSubmission handlerSubmission);
+
+	/**
+	 * Removes a single handler submission from consideration by the workbench.
+	 * The handler submission must be the same as the one added (not just
+	 * equivalent). This could cause the handlers for one or more commands to
+	 * change.
+	 *
+	 * @param handlerSubmissions
+	 *            The submissions to be removed; must not be <code>null</code>,
+	 *            and must contain instances of <code>HandlerSubmission</code>
+	 *            only.
+	 */
+	@Deprecated
+	void removeHandlerSubmissions(Collection handlerSubmissions);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/KeyConfigurationEvent.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/KeyConfigurationEvent.java
new file mode 100644
index 0000000..bef3b30
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/KeyConfigurationEvent.java
@@ -0,0 +1,136 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.commands;
+
+/**
+ * An instance of this class describes changes to an instance of
+ * <code>IKeyConfiguration</code>.
+ * <p>
+ * This class is not intended to be extended by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @see IKeyConfigurationListener#keyConfigurationChanged(KeyConfigurationEvent)
+ * @deprecated Please use the bindings support in the "org.eclipse.jface"
+ * plug-in instead.
+ * @see org.eclipse.jface.bindings.SchemeEvent
+ */
+@Deprecated
+@SuppressWarnings("all")
+public final class KeyConfigurationEvent {
+
+    /**
+     * whether the key configuration has become or active or inactive.
+     */
+    private final boolean activeChanged;
+
+    /**
+     * Whether the key configuration has become defined or undefined.
+     */
+    private final boolean definedChanged;
+
+    /**
+     * The key configuration that has changed; this value is never
+     * <code>null</code>.
+     */
+    private final IKeyConfiguration keyConfiguration;
+
+    /**
+     * Whether the name of the key configuration has changed.
+     */
+    private final boolean nameChanged;
+
+    /**
+     * Whether the parent identifier has changed.
+     */
+    private final boolean parentIdChanged;
+
+    /**
+     * Creates a new instance of this class.
+     *
+     * @param keyConfiguration
+     *            the instance of the interface that changed.
+     * @param activeChanged
+     *            true, iff the active property changed.
+     * @param definedChanged
+     *            true, iff the defined property changed.
+     * @param nameChanged
+     *            true, iff the name property changed.
+     * @param parentIdChanged
+     *            true, iff the parentId property changed.
+     */
+	@Deprecated
+    public KeyConfigurationEvent(IKeyConfiguration keyConfiguration,
+            boolean activeChanged, boolean definedChanged, boolean nameChanged,
+            boolean parentIdChanged) {
+        if (keyConfiguration == null) {
+			throw new NullPointerException();
+		}
+
+        this.keyConfiguration = keyConfiguration;
+        this.activeChanged = activeChanged;
+        this.definedChanged = definedChanged;
+        this.nameChanged = nameChanged;
+        this.parentIdChanged = parentIdChanged;
+    }
+
+    /**
+     * Returns the instance of the interface that changed.
+     *
+     * @return the instance of the interface that changed. Guaranteed not to be
+     *         <code>null</code>.
+     */
+	@Deprecated
+    public IKeyConfiguration getKeyConfiguration() {
+        return keyConfiguration;
+    }
+
+    /**
+     * Returns whether or not the active property changed.
+     *
+     * @return true, iff the active property changed.
+     */
+	@Deprecated
+    public boolean hasActiveChanged() {
+        return activeChanged;
+    }
+
+    /**
+     * Returns whether or not the defined property changed.
+     *
+     * @return true, iff the defined property changed.
+     */
+	@Deprecated
+    public boolean hasDefinedChanged() {
+        return definedChanged;
+    }
+
+    /**
+     * Returns whether or not the name property changed.
+     *
+     * @return true, iff the name property changed.
+     */
+	@Deprecated
+    public boolean hasNameChanged() {
+        return nameChanged;
+    }
+
+    /**
+     * Returns whether or not the parentId property changed.
+     *
+     * @return true, iff the parentId property changed.
+     */
+	@Deprecated
+    public boolean hasParentIdChanged() {
+        return parentIdChanged;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/NotDefinedException.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/NotDefinedException.java
new file mode 100644
index 0000000..ab238c1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/NotDefinedException.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.commands;
+
+/**
+ * Signals that an attempt was made to access the properties of an undefined
+ * object.
+ * <p>
+ * This class is not intended to be extended by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @deprecated Please use the "org.eclipse.core.commands" plug-in instead.
+ * @see org.eclipse.core.commands.common.NotDefinedException
+ */
+@Deprecated
+@SuppressWarnings("all")
+public final class NotDefinedException extends CommandException {
+
+    /**
+     * Generated serial version UID for this class.
+     *
+     * @since 3.1
+     */
+    private static final long serialVersionUID = 3257572788998124596L;
+
+    /**
+     * Creates a new instance of this class with the specified detail message.
+     *
+     * @param s
+     *            the detail message.
+     */
+	@Deprecated
+    public NotDefinedException(String s) {
+        super(s);
+    }
+
+    /**
+     * Constructs a legacy <code>NotDefinedException</code> based on the new
+     * <code>NotDefinedException</code>.
+     *
+     * @param e
+     *            The exception from which this exception should be created;
+     *            must not be <code>null</code>.
+     * @since 3.1
+     */
+	@Deprecated
+    public NotDefinedException(
+            final org.eclipse.core.commands.common.NotDefinedException e) {
+        super(e.getMessage(), e);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/NotHandledException.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/NotHandledException.java
new file mode 100644
index 0000000..db4c21a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/NotHandledException.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.commands;
+
+/**
+ * Signals that an attempt was made to access the properties of an unhandled
+ * object.
+ * <p>
+ * This class is not intended to be extended by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @deprecated Please use the "org.eclipse.core.commands" plug-in instead.
+ * @see org.eclipse.core.commands.NotHandledException
+ */
+@Deprecated
+@SuppressWarnings("all")
+public final class NotHandledException extends CommandException {
+
+    /**
+     * Generated serial version UID for this class.
+     *
+     * @since 3.1
+     */
+    private static final long serialVersionUID = 3256446914827726904L;
+
+    /**
+     * Creates a new instance of this class with the specified detail message.
+     *
+     * @param s
+     *            the detail message.
+     */
+	@Deprecated
+    public NotHandledException(String s) {
+        super(s);
+    }
+
+    /**
+     * Constructs a legacy <code>NotHandledException</code> based on the new
+     * <code>NotHandledException</code>
+     *
+     * @param e
+     *            The exception from which this exception should be created;
+     *            must not be <code>null</code>.
+     * @since 3.1
+     */
+	@Deprecated
+    public NotHandledException(final org.eclipse.core.commands.NotHandledException e) {
+        super(e.getMessage(), e);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/Priority.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/Priority.java
new file mode 100644
index 0000000..6fbb169
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/Priority.java
@@ -0,0 +1,127 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.commands;
+
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.internal.util.Util;
+
+/**
+ * <p>
+ * An instance of this interface represents a priority for use with instances of
+ * <code>HandlerSubmission</code>.
+ * </p>
+ * <p>
+ * The order of precedence (from highest to lowest) is as follows. Submissions
+ * with higher priority will be preferred over those with lower priority.
+ * </p>
+ * <ol>
+ * <li>MEDIUM</li>
+ * <li>LOW</li>
+ * <li>LEGACY</li>
+ * </ol>
+ * </p>
+ * <p>
+ * This class is not intended to be extended by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @see HandlerSubmission
+ * @see org.eclipse.ui.ISources
+ * @see org.eclipse.ui.handlers.IHandlerService#activateHandler(String,
+ *      org.eclipse.core.commands.IHandler, Expression)
+ * @deprecated This concept is now captured in the <code>ISources</code> integer
+ *             constants.
+ *
+ */
+@Deprecated
+@SuppressWarnings("rawtypes")
+public final class Priority implements Comparable {
+
+	/**
+	 * An instance representing 'legacy' priority.
+	 */
+	public final static Priority LEGACY = new Priority(ISources.LEGACY_LEGACY);
+
+	/**
+	 * An instance representing 'low' priority.
+	 */
+	public final static Priority LOW = new Priority(ISources.LEGACY_LOW);
+
+	/**
+	 * An instance representing 'medium' priority.
+	 */
+	public final static Priority MEDIUM = new Priority(ISources.LEGACY_MEDIUM);
+
+	/**
+	 * The string representation of this priority. This is computed once
+	 * (lazily). Before it is computed, this value is <code>null</code>.
+	 */
+	private transient String string = null;
+
+	/**
+	 * The priority value for this instance. A lesser integer is considered to
+	 * have a higher priority.
+	 */
+	private int value;
+
+	/**
+	 * Constructs a new instance of <code>Priority</code> using a value. This
+	 * constructor should only be used internally. Priority instances should be
+	 * retrieved from the static members defined above.
+	 *
+	 * @param value
+	 *            The priority value; a lesser integer is consider to have a
+	 *            higher priority value.
+	 */
+	private Priority(int value) {
+		this.value = value;
+	}
+
+	/**
+	 * @see Comparable#compareTo(java.lang.Object)
+	 */
+	@Override
+	@Deprecated
+	public int compareTo(Object object) {
+		Priority castedObject = (Priority) object;
+		int compareTo = Util.compare(value, castedObject.value);
+		return compareTo;
+	}
+
+	/**
+	 * The value for this priority. The lesser the value, the higher priority
+	 * this represents.
+	 *
+	 * @return The integer priority value.
+	 */
+	@Deprecated
+	int getValue() {
+		return value;
+	}
+
+	/**
+	 * @see Object#toString()
+	 */
+	@Override
+	@Deprecated
+	public String toString() {
+		if (string == null) {
+			final StringBuffer stringBuffer = new StringBuffer();
+			stringBuffer.append("[value="); //$NON-NLS-1$
+			stringBuffer.append(value);
+			stringBuffer.append(']');
+			string = stringBuffer.toString();
+		}
+
+		return string;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/package.html b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/package.html
new file mode 100644
index 0000000..4108dee
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/commands/package.html
@@ -0,0 +1,21 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <meta name="Author" content="IBM">
+   <meta name="GENERATOR" content="Mozilla/4.5 [en] (Win98; I) [Netscape]">
+   <title>Package-level Javadoc</title>
+</head>
+<body>
+<p>Provides support for retrieving information on Commands from the workbench.</p>
+
+<h2>Package Specification</h2>
+<p>
+Most of org.eclipse.ui.commands.* is depracated in favour of org.eclipse.core.commands,
+but the ICommandService and associated classes are used to access the workbench
+view of org.eclipse.core.commands.  <code>getService(ICommandService.class)</code>
+can be used to get the ICommandService from the workbench, workbench window,
+or part site.
+</p>
+</body>
+</html>
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/ContextEvent.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/ContextEvent.java
new file mode 100644
index 0000000..6b8a739
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/ContextEvent.java
@@ -0,0 +1,126 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.contexts;
+
+/**
+ * An instance of this class describes changes to an instance of
+ * <code>IContext</code>.
+ * <p>
+ * This class is not intended to be extended by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @see IContextListener#contextChanged(ContextEvent)
+ * @deprecated Please use the "org.eclipse.core.commands" plug-in instead.
+ * @see org.eclipse.core.commands.contexts.ContextEvent
+ */
+@Deprecated
+public final class ContextEvent {
+
+    /**
+     * The context that has changed. This value is never <code>null</code>.
+     */
+    private final IContext context;
+
+    /**
+     * Whether the context has become defined or undefined.
+     */
+    private final boolean definedChanged;
+
+    /**
+     * Whether the context has become enabled or disabled.
+     */
+    private final boolean enabledChanged;
+
+    /**
+     * Whether the name of the context has changed.
+     */
+    private final boolean nameChanged;
+
+    /**
+     * Whether the parent identifier has changed.
+     */
+    private final boolean parentIdChanged;
+
+    /**
+     * Creates a new instance of this class.
+     *
+     * @param context
+     *            the instance of the interface that changed.
+     * @param definedChanged
+     *            true, iff the defined property changed.
+     * @param enabledChanged
+     *            true, iff the enabled property changed.
+     * @param nameChanged
+     *            true, iff the name property changed.
+     * @param parentIdChanged
+     *            true, iff the parentId property changed.
+     */
+    public ContextEvent(IContext context, boolean definedChanged,
+            boolean enabledChanged, boolean nameChanged, boolean parentIdChanged) {
+        if (context == null) {
+			throw new NullPointerException();
+		}
+
+        this.context = context;
+        this.definedChanged = definedChanged;
+        this.enabledChanged = enabledChanged;
+        this.nameChanged = nameChanged;
+        this.parentIdChanged = parentIdChanged;
+    }
+
+    /**
+     * Returns the instance of the interface that changed.
+     *
+     * @return the instance of the interface that changed. Guaranteed not to be
+     *         <code>null</code>.
+     */
+    public IContext getContext() {
+        return context;
+    }
+
+    /**
+     * Returns whether or not the defined property changed.
+     *
+     * @return true, iff the defined property changed.
+     */
+    public boolean hasDefinedChanged() {
+        return definedChanged;
+    }
+
+    /**
+     * Returns whether or not the enabled property changed.
+     *
+     * @return true, iff the enabled property changed.
+     */
+    public boolean hasEnabledChanged() {
+        return enabledChanged;
+    }
+
+    /**
+     * Returns whether or not the name property changed.
+     *
+     * @return true, iff the name property changed.
+     */
+    public boolean hasNameChanged() {
+        return nameChanged;
+    }
+
+    /**
+     * Returns whether or not the parentId property changed.
+     *
+     * @return true, iff the parentId property changed.
+     */
+    public boolean hasParentIdChanged() {
+        return parentIdChanged;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/ContextException.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/ContextException.java
new file mode 100644
index 0000000..f4843a0
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/ContextException.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.contexts;
+
+/**
+ * Signals that an exception occurred within the context architecture.
+ * <p>
+ * This class is not intended to be extended by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @deprecated Please use the "org.eclipse.core.commands" plug-in instead.
+ * @see org.eclipse.core.commands.common.CommandException
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+@Deprecated
+public abstract class ContextException extends Exception {
+
+	/**
+	 * Generated serial version UID for this class.
+	 *
+	 * @since 3.4
+	 */
+	private static final long serialVersionUID= -5143404124388080211L;
+
+
+	private Throwable cause;
+
+    /**
+     * Creates a new instance of this class with the specified detail message.
+     *
+     * @param message
+     *            the detail message.
+     */
+    public ContextException(String message) {
+        super(message);
+    }
+
+    /**
+     * Creates a new instance of this class with the specified detail message
+     * and cause.
+     *
+     * @param message
+     *            the detail message.
+     * @param cause
+     *            the cause.
+     */
+    public ContextException(String message, Throwable cause) {
+        super(message);
+        // don't pass the cause to super, to allow compilation against JCL Foundation
+        this.cause = cause;
+    }
+
+    /**
+     * Returns the cause of this throwable or <code>null</code> if the
+     * cause is nonexistent or unknown.
+     *
+     * @return the cause or <code>null</code>
+     * @since 3.1
+     */
+    @Override
+	public Throwable getCause() {
+        return cause;
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/ContextManagerEvent.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/ContextManagerEvent.java
new file mode 100644
index 0000000..3125b02
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/ContextManagerEvent.java
@@ -0,0 +1,178 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.contexts;
+
+import java.util.Set;
+
+import org.eclipse.ui.internal.util.Util;
+
+/**
+ * An instance of this class describes changes to an instance of
+ * <code>IContextManager</code>.
+ * <p>
+ * This class is not intended to be extended by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @see IContextManagerListener#contextManagerChanged(ContextManagerEvent)
+ * @deprecated Please use the "org.eclipse.core.commands" plug-in instead.
+ * @see org.eclipse.core.commands.contexts.ContextManagerEvent
+ */
+@Deprecated
+public final class ContextManagerEvent {
+
+    /**
+     * The context manager which has changed. This value is never
+     * <code>null</code>.
+     */
+    private final IContextManager contextManager;
+
+    /**
+     * Whether the set of defined contexts has changed.
+     */
+    private final boolean definedContextIdsChanged;
+
+    /**
+     * Whether the set of enabled contexts has changed.
+     */
+    private final boolean enabledContextIdsChanged;
+
+    /**
+     * The set of context identifiers (strings) that were defined before the
+     * change occurred. If the defined contexts did not changed, then this value
+     * is <code>null</code>.
+     */
+    private final Set previouslyDefinedContextIds;
+
+    /**
+     * The set of context identifiers (strings) that were enabled before the
+     * change occurred. If the enabled contexts did not changed, then this value
+     * is <code>null</code>.
+     */
+    private final Set previouslyEnabledContextIds;
+
+    /**
+     * Creates a new instance of this class.
+     *
+     * @param contextManager
+     *            the instance of the interface that changed.
+     * @param definedContextIdsChanged
+     *            true, iff the definedContextIds property changed.
+     * @param enabledContextIdsChanged
+     *            true, iff the enabledContextIds property changed.
+     * @param previouslyDefinedContextIds
+     *            the set of identifiers to previously defined contexts. This
+     *            set may be empty. If this set is not empty, it must only
+     *            contain instances of <code>String</code>. This set must be
+     *            <code>null</code> if definedContextIdsChanged is
+     *            <code>false</code> and must not be null if
+     *            definedContextIdsChanged is <code>true</code>.
+     * @param previouslyEnabledContextIds
+     *            the set of identifiers to previously enabled contexts. This
+     *            set may be empty. If this set is not empty, it must only
+     *            contain instances of <code>String</code>. This set must be
+     *            <code>null</code> if enabledContextIdsChanged is
+     *            <code>false</code> and must not be null if
+     *            enabledContextIdsChanged is <code>true</code>.
+     */
+    public ContextManagerEvent(IContextManager contextManager,
+            boolean definedContextIdsChanged, boolean enabledContextIdsChanged,
+            Set previouslyDefinedContextIds, Set previouslyEnabledContextIds) {
+        if (contextManager == null) {
+			throw new NullPointerException();
+		}
+
+        if (!definedContextIdsChanged && previouslyDefinedContextIds != null) {
+			throw new IllegalArgumentException();
+		}
+
+        if (!enabledContextIdsChanged && previouslyEnabledContextIds != null) {
+			throw new IllegalArgumentException();
+		}
+
+        if (definedContextIdsChanged) {
+            this.previouslyDefinedContextIds = Util.safeCopy(
+                    previouslyDefinedContextIds, String.class);
+        } else {
+            this.previouslyDefinedContextIds = null;
+        }
+
+        if (enabledContextIdsChanged) {
+            this.previouslyEnabledContextIds = Util.safeCopy(
+                    previouslyEnabledContextIds, String.class);
+        } else {
+            this.previouslyEnabledContextIds = null;
+        }
+
+        this.contextManager = contextManager;
+        this.definedContextIdsChanged = definedContextIdsChanged;
+        this.enabledContextIdsChanged = enabledContextIdsChanged;
+    }
+
+    /**
+     * Returns the instance of the interface that changed.
+     *
+     * @return the instance of the interface that changed. Guaranteed not to be
+     *         <code>null</code>.
+     */
+    public IContextManager getContextManager() {
+        return contextManager;
+    }
+
+    /**
+     * Returns the set of identifiers to previously defined contexts.
+     *
+     * @return the set of identifiers to previously defined contexts. This set
+     *         may be empty. If this set is not empty, it is guaranteed to only
+     *         contain instances of <code>String</code>. This set is
+     *         guaranteed to be <code>null</code> if
+     *         haveDefinedContextIdsChanged() is <code>false</code> and is
+     *         guaranteed to not be null if haveDefinedContextIdsChanged() is
+     *         <code>true</code>.
+     */
+    public Set getPreviouslyDefinedContextIds() {
+        return previouslyDefinedContextIds;
+    }
+
+    /**
+     * Returns the set of identifiers to previously enabled contexts.
+     *
+     * @return the set of identifiers to previously enabled contexts. This set
+     *         may be empty. If this set is not empty, it is guaranteed to only
+     *         contain instances of <code>String</code>. This set is
+     *         guaranteed to be <code>null</code> if
+     *         haveEnabledContextIdsChanged() is <code>false</code> and is
+     *         guaranteed to not be null if haveEnabledContextIdsChanged() is
+     *         <code>true</code>.
+     */
+    public Set getPreviouslyEnabledContextIds() {
+        return previouslyEnabledContextIds;
+    }
+
+    /**
+     * Returns whether or not the definedContextIds property changed.
+     *
+     * @return true, iff the definedContextIds property changed.
+     */
+    public boolean haveDefinedContextIdsChanged() {
+        return definedContextIdsChanged;
+    }
+
+    /**
+     * Returns whether or not the enabledContextIds property changed.
+     *
+     * @return true, iff the enabledContextIds property changed.
+     */
+    public boolean haveEnabledContextIdsChanged() {
+        return enabledContextIdsChanged;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/EnabledSubmission.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/EnabledSubmission.java
new file mode 100644
index 0000000..d032015
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/EnabledSubmission.java
@@ -0,0 +1,194 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.contexts;
+
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.internal.util.Util;
+
+/**
+ * </p>
+ * An instance of this class represents a request to enabled a context. An
+ * enabled submission specifies a list of conditions under which it would be
+ * appropriate for a particular context to be enabled. These conditions include
+ * things like the active part or the active shell. So, it is possible to say
+ * things like: "when the java editor is active, please consider enabling the
+ * 'editing java' context".
+ * </p>
+ * <p>
+ * The workbench considers all of the submissions it has received and choses the
+ * ones it views as the best possible match.
+ * </p>
+ * <p>
+ * This class is not intended to be extended by clients.
+ * </p>
+ * <p>
+ * Note: this class has a natural ordering that is inconsistent with equals.
+ * </p>
+ *
+ * @since 3.0
+ * @see IWorkbenchContextSupport
+ * @deprecated Please use <code>IContextService.activateContext</code>
+ *             instead.
+ * @see org.eclipse.ui.contexts.IContextService
+ */
+@Deprecated
+public final class EnabledSubmission implements Comparable {
+
+    /**
+     * The identifier of the part in which this context should be enabled. If
+     * this value is <code>null</code>, this means it should be active in any
+     * part.
+     */
+    private final String activePartId;
+
+    /**
+     * The shell in which this context should be enabled. If this value is
+     * <code>null</code>, this means it should be active in any shell.
+     */
+    private final Shell activeShell;
+
+    /**
+     * The part site in which this context should be enabled. If this value is
+     * <code>null</code>, this means it should be active in any part site.
+     */
+    private final IWorkbenchPartSite activeWorkbenchPartSite;
+
+    /**
+     * The identifier for the context that should be enabled by this
+     * submissions. This value should never be <code>null</code>.
+     */
+    private final String contextId;
+
+    /**
+     * The cached string representation of this instance. This value is computed
+     * lazily on the first call to retrieve the string representation, and the
+     * cache is used for all future calls. If this value is <code>null</code>,
+     * then the value has not yet been computed.
+     */
+    private transient String string = null;
+
+    /**
+     * Creates a new instance of this class.
+     *
+     * @param activePartId
+     *            the identifier of the part that must be active for this
+     *            request to be considered. May be <code>null</code>.
+     * @param activeShell
+     *            the shell that must be active for this request to be
+     *            considered. May be <code>null</code>.
+     * @param activeWorkbenchPartSite
+     *            the workbench part site of the part that must be active for
+     *            this request to be considered. May be <code>null</code>.
+     * @param contextId
+     *            the identifier of the context to be enabled. Must not be
+     *            <code>null</code>.
+     */
+    public EnabledSubmission(String activePartId, Shell activeShell,
+            IWorkbenchPartSite activeWorkbenchPartSite, String contextId) {
+        if (contextId == null) {
+			throw new NullPointerException();
+		}
+
+        this.activePartId = activePartId;
+        this.activeShell = activeShell;
+        this.activeWorkbenchPartSite = activeWorkbenchPartSite;
+        this.contextId = contextId;
+    }
+
+    /**
+     * @see Comparable#compareTo(java.lang.Object)
+     */
+    @Override
+	public int compareTo(Object object) {
+        EnabledSubmission castedObject = (EnabledSubmission) object;
+        int compareTo = Util.compare(activeWorkbenchPartSite,
+                castedObject.activeWorkbenchPartSite);
+
+        if (compareTo == 0) {
+            compareTo = Util.compare(activePartId, castedObject.activePartId);
+
+            if (compareTo == 0) {
+                compareTo = Util.compare(activeShell, castedObject.activeShell);
+
+                if (compareTo == 0) {
+					compareTo = Util.compare(contextId, castedObject.contextId);
+				}
+            }
+        }
+
+        return compareTo;
+    }
+
+    /**
+     * Returns the identifier of the part that must be active for this request
+     * to be considered.
+     *
+     * @return the identifier of the part that must be active for this request
+     *         to be considered. May be <code>null</code>.
+     */
+    public String getActivePartId() {
+        return activePartId;
+    }
+
+    /**
+     * Returns the shell that must be active for this request to be considered.
+     *
+     * @return the shell that must be active for this request to be considered.
+     *         May be <code>null</code>.
+     */
+    public Shell getActiveShell() {
+        return activeShell;
+    }
+
+    /**
+     * Returns the workbench part site of the part that must be active for this
+     * request to be considered.
+     *
+     * @return the workbench part site of the part that must be active for this
+     *         request to be considered. May be <code>null</code>.
+     */
+    public IWorkbenchPartSite getActiveWorkbenchPartSite() {
+        return activeWorkbenchPartSite;
+    }
+
+    /**
+     * Returns the identifier of the context to be enabled.
+     *
+     * @return the identifier of the context to be enabled. Guaranteed not to be
+     *         <code>null</code>.
+     */
+    public String getContextId() {
+        return contextId;
+    }
+
+    /**
+     * @see Object#toString()
+     */
+    @Override
+	public String toString() {
+        if (string == null) {
+            final StringBuffer stringBuffer = new StringBuffer();
+            stringBuffer.append("[activePartId="); //$NON-NLS-1$
+            stringBuffer.append(activePartId);
+            stringBuffer.append(",activeShell="); //$NON-NLS-1$
+            stringBuffer.append(activeShell);
+            stringBuffer.append(",activeWorkbenchSite="); //$NON-NLS-1$
+            stringBuffer.append(activeWorkbenchPartSite);
+            stringBuffer.append(",contextId="); //$NON-NLS-1$
+            stringBuffer.append(contextId);
+            stringBuffer.append(']');
+            string = stringBuffer.toString();
+        }
+
+        return string;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/IContext.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/IContext.java
new file mode 100644
index 0000000..70684f3
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/IContext.java
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.contexts;
+
+/**
+ * An instance of this interface is an context as defined by the extension point
+ * <code>org.eclipse.ui.contexts</code>.
+ * <p>
+ * An instance of this interface can be obtained from an instance of
+ * <code>IContextManager</code> for any identifier, whether or not an context
+ * with that identifier is defined in the extension registry.
+ * </p>
+ * <p>
+ * The handle-based nature of this API allows it to work well with runtime
+ * plugin activation and deactivation. If a context is defined, that means that
+ * its corresponding plug-in is active. If the plug-in is then deactivated, the
+ * context will still exist but it will be undefined. An attempts to use an
+ * undefined context will result in a <code>NotDefinedException</code> being
+ * thrown.
+ * </p>
+ * <p>
+ * This interface is not intended to be extended or implemented by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @see org.eclipse.ui.contexts.IContextManager
+ * @see org.eclipse.core.commands.contexts.Context
+ * @deprecated Please use the "org.eclipse.core.commands" plug-in instead.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+@Deprecated
+public interface IContext extends Comparable {
+
+    /**
+     * Registers an instance of <code>IContextListener</code> to listen for
+     * changes to properties of this instance.
+     *
+     * @param contextListener
+     *            the instance to register. Must not be <code>null</code>. If
+     *            an attempt is made to register an instance which is already
+     *            registered with this instance, no operation is performed.
+     */
+    void addContextListener(IContextListener contextListener);
+
+    /**
+     * Returns the identifier of this instance.
+     *
+     * @return the identifier of this instance. Guaranteed not to be
+     *         <code>null</code>.
+     */
+    String getId();
+
+    /**
+     * Returns the name of this instance suitable for display to the user.
+     * <p>
+     * Notification is sent to all registered listeners if this property
+     * changes.
+     * </p>
+     *
+     * @return the name of this instance. Guaranteed not to be <code>null</code>.
+     * @throws NotDefinedException
+     *             if this instance is not defined.
+     */
+    String getName() throws NotDefinedException;
+
+    /**
+     * Returns the identifier of the parent of this instance.
+     * <p>
+     * Notification is sent to all registered listeners if this property
+     * changes.
+     * </p>
+     *
+     * @return the identifier of the parent of this instance. May be
+     *         <code>null</code>.
+     * @throws NotDefinedException
+     *             if this instance is not defined.
+     */
+    String getParentId() throws NotDefinedException;
+
+    /**
+     * Returns whether or not this instance is defined.
+     * <p>
+     * Notification is sent to all registered listeners if this property
+     * changes.
+     * </p>
+     *
+     * @return true, iff this instance is defined.
+     */
+    boolean isDefined();
+
+    /**
+     * Returns whether or not this instance is enabled.
+     * <p>
+     * Notification is sent to all registered listeners if this property
+     * changes.
+     * </p>
+     *
+     * @return true, iff this instance is enabled.
+     */
+    boolean isEnabled();
+
+    /**
+     * Unregisters an instance of <code>IContextListener</code> listening for
+     * changes to properties of this instance.
+     *
+     * @param contextListener
+     *            the instance to unregister. Must not be <code>null</code>.
+     *            If an attempt is made to unregister an instance which is not
+     *            already registered with this instance, no operation is
+     *            performed.
+     */
+    void removeContextListener(IContextListener contextListener);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/IContextActivation.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/IContextActivation.java
new file mode 100644
index 0000000..886ac1c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/IContextActivation.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.contexts;
+
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.ui.internal.services.IEvaluationResultCache;
+
+/**
+ * <p>
+ * A token representing the activation of a context. This token can later be
+ * used to cancel that activation. Without this token, then context will only
+ * become inactive if the component in which the context was activated is
+ * destroyed.
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented or extended by clients.
+ * </p>
+ *
+ * @since 3.1
+ * @see org.eclipse.ui.ISources
+ * @see org.eclipse.ui.ISourceProvider
+ */
+public interface IContextActivation extends IEvaluationResultCache {
+
+	/**
+	 * Clears the cached computation of the <code>isActive</code> method, if
+	 * any. This method is only intended for internal use. It provides a
+	 * mechanism by which <code>ISourceProvider</code> events can invalidate
+	 * state on a <code>IContextActivation</code> instance.
+	 *
+	 * @deprecated Use {@link IEvaluationResultCache#clearResult()} instead.
+	 */
+	@Deprecated
+	public void clearActive();
+
+	/**
+	 * Returns the identifier of the context that is being activated.
+	 *
+	 * @return The context identifier; never <code>null</code>.
+	 */
+	public String getContextId();
+
+	/**
+	 * Returns the context service from which this activation was requested.
+	 * This is used to ensure that an activation can only be retracted from the
+	 * same service which issued it.
+	 *
+	 * @return The context service; never <code>null</code>.
+	 */
+	public IContextService getContextService();
+
+	/**
+	 * Returns whether this context activation is currently active -- given the
+	 * current state of the workbench. This method should cache its computation.
+	 * The cache will be cleared by a call to <code>clearActive</code>.
+	 *
+	 * @param context
+	 *            The context in which this state should be evaluated; must not
+	 *            be <code>null</code>.
+	 * @return <code>true</code> if the activation is currently active;
+	 *         <code>false</code> otherwise.
+	 * @deprecated Use
+	 *             {@link IEvaluationResultCache#evaluate(IEvaluationContext)}
+	 *             instead.
+	 */
+	@Deprecated
+	public boolean isActive(IEvaluationContext context);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/IContextListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/IContextListener.java
new file mode 100644
index 0000000..97a7c8e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/IContextListener.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.contexts;
+
+/**
+ * An instance of this interface can be used by clients to receive notification
+ * of changes to one or more instances of <code>IContext</code>.
+ * <p>
+ * This interface may be implemented by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @see org.eclipse.ui.contexts.IContext#addContextListener(IContextListener)
+ * @see org.eclipse.ui.contexts.IContext#removeContextListener(IContextListener)
+ * @deprecated Please use the "org.eclipse.core.commands" plug-in instead.
+ * @see org.eclipse.core.commands.contexts.IContextListener
+ */
+@Deprecated
+public interface IContextListener {
+
+    /**
+     * Notifies that one or more properties of an instance of
+     * <code>IContext</code> have changed. Specific details are described in
+     * the <code>ContextEvent</code>.
+     *
+     * @param contextEvent
+     *            the context event. Guaranteed not to be <code>null</code>.
+     */
+    void contextChanged(ContextEvent contextEvent);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/IContextManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/IContextManager.java
new file mode 100644
index 0000000..b780290
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/IContextManager.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.contexts;
+
+import java.util.SortedSet;
+
+/**
+ * <p>
+ * A context manager tracks the sets of defined and enabled contexts within the
+ * application. The manager sends notification events to listeners when these
+ * sets change. It is also possible to retrieve any given context with its
+ * identifier.
+ * </p>
+ * <p>
+ * This interface is not intended to be extended or implemented by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @deprecated Please use the "org.eclipse.core.commands" plug-in instead.
+ * @see org.eclipse.core.commands.contexts.ContextManager
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+@Deprecated
+public interface IContextManager {
+
+    /**
+     * Registers an instance of <code>IContextManagerListener</code> to listen
+     * for changes to properties of this instance.
+     *
+     * @param contextManagerListener
+     *            the instance to register. Must not be <code>null</code>. If
+     *            an attempt is made to register an instance which is already
+     *            registered with this instance, no operation is performed.
+     */
+    void addContextManagerListener(
+            IContextManagerListener contextManagerListener);
+
+    /**
+     * Returns an instance of <code>IContext</code> given an identifier.
+     *
+     * @param contextId
+     *            an identifier. Must not be <code>null</code>
+     * @return an instance of <code>IContext</code>.
+     */
+    IContext getContext(String contextId);
+
+    /**
+     * Returns the set of identifiers to defined contexts.  The set is sorted by
+     * the depth of the context within the tree of contexts.  So, for example,
+     * a child context will always appear before its parent.
+     * <p>
+     * Notification is sent to all registered listeners if this property
+     * changes.
+     * </p>
+     *
+     * @return the set of identifiers to defined contexts. This set may be
+     *         empty, but is guaranteed not to be <code>null</code>. If this
+     *         set is not empty, it is guaranteed to only contain instances of
+     *         <code>String</code>.
+     */
+    SortedSet getDefinedContextIds();
+
+    /**
+     * Returns the set of identifiers to enabled contexts.  The set is sorted by
+     * the depth of the context within the tree of contexts.  So, for example,
+     * a child context will always appear before its parent.
+     * <p>
+     * Notification is sent to all registered listeners if this property
+     * changes.
+     * </p>
+     *
+     * @return the set of identifiers to enabled contexts. This set may be
+     *         empty, but is guaranteed not to be <code>null</code>. If this
+     *         set is not empty, it is guaranteed to only contain instances of
+     *         <code>String</code>.
+     */
+    SortedSet getEnabledContextIds();
+
+    /**
+     * Unregisters an instance of <code>IContextManagerListener</code>
+     * listening for changes to properties of this instance.
+     *
+     * @param contextManagerListener
+     *            the instance to unregister. Must not be <code>null</code>.
+     *            If an attempt is made to unregister an instance which is not
+     *            already registered with this instance, no operation is
+     *            performed.
+     */
+    void removeContextManagerListener(
+            IContextManagerListener contextManagerListener);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/IContextManagerListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/IContextManagerListener.java
new file mode 100644
index 0000000..5d65b81
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/IContextManagerListener.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.contexts;
+
+/**
+ * An instance of this interface can be used by clients to receive notification
+ * of changes to one or more instances of <code>IContextManager</code>.
+ * <p>
+ * This interface may be implemented by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @see IContextManager#addContextManagerListener(IContextManagerListener)
+ * @see IContextManager#removeContextManagerListener(IContextManagerListener)
+ * @deprecated Please use the "org.eclipse.core.commands" plug-in instead.
+ * @see org.eclipse.core.commands.contexts.IContextManagerListener
+ */
+@Deprecated
+public interface IContextManagerListener {
+
+    /**
+     * Notifies that one or more properties of an instance of
+     * <code>IContextManager</code> have changed. Specific details are
+     * described in the <code>ContextManagerEvent</code>.
+     *
+     * @param contextManagerEvent
+     *            the context manager event. Guaranteed not to be
+     *            <code>null</code>.
+     */
+    void contextManagerChanged(ContextManagerEvent contextManagerEvent);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/IContextService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/IContextService.java
new file mode 100644
index 0000000..fe04d23
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/IContextService.java
@@ -0,0 +1,405 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.contexts;
+
+import java.util.Collection;
+import org.eclipse.core.commands.contexts.Context;
+import org.eclipse.core.commands.contexts.IContextManagerListener;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.services.IServiceWithSources;
+
+/**
+ * <p>
+ * Provides services related to contexts in the Eclipse workbench. This provides
+ * access to contexts.
+ * </p>
+ * <p>
+ * This service can be acquired from your service locator:
+ * <pre>
+ * 	IContextService service = (IContextService) getSite().getService(IContextService.class);
+ * </pre>
+ * <ul>
+ * <li>This service is available globally.</li>
+ * </ul>
+ * </p>
+ *
+ * @since 3.1
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IContextService extends IServiceWithSources {
+
+	/**
+	 * The identifier for the context that is active when a workbench is active.
+	 *
+	 * @since 3.7
+	 */
+	public static final String CONTEXT_ID_WORKBENCH_MENU = "org.eclipse.ui.contexts.workbenchMenu"; //$NON-NLS-1$
+
+	/**
+	 * The identifier for the context that is active when a shell registered as
+	 * a dialog.
+	 */
+	public static final String CONTEXT_ID_DIALOG = "org.eclipse.ui.contexts.dialog"; //$NON-NLS-1$
+
+	/**
+	 * The identifier for the context that is active when a shell is registered
+	 * as either a window or a dialog.
+	 */
+	public static final String CONTEXT_ID_DIALOG_AND_WINDOW = "org.eclipse.ui.contexts.dialogAndWindow"; //$NON-NLS-1$
+
+	/**
+	 * The identifier for the context that is active when a shell is registered
+	 * as a window.
+	 */
+	public static final String CONTEXT_ID_WINDOW = "org.eclipse.ui.contexts.window"; //$NON-NLS-1$
+
+	/**
+	 * The type used for registration indicating that the shell should be
+	 * treated as a dialog. When the given shell is active, the "In Dialogs"
+	 * context should also be active.
+	 */
+	public static final int TYPE_DIALOG = 0;
+
+	/**
+	 * The type used for registration indicating that the shell should not
+	 * receive any key bindings be default. When the given shell is active, we
+	 * should not provide any <code>EnabledSubmission</code> instances for the
+	 * "In Dialogs" or "In Windows" contexts.
+	 *
+	 */
+	public static final int TYPE_NONE = 1;
+
+	/**
+	 * The type used for registration indicating that the shell should be
+	 * treated as a window. When the given shell is active, the "In Windows"
+	 * context should also be active.
+	 */
+	public static final int TYPE_WINDOW = 2;
+
+	/**
+	 * <p>
+	 * Activates the given context within the context of this service. If this
+	 * service was retrieved from the workbench, then this context will be
+	 * active globally. If the service was retrieved from a nested component,
+	 * then the context will only be active within that component.
+	 * </p>
+	 * <p>
+	 * Also, it is guaranteed that the contexts submitted through a particular
+	 * service will be cleaned up when that services is destroyed. So, for
+	 * example, a service retrieved from a <code>IWorkbenchPartSite</code>
+	 * would deactivate all of its contexts when the site is destroyed.
+	 * </p>
+	 *
+	 * @param contextId
+	 *            The identifier for the context which should be activated; must
+	 *            not be <code>null</code>.
+	 * @return A token which can be used to later cancel the activation. Only
+	 *         someone with access to this token can cancel the activation. The
+	 *         activation will automatically be cancelled if the context from
+	 *         which this service was retrieved is destroyed.
+	 */
+	public IContextActivation activateContext(String contextId);
+
+	/**
+	 * <p>
+	 * Activates the given context within the context of this service. The
+	 * context becomes active when <code>expression</code> evaluates to
+	 * <code>true</code>. This is the same as calling
+	 * {@link #activateContext(String, Expression, boolean)} with global==<code>false</code>.
+	 * </p>
+	 * <p>
+	 * Also, it is guaranteed that the context submitted through a particular
+	 * service will be cleaned up when that services is destroyed. So, for
+	 * example, a service retrieved from a <code>IWorkbenchPartSite</code>
+	 * would deactivate all of its handlers when the site is destroyed.
+	 * </p>
+	 *
+	 * @param contextId
+	 *            The identifier for the context which should be activated; must
+	 *            not be <code>null</code>.
+	 * @param expression
+	 *            This expression must evaluate to <code>true</code> before
+	 *            this context will really become active. The expression may be
+	 *            <code>null</code> if the context should always be active.
+	 * @return A token which can be used to later cancel the activation. Only
+	 *         someone with access to this token can cancel the activation. The
+	 *         activation will automatically be cancelled if the context from
+	 *         which this service was retrieved is destroyed.
+	 *
+	 * @see org.eclipse.ui.ISources
+	 * @since 3.2
+	 */
+	public IContextActivation activateContext(String contextId,
+			Expression expression);
+
+	/**
+	 * <p>
+	 * Activates the given context within the context of this service. The
+	 * context becomes active when <code>expression</code> evaluates to
+	 * <code>true</code>. If global==<code>false</code> then this service
+	 * must also be the active service to activate the context.
+	 * </p>
+	 * <p>
+	 * Also, it is guaranteed that the context submitted through a particular
+	 * service will be cleaned up when that services is destroyed. So, for
+	 * example, a service retrieved from a <code>IWorkbenchPartSite</code>
+	 * would deactivate all of its handlers when the site is destroyed.
+	 * </p>
+	 *
+	 * @param contextId
+	 *            The identifier for the context which should be activated; must
+	 *            not be <code>null</code>.
+	 * @param expression
+	 *            This expression must evaluate to <code>true</code> before
+	 *            this context will really become active. The expression may be
+	 *            <code>null</code> if the context should always be active.
+	 * @param global
+	 *            Indicates that the handler should be activated irrespectively
+	 *            of whether the corresponding workbench component (e.g.,
+	 *            window, part, etc.) is active.
+	 * @return A token which can be used to later cancel the activation. Only
+	 *         someone with access to this token can cancel the activation. The
+	 *         activation will automatically be cancelled if the context from
+	 *         which this service was retrieved is destroyed.
+	 *
+	 * @see org.eclipse.ui.ISources
+	 * @since 3.2
+	 */
+	public IContextActivation activateContext(String contextId,
+			Expression expression, boolean global);
+
+	/**
+	 * <p>
+	 * Activates the given context within the context of this service. The
+	 * context becomes active when <code>expression</code> evaluates to
+	 * <code>true</code>.
+	 * </p>
+	 * <p>
+	 * Also, it is guaranteed that the context submitted through a particular
+	 * service will be cleaned up when that services is destroyed. So, for
+	 * example, a service retrieved from a <code>IWorkbenchPartSite</code>
+	 * would deactivate all of its handlers when the site is destroyed.
+	 * </p>
+	 *
+	 * @param contextId
+	 *            The identifier for the context which should be activated; must
+	 *            not be <code>null</code>.
+	 * @param expression
+	 *            This expression must evaluate to <code>true</code> before
+	 *            this context will really become active. The expression may be
+	 *            <code>null</code> if the context should always be active.
+	 * @param sourcePriorities
+	 *            The source priorities for the expression.
+	 * @return A token which can be used to later cancel the activation. Only
+	 *         someone with access to this token can cancel the activation. The
+	 *         activation will automatically be cancelled if the context from
+	 *         which this service was retrieved is destroyed.
+	 *
+	 * @see org.eclipse.ui.ISources
+	 * @deprecated Use
+	 *             {@link IContextService#activateContext(String, Expression)}
+	 *             instead.
+	 */
+	@Deprecated
+	public IContextActivation activateContext(String contextId,
+			Expression expression, int sourcePriorities);
+
+	/**
+	 * Adds a listener to this context service. The listener will be notified
+	 * when the set of defined contexts changes. This can be used to track the
+	 * global appearance and disappearance of contexts.
+	 * <p>
+	 * <b>Note:</b> listeners should be removed when no longer necessary. If
+	 * not, they will be removed when the IServiceLocator used to acquire this
+	 * service is disposed.
+	 * </p>
+	 *
+	 * @param listener
+	 *            The listener to attach; must not be <code>null</code>.
+	 * @since 3.2
+	 * @see #removeContextManagerListener(IContextManagerListener)
+	 */
+	public void addContextManagerListener(IContextManagerListener listener);
+
+	/**
+	 * Deactivates the given context within the context of this service. If the
+	 * handler was context with a different service, then it must be deactivated
+	 * from that service instead. It is only possible to retract a context
+	 * activation with this method. That is, you must have the same
+	 * <code>IContextActivation</code> used to activate the context.
+	 *
+	 * @param activation
+	 *            The token that was returned from a call to
+	 *            <code>activateContext</code>; must not be <code>null</code>.
+	 */
+	public void deactivateContext(IContextActivation activation);
+
+	/**
+	 * Deactivates the given contexts within the context of this service. If the
+	 * contexts were activated with a different service, then they must be
+	 * deactivated from that service instead. It is only possible to retract
+	 * context activations with this method. That is, you must have the same
+	 * <code>IContextActivation</code> instances used to activate the
+	 * contexts.
+	 *
+	 * @param activations
+	 *            The tokens that were returned from a call to
+	 *            <code>activateContext</code>. This collection must only
+	 *            contain instances of <code>IContextActivation</code>. The
+	 *            collection must not be <code>null</code>.
+	 */
+	public void deactivateContexts(Collection activations);
+
+	/**
+	 * Returns the set of active context identifiers.
+	 *
+	 * @return The set of active context identifiers; this value may be
+	 *         <code>null</code> if no active contexts have been set yet. If
+	 *         the set is not <code>null</code>, then it contains only
+	 *         instances of <code>String</code>.
+	 * @since 3.2
+	 */
+	public Collection getActiveContextIds();
+
+	/**
+	 * Retrieves the context with the given identifier. If no such context
+	 * exists, then an undefined context with the given id is created.
+	 *
+	 * @param contextId
+	 *            The identifier to find; must not be <code>null</code>.
+	 * @return A context with the given identifier, either defined or undefined.
+	 */
+	public Context getContext(String contextId);
+
+	/**
+	 * Returns the collection of all of the defined contexts in the workbench.
+	 *
+	 * @return The collection of contexts (<code>Context</code>) that are
+	 *         defined; never <code>null</code>, but may be empty.
+	 * @since 3.2
+	 */
+	public Context[] getDefinedContexts();
+
+	/**
+	 * Returns the collection of the identifiers for all of the defined contexts
+	 * in the workbench.
+	 *
+	 * @return The collection of context identifiers (<code>String</code>)
+	 *         that are defined; never <code>null</code>, but may be empty.
+	 */
+	public Collection getDefinedContextIds();
+
+	/**
+	 * Returns the shell type for the given shell.
+	 *
+	 * @param shell
+	 *            The shell for which the type should be determined. If this
+	 *            value is <code>null</code>, then
+	 *            <code>IContextService.TYPE_NONE</code> is returned.
+	 * @return <code>IContextService.TYPE_WINDOW</code>,
+	 *         <code>IContextService.TYPE_DIALOG</code>, or
+	 *         <code>IContextService.TYPE_NONE</code>.
+	 */
+	public int getShellType(Shell shell);
+
+	/**
+	 * <p>
+	 * Reads the context information from the registry and the preferences. This
+	 * will overwrite any of the existing information in the context service.
+	 * This method is intended to be called during start-up. When this method
+	 * completes, this context service will reflect the current state of the
+	 * registry and preference store.
+	 * </p>
+	 */
+	public void readRegistry();
+
+	/**
+	 * <p>
+	 * Registers a shell to automatically promote or demote some basic types of
+	 * contexts. The "In Dialogs" and "In Windows" contexts are provided by the
+	 * system. This a convenience method to ensure that these contexts are
+	 * promoted when the given shell is active.
+	 * </p>
+	 * <p>
+	 * If a shell is registered as a window, then the "In Windows" context is
+	 * enabled when that shell is active. If a shell is registered as a dialog
+	 * -- or is not registered, but has a parent shell -- then the "In Dialogs"
+	 * context is enabled when that shell is active. If the shell is registered
+	 * as none -- or is not registered, but has no parent shell -- then the
+	 * neither of the contexts will be enabled (by us -- someone else can always
+	 * enabled them).
+	 * </p>
+	 * <p>
+	 * If the provided shell has already been registered, then this method will
+	 * change the registration.
+	 * </p>
+	 *
+	 * @param shell
+	 *            The shell to register for key bindings; must not be
+	 *            <code>null</code>.
+	 * @param type
+	 *            The type of shell being registered. This value must be one of
+	 *            the constants given in this interface.
+	 *
+	 * @return <code>true</code> if the shell had already been registered (i.e.,
+	 *         the registration has changed); <code>false</code> otherwise.
+	 */
+	public boolean registerShell(Shell shell, int type);
+
+	/**
+	 * Removes a listener from this context service.
+	 *
+	 * @param listener
+	 *            The listener to be removed; must not be <code>null</code>.
+	 * @since 3.2
+	 */
+	public void removeContextManagerListener(IContextManagerListener listener);
+
+	/**
+	 * <p>
+	 * Unregisters a shell that was previously registered. After this method
+	 * completes, the shell will be treated as if it had never been registered
+	 * at all. If you have registered a shell, you should ensure that this
+	 * method is called when the shell is disposed. Otherwise, a potential
+	 * memory leak will exist.
+	 * </p>
+	 * <p>
+	 * If the shell was never registered, or if the shell is <code>null</code>,
+	 * then this method returns <code>false</code> and does nothing.
+	 *
+	 * @param shell
+	 *            The shell to be unregistered; does nothing if this value is
+	 *            <code>null</code>.
+	 *
+	 * @return <code>true</code> if the shell had been registered;
+	 *         <code>false</code> otherwise.
+	 */
+	public boolean unregisterShell(Shell shell);
+
+	/**
+	 * Informs the service that a batch operation has started.
+	 * <p>
+	 * <b>Note:</b> You must insure that if you call
+	 * <code>deferUpdates(true)</code> that nothing in your batched operation
+	 * will prevent the matching call to <code>deferUpdates(false)</code>.
+	 * </p>
+	 *
+	 * @param defer
+	 *            true when starting a batch operation false when ending the
+	 *            operation
+	 *
+	 * @since 3.5
+	 */
+	public void deferUpdates(boolean defer);
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/IWorkbenchContextSupport.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/IWorkbenchContextSupport.java
new file mode 100644
index 0000000..c0af72a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/IWorkbenchContextSupport.java
@@ -0,0 +1,271 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.contexts;
+
+import java.util.Collection;
+
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * <p>
+ * An instance of this interface provides support for managing contexts at the
+ * <code>IWorkbench</code> level. This provides the functionality necessary to
+ * enabled contexts, disable or enabled the key binding service, as well as
+ * register shells as particular types of windows.
+ * <p>
+ * This interface is not intended to be extended or implemented by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @deprecated Please use <code>IBindingService</code> and
+ *             <code>IContextService</code> instead.
+ * @see org.eclipse.ui.contexts.IContextService
+ * @see org.eclipse.ui.keys.IBindingService
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+@Deprecated
+public interface IWorkbenchContextSupport {
+
+	/**
+	 * The identifier for the context that is active when a shell registered as
+	 * a dialog.
+	 */
+	public static final String CONTEXT_ID_DIALOG = IContextService.CONTEXT_ID_DIALOG;
+
+	/**
+	 * The identifier for the context that is active when a shell is registered
+	 * as either a window or a dialog.
+	 */
+	public static final String CONTEXT_ID_DIALOG_AND_WINDOW = IContextService.CONTEXT_ID_DIALOG_AND_WINDOW;
+
+	/**
+	 * The identifier for the context that is active when a shell is registered
+	 * as a window.
+	 */
+	public static final String CONTEXT_ID_WINDOW = IContextService.CONTEXT_ID_WINDOW;
+
+	/**
+	 * The type used for registration indicating that the shell should be
+	 * treated as a dialog. When the given shell is active, the "In Dialogs"
+	 * context should also be active.
+	 */
+	public static final int TYPE_DIALOG = IContextService.TYPE_DIALOG;
+
+	/**
+	 * The type used for registration indicating that the shell should not
+	 * receive any key bindings be default. When the given shell is active, we
+	 * should not provide any <code>EnabledSubmission</code> instances for the
+	 * "In Dialogs" or "In Windows" contexts.
+	 *
+	 */
+	public static final int TYPE_NONE = IContextService.TYPE_NONE;
+
+	/**
+	 * The type used for registration indicating that the shell should be
+	 * treated as a window. When the given shell is active, the "In Windows"
+	 * context should also be active.
+	 */
+	public static final int TYPE_WINDOW = IContextService.TYPE_WINDOW;
+
+	/**
+	 * <p>
+	 * Add a single enabled submission for consideration. An enabled submission
+	 * is a description of certain criteria under which a particular context
+	 * should become active. All added submissions will be check when the
+	 * conditions in the workbench change, and zero or more contexts will be
+	 * selected as active.
+	 * </p>
+	 * <p>
+	 * Just because an enabled submission is added, it does not mean that the
+	 * corresponding context will become active. The workbench will consider the
+	 * request, but other factors (such as conflicts) may prevent the context
+	 * from becoming active.
+	 * </p>
+	 *
+	 * @param enabledSubmission
+	 *            The enabled submission to be considered; must not be
+	 *            <code>null</code>.
+	 */
+	void addEnabledSubmission(EnabledSubmission enabledSubmission);
+
+	/**
+	 * <p>
+	 * Adds zero or more enabled submissions for consideration. An enabled
+	 * submission is a description of certain criteria under which a particular
+	 * context should become active. All added submissions will be check when
+	 * the conditions in the workbench change, and zero or more contexts will be
+	 * selected as active.
+	 * </p>
+	 * <p>
+	 * Just because an enabled submission is added, it does not mean that the
+	 * corresponding context will become active. The workbench will consider the
+	 * request, but other factors (such as conflicts) may prevent the context
+	 * from becoming active.
+	 * </p>
+	 *
+	 * @param enabledSubmissions
+	 *            The enabled submissions to be considered; must not be
+	 *            <code>null</code>, but may be empty. Every element in the
+	 *            collection must be an instance of
+	 *            <code>EnabledSubmission</code>.
+	 */
+	void addEnabledSubmissions(Collection enabledSubmissions);
+
+	/**
+	 * Returns the context manager for the workbench.
+	 *
+	 * @return the context manager for the workbench. Guaranteed not to be
+	 *         <code>null</code>.
+	 */
+	IContextManager getContextManager();
+
+	/**
+	 * Returns the shell type for the given shell.
+	 *
+	 * @param shell
+	 *            The shell for which the type should be determined. If this
+	 *            value is <code>null</code>, then
+	 *            <code>IWorkbenchContextSupport.TYPE_NONE</code> is returned.
+	 * @return <code>IWorkbenchContextSupport.TYPE_WINDOW</code>,
+	 *         <code>IWorkbenchContextSupport.TYPE_DIALOG</code>, or
+	 *         <code>IWorkbenchContextSupport.TYPE_NONE</code>.
+	 * @since 3.1
+	 */
+	public int getShellType(final Shell shell);
+
+	/**
+	 * Tests whether the global key binding architecture is currently active.
+	 *
+	 * @return <code>true</code> if the key bindings are active;
+	 *         <code>false</code> otherwise.
+	 */
+	public boolean isKeyFilterEnabled();
+
+	/**
+	 * Opens the key assistant dialog positioned near the key binding entry in
+	 * the status bar.
+	 *
+	 * @since 3.1
+	 */
+	public void openKeyAssistDialog();
+
+	/**
+	 * <p>
+	 * Registers a shell to automatically promote or demote some basic types of
+	 * contexts. The "In Dialogs" and "In Windows" contexts are provided by the
+	 * system. This a convenience method to ensure that these contexts are
+	 * promoted when the given is shell is active.
+	 * </p>
+	 * <p>
+	 * If a shell is registered as a window, then the "In Windows" context is
+	 * enabled when that shell is active. If a shell is registered as a dialog --
+	 * or is not registered, but has a parent shell -- then the "In Dialogs"
+	 * context is enabled when that shell is active. If the shell is registered
+	 * as none -- or is not registered, but has no parent shell -- then the
+	 * neither of the contexts will be enabled (by us -- someone else can always
+	 * enabled them).
+	 * </p>
+	 * <p>
+	 * If the provided shell has already been registered, then this method will
+	 * change the registration.
+	 * </p>
+	 *
+	 * @param shell
+	 *            The shell to register for key bindings; must not be
+	 *            <code>null</code>.
+	 * @param type
+	 *            The type of shell being registered. This value must be one of
+	 *            the constants given in this interface.
+	 *
+	 * @return <code>true</code> if the shell had already been registered
+	 *         (i.e., the registration has changed); <code>false</code>
+	 *         otherwise.
+	 */
+	public boolean registerShell(final Shell shell, final int type);
+
+	/**
+	 * <p>
+	 * Removes a single enabled submission from consideration. Only the same
+	 * enabled submission will be removed; equivalent submissions will not be
+	 * removed. Removing an enabled submission does not necessarily mean that
+	 * the corresponding context will become inactive. It is possible that other
+	 * parts of the application have requested that the context be enabled.
+	 * </p>
+	 * <p>
+	 * There is no way to disable a context. It is only possible to not enable
+	 * it.
+	 * </p>
+	 *
+	 * @param enabledSubmission
+	 *            The enabled submission to be removed; must not be
+	 *            <code>null</code>.
+	 */
+	void removeEnabledSubmission(EnabledSubmission enabledSubmission);
+
+	/**
+	 * <p>
+	 * Removes a collection of enabled submissions from consideration. Only the
+	 * same enabled submissions will be removed; equivalent submissions will not
+	 * be removed. Removing an enabled submission does not necessarily mean that
+	 * the corresponding context will become inactive. It is possible that other
+	 * parts of the application have requested that the context be enabled.
+	 * </p>
+	 * <p>
+	 * There is no way to disable a context. It is only possible to not enable
+	 * it.
+	 * </p>
+	 *
+	 * @param enabledSubmissions
+	 *            The enabled submissions to be removed; must not be
+	 *            <code>null</code>, but may be empty. The collection must
+	 *            only contain instances of <code>EnabledSubmission</code>.
+	 */
+	void removeEnabledSubmissions(Collection enabledSubmissions);
+
+	/**
+	 * Enables or disables the global key binding architecture. The architecture
+	 * should be enabled by default.
+	 *
+	 * When enabled, keyboard shortcuts are active, and that key events can
+	 * trigger commands. This also means that widgets may not see all key events
+	 * (as they might be trapped as a keyboard shortcut).
+	 *
+	 * When disabled, no key events will trapped as keyboard shortcuts, and that
+	 * no commands can be triggered by keyboard events. (Exception: it is
+	 * possible that someone listening for key events on a widget could trigger
+	 * a command.)
+	 *
+	 * @param enabled
+	 *            Whether the key filter should be enabled.
+	 */
+	public void setKeyFilterEnabled(final boolean enabled);
+
+	/**
+	 * <p>
+	 * Unregisters a shell that was previously registered. After this method
+	 * completes, the shell will be treated as if it had never been registered
+	 * at all. If you have registered a shell, you should ensure that this
+	 * method is called when the shell is disposed. Otherwise, a potential
+	 * memory leak will exist.
+	 * </p>
+	 * <p>
+	 * If the shell was never registered, or if the shell is <code>null</code>,
+	 * then this method returns <code>false</code> and does nothing.
+	 *
+	 * @param shell
+	 *            The shell to be unregistered; does nothing if this value is
+	 *            <code>null</code>.
+	 *
+	 * @return <code>true</code> if the shell had been registered;
+	 *         <code>false</code> otherwise.
+	 */
+	public boolean unregisterShell(final Shell shell);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/NotDefinedException.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/NotDefinedException.java
new file mode 100644
index 0000000..049ba9d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/NotDefinedException.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.contexts;
+
+/**
+ * Signals that an attempt was made to access the properties of an undefined
+ * object.
+ * <p>
+ * This class is not intended to be extended by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @deprecated Please use the "org.eclipse.core.commands" plug-in instead.
+ * @see org.eclipse.core.commands.common.NotDefinedException
+ */
+@Deprecated
+public final class NotDefinedException extends ContextException {
+
+	/**
+	 * Generated serial version UID for this class.
+	 *
+	 * @since 3.1
+	 */
+	private static final long serialVersionUID = 3833750983926167092L;
+
+	/**
+	 * Creates a new instance of this class with the specified detail message.
+	 *
+	 * @param message
+	 *            the detail message.
+	 */
+	public NotDefinedException(String message) {
+		super(message);
+	}
+
+	/**
+	 * Constructs a new instance of <code>NotDefinedException</code>.
+	 *
+	 * @param e
+	 *            The exception being thrown; must not be <code>null</code>.
+	 * @since 3.1
+	 */
+	public NotDefinedException(
+			org.eclipse.core.commands.common.NotDefinedException e) {
+		super(e.getMessage(), e);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/package.html b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/package.html
new file mode 100644
index 0000000..d23fd94
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/contexts/package.html
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <meta name="Author" content="IBM">
+   <meta name="GENERATOR" content="Mozilla/4.5 [en] (Win98; I) [Netscape]">
+   <title>Package-level Javadoc</title>
+</head>
+<body>
+<p>Provides support for integrating contexts into the Eclipse workbench.</p>
+
+<h2>Package Specification</h2>
+<p>
+This package provides the classes required to integrate contexts into the
+Eclipse workbench.
+</p>
+<p>
+To use the context integration, the method <code>getAdapter</code> is called on
+the Eclipse workbench, with the argument <code>IContextService.class</code>.
+This will return an instance of <code>IContextService</code>.
+</p>
+</body>
+</html>
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/databinding/WorkbenchObservables.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/databinding/WorkbenchObservables.java
new file mode 100644
index 0000000..babbafd
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/databinding/WorkbenchObservables.java
@@ -0,0 +1,444 @@
+/*******************************************************************************
+ * 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     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;
+
+/**
+ * Factory methods for creating observables for Workbench objects
+ *
+ * @since 3.5
+ */
+public class WorkbenchObservables {
+	/**
+	 * Returns an observable with values of the given target type. If the
+	 * wrapped observable's value is of the target type, or can be adapted to
+	 * the target type, this is taken as the value of the returned observable,
+	 * otherwise <code>null</code>.
+	 *
+	 * @param master
+	 *            the observable whose value should be adapted
+	 * @param adapter
+	 *            the target type
+	 * @return an observable with values of the given type, or <code>null</code>
+	 *         if the current value of the given observable does not adapt to
+	 *         the target type
+	 */
+	public static <T> IObservableValue<T> observeDetailAdaptedValue(IObservableValue<?> master, Class<T> adapter) {
+		return observeDetailAdaptedValue(master, adapter, Platform
+				.getAdapterManager());
+	}
+
+	/**
+	 * Returns an observable with values of the given target type. If the
+	 * wrapped observable's value is of the target type, or can be adapted to
+	 * the target type, this is taken as the value of the returned observable,
+	 * otherwise <code>null</code>.
+	 *
+	 * @param master
+	 *            the observable whose value should be adapted
+	 * @param adapter
+	 *            the target type
+	 * @param adapterManager
+	 *            the adapter manager used to adapt the master value
+	 * @return an observable with values of the given type, or <code>null</code>
+	 *         if the current value of the given observable does not adapt to
+	 *         the target type
+	 */
+	static <T> IObservableValue<T> observeDetailAdaptedValue(IObservableValue<?> master, Class<T> adapter,
+			IAdapterManager adapterManager) {
+		return WorkbenchProperties.adaptedValue(adapter, adapterManager)
+				.observeDetail(master);
+	}
+
+	/**
+	 * Returns an observable value that tracks the post selection of a selection
+	 * service obtained through the given service locator, and adapts the first
+	 * element of that selection to the given target type.
+	 * <p>
+	 * This method can be used by view or editor implementers to tie into the
+	 * selection service, for example as follows:
+	 *
+	 * <pre>
+	 * IObservableValue&lt;IResource&gt; selection = WorkbenchObservables.observeAdaptedSingleSelection(getSite(),
+	 * 		IResource.class);
+	 * </pre>
+	 *
+	 * </p>
+	 *
+	 * @param locator
+	 *            a service locator with an available {@link ISelectionService}
+	 * @param targetType
+	 *            the target type
+	 * @return an observable value whose value type is the given target type
+	 */
+	public static <T> IObservableValue<T> observeAdaptedSingleSelection(IServiceLocator locator, Class<T> targetType) {
+		ISelectionService selectionService = locator.getService(ISelectionService.class);
+		Assert.isNotNull(selectionService);
+		return WorkbenchProperties.singleSelection(null, true).value(
+				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.rap.ui.workbench/src/org/eclipse/ui/databinding/WorkbenchProperties.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/databinding/WorkbenchProperties.java
new file mode 100644
index 0000000..3b32522
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/databinding/WorkbenchProperties.java
@@ -0,0 +1,307 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2015 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
+ *     Matthew Hall - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ui.databinding;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import org.eclipse.core.databinding.observable.list.ListDiff;
+import org.eclipse.core.databinding.property.INativePropertyListener;
+import org.eclipse.core.databinding.property.IProperty;
+import org.eclipse.core.databinding.property.ISimplePropertyListener;
+import org.eclipse.core.databinding.property.NativePropertyListener;
+import org.eclipse.core.databinding.property.list.IListProperty;
+import org.eclipse.core.databinding.property.list.SimpleListProperty;
+import org.eclipse.core.databinding.property.value.IValueProperty;
+import org.eclipse.core.databinding.property.value.SimpleValueProperty;
+import org.eclipse.core.runtime.IAdapterManager;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.ISelectionListener;
+import org.eclipse.ui.ISelectionService;
+import org.eclipse.ui.IWorkbenchPart;
+
+/**
+ * Factory methods for creating properties for the Workbench.
+ *
+ * <p>
+ * Examples:
+ *
+ * <pre>
+ * WorkbenchProperties.singleSelection().observe(
+ * 		getSite().getService(ISelectionService.class))
+ * </pre>
+ *
+ * </p>
+ *
+ * @since 3.5
+ */
+public class WorkbenchProperties {
+	/**
+	 * Returns a value property which observes the source object as the adapted
+	 * type, using the platform adapter manager. If the source is of the target
+	 * type, or can be adapted to the target type, this is used as the value of
+	 * property, otherwise <code>null</code>.
+	 *
+	 * @param adapter
+	 *            the adapter class
+	 * @return a value property which observes the source object as the adapted
+	 *         type.
+	 */
+	public static IValueProperty adaptedValue(Class adapter) {
+		return adaptedValue(adapter, Platform.getAdapterManager());
+	}
+
+	/**
+	 * Returns a value property which observes the source object as the adapted
+	 * type. If the source object is of the target type, or can be adapted to
+	 * the target type, this is used as the value of property, otherwise
+	 * <code>null</code>.
+	 *
+	 * @param adapter
+	 *            the adapter class
+	 * @param adapterManager
+	 *            the adapter manager used to adapt source objects
+	 * @return a value property which observes the source object as the adapted
+	 *         type.
+	 */
+	static IValueProperty adaptedValue(final Class adapter,
+			final IAdapterManager adapterManager) {
+		return new AdaptedValueProperty(adapter, adapterManager);
+	}
+
+	/**
+	 * Returns a property for observing the first element of a structured
+	 * selection as exposed by {@link ISelectionService}.
+	 *
+	 * @return an observable value
+	 */
+	public static IValueProperty singleSelection() {
+		return singleSelection(null, false);
+	}
+
+	/**
+	 * Returns a property for observing the first element of a structured
+	 * selection as exposed by {@link ISelectionService}.
+	 *
+	 * @param partId
+	 *            the part id, or <code>null</code> if the selection can be from
+	 *            any part
+	 * @param postSelection
+	 *            <code>true</code> if the selection should be delayed for
+	 *            keyboard-triggered selections
+	 *
+	 * @return an observable value
+	 */
+	public static IValueProperty singleSelection(String partId,
+			boolean postSelection) {
+		return new SingleSelectionProperty(partId, postSelection);
+	}
+
+	/**
+	 * Returns a property for observing the elements of a structured selection
+	 * as exposed by {@link ISelectionService}.
+	 *
+	 * @return an observable value
+	 */
+	public static IListProperty multipleSelection() {
+		return multipleSelection(null, false);
+	}
+
+	/**
+	 * Returns a property for observing the elements of a structured selection
+	 * as exposed by {@link ISelectionService}.
+	 *
+	 * @param partId
+	 *            the part id, or <code>null</code> if the selection can be from
+	 *            any part
+	 * @param postSelection
+	 *            <code>true</code> if the selection should be delayed for
+	 *            keyboard-triggered selections
+	 *
+	 * @return an observable value
+	 */
+	public static IListProperty multipleSelection(String partId,
+			boolean postSelection) {
+		return new MultiSelectionProperty(partId, postSelection);
+	}
+
+	static final class AdaptedValueProperty extends SimpleValueProperty {
+		private final Class adapter;
+		private final IAdapterManager adapterManager;
+
+		private AdaptedValueProperty(Class adapter,
+				IAdapterManager adapterManager) {
+			this.adapter = adapter;
+			this.adapterManager = adapterManager;
+		}
+
+		@Override
+		public Object getValueType() {
+			return adapter;
+		}
+
+		@Override
+		protected Object doGetValue(Object source) {
+			if (adapter.isInstance(source))
+				return source;
+			return adapterManager.getAdapter(source, adapter);
+		}
+
+		@Override
+		protected void doSetValue(Object source, Object value) {
+			throw new UnsupportedOperationException();
+		}
+
+		@Override
+		public INativePropertyListener adaptListener(
+				ISimplePropertyListener listener) {
+			return null;
+		}
+	}
+
+	static class SingleSelectionProperty extends SimpleValueProperty {
+		private final String partId;
+		private final boolean post;
+
+		SingleSelectionProperty(String partId, boolean post) {
+			this.partId = partId;
+			this.post = post;
+		}
+
+		@Override
+		public INativePropertyListener adaptListener(
+				ISimplePropertyListener listener) {
+			return new SelectionServiceListener(this, listener, partId, post);
+		}
+
+		@Override
+		protected Object doGetValue(Object source) {
+			ISelection selection;
+			if (partId != null) {
+				selection = ((ISelectionService) source).getSelection(partId);
+			} else {
+				selection = ((ISelectionService) source).getSelection();
+			}
+			if (selection instanceof IStructuredSelection) {
+				return ((IStructuredSelection) selection).getFirstElement();
+			}
+			return null;
+		}
+
+		@Override
+		protected void doSetValue(Object source, Object value) {
+			throw new UnsupportedOperationException();
+		}
+
+		@Override
+		public Object getValueType() {
+			return Object.class;
+		}
+	}
+
+	static class MultiSelectionProperty extends SimpleListProperty {
+		private final String partId;
+		private final boolean post;
+
+		MultiSelectionProperty(String partId, boolean post) {
+			this.partId = partId;
+			this.post = post;
+		}
+
+		@Override
+		public INativePropertyListener adaptListener(
+				ISimplePropertyListener listener) {
+			return new SelectionServiceListener(this, listener, partId, post);
+		}
+
+		@Override
+		public Object getElementType() {
+			return Object.class;
+		}
+
+		@Override
+		protected List doGetList(Object source) {
+			ISelection selection;
+			if (partId != null) {
+				selection = ((ISelectionService) source).getSelection(partId);
+			} else {
+				selection = ((ISelectionService) source).getSelection();
+			}
+			if (selection instanceof IStructuredSelection) {
+				return new ArrayList(((IStructuredSelection) selection)
+						.toList());
+			}
+			return Collections.EMPTY_LIST;
+		}
+
+		@Override
+		protected void doSetList(Object source, List list, ListDiff diff) {
+			throw new UnsupportedOperationException();
+		}
+	}
+
+	static class SelectionServiceListener extends NativePropertyListener
+			implements ISelectionListener {
+		private final String partId;
+		private final boolean post;
+
+		public SelectionServiceListener(IProperty property,
+				ISimplePropertyListener wrapped, String partID, boolean post) {
+			super(property, wrapped);
+			this.partId = partID;
+			this.post = post;
+		}
+
+		@Override
+		protected void doAddTo(Object source) {
+			ISelectionService selectionService = (ISelectionService) source;
+			if (post) {
+				if (partId != null) {
+					selectionService.addPostSelectionListener(partId, this);
+				} else {
+					selectionService.addPostSelectionListener(this);
+				}
+			} else {
+				if (partId != null) {
+					selectionService.addSelectionListener(partId, this);
+				} else {
+					selectionService.addSelectionListener(this);
+				}
+			}
+		}
+
+		@Override
+		protected void doRemoveFrom(Object source) {
+			ISelectionService selectionService = (ISelectionService) source;
+			if (post) {
+				if (partId != null) {
+					selectionService.removePostSelectionListener(partId, this);
+				} else {
+					selectionService.removePostSelectionListener(this);
+				}
+			} else {
+				if (partId != null) {
+					selectionService.removeSelectionListener(partId, this);
+				} else {
+					selectionService.removeSelectionListener(this);
+				}
+			}
+		}
+
+		@Override
+		public void selectionChanged(IWorkbenchPart part, ISelection selection) {
+			fireChange(part, null);
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/databinding/package.html b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/databinding/package.html
new file mode 100644
index 0000000..8f650c1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/databinding/package.html
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<meta name="Author" content="IBM">
+<title>Package-level Javadoc</title>
+</head>
+
+<body>
+APIs for Workbench properties and observables for use with data binding
+<h2>Package Specification</h2>
+This package provides APIs that provide access to properties of Workbench objects for
+use with the data binding framework.
+</body>
+
+</html>
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/AbstractElementListSelectionDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/AbstractElementListSelectionDialog.java
new file mode 100644
index 0000000..b5e2ba0
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/AbstractElementListSelectionDialog.java
@@ -0,0 +1,495 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Sebastian Davids <sdavids@gmx.de> - Fix for bug 19346 - Dialog
+ *     font should be activated and used by other components.
+ *******************************************************************************/
+package org.eclipse.ui.dialogs;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * An abstract class to select elements out of a list of elements.
+ *
+ * @since 2.0
+ */
+public abstract class AbstractElementListSelectionDialog extends SelectionStatusDialog {
+
+    private ILabelProvider fRenderer;
+
+    private boolean fIgnoreCase = true;
+
+    private boolean fIsMultipleSelection = false;
+
+    private boolean fMatchEmptyString = true;
+
+    private boolean fAllowDuplicates = true;
+
+    private Label fMessage;
+
+    protected FilteredList fFilteredList;
+
+    private Text fFilterText;
+
+    private ISelectionStatusValidator fValidator;
+
+    private String fFilter = null;
+
+    private String fEmptyListMessage = ""; //$NON-NLS-1$
+
+    private String fEmptySelectionMessage = ""; //$NON-NLS-1$
+
+    private int fWidth = 60;
+
+    private int fHeight = 18;
+
+    private Object[] fSelection = new Object[0];
+
+    /**
+     * Constructs a list selection dialog.
+     * @param parent The parent for the list.
+     * @param renderer ILabelProvider for the list
+     */
+	protected AbstractElementListSelectionDialog(Shell parent, ILabelProvider renderer) {
+        super(parent);
+        fRenderer = renderer;
+    }
+
+    /**
+     * Handles default selection (double click).
+     * By default, the OK button is pressed.
+     */
+    protected void handleDefaultSelected() {
+        if (validateCurrentSelection()) {
+			buttonPressed(IDialogConstants.OK_ID);
+		}
+    }
+
+    /**
+     * Specifies if sorting, filtering and folding is case sensitive.
+     * @param ignoreCase
+     */
+    public void setIgnoreCase(boolean ignoreCase) {
+        fIgnoreCase = ignoreCase;
+    }
+
+    /**
+     * Returns if sorting, filtering and folding is case sensitive.
+     * @return boolean
+     */
+    public boolean isCaseIgnored() {
+        return fIgnoreCase;
+    }
+
+    /**
+     * Specifies whether everything or nothing should be filtered on
+     * empty filter string.
+     * @param matchEmptyString boolean
+     */
+    public void setMatchEmptyString(boolean matchEmptyString) {
+        fMatchEmptyString = matchEmptyString;
+    }
+
+    /**
+     * Specifies if multiple selection is allowed.
+     * @param multipleSelection
+     */
+    public void setMultipleSelection(boolean multipleSelection) {
+        fIsMultipleSelection = multipleSelection;
+    }
+
+    /**
+     * Specifies whether duplicate entries are displayed or not.
+     * @param allowDuplicates
+     */
+    public void setAllowDuplicates(boolean allowDuplicates) {
+        fAllowDuplicates = allowDuplicates;
+    }
+
+    /**
+     * Sets the list size in unit of characters.
+     * @param width  the width of the list.
+     * @param height the height of the list.
+     */
+    public void setSize(int width, int height) {
+        fWidth = width;
+        fHeight = height;
+    }
+
+    /**
+     * Sets the message to be displayed if the list is empty.
+     * @param message the message to be displayed.
+     */
+    public void setEmptyListMessage(String message) {
+        fEmptyListMessage = message;
+    }
+
+    /**
+     * Sets the message to be displayed if the selection is empty.
+     * @param message the message to be displayed.
+     */
+    public void setEmptySelectionMessage(String message) {
+        fEmptySelectionMessage = message;
+    }
+
+    /**
+     * Sets an optional validator to check if the selection is valid.
+     * The validator is invoked whenever the selection changes.
+     * @param validator the validator to validate the selection.
+     */
+    public void setValidator(ISelectionStatusValidator validator) {
+        fValidator = validator;
+    }
+
+    /**
+	 * Sets the elements of the list (widget).
+	 *
+	 * @param elements
+	 *            the elements of the list.
+	 */
+    protected void setListElements(Object[] elements) {
+        Assert.isNotNull(fFilteredList);
+        fFilteredList.setElements(elements);
+		handleElementsChanged();
+    }
+
+    /**
+	 * This method is called when the elements of the backing list are changed
+	 * to refresh the standard dialog widgets.
+	 *
+	 * @since 3.8
+	 */
+	protected void handleElementsChanged() {
+		boolean enabled = !fFilteredList.isEmpty();
+
+		if (fMessage != null && !fMessage.isDisposed())
+			fMessage.setEnabled(enabled);
+
+		fFilteredList.setEnabled(enabled);
+		updateOkState();
+	}
+
+	/**
+	 * Sets the filter pattern.
+	 *
+	 * @param filter
+	 *            the filter pattern.
+	 */
+    public void setFilter(String filter) {
+        if (fFilterText == null) {
+			fFilter = filter;
+		} else {
+			fFilterText.setText(filter);
+		}
+    }
+
+    /**
+     * Returns the current filter pattern.
+     * @return returns the current filter pattern or <code>null<code> if filter was not set.
+     */
+    public String getFilter() {
+        if (fFilteredList == null) {
+			return fFilter;
+		}
+		return fFilteredList.getFilter();
+    }
+
+    /**
+     * Returns the indices referring the current selection.
+     * To be called within open().
+     * @return returns the indices of the current selection.
+     */
+    protected int[] getSelectionIndices() {
+        Assert.isNotNull(fFilteredList);
+        return fFilteredList.getSelectionIndices();
+    }
+
+    /**
+     * Returns an index referring the first current selection.
+     * To be called within open().
+     * @return returns the indices of the current selection.
+     */
+    protected int getSelectionIndex() {
+        Assert.isNotNull(fFilteredList);
+        return fFilteredList.getSelectionIndex();
+    }
+
+    /**
+     * Sets the selection referenced by an array of elements.
+     * Empty or null array removes selection.
+     * To be called within open().
+     * @param selection the indices of the selection.
+     */
+    protected void setSelection(Object[] selection) {
+        Assert.isNotNull(fFilteredList);
+        fFilteredList.setSelection(selection);
+    }
+
+    /**
+     * Returns an array of the currently selected elements.
+     * To be called within or after open().
+     * @return returns an array of the currently selected elements.
+     */
+    protected Object[] getSelectedElements() {
+        Assert.isNotNull(fFilteredList);
+        return fFilteredList.getSelection();
+    }
+
+    /**
+     * Returns all elements which are folded together to one entry in the list.
+     * @param  index the index selecting the entry in the list.
+     * @return returns an array of elements folded together.
+     */
+    public Object[] getFoldedElements(int index) {
+        Assert.isNotNull(fFilteredList);
+        return fFilteredList.getFoldedElements(index);
+    }
+
+    /**
+     * Creates the message text widget and sets layout data.
+     * @param composite the parent composite of the message area.
+     */
+    @Override
+	protected Label createMessageArea(Composite composite) {
+        Label label = super.createMessageArea(composite);
+
+        GridData data = new GridData();
+        data.grabExcessVerticalSpace = false;
+        data.grabExcessHorizontalSpace = true;
+        data.horizontalAlignment = GridData.FILL;
+        data.verticalAlignment = GridData.BEGINNING;
+        label.setLayoutData(data);
+
+        fMessage = label;
+
+        return label;
+    }
+
+    /**
+     * Handles a selection changed event.
+     * By default, the current selection is validated.
+     */
+    protected void handleSelectionChanged() {
+        validateCurrentSelection();
+    }
+
+    /**
+     * Validates the current selection and updates the status line
+     * accordingly.
+     * @return boolean <code>true</code> if the current selection is
+     * valid.
+     */
+    protected boolean validateCurrentSelection() {
+        Assert.isNotNull(fFilteredList);
+
+        IStatus status;
+        Object[] elements = getSelectedElements();
+
+        if (elements.length > 0) {
+            if (fValidator != null) {
+                status = fValidator.validate(elements);
+            } else {
+                status = new Status(IStatus.OK, PlatformUI.PLUGIN_ID,
+                        IStatus.OK, "", //$NON-NLS-1$
+                        null);
+            }
+        } else {
+            if (fFilteredList.isEmpty()) {
+                status = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID,
+                        IStatus.ERROR, fEmptyListMessage, null);
+            } else {
+                status = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID,
+                        IStatus.ERROR, fEmptySelectionMessage, null);
+            }
+        }
+
+        updateStatus(status);
+
+        return status.isOK();
+    }
+
+    @Override
+	protected void cancelPressed() {
+        setResult(null);
+        super.cancelPressed();
+    }
+
+    /**
+     * Creates a filtered list.
+     * @param parent the parent composite.
+     * @return returns the filtered list widget.
+     */
+    protected FilteredList createFilteredList(Composite parent) {
+        int flags = SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL
+                | (fIsMultipleSelection ? SWT.MULTI : SWT.SINGLE);
+
+        FilteredList list = new FilteredList(parent, flags, fRenderer,
+                fIgnoreCase, fAllowDuplicates, fMatchEmptyString);
+
+        GridData data = new GridData();
+        data.widthHint = convertWidthInCharsToPixels(fWidth);
+        data.heightHint = convertHeightInCharsToPixels(fHeight);
+        data.grabExcessVerticalSpace = true;
+        data.grabExcessHorizontalSpace = true;
+        data.horizontalAlignment = GridData.FILL;
+        data.verticalAlignment = GridData.FILL;
+        list.setLayoutData(data);
+        list.setFont(parent.getFont());
+        list.setFilter((fFilter == null ? "" : fFilter)); //$NON-NLS-1$
+
+        list.addSelectionListener(new SelectionListener() {
+            @Override
+			public void widgetDefaultSelected(SelectionEvent e) {
+                handleDefaultSelected();
+            }
+
+            @Override
+			public void widgetSelected(SelectionEvent e) {
+                handleWidgetSelected();
+            }
+        });
+
+        fFilteredList = list;
+
+        return list;
+    }
+
+    // 3515
+    private void handleWidgetSelected() {
+        Object[] newSelection = fFilteredList.getSelection();
+
+        if (newSelection.length != fSelection.length) {
+            fSelection = newSelection;
+            handleSelectionChanged();
+        } else {
+            for (int i = 0; i != newSelection.length; i++) {
+                if (!newSelection[i].equals(fSelection[i])) {
+                    fSelection = newSelection;
+                    handleSelectionChanged();
+                    break;
+                }
+            }
+        }
+    }
+
+    protected Text createFilterText(Composite parent) {
+        Text text = new Text(parent, SWT.BORDER);
+
+        GridData data = new GridData();
+        data.grabExcessVerticalSpace = false;
+        data.grabExcessHorizontalSpace = true;
+        data.horizontalAlignment = GridData.FILL;
+        data.verticalAlignment = GridData.BEGINNING;
+        text.setLayoutData(data);
+        text.setFont(parent.getFont());
+
+        text.setText((fFilter == null ? "" : fFilter)); //$NON-NLS-1$
+
+        Listener listener = e -> fFilteredList.setFilter(fFilterText.getText());
+        text.addListener(SWT.Modify, listener);
+
+        text.addKeyListener(new KeyListener() {
+            @Override
+			public void keyPressed(KeyEvent e) {
+                if (e.keyCode == SWT.ARROW_DOWN) {
+					fFilteredList.setFocus();
+				}
+            }
+
+            @Override
+			public void keyReleased(KeyEvent e) {
+            }
+        });
+
+        fFilterText = text;
+
+        return text;
+    }
+
+    @Override
+	public int open() {
+        super.open();
+        return getReturnCode();
+    }
+
+    private void access$superCreate() {
+        super.create();
+    }
+
+    @Override
+	public void create() {
+
+        BusyIndicator.showWhile(null, () -> {
+		    access$superCreate();
+
+		    Assert.isNotNull(fFilteredList);
+
+		    if (fFilteredList.isEmpty()) {
+		        handleEmptyList();
+		    } else {
+		        validateCurrentSelection();
+		        fFilterText.selectAll();
+		        fFilterText.setFocus();
+		    }
+		});
+
+    }
+
+    /**
+     * Handles empty list by disabling widgets.
+     */
+    protected void handleEmptyList() {
+		fMessage.setEnabled(false);
+		fFilterText.setEnabled(false);
+		fFilteredList.setEnabled(false);
+        updateOkState();
+    }
+
+    /**
+     * Update the enablement of the OK button based on whether or not there
+     * is a selection.
+     *
+     */
+    protected void updateOkState() {
+        Button okButton = getOkButton();
+        if (okButton != null) {
+			okButton.setEnabled(getSelectedElements().length != 0);
+		}
+    }
+
+    /**
+     * Gets the optional validator used to check if the selection is valid.
+     * The validator is invoked whenever the selection changes.
+     * @return the validator to validate the selection, or <code>null</code>
+     * if no validator has been set.
+     *
+     * @since 3.5
+     */
+    protected ISelectionStatusValidator getValidator() {
+        return fValidator;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/CheckedTreeSelectionDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/CheckedTreeSelectionDialog.java
new file mode 100644
index 0000000..da05306
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/CheckedTreeSelectionDialog.java
@@ -0,0 +1,433 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ * 		Sebastian Davids <sdavids@gmx.de> - Fix for bug 19346 - Dialog font should be
+ * 			activated and used by other components.
+ *      Lubomir Marinov <lubomir.marinov@gmail.com> - Fix for bug 182122 -[Dialogs]
+ *          CheckedTreeSelectionDialog#createSelectionButtons(Composite) fails to
+ *          align the selection buttons to the right
+ *******************************************************************************/
+package org.eclipse.ui.dialogs;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.viewers.CheckboxTreeViewer;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.jface.viewers.ViewerSorter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchMessages;
+
+/**
+ * A class to select elements out of a tree structure.
+ *
+ * @since 2.0
+ */
+public class CheckedTreeSelectionDialog extends SelectionStatusDialog {
+    private CheckboxTreeViewer fViewer;
+
+    private ILabelProvider fLabelProvider;
+
+    private ITreeContentProvider fContentProvider;
+
+    private ISelectionStatusValidator fValidator = null;
+
+    private ViewerComparator fComparator;
+
+    private String fEmptyListMessage = WorkbenchMessages.get().CheckedTreeSelectionDialog_nothing_available;
+
+    private IStatus fCurrStatus = new Status(IStatus.OK, PlatformUI.PLUGIN_ID,
+            0, "", null); //$NON-NLS-1$
+
+    private List fFilters;
+
+    private Object fInput;
+
+    private boolean fIsEmpty;
+
+    private int fWidth = 60;
+
+    private int fHeight = 18;
+
+    private boolean fContainerMode;
+
+    private Object[] fExpandedElements;
+
+	private int fStyle = SWT.BORDER;
+
+    /**
+     * Constructs an instance of <code>ElementTreeSelectionDialog</code>.
+     *
+     * @param parent
+     *            The shell to parent from.
+     * @param labelProvider
+     *            the label provider to render the entries
+     * @param contentProvider
+     *            the content provider to evaluate the tree structure
+     */
+    public CheckedTreeSelectionDialog(Shell parent,
+            ILabelProvider labelProvider, ITreeContentProvider contentProvider) {
+		this(parent, labelProvider, contentProvider, SWT.BORDER);
+    }
+
+	/**
+	 * Constructs an instance of <code>ElementTreeSelectionDialog</code>.
+	 *
+	 * @param parent
+	 *            The shell to parent from.
+	 * @param labelProvider
+	 *            the label provider to render the entries
+	 * @param contentProvider
+	 *            the content provider to evaluate the tree structure
+	 * @param style
+	 *            the style of the tree
+	 * @since 3.105
+	 */
+	public CheckedTreeSelectionDialog(Shell parent, ILabelProvider labelProvider,
+			ITreeContentProvider contentProvider, int style) {
+		super(parent);
+		fLabelProvider = labelProvider;
+		fContentProvider = contentProvider;
+		setResult(new ArrayList(0));
+		setStatusLineAboveButtons(true);
+		fContainerMode = false;
+		fExpandedElements = null;
+		fStyle = style;
+	}
+
+    /**
+     * If set, the checked /gray state of containers (inner nodes) is derived
+     * from the checked state of its leaf nodes.
+     *
+     * @param containerMode
+     *            The containerMode to set
+     */
+    public void setContainerMode(boolean containerMode) {
+        fContainerMode = containerMode;
+    }
+
+    /**
+     * Sets the initial selection. Convenience method.
+     *
+     * @param selection
+     *            the initial selection.
+     */
+    public void setInitialSelection(Object selection) {
+        setInitialSelections(new Object[] { selection });
+    }
+
+    /**
+     * Sets the message to be displayed if the list is empty.
+     *
+     * @param message
+     *            the message to be displayed.
+     */
+    public void setEmptyListMessage(String message) {
+        fEmptyListMessage = message;
+    }
+
+    /**
+	 * Sets the sorter used by the tree viewer.
+	 *
+	 * @param sorter
+	 * @deprecated since 3.3, use
+	 *             {@link CheckedTreeSelectionDialog#setComparator(ViewerComparator)}
+	 *             instead
+	 */
+    @Deprecated
+	public void setSorter(ViewerSorter sorter) {
+        fComparator = sorter;
+    }
+
+    /**
+	 * Set the style used for the creation of the Tree. Changing this will only
+	 * have an effect up to the time the Tree is created.
+	 *
+	 * @param style
+	 *            the style of the tree
+	 * @since 3.105
+	 */
+	public void setStyle(int style) {
+		fStyle = style;
+	}
+
+	/**
+	 * Sets the comparator used by the tree viewer.
+	 *
+	 * @param comparator
+	 * @since 3.3
+	 */
+    public void setComparator(ViewerComparator comparator){
+    	fComparator = comparator;
+    }
+
+    /**
+     * Adds a filter to the tree viewer.
+     *
+     * @param filter
+     *            a filter.
+     */
+    public void addFilter(ViewerFilter filter) {
+        if (fFilters == null) {
+			fFilters = new ArrayList(4);
+		}
+        fFilters.add(filter);
+    }
+
+    /**
+     * Sets an optional validator to check if the selection is valid. The
+     * validator is invoked whenever the selection changes.
+     *
+     * @param validator
+     *            the validator to validate the selection.
+     */
+    public void setValidator(ISelectionStatusValidator validator) {
+        fValidator = validator;
+    }
+
+    /**
+     * Sets the tree input.
+     *
+     * @param input
+     *            the tree input.
+     */
+    public void setInput(Object input) {
+        fInput = input;
+    }
+
+    /**
+     * Expands elements in the tree.
+     *
+     * @param elements
+     *            The elements that will be expanded.
+     */
+    public void setExpandedElements(Object[] elements) {
+        fExpandedElements = elements;
+    }
+
+    /**
+     * Sets the size of the tree in unit of characters.
+     *
+     * @param width
+     *            the width of the tree.
+     * @param height
+     *            the height of the tree.
+     */
+    public void setSize(int width, int height) {
+        fWidth = width;
+        fHeight = height;
+    }
+
+    /**
+     * Validate the receiver and update the status with the result.
+     *
+     */
+    protected void updateOKStatus() {
+        if (!fIsEmpty) {
+            if (fValidator != null) {
+                fCurrStatus = fValidator.validate(fViewer.getCheckedElements());
+                updateStatus(fCurrStatus);
+            } else if (!fCurrStatus.isOK()) {
+                fCurrStatus = new Status(IStatus.OK, PlatformUI.PLUGIN_ID,
+                        IStatus.OK, "", //$NON-NLS-1$
+                        null);
+            }
+        } else {
+            fCurrStatus = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID,
+                    IStatus.OK, fEmptyListMessage, null);
+        }
+        updateStatus(fCurrStatus);
+    }
+
+    @Override
+	public int open() {
+        fIsEmpty = evaluateIfTreeEmpty(fInput);
+        super.open();
+        return getReturnCode();
+    }
+
+    private void access$superCreate() {
+        super.create();
+    }
+
+    /**
+     * Handles cancel button pressed event.
+     */
+    @Override
+	protected void cancelPressed() {
+        setResult(null);
+        super.cancelPressed();
+    }
+
+    /*
+     * @see SelectionStatusDialog#computeResult()
+     */
+    @Override
+	protected void computeResult() {
+        setResult(Arrays.asList(fViewer.getCheckedElements()));
+    }
+
+    @Override
+	public void create() {
+        BusyIndicator.showWhile(null, () -> {
+		    access$superCreate();
+		    fViewer.setCheckedElements(getInitialElementSelections()
+		            .toArray());
+		    if (fExpandedElements != null) {
+		        fViewer.setExpandedElements(fExpandedElements);
+		    }
+		    updateOKStatus();
+		});
+    }
+
+    @Override
+	protected Control createDialogArea(Composite parent) {
+        Composite composite = (Composite) super.createDialogArea(parent);
+        Label messageLabel = createMessageArea(composite);
+        CheckboxTreeViewer treeViewer = createTreeViewer(composite);
+        Control buttonComposite = createSelectionButtons(composite);
+        GridData data = new GridData(GridData.FILL_BOTH);
+        data.widthHint = convertWidthInCharsToPixels(fWidth);
+        data.heightHint = convertHeightInCharsToPixels(fHeight);
+        Tree treeWidget = treeViewer.getTree();
+        treeWidget.setLayoutData(data);
+        treeWidget.setFont(parent.getFont());
+        if (fIsEmpty) {
+            messageLabel.setEnabled(false);
+            treeWidget.setEnabled(false);
+            buttonComposite.setEnabled(false);
+        }
+        return composite;
+    }
+
+    /**
+     * Creates the tree viewer.
+     *
+     * @param parent
+     *            the parent composite
+     * @return the tree viewer
+     */
+    protected CheckboxTreeViewer createTreeViewer(Composite parent) {
+        if (fContainerMode) {
+			fViewer = new ContainerCheckedTreeViewer(parent, fStyle);
+        } else {
+			fViewer = new CheckboxTreeViewer(parent, fStyle);
+        }
+        fViewer.setContentProvider(fContentProvider);
+        fViewer.setLabelProvider(fLabelProvider);
+        fViewer.addCheckStateListener(event -> updateOKStatus());
+        fViewer.setComparator(fComparator);
+        if (fFilters != null) {
+            for (int i = 0; i != fFilters.size(); i++) {
+				fViewer.addFilter((ViewerFilter) fFilters.get(i));
+			}
+        }
+        fViewer.setInput(fInput);
+        return fViewer;
+    }
+
+    /**
+     * Returns the tree viewer.
+     *
+     * @return the tree viewer
+     */
+    protected CheckboxTreeViewer getTreeViewer() {
+        return fViewer;
+    }
+
+    /**
+     * Adds the selection and deselection buttons to the dialog.
+     *
+     * @param composite
+     *            the parent composite
+     * @return Composite the composite the buttons were created in.
+     */
+    protected Composite createSelectionButtons(Composite composite) {
+        Composite buttonComposite = new Composite(composite, SWT.RIGHT);
+        GridLayout layout = new GridLayout();
+        layout.numColumns = 0;
+		layout.marginWidth = 0;
+		layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
+		buttonComposite.setLayout(layout);
+        buttonComposite.setFont(composite.getFont());
+        GridData data = new GridData(GridData.HORIZONTAL_ALIGN_END
+                | GridData.GRAB_HORIZONTAL);
+        data.grabExcessHorizontalSpace = true;
+        buttonComposite.setLayoutData(data);
+        Button selectButton = createButton(buttonComposite,
+                IDialogConstants.SELECT_ALL_ID, WorkbenchMessages.get().CheckedTreeSelectionDialog_select_all,
+                false);
+        SelectionListener listener = new SelectionAdapter()
+        {
+            /** {@inheritDoc} */
+            @Override
+            public void widgetSelected(SelectionEvent e)
+            {
+                Object[] viewerElements = fContentProvider.getElements(fInput);
+                if (fContainerMode) {
+                    fViewer.setCheckedElements(viewerElements);
+                } else {
+                    for (Object viewerElement : viewerElements) {
+                        fViewer.setSubtreeChecked(viewerElement, true);
+                    }
+                }
+                updateOKStatus();
+            }
+        };
+        selectButton.addSelectionListener(listener);
+        Button deselectButton = createButton(buttonComposite,
+                IDialogConstants.DESELECT_ALL_ID, WorkbenchMessages.get().CheckedTreeSelectionDialog_deselect_all,
+                false);
+        listener = new SelectionAdapter()
+        {
+            /** {@inheritDoc} */
+            @Override
+            public void widgetSelected(SelectionEvent e)
+            {
+                fViewer.setCheckedElements(new Object[0]);
+                updateOKStatus();
+            }
+        };
+        deselectButton.addSelectionListener(listener);
+        return buttonComposite;
+    }
+
+    private boolean evaluateIfTreeEmpty(Object input) {
+        Object[] elements = fContentProvider.getElements(input);
+        if (elements.length > 0) {
+            if (fFilters != null) {
+                for (int i = 0; i < fFilters.size(); i++) {
+                    ViewerFilter curr = (ViewerFilter) fFilters.get(i);
+                    elements = curr.filter(fViewer, input, elements);
+                }
+            }
+        }
+        return elements.length == 0;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/ContainerCheckedTreeViewer.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/ContainerCheckedTreeViewer.java
new file mode 100644
index 0000000..e2bb375
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/ContainerCheckedTreeViewer.java
@@ -0,0 +1,199 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.dialogs;
+
+import java.util.ArrayList;
+import org.eclipse.jface.viewers.CheckboxTreeViewer;
+import org.eclipse.jface.viewers.ITreeViewerListener;
+import org.eclipse.jface.viewers.TreeExpansionEvent;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Item;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.swt.widgets.Widget;
+
+/**
+ * CheckboxTreeViewer with special behaviour of the checked / gray state on
+ * container (non-leaf) nodes:
+ * The grayed state is used to visualize the checked state of its children.
+ * Containers are checked and non-gray if all contained leafs are checked. The
+ * container is grayed if some but not all leafs are checked.
+ * @since 3.1
+ */
+public class ContainerCheckedTreeViewer extends CheckboxTreeViewer {
+
+    /**
+     * Constructor for ContainerCheckedTreeViewer.
+     * @see CheckboxTreeViewer#CheckboxTreeViewer(Composite)
+     */
+    public ContainerCheckedTreeViewer(Composite parent) {
+        super(parent);
+        initViewer();
+    }
+
+    /**
+     * Constructor for ContainerCheckedTreeViewer.
+     * @see CheckboxTreeViewer#CheckboxTreeViewer(Composite,int)
+     */
+    public ContainerCheckedTreeViewer(Composite parent, int style) {
+        super(parent, style);
+        initViewer();
+    }
+
+    /**
+     * Constructor for ContainerCheckedTreeViewer.
+     * @see CheckboxTreeViewer#CheckboxTreeViewer(Tree)
+     */
+    public ContainerCheckedTreeViewer(Tree tree) {
+        super(tree);
+        initViewer();
+    }
+
+    private void initViewer() {
+        setUseHashlookup(true);
+        addCheckStateListener(event -> doCheckStateChanged(event.getElement()));
+        addTreeListener(new ITreeViewerListener() {
+            @Override
+			public void treeCollapsed(TreeExpansionEvent event) {
+            }
+
+            @Override
+			public void treeExpanded(TreeExpansionEvent event) {
+                Widget item = findItem(event.getElement());
+                if (item instanceof TreeItem) {
+                    initializeItem((TreeItem) item);
+                }
+            }
+        });
+    }
+
+	/**
+	 * Update element after a checkstate change.
+	 * @param element
+	 */
+    protected void doCheckStateChanged(Object element) {
+        Widget item = findItem(element);
+        if (item instanceof TreeItem) {
+            TreeItem treeItem = (TreeItem) item;
+            treeItem.setGrayed(false);
+            updateChildrenItems(treeItem);
+            updateParentItems(treeItem.getParentItem());
+        }
+    }
+
+    /**
+     * The item has expanded. Updates the checked state of its children.
+     */
+    private void initializeItem(TreeItem item) {
+        if (item.getChecked() && !item.getGrayed()) {
+            updateChildrenItems(item);
+        }
+    }
+
+    /**
+     * Updates the check state of all created children
+     */
+    private void updateChildrenItems(TreeItem parent) {
+        Item[] children = getChildren(parent);
+        boolean state = parent.getChecked();
+        for (Item element : children) {
+            TreeItem curr = (TreeItem) element;
+            if (curr.getData() != null
+                    && ((curr.getChecked() != state) || curr.getGrayed())) {
+                curr.setChecked(state);
+                curr.setGrayed(false);
+                updateChildrenItems(curr);
+            }
+        }
+    }
+
+    /**
+     * Updates the check / gray state of all parent items
+     */
+    private void updateParentItems(TreeItem item) {
+        if (item != null) {
+            Item[] children = getChildren(item);
+            boolean containsChecked = false;
+            boolean containsUnchecked = false;
+            for (Item element : children) {
+                TreeItem curr = (TreeItem) element;
+                containsChecked |= curr.getChecked();
+                containsUnchecked |= (!curr.getChecked() || curr.getGrayed());
+            }
+            item.setChecked(containsChecked);
+            item.setGrayed(containsChecked && containsUnchecked);
+            updateParentItems(item.getParentItem());
+        }
+    }
+
+
+    @Override
+	public boolean setChecked(Object element, boolean state) {
+        if (super.setChecked(element, state)) {
+            doCheckStateChanged(element);
+            return true;
+        }
+        return false;
+    }
+
+
+    @Override
+	public void setCheckedElements(Object[] elements) {
+        super.setCheckedElements(elements);
+        for (Object element : elements) {
+            doCheckStateChanged(element);
+        }
+    }
+
+
+    @Override
+	protected void setExpanded(Item item, boolean expand) {
+        super.setExpanded(item, expand);
+        if (expand && item instanceof TreeItem) {
+            initializeItem((TreeItem) item);
+        }
+    }
+
+
+    @Override
+	public Object[] getCheckedElements() {
+        Object[] checked = super.getCheckedElements();
+        // add all items that are children of a checked node but not created yet
+        ArrayList result = new ArrayList();
+        for (Object curr : checked) {
+            result.add(curr);
+            Widget item = findItem(curr);
+            if (item != null) {
+                Item[] children = getChildren(item);
+                // check if contains the dummy node
+                if (children.length == 1 && children[0].getData() == null) {
+                    // not yet created
+                    collectChildren(curr, result);
+                }
+            }
+        }
+        return result.toArray();
+    }
+
+	/**
+	 * Recursively add the filtered children of element to the result.
+	 * @param element
+	 * @param result
+	 */
+    private void collectChildren(Object element, ArrayList result) {
+        Object[] filteredChildren = getFilteredChildren(element);
+        for (Object curr : filteredChildren) {
+            result.add(curr);
+            collectChildren(curr, result);
+        }
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/EditorSelectionDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/EditorSelectionDialog.java
new file mode 100644
index 0000000..dd1f109
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/EditorSelectionDialog.java
@@ -0,0 +1,789 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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
+ *     Benjamin Muskalla -Bug 29633
+ *     Helena Halperin - Bug 298747
+ *     Andrey Loskutov <loskutov@gmx.de> - Bug 378485, 460555, 463262
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ *     Patrik Suzzi <psuzzi@gmail.com> - Bug 486859
+ *******************************************************************************/
+package org.eclipse.ui.dialogs;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.jface.resource.ResourceManager;
+import org.eclipse.jface.util.Util;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.osgi.util.TextProcessor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.ui.IEditorDescriptor;
+import org.eclipse.ui.IEditorRegistry;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.registry.EditorDescriptor;
+import org.eclipse.ui.internal.registry.EditorRegistry;
+
+
+/**
+ * This class is used to allow the user to select a dialog from the set of
+ * internal and external editors.
+ *
+ * @since 3.3
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+
+public class EditorSelectionDialog extends Dialog {
+
+	private static class TreeArrayContentProvider implements ITreeContentProvider {
+
+		private static final Object[] EMPTY = new Object[0];
+
+		@Override
+		public void dispose() {
+			//
+		}
+
+		@Override
+		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+			//
+		}
+
+		@Override
+		public Object[] getElements(Object inputElement) {
+			if (inputElement == null || !inputElement.getClass().isArray()) {
+				return EMPTY;
+			}
+			// see bug 9262 why we can't return the same array
+			Object[] orig = (Object[]) inputElement;
+			Object[] arr = new Object[orig.length];
+			System.arraycopy(orig, 0, arr, 0, arr.length);
+			return arr;
+		}
+
+		@Override
+		public Object[] getChildren(Object parentElement) {
+			return EMPTY;
+		}
+
+		@Override
+		public Object getParent(Object element) {
+			return null;
+		}
+
+		@Override
+		public boolean hasChildren(Object element) {
+			return false;
+		}
+
+	}
+
+	private IEditorDescriptor selectedEditor;
+
+	private IEditorDescriptor hiddenSelectedEditor;
+
+	private Button externalButton;
+
+	private FilteredTree editorTable;
+
+	private Button browseExternalEditorsButton;
+
+	private Button internalButton;
+
+	private Button okButton;
+
+	/**
+	 * For internal use only.
+	 *
+	 * @noreference This field is not intended to be referenced by clients.
+	 * @since 3.7
+	 */
+	protected static final String STORE_ID_INTERNAL_EXTERNAL = "EditorSelectionDialog.STORE_ID_INTERNAL_EXTERNAL";//$NON-NLS-1$
+
+	private static final String STORE_ID_DESCR = "EditorSelectionDialog.STORE_ID_DESCR";//$NON-NLS-1$
+
+	private static final String STORE_ID_FILE_EXTENSION = "EditorSelectionDialog.STORE_ID_FILE_EXTENSION";//$NON-NLS-1$
+
+	private String message = WorkbenchMessages.get().EditorSelection_chooseAnEditor;
+
+	// collection of IEditorDescriptor
+	private IEditorDescriptor[] externalEditors;
+
+	private IEditorDescriptor[] internalEditors;
+
+	private IEditorDescriptor[] editorsToFilter;
+
+	private DialogListener listener = new DialogListener();
+
+	private ResourceManager resourceManager;
+
+	private TreeViewer editorTableViewer;
+
+	private String fileName;
+
+	private Button rememberTypeButton;
+
+	private Button rememberEditorButton;
+
+	private static final String[] Executable_Filters;
+
+	private static final int TABLE_WIDTH = 200;
+	static {
+		if (Util.isWindows()) {
+			Executable_Filters = new String[] { "*.exe", "*.bat", "*.*" };//$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		} else if (Util.isMac()) {
+			Executable_Filters = new String[] { "*.app", "*" }; //$NON-NLS-1$ //$NON-NLS-2$
+		} else {
+			Executable_Filters = new String[] { "*" }; //$NON-NLS-1$
+		}
+	}
+
+	/**
+	 * Create an instance of this class.
+	 *
+	 * @param parentShell
+	 *            the parent shell
+	 */
+	public EditorSelectionDialog(Shell parentShell) {
+		super(parentShell);
+		resourceManager = new LocalResourceManager(JFaceResources.getResources(parentShell
+				.getDisplay()));
+	}
+
+	/**
+	 * This method is called if a button has been pressed.
+	 */
+	@Override
+	protected void buttonPressed(int buttonId) {
+		if (buttonId == IDialogConstants.OK_ID) {
+			saveWidgetValues();
+		}
+		super.buttonPressed(buttonId);
+	}
+
+	/**
+	 * Close the window.
+	 */
+	@Override
+	public boolean close() {
+		boolean result = super.close();
+		resourceManager.dispose();
+		resourceManager = null;
+		return result;
+	}
+
+	@Override
+	protected void configureShell(Shell shell) {
+		super.configureShell(shell);
+		shell.setText(WorkbenchMessages.get().EditorSelection_title);
+		PlatformUI.getWorkbench().getHelpSystem().setHelp(shell,
+				IWorkbenchHelpContextIds.EDITOR_SELECTION_DIALOG);
+	}
+
+	/**
+	 * Creates and returns the contents of the upper part of the dialog (above
+	 * the button bar).
+	 *
+	 * Subclasses should overide.
+	 *
+	 * @param parent
+	 *            the parent composite to contain the dialog area
+	 * @return the dialog area control
+	 */
+	@Override
+	protected Control createDialogArea(Composite parent) {
+		Font font = parent.getFont();
+		// create main group
+		Composite contents = (Composite) super.createDialogArea(parent);
+		((GridLayout) contents.getLayout()).numColumns = 2;
+
+		// begin the layout
+		Label textLabel = new Label(contents, SWT.WRAP);
+
+		textLabel.setText(message);
+		GridData data = new GridData();
+		data.horizontalSpan = 2;
+		data.horizontalAlignment = SWT.FILL;
+		data.widthHint = TABLE_WIDTH;
+		textLabel.setLayoutData(data);
+		textLabel.setFont(font);
+
+		Composite group = new Composite(contents, SWT.SHADOW_NONE);
+		data = new GridData();
+		data.grabExcessHorizontalSpace = true;
+		data.horizontalAlignment = SWT.FILL;
+		data.horizontalSpan = 2;
+		group.setLayout(new RowLayout(SWT.HORIZONTAL));
+		group.setLayoutData(data);
+
+		internalButton = new Button(group, SWT.RADIO | SWT.LEFT);
+		internalButton.setText(WorkbenchMessages.get().EditorSelection_internal);
+		internalButton.addListener(SWT.Selection, listener);
+		internalButton.setFont(font);
+
+		externalButton = new Button(group, SWT.RADIO | SWT.LEFT);
+		externalButton.setText(WorkbenchMessages.get().EditorSelection_external);
+		externalButton.addListener(SWT.Selection, listener);
+		externalButton.setFont(font);
+
+		editorTable = new FilteredTree(contents, SWT.SINGLE | SWT.BORDER, new PatternFilter(), true);
+		editorTableViewer = editorTable.getViewer();
+		Tree tree = editorTableViewer.getTree();
+		tree.addListener(SWT.Selection, listener);
+		tree.addListener(SWT.DefaultSelection, listener);
+		tree.addListener(SWT.MouseDoubleClick, listener);
+		data = new GridData();
+		data.widthHint = convertHorizontalDLUsToPixels(TABLE_WIDTH);
+		data.horizontalAlignment = GridData.FILL;
+		data.grabExcessHorizontalSpace = true;
+		data.verticalAlignment = GridData.FILL;
+		data.grabExcessVerticalSpace = true;
+		data.horizontalSpan = 2;
+		editorTable.setLayoutData(data);
+		editorTable.setFont(font);
+		data.heightHint = tree.getItemHeight() * 12;
+		editorTableViewer.setContentProvider(new TreeArrayContentProvider());
+		editorTableViewer.setLabelProvider(new LabelProvider() {
+			@Override
+			public String getText(Object element) {
+				IEditorDescriptor d = (IEditorDescriptor) element;
+				return TextProcessor.process(d.getLabel(), "."); //$NON-NLS-1$
+			}
+
+			@Override
+			public Image getImage(Object element) {
+				IEditorDescriptor d = (IEditorDescriptor) element;
+				return (Image) resourceManager.get(d.getImageDescriptor());
+			}
+		});
+
+		browseExternalEditorsButton = new Button(contents, SWT.PUSH);
+		browseExternalEditorsButton
+				.setText(WorkbenchMessages.get().EditorSelection_browse);
+		browseExternalEditorsButton.addListener(SWT.Selection, listener);
+		data = new GridData();
+		int widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
+		data.widthHint = Math.max(widthHint, browseExternalEditorsButton
+				.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x);
+		data.horizontalSpan = 2;
+		browseExternalEditorsButton.setLayoutData(data);
+		browseExternalEditorsButton.setFont(font);
+
+		if (fileName != null) {
+
+			rememberEditorButton = new Button(contents, SWT.CHECK | SWT.LEFT);
+			rememberEditorButton.setText(NLS.bind(WorkbenchMessages.get().EditorSelection_rememberEditor, fileName));
+			rememberEditorButton.addListener(SWT.Selection, listener);
+			data = new GridData();
+			data.horizontalSpan = 2;
+			rememberEditorButton.setLayoutData(data);
+			rememberEditorButton.setFont(font);
+
+			String fileType = getFileType();
+			if (!fileType.isEmpty()) {
+				rememberTypeButton = new Button(contents, SWT.CHECK | SWT.LEFT);
+				rememberTypeButton.setText(NLS.bind(WorkbenchMessages.get().EditorSelection_rememberType, fileType));
+				rememberTypeButton.addListener(SWT.Selection, listener);
+				data = new GridData();
+				data.horizontalSpan = 2;
+				rememberTypeButton.setLayoutData(data);
+				rememberTypeButton.setFont(font);
+			}
+		}
+
+		initializeSuggestion();
+		restoreWidgetValues(); // Place buttons to the appropriate state
+
+		// Run async to restore selection on *visible* dialog - otherwise three won't scroll
+		PlatformUI.getWorkbench().getDisplay().asyncExec(() -> {
+			if (editorTable.isDisposed()) {
+				return;
+			}
+			fillEditorTable();
+			updateEnableState();
+		});
+	    return contents;
+	}
+
+	private String getFileType() {
+		if (fileName == null) {
+			return ""; //$NON-NLS-1$
+		}
+		int lastDot = fileName.lastIndexOf('.');
+		if (lastDot == -1 || lastDot >= fileName.length() - 1) {
+			return ""; //$NON-NLS-1$
+		}
+		return fileName.substring(lastDot + 1, fileName.length());
+	}
+
+	protected void fillEditorTable() {
+//		IEditorDescriptor newSelection = selectedEditor;
+//
+//		boolean showInternal = internalButton.getSelection();
+//		Object[] input = (Object[]) editorTableViewer.getInput();
+//		if (input != null) {
+//			// we are switching between external/internal editors
+//			boolean isShowingInternal = Arrays.equals(input, getInternalEditors());
+//			if (showInternal != isShowingInternal) {
+//				newSelection = hiddenSelectedEditor;
+//				if (!editorTableViewer.getSelection().isEmpty()) {
+//					hiddenSelectedEditor = (EditorDescriptor) editorTableViewer.getStructuredSelection()
+//							.getFirstElement();
+//				}
+//			}
+//		}
+
+        editorTableViewer.setInput(getInternalEditors());
+
+//		if (fileName != null && newSelection == null) {
+//			if (!showInternal) {
+//				newSelection = findBestExternalEditor();
+//			} else {
+//				newSelection = PlatformUI.getWorkbench().getEditorRegistry().getDefaultEditor(fileName);
+//			}
+//		}
+//		if (newSelection != null) {
+//			editorTableViewer.setSelection(new StructuredSelection(newSelection), true);
+//		}
+//
+//		if (editorTableViewer.getSelection().isEmpty()) {
+//			// set focus to first element, but don't select it:
+//			Tree tree = editorTableViewer.getTree();
+//			if (tree.getItemCount() > 0) {
+//				tree.showItem(tree.getItem(0));
+//			}
+//		}
+//		editorTable.setFocus();
+	}
+
+	private static String getFileExtension(String fileName) {
+		if (fileName == null) {
+			return null;
+		}
+		int index = fileName.lastIndexOf('.');
+		if (index != -1) {
+			return fileName.substring(index);
+		}
+		return fileName;
+	}
+
+	/**
+	 * Return the dialog store to cache values into
+	 */
+	protected IDialogSettings getDialogSettings() {
+		IDialogSettings workbenchSettings = WorkbenchPlugin.getDefault()
+				.getDialogSettings();
+		IDialogSettings section = workbenchSettings
+				.getSection("EditorSelectionDialog");//$NON-NLS-1$
+		if (section == null) {
+			section = workbenchSettings.addNewSection("EditorSelectionDialog");//$NON-NLS-1$
+		}
+		return section;
+	}
+
+    // RAP [bm]: no external editors    
+//  /**
+//   * Get a list of registered programs from the OS
+//   */
+//	protected IEditorDescriptor[] getExternalEditors() {
+//		if (externalEditors == null) {
+//			IProgressService ps = PlatformUI.getWorkbench().getService(IProgressService.class);
+//			// Since this can take a while, show the busy cursor.
+//			IRunnableWithProgress runnable = monitor -> {
+//				// Get the external editors available
+//				EditorRegistry reg = (EditorRegistry) WorkbenchPlugin.getDefault().getEditorRegistry();
+//				externalEditors = reg.getSortedEditorsFromOS();
+//				externalEditors = filterEditors(externalEditors);
+//			};
+//			try {
+//				// See bug 47556 - Program.getPrograms() requires a Display.getCurrent() != null
+//				ps.runInUI(PlatformUI.getWorkbench().getActiveWorkbenchWindow(), runnable, null);
+//			} catch (InvocationTargetException e) {
+//				Throwable cause = e.getCause();
+//				IStatus status;
+//				if (cause instanceof CoreException) {
+//					status = ((CoreException) cause).getStatus();
+//				} else {
+//					status = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID,
+//							"Error while retrieving native editors", cause); //$NON-NLS-1$
+//				}
+//				StatusManager.getManager().handle(status);
+//			} catch (InterruptedException e) {
+//				// Canceled by the user
+//			}
+//
+//		}
+//		return externalEditors;
+//	}
+
+	/**
+	 * Returns an array of editors which have been filtered according to the
+	 * array of editors in the editorsToFilter instance variable.
+	 *
+	 * @param editors
+	 *            an array of editors to filter
+	 * @return a filtered array of editors
+	 */
+	protected IEditorDescriptor[] filterEditors(IEditorDescriptor[] editors) {
+		if ((editors == null) || (editors.length < 1)) {
+			return editors;
+		}
+
+		if ((editorsToFilter == null) || (editorsToFilter.length < 1)) {
+			return editors;
+		}
+
+		List<IEditorDescriptor> filteredList = new ArrayList<>();
+		for (IEditorDescriptor editor : editors) {
+			boolean add = true;
+			for (IEditorDescriptor element : editorsToFilter) {
+				if (editor.getId().equals(element.getId())) {
+					add = false;
+				}
+			}
+			if (add) {
+				filteredList.add(editor);
+			}
+		}
+
+		return filteredList.toArray(new IEditorDescriptor[filteredList.size()]);
+	}
+
+	/**
+	 * Returns the internal editors
+	 */
+	protected IEditorDescriptor[] getInternalEditors() {
+		if (internalEditors == null) {
+			EditorRegistry reg = (EditorRegistry) WorkbenchPlugin.getDefault()
+					.getEditorRegistry();
+			internalEditors = reg.getSortedEditorsFromPlugins();
+			internalEditors = filterEditors(internalEditors);
+		}
+		return internalEditors;
+	}
+
+	/**
+	 * Return the editor the user selected
+	 *
+	 * @return the selected editor
+	 */
+	public IEditorDescriptor getSelectedEditor() {
+		return selectedEditor;
+	}
+
+    // RAP [rh] external editors not supported
+//	protected void promptForExternalEditor() {
+//		FileDialog dialog = new FileDialog(getShell(), SWT.OPEN
+//				| SWT.PRIMARY_MODAL | SWT.SHEET);
+//		dialog.setFilterExtensions(Executable_Filters);
+//		String result = dialog.open();
+//		if (result != null) {
+//			EditorDescriptor editor = EditorDescriptor.createForProgram(result);
+//
+//			/*
+//			 * add to our collection of cached external editors in case the user
+//			 * flips back and forth between internal/external
+//			 */
+//			IEditorDescriptor[] newEditors = new IEditorDescriptor[externalEditors.length + 1];
+//			System.arraycopy(externalEditors, 0, newEditors, 0,
+//					externalEditors.length);
+//			newEditors[newEditors.length - 1] = editor;
+//			externalEditors = newEditors;
+//			editorTableViewer.setInput(externalEditors);
+//			editorTableViewer.setSelection(new StructuredSelection(editor), true);
+//			editorTable.setFocus();
+//			selectedEditor = editor;
+//		}
+//	}
+
+	/**
+	 * Handle a double click event on the list
+	 */
+	protected void handleDoubleClickEvent() {
+		buttonPressed(IDialogConstants.OK_ID);
+	}
+
+	private void initializeSuggestion() {
+		if (fileName == null) {
+			return;
+		}
+		IEditorRegistry editorRegistry = PlatformUI.getWorkbench().getEditorRegistry();
+		IEditorDescriptor suggestion = editorRegistry.getDefaultEditor(fileName);
+//		if (suggestion != null && suggestion.isInternal()) {
+			selectedEditor = suggestion;
+//		} else {
+//			selectedEditor = findBestExternalEditor();
+//		}
+		boolean enableInternalList = selectedEditor == null || selectedEditor.isInternal();
+		internalButton.setSelection(enableInternalList);
+		externalButton.setSelection(!enableInternalList);
+	}
+
+//	private IEditorDescriptor findBestExternalEditor() {
+//		if (fileName == null) {
+//			return null;
+//		}
+//		String extension = getFileExtension(fileName);
+//		Program program = Program.findProgram(extension);
+//		if (program != null) {
+//			for (IEditorDescriptor descriptor : getExternalEditors()) {
+//				if (descriptor instanceof EditorDescriptor
+//						&& program.equals(((EditorDescriptor) descriptor).getProgram())) {
+//					return descriptor;
+//				}
+//			}
+//		}
+//		return null;
+//	}
+
+	/**
+	 * Use the dialog store to restore widget values to the values that they
+	 * held last time this wizard was used to completion, if the previous file
+	 * has same extension.
+	 */
+	protected void restoreWidgetValues() {
+// RAP [rh] external editors not supported	    
+//		IDialogSettings settings = getDialogSettings();
+//		if (fileName == null || selectedEditor == null
+//				|| getFileExtension(fileName).equals(settings.get(STORE_ID_FILE_EXTENSION))) {
+//			boolean wasExternal = settings.getBoolean(STORE_ID_INTERNAL_EXTERNAL);
+//			internalButton.setSelection(!wasExternal);
+//			externalButton.setSelection(wasExternal);
+//			String id = settings.get(STORE_ID_DESCR);
+//			if (id != null) {
+//				IEditorDescriptor[] editors;
+//				if (wasExternal) {
+//					editors = getExternalEditors();
+//				} else {
+//					editors = getInternalEditors();
+//				}
+//				for (IEditorDescriptor desc : editors) {
+//					if (id.equals(desc.getId())) {
+//						selectedEditor = desc;
+//					}
+//				}
+//			}
+//		}
+	}
+
+	/**
+	 * Since Finish was pressed, write widget values to the dialog store so that
+	 * they will persist into the next invocation of this wizard page
+	 */
+	protected void saveWidgetValues() {
+// RAP [rh] external editors not supported
+//		IDialogSettings settings = getDialogSettings();
+//		// record whether use was viewing internal or external editors
+//		settings.put(STORE_ID_FILE_EXTENSION, getFileExtension(fileName));
+//		settings.put(STORE_ID_INTERNAL_EXTERNAL, !internalButton.getSelection());
+//		settings.put(STORE_ID_DESCR, selectedEditor.getId());
+//		String editorId = selectedEditor.getId();
+//		settings.put(STORE_ID_DESCR, editorId);
+//		boolean associateEditor = false;
+//		EditorRegistry reg = (EditorRegistry) WorkbenchPlugin.getDefault().getEditorRegistry();
+//		// remember editor for specific file
+//		if (rememberEditorButton != null && rememberEditorButton.getSelection()) {
+//			updateFileMappings(reg, true);
+//			reg.setDefaultEditor(fileName, selectedEditor);
+//			associateEditor = true;
+//		}
+//		// remember editor for given extension type
+//		if (rememberTypeButton != null && rememberTypeButton.getSelection()) {
+//			updateFileMappings(reg, false);
+//			reg.setDefaultEditor("*." + getFileType(), selectedEditor); //$NON-NLS-1$
+//			associateEditor = true;
+//		}
+//		if (associateEditor) {
+//			// bug 468906: always re-set editor mappings: this is needed to
+//			// rebuild internal editors map after setting the default editor
+//			List<IFileEditorMapping> newMappings = new ArrayList<>();
+//			newMappings.addAll(Arrays.asList(reg.getFileEditorMappings()));
+//			reg.setFileEditorMappings(newMappings.toArray(new FileEditorMapping[newMappings.size()]));
+//			reg.saveAssociations();
+//		}
+	}
+
+//	/**
+//	 * Make sure EditorRegistry has editor mapping for the file name/type
+//	 */
+//	private void updateFileMappings(EditorRegistry reg, boolean useFileName) {
+//		IFileEditorMapping[] mappings = reg.getFileEditorMappings();
+//		boolean hasMapping = false;
+//		String fileType = getFileType();
+//		for (IFileEditorMapping mapping : mappings) {
+//			if (useFileName) {
+//				if (fileName.equals(mapping.getLabel())) {
+//					hasMapping = true;
+//					break;
+//				}
+//			} else {
+//				if (fileType.equals(mapping.getExtension())) {
+//					hasMapping = true;
+//					break;
+//				}
+//
+//			}
+//		}
+//		if (hasMapping) {
+//			return;
+//		}
+//		FileEditorMapping mapping;
+//		if (useFileName) {
+//			mapping = new FileEditorMapping(fileName, null);
+//		} else {
+//			mapping = new FileEditorMapping(null, fileType);
+//		}
+//		List<IFileEditorMapping> newMappings = new ArrayList<>();
+//		newMappings.addAll(Arrays.asList(mappings));
+//		newMappings.add(mapping);
+//		FileEditorMapping[] array = newMappings.toArray(new FileEditorMapping[newMappings.size()]);
+//		reg.setFileEditorMappings(array);
+//	}
+
+	/**
+	 * Set the message displayed by this message dialog
+	 *
+	 * @param aMessage
+	 *            the message
+	 */
+	public void setMessage(String aMessage) {
+		message = aMessage;
+	}
+
+	/**
+	 * Set the file name which can be used to store the selected editor
+	 * preference
+	 *
+	 * @param fileName
+	 *            the file name
+	 * @since 3.107
+	 */
+	public void setFileName(String fileName) {
+		this.fileName = fileName;
+	}
+
+	/**
+	 * Set the editors which will not appear in the dialog.
+	 *
+	 * @param editors
+	 *            an array of editors
+	 */
+	public void setEditorsToFilter(IEditorDescriptor[] editors) {
+		editorsToFilter = editors;
+	}
+
+	/**
+	 * Update enabled state.
+	 */
+	protected void updateEnableState() {
+		boolean enableExternal = externalButton.getSelection();
+		browseExternalEditorsButton.setEnabled(enableExternal);
+		updateOkButton();
+	}
+
+	@Override
+	protected void createButtonsForButtonBar(Composite parent) {
+		okButton = createButton(parent, IDialogConstants.OK_ID,
+				IDialogConstants.get().OK_LABEL, true);
+		createButton(parent, IDialogConstants.CANCEL_ID,
+				IDialogConstants.get().CANCEL_LABEL, false);
+		// initially there is no selection so OK button should not be enabled
+		okButton.setEnabled(false);
+
+	}
+
+	/**
+	 * Update the button enablement state.
+	 */
+	protected void updateOkButton() {
+		// Buttons are null during dialog creation
+		if (okButton == null) {
+			return;
+		}
+		// If there is no selection, do not enable OK button
+		if (editorTableViewer.getSelection().isEmpty()) {
+			okButton.setEnabled(false);
+			return;
+		}
+		// At this point, there is a selection
+		okButton.setEnabled(selectedEditor != null);
+	}
+
+	private class DialogListener implements Listener {
+
+		@Override
+		public void handleEvent(Event event) {
+            // RAP [rh] Mouse events don't work reliably with Table
+//          if (event.type == SWT.MouseDoubleClick) {
+//              handleDoubleClickEvent();
+//              return;
+//          }
+		 // RAP [rh] external editors not supported
+//          if (event.widget == externalButton) {
+//              fillEditorTable();
+//          } else if (event.widget == browseExternalEditorsButton) {
+//              promptForExternalEditor();
+/*          } else */ if (event.widget == editorTableViewer.getTree()) {
+				if (!editorTableViewer.getSelection().isEmpty()) {
+					selectedEditor = (EditorDescriptor) editorTableViewer.getStructuredSelection().getFirstElement();
+				} else {
+					selectedEditor = null;
+					okButton.setEnabled(false);
+				}
+			}
+			// 486859 both checked: checking one box unchecks the other
+			if (rememberEditorButton != null && rememberTypeButton != null && rememberEditorButton.getSelection()
+					&& rememberTypeButton.getSelection()) {
+				if (event.widget == rememberEditorButton) {
+					rememberTypeButton.setSelection(false);
+				}
+				if (event.widget == rememberTypeButton) {
+					rememberEditorButton.setSelection(false);
+				}
+			}
+			updateEnableState();
+		}
+
+	}
+
+	@Override
+	protected boolean isResizable() {
+		return true;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/ElementListSelectionDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/ElementListSelectionDialog.java
new file mode 100644
index 0000000..91523f6
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/ElementListSelectionDialog.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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.ui.dialogs;
+
+import java.util.Arrays;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * A class to select elements out of a list of elements.
+ *
+ * @since 2.0
+ */
+public class ElementListSelectionDialog extends AbstractElementListSelectionDialog {
+
+    private Object[] fElements;
+
+    /**
+     * Creates a list selection dialog.
+     * @param parent   the parent widget.
+     * @param renderer the label renderer.
+     */
+    public ElementListSelectionDialog(Shell parent, ILabelProvider renderer) {
+        super(parent, renderer);
+    }
+
+    /**
+     * Sets the elements of the list.
+     * @param elements the elements of the list.
+     */
+    public void setElements(Object[] elements) {
+        fElements = elements;
+    }
+
+    @Override
+	protected void computeResult() {
+        setResult(Arrays.asList(getSelectedElements()));
+    }
+
+    @Override
+	protected Control createDialogArea(Composite parent) {
+        Composite contents = (Composite) super.createDialogArea(parent);
+
+        createMessageArea(contents);
+        createFilterText(contents);
+        createFilteredList(contents);
+
+        setListElements(fElements);
+
+        setSelection(getInitialElementSelections().toArray());
+
+        return contents;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/ElementTreeSelectionDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/ElementTreeSelectionDialog.java
new file mode 100644
index 0000000..2674c77
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/ElementTreeSelectionDialog.java
@@ -0,0 +1,417 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *   Sebastian Davids <sdavids@gmx.de> - Fix for bug 19346 - Dialog
+ *     font should be activated and used by other components.
+ *   Carsten Pfeiffer <carsten.pfeiffer@gebit.de> - Fix for bug 182354 -
+ *     [Dialogs] API - make ElementTreeSelectionDialog usable with a
+ *     FilteredTree
+ *******************************************************************************/
+package org.eclipse.ui.dialogs;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.jface.viewers.ViewerSorter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchMessages;
+
+/**
+ * A class to select elements out of a tree structure.
+ *
+ * @since 2.0
+ */
+public class ElementTreeSelectionDialog extends SelectionStatusDialog {
+
+    private TreeViewer fViewer;
+
+	private IBaseLabelProvider fLabelProvider;
+
+    private ITreeContentProvider fContentProvider;
+
+    private ISelectionStatusValidator fValidator = null;
+
+    private ViewerComparator fComparator;
+
+    private boolean fAllowMultiple = true;
+
+    private boolean fDoubleClickSelects = true;
+
+    private String fEmptyListMessage = WorkbenchMessages.get().ElementTreeSelectionDialog_nothing_available;
+
+    private IStatus fCurrStatus = new Status(IStatus.OK, PlatformUI.PLUGIN_ID,
+            IStatus.OK, "", null); //$NON-NLS-1$
+
+    private List fFilters;
+
+    private Object fInput;
+
+    private boolean fIsEmpty;
+
+    private int fWidth = 60;
+
+    private int fHeight = 18;
+
+    /**
+     * Constructs an instance of <code>ElementTreeSelectionDialog</code>.
+     * @param parent The parent shell for the dialog
+     * @param labelProvider   the label provider to render the entries
+     * @param contentProvider the content provider to evaluate the tree structure
+     */
+    public ElementTreeSelectionDialog(Shell parent,
+            ILabelProvider labelProvider, ITreeContentProvider contentProvider) {
+		this(parent, (IBaseLabelProvider) labelProvider, contentProvider);
+	}
+
+	/**
+	 * Constructs an instance of <code>ElementTreeSelectionDialog</code>.
+	 *
+	 * @param parent
+	 *            The parent shell for the dialog
+	 * @param labelProvider
+	 *            the label provider to render the entries. It must be
+	 *            compatible with the Viewerreturned from
+	 *            {@link #doCreateTreeViewer(Composite, int)}
+	 * @param contentProvider
+	 *            the content provider to evaluate the tree structure
+	 * @since 3.106
+	 */
+	public ElementTreeSelectionDialog(Shell parent, IBaseLabelProvider labelProvider,
+			ITreeContentProvider contentProvider) {
+        super(parent);
+
+        fLabelProvider = labelProvider;
+        fContentProvider = contentProvider;
+
+        setResult(new ArrayList(0));
+        setStatusLineAboveButtons(true);
+    }
+
+    /**
+     * Sets the initial selection.
+     * Convenience method.
+     * @param selection the initial selection.
+     */
+    public void setInitialSelection(Object selection) {
+        setInitialSelections(new Object[] { selection });
+    }
+
+    /**
+     * Sets the message to be displayed if the list is empty.
+     * @param message the message to be displayed.
+     */
+    public void setEmptyListMessage(String message) {
+        fEmptyListMessage = message;
+    }
+
+    /**
+     * Specifies if multiple selection is allowed.
+     * @param allowMultiple
+     */
+    public void setAllowMultiple(boolean allowMultiple) {
+        fAllowMultiple = allowMultiple;
+    }
+
+    /**
+     * Specifies if default selected events (double click) are created.
+     * @param doubleClickSelects
+     */
+    public void setDoubleClickSelects(boolean doubleClickSelects) {
+        fDoubleClickSelects = doubleClickSelects;
+    }
+
+    /**
+     * Sets the sorter used by the tree viewer.
+     * @param sorter
+     * @deprecated as of 3.3, use {@link ElementTreeSelectionDialog#setComparator(ViewerComparator)} instead
+     */
+    @Deprecated
+	public void setSorter(ViewerSorter sorter) {
+        fComparator = sorter;
+    }
+
+    /**
+     * Sets the comparator used by the tree viewer.
+     * @param comparator
+     * @since 3.3
+     */
+    public void setComparator(ViewerComparator comparator){
+    	fComparator = comparator;
+    }
+
+    /**
+     * Adds a filter to the tree viewer.
+     * @param filter a filter.
+     */
+    public void addFilter(ViewerFilter filter) {
+        if (fFilters == null) {
+			fFilters = new ArrayList(4);
+		}
+
+        fFilters.add(filter);
+    }
+
+    /**
+     * Sets an optional validator to check if the selection is valid.
+     * The validator is invoked whenever the selection changes.
+     * @param validator the validator to validate the selection.
+     */
+    public void setValidator(ISelectionStatusValidator validator) {
+        fValidator = validator;
+    }
+
+    /**
+     * Sets the tree input.
+     * @param input the tree input.
+     */
+    public void setInput(Object input) {
+        fInput = input;
+    }
+
+    /**
+     * Sets the size of the tree in unit of characters.
+     * @param width  the width of the tree.
+     * @param height the height of the tree.
+     */
+    public void setSize(int width, int height) {
+        fWidth = width;
+        fHeight = height;
+    }
+
+    /**
+     * Validate the receiver and update the ok status.
+     *
+     */
+    protected void updateOKStatus() {
+        if (!fIsEmpty) {
+            if (fValidator != null) {
+                fCurrStatus = fValidator.validate(getResult());
+                updateStatus(fCurrStatus);
+            } else {
+                fCurrStatus = new Status(IStatus.OK, PlatformUI.PLUGIN_ID,
+                        IStatus.OK, "", //$NON-NLS-1$
+                        null);
+            }
+        } else {
+            fCurrStatus = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID,
+                    IStatus.ERROR, fEmptyListMessage, null);
+        }
+        updateStatus(fCurrStatus);
+    }
+
+    @Override
+	public int open() {
+        fIsEmpty = evaluateIfTreeEmpty(fInput);
+        super.open();
+        return getReturnCode();
+    }
+
+    private void access$superCreate() {
+        super.create();
+    }
+
+    /**
+     * Handles cancel button pressed event.
+     */
+    @Override
+	protected void cancelPressed() {
+        setResult(null);
+        super.cancelPressed();
+    }
+
+    @Override
+	protected void computeResult() {
+		setResult(fViewer.getStructuredSelection().toList());
+    }
+
+    @Override
+	public void create() {
+        BusyIndicator.showWhile(null, () -> {
+		    access$superCreate();
+		    fViewer.setSelection(new StructuredSelection(
+		            getInitialElementSelections()), true);
+		    updateOKStatus();
+		});
+    }
+
+    @Override
+	protected Control createDialogArea(Composite parent) {
+        Composite composite = (Composite) super.createDialogArea(parent);
+
+        Label messageLabel = createMessageArea(composite);
+        TreeViewer treeViewer = createTreeViewer(composite);
+
+        GridData data = new GridData(GridData.FILL_BOTH);
+        data.widthHint = convertWidthInCharsToPixels(fWidth);
+        data.heightHint = convertHeightInCharsToPixels(fHeight);
+
+        Tree treeWidget = treeViewer.getTree();
+        treeWidget.setLayoutData(data);
+        treeWidget.setFont(parent.getFont());
+
+        if (fIsEmpty) {
+            messageLabel.setEnabled(false);
+            treeWidget.setEnabled(false);
+        }
+
+        return composite;
+    }
+
+    /**
+     * Creates and initializes the tree viewer.
+     *
+     * @param parent the parent composite
+     * @return the tree viewer
+     * @see #doCreateTreeViewer(Composite, int)
+     */
+    protected TreeViewer createTreeViewer(Composite parent) {
+        int style = SWT.BORDER | (fAllowMultiple ? SWT.MULTI : SWT.SINGLE);
+
+        fViewer = doCreateTreeViewer(parent, style);
+        fViewer.setContentProvider(fContentProvider);
+        fViewer.setLabelProvider(fLabelProvider);
+        fViewer.addSelectionChangedListener(event -> {
+		    access$setResult(((IStructuredSelection) event.getSelection())
+		            .toList());
+		    updateOKStatus();
+		});
+
+        fViewer.setComparator(fComparator);
+        if (fFilters != null) {
+            for (int i = 0; i != fFilters.size(); i++) {
+				fViewer.addFilter((ViewerFilter) fFilters.get(i));
+			}
+        }
+
+        if (fDoubleClickSelects) {
+            Tree tree = fViewer.getTree();
+            tree.addSelectionListener(new SelectionAdapter()
+            {
+                /** {@inheritDoc} */
+                @Override
+                public void widgetDefaultSelected(SelectionEvent e)
+                {
+                    updateOKStatus();
+                    if (fCurrStatus.isOK()) {
+                        access$superButtonPressed(IDialogConstants.OK_ID);
+                    }
+                }
+            });
+        }
+        fViewer.addDoubleClickListener(event -> {
+		    updateOKStatus();
+
+		    //If it is not OK or if double click does not
+		    //select then expand
+		    if (!(fDoubleClickSelects && fCurrStatus.isOK())) {
+		        ISelection selection = event.getSelection();
+		        if (selection instanceof IStructuredSelection) {
+		            Object item = ((IStructuredSelection) selection)
+		                    .getFirstElement();
+		            if (fViewer.getExpandedState(item)) {
+						fViewer.collapseToLevel(item, 1);
+					} else {
+						fViewer.expandToLevel(item, 1);
+					}
+		        }
+		    }
+		});
+
+        fViewer.setInput(fInput);
+
+        return fViewer;
+    }
+
+    /**
+     * Creates the tree viewer.
+     *
+     * @param parent the parent composite
+     * @param style the {@link SWT} style bits
+     * @return the tree viewer
+     * @since 3.4
+	 */
+	protected TreeViewer doCreateTreeViewer(Composite parent, int style) {
+		return new TreeViewer(new Tree(parent, style));
+	}
+
+	/**
+     * Returns the tree viewer.
+     *
+     * @return the tree viewer
+     */
+    protected TreeViewer getTreeViewer() {
+        return fViewer;
+    }
+
+    private boolean evaluateIfTreeEmpty(Object input) {
+        Object[] elements = fContentProvider.getElements(input);
+        if (elements.length > 0) {
+            if (fFilters != null) {
+                for (int i = 0; i < fFilters.size(); i++) {
+                    ViewerFilter curr = (ViewerFilter) fFilters.get(i);
+                    elements = curr.filter(fViewer, input, elements);
+                }
+            }
+        }
+        return elements.length == 0;
+    }
+
+    /**
+     * Set the result using the super class implementation of
+     * buttonPressed.
+     * @param id
+     * @see org.eclipse.jface.dialogs.Dialog#buttonPressed(int)
+     */
+    protected void access$superButtonPressed(int id) {
+        super.buttonPressed(id);
+    }
+
+    /**
+     * Set the result using the super class implementation of
+     * setResult.
+     * @param result
+     * @see SelectionStatusDialog#setResult(int, Object)
+     */
+    protected void access$setResult(List result) {
+        super.setResult(result);
+    }
+
+    @Override
+	protected void handleShellCloseEvent() {
+        super.handleShellCloseEvent();
+
+        //Handle the closing of the shell by selecting the close icon
+        if (getReturnCode() == CANCEL) {
+			setResult(null);
+		}
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/FileEditorMappingContentProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/FileEditorMappingContentProvider.java
new file mode 100644
index 0000000..0b7aadb
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/FileEditorMappingContentProvider.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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.ui.dialogs;
+
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.ui.IFileEditorMapping;
+
+/**
+ * A content provider for displaying of <code>IFileEditorMapping</code>
+ * objects in viewers.
+ * <p>
+ * This class has a singleton instance,
+ * <code>FileEditorMappingContentProvider.INSTANCE</code>,
+ * which can be used any place this kind of content provider is needed.
+ * </p>
+ *
+ * @see org.eclipse.jface.viewers.IContentProvider
+ */
+public class FileEditorMappingContentProvider implements IStructuredContentProvider {
+
+    /**
+     * Singleton instance accessor.
+     */
+    public final static FileEditorMappingContentProvider INSTANCE = new FileEditorMappingContentProvider();
+
+    /**
+     * Creates an instance of this class.  The private visibility of this
+     * constructor ensures that this class is only usable as a singleton.
+     */
+    private FileEditorMappingContentProvider() {
+        super();
+    }
+    
+    @Override
+    public void dispose() {
+    }
+
+    @Override
+	public Object[] getElements(Object element) {
+        IFileEditorMapping[] array = (IFileEditorMapping[]) element;
+        return array == null ? new Object[0] : array;
+    }
+    
+    @Override
+    public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/FileEditorMappingLabelProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/FileEditorMappingLabelProvider.java
new file mode 100644
index 0000000..c30ea46
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/FileEditorMappingLabelProvider.java
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.dialogs;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.osgi.util.TextProcessor;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.IFileEditorMapping;
+
+/**
+ * A label provider for displaying of <code>IFileEditorMapping</code>
+ * objects in viewers.
+ * <p>
+ * This class has a singleton instance,
+ * <code>FileEditorMappingLabelProvider.INSTANCE</code>,
+ * which can be used any place this kind of label provider is needed.
+ * </p>
+ * <p>
+ * The singleton instance hangs on to images, which get freed up when
+ * <code>dispose</code> is called.
+ * </p>
+ *
+ * @see org.eclipse.jface.viewers.ILabelProvider
+ */
+public class FileEditorMappingLabelProvider extends LabelProvider implements
+        ITableLabelProvider {
+
+    /**
+     * Singleton instance accessor.
+     */
+    public final static FileEditorMappingLabelProvider INSTANCE = new FileEditorMappingLabelProvider();
+
+    /**
+     * Images that will require disposal.
+     */
+    private List imagesToDispose = new ArrayList();
+
+    /**
+     * Creates an instance of this class.  The private visibility of this
+     * constructor ensures that this class is only usable as a singleton.
+     */
+    private FileEditorMappingLabelProvider() {
+        super();
+    }
+
+    @Override
+	public void dispose() {
+        super.dispose();
+        for (Iterator e = imagesToDispose.iterator(); e.hasNext();) {
+            ((Image) e.next()).dispose();
+        }
+        imagesToDispose.clear();
+    }
+
+    /**
+     * The <code>ResourceTypeEditorMappingLabelProvider</code> implementation of this
+     * <code>ITableLabelProvider</code> method creates and returns an new image. The
+     * image is remembered internally and will be deallocated by
+     * <code>dispose</code>.
+     */
+    @Override
+	public Image getColumnImage(Object element, int row) {
+        return getImage(element);
+    }
+
+    @Override
+	public String getColumnText(Object element, int row) {
+        return getText(element);
+    }
+
+    /**
+     * The <code>ResourceTypeEditorMappingLabelProvider</code> implementation of this
+     * <code>ILabelProvider</code> method creates and returns an new image. The image
+     * is remembered internally and will be deallocated by <code>dispose</code>.
+     */
+    @Override
+	public Image getImage(Object element) {
+        if (element instanceof IFileEditorMapping) {
+            Image image = ((IFileEditorMapping) element).getImageDescriptor()
+                    .createImage();
+            imagesToDispose.add(image);
+            return image;
+        }
+        return null;
+    }
+
+    @Override
+	public String getText(Object element) {
+        if (element instanceof IFileEditorMapping) {
+			return TextProcessor.process(((IFileEditorMapping) element)
+					.getLabel(), "*."); //$NON-NLS-1$
+		}
+
+		return null;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/FileSystemElement.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/FileSystemElement.java
new file mode 100644
index 0000000..b742fff
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/FileSystemElement.java
@@ -0,0 +1,268 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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.ui.dialogs;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.model.AdaptableList;
+import org.eclipse.ui.model.IWorkbenchAdapter;
+
+/**
+ * Instances of this class represent files or file-like entities (eg.- zip file
+ * entries) on the local file system. They do not represent resources within the
+ * workbench. This distinction is made because the representation of a file
+ * system resource is significantly different from that of a workbench resource.
+ *
+ * If self represents a collection (eg.- file system directory, zip directory)
+ * then its icon will be the folderIcon static field. Otherwise (ie.- self
+ * represents a file system file) self's icon is stored in field "icon", and is
+ * determined by the extension of the file that self represents.
+ *
+ * This class is adaptable, and implements one adapter itself, namely the
+ * IWorkbenchAdapter adapter used for navigation and display in the workbench.
+ */
+public class FileSystemElement implements IAdaptable {
+    private String name;
+
+    private Object fileSystemObject;
+
+    /*
+     * Wait until a child is added to initialize the receiver's lists. Doing so
+     * minimizes the amount of memory that is allocated when a large directory
+     * structure is being processed.
+     */
+    private AdaptableList folders = null;
+
+    private AdaptableList files = null;
+
+    private boolean isDirectory = false;
+
+    private FileSystemElement parent;
+
+    private IWorkbenchAdapter workbenchAdapter = new IWorkbenchAdapter() {
+        /**
+         * Answer the children property of this element
+         */
+        @Override
+		public Object[] getChildren(Object o) {
+            return getFolders().getChildren(o);
+        }
+
+        /**
+         * Returns the parent of this element
+         */
+        @Override
+		public Object getParent(Object o) {
+            return parent;
+        }
+
+        /**
+         * Returns an appropriate label for this file system element.
+         */
+        @Override
+		public String getLabel(Object o) {
+            return name;
+        }
+
+        /**
+         * Returns an image descriptor for this file system element
+         */
+        @Override
+		public ImageDescriptor getImageDescriptor(Object object) {
+            if (isDirectory()) {
+                return WorkbenchImages
+                        .getImageDescriptor(ISharedImages.IMG_OBJ_FOLDER);
+            } else {
+                return WorkbenchPlugin.getDefault().getEditorRegistry()
+                        .getImageDescriptor(name);
+				//TODO: what are the implications for content types?  Should I guess?
+            }
+        }
+    };
+
+    /**
+     * Creates a new <code>FileSystemElement</code> and initializes it and its
+     * parent if applicable.
+     *
+     * @param name
+     *            The name of the element
+     * @param parent
+     *            The parent element. May be <code>null</code>
+     * @param isDirectory
+     *            if <code>true</code> this is representing a directory,
+     *            otherwise it is a file.
+     */
+    public FileSystemElement(String name, FileSystemElement parent,
+            boolean isDirectory) {
+        this.name = name;
+        this.parent = parent;
+        this.isDirectory = isDirectory;
+        if (parent != null) {
+			parent.addChild(this);
+		}
+    }
+
+    /**
+     * Adds the passed child to this object's collection of children.
+     *
+     * @param child
+     *            FileSystemElement
+     */
+    public void addChild(FileSystemElement child) {
+        if (child.isDirectory()) {
+            if (folders == null) {
+				folders = new AdaptableList(1);
+			}
+            folders.add(child);
+        } else {
+            if (files == null) {
+				files = new AdaptableList(1);
+			}
+            files.add(child);
+        }
+    }
+
+    /**
+     * Returns the adapter
+     */
+	@Override
+	public <T> T getAdapter(Class<T> adapter) {
+        if (adapter == IWorkbenchAdapter.class) {
+			return adapter.cast(workbenchAdapter);
+        }
+        //defer to the platform
+        return Platform.getAdapterManager().getAdapter(this, adapter);
+    }
+
+    /**
+     * Returns the extension of this element's filename.
+     *
+     * @return The extension or an empty string if there is no extension.
+     */
+    public String getFileNameExtension() {
+        int lastDot = name.lastIndexOf('.');
+        return lastDot < 0 ? "" : name.substring(lastDot + 1); //$NON-NLS-1$
+    }
+
+    /**
+     * Answer the files property of this element. Answer an empty list if the
+     * files property is null. This method should not be used to add children to
+     * the receiver. Use addChild(FileSystemElement) instead.
+     *
+     * @return AdaptableList The list of files parented by the receiver.
+     */
+    public AdaptableList getFiles() {
+        if (files == null) {
+            // lazily initialize (can't share result since it's modifiable)
+            files = new AdaptableList(0);
+        }
+        return files;
+    }
+
+    /**
+     * Returns the file system object property of this element
+     *
+     * @return the file system object
+     */
+    public Object getFileSystemObject() {
+        return fileSystemObject;
+    }
+
+    /**
+     * Returns a list of the folders that are immediate children of this folder.
+     * Answer an empty list if the folders property is null. This method should
+     * not be used to add children to the receiver. Use
+     * addChild(FileSystemElement) instead.
+     *
+     * @return AdapatableList The list of folders parented by the receiver.
+     */
+    public AdaptableList getFolders() {
+        if (folders == null) {
+            // lazily initialize (can't share result since it's modifiable)
+            folders = new AdaptableList(0);
+        }
+        return folders;
+    }
+
+    /**
+     * Return the parent of this element.
+     *
+     * @return the parent file system element, or <code>null</code> if this is
+     *         the root
+     */
+    public FileSystemElement getParent() {
+        return this.parent;
+    }
+
+    /**
+     * @return boolean <code>true</code> if this element represents a
+     *         directory, and <code>false</code> otherwise.
+     */
+    public boolean isDirectory() {
+        return isDirectory;
+    }
+
+    /**
+     * Removes a sub-folder from this file system element.
+     * @param child The child to remove.
+     */
+    public void removeFolder(FileSystemElement child) {
+        if (folders == null) {
+			return;
+		}
+        folders.remove(child);
+        child.setParent(null);
+    }
+
+    /**
+     * Set the file system object property of this element
+     *
+     * @param value
+     *            the file system object
+     */
+    public void setFileSystemObject(Object value) {
+        fileSystemObject = value;
+    }
+
+    /**
+     * Sets the parent of this file system element.
+     * @param element The new parent.
+     */
+    public void setParent(FileSystemElement element) {
+        parent = element;
+    }
+
+    /**
+     * For debugging purposes only.
+     */
+    @Override
+	public String toString() {
+        StringBuffer buf = new StringBuffer();
+        if (isDirectory()) {
+            buf.append("Folder(");//$NON-NLS-1$
+        } else {
+            buf.append("File(");//$NON-NLS-1$
+        }
+        buf.append(name).append(")");//$NON-NLS-1$
+        if (!isDirectory()) {
+            return buf.toString();
+        }
+        buf.append(" folders: ");//$NON-NLS-1$
+        buf.append(folders);
+        buf.append(" files: ");//$NON-NLS-1$
+        buf.append(files);
+        return buf.toString();
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/FilteredItemsSelectionDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/FilteredItemsSelectionDialog.java
new file mode 100644
index 0000000..69983f1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/FilteredItemsSelectionDialog.java
@@ -0,0 +1,3113 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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
+ *  Willian Mitsuda <wmitsuda@gmail.com>
+ *     - Fix for bug 196553 - [Dialogs] Support IColorProvider/IFontProvider in FilteredItemsSelectionDialog
+ *  Peter Friese <peter.friese@gentleware.com>
+ *     - Fix for bug 208602 - [Dialogs] Open Type dialog needs accessible labels
+ *  Simon Muschel <smuschel@gmx.de> - bug 258493
+ *  Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *  Patrik Suzzi <psuzzi@gmail.com> - Bug 485133
+ *******************************************************************************/
+package org.eclipse.ui.dialogs;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.ProgressMonitorWrapper;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.ActionContributionItem;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.LegacyActionTools;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.viewers.CellLabelProvider;
+import org.eclipse.jface.viewers.ContentViewer;
+import org.eclipse.jface.viewers.IColorProvider;
+import org.eclipse.jface.viewers.IContentProvider;
+import org.eclipse.jface.viewers.IFontProvider;
+import org.eclipse.jface.viewers.ILabelDecorator;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.ILazyContentProvider;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.LabelProviderChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerCell;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CLabel;
+import org.eclipse.swt.custom.ViewForm;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+import org.eclipse.ui.ActiveShellExpression;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.IWorkbenchPreferenceConstants;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.WorkbenchException;
+import org.eclipse.ui.XMLMemento;
+import org.eclipse.ui.handlers.IHandlerActivation;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.progress.UIJob;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+/**
+ * Shows a list of items to the user with a text entry field for a string
+ * pattern used to filter the list of items.
+ *
+ * @since 3.3
+ */
+public abstract class FilteredItemsSelectionDialog extends SelectionStatusDialog {
+
+	private static final String DIALOG_BOUNDS_SETTINGS = "DialogBoundsSettings"; //$NON-NLS-1$
+
+	private static final String SHOW_STATUS_LINE = "ShowStatusLine"; //$NON-NLS-1$
+
+	private static final String HISTORY_SETTINGS = "History"; //$NON-NLS-1$
+
+	private static final String DIALOG_HEIGHT = "DIALOG_HEIGHT"; //$NON-NLS-1$
+
+	private static final String DIALOG_WIDTH = "DIALOG_WIDTH"; //$NON-NLS-1$
+
+	/**
+	 * Represents an empty selection in the pattern input field (used only for
+	 * initial pattern).
+	 */
+	public static final int NONE = 0;
+
+	/**
+	 * Pattern input field selection where caret is at the beginning (used only
+	 * for initial pattern).
+	 */
+	public static final int CARET_BEGINNING = 1;
+
+	/**
+	 * Represents a full selection in the pattern input field (used only for
+	 * initial pattern).
+	 */
+	public static final int FULL_SELECTION = 2;
+
+	private Text pattern;
+
+	private TableViewer list;
+
+	private DetailsContentViewer details;
+
+	/**
+	 * It is a duplicate of a field in the CLabel class in DetailsContentViewer.
+	 * It is maintained, because the <code>setDetailsLabelProvider()</code>
+	 * could be called before content area is created.
+	 */
+	private ILabelProvider detailsLabelProvider;
+
+	private ItemsListLabelProvider itemsListLabelProvider;
+
+	private MenuManager menuManager;
+
+	private MenuManager contextMenuManager;
+
+	private boolean multi;
+
+	private ToolBar toolBar;
+
+	private ToolItem toolItem;
+
+	private Label progressLabel;
+
+	private ToggleStatusLineAction toggleStatusLineAction;
+
+	private RemoveHistoryItemAction removeHistoryItemAction;
+
+	private ActionContributionItem removeHistoryActionContributionItem;
+
+	private IStatus status;
+
+	private RefreshCacheJob refreshCacheJob;
+
+	private RefreshProgressMessageJob refreshProgressMessageJob = new RefreshProgressMessageJob();
+
+	private Object[] currentSelection;
+
+	private ContentProvider contentProvider;
+
+	private FilterHistoryJob filterHistoryJob;
+
+	private FilterJob filterJob;
+
+	private ItemsFilter filter;
+
+	private List lastCompletedResult;
+
+	private ItemsFilter lastCompletedFilter;
+
+	private String initialPatternText;
+
+	private int selectionMode;
+
+	private ItemsListSeparator itemsListSeparator;
+
+	private static final String EMPTY_STRING = ""; //$NON-NLS-1$
+
+	private boolean refreshWithLastSelection = false;
+
+	private IHandlerActivation showViewHandler;
+
+	/**
+	 * Creates a new instance of the class.
+	 *
+	 * @param shell
+	 *            shell to parent the dialog on
+	 * @param multi
+	 *            indicates whether dialog allows to select more than one
+	 *            position in its list of items
+	 */
+	public FilteredItemsSelectionDialog(Shell shell, boolean multi) {
+		super(shell);
+		this.multi = multi;
+		filterHistoryJob = new FilterHistoryJob();
+		filterJob = new FilterJob();
+		contentProvider = new ContentProvider();
+		refreshCacheJob = new RefreshCacheJob();
+		itemsListSeparator = new ItemsListSeparator(
+				WorkbenchMessages.get().FilteredItemsSelectionDialog_separatorLabel);
+		selectionMode = NONE;
+	}
+
+	/**
+	 * Creates a new instance of the class. Created dialog won't allow to select
+	 * more than one item.
+	 *
+	 * @param shell
+	 *            shell to parent the dialog on
+	 */
+	public FilteredItemsSelectionDialog(Shell shell) {
+		this(shell, false);
+	}
+
+	/**
+	 * Adds viewer filter to the dialog items list.
+	 *
+	 * @param filter
+	 *            the new filter
+	 */
+	protected void addListFilter(ViewerFilter filter) {
+		contentProvider.addFilter(filter);
+	}
+
+	/**
+	 * Sets a new label provider for items in the list. If the label provider
+	 * also implements {@link
+	 * org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider
+	 * .IStyledLabelProvider}, the style text labels provided by it will be used
+	 * provided that the corresponding preference is set.
+	 *
+	 * @see IWorkbenchPreferenceConstants#USE_COLORED_LABELS
+	 *
+	 * @param listLabelProvider
+	 * 		the label provider for items in the list
+	 */
+	public void setListLabelProvider(ILabelProvider listLabelProvider) {
+		getItemsListLabelProvider().setProvider(listLabelProvider);
+	}
+
+	/**
+	 * Returns the label decorator for selected items in the list.
+	 *
+	 * @return the label decorator for selected items in the list
+	 */
+	private ILabelDecorator getListSelectionLabelDecorator() {
+		return getItemsListLabelProvider().getSelectionDecorator();
+	}
+
+	/**
+	 * Sets the label decorator for selected items in the list.
+	 *
+	 * @param listSelectionLabelDecorator
+	 *            the label decorator for selected items in the list
+	 */
+	public void setListSelectionLabelDecorator(
+			ILabelDecorator listSelectionLabelDecorator) {
+		getItemsListLabelProvider().setSelectionDecorator(
+				listSelectionLabelDecorator);
+	}
+
+	/**
+	 * Returns the item list label provider.
+	 *
+	 * @return the item list label provider
+	 */
+	private ItemsListLabelProvider getItemsListLabelProvider() {
+		if (itemsListLabelProvider == null) {
+			itemsListLabelProvider = new ItemsListLabelProvider(
+					new LabelProvider(), null);
+		}
+		return itemsListLabelProvider;
+	}
+
+	/**
+	 * Sets label provider for the details field.
+	 *
+	 * For a single selection, the element sent to
+	 * {@link ILabelProvider#getImage(Object)} and
+	 * {@link ILabelProvider#getText(Object)} is the selected object, for
+	 * multiple selection a {@link String} with amount of selected items is the
+	 * element.
+	 *
+	 * @see #getSelectedItems() getSelectedItems() can be used to retrieve
+	 *      selected items and get the items count.
+	 *
+	 * @param detailsLabelProvider
+	 *            the label provider for the details field
+	 */
+	public void setDetailsLabelProvider(ILabelProvider detailsLabelProvider) {
+		this.detailsLabelProvider = detailsLabelProvider;
+		if (details != null) {
+			details.setLabelProvider(detailsLabelProvider);
+		}
+	}
+
+	private ILabelProvider getDetailsLabelProvider() {
+		if (detailsLabelProvider == null) {
+			detailsLabelProvider = new LabelProvider();
+		}
+		return detailsLabelProvider;
+	}
+
+	@Override
+	public void create() {
+		super.create();
+		pattern.setFocus();
+	}
+
+	/**
+	 * Restores dialog using persisted settings. The default implementation
+	 * restores the status of the details line and the selection history.
+	 *
+	 * @param settings
+	 *            settings used to restore dialog
+	 */
+	protected void restoreDialog(IDialogSettings settings) {
+		boolean toggleStatusLine = true;
+
+		if (settings.get(SHOW_STATUS_LINE) != null) {
+			toggleStatusLine = settings.getBoolean(SHOW_STATUS_LINE);
+		}
+
+		toggleStatusLineAction.setChecked(toggleStatusLine);
+
+		details.setVisible(toggleStatusLine);
+
+		String setting = settings.get(HISTORY_SETTINGS);
+		if (setting != null) {
+			try {
+				IMemento memento = XMLMemento.createReadRoot(new StringReader(
+						setting));
+				this.contentProvider.loadHistory(memento);
+			} catch (WorkbenchException e) {
+				// Simply don't restore the settings
+				StatusManager
+						.getManager()
+						.handle(
+								new Status(
+										IStatus.ERROR,
+										PlatformUI.PLUGIN_ID,
+										IStatus.ERROR,
+										WorkbenchMessages.get().FilteredItemsSelectionDialog_restoreError,
+										e));
+			}
+		}
+	}
+
+	@Override
+	public boolean close() {
+		this.filterJob.cancel();
+		this.refreshCacheJob.cancel();
+		this.refreshProgressMessageJob.cancel();
+		if (showViewHandler != null) {
+			IHandlerService service = PlatformUI
+					.getWorkbench().getService(IHandlerService.class);
+			service.deactivateHandler(showViewHandler);
+			showViewHandler.getHandler().dispose();
+			showViewHandler = null;
+		}
+		if (menuManager != null)
+			menuManager.dispose();
+		if (contextMenuManager != null)
+			contextMenuManager.dispose();
+		storeDialog(getDialogSettings());
+		return super.close();
+	}
+
+	/**
+	 * Stores dialog settings.
+	 *
+	 * @param settings
+	 *            settings used to store dialog
+	 */
+	protected void storeDialog(IDialogSettings settings) {
+		settings.put(SHOW_STATUS_LINE, toggleStatusLineAction.isChecked());
+
+		XMLMemento memento = XMLMemento.createWriteRoot(HISTORY_SETTINGS);
+		this.contentProvider.saveHistory(memento);
+		StringWriter writer = new StringWriter();
+		try {
+			memento.save(writer);
+			settings.put(HISTORY_SETTINGS, writer.getBuffer().toString());
+		} catch (IOException e) {
+			// Simply don't store the settings
+			StatusManager
+					.getManager()
+					.handle(
+							new Status(
+									IStatus.ERROR,
+									PlatformUI.PLUGIN_ID,
+									IStatus.ERROR,
+									WorkbenchMessages.get().FilteredItemsSelectionDialog_storeError,
+									e));
+		}
+	}
+
+	/**
+	 * Create a new header which is labelled by headerLabel.
+	 *
+	 * @param parent
+	 * @return Label the label of the header
+	 */
+	private Label createHeader(Composite parent) {
+		Composite header = new Composite(parent, SWT.NONE);
+
+		GridLayout layout = new GridLayout();
+		layout.numColumns = 2;
+		layout.marginWidth = 0;
+		layout.marginHeight = 0;
+		header.setLayout(layout);
+
+		Label headerLabel = new Label(header, SWT.NONE);
+		headerLabel.setText((getMessage() != null && getMessage().trim()
+				.length() > 0) ? getMessage()
+				: WorkbenchMessages.get().FilteredItemsSelectionDialog_patternLabel);
+        // RAP [rh] Traverse events missing     
+//      headerLabel.addTraverseListener(new TraverseListener() {
+//          public void keyTraversed(TraverseEvent e) {
+//              if (e.detail == SWT.TRAVERSE_MNEMONIC && e.doit) {
+//                  e.detail = SWT.TRAVERSE_NONE;
+//                  pattern.setFocus();
+//              }
+//          }
+//      });
+
+		GridData gd = new GridData(GridData.FILL_HORIZONTAL);
+		headerLabel.setLayoutData(gd);
+
+		createViewMenu(header);
+		header.setLayoutData(gd);
+		return headerLabel;
+	}
+
+	/**
+	 * Create the labels for the list and the progress. Return the list label.
+	 *
+	 * @param parent
+	 * @return Label
+	 */
+	private Label createLabels(Composite parent) {
+		Composite labels = new Composite(parent, SWT.NONE);
+
+		GridLayout layout = new GridLayout();
+		layout.numColumns = 2;
+		layout.marginWidth = 0;
+		layout.marginHeight = 0;
+		labels.setLayout(layout);
+
+		Label listLabel = new Label(labels, SWT.NONE);
+		listLabel
+				.setText(WorkbenchMessages.get().FilteredItemsSelectionDialog_listLabel);
+
+        // RAP [rh] Traverse events missing
+//      listLabel.addTraverseListener(new TraverseListener() {
+//          public void keyTraversed(TraverseEvent e) {
+//              if (e.detail == SWT.TRAVERSE_MNEMONIC && e.doit) {
+//                  e.detail = SWT.TRAVERSE_NONE;
+//                  list.getTable().setFocus();
+//              }
+//          }
+//      });
+
+		GridData gd = new GridData(GridData.FILL_HORIZONTAL);
+		listLabel.setLayoutData(gd);
+
+		progressLabel = new Label(labels, SWT.RIGHT);
+		progressLabel.setLayoutData(gd);
+
+		labels.setLayoutData(gd);
+		return listLabel;
+	}
+
+	private void createViewMenu(Composite parent) {
+		toolBar = new ToolBar(parent, SWT.FLAT);
+		toolItem = new ToolItem(toolBar, SWT.PUSH, 0);
+
+		GridData data = new GridData();
+		data.horizontalAlignment = GridData.END;
+		toolBar.setLayoutData(data);
+
+		toolBar.addMouseListener(new MouseAdapter() {
+			@Override
+			public void mouseDown(MouseEvent e) {
+				showViewMenu();
+			}
+		});
+
+		toolItem.setImage(WorkbenchImages
+				.getImage(IWorkbenchGraphicConstants.IMG_LCL_VIEW_MENU));
+		toolItem
+				.setToolTipText(WorkbenchMessages.get().FilteredItemsSelectionDialog_menu);
+		toolItem.addSelectionListener(new SelectionAdapter() {
+		    @Override
+		    public void widgetSelected(SelectionEvent e) {
+		        showViewMenu();
+		    }
+		});
+
+		menuManager = new MenuManager();
+
+		fillViewMenu(menuManager);
+
+		IHandlerService service = PlatformUI.getWorkbench()
+				.getService(IHandlerService.class);
+		IHandler handler = new AbstractHandler() {
+			@Override
+			public Object execute(ExecutionEvent event) {
+				showViewMenu();
+				return null;
+			}
+		};
+		showViewHandler = service.activateHandler(
+				IWorkbenchCommandConstants.WINDOW_SHOW_VIEW_MENU, handler,
+				new ActiveShellExpression(getShell()));
+	}
+
+	/**
+	 * Fills the menu of the dialog.
+	 *
+	 * @param menuManager
+	 *            the menu manager
+	 */
+	protected void fillViewMenu(IMenuManager menuManager) {
+		toggleStatusLineAction = new ToggleStatusLineAction();
+		menuManager.add(toggleStatusLineAction);
+	}
+
+	private void showViewMenu() {
+		Menu menu = menuManager.createContextMenu(getShell());
+		Rectangle bounds = toolItem.getBounds();
+		Point topLeft = new Point(bounds.x, bounds.y + bounds.height);
+		topLeft = toolBar.toDisplay(topLeft);
+		menu.setLocation(topLeft.x, topLeft.y);
+		menu.setVisible(true);
+	}
+
+    /**
+     * Hook that allows to add actions to the context menu.
+	 * <p>
+	 * Subclasses may extend in order to add other actions.</p>
+     *
+     * @param menuManager the context menu manager
+     * @since 3.5
+     */
+	protected void fillContextMenu(IMenuManager menuManager) {
+		List selectedElements = list.getStructuredSelection().toList();
+
+		Object item= null;
+
+		for (Iterator it= selectedElements.iterator(); it.hasNext();) {
+			item= it.next();
+			if (item instanceof ItemsListSeparator || !isHistoryElement(item)) {
+				return;
+			}
+		}
+
+		if (selectedElements.size() > 0) {
+			removeHistoryItemAction.setText(WorkbenchMessages.get().FilteredItemsSelectionDialog_removeItemsFromHistoryAction);
+
+			menuManager.add(removeHistoryActionContributionItem);
+
+		}
+	}
+
+	private void createPopupMenu() {
+		removeHistoryItemAction = new RemoveHistoryItemAction();
+		removeHistoryActionContributionItem = new ActionContributionItem(removeHistoryItemAction);
+
+		contextMenuManager = new MenuManager();
+		contextMenuManager.setRemoveAllWhenShown(true);
+		contextMenuManager.addMenuListener(manager -> fillContextMenu(manager));
+
+		final Table table = list.getTable();
+		Menu menu= contextMenuManager.createContextMenu(table);
+		table.setMenu(menu);
+	}
+
+	/**
+	 * Creates an extra content area, which will be located above the details.
+	 *
+	 * @param parent
+	 *            parent to create the dialog widgets in
+	 * @return an extra content area
+	 */
+	protected abstract Control createExtendedContentArea(Composite parent);
+
+	@Override
+	protected Control createDialogArea(Composite parent) {
+		Composite dialogArea = (Composite) super.createDialogArea(parent);
+
+		Composite content = new Composite(dialogArea, SWT.NONE);
+		GridData gd = new GridData(GridData.FILL_BOTH);
+		content.setLayoutData(gd);
+
+		GridLayout layout = new GridLayout();
+		layout.numColumns = 1;
+		layout.marginWidth = 0;
+		layout.marginHeight = 0;
+		content.setLayout(layout);
+
+		// RAP [rh] workaround "unused variable" compile error
+//		final Label headerLabel = createHeader(content);
+		createHeader(content);
+
+		pattern = new Text(content, SWT.SINGLE | SWT.BORDER | SWT.SEARCH | SWT.ICON_CANCEL);
+		// RAP [rh] Accessibility API missing
+//		pattern.getAccessible().addAccessibleListener(new AccessibleAdapter() {
+//			public void getName(AccessibleEvent e) {
+//				e.result = LegacyActionTools.removeMnemonics(headerLabel
+//						.getText());
+//			}
+//		});
+		gd = new GridData(GridData.FILL_HORIZONTAL);
+		pattern.setLayoutData(gd);
+
+		// RAP [rh] wor around "unused variable" compile error    
+//		final Label listLabel = createLabels(content);
+      createLabels(content);
+
+		list = new TableViewer(content, (multi ? SWT.MULTI : SWT.SINGLE)
+				| SWT.BORDER | SWT.V_SCROLL | SWT.VIRTUAL);
+		// RAP [rh] Accessibility API missing
+//		list.getTable().getAccessible().addAccessibleListener(
+//				new AccessibleAdapter() {
+//					public void getName(AccessibleEvent e) {
+//						e.result = LegacyActionTools.removeMnemonics(listLabel
+//								.getText());
+//					}
+//				});
+		list.setContentProvider(contentProvider);
+		list.setLabelProvider(getItemsListLabelProvider());
+		list.setInput(new Object[0]);
+		list.setItemCount(contentProvider.getNumberOfElements());
+		gd = new GridData(GridData.FILL_BOTH);
+		applyDialogFont(list.getTable());
+		gd.heightHint= list.getTable().getItemHeight() * 15;
+		list.getTable().setLayoutData(gd);
+
+		createPopupMenu();
+
+		pattern.addModifyListener(e -> applyFilter());
+
+		pattern.addKeyListener(new KeyAdapter() {
+			@Override
+			public void keyPressed(KeyEvent e) {
+				if (e.keyCode == SWT.ARROW_DOWN) {
+					if (list.getTable().getItemCount() > 0) {
+						list.getTable().setFocus();
+					}
+				}
+			}
+		});
+
+		list.addSelectionChangedListener(event -> {
+			StructuredSelection selection = (StructuredSelection) event.getSelection();
+			handleSelected(selection);
+		});
+
+		list.addDoubleClickListener(event -> handleDoubleClick());
+
+		list.getTable().addKeyListener(new KeyAdapter() {
+			@Override
+			public void keyPressed(KeyEvent e) {
+
+				if (e.keyCode == SWT.DEL) {
+
+					List selectedElements = ((StructuredSelection) list
+							.getSelection()).toList();
+
+					Object item = null;
+					boolean isSelectedHistory = true;
+
+					for (Iterator it = selectedElements.iterator(); it
+							.hasNext();) {
+						item = it.next();
+						if (item instanceof ItemsListSeparator
+								|| !isHistoryElement(item)) {
+							isSelectedHistory = false;
+							break;
+						}
+					}
+					if (isSelectedHistory)
+						removeSelectedItems(selectedElements);
+
+				}
+
+				if (e.keyCode == SWT.ARROW_UP && (e.stateMask & SWT.SHIFT) != 0
+						&& (e.stateMask & SWT.CTRL) != 0) {
+					IStructuredSelection selection = list.getStructuredSelection();
+
+					if (selection.size() == 1) {
+						Object element = selection.getFirstElement();
+						if (element.equals(list.getElementAt(0))) {
+							pattern.setFocus();
+						}
+						if (list.getElementAt(list.getTable()
+								.getSelectionIndex() - 1) instanceof ItemsListSeparator)
+							list.getTable().setSelection(
+									list.getTable().getSelectionIndex() - 1);
+						list.getTable().notifyListeners(SWT.Selection, new Event());
+
+					}
+				}
+
+				if (e.keyCode == SWT.ARROW_DOWN
+						&& (e.stateMask & SWT.SHIFT) != 0
+						&& (e.stateMask & SWT.CTRL) != 0) {
+
+					if (list
+							.getElementAt(list.getTable().getSelectionIndex() + 1) instanceof ItemsListSeparator)
+						list.getTable().setSelection(
+								list.getTable().getSelectionIndex() + 1);
+					list.getTable().notifyListeners(SWT.Selection, new Event());
+				}
+
+			}
+		});
+
+		createExtendedContentArea(content);
+
+		details = new DetailsContentViewer(content, SWT.BORDER | SWT.FLAT);
+		details.setVisible(toggleStatusLineAction.isChecked());
+		details.setContentProvider(new NullContentProvider());
+		details.setLabelProvider(getDetailsLabelProvider());
+
+		applyDialogFont(content);
+
+		restoreDialog(getDialogSettings());
+
+		if (initialPatternText != null) {
+			pattern.setText(initialPatternText);
+		}
+
+		switch (selectionMode) {
+		case CARET_BEGINNING:
+			pattern.setSelection(0, 0);
+			break;
+		case FULL_SELECTION:
+			pattern.setSelection(0, initialPatternText.length());
+			break;
+		}
+
+		// apply filter even if pattern is empty (display history)
+		applyFilter();
+
+		return dialogArea;
+	}
+
+	/**
+	 * This method is a hook for subclasses to override default dialog behavior.
+	 * The <code>handleDoubleClick()</code> method handles double clicks on
+	 * the list of filtered elements.
+	 * <p>
+	 * Current implementation makes double-clicking on the list do the same as
+	 * pressing <code>OK</code> button on the dialog.
+	 */
+	protected void handleDoubleClick() {
+		okPressed();
+	}
+
+	/**
+	 * Refreshes the details field according to the current selection in the
+	 * items list.
+	 */
+	private void refreshDetails() {
+		StructuredSelection selection = getSelectedItems();
+
+		switch (selection.size()) {
+		case 0:
+			details.setInput(null);
+			break;
+		case 1:
+			details.setInput(selection.getFirstElement());
+			break;
+		default:
+			details
+					.setInput(NLS
+							.bind(
+									WorkbenchMessages.get().FilteredItemsSelectionDialog_nItemsSelected,
+									Integer.valueOf(selection.size())));
+			break;
+		}
+
+	}
+
+	/**
+	 * Handle selection in the items list by updating labels of selected and
+	 * unselected items and refresh the details field using the selection.
+	 *
+	 * @param selection
+	 *            the new selection
+	 */
+	protected void handleSelected(StructuredSelection selection) {
+		IStatus status = new Status(IStatus.OK, PlatformUI.PLUGIN_ID,
+				IStatus.OK, EMPTY_STRING, null);
+
+		Object[] lastSelection = currentSelection;
+
+		currentSelection = selection.toArray();
+
+		if (selection.size() == 0) {
+			status = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID,
+					IStatus.ERROR, EMPTY_STRING, null);
+
+			if (lastSelection != null
+					&& getListSelectionLabelDecorator() != null) {
+				list.update(lastSelection, null);
+			}
+
+			currentSelection = null;
+
+		} else {
+			status = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID,
+					IStatus.ERROR, EMPTY_STRING, null);
+
+			List items = selection.toList();
+
+			Object item = null;
+			IStatus tempStatus = null;
+
+			for (Iterator it = items.iterator(); it.hasNext();) {
+				Object o = it.next();
+
+				if (o instanceof ItemsListSeparator) {
+					continue;
+				}
+
+				item = o;
+				tempStatus = validateItem(item);
+
+				if (tempStatus.isOK()) {
+					status = new Status(IStatus.OK, PlatformUI.PLUGIN_ID,
+							IStatus.OK, EMPTY_STRING, null);
+				} else {
+					status = tempStatus;
+					// if any selected element is not valid status is set to
+					// ERROR
+					break;
+				}
+			}
+
+			if (lastSelection != null
+					&& getListSelectionLabelDecorator() != null) {
+				list.update(lastSelection, null);
+			}
+
+			if (getListSelectionLabelDecorator() != null) {
+				list.update(currentSelection, null);
+			}
+		}
+
+		refreshDetails();
+		updateStatus(status);
+	}
+
+	@Override
+	protected IDialogSettings getDialogBoundsSettings() {
+		IDialogSettings settings = getDialogSettings();
+		IDialogSettings section = settings.getSection(DIALOG_BOUNDS_SETTINGS);
+		if (section == null) {
+			section = settings.addNewSection(DIALOG_BOUNDS_SETTINGS);
+			section.put(DIALOG_HEIGHT, 500);
+			section.put(DIALOG_WIDTH, 600);
+		}
+		return section;
+	}
+
+	/**
+	 * Returns the dialog settings. Returned object can't be null.
+	 *
+	 * @return return dialog settings for this dialog
+	 */
+	protected abstract IDialogSettings getDialogSettings();
+
+	/**
+	 * Refreshes the dialog - has to be called in UI thread.
+	 */
+	public void refresh() {
+		if (list != null && !list.getTable().isDisposed()) {
+
+			List lastRefreshSelection = ((StructuredSelection) list
+					.getSelection()).toList();
+			list.getTable().deselectAll();
+
+			list.setItemCount(contentProvider.getNumberOfElements());
+			list.refresh();
+
+			if (list.getTable().getItemCount() > 0) {
+				// preserve previous selection
+				if (refreshWithLastSelection && lastRefreshSelection != null
+						&& lastRefreshSelection.size() > 0) {
+					list.setSelection(new StructuredSelection(
+							lastRefreshSelection));
+				} else {
+					refreshWithLastSelection = true;
+					list.getTable().setSelection(0);
+					list.getTable().notifyListeners(SWT.Selection, new Event());
+				}
+			} else {
+				list.setSelection(StructuredSelection.EMPTY);
+			}
+
+		}
+
+		scheduleProgressMessageRefresh();
+	}
+
+	/**
+	 * Updates the progress label.
+	 *
+	 * @deprecated
+	 */
+	@Deprecated
+	public void updateProgressLabel() {
+		scheduleProgressMessageRefresh();
+	}
+
+	/**
+	 * Notifies the content provider - fires filtering of content provider
+	 * elements. During the filtering, a separator between history and workspace
+	 * matches is added.
+	 * <p>
+	 * This is a long running operation and should be called in a job.
+	 *
+	 * @param checkDuplicates
+	 *            <code>true</code> if data concerning elements duplication
+	 *            should be computed - it takes much more time than the standard
+	 *            filtering
+	 * @param monitor
+	 *            a progress monitor or <code>null</code> if no monitor is
+	 *            available
+	 */
+	public void reloadCache(boolean checkDuplicates, IProgressMonitor monitor) {
+		if (list != null && !list.getTable().isDisposed()
+				&& contentProvider != null) {
+			contentProvider.reloadCache(checkDuplicates, monitor);
+		}
+	}
+
+	/**
+	 * Schedule refresh job.
+	 */
+	public void scheduleRefresh() {
+		refreshCacheJob.cancelAll();
+		refreshCacheJob.schedule();
+	}
+
+	/**
+	 * Schedules progress message refresh.
+	 */
+	public void scheduleProgressMessageRefresh() {
+		if (filterJob.getState() != Job.RUNNING
+				&& refreshProgressMessageJob.getState() != Job.RUNNING)
+			refreshProgressMessageJob.scheduleProgressRefresh(null);
+	}
+
+	@Override
+	protected void computeResult() {
+
+		List selectedElements = list.getStructuredSelection().toList();
+
+		List objectsToReturn = new ArrayList();
+
+		Object item = null;
+
+		for (Iterator it = selectedElements.iterator(); it.hasNext();) {
+			item = it.next();
+
+			if (!(item instanceof ItemsListSeparator)) {
+				accessedHistoryItem(item);
+				objectsToReturn.add(item);
+			}
+		}
+
+		setResult(objectsToReturn);
+	}
+
+	/*
+	 * @see org.eclipse.ui.dialogs.SelectionStatusDialog#updateStatus(org.eclipse.core.runtime.IStatus)
+	 */
+	@Override
+	protected void updateStatus(IStatus status) {
+		this.status = status;
+		super.updateStatus(status);
+	}
+
+	/*
+	 * @see Dialog#okPressed()
+	 */
+	@Override
+	protected void okPressed() {
+		if (status != null
+				&& (status.isOK() || status.getCode() == IStatus.INFO)) {
+			super.okPressed();
+		}
+	}
+
+	/**
+	 * Sets the initial pattern used by the filter. This text is copied into the
+	 * selection input on the dialog. A full selection is used in the pattern
+	 * input field.
+	 *
+	 * @param text
+	 *            initial pattern for the filter
+	 * @see FilteredItemsSelectionDialog#FULL_SELECTION
+	 */
+	public void setInitialPattern(String text) {
+		setInitialPattern(text, FULL_SELECTION);
+	}
+
+	/**
+	 * Sets the initial pattern used by the filter. This text is copied into the
+	 * selection input on the dialog. The <code>selectionMode</code> is used
+	 * to choose selection type for the input field.
+	 *
+	 * @param text
+	 *            initial pattern for the filter
+	 * @param selectionMode
+	 *            one of: {@link FilteredItemsSelectionDialog#NONE},
+	 *            {@link FilteredItemsSelectionDialog#CARET_BEGINNING},
+	 *            {@link FilteredItemsSelectionDialog#FULL_SELECTION}
+	 */
+	public void setInitialPattern(String text, int selectionMode) {
+		this.initialPatternText = text;
+		this.selectionMode = selectionMode;
+	}
+
+	/**
+	 * Gets initial pattern.
+	 *
+	 * @return initial pattern, or <code>null</code> if initial pattern is not
+	 *         set
+	 */
+	protected String getInitialPattern() {
+		return this.initialPatternText;
+	}
+
+	/**
+	 * Returns the current selection.
+	 *
+	 * @return the current selection
+	 */
+	protected StructuredSelection getSelectedItems() {
+
+		StructuredSelection selection = (StructuredSelection) list.getStructuredSelection();
+
+		List selectedItems = selection.toList();
+		Object itemToRemove = null;
+
+		for (Iterator it = selection.iterator(); it.hasNext();) {
+			Object item = it.next();
+			if (item instanceof ItemsListSeparator) {
+				itemToRemove = item;
+				break;
+			}
+		}
+
+		if (itemToRemove == null)
+			return new StructuredSelection(selectedItems);
+		// Create a new selection without the collision
+		List newItems = new ArrayList(selectedItems);
+		newItems.remove(itemToRemove);
+		return new StructuredSelection(newItems);
+
+	}
+
+	/**
+	 * Validates the item. When items on the items list are selected or
+	 * deselected, it validates each item in the selection and the dialog status
+	 * depends on all validations.
+	 *
+	 * @param item
+	 *            an item to be checked
+	 * @return status of the dialog to be set
+	 */
+	protected abstract IStatus validateItem(Object item);
+
+	/**
+	 * Creates an instance of a filter.
+	 *
+	 * @return a filter for items on the items list. Can be <code>null</code>,
+	 *         no filtering will be applied then, causing no item to be shown in
+	 *         the list.
+	 */
+	protected abstract ItemsFilter createFilter();
+
+	/**
+	 * Applies the filter created by <code>createFilter()</code> method to the
+	 * items list. When new filter is different than previous one it will cause
+	 * refiltering.
+	 */
+	protected void applyFilter() {
+
+		ItemsFilter newFilter = createFilter();
+
+		// don't apply filtering for patterns which mean the same, for example:
+		// *a**b and ***a*b
+		if (filter != null && filter.equalsFilter(newFilter)) {
+			return;
+		}
+
+		filterHistoryJob.cancel();
+		filterJob.cancel();
+
+		this.filter = newFilter;
+
+		if (this.filter != null) {
+			filterHistoryJob.schedule();
+		}
+	}
+
+	/**
+	 * Returns comparator to sort items inside content provider. Returned object
+	 * will be probably created as an anonymous class. Parameters passed to the
+	 * <code>compare(java.lang.Object, java.lang.Object)</code> are going to
+	 * be the same type as the one used in the content provider.
+	 *
+	 * @return comparator to sort items content provider
+	 */
+	protected abstract Comparator getItemsComparator();
+
+	/**
+	 * Fills the content provider with matching items.
+	 *
+	 * @param contentProvider
+	 *            collector to add items to.
+	 *            {@link FilteredItemsSelectionDialog.AbstractContentProvider#add(Object, FilteredItemsSelectionDialog.ItemsFilter)}
+	 *            only adds items that pass the given <code>itemsFilter</code>.
+	 * @param itemsFilter
+	 *            the items filter
+	 * @param progressMonitor
+	 *            must be used to report search progress. The state of this
+	 *            progress monitor reflects the state of the filtering process.
+	 * @throws CoreException
+	 */
+	protected abstract void fillContentProvider(
+			AbstractContentProvider contentProvider, ItemsFilter itemsFilter,
+			IProgressMonitor progressMonitor) throws CoreException;
+
+	/**
+	 * Removes selected items from history.
+	 *
+	 * @param items
+	 *            items to be removed
+	 */
+	private void removeSelectedItems(List items) {
+		for (Iterator iter = items.iterator(); iter.hasNext();) {
+			Object item = iter.next();
+			removeHistoryItem(item);
+		}
+		refreshWithLastSelection = false;
+		contentProvider.refresh();
+	}
+
+	/**
+	 * Removes an item from history.
+	 *
+	 * @param item
+	 *            an item to remove
+	 * @return removed item
+	 */
+	protected Object removeHistoryItem(Object item) {
+		return contentProvider.removeHistoryElement(item);
+	}
+
+	/**
+	 * Adds item to history.
+	 *
+	 * @param item
+	 *            the item to be added
+	 */
+	protected void accessedHistoryItem(Object item) {
+		contentProvider.addHistoryElement(item);
+	}
+
+	/**
+	 * Returns a history comparator.
+	 *
+	 * @return decorated comparator
+	 */
+	private Comparator getHistoryComparator() {
+		return new HistoryComparator();
+	}
+
+	/**
+	 * Returns the history of selected elements.
+	 *
+	 * @return history of selected elements, or <code>null</code> if it is not
+	 *         set
+	 */
+	protected SelectionHistory getSelectionHistory() {
+		return this.contentProvider.getSelectionHistory();
+	}
+
+	/**
+	 * Sets new history.
+	 *
+	 * @param selectionHistory
+	 *            the history
+	 */
+	protected void setSelectionHistory(SelectionHistory selectionHistory) {
+		if (this.contentProvider != null)
+			this.contentProvider.setSelectionHistory(selectionHistory);
+	}
+
+	/**
+	 * Indicates whether the given item is a history item.
+	 *
+	 * @param item
+	 *            the item to be investigated
+	 * @return <code>true</code> if the given item exists in history,
+	 *         <code>false</code> otherwise
+	 */
+	public boolean isHistoryElement(Object item) {
+		return this.contentProvider.isHistoryElement(item);
+	}
+
+	/**
+	 * Indicates whether the given item is a duplicate.
+	 *
+	 * @param item
+	 *            the item to be investigated
+	 * @return <code>true</code> if the item is duplicate, <code>false</code>
+	 *         otherwise
+	 */
+	public boolean isDuplicateElement(Object item) {
+		return this.contentProvider.isDuplicateElement(item);
+	}
+
+	/**
+	 * Sets separator label
+	 *
+	 * @param separatorLabel
+	 *            the label showed on separator
+	 */
+	public void setSeparatorLabel(String separatorLabel) {
+		this.itemsListSeparator = new ItemsListSeparator(separatorLabel);
+	}
+
+	/**
+	 * Returns name for then given object.
+	 *
+	 * @param item
+	 *            an object from the content provider. Subclasses should pay
+	 *            attention to the passed argument. They should either only pass
+	 *            objects of a known type (one used in content provider) or make
+	 *            sure that passed parameter is the expected one (by type
+	 *            checking like <code>instanceof</code> inside the method).
+	 * @return name of the given item
+	 */
+	public abstract String getElementName(Object item);
+
+	private class ToggleStatusLineAction extends Action {
+
+		/**
+		 * Creates a new instance of the class.
+		 */
+		public ToggleStatusLineAction() {
+			super(
+					WorkbenchMessages.get().FilteredItemsSelectionDialog_toggleStatusAction,
+					IAction.AS_CHECK_BOX);
+		}
+
+		@Override
+		public void run() {
+			details.setVisible(isChecked());
+		}
+	}
+
+	/**
+	 * Only refreshes UI on the basis of an already sorted and filtered set of
+	 * items.
+	 * <p>
+	 * Standard invocation scenario:
+	 * <ol>
+	 * <li>filtering job (<code>FilterJob</code> class extending
+	 * <code>Job</code> class)</li>
+	 * <li>cache refresh without checking for duplicates (<code>RefreshCacheJob</code>
+	 * class extending <code>Job</code> class)</li>
+	 * <li>UI refresh (<code>RefreshJob</code> class extending
+	 * <code>UIJob</code> class)</li>
+	 * <li>cache refresh with checking for duplicates (<cod>CacheRefreshJob</code>
+	 * class extending <code>Job</code> class)</li>
+	 * <li>UI refresh (<code>RefreshJob</code> class extending <code>UIJob</code>
+	 * class)</li>
+	 * </ol>
+	 * The scenario is rather complicated, but it had to be applied, because:
+	 * <ul>
+	 * <li> refreshing cache is rather a long action and cannot be run in the UI -
+	 * cannot be run in a UIJob</li>
+	 * <li> refreshing cache checking for duplicates is twice as long as
+	 * refreshing cache without checking for duplicates; results of the search
+	 * could be displayed earlier</li>
+	 * <li> refreshing the UI have to be run in a UIJob</li>
+	 * </ul>
+	 *
+	 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog.FilterJob
+	 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog.RefreshJob
+	 * @see org.eclipse.ui.dialogs.FilteredItemsSelectionDialog.RefreshCacheJob
+	 */
+	private class RefreshJob extends UIJob {
+
+		/**
+		 * Creates a new instance of the class.
+		 */
+		public RefreshJob() {
+			super(FilteredItemsSelectionDialog.this.getParentShell()
+					.getDisplay(),
+					WorkbenchMessages.get().FilteredItemsSelectionDialog_refreshJob);
+			setSystem(true);
+		}
+
+		@Override
+		public IStatus runInUIThread(IProgressMonitor monitor) {
+			if (monitor.isCanceled())
+				return new Status(IStatus.OK, WorkbenchPlugin.PI_WORKBENCH,
+						IStatus.OK, EMPTY_STRING, null);
+
+			if (FilteredItemsSelectionDialog.this != null) {
+				FilteredItemsSelectionDialog.this.refresh();
+			}
+
+			return new Status(IStatus.OK, PlatformUI.PLUGIN_ID, IStatus.OK,
+					EMPTY_STRING, null);
+		}
+
+	}
+
+	/**
+	 * Refreshes the progress message cyclically with 500 milliseconds delay.
+	 * <code>RefreshProgressMessageJob</code> is strictly connected with
+	 * <code>GranualProgressMonitor</code> and use it to to get progress
+	 * message and to decide about break of cyclical refresh.
+	 */
+	private class RefreshProgressMessageJob extends UIJob {
+
+		private GranualProgressMonitor progressMonitor;
+
+		/**
+		 * Creates a new instance of the class.
+		 */
+		public RefreshProgressMessageJob() {
+			super(
+					FilteredItemsSelectionDialog.this.getParentShell()
+							.getDisplay(),
+					WorkbenchMessages.get().FilteredItemsSelectionDialog_progressRefreshJob);
+			setSystem(true);
+		}
+
+		@Override
+		public IStatus runInUIThread(IProgressMonitor monitor) {
+
+			if (!progressLabel.isDisposed())
+				progressLabel.setText(progressMonitor != null ? progressMonitor
+						.getMessage() : EMPTY_STRING);
+
+			if (progressMonitor == null || progressMonitor.isDone()) {
+				return new Status(IStatus.CANCEL, PlatformUI.PLUGIN_ID,
+						IStatus.CANCEL, EMPTY_STRING, null);
+			}
+
+			// Schedule cyclical with 500 milliseconds delay
+			schedule(500);
+
+			return new Status(IStatus.OK, PlatformUI.PLUGIN_ID, IStatus.OK,
+					EMPTY_STRING, null);
+		}
+
+		/**
+		 * Schedule progress refresh job.
+		 *
+		 * @param progressMonitor
+		 *            used during refresh progress label
+		 */
+		public void scheduleProgressRefresh(
+				GranualProgressMonitor progressMonitor) {
+			this.progressMonitor = progressMonitor;
+			// Schedule with initial delay to avoid flickering when the user
+			// types quickly
+			schedule(200);
+		}
+
+	}
+
+	/**
+	 * A job responsible for computing filtered items list presented using
+	 * <code>RefreshJob</code>.
+	 *
+	 * @see FilteredItemsSelectionDialog.RefreshJob
+	 *
+	 */
+	private class RefreshCacheJob extends Job {
+
+		private RefreshJob refreshJob = new RefreshJob();
+
+		/**
+		 * Creates a new instance of the class.
+		 */
+		public RefreshCacheJob() {
+			super(
+					WorkbenchMessages.get().FilteredItemsSelectionDialog_cacheRefreshJob);
+			setSystem(true);
+		}
+
+		/**
+		 * Stops the job and all sub-jobs.
+		 */
+		public void cancelAll() {
+			cancel();
+			refreshJob.cancel();
+		}
+
+		@Override
+		protected IStatus run(IProgressMonitor monitor) {
+			if (monitor.isCanceled()) {
+				return new Status(IStatus.CANCEL, WorkbenchPlugin.PI_WORKBENCH,
+						IStatus.CANCEL, EMPTY_STRING, null);
+			}
+
+			if (FilteredItemsSelectionDialog.this != null) {
+				GranualProgressMonitor wrappedMonitor = new GranualProgressMonitor(
+						monitor);
+				FilteredItemsSelectionDialog.this.reloadCache(true,
+						wrappedMonitor);
+			}
+
+			if (!monitor.isCanceled()) {
+				refreshJob.schedule();
+			}
+
+			return new Status(IStatus.OK, PlatformUI.PLUGIN_ID, IStatus.OK,
+					EMPTY_STRING, null);
+
+		}
+
+		@Override
+		protected void canceling() {
+			super.canceling();
+			contentProvider.stopReloadingCache();
+		}
+
+	}
+
+	private class RemoveHistoryItemAction extends Action {
+
+		/**
+		 * Creates a new instance of the class.
+		 */
+		public RemoveHistoryItemAction() {
+			super(
+					WorkbenchMessages.get().FilteredItemsSelectionDialog_removeItemsFromHistoryAction);
+		}
+
+		@Override
+		public void run() {
+			List selectedElements = ((StructuredSelection) list.getSelection()).toList();
+			removeSelectedItems(selectedElements);
+		}
+	}
+
+	private static boolean showColoredLabels() {
+		return PlatformUI.getPreferenceStore().getBoolean(IWorkbenchPreferenceConstants.USE_COLORED_LABELS);
+	}
+
+    // RAP [rh] StyledCellLabelProvider not supported   
+//  private class ItemsListLabelProvider extends StyledCellLabelProvider
+        private class ItemsListLabelProvider extends CellLabelProvider 
+            implements ILabelProviderListener {
+		private ILabelProvider provider;
+
+		private ILabelDecorator selectionDecorator;
+
+		// Need to keep our own list of listeners
+		private ListenerList<ILabelProviderListener> listeners = new ListenerList<>();
+
+		/**
+		 * Creates a new instance of the class.
+		 *
+		 * @param provider
+		 *            the label provider for all items, not <code>null</code>
+		 * @param selectionDecorator
+		 *            the decorator for selected items, can be <code>null</code>
+		 */
+		public ItemsListLabelProvider(ILabelProvider provider,
+				ILabelDecorator selectionDecorator) {
+			Assert.isNotNull(provider);
+			this.provider = provider;
+			this.selectionDecorator = selectionDecorator;
+
+// RAP [rh] IStyledLabelProvider not supported
+//			setOwnerDrawEnabled(showColoredLabels() && provider instanceof IStyledLabelProvider);
+
+			provider.addListener(this);
+
+			if (selectionDecorator != null) {
+				selectionDecorator.addListener(this);
+			}
+		}
+
+		/**
+		 * Sets new selection decorator.
+		 *
+		 * @param newSelectionDecorator
+		 *            new label decorator for selected items in the list
+		 */
+		public void setSelectionDecorator(ILabelDecorator newSelectionDecorator) {
+			if (selectionDecorator != null) {
+				selectionDecorator.removeListener(this);
+				selectionDecorator.dispose();
+			}
+
+			selectionDecorator = newSelectionDecorator;
+
+			if (selectionDecorator != null) {
+				selectionDecorator.addListener(this);
+			}
+		}
+
+		/**
+		 * Gets selection decorator.
+		 *
+		 * @return the label decorator for selected items in the list
+		 */
+		public ILabelDecorator getSelectionDecorator() {
+			return selectionDecorator;
+		}
+
+		/**
+		 * Sets new label provider.
+		 *
+		 * @param newProvider
+		 *            new label provider for items in the list, not
+		 *            <code>null</code>
+		 */
+		public void setProvider(ILabelProvider newProvider) {
+			Assert.isNotNull(newProvider);
+			provider.removeListener(this);
+			provider.dispose();
+
+			provider = newProvider;
+
+			if (provider != null) {
+				provider.addListener(this);
+			}
+
+// RAP [rh] IStyledLabelProvider not supported
+//			setOwnerDrawEnabled(showColoredLabels() && provider instanceof IStyledLabelProvider);
+		}
+
+		private Image getImage(Object element) {
+			if (element instanceof ItemsListSeparator) {
+				return WorkbenchImages
+						.getImage(IWorkbenchGraphicConstants.IMG_OBJ_SEPARATOR);
+			}
+
+			return provider.getImage(element);
+		}
+
+		private boolean isSelected(Object element) {
+			if (element != null && currentSelection != null) {
+				for (Object entry : currentSelection) {
+					if (element.equals(entry))
+						return true;
+				}
+			}
+			return false;
+		}
+
+		private String getText(Object element) {
+			if (element instanceof ItemsListSeparator) {
+				return getSeparatorLabel(((ItemsListSeparator) element).getName());
+			}
+
+			String str = provider.getText(element);
+			if (selectionDecorator != null && isSelected(element)) {
+				return selectionDecorator.decorateText(str.toString(), element);
+			}
+
+			return str;
+		}
+		
+// RAP [rh] IStyledLabelProvider not supported
+//		private StyledString getStyledText(Object element, IStyledLabelProvider provider) {
+//			StyledString string = provider.getStyledText(element);
+//
+//			if (selectionDecorator != null && isSelected(element)) {
+//				String decorated = selectionDecorator.decorateText(string.getString(), element);
+//				return StyledCellLabelProvider.styleDecoratedString(decorated, null, string);
+//				// no need to add colors when element is selected
+//			}
+//			return string;
+//		}
+
+		@Override
+		public void update(ViewerCell cell) {
+			Object element = cell.getElement();
+			
+			// RAP [rh] IStyledLabelProvider not supported
+//			if (!(element instanceof ItemsListSeparator)
+//					&& provider instanceof IStyledLabelProvider) {
+//				IStyledLabelProvider styledLabelProvider = (IStyledLabelProvider) provider;
+//				StyledString styledString = getStyledText(element,
+//						styledLabelProvider);
+//
+//				cell.setText(styledString.getString());
+//				cell.setStyleRanges(styledString.getStyleRanges());
+//				cell.setImage(styledLabelProvider.getImage(element));
+//			} else {
+				cell.setText(getText(element));
+				cell.setImage(getImage(element));
+//			}
+			cell.setFont(getFont(element));
+			cell.setForeground(getForeground(element));
+			cell.setBackground(getBackground(element));
+
+// RAP [rh] Obsolete because of changed inheritance
+//			super.update(cell);
+		}
+
+		private String getSeparatorLabel(String separatorLabel) {
+			Rectangle rect = list.getTable().getBounds();
+
+			int borderWidth = list.getTable().computeTrim(0, 0, 0, 0).width;
+
+			int imageWidth = WorkbenchImages.getImage(
+					IWorkbenchGraphicConstants.IMG_OBJ_SEPARATOR).getBounds().width;
+
+			int width = rect.width - borderWidth - imageWidth;
+
+			GC gc = new GC(list.getTable());
+			gc.setFont(list.getTable().getFont());
+			
+//RAP [rh] GC#getAdvanceWidth missing
+//			int fSeparatorWidth = gc.getAdvanceWidth('-');
+			int fSeparatorWidth = gc.getCharWidth('-');
+			int fMessageLength = gc.textExtent(separatorLabel).x;
+
+			gc.dispose();
+
+			StringBuffer dashes = new StringBuffer();
+			int chars = (((width - fMessageLength) / fSeparatorWidth) / 2) - 2;
+			for (int i = 0; i < chars; i++) {
+				dashes.append('-');
+			}
+
+			StringBuffer result = new StringBuffer();
+			result.append(dashes);
+			result.append(" " + separatorLabel + " "); //$NON-NLS-1$//$NON-NLS-2$
+			result.append(dashes);
+			return result.toString().trim();
+		}
+
+		@Override
+		public void addListener(ILabelProviderListener listener) {
+			listeners.add(listener);
+		}
+
+		@Override
+		public void dispose() {
+			provider.removeListener(this);
+			provider.dispose();
+
+			if (selectionDecorator != null) {
+				selectionDecorator.removeListener(this);
+				selectionDecorator.dispose();
+			}
+
+			super.dispose();
+		}
+
+		@Override
+		public boolean isLabelProperty(Object element, String property) {
+			if (provider.isLabelProperty(element, property)) {
+				return true;
+			}
+			if (selectionDecorator != null
+					&& selectionDecorator.isLabelProperty(element, property)) {
+				return true;
+			}
+			return false;
+		}
+
+		@Override
+		public void removeListener(ILabelProviderListener listener) {
+			listeners.remove(listener);
+		}
+
+		private Color getBackground(Object element) {
+			if (element instanceof ItemsListSeparator) {
+				return null;
+			}
+			if (provider instanceof IColorProvider) {
+				return ((IColorProvider) provider).getBackground(element);
+			}
+			return null;
+		}
+
+		private Color getForeground(Object element) {
+			if (element instanceof ItemsListSeparator) {
+				return Display.getCurrent().getSystemColor(
+						SWT.COLOR_WIDGET_NORMAL_SHADOW);
+			}
+			if (provider instanceof IColorProvider) {
+				return ((IColorProvider) provider).getForeground(element);
+			}
+			return null;
+		}
+
+		private Font getFont(Object element) {
+			if (element instanceof ItemsListSeparator) {
+				return null;
+			}
+			if (provider instanceof IFontProvider) {
+				return ((IFontProvider) provider).getFont(element);
+			}
+			return null;
+		}
+
+		@Override
+		public void labelProviderChanged(LabelProviderChangedEvent event) {
+			for (ILabelProviderListener l : listeners) {
+				l.labelProviderChanged(event);
+			}
+		}
+	}
+
+	/**
+	 * Used in ItemsListContentProvider, separates history and non-history
+	 * items.
+	 */
+	private class ItemsListSeparator {
+
+		private String name;
+
+		/**
+		 * Creates a new instance of the class.
+		 *
+		 * @param name
+		 *            the name of the separator
+		 */
+		public ItemsListSeparator(String name) {
+			this.name = name;
+		}
+
+		/**
+		 * Returns the name of this separator.
+		 *
+		 * @return the name of the separator
+		 */
+		public String getName() {
+			return name;
+		}
+	}
+
+	/**
+	 * GranualProgressMonitor is used for monitoring progress of filtering
+	 * process. It is used by <code>RefreshProgressMessageJob</code> to
+	 * refresh progress message. State of this monitor illustrates state of
+	 * filtering or cache refreshing process.
+	 *
+	 */
+	private class GranualProgressMonitor extends ProgressMonitorWrapper {
+
+		private String name;
+
+		private String subName;
+
+		private int totalWork;
+
+		private double worked;
+
+		private boolean done;
+
+		/**
+		 * Creates instance of <code>GranualProgressMonitor</code>.
+		 *
+		 * @param monitor
+		 *            progress to be wrapped
+		 */
+		public GranualProgressMonitor(IProgressMonitor monitor) {
+			super(monitor);
+		}
+
+		/**
+		 * Checks if filtering has been done
+		 *
+		 * @return true if filtering work has been done false in other way
+		 */
+		public boolean isDone() {
+			return done;
+		}
+
+		@Override
+		public void setTaskName(String name) {
+			super.setTaskName(name);
+			this.name = name;
+			this.subName = null;
+		}
+
+		@Override
+		public void subTask(String name) {
+			super.subTask(name);
+			this.subName = name;
+		}
+
+		@Override
+		public void beginTask(String name, int totalWork) {
+			super.beginTask(name, totalWork);
+			if (this.name == null)
+				this.name = name;
+			this.totalWork = totalWork;
+			refreshProgressMessageJob.scheduleProgressRefresh(this);
+		}
+
+		@Override
+		public void worked(int work) {
+			super.worked(work);
+			internalWorked(work);
+		}
+
+		@Override
+		public void done() {
+			done = true;
+			super.done();
+		}
+
+		@Override
+		public void setCanceled(boolean b) {
+			done = b;
+			super.setCanceled(b);
+		}
+
+		@Override
+		public void internalWorked(double work) {
+			worked = worked + work;
+		}
+
+		private String getMessage() {
+			if (done)
+				return ""; //$NON-NLS-1$
+
+			String message;
+
+			if (name == null) {
+				message = subName == null ? "" : subName; //$NON-NLS-1$
+			} else {
+				message = subName == null ? name
+						: NLS
+								.bind(
+										WorkbenchMessages.get().FilteredItemsSelectionDialog_subtaskProgressMessage,
+										new Object[] { name, subName });
+			}
+			if (totalWork == 0)
+				return message;
+
+			return NLS
+					.bind(
+							WorkbenchMessages.get().FilteredItemsSelectionDialog_taskProgressMessage,
+							new Object[] {
+									message,
+									Integer.valueOf((int) ((worked * 100) / totalWork)) });
+
+		}
+
+	}
+
+	/**
+	 * Filters items history and schedule filter job.
+	 */
+	private class FilterHistoryJob extends Job {
+
+		/**
+		 * Filter used during the filtering process.
+		 */
+		private ItemsFilter itemsFilter;
+
+		/**
+		 * Creates new instance of receiver.
+		 */
+		public FilterHistoryJob() {
+			super(WorkbenchMessages.get().FilteredItemsSelectionDialog_jobLabel);
+			setSystem(true);
+		}
+
+		@Override
+		protected IStatus run(IProgressMonitor monitor) {
+
+			this.itemsFilter = filter;
+
+			contentProvider.reset();
+
+			refreshWithLastSelection = false;
+
+			contentProvider.addHistoryItems(itemsFilter);
+
+			if (!(lastCompletedFilter != null && lastCompletedFilter
+					.isSubFilter(this.itemsFilter)))
+				contentProvider.refresh();
+
+			filterJob.schedule();
+
+			return Status.OK_STATUS;
+		}
+
+	}
+
+	/**
+	 * Filters items in indicated set and history. During filtering, it
+	 * refreshes the dialog (progress monitor and elements list).
+	 *
+	 * Depending on the filter, <code>FilterJob</code> decides which kind of
+	 * search will be run inside <code>filterContent</code>. If the last
+	 * filtering is done (last completed filter), is not null, and the new
+	 * filter is a sub-filter ({@link FilteredItemsSelectionDialog.ItemsFilter#isSubFilter(FilteredItemsSelectionDialog.ItemsFilter)})
+	 * of the last, then <code>FilterJob</code> only filters in the cache. If
+	 * it is the first filtering or the new filter isn't a sub-filter of the
+	 * last one, a full search is run.
+	 */
+	private class FilterJob extends Job {
+
+		/**
+		 * Filter used during the filtering process.
+		 */
+		protected ItemsFilter itemsFilter;
+
+		/**
+		 * Creates new instance of FilterJob
+		 */
+		public FilterJob() {
+			super(WorkbenchMessages.get().FilteredItemsSelectionDialog_jobLabel);
+			setSystem(true);
+		}
+
+		@Override
+		protected final IStatus run(IProgressMonitor parent) {
+			GranualProgressMonitor monitor = new GranualProgressMonitor(parent);
+			return doRun(monitor);
+		}
+
+		/**
+		 * Executes job using the given filtering progress monitor. A hook for
+		 * subclasses.
+		 *
+		 * @param monitor
+		 *            progress monitor
+		 * @return result of the execution
+		 */
+		protected IStatus doRun(GranualProgressMonitor monitor) {
+			try {
+				internalRun(monitor);
+			} catch (CoreException e) {
+				cancel();
+				return new Status(
+						IStatus.ERROR,
+						PlatformUI.PLUGIN_ID,
+						IStatus.ERROR,
+						WorkbenchMessages.get().FilteredItemsSelectionDialog_jobError,
+						e);
+			}
+			return Status.OK_STATUS;
+		}
+
+		/**
+		 * Main method for the job.
+		 *
+		 * @param monitor
+		 * @throws CoreException
+		 */
+		private void internalRun(GranualProgressMonitor monitor)
+				throws CoreException {
+			try {
+				if (monitor.isCanceled())
+					return;
+
+				this.itemsFilter = filter;
+
+				if (filter.getPattern().length() != 0) {
+					filterContent(monitor);
+				}
+
+				if (monitor.isCanceled())
+					return;
+
+				contentProvider.refresh();
+			} finally {
+				monitor.done();
+			}
+		}
+
+		/**
+		 * Filters items.
+		 *
+		 * @param monitor
+		 *            for monitoring progress
+		 * @throws CoreException
+		 */
+		protected void filterContent(GranualProgressMonitor monitor)
+				throws CoreException {
+
+			if (lastCompletedFilter != null
+					&& lastCompletedFilter.isSubFilter(this.itemsFilter)) {
+
+				int length = lastCompletedResult.size() / 500;
+				monitor
+						.beginTask(
+								WorkbenchMessages.get().FilteredItemsSelectionDialog_cacheSearchJob_taskName,
+								length);
+
+				for (int pos = 0; pos < lastCompletedResult.size(); pos++) {
+
+					Object item = lastCompletedResult.get(pos);
+					if (monitor.isCanceled())
+						break;
+					contentProvider.add(item, itemsFilter);
+
+					if ((pos % 500) == 0) {
+						monitor.worked(1);
+					}
+				}
+
+			} else {
+
+				lastCompletedFilter = null;
+				lastCompletedResult = null;
+
+				SubMonitor subMonitor = SubMonitor.convert(monitor,
+									WorkbenchMessages.get().FilteredItemsSelectionDialog_searchJob_taskName,
+									100);
+
+				fillContentProvider(contentProvider, itemsFilter, subMonitor.split(95));
+
+				if (monitor != null && !monitor.isCanceled()) {
+					subMonitor.worked(2);
+					contentProvider.rememberResult(itemsFilter);
+					subMonitor.worked(3);
+				}
+			}
+
+		}
+
+	}
+
+	/**
+	 * History stores a list of key, object pairs. The list is bounded at a
+	 * certain size. If the list exceeds this size the oldest element is removed
+	 * from the list. An element can be added/renewed with a call to
+	 * <code>accessed(Object)</code>.
+	 * <p>
+	 * The history can be stored to/loaded from an XML file.
+	 */
+	protected static abstract class SelectionHistory {
+
+		private static final String DEFAULT_ROOT_NODE_NAME = "historyRootNode"; //$NON-NLS-1$
+
+		private static final String DEFAULT_INFO_NODE_NAME = "infoNode"; //$NON-NLS-1$
+
+		private static final int MAX_HISTORY_SIZE = 60;
+
+		private final Set historyList;
+
+		private final String rootNodeName;
+
+		private final String infoNodeName;
+
+		private SelectionHistory(String rootNodeName, String infoNodeName) {
+
+			historyList = Collections.synchronizedSet(new LinkedHashSet() {
+
+				private static final long serialVersionUID = 0L;
+
+				@Override
+				public boolean add(Object arg0) {
+					if (this.size() >= MAX_HISTORY_SIZE) {
+						Iterator iterator = this.iterator();
+						iterator.next();
+						iterator.remove();
+					}
+					return super.add(arg0);
+				}
+
+			});
+
+			this.rootNodeName = rootNodeName;
+			this.infoNodeName = infoNodeName;
+		}
+
+		/**
+		 * Creates new instance of <code>SelectionHistory</code>.
+		 */
+		public SelectionHistory() {
+			this(DEFAULT_ROOT_NODE_NAME, DEFAULT_INFO_NODE_NAME);
+		}
+
+		/**
+		 * Adds object to history.
+		 *
+		 * @param object
+		 *            the item to be added to the history
+		 */
+		public synchronized void accessed(Object object) {
+			historyList.remove(object);
+			historyList.add(object);
+		}
+
+		/**
+		 * Returns <code>true</code> if history contains object.
+		 *
+		 * @param object
+		 *            the item for which check will be executed
+		 * @return <code>true</code> if history contains object
+		 *         <code>false</code> in other way
+		 */
+		public synchronized boolean contains(Object object) {
+			return historyList.contains(object);
+		}
+
+		/**
+		 * Returns <code>true</code> if history is empty.
+		 *
+		 * @return <code>true</code> if history is empty
+		 */
+		public synchronized boolean isEmpty() {
+			return historyList.isEmpty();
+		}
+
+		/**
+		 * Remove element from history.
+		 *
+		 * @param element
+		 *            to remove form the history
+		 * @return <code>true</code> if this list contained the specified
+		 *         element
+		 */
+		public synchronized boolean remove(Object element) {
+			return historyList.remove(element);
+		}
+
+		/**
+		 * Load history elements from memento.
+		 *
+		 * @param memento
+		 *            memento from which the history will be retrieved
+		 */
+		public void load(IMemento memento) {
+
+			XMLMemento historyMemento = (XMLMemento) memento
+					.getChild(rootNodeName);
+
+			if (historyMemento == null) {
+				return;
+			}
+
+			IMemento[] mementoElements = historyMemento
+					.getChildren(infoNodeName);
+			for (IMemento mementoElement : mementoElements) {
+				Object object = restoreItemFromMemento(mementoElement);
+				if (object != null) {
+					historyList.add(object);
+				}
+			}
+		}
+
+		/**
+		 * Save history elements to memento.
+		 *
+		 * @param memento
+		 *            memento to which the history will be added
+		 */
+		public void save(IMemento memento) {
+
+			IMemento historyMemento = memento.createChild(rootNodeName);
+
+			Object[] items = getHistoryItems();
+			for (Object item : items) {
+				IMemento elementMemento = historyMemento
+						.createChild(infoNodeName);
+				storeItemToMemento(item, elementMemento);
+			}
+
+		}
+
+		/**
+		 * Gets array of history items.
+		 *
+		 * @return array of history elements
+		 */
+		public synchronized Object[] getHistoryItems() {
+			return historyList.toArray();
+		}
+
+		/**
+		 * Creates an object using given memento.
+		 *
+		 * @param memento
+		 *            memento used for creating new object
+		 *
+		 * @return the restored object
+		 */
+		protected abstract Object restoreItemFromMemento(IMemento memento);
+
+		/**
+		 * Store object in <code>IMemento</code>.
+		 *
+		 * @param item
+		 *            the item to store
+		 * @param memento
+		 *            the memento to store to
+		 */
+		protected abstract void storeItemToMemento(Object item, IMemento memento);
+
+	}
+
+	/**
+	 * Filters elements using SearchPattern by comparing the names of items with
+	 * the filter pattern.
+	 */
+	protected abstract class ItemsFilter {
+
+		protected SearchPattern patternMatcher;
+
+		/**
+		 * Creates new instance of ItemsFilter.
+		 */
+		public ItemsFilter() {
+			this(new SearchPattern());
+		}
+
+		/**
+		 * Creates new instance of ItemsFilter.
+		 *
+		 * @param searchPattern
+		 *            the pattern to be used when filtering
+		 */
+		public ItemsFilter(SearchPattern searchPattern) {
+			patternMatcher = searchPattern;
+			String stringPattern = ""; //$NON-NLS-1$
+			if (pattern != null && !pattern.getText().equals("*")) { //$NON-NLS-1$
+				stringPattern = pattern.getText();
+			}
+			patternMatcher.setPattern(stringPattern);
+		}
+
+		/**
+		 * Check if the given filter is a sub-filter of this filter. The default
+		 * implementation checks if the <code>SearchPattern</code> from the
+		 * given filter is a sub-pattern of the one from this filter.
+		 * <p>
+		 * <i>WARNING: This method is <b>not</b> defined in reading order, i.e.
+		 * <code>a.isSubFilter(b)</code> is <code>true</code> iff
+		 * <code>b</code> is a sub-filter of <code>a</code>, and not
+		 * vice-versa. </i>
+		 * </p>
+		 *
+		 * @param filter
+		 *            the filter to be checked, or <code>null</code>
+		 * @return <code>true</code> if the given filter is sub-filter of this
+		 *         filter, <code>false</code> if the given filter isn't a
+		 *         sub-filter or is <code>null</code>
+		 *
+		 * @see org.eclipse.ui.dialogs.SearchPattern#isSubPattern(org.eclipse.ui.dialogs.SearchPattern)
+		 */
+		public boolean isSubFilter(ItemsFilter filter) {
+			if (filter != null) {
+				return this.patternMatcher.isSubPattern(filter.patternMatcher);
+			}
+			return false;
+		}
+
+		/**
+		 * Checks whether the provided filter is equal to the current filter.
+		 * The default implementation checks if <code>SearchPattern</code>
+		 * from current filter is equal to the one from provided filter.
+		 *
+		 * @param filter
+		 *            filter to be checked, or <code>null</code>
+		 * @return <code>true</code> if the given filter is equal to current
+		 *         filter, <code>false</code> if given filter isn't equal to
+		 *         current one or if it is <code>null</code>
+		 *
+		 * @see org.eclipse.ui.dialogs.SearchPattern#equalsPattern(org.eclipse.ui.dialogs.SearchPattern)
+		 */
+		public boolean equalsFilter(ItemsFilter filter) {
+			if (filter != null
+					&& filter.patternMatcher.equalsPattern(this.patternMatcher)) {
+				return true;
+			}
+			return false;
+		}
+
+		/**
+		 * Checks whether the pattern's match rule is camel case.
+		 *
+		 * @return <code>true</code> if pattern's match rule is camel case,
+		 *         <code>false</code> otherwise
+		 */
+		public boolean isCamelCasePattern() {
+			return patternMatcher.getMatchRule() == SearchPattern.RULE_CAMELCASE_MATCH;
+		}
+
+		/**
+		 * Returns the pattern string.
+		 *
+		 * @return pattern for this filter
+		 *
+		 * @see SearchPattern#getPattern()
+		 */
+		public String getPattern() {
+			return patternMatcher.getPattern();
+		}
+
+		/**
+		 * Returns the rule to apply for matching keys.
+		 *
+		 * @return an implementation-specific match rule
+		 *
+		 * @see SearchPattern#getMatchRule() for match rules returned by the
+		 *      default implementation
+		 */
+		public int getMatchRule() {
+			return patternMatcher.getMatchRule();
+		}
+
+		/**
+		 * Matches text with filter.
+		 *
+		 * @param text
+		 *            the text to match with the filter
+		 * @return <code>true</code> if text matches with filter pattern,
+		 *         <code>false</code> otherwise
+		 */
+		protected boolean matches(String text) {
+			return patternMatcher.matches(text);
+		}
+
+		/**
+		 * General method for matching raw name pattern. Checks whether current
+		 * pattern is prefix of name provided item.
+		 *
+		 * @param item
+		 *            item to check
+		 * @return <code>true</code> if current pattern is a prefix of name
+		 *         provided item, <code>false</code> if item's name is shorter
+		 *         than prefix or sequences of characters don't match.
+		 */
+		public boolean matchesRawNamePattern(Object item) {
+			String prefix = patternMatcher.getPattern();
+			String text = getElementName(item);
+
+			if (text == null)
+				return false;
+
+			int textLength = text.length();
+			int prefixLength = prefix.length();
+			if (textLength < prefixLength) {
+				return false;
+			}
+			for (int i = prefixLength - 1; i >= 0; i--) {
+				if (Character.toLowerCase(prefix.charAt(i)) != Character
+						.toLowerCase(text.charAt(i)))
+					return false;
+			}
+			return true;
+		}
+
+		/**
+		 * Matches an item against filter conditions.
+		 *
+		 * @param item
+		 * @return <code>true<code> if item matches against filter conditions, <code>false</code>
+		 *         otherwise
+		 */
+		public abstract boolean matchItem(Object item);
+
+		/**
+		 * Checks consistency of an item. Item is inconsistent if was changed or
+		 * removed.
+		 *
+		 * @param item
+		 * @return <code>true</code> if item is consistent, <code>false</code>
+		 *         if item is inconsistent
+		 */
+		public abstract boolean isConsistentItem(Object item);
+
+	}
+
+	/**
+	 * An interface to content providers for
+	 * <code>FilterItemsSelectionDialog</code>.
+	 */
+	protected abstract class AbstractContentProvider {
+		/**
+		 * Adds the item to the content provider iff the filter matches the
+		 * item. Otherwise does nothing.
+		 *
+		 * @param item
+		 *            the item to add
+		 * @param itemsFilter
+		 *            the filter
+		 *
+		 * @see FilteredItemsSelectionDialog.ItemsFilter#matchItem(Object)
+		 */
+		public abstract void add(Object item, ItemsFilter itemsFilter);
+	}
+
+	/**
+	 * Collects filtered elements. Contains one synchronized, sorted set for
+	 * collecting filtered elements. All collected elements are sorted using
+	 * comparator. Comparator is returned by getElementComparator() method.
+	 * Implementation of <code>ItemsFilter</code> is used to filter elements.
+	 * The key function of filter used in to filtering is
+	 * <code>matchElement(Object item)</code>.
+	 * <p>
+	 * The <code>ContentProvider</code> class also provides item filtering
+	 * methods. The filtering has been moved from the standard TableView
+	 * <code>getFilteredItems()</code> method to content provider, because
+	 * <code>ILazyContentProvider</code> and virtual tables are used. This
+	 * class is responsible for adding a separator below history items and
+	 * marking each items as duplicate if its name repeats more than once on the
+	 * filtered list.
+	 */
+	private class ContentProvider extends AbstractContentProvider implements
+			IStructuredContentProvider, ILazyContentProvider {
+
+		private SelectionHistory selectionHistory;
+
+		/**
+		 * Raw result of the searching (unsorted, unfiltered).
+		 * <p>
+		 * Standard object flow:
+		 * <code>items -> lastSortedItems -> lastFilteredItems</code>
+		 */
+		private Set items;
+
+		/**
+		 * Items that are duplicates.
+		 */
+		private Set duplicates;
+
+		/**
+		 * List of <code>ViewerFilter</code>s to be used during filtering
+		 */
+		private List filters;
+
+		/**
+		 * Result of the last filtering.
+		 * <p>
+		 * Standard object flow:
+		 * <code>items -> lastSortedItems -> lastFilteredItems</code>
+		 */
+		private List lastFilteredItems;
+
+		/**
+		 * Result of the last sorting.
+		 * <p>
+		 * Standard object flow:
+		 * <code>items -> lastSortedItems -> lastFilteredItems</code>
+		 */
+		private List lastSortedItems;
+
+		/**
+		 * Used for <code>getFilteredItems()</code> method canceling (when the
+		 * job that invoked the method was canceled).
+		 * <p>
+		 * Method canceling could be based (only) on monitor canceling
+		 * unfortunately sometimes the method <code>getFilteredElements()</code>
+		 * could be run with a null monitor, the <code>reset</code> flag have
+		 * to be left intact.
+		 */
+		private boolean reset;
+
+		/**
+		 * Creates new instance of <code>ContentProvider</code>.
+		 */
+		public ContentProvider() {
+			this.items = Collections.synchronizedSet(new HashSet(2048));
+			this.duplicates = Collections.synchronizedSet(new HashSet(256));
+			this.lastFilteredItems = new ArrayList();
+			this.lastSortedItems = Collections.synchronizedList(new ArrayList(
+					2048));
+		}
+
+		/**
+		 * Sets selection history.
+		 *
+		 * @param selectionHistory
+		 *            The selectionHistory to set.
+		 */
+		public void setSelectionHistory(SelectionHistory selectionHistory) {
+			this.selectionHistory = selectionHistory;
+		}
+
+		/**
+		 * @return Returns the selectionHistory.
+		 */
+		public SelectionHistory getSelectionHistory() {
+			return selectionHistory;
+		}
+
+		/**
+		 * Removes all content items and resets progress message.
+		 */
+		public void reset() {
+			reset = true;
+			this.items.clear();
+			this.duplicates.clear();
+			this.lastSortedItems.clear();
+		}
+
+		/**
+		 * Stops reloading cache - <code>getFilteredItems()</code> method.
+		 */
+		public void stopReloadingCache() {
+			reset = true;
+		}
+
+		/**
+		 * Adds filtered item.
+		 *
+		 * @param item
+		 * @param itemsFilter
+		 */
+		@Override
+		public void add(Object item, ItemsFilter itemsFilter) {
+			if (itemsFilter == filter) {
+				if (itemsFilter != null) {
+					if (itemsFilter.matchItem(item)) {
+						this.items.add(item);
+					}
+				} else {
+					this.items.add(item);
+				}
+			}
+		}
+
+		/**
+		 * Add all history items to <code>contentProvider</code>.
+		 *
+		 * @param itemsFilter
+		 */
+		public void addHistoryItems(ItemsFilter itemsFilter) {
+			if (this.selectionHistory != null) {
+				Object[] items = this.selectionHistory.getHistoryItems();
+				for (Object item : items) {
+					if (itemsFilter == filter) {
+						if (itemsFilter != null) {
+							if (itemsFilter.matchItem(item)) {
+								if (itemsFilter.isConsistentItem(item)) {
+									this.items.add(item);
+								} else {
+									this.selectionHistory.remove(item);
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+
+		/**
+		 * Refresh dialog.
+		 */
+		public void refresh() {
+			scheduleRefresh();
+		}
+
+		/**
+		 * Removes items from history and refreshes the view.
+		 *
+		 * @param item
+		 *            to remove
+		 *
+		 * @return removed item
+		 */
+		public Object removeHistoryElement(Object item) {
+			if (this.selectionHistory != null)
+				this.selectionHistory.remove(item);
+			if (filter == null || filter.getPattern().length() == 0) {
+				items.remove(item);
+				duplicates.remove(item);
+				this.lastSortedItems.remove(item);
+			}
+
+			synchronized (lastSortedItems) {
+				Collections.sort(lastSortedItems, getHistoryComparator());
+			}
+			return item;
+		}
+
+		/**
+		 * Adds item to history and refresh view.
+		 *
+		 * @param item
+		 *            to add
+		 */
+		public void addHistoryElement(Object item) {
+			if (this.selectionHistory != null)
+				this.selectionHistory.accessed(item);
+			if (filter == null || !filter.matchItem(item)) {
+				this.items.remove(item);
+				this.duplicates.remove(item);
+				this.lastSortedItems.remove(item);
+			}
+			synchronized (lastSortedItems) {
+				Collections.sort(lastSortedItems, getHistoryComparator());
+			}
+			this.refresh();
+		}
+
+		/**
+		 * @param item
+		 * @return <code>true</code> if given item is part of the history
+		 */
+		public boolean isHistoryElement(Object item) {
+			if (this.selectionHistory != null) {
+				return this.selectionHistory.contains(item);
+			}
+			return false;
+		}
+
+		/**
+		 * Sets/unsets given item as duplicate.
+		 *
+		 * @param item
+		 *            item to change
+		 *
+		 * @param isDuplicate
+		 *            duplicate flag
+		 */
+		public void setDuplicateElement(Object item, boolean isDuplicate) {
+			if (this.items.contains(item)) {
+				if (isDuplicate)
+					this.duplicates.add(item);
+				else
+					this.duplicates.remove(item);
+			}
+		}
+
+		/**
+		 * Indicates whether given item is a duplicate.
+		 *
+		 * @param item
+		 *            item to check
+		 * @return <code>true</code> if item is duplicate
+		 */
+		public boolean isDuplicateElement(Object item) {
+			return duplicates.contains(item);
+		}
+
+		/**
+		 * Load history from memento.
+		 *
+		 * @param memento
+		 *            memento from which the history will be retrieved
+		 */
+		public void loadHistory(IMemento memento) {
+			if (this.selectionHistory != null)
+				this.selectionHistory.load(memento);
+		}
+
+		/**
+		 * Save history to memento.
+		 *
+		 * @param memento
+		 *            memento to which the history will be added
+		 */
+		public void saveHistory(IMemento memento) {
+			if (this.selectionHistory != null)
+				this.selectionHistory.save(memento);
+		}
+
+		/**
+		 * Gets sorted items.
+		 *
+		 * @return sorted items
+		 */
+		private Object[] getSortedItems() {
+			if (lastSortedItems.size() != items.size()) {
+				synchronized (lastSortedItems) {
+					lastSortedItems.clear();
+					lastSortedItems.addAll(items);
+					Collections.sort(lastSortedItems, getHistoryComparator());
+				}
+			}
+			return lastSortedItems.toArray();
+		}
+
+		/**
+		 * Remember result of filtering.
+		 *
+		 * @param itemsFilter
+		 */
+		public void rememberResult(ItemsFilter itemsFilter) {
+			List itemsList = Collections.synchronizedList(Arrays
+					.asList(getSortedItems()));
+			// synchronization
+			if (itemsFilter == filter) {
+				lastCompletedFilter = itemsFilter;
+				lastCompletedResult = itemsList;
+			}
+
+		}
+
+		@Override
+		public Object[] getElements(Object inputElement) {
+			return lastFilteredItems.toArray();
+		}
+
+		public int getNumberOfElements() {
+			return lastFilteredItems.size();
+		}
+
+		@Override
+		public void dispose() {
+		}
+
+		@Override
+		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+		}
+
+		@Override
+		public void updateElement(int index) {
+
+			FilteredItemsSelectionDialog.this.list.replace((lastFilteredItems
+					.size() > index) ? lastFilteredItems.get(index) : null,
+					index);
+
+		}
+
+		/**
+		 * Main method responsible for getting the filtered items and checking
+		 * for duplicates. It is based on the
+		 * {@link FilteredItemsSelectionDialog.ContentProvider#getFilteredItems(Object, IProgressMonitor)}.
+		 *
+		 * @param checkDuplicates
+		 *            <code>true</code> if data concerning elements
+		 *            duplication should be computed - it takes much more time
+		 *            than standard filtering
+		 *
+		 * @param monitor
+		 *            progress monitor
+		 */
+		public void reloadCache(boolean checkDuplicates, IProgressMonitor monitor) {
+			reset = false;
+
+			// the work is divided into two actions of the same length
+			int totalWork = checkDuplicates ? 200 : 100;
+
+			SubMonitor subMonitor = SubMonitor.convert(monitor,
+					WorkbenchMessages.get().FilteredItemsSelectionDialog_cacheRefreshJob, totalWork);
+
+			// the TableViewer's root (the input) is treated as parent
+
+			lastFilteredItems = Arrays.asList(getFilteredItems(list.getInput(), subMonitor.split(100)));
+
+			if (reset || subMonitor.isCanceled()) {
+				return;
+			}
+
+			if (checkDuplicates) {
+				checkDuplicates(subMonitor.split(100));
+			}
+		}
+
+		private void checkDuplicates(IProgressMonitor monitor) {
+			synchronized (lastFilteredItems) {
+				SubMonitor subMonitor = SubMonitor.convert(monitor,
+						WorkbenchMessages.get().FilteredItemsSelectionDialog_cacheRefreshJob_checkDuplicates,
+						lastFilteredItems.size());
+				HashMap<String, Object> helperMap = new HashMap<>();
+				for (int i = 0; i < lastFilteredItems.size(); i++) {
+					if (reset || subMonitor.isCanceled())
+						return;
+					Object item = lastFilteredItems.get(i);
+
+					if (!(item instanceof ItemsListSeparator)) {
+						Object previousItem = helperMap.put(getElementName(item), item);
+						if (previousItem != null) {
+							setDuplicateElement(previousItem, true);
+							setDuplicateElement(item, true);
+						} else {
+							setDuplicateElement(item, false);
+						}
+					}
+
+					subMonitor.worked(1);
+				}
+				helperMap.clear();
+			}
+		}
+
+		/**
+		 * Returns an array of items filtered using the provided
+		 * <code>ViewerFilter</code>s with a separator added.
+		 *
+		 * @param parent
+		 *            the parent
+		 * @param monitor
+		 *            progress monitor, can be <code>null</code>
+		 * @return an array of filtered items
+		 */
+		protected Object[] getFilteredItems(Object parent,
+				IProgressMonitor monitor) {
+			int ticks = 100;
+			if (monitor == null) {
+				monitor = new NullProgressMonitor();
+			}
+
+			monitor
+					.beginTask(
+							WorkbenchMessages.get().FilteredItemsSelectionDialog_cacheRefreshJob_getFilteredElements,
+							ticks);
+			if (filters != null) {
+				ticks /= (filters.size() + 2);
+			} else {
+				ticks /= 2;
+			}
+
+			// get already sorted array
+			Object[] filteredElements = getSortedItems();
+
+			monitor.worked(ticks);
+
+			// filter the elements using provided ViewerFilters
+			if (filters != null && filteredElements != null) {
+				for (Iterator iter = filters.iterator(); iter.hasNext();) {
+					ViewerFilter f = (ViewerFilter) iter.next();
+					filteredElements = f.filter(list, parent, filteredElements);
+					monitor.worked(ticks);
+				}
+			}
+
+			if (filteredElements == null || monitor.isCanceled()) {
+				monitor.done();
+				return new Object[0];
+			}
+
+			ArrayList preparedElements = new ArrayList();
+			boolean hasHistory = false;
+
+			if (filteredElements.length > 0) {
+				if (isHistoryElement(filteredElements[0])) {
+					hasHistory = true;
+				}
+			}
+
+			int reportEvery = filteredElements.length / ticks;
+
+			// add separator
+			for (int i = 0; i < filteredElements.length; i++) {
+				Object item = filteredElements[i];
+
+				if (hasHistory && !isHistoryElement(item)) {
+					preparedElements.add(itemsListSeparator);
+					hasHistory = false;
+				}
+
+				preparedElements.add(item);
+
+				if (reportEvery != 0 && ((i + 1) % reportEvery == 0)) {
+					monitor.worked(1);
+				}
+			}
+
+			monitor.done();
+
+			return preparedElements.toArray();
+		}
+
+		/**
+		 * Adds a filter to this content provider. For an example usage of such
+		 * filters look at the project <code>org.eclipse.ui.ide</code>, class
+		 * <code>org.eclipse.ui.dialogs.FilteredResourcesSelectionDialog.CustomWorkingSetFilter</code>.
+		 *
+		 *
+		 * @param filter
+		 *            the filter to be added
+		 */
+		public void addFilter(ViewerFilter filter) {
+			if (filters == null) {
+				filters = new ArrayList();
+			}
+			filters.add(filter);
+			// currently filters are only added when dialog is restored
+			// if it is changed, refreshing the whole TableViewer should be
+			// added
+		}
+
+	}
+	
+	/**
+     * A content provider that does nothing.
+     */
+    private class NullContentProvider implements IContentProvider {
+
+        @Override
+        public void dispose() {
+        }
+
+        @Override
+        public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+        }
+
+    }
+
+	/**
+	 * DetailsContentViewer objects are wrappers for labels.
+	 * DetailsContentViewer provides means to change label's image and text when
+	 * the attached LabelProvider is updated.
+	 */
+	private class DetailsContentViewer extends ContentViewer {
+
+		private CLabel label;
+
+		/**
+		 * Unfortunately, it was impossible to delegate displaying border to
+		 * label. The <code>ViewForm</code> is used because
+		 * <code>CLabel</code> displays shadow when border is present.
+		 */
+		private ViewForm viewForm;
+
+		/**
+		 * Constructs a new instance of this class given its parent and a style
+		 * value describing its behavior and appearance.
+		 *
+		 * @param parent
+		 *            the parent component
+		 * @param style
+		 *            SWT style bits
+		 */
+		public DetailsContentViewer(Composite parent, int style) {
+			viewForm = new ViewForm(parent, style);
+			GridData gd = new GridData(GridData.FILL_HORIZONTAL);
+			gd.horizontalSpan = 2;
+			viewForm.setLayoutData(gd);
+			label = new CLabel(viewForm, SWT.FLAT);
+			label.setFont(parent.getFont());
+			viewForm.setContent(label);
+			hookControl(label);
+		}
+
+		/**
+		 * Shows/hides the content viewer.
+		 *
+		 * @param visible
+		 *            if the content viewer should be visible.
+		 */
+		public void setVisible(boolean visible) {
+			viewForm.setVisible(visible);
+			GridData gd = (GridData) viewForm.getLayoutData();
+			gd.exclude = !visible;
+			viewForm.getParent().layout();
+		}
+
+		@Override
+		protected void inputChanged(Object input, Object oldInput) {
+			if (oldInput == null) {
+				if (input == null) {
+					return;
+				}
+				refresh();
+				return;
+			}
+
+			refresh();
+
+		}
+
+		@Override
+		protected void handleLabelProviderChanged(
+				LabelProviderChangedEvent event) {
+			if (event != null) {
+				refresh(event.getElements());
+			}
+		}
+
+		@Override
+		public Control getControl() {
+			return label;
+		}
+
+		@Override
+		public ISelection getSelection() {
+			// not supported
+			return null;
+		}
+
+		@Override
+		public void refresh() {
+			Object input = this.getInput();
+			if (input != null) {
+				ILabelProvider labelProvider = (ILabelProvider) getLabelProvider();
+				doRefresh(labelProvider.getText(input), labelProvider
+						.getImage(input));
+			} else {
+				doRefresh(null, null);
+			}
+		}
+
+		/**
+		 * Sets the given text and image to the label.
+		 *
+		 * @param text
+		 *            the new text or null
+		 * @param image
+		 *            the new image
+		 */
+		private void doRefresh(String text, Image image) {
+			if ( text != null ) {
+				text = LegacyActionTools.escapeMnemonics(text);
+			}
+			label.setText(text);
+			label.setImage(image);
+		}
+
+		@Override
+		public void setSelection(ISelection selection, boolean reveal) {
+			// not supported
+		}
+
+		/**
+		 * Refreshes the label if currently chosen element is on the list.
+		 *
+		 * @param objs
+		 *            list of changed object
+		 */
+		private void refresh(Object[] objs) {
+			if (objs == null || getInput() == null) {
+				return;
+			}
+			Object input = getInput();
+			for (Object obj : objs) {
+				if (obj.equals(input)) {
+					refresh();
+					break;
+				}
+			}
+		}
+	}
+
+	/**
+	 * Compares items according to the history.
+	 */
+	private class HistoryComparator implements Comparator {
+
+		@Override
+		public int compare(Object o1, Object o2) {
+			boolean h1 = isHistoryElement(o1);
+			boolean h2 = isHistoryElement(o2);
+			if (h1 == h2)
+				return getItemsComparator().compare(o1, o2);
+
+			if (h1)
+				return -2;
+			if (h2)
+				return +2;
+
+			return 0;
+		}
+
+	}
+
+
+	/**
+	 * Get the control where the search pattern is entered. Any filtering should
+	 * be done using an {@link ItemsFilter}. This control should only be
+	 * accessed for listeners that wish to handle events that do not affect
+	 * filtering such as custom traversal.
+	 *
+	 * @return Control or <code>null</code> if the pattern control has not
+	 *         been created.
+	 */
+	public Control getPatternControl() {
+		return pattern;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/FilteredList.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/FilteredList.java
new file mode 100644
index 0000000..e239afc
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/FilteredList.java
@@ -0,0 +1,776 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *   Sebastian Davids <sdavids@gmx.de> - Fix for bug 19346 - Dialog font should be activated and used by other components.
+ *******************************************************************************/
+package org.eclipse.ui.dialogs;
+
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.Vector;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.accessibility.Accessible;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.misc.StringMatcher;
+import org.eclipse.ui.internal.util.Util;
+import org.eclipse.ui.progress.WorkbenchJob;
+
+/**
+ * A composite widget which holds a list of elements for user selection. The
+ * elements are sorted alphabetically. Optionally, the elements can be filtered
+ * and duplicate entries can be hidden (folding).
+ *
+ * @since 2.0
+ */
+public class FilteredList extends Composite {
+	/**
+	 * The FilterMatcher is the interface used to check filtering criterea.
+	 */
+	public interface FilterMatcher {
+		/**
+		 * Sets the filter.
+		 *
+		 * @param pattern
+		 *            the filter pattern.
+		 * @param ignoreCase
+		 *            a flag indicating whether pattern matching is case
+		 *            insensitive or not.
+		 * @param ignoreWildCards
+		 *            a flag indicating whether wildcard characters are
+		 *            interpreted or not.
+		 */
+		void setFilter(String pattern, boolean ignoreCase,
+				boolean ignoreWildCards);
+
+		/**
+		 * @param element
+		 *            The element to test against.
+		 * @return <code>true</code> if the object matches the pattern,
+		 *         <code>false</code> otherwise. <code>setFilter()</code>
+		 *         must have been called at least once prior to a call to this
+		 *         method.
+		 */
+		boolean match(Object element);
+	}
+
+	private class DefaultFilterMatcher implements FilterMatcher {
+		private StringMatcher fMatcher;
+
+		@Override
+		public void setFilter(String pattern, boolean ignoreCase,
+				boolean ignoreWildCards) {
+			fMatcher = new StringMatcher(pattern + '*', ignoreCase,
+					ignoreWildCards);
+		}
+
+		@Override
+		public boolean match(Object element) {
+			return fMatcher.match(fLabelProvider.getText(element));
+		}
+	}
+
+	private Table fList;
+
+	ILabelProvider fLabelProvider;
+
+	private boolean fMatchEmptyString = true;
+
+	private boolean fIgnoreCase;
+
+	private boolean fAllowDuplicates;
+
+	private String fFilter = ""; //$NON-NLS-1$
+
+	private TwoArrayQuickSorter fSorter;
+
+	Object[] fElements = new Object[0];
+
+	Label[] fLabels;
+
+	Vector fImages = new Vector();
+
+	int[] fFoldedIndices;
+
+	int fFoldedCount;
+
+	int[] fFilteredIndices;
+
+	int fFilteredCount;
+
+	private FilterMatcher fFilterMatcher = new DefaultFilterMatcher();
+
+	Comparator fComparator;
+
+	TableUpdateJob fUpdateJob;
+
+	/**
+	 * Label is a private class used for comparing list objects
+	 */
+	private static class Label {
+		/**
+		 * The string portion of the label.
+		 */
+		public final String string;
+
+		/**
+		 * The image portion of the label.
+		 */
+		public final Image image;
+
+		/**
+		 * Create a new instance of label.
+		 *
+		 * @param newString
+		 * @param image
+		 */
+		public Label(String newString, Image image) {
+			if (newString == null) {
+				this.string = Util.ZERO_LENGTH_STRING;
+			} else {
+				this.string = newString;
+			}
+			this.image = image;
+		}
+
+		/**
+		 * Return whether or not the receiver is the same as label.
+		 *
+		 * @param label
+		 * @return boolean
+		 */
+		public boolean equals(Label label) {
+			if (label == null) {
+				return false;
+			}
+			// If the string portions match (whether null or not), fall
+			// through and check the image portion.
+			if (string == null && label.string != null) {
+				return false;
+			}
+			if ((string != null) && (!string.equals(label.string))) {
+				return false;
+			}
+			if (image == null) {
+				return label.image == null;
+			}
+			return image.equals(label.image);
+		}
+	}
+
+	private final class LabelComparator implements Comparator {
+		private boolean labelIgnoreCase;
+
+		LabelComparator(boolean ignoreCase) {
+			labelIgnoreCase = ignoreCase;
+		}
+
+		@Override
+		public int compare(Object left, Object right) {
+			Label leftLabel = (Label) left;
+			Label rightLabel = (Label) right;
+			int value;
+			if (fComparator == null) {
+				value = labelIgnoreCase ? leftLabel.string
+						.compareToIgnoreCase(rightLabel.string)
+						: leftLabel.string.compareTo(rightLabel.string);
+			} else {
+				value = fComparator
+						.compare(leftLabel.string, rightLabel.string);
+			}
+			if (value != 0) {
+				return value;
+			}
+			// images are allowed to be null
+			if (leftLabel.image == null) {
+				return (rightLabel.image == null) ? 0 : -1;
+			} else if (rightLabel.image == null) {
+				return +1;
+			} else {
+				return fImages.indexOf(leftLabel.image)
+						- fImages.indexOf(rightLabel.image);
+			}
+		}
+	}
+
+	/**
+	 * Constructs a new filtered list.
+	 *
+	 * @param parent
+	 *            the parent composite
+	 * @param style
+	 *            the widget style
+	 * @param labelProvider
+	 *            the label renderer
+	 * @param ignoreCase
+	 *            specifies whether sorting and folding is case sensitive
+	 * @param allowDuplicates
+	 *            specifies whether folding of duplicates is desired
+	 * @param matchEmptyString
+	 *            specifies whether empty filter strings should filter
+	 *            everything or nothing
+	 */
+	public FilteredList(Composite parent, int style,
+			ILabelProvider labelProvider, boolean ignoreCase,
+			boolean allowDuplicates, boolean matchEmptyString) {
+		super(parent, SWT.NONE);
+		GridLayout layout = new GridLayout();
+		layout.marginHeight = 0;
+		layout.marginWidth = 0;
+		setLayout(layout);
+		fList = new Table(this, style);
+		fList.setLayoutData(new GridData(GridData.FILL_BOTH));
+		fList.setFont(parent.getFont());
+		fList.addDisposeListener(e -> {
+			fLabelProvider.dispose();
+			if (fUpdateJob != null) {
+				fUpdateJob.cancel();
+			}
+		});
+		fLabelProvider = labelProvider;
+		fIgnoreCase = ignoreCase;
+		fSorter = new TwoArrayQuickSorter(new LabelComparator(ignoreCase));
+		fAllowDuplicates = allowDuplicates;
+		fMatchEmptyString = matchEmptyString;
+	}
+
+	/**
+	 * Sets the list of elements.
+	 *
+	 * @param elements
+	 *            the elements to be shown in the list.
+	 */
+	public void setElements(Object[] elements) {
+		if (elements == null) {
+			fElements = new Object[0];
+		} else {
+			// copy list for sorting
+			fElements = new Object[elements.length];
+			System.arraycopy(elements, 0, fElements, 0, elements.length);
+		}
+		int length = fElements.length;
+		// fill labels
+		fLabels = new Label[length];
+		Set imageSet = new HashSet();
+		for (int i = 0; i != length; i++) {
+			String text = fLabelProvider.getText(fElements[i]);
+			Image image = fLabelProvider.getImage(fElements[i]);
+			fLabels[i] = new Label(text, image);
+			imageSet.add(image);
+		}
+		fList.deselectAll();
+		fImages.clear();
+		fImages.addAll(imageSet);
+		fSorter.sort(fLabels, fElements);
+		fFilteredIndices = new int[length];
+		fFoldedIndices = new int[length];
+		updateList();
+	}
+
+	/**
+	 * Tests if the list (before folding and filtering) is empty.
+	 *
+	 * @return returns <code>true</code> if the list is empty,
+	 *         <code>false</code> otherwise.
+	 */
+	public boolean isEmpty() {
+		return (fElements == null) || (fElements.length == 0);
+	}
+
+	/**
+	 * Sets the filter matcher.
+	 *
+	 * @param filterMatcher
+	 */
+	public void setFilterMatcher(FilterMatcher filterMatcher) {
+		Assert.isNotNull(filterMatcher);
+		fFilterMatcher = filterMatcher;
+	}
+
+	/**
+	 * Sets a custom comparator for sorting the list.
+	 *
+	 * @param comparator
+	 */
+	public void setComparator(Comparator comparator) {
+		Assert.isNotNull(comparator);
+		fComparator = comparator;
+	}
+
+	/**
+	 * Adds a selection listener to the list.
+	 *
+	 * @param listener
+	 *            the selection listener to be added.
+	 */
+	public void addSelectionListener(SelectionListener listener) {
+		fList.addSelectionListener(listener);
+	}
+
+	/**
+	 * Removes a selection listener from the list.
+	 *
+	 * @param listener
+	 *            the selection listener to be removed.
+	 */
+	public void removeSelectionListener(SelectionListener listener) {
+		fList.removeSelectionListener(listener);
+	}
+
+	/**
+	 * Sets the selection of the list. Empty or null array removes selection.
+	 *
+	 * @param selection
+	 *            an array of indices specifying the selection.
+	 */
+	public void setSelection(int[] selection) {
+		if (selection == null || selection.length == 0) {
+			fList.deselectAll();
+		} else {
+			// If there is no working update job, or the update job is ready to
+			// accept selections, set the selection immediately.
+			if (fUpdateJob == null) {
+				fList.setSelection(selection);
+				fList.notifyListeners(SWT.Selection, new Event());
+			} else {
+				// There is an update job doing the population of the list, so
+				// it should update the selection.
+				fUpdateJob.updateSelection(selection);
+			}
+		}
+	}
+
+	/**
+	 * Returns the selection of the list.
+	 *
+	 * @return returns an array of indices specifying the current selection.
+	 */
+	public int[] getSelectionIndices() {
+		return fList.getSelectionIndices();
+	}
+
+	/**
+	 * Returns the selection of the list. This is a convenience function for
+	 * <code>getSelectionIndices()</code>.
+	 *
+	 * @return returns the index of the selection, -1 for no selection.
+	 */
+	public int getSelectionIndex() {
+		return fList.getSelectionIndex();
+	}
+
+	/**
+	 * Sets the selection of the list. Empty or null array removes selection.
+	 *
+	 * @param elements
+	 *            the array of elements to be selected.
+	 */
+	public void setSelection(Object[] elements) {
+		if (elements == null || elements.length == 0) {
+			fList.deselectAll();
+			return;
+		}
+		if (fElements == null) {
+			return;
+		}
+		// fill indices
+		int[] indices = new int[elements.length];
+		for (int i = 0; i != elements.length; i++) {
+			int j;
+			for (j = 0; j != fFoldedCount; j++) {
+				int max = (j == fFoldedCount - 1) ? fFilteredCount
+						: fFoldedIndices[j + 1];
+				int l;
+				for (l = fFoldedIndices[j]; l != max; l++) {
+					// found matching element?
+					if (fElements[fFilteredIndices[l]].equals(elements[i])) {
+						indices[i] = j;
+						break;
+					}
+				}
+				if (l != max) {
+					break;
+				}
+			}
+			// not found
+			if (j == fFoldedCount) {
+				indices[i] = 0;
+			}
+		}
+		setSelection(indices);
+	}
+
+	/**
+	 * Returns an array of the selected elements. The type of the elements
+	 * returned in the list are the same as the ones passed with
+	 * <code>setElements</code>. The array does not contain the rendered
+	 * strings.
+	 *
+	 * @return returns the array of selected elements.
+	 */
+	public Object[] getSelection() {
+		if (fList.isDisposed() || (fList.getSelectionCount() == 0)) {
+			return new Object[0];
+		}
+		int[] indices = fList.getSelectionIndices();
+		Object[] elements = new Object[indices.length];
+		for (int i = 0; i != indices.length; i++) {
+			elements[i] = fElements[fFilteredIndices[fFoldedIndices[indices[i]]]];
+		}
+		return elements;
+	}
+
+	/**
+	 * Sets the filter pattern. Current only prefix filter patterns are
+	 * supported.
+	 *
+	 * @param filter
+	 *            the filter pattern.
+	 */
+	public void setFilter(String filter) {
+		fFilter = (filter == null) ? "" : filter; //$NON-NLS-1$
+		updateList();
+	}
+
+	private void updateList() {
+		fFilteredCount = filter();
+		fFoldedCount = fold();
+		if (fUpdateJob != null) {
+			fUpdateJob.cancel();
+		}
+		fUpdateJob = new TableUpdateJob(fList, fFoldedCount);
+		fUpdateJob.schedule();
+	}
+
+	/**
+	 * Returns the filter pattern.
+	 *
+	 * @return returns the filter pattern.
+	 */
+	public String getFilter() {
+		return fFilter;
+	}
+
+	/**
+	 * Returns all elements which are folded together to one entry in the list.
+	 *
+	 * @param index
+	 *            the index selecting the entry in the list.
+	 * @return returns an array of elements folded together, <code>null</code>
+	 *         if index is out of range.
+	 */
+	public Object[] getFoldedElements(int index) {
+		if ((index < 0) || (index >= fFoldedCount)) {
+			return null;
+		}
+		int start = fFoldedIndices[index];
+		int count = (index == fFoldedCount - 1) ? fFilteredCount - start
+				: fFoldedIndices[index + 1] - start;
+		Object[] elements = new Object[count];
+		for (int i = 0; i != count; i++) {
+			elements[i] = fElements[fFilteredIndices[start + i]];
+		}
+		return elements;
+	}
+
+	/*
+	 * Folds duplicate entries. Two elements are considered as a pair of
+	 * duplicates if they coiincide in the rendered string and image. @return
+	 * returns the number of elements after folding.
+	 */
+	private int fold() {
+		if (fAllowDuplicates) {
+			for (int i = 0; i != fFilteredCount; i++) {
+				fFoldedIndices[i] = i; // identity mapping
+			}
+			return fFilteredCount;
+		}
+		int k = 0;
+		Label last = null;
+		for (int i = 0; i != fFilteredCount; i++) {
+			int j = fFilteredIndices[i];
+			Label current = fLabels[j];
+			if (!current.equals(last)) {
+				fFoldedIndices[k] = i;
+				k++;
+				last = current;
+			}
+		}
+		return k;
+	}
+
+	/*
+	 * Filters the list with the filter pattern. @return returns the number of
+	 * elements after filtering.
+	 */
+	private int filter() {
+		if (((fFilter == null) || (fFilter.length() == 0))
+				&& !fMatchEmptyString) {
+			return 0;
+		}
+		fFilterMatcher.setFilter(fFilter.trim(), fIgnoreCase, false);
+		int k = 0;
+		for (int i = 0; i != fElements.length; i++) {
+			if (fFilterMatcher.match(fElements[i])) {
+				fFilteredIndices[k++] = i;
+			}
+		}
+		return k;
+	}
+
+	private class TableUpdateJob extends WorkbenchJob {
+		final Table fTable;
+
+		final int fCount;
+
+		private int currentIndex = 0;
+
+		/*
+		 * Programmatic selections requested while this job was running.
+		 */
+		int[] indicesToSelect;
+
+		private boolean readyForSelection = false;
+
+		/**
+		 * Create a new instance of a job used to update the table.
+		 *
+		 * @param table
+		 * @param count
+		 *            The number of items to update per running.
+		 */
+		public TableUpdateJob(Table table, int count) {
+			super(WorkbenchMessages.get().FilteredList_UpdateJobName);
+			setSystem(true);
+			fTable = table;
+			fCount = count;
+		}
+
+@Override
+public IStatus runInUIThread(IProgressMonitor monitor) {
+            if (fTable.isDisposed()) {
+				return Status.CANCEL_STATUS;
+			}
+            int itemCount = fTable.getItemCount();
+
+            // Remove excess items
+            if (fCount < itemCount) {
+                fTable.setRedraw(false);
+                fTable.remove(fCount, itemCount - 1);
+                fTable.setRedraw(true);
+                itemCount = fTable.getItemCount();
+            }
+            // table empty -> no selection
+            if (fCount == 0) {
+                fTable.notifyListeners(SWT.Selection, new Event());
+                return Status.OK_STATUS;
+            }
+            // How many we are going to do this time.
+            int iterations = Math.min(10, fCount - currentIndex);
+            for (int i = 0; i < iterations; i++) {
+                if (monitor.isCanceled()) {
+					return Status.CANCEL_STATUS;
+				}
+                final TableItem item = (currentIndex < itemCount) ? fTable
+                        .getItem(currentIndex)
+                        : new TableItem(fTable, SWT.NONE);
+                final Label label = fLabels[fFilteredIndices[fFoldedIndices[currentIndex]]];
+                item.setText(label.string);
+                item.setImage(label.image);
+                currentIndex++;
+            }
+            if (monitor.isCanceled()) {
+				return Status.CANCEL_STATUS;
+			}
+            if (currentIndex < fCount) {
+				schedule(100);
+			} else {
+                if (indicesToSelect == null) {
+                 	// Make a default selection in the table if there is none.
+                	// If a selection has already been made, honor it.
+                	// See https://bugs.eclipse.org/bugs/show_bug.cgi?id=112146
+                    if (fCount > 0) {
+                    	if (fTable.getSelectionIndices().length == 0) {
+                    		defaultSelect();
+                    	} else {
+                    		// There is a selection, but it likely hasn't changed since the
+                    		// job started.  Force a selection notification, since the
+                    		// items represented by the selection have changed.
+							// See https://bugs.eclipse.org/bugs/show_bug.cgi?id=119456
+                    		fTable.notifyListeners(SWT.Selection, new Event());
+                    	}
+                    }
+                } else {
+                	// Set the selection as indicated.
+                    selectAndNotify(indicesToSelect);
+                }
+                // This flag signifies that the selection can now be directly
+                // updated in the widget.
+                readyForSelection = true;
+            }
+            return Status.OK_STATUS;
+        }
+		/**
+		 * Update the selection for the supplied indices.
+		 *
+		 * @param indices
+		 */
+		void updateSelection(final int[] indices) {
+			indicesToSelect = indices;
+			if (readyForSelection) {
+				selectAndNotify(indices);
+			}
+		}
+
+		/**
+		 * Select the first element if there is no selection
+		 */
+		private void defaultSelect() {
+			/**
+			 * Reset to the first selection if no index has been queued.
+			 */
+			selectAndNotify(new int[] { 0 });
+		}
+
+		/**
+		 * Select the supplied indices and notify any listeners
+		 *
+		 * @param indices
+		 */
+		private void selectAndNotify(final int[] indices) {
+			// It is possible that the table was disposed
+			// before the update finished. If so then leave
+			if (fTable.isDisposed()) {
+				return;
+			}
+			fTable.setSelection(indices);
+			fTable.notifyListeners(SWT.Selection, new Event());
+		}
+	}
+
+	/**
+	 * Returns whether or not duplicates are allowed.
+	 *
+	 * @return <code>true</code> indicates duplicates are allowed
+	 */
+	public boolean getAllowDuplicates() {
+		return fAllowDuplicates;
+	}
+
+	/**
+	 * Sets whether or not duplicates are allowed. If this value is set the
+	 * items should be set again for this value to take effect.
+	 *
+	 * @param allowDuplicates
+	 *            <code>true</code> indicates duplicates are allowed
+	 */
+	public void setAllowDuplicates(boolean allowDuplicates) {
+		this.fAllowDuplicates = allowDuplicates;
+	}
+
+	/**
+	 * Returns whether or not case should be ignored.
+	 *
+	 * @return <code>true</code> if case should be ignored
+	 */
+	public boolean getIgnoreCase() {
+		return fIgnoreCase;
+	}
+
+	/**
+	 * Sets whether or not case should be ignored If this value is set the items
+	 * should be set again for this value to take effect.
+	 *
+	 * @param ignoreCase
+	 *            <code>true</code> if case should be ignored
+	 */
+	public void setIgnoreCase(boolean ignoreCase) {
+		this.fIgnoreCase = ignoreCase;
+	}
+
+	/**
+	 * Returns whether empty filter strings should filter everything or nothing.
+	 *
+	 * @return <code>true</code> for the empty string to match all items,
+	 *         <code>false</code> to match none
+	 */
+	public boolean getMatchEmptyString() {
+		return fMatchEmptyString;
+	}
+
+	/**
+	 * Sets whether empty filter strings should filter everything or nothing. If
+	 * this value is set the items should be set again for this value to take
+	 * effect.
+	 *
+	 * @param matchEmptyString
+	 *            <code>true</code> for the empty string to match all items,
+	 *            <code>false</code> to match none
+	 */
+	public void setMatchEmptyString(boolean matchEmptyString) {
+		this.fMatchEmptyString = matchEmptyString;
+	}
+
+	/**
+	 * Returns the label provider for the items.
+	 *
+	 * @return the label provider
+	 */
+	public ILabelProvider getLabelProvider() {
+		return fLabelProvider;
+	}
+
+	/**
+	 * Sets the label provider. If this value is set the items should be set
+	 * again for this value to take effect.
+	 *
+	 * @param labelProvider
+	 *            the label provider
+	 */
+	public void setLabelProvider(ILabelProvider labelProvider) {
+		this.fLabelProvider = labelProvider;
+	}
+
+	/**
+	 * Returns the accessible object for the receiver.
+	 * If this is the first time this object is requested,
+	 * then the object is created and returned.
+	 *
+	 * @return the accessible object
+	 *
+	 * @exception SWTException <ul>
+	 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+	 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+	 * </ul>
+	 *
+	 * @see Accessible#addAccessibleListener
+	 * @see Accessible#addAccessibleControlListener
+	 *
+	 * @since 3.3
+	 */
+	@Override
+	public Accessible getAccessible() {
+		return fList.getAccessible();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/FilteredTree.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/FilteredTree.java
new file mode 100644
index 0000000..9f0fce2
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/FilteredTree.java
@@ -0,0 +1,1267 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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
+ *     Jacek Pospychala - bug 187762
+ *     Mohamed Tarief - tarief@eg.ibm.com - IBM - Bug 174481
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 422040
+ *******************************************************************************/
+package org.eclipse.ui.dialogs;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.ToolBarManager;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.viewers.IContentProvider;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.accessibility.AccessibleAdapter;
+import org.eclipse.swt.accessibility.AccessibleEvent;
+import org.eclipse.swt.events.FocusAdapter;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseMoveListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.ui.IWorkbenchPreferenceConstants;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.eclipse.ui.progress.WorkbenchJob;
+
+/**
+ * A simple control that provides a text widget and a tree viewer. The contents
+ * of the text widget are used to drive a PatternFilter that is on the viewer.
+ *
+ * @see org.eclipse.ui.dialogs.PatternFilter
+ * @since 3.2
+ */
+public class FilteredTree extends Composite {
+
+	/**
+	 * The filter text widget to be used by this tree. This value may be
+	 * <code>null</code> if there is no filter widget, or if the controls have
+	 * not yet been created.
+	 */
+	protected Text filterText;
+
+	/**
+	 * The control representing the clear button for the filter text entry. This
+	 * value may be <code>null</code> if no such button exists, or if the
+	 * controls have not yet been created.
+	 * <p>
+	 * <strong>Note:</strong> As of 3.5, this is not used if the new look is chosen.
+	 * </p>
+	 */
+	protected ToolBarManager filterToolBar;
+
+	/**
+	 * The control representing the clear button for the filter text entry. This
+	 * value may be <code>null</code> if no such button exists, or if the
+	 * controls have not yet been created.
+	 * <p>
+	 * <strong>Note:</strong> This is only used if the new look is chosen.
+	 * </p>
+	 *
+	 * @since 3.5
+	 */
+	protected Control clearButtonControl;
+
+
+	/**
+	 * The viewer for the filtered tree. This value should never be
+	 * <code>null</code> after the widget creation methods are complete.
+	 */
+	protected TreeViewer treeViewer;
+
+	/**
+	 * The Composite on which the filter controls are created. This is used to
+	 * set the background color of the filter controls to match the surrounding
+	 * controls.
+	 */
+	protected Composite filterComposite;
+
+	/**
+	 * The pattern filter for the tree. This value must not be <code>null</code>.
+	 */
+	private PatternFilter patternFilter;
+
+	/**
+	 * The text to initially show in the filter text control.
+	 */
+	protected String initialText = ""; //$NON-NLS-1$
+
+	/**
+	 * The job used to refresh the tree.
+	 */
+	private Job refreshJob;
+
+	/**
+	 * The parent composite of the filtered tree.
+	 *
+	 * @since 3.3
+	 */
+	protected Composite parent;
+
+	/**
+	 * Whether or not to show the filter controls (text and clear button). The
+	 * default is to show these controls. This can be overridden by providing a
+	 * setting in the product configuration file. The setting to add to not show
+	 * these controls is:
+	 *
+	 * org.eclipse.ui/SHOW_FILTERED_TEXTS=false
+	 */
+	protected boolean showFilterControls;
+
+	/**
+	 * @since 3.3
+	 */
+	protected Composite treeComposite;
+
+	/**
+	 * Tells whether to use the pre 3.5 or the new look.
+	 *
+	 * @since 3.5
+	 */
+	private boolean useNewLook = false;
+
+	/**
+	 * Tells whether this filtetered tree is used to make quick selections. In
+	 * this mode the first match in the tree is automatically selected while
+	 * filtering and the 'Enter' key is not used to move the focus to the tree.
+	 *
+	 * @since 3.105
+	 */
+	private boolean quickSelectionMode = false;
+
+	/**
+	 * Image descriptor for enabled clear button.
+	 */
+	private static final String CLEAR_ICON = "org.eclipse.ui.internal.dialogs.CLEAR_ICON"; //$NON-NLS-1$
+
+	/**
+	 * Image descriptor for disabled clear button.
+	 */
+	private static final String DISABLED_CLEAR_ICON= "org.eclipse.ui.internal.dialogs.DCLEAR_ICON"; //$NON-NLS-1$
+
+	/**
+	 * Maximum time spent expanding the tree after the filter text has been
+	 * updated (this is only used if we were able to at least expand the visible
+	 * nodes)
+	 */
+	private static final long SOFT_MAX_EXPAND_TIME = 200;
+
+	/**
+	 * Get image descriptors for the clear button.
+	 */
+	static {
+		ImageDescriptor descriptor = AbstractUIPlugin
+				.imageDescriptorFromPlugin(PlatformUI.PLUGIN_ID,
+						"$nl$/icons/full/etool16/clear_co.png"); //$NON-NLS-1$
+		if (descriptor != null) {
+			JFaceResources.getImageRegistry().put(CLEAR_ICON, descriptor);
+		}
+		descriptor = AbstractUIPlugin.imageDescriptorFromPlugin(
+				PlatformUI.PLUGIN_ID, "$nl$/icons/full/dtool16/clear_co.png"); //$NON-NLS-1$
+		if (descriptor != null) {
+			JFaceResources.getImageRegistry().put(DISABLED_CLEAR_ICON, descriptor);
+		}
+	}
+
+	/**
+	 * Create a new instance of the receiver.
+	 *
+	 * @param parent
+	 *            the parent <code>Composite</code>
+	 * @param treeStyle
+	 *            the style bits for the <code>Tree</code>
+	 * @param filter
+	 *            the filter to be used
+	 *
+	 * @deprecated As of 3.5, replaced by
+	 *             {@link #FilteredTree(Composite, int, PatternFilter, boolean)} where using the new
+	 *             look is encouraged
+	 */
+	@Deprecated
+	public FilteredTree(Composite parent, int treeStyle, PatternFilter filter) {
+		super(parent, SWT.NONE);
+		this.parent = parent;
+		init(treeStyle, filter);
+	}
+
+	/**
+	 * Create a new instance of the receiver.
+	 *
+	 * @param parent
+	 *            the parent <code>Composite</code>
+	 * @param treeStyle
+	 *            the style bits for the <code>Tree</code>
+	 * @param filter
+	 *            the filter to be used
+	 * @param useNewLook
+	 *            <code>true</code> if the new 3.5 look should be used
+	 * @since 3.5
+	 */
+	public FilteredTree(Composite parent, int treeStyle, PatternFilter filter, boolean useNewLook) {
+		super(parent, SWT.NONE);
+		this.parent = parent;
+		this.useNewLook= useNewLook;
+		init(treeStyle, filter);
+	}
+
+	/**
+	 * Create a new instance of the receiver. Subclasses that wish to override
+	 * the default creation behavior may use this constructor, but must ensure
+	 * that the <code>init(composite, int, PatternFilter)</code> method is
+	 * called in the overriding constructor.
+	 *
+	 * @param parent
+	 *            the parent <code>Composite</code>
+	 * @see #init(int, PatternFilter)
+	 *
+	 * @since 3.3
+	 * @deprecated As of 3.5, replaced by {@link #FilteredTree(Composite, boolean)} where using the
+	 *             look is encouraged
+	 */
+	@Deprecated
+	protected FilteredTree(Composite parent) {
+		super(parent, SWT.NONE);
+		this.parent = parent;
+	}
+
+	/**
+	 * Create a new instance of the receiver. Subclasses that wish to override
+	 * the default creation behavior may use this constructor, but must ensure
+	 * that the <code>init(composite, int, PatternFilter)</code> method is
+	 * called in the overriding constructor.
+	 *
+	 * @param parent
+	 *            the parent <code>Composite</code>
+	 * @param useNewLook
+	 *            <code>true</code> if the new 3.5 look should be used
+	 * @see #init(int, PatternFilter)
+	 *
+	 * @since 3.5
+	 */
+	protected FilteredTree(Composite parent, boolean useNewLook) {
+		super(parent, SWT.NONE);
+		this.parent = parent;
+		this.useNewLook = useNewLook;
+	}
+
+	/**
+	 * Create the filtered tree.
+	 *
+	 * @param treeStyle
+	 *            the style bits for the <code>Tree</code>
+	 * @param filter
+	 *            the filter to be used
+	 *
+	 * @since 3.3
+	 */
+	protected void init(int treeStyle, PatternFilter filter) {
+		patternFilter = filter;
+		showFilterControls = PlatformUI.getPreferenceStore().getBoolean(
+				IWorkbenchPreferenceConstants.SHOW_FILTERED_TEXTS);
+		createControl(parent, treeStyle);
+		createRefreshJob();
+		setInitialText(WorkbenchMessages.get().FilteredTree_FilterMessage);
+		setFont(parent.getFont());
+
+	}
+
+	/**
+	 * Create the filtered tree's controls. Subclasses should override.
+	 *
+	 * @param parent
+	 * @param treeStyle
+	 */
+	protected void createControl(Composite parent, int treeStyle) {
+		GridLayout layout = new GridLayout();
+		layout.marginHeight = 0;
+		layout.marginWidth = 0;
+		setLayout(layout);
+
+		if (parent.getLayout() instanceof GridLayout) {
+			setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+		}
+
+		if (showFilterControls) {
+			if (!useNewLook || useNativeSearchField(parent)) {
+				filterComposite= new Composite(this, SWT.NONE);
+			} else {
+				filterComposite= new Composite(this, SWT.BORDER);
+				filterComposite.setBackground(getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
+			}
+			GridLayout filterLayout= new GridLayout(2, false);
+			filterLayout.marginHeight= 0;
+			filterLayout.marginWidth= 0;
+			filterComposite.setLayout(filterLayout);
+			filterComposite.setFont(parent.getFont());
+
+			createFilterControls(filterComposite);
+			filterComposite.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING,
+					true, false));
+		}
+
+		treeComposite = new Composite(this, SWT.NONE);
+		GridLayout treeCompositeLayout = new GridLayout();
+		treeCompositeLayout.marginHeight = 0;
+		treeCompositeLayout.marginWidth = 0;
+		treeComposite.setLayout(treeCompositeLayout);
+		GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
+		treeComposite.setLayoutData(data);
+		createTreeControl(treeComposite, treeStyle);
+	}
+
+	private static Boolean useNativeSearchField;
+
+	private static boolean useNativeSearchField(Composite composite) {
+		if (useNativeSearchField == null) {
+			useNativeSearchField = Boolean.FALSE;
+			Text testText = null;
+			try {
+				testText = new Text(composite, SWT.SEARCH | SWT.ICON_CANCEL);
+				useNativeSearchField = Boolean.valueOf((testText.getStyle() & SWT.ICON_CANCEL) != 0);
+			} finally {
+				if (testText != null) {
+					testText.dispose();
+				}
+			}
+
+		}
+		return useNativeSearchField.booleanValue();
+	}
+
+
+	/**
+	 * Create the filter controls. By default, a text and corresponding tool bar
+	 * button that clears the contents of the text is created. Subclasses may
+	 * override.
+	 *
+	 * @param parent
+	 *            parent <code>Composite</code> of the filter controls
+	 * @return the <code>Composite</code> that contains the filter controls
+	 */
+	protected Composite createFilterControls(Composite parent) {
+		createFilterText(parent);
+		if (useNewLook)
+			createClearTextNew(parent);
+		else
+			createClearTextOld(parent);
+		if (clearButtonControl != null) {
+			// initially there is no text to clear
+			clearButtonControl.setVisible(false);
+		}
+		if (filterToolBar != null) {
+			filterToolBar.update(false);
+			// initially there is no text to clear
+			filterToolBar.getControl().setVisible(false);
+		}
+		return parent;
+	}
+
+	/**
+	 * Creates and set up the tree and tree viewer. This method calls
+	 * {@link #doCreateTreeViewer(Composite, int)} to create the tree viewer.
+	 * Subclasses should override {@link #doCreateTreeViewer(Composite, int)}
+	 * instead of overriding this method.
+	 *
+	 * @param parent
+	 *            parent <code>Composite</code>
+	 * @param style
+	 *            SWT style bits used to create the tree
+	 * @return the tree
+	 */
+	protected Control createTreeControl(Composite parent, int style) {
+		treeViewer = doCreateTreeViewer(parent, style);
+		GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
+		treeViewer.getControl().setLayoutData(data);
+		treeViewer.getControl().addDisposeListener(e -> refreshJob.cancel());
+		if (treeViewer instanceof NotifyingTreeViewer) {
+			patternFilter.setUseCache(true);
+		}
+		treeViewer.addFilter(patternFilter);
+		return treeViewer.getControl();
+	}
+
+	/**
+	 * Creates the tree viewer. Subclasses may override.
+	 *
+	 * @param parent
+	 *            the parent composite
+	 * @param style
+	 *            SWT style bits used to create the tree viewer
+	 * @return the tree viewer
+	 *
+	 * @since 3.3
+	 */
+	protected TreeViewer doCreateTreeViewer(Composite parent, int style) {
+		return new NotifyingTreeViewer(parent, style);
+	}
+
+	/**
+	 * Return the first item in the tree that matches the filter pattern.
+	 *
+	 * @param items
+	 * @return the first matching TreeItem
+	 */
+	private TreeItem getFirstMatchingItem(TreeItem[] items) {
+		for (TreeItem item : items) {
+			if (patternFilter.isLeafMatch(treeViewer, item.getData())
+					&& patternFilter.isElementSelectable(item.getData())) {
+				return item;
+			}
+			TreeItem treeItem = getFirstMatchingItem(item.getItems());
+			if (treeItem != null) {
+				return treeItem;
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Create the refresh job for the receiver.
+	 *
+	 */
+	private void createRefreshJob() {
+		refreshJob = doCreateRefreshJob();
+		refreshJob.setSystem(true);
+	}
+
+	/**
+	 * Creates a workbench job that will refresh the tree based on the current filter text.
+	 * Subclasses may override.
+	 *
+	 * @return a workbench job that can be scheduled to refresh the tree
+	 *
+	 * @since 3.4
+	 */
+	protected WorkbenchJob doCreateRefreshJob() {
+		return new WorkbenchJob("Refresh Filter") {//$NON-NLS-1$
+			@Override
+			public IStatus runInUIThread(IProgressMonitor monitor) {
+				if (treeViewer.getControl().isDisposed()) {
+					return Status.CANCEL_STATUS;
+				}
+
+				String text = getFilterString();
+				if (text == null) {
+					return Status.OK_STATUS;
+				}
+
+				boolean initial = initialText != null
+						&& initialText.equals(text);
+				if (initial) {
+					patternFilter.setPattern(null);
+				} else if (text != null) {
+					patternFilter.setPattern(text);
+				}
+
+				Control redrawFalseControl = treeComposite != null ? treeComposite
+						: treeViewer.getControl();
+				try {
+					// don't want the user to see updates that will be made to
+					// the tree
+					// we are setting redraw(false) on the composite to avoid
+					// dancing scrollbar
+					redrawFalseControl.setRedraw(false);
+					if (!narrowingDown) {
+						// collapse all
+						TreeItem[] is = treeViewer.getTree().getItems();
+						for (TreeItem item : is) {
+							if (item.getExpanded()) {
+								treeViewer.setExpandedState(item.getData(),
+										false);
+							}
+						}
+					}
+					treeViewer.refresh(true);
+
+					if (text.length() > 0 && !initial) {
+						/*
+						 * Expand elements one at a time. After each is
+						 * expanded, check to see if the filter text has been
+						 * modified. If it has, then cancel the refresh job so
+						 * the user doesn't have to endure expansion of all the
+						 * nodes.
+						 */
+						TreeItem[] items = getViewer().getTree().getItems();
+						int treeHeight = getViewer().getTree().getBounds().height;
+						int numVisibleItems = treeHeight
+								/ getViewer().getTree().getItemHeight();
+						long stopTime = SOFT_MAX_EXPAND_TIME
+								+ System.currentTimeMillis();
+						boolean cancel = false;
+						if (items.length > 0
+								&& recursiveExpand(items, monitor, stopTime,
+										new int[] { numVisibleItems })) {
+							cancel = true;
+						}
+
+						// enabled toolbar - there is text to clear
+						// and the list is currently being filtered
+						updateToolbar(true);
+
+						if (cancel) {
+							return Status.CANCEL_STATUS;
+						}
+					} else {
+						// disabled toolbar - there is no text to clear
+						// and the list is currently not filtered
+						updateToolbar(false);
+					}
+				} finally {
+					// done updating the tree - set redraw back to true
+					TreeItem[] items = getViewer().getTree().getItems();
+					if (items.length > 0
+							&& getViewer().getTree().getSelectionCount() == 0) {
+						treeViewer.getTree().setTopItem(items[0]);
+					}
+					if (quickSelectionMode)
+						updateTreeSelection(false);
+					redrawFalseControl.setRedraw(true);
+				}
+				return Status.OK_STATUS;
+			}
+
+			/**
+			 * Returns true if the job should be canceled (because of timeout or
+			 * actual cancellation).
+			 *
+			 * @param items
+			 * @param monitor
+			 * @param cancelTime
+			 * @param numItemsLeft
+			 * @return true if canceled
+			 */
+			private boolean recursiveExpand(TreeItem[] items,
+					IProgressMonitor monitor, long cancelTime,
+					int[] numItemsLeft) {
+				boolean canceled = false;
+				for (int i = 0; !canceled && i < items.length; i++) {
+					TreeItem item = items[i];
+					boolean visible = numItemsLeft[0]-- >= 0;
+					if (monitor.isCanceled()
+							|| (!visible && System.currentTimeMillis() > cancelTime)) {
+						canceled = true;
+					} else {
+						Object itemData = item.getData();
+						if (itemData != null) {
+							if (!item.getExpanded()) {
+								// do the expansion through the viewer so that
+								// it can refresh children appropriately.
+								treeViewer.setExpandedState(itemData, true);
+							}
+							TreeItem[] children = item.getItems();
+							if (items.length > 0) {
+								canceled = recursiveExpand(children, monitor,
+										cancelTime, numItemsLeft);
+							}
+						}
+					}
+				}
+				return canceled;
+			}
+
+		};
+	}
+
+	protected void updateToolbar(boolean visible) {
+		if (clearButtonControl != null) {
+			clearButtonControl.setVisible(visible);
+		}
+		if (filterToolBar != null) {
+			filterToolBar.getControl().setVisible(visible);
+		}
+	}
+
+	/**
+	 * Creates the filter text and adds listeners. This method calls
+	 * {@link #doCreateFilterText(Composite)} to create the text control.
+	 * Subclasses should override {@link #doCreateFilterText(Composite)} instead
+	 * of overriding this method.
+	 *
+	 * @param parent
+	 *            <code>Composite</code> of the filter text
+	 */
+	protected void createFilterText(Composite parent) {
+		filterText = doCreateFilterText(parent);
+		filterText.getAccessible().addAccessibleListener(
+				new AccessibleAdapter() {
+					@Override
+					public void getName(AccessibleEvent e) {
+						String filterTextString = filterText.getText();
+						if (filterTextString.length() == 0
+								|| filterTextString.equals(initialText)) {
+							e.result = initialText;
+						} else {
+							e.result = NLS
+									.bind(
+											WorkbenchMessages.get().FilteredTree_AccessibleListenerFiltered,
+											new String[] {
+													filterTextString,
+													String
+															.valueOf(getFilteredItemsCount()) });
+						}
+					}
+
+					/**
+					 * Return the number of filtered items
+					 * @return int
+					 */
+					private int getFilteredItemsCount() {
+						int total = 0;
+						TreeItem[] items = getViewer().getTree().getItems();
+						for (TreeItem item : items) {
+							total += itemCount(item);
+
+						}
+						return total;
+					}
+
+					/**
+					 * Return the count of treeItem and it's children to infinite depth.
+					 * @param treeItem
+					 * @return int
+					 */
+					private int itemCount(TreeItem treeItem) {
+						int count = 1;
+						TreeItem[] children = treeItem.getItems();
+						for (TreeItem element : children) {
+							count += itemCount(element);
+
+						}
+						return count;
+					}
+				});
+
+		filterText.addFocusListener(new FocusAdapter() {
+			@Override
+			public void focusGained(FocusEvent e) {
+				if (!useNewLook) {
+					/*
+					 * Running in an asyncExec because the selectAll() does not appear to work when
+					 * using mouse to give focus to text.
+					 */
+					Display display= filterText.getDisplay();
+					display.asyncExec(() -> {
+						if (!filterText.isDisposed()) {
+							if (getInitialText().equals(
+									filterText.getText().trim())) {
+								filterText.selectAll();
+							}
+						}
+					});
+					return;
+				}
+			}
+
+			@Override
+			public void focusLost(FocusEvent e) {
+				if (!useNewLook) {
+					return;
+				}
+				if (filterText.getText().equals(initialText)) {
+					setFilterText(""); //$NON-NLS-1$
+					textChanged();
+				}
+			}
+		});
+
+		if (useNewLook) {
+			filterText.addMouseListener(new MouseAdapter() {
+				@Override
+				public void mouseDown(MouseEvent e) {
+					if (filterText.getText().equals(initialText)) {
+						// XXX: We cannot call clearText() due to https://bugs.eclipse.org/bugs/show_bug.cgi?id=260664
+						setFilterText(""); //$NON-NLS-1$
+						textChanged();
+					}
+				}
+			});
+		}
+
+		filterText.addKeyListener(new KeyAdapter() {
+			@Override
+			public void keyPressed(KeyEvent e) {
+				// on a CR we want to transfer focus to the list
+				boolean hasItems = getViewer().getTree().getItemCount() > 0;
+				if (hasItems && e.keyCode == SWT.ARROW_DOWN) {
+					treeViewer.getTree().setFocus();
+					return;
+				}
+			}
+		});
+
+		// enter key set focus to tree
+		filterText.addTraverseListener(e -> {
+			if (quickSelectionMode) {
+				return;
+			}
+			if (e.detail == SWT.TRAVERSE_RETURN) {
+				e.doit = false;
+				updateTreeSelection(true);
+			}
+		});
+
+		filterText.addModifyListener(e -> textChanged());
+
+		// if we're using a field with built in cancel we need to listen for
+		// default selection changes (which tell us the cancel button has been
+		// pressed)
+		if ((filterText.getStyle() & SWT.ICON_CANCEL) != 0) {
+		    filterText.addSelectionListener(new SelectionAdapter() {
+                @Override
+                public void widgetDefaultSelected(SelectionEvent e) {
+                    if (e.detail == SWT.ICON_CANCEL)
+                        clearText();
+                }
+            });
+		}
+
+		GridData gridData= new GridData(SWT.FILL, SWT.CENTER, true, false);
+		// if the text widget supported cancel then it will have it's own
+		// integrated button. We can take all of the space.
+		if ((filterText.getStyle() & SWT.ICON_CANCEL) != 0)
+			gridData.horizontalSpan = 2;
+		filterText.setLayoutData(gridData);
+	}
+
+	/**
+	 * Updates the selection in the tree, based on the filter text.
+	 *
+	 * @param setFocus
+	 *            <code>true</code> if the focus should be set on the tree,
+	 *            <code>false</code> otherwise
+	 * @since 3.105
+	 */
+	protected void updateTreeSelection(boolean setFocus) {
+		Tree tree = getViewer().getTree();
+		if (tree.getItemCount() == 0) {
+			if (setFocus)
+				Display.getCurrent().beep();
+		} else {
+			// if the initial filter text hasn't changed, do not try
+			// to match
+			boolean hasFocus = setFocus ? tree.setFocus() : true;
+			boolean textChanged = !getInitialText().equals(filterText.getText().trim());
+			if (hasFocus && textChanged && filterText.getText().trim().length() > 0) {
+				TreeItem item;
+				if (tree.getSelectionCount() > 0)
+					item = getFirstMatchingItem(tree.getSelection());
+				else
+					item = getFirstMatchingItem(tree.getItems());
+				if (item != null) {
+					tree.setSelection(new TreeItem[] { item });
+					ISelection sel = getViewer().getSelection();
+					getViewer().setSelection(sel, true);
+				}
+			}
+		}
+	}
+
+	/**
+	 * Creates the text control for entering the filter text. Subclasses may
+	 * override.
+	 *
+	 * @param parent
+	 *            the parent composite
+	 * @return the text widget
+	 *
+	 * @since 3.3
+	 */
+	protected Text doCreateFilterText(Composite parent) {
+		if (!useNewLook || useNativeSearchField(parent)) {
+			return new Text(parent, SWT.SINGLE | SWT.BORDER | SWT.SEARCH
+					| SWT.ICON_CANCEL);
+		}
+		return new Text(parent, SWT.SINGLE);
+	}
+
+	private String previousFilterText;
+
+	private boolean narrowingDown;
+
+	/**
+	 * Update the receiver after the text has changed.
+	 */
+	protected void textChanged() {
+		narrowingDown = previousFilterText == null
+				|| previousFilterText
+						.equals(WorkbenchMessages.get().FilteredTree_FilterMessage)
+				|| getFilterString().startsWith(previousFilterText);
+		previousFilterText = getFilterString();
+		// cancel currently running job first, to prevent unnecessary redraw
+		refreshJob.cancel();
+		refreshJob.schedule(getRefreshJobDelay());
+	}
+
+	/**
+	 * Return the time delay that should be used when scheduling the
+	 * filter refresh job.  Subclasses may override.
+	 *
+	 * @return a time delay in milliseconds before the job should run
+	 *
+	 * @since 3.5
+	 */
+	protected long getRefreshJobDelay() {
+		return 200;
+	}
+
+	/**
+	 * Set the background for the widgets that support the filter text area.
+	 *
+	 * @param background
+	 *            background <code>Color</code> to set
+	 */
+	@Override
+	public void setBackground(Color background) {
+		super.setBackground(background);
+		if (filterComposite != null && (!useNewLook || useNativeSearchField(filterComposite))) {
+			filterComposite.setBackground(background);
+		}
+		if (filterToolBar != null && filterToolBar.getControl() != null) {
+			filterToolBar.getControl().setBackground(background);
+		}
+	}
+
+	/**
+	 * Create the button that clears the text.
+	 *
+	 * @param parent
+	 *            parent <code>Composite</code> of toolbar button
+	 */
+	private void createClearTextOld(Composite parent) {
+		// only create the button if the text widget doesn't support one
+		// natively
+		if ((filterText.getStyle() & SWT.ICON_CANCEL) == 0) {
+			filterToolBar= new ToolBarManager(SWT.FLAT | SWT.HORIZONTAL);
+			filterToolBar.createControl(parent);
+
+			IAction clearTextAction= new Action("", IAction.AS_PUSH_BUTTON) {//$NON-NLS-1$
+				@Override
+				public void run() {
+					clearText();
+				}
+			};
+
+			clearTextAction
+					.setToolTipText(WorkbenchMessages.get().FilteredTree_ClearToolTip);
+			clearTextAction.setImageDescriptor(JFaceResources
+					.getImageRegistry().getDescriptor(CLEAR_ICON));
+			clearTextAction.setDisabledImageDescriptor(JFaceResources
+.getImageRegistry().getDescriptor(DISABLED_CLEAR_ICON));
+
+			filterToolBar.add(clearTextAction);
+		}
+	}
+
+	/**
+	 * Create the button that clears the text.
+	 *
+	 * @param parent parent <code>Composite</code> of toolbar button
+	 */
+	private void createClearTextNew(Composite parent) {
+		// only create the button if the text widget doesn't support one
+		// natively
+		if ((filterText.getStyle() & SWT.ICON_CANCEL) == 0) {
+			final Image inactiveImage= JFaceResources.getImageRegistry().getDescriptor(DISABLED_CLEAR_ICON).createImage();
+			final Image activeImage= JFaceResources.getImageRegistry().getDescriptor(CLEAR_ICON).createImage();
+			// RAP [bm] IMAGE_GRAY
+//			final Image pressedImage= new Image(getDisplay(), activeImage, SWT.IMAGE_GRAY);
+			final Image pressedImage= new Image(getDisplay(), activeImage, SWT.IMAGE_COPY);
+
+			final Label clearButton= new Label(parent, SWT.NONE);
+			clearButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
+			clearButton.setImage(inactiveImage);
+			clearButton.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
+			clearButton.setToolTipText(WorkbenchMessages.get().FilteredTree_ClearToolTip);
+			clearButton.addMouseListener(new MouseAdapter() {
+				private MouseMoveListener fMoveListener;
+
+				@Override
+				public void mouseDown(MouseEvent e) {
+					clearButton.setImage(pressedImage);
+					fMoveListener= new MouseMoveListener() {
+						private boolean fMouseInButton= true;
+
+						@Override
+						public void mouseMove(MouseEvent e) {
+							boolean mouseInButton= isMouseInButton(e);
+							if (mouseInButton != fMouseInButton) {
+								fMouseInButton= mouseInButton;
+								clearButton.setImage(mouseInButton ? pressedImage : inactiveImage);
+							}
+						}
+					};
+					// RAP [bm] mouse move listener
+//					clearButton.addMouseMoveListener(fMoveListener);
+				}
+
+				@Override
+				public void mouseUp(MouseEvent e) {
+					if (fMoveListener != null) {
+						// RAP [bm] mouse move listener
+//						clearButton.removeMouseMoveListener(fMoveListener);
+						fMoveListener= null;
+						boolean mouseInButton= isMouseInButton(e);
+						clearButton.setImage(mouseInButton ? activeImage : inactiveImage);
+						if (mouseInButton) {
+							clearText();
+							filterText.setFocus();
+						}
+					}
+				}
+
+				private boolean isMouseInButton(MouseEvent e) {
+					Point buttonSize = clearButton.getSize();
+					return 0 <= e.x && e.x < buttonSize.x && 0 <= e.y && e.y < buttonSize.y;
+				}
+			});
+			// RAP [bm] MouseTrackListener
+//			clearButton.addMouseTrackListener(new MouseTrackListener() {
+//				@Override
+//				public void mouseEnter(MouseEvent e) {
+//					clearButton.setImage(activeImage);
+//				}
+//
+//				@Override
+//				public void mouseExit(MouseEvent e) {
+//					clearButton.setImage(inactiveImage);
+//				}
+//
+//				@Override
+//				public void mouseHover(MouseEvent e) {
+//				}
+//			});
+			clearButton.addDisposeListener(e -> {
+				inactiveImage.dispose();
+				activeImage.dispose();
+				pressedImage.dispose();
+			});
+			// RAP [bm] Accessibility
+//			clearButton.getAccessible().addAccessibleListener(
+//				new AccessibleAdapter() {
+//					@Override
+//					public void getName(AccessibleEvent e) {
+//						e.result= WorkbenchMessages.FilteredTree_AccessibleListenerClearButton;
+//					}
+//			});
+//			clearButton.getAccessible().addAccessibleControlListener(
+//				new AccessibleControlAdapter() {
+//					@Override
+//					public void getRole(AccessibleControlEvent e) {
+//						e.detail= ACC.ROLE_PUSHBUTTON;
+//					}
+//			});
+			this.clearButtonControl= clearButton;
+		}
+	}
+
+	/**
+	 * Clears the text in the filter text widget.
+	 */
+	protected void clearText() {
+		setFilterText(""); //$NON-NLS-1$
+		textChanged();
+	}
+
+	/**
+	 * Set the text in the filter control.
+	 *
+	 * @param string
+	 */
+	protected void setFilterText(String string) {
+		if (filterText != null) {
+			filterText.setText(string);
+			selectAll();
+		}
+	}
+
+	/**
+	 * Returns the pattern filter used by this tree.
+	 *
+	 * @return The pattern filter; never <code>null</code>.
+	 */
+	public final PatternFilter getPatternFilter() {
+		return patternFilter;
+	}
+
+	/**
+	 * Get the tree viewer of the receiver.
+	 *
+	 * @return the tree viewer
+	 */
+	public TreeViewer getViewer() {
+		return treeViewer;
+	}
+
+	/**
+	 * Get the filter text for the receiver, if it was created. Otherwise return
+	 * <code>null</code>.
+	 *
+	 * @return the filter Text, or null if it was not created
+	 */
+	public Text getFilterControl() {
+		return filterText;
+	}
+
+	/**
+	 * Convenience method to return the text of the filter control. If the text
+	 * widget is not created, then null is returned.
+	 *
+	 * @return String in the text, or null if the text does not exist
+	 */
+	protected String getFilterString() {
+		return filterText != null ? filterText.getText() : null;
+	}
+
+	/**
+	 * Set the text that will be shown until the first focus. A default value is
+	 * provided, so this method only need be called if overriding the default
+	 * initial text is desired.
+	 *
+	 * @param text
+	 *            initial text to appear in text field
+	 */
+	public void setInitialText(String text) {
+		initialText = text;
+		if (useNewLook && filterText != null) {
+			filterText.setMessage(text);
+			if (filterText.isFocusControl()) {
+				setFilterText(initialText);
+				textChanged();
+			} else {
+				getDisplay().asyncExec(() -> {
+					if (!filterText.isDisposed() && filterText.isFocusControl()) {
+						setFilterText(initialText);
+						textChanged();
+					}
+				});
+			}
+		} else {
+			setFilterText(initialText);
+			textChanged();
+		}
+	}
+
+	/**
+	 * Sets whether this filtered tree is used to make quick selections. In this
+	 * mode the first match in the tree is automatically selected while
+	 * filtering and the 'Enter' key is not used to move the focus to the tree.
+	 * <p>
+	 * By default, this is set to <code>false</code>.
+	 * </p>
+	 *
+	 * @param enabled
+	 *            <code>true</code> if this filtered tree is used to make quick
+	 *            selections, <code>false</code> otherwise
+	 * @since 3.105
+	 */
+	public void setQuickSelectionMode(boolean enabled) {
+		this.quickSelectionMode = enabled;
+	}
+
+	/**
+	 * Select all text in the filter text field.
+	 *
+	 */
+	protected void selectAll() {
+		if (filterText != null) {
+			filterText.selectAll();
+		}
+	}
+
+	/**
+	 * Get the initial text for the receiver.
+	 *
+	 * @return String
+	 */
+	protected String getInitialText() {
+		return initialText;
+	}
+
+	/**
+	 * Return a bold font if the given element matches the given pattern.
+	 * Clients can opt to call this method from a Viewer's label provider to get
+	 * a bold font for which to highlight the given element in the tree.
+	 *
+	 * @param element
+	 *            element for which a match should be determined
+	 * @param tree
+	 *            FilteredTree in which the element resides
+	 * @param filter
+	 *            PatternFilter which determines a match
+	 *
+	 * @return bold font
+	 */
+	public static Font getBoldFont(Object element, FilteredTree tree,
+			PatternFilter filter) {
+		String filterText = tree.getFilterString();
+
+		if (filterText == null) {
+			return null;
+		}
+
+		// Do nothing if it's empty string
+		String initialText = tree.getInitialText();
+		if (!filterText.equals("") && !filterText.equals(initialText)) {//$NON-NLS-1$
+			if (tree.getPatternFilter() != filter) {
+				boolean initial= initialText != null
+					&& initialText.equals(filterText);
+				if (initial) {
+					filter.setPattern(null);
+				} else if (filterText != null) {
+					filter.setPattern(filterText);
+				}
+			}
+			if (filter.isElementVisible(tree.getViewer(), element)
+					&& filter.isLeafMatch(tree.getViewer(), element)) {
+				return JFaceResources.getFontRegistry().getBold(
+						JFaceResources.DIALOG_FONT);
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Custom tree viewer subclass that clears the caches in patternFilter on
+	 * any change to the tree. See bug 187200.
+	 *
+	 * @since 3.3
+	 *
+	 */
+	class NotifyingTreeViewer extends TreeViewer {
+
+		/**
+		 * @param parent
+		 * @param style
+		 */
+		public NotifyingTreeViewer(Composite parent, int style) {
+			super(parent, style);
+		}
+
+		@Override
+		public void add(Object parentElementOrTreePath, Object childElement) {
+			getPatternFilter().clearCaches();
+			super.add(parentElementOrTreePath, childElement);
+		}
+
+		@Override
+		public void add(Object parentElementOrTreePath, Object[] childElements) {
+			getPatternFilter().clearCaches();
+			super.add(parentElementOrTreePath, childElements);
+		}
+
+		@Override
+		protected void inputChanged(Object input, Object oldInput) {
+			getPatternFilter().clearCaches();
+			super.inputChanged(input, oldInput);
+		}
+
+		@Override
+		public void insert(Object parentElementOrTreePath, Object element,
+				int position) {
+			getPatternFilter().clearCaches();
+			super.insert(parentElementOrTreePath, element, position);
+		}
+
+		@Override
+		public void refresh() {
+			getPatternFilter().clearCaches();
+			super.refresh();
+		}
+
+		@Override
+		public void refresh(boolean updateLabels) {
+			getPatternFilter().clearCaches();
+			super.refresh(updateLabels);
+		}
+
+		@Override
+		public void refresh(Object element) {
+			getPatternFilter().clearCaches();
+			super.refresh(element);
+		}
+
+		@Override
+		public void refresh(Object element, boolean updateLabels) {
+			getPatternFilter().clearCaches();
+			super.refresh(element, updateLabels);
+		}
+
+		@Override
+		public void remove(Object elementsOrTreePaths) {
+			getPatternFilter().clearCaches();
+			super.remove(elementsOrTreePaths);
+		}
+
+		@Override
+		public void remove(Object parent, Object[] elements) {
+			getPatternFilter().clearCaches();
+			super.remove(parent, elements);
+		}
+
+		@Override
+		public void remove(Object[] elementsOrTreePaths) {
+			getPatternFilter().clearCaches();
+			super.remove(elementsOrTreePaths);
+		}
+
+		@Override
+		public void replace(Object parentElementOrTreePath, int index,
+				Object element) {
+			getPatternFilter().clearCaches();
+			super.replace(parentElementOrTreePath, index, element);
+		}
+
+		@Override
+		public void setChildCount(Object elementOrTreePath, int count) {
+			getPatternFilter().clearCaches();
+			super.setChildCount(elementOrTreePath, count);
+		}
+
+		@Override
+		public void setContentProvider(IContentProvider provider) {
+			getPatternFilter().clearCaches();
+			super.setContentProvider(provider);
+		}
+
+		@Override
+		public void setHasChildren(Object elementOrTreePath, boolean hasChildren) {
+			getPatternFilter().clearCaches();
+			super.setHasChildren(elementOrTreePath, hasChildren);
+		}
+
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/IOverwriteQuery.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/IOverwriteQuery.java
new file mode 100644
index 0000000..28ca273
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/IOverwriteQuery.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.dialogs;
+
+/**
+ *	Implementors of this interface answer one of the prescribed return codes
+ *	when asked whether to overwrite a certain path string (which could
+ *	represent a resource path, a file system path, etc).
+ */
+public interface IOverwriteQuery {
+    /**
+     * Return code indicating the operation should be canceled.
+     */
+    public static final String CANCEL = "CANCEL"; //$NON-NLS-1$
+
+    /**
+     * Return code indicating the entity should not be overwritten,
+     * but operation should not be canceled.
+     */
+    public static final String NO = "NO"; //$NON-NLS-1$
+
+    /**
+     * Return code indicating the entity should be overwritten.
+     */
+    public static final String YES = "YES"; //$NON-NLS-1$
+
+    /**
+     * Return code indicating the entity should be overwritten,
+     * and all subsequent entities should be overwritten without prompting.
+     */
+    public static final String ALL = "ALL"; //$NON-NLS-1$
+
+    /**
+     * Return code indicating the entity should not be overwritten,
+     * and all subsequent entities should not be overwritten without prompting.
+     */
+    public static final String NO_ALL = "NOALL"; //$NON-NLS-1$
+
+    /**
+     * Returns one of the return code constants declared on this interface,
+     * indicating whether the entity represented by the passed String should be overwritten.
+     * <p>
+     * This method may be called from a non-UI thread, in which case this method must run the query
+     * in a sync exec in the UI thread, if it needs to query the user.
+     * </p>
+     * @param pathString the path representing the entity to be overwritten
+     * @return one of the return code constants declared on this interface
+     */
+    String queryOverwrite(String pathString);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/ISelectionStatusValidator.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/ISelectionStatusValidator.java
new file mode 100644
index 0000000..884e497
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/ISelectionStatusValidator.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.dialogs;
+
+import org.eclipse.core.runtime.IStatus;
+
+/**
+ * Used in selection dialogs to validate selections
+ *
+ * @since 2.0
+ */
+public interface ISelectionStatusValidator {
+
+    /**
+     * Validates an array of elements and returns the resulting status.
+     * @param selection The elements to validate
+     * @return The resulting status
+     */
+    IStatus validate(Object[] selection);
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/ISelectionValidator.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/ISelectionValidator.java
new file mode 100644
index 0000000..0a3e9b2
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/ISelectionValidator.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.dialogs;
+
+/**
+ * For validating selections in some selection dialogs.
+ * <p>
+ * Clients should implement this interface to define specialized selection
+ * validators.
+ * </p>
+ */
+public interface ISelectionValidator {
+    /**
+     * Returns a string indicating whether the given selection is valid. If the
+     * result is <code>null</code>, the selection is considered to be valid; if the result is
+     * non-empty, it contains the error message to be displayed to the user.
+     *
+     * @param selection the selection to be validated
+     * @return the error message, or <code>null</code> indicating
+     *	that the value is valid
+     */
+    public String isValid(Object selection);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/IWorkingSetEditWizard.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/IWorkingSetEditWizard.java
new file mode 100644
index 0000000..5256f7d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/IWorkingSetEditWizard.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.dialogs;
+
+import org.eclipse.jface.wizard.IWizard;
+import org.eclipse.ui.IWorkingSet;
+
+/**
+ * A working set edit wizard allows editing a working set using
+ * the IWorkingSetPage associated with the working set.
+ * See the org.eclipse.ui.workingSets extension point for details.
+ * <p>
+ * Use org.eclipse.ui.IWorkingSetManager#createWorkingSetEditWizard(IWorkingSet)
+ * to create an instance of this wizard.
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ * @see org.eclipse.ui.IWorkingSetManager
+ * @since 2.1
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IWorkingSetEditWizard extends IWizard {
+    /**
+     * Returns the working set edited in the wizard.
+     *
+     * @return the working set edited in the wizard.
+     */
+    public IWorkingSet getSelection();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/IWorkingSetNewWizard.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/IWorkingSetNewWizard.java
new file mode 100644
index 0000000..c1edb30
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/IWorkingSetNewWizard.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.dialogs;
+
+import org.eclipse.jface.wizard.IWizard;
+import org.eclipse.ui.IWorkingSet;
+
+/**
+ * A working set new wizard allows creating new working sets using
+ * a plug-in specific working set page.
+ * <p>
+ * Use org.eclipse.ui.IWorkingSetManager#createWorkingSetNewWizard(String[] workingSetIds)
+ * to create an instance of this wizard.
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ * @see org.eclipse.ui.IWorkingSetManager
+ * @see org.eclipse.ui.dialogs.IWorkingSetPage
+ *
+ * @since 3.1
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IWorkingSetNewWizard extends IWizard {
+
+    /**
+     * Returns the new working set. Returns <code>null</code> if the wizard has
+     * been cancelled.
+     *
+     * @return the new working set or <code>null</code> if the wizard has been
+     * 	cancelled.
+     */
+    public IWorkingSet getSelection();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/IWorkingSetPage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/IWorkingSetPage.java
new file mode 100644
index 0000000..9157a8a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/IWorkingSetPage.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.dialogs;
+
+import org.eclipse.jface.wizard.IWizardPage;
+import org.eclipse.ui.IWorkingSet;
+
+/**
+ * A working set page allows the user to edit an existing
+ * working set and create a new working set.
+ * <p>
+ * Clients should implement this interface and include the
+ * name of their class in an extension contributed to the
+ * workbench's working set extension point
+ * (named <code>"org.eclipse.ui.workingSets"</code>) if they
+ * want to provide a special wizard page for a particular
+ * working set element type.
+ * </p>
+ * <p>
+ * Clients implementing this interface may subclass from
+ * org.eclipse.jface.wizard.WizardPage.
+ * </p>
+ *
+ * @since 2.0
+ */
+public interface IWorkingSetPage extends IWizardPage {
+    /**
+     * Called when the working set wizard is closed by selecting
+     * the finish button.
+     * Implementers may store the page result (new/changed working
+     * set returned in getSelection) here.
+     */
+    public void finish();
+
+    /**
+     * Returns the working set edited or created on the page
+     * after the wizard has closed.
+     * Returns the working set that was initially set using
+     * <code>setSelection</code>if the wizard has not been
+     * closed yet.
+     * Implementors should return the object set in setSelection
+     * instead of making a copy and returning the changed copy.
+     *
+     * @return the working set edited or created on the page.
+     */
+    public IWorkingSet getSelection();
+
+    /**
+     * Sets the working set edited on the page.
+     * Implementors should not make a copy of this working set.
+     * The passed object can be edited as is and should be
+     * returned in getSelection().
+     *
+     * @param workingSet the working set edited on the page.
+     */
+    public void setSelection(IWorkingSet workingSet);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/IWorkingSetSelectionDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/IWorkingSetSelectionDialog.java
new file mode 100644
index 0000000..a845bc7
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/IWorkingSetSelectionDialog.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.dialogs;
+
+import org.eclipse.ui.IWorkingSet;
+
+/**
+ * A working set selection dialog displays the list of working
+ * sets available in the workbench.
+ * <p>
+ * Use org.eclipse.ui.IWorkingSetManager#createWorkingSetSelectionDialog(Shell)
+ * to create an instance of this dialog.
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ * @see org.eclipse.ui.IWorkingSetManager
+ * @since 2.0
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IWorkingSetSelectionDialog {
+    /**
+     * Returns the working sets selected in the dialog or
+     * <code>null</code> if the dialog was canceled.
+     *
+     * @return the working sets selected in the dialog.
+     */
+    public IWorkingSet[] getSelection();
+
+    /**
+     * Displays the working set selection dialog.
+     *
+     * @return Window.OK if the dialog closes with the working
+     * 	set selection confirmed.
+     * 	Window.CANCEL if the dialog closes with the working set
+     * 	selection dismissed.
+     * @see org.eclipse.jface.window.Window
+     */
+    public int open();
+
+    /**
+     * Sets the working sets that are initially selected in the dialog.
+     *
+     * @param workingSets the working sets to select in the dialog.
+     */
+    public void setSelection(IWorkingSet[] workingSets);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/ListDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/ListDialog.java
new file mode 100644
index 0000000..19d698c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/ListDialog.java
@@ -0,0 +1,186 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.dialogs;
+
+import java.util.List;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+
+/**
+ * A dialog that prompts for one element out of a list of elements. Uses
+ * <code>IStructuredContentProvider</code> to provide the elements and
+ * <code>ILabelProvider</code> to provide their labels.
+ *
+ * @since 2.1
+ */
+public class ListDialog extends SelectionDialog {
+    private IStructuredContentProvider fContentProvider;
+
+    private ILabelProvider fLabelProvider;
+
+    private Object fInput;
+
+    private TableViewer fTableViewer;
+
+    private boolean fAddCancelButton = true;
+
+    private int widthInChars = 55;
+
+    private int heightInChars = 15;
+
+    /**
+     * Create a new instance of the receiver with parent shell of parent.
+     * @param parent
+     */
+    public ListDialog(Shell parent) {
+        super(parent);
+    }
+
+    /**
+     * @param input The input for the list.
+     */
+    public void setInput(Object input) {
+        fInput = input;
+    }
+
+    /**
+     * @param sp The content provider for the list.
+     */
+    public void setContentProvider(IStructuredContentProvider sp) {
+        fContentProvider = sp;
+    }
+
+    /**
+     * @param lp The labelProvider for the list.
+     */
+    public void setLabelProvider(ILabelProvider lp) {
+        fLabelProvider = lp;
+    }
+
+    /**
+     *@param addCancelButton if <code>true</code> there will be a cancel
+     * button.
+     */
+    public void setAddCancelButton(boolean addCancelButton) {
+        fAddCancelButton = addCancelButton;
+    }
+
+    /**
+     * @return the TableViewer for the receiver.
+     */
+    public TableViewer getTableViewer() {
+        return fTableViewer;
+    }
+
+    @Override
+	protected void createButtonsForButtonBar(Composite parent) {
+        if (!fAddCancelButton) {
+			createButton(parent, IDialogConstants.OK_ID,
+                    IDialogConstants.get().OK_LABEL, true);
+		} else {
+			super.createButtonsForButtonBar(parent);
+		}
+    }
+
+    @Override
+	protected Control createDialogArea(Composite container) {
+        Composite parent = (Composite) super.createDialogArea(container);
+        createMessageArea(parent);
+        fTableViewer = new TableViewer(parent, getTableStyle());
+        fTableViewer.setContentProvider(fContentProvider);
+        fTableViewer.setLabelProvider(fLabelProvider);
+        fTableViewer.setInput(fInput);
+        fTableViewer.addDoubleClickListener(event -> {
+		    if (fAddCancelButton) {
+				okPressed();
+			}
+		});
+        List initialSelection = getInitialElementSelections();
+        if (initialSelection != null) {
+			fTableViewer
+                    .setSelection(new StructuredSelection(initialSelection));
+		}
+        GridData gd = new GridData(GridData.FILL_BOTH);
+        gd.heightHint = convertHeightInCharsToPixels(heightInChars);
+        gd.widthHint = convertWidthInCharsToPixels(widthInChars);
+        Table table = fTableViewer.getTable();
+        table.setLayoutData(gd);
+        table.setFont(container.getFont());
+        return parent;
+    }
+
+    /**
+     * Return the style flags for the table viewer.
+     * @return int
+     */
+    protected int getTableStyle() {
+        return SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER;
+    }
+
+    /*
+     * Overrides method from Dialog
+     */
+    @Override
+	protected void okPressed() {
+        // Build a list of selected children.
+		IStructuredSelection selection = fTableViewer.getStructuredSelection();
+        setResult(selection.toList());
+        super.okPressed();
+    }
+
+    /**
+     * Returns the initial height of the dialog in number of characters.
+     *
+     * @return the initial height of the dialog in number of characters
+     */
+    public int getHeightInChars() {
+        return heightInChars;
+    }
+
+    /**
+     * Returns the initial width of the dialog in number of characters.
+     *
+     * @return the initial width of the dialog in number of characters
+     */
+    public int getWidthInChars() {
+        return widthInChars;
+    }
+
+    /**
+     * Sets the initial height of the dialog in number of characters.
+     *
+     * @param heightInChars
+     *            the initialheight of the dialog in number of characters
+     */
+    public void setHeightInChars(int heightInChars) {
+        this.heightInChars = heightInChars;
+    }
+
+    /**
+     * Sets the initial width of the dialog in number of characters.
+     *
+     * @param widthInChars
+     *            the initial width of the dialog in number of characters
+     */
+    public void setWidthInChars(int widthInChars) {
+        this.widthInChars = widthInChars;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/ListSelectionDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/ListSelectionDialog.java
new file mode 100644
index 0000000..36eb466
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/ListSelectionDialog.java
@@ -0,0 +1,237 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ * 	   Sebastian Davids <sdavids@gmx.de> - Fix for bug 90273 - [Dialogs]
+ * 			ListSelectionDialog dialog alignment
+ *******************************************************************************/
+package org.eclipse.ui.dialogs;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.viewers.CheckboxTableViewer;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchMessages;
+
+/**
+ * A standard dialog which solicits a list of selections from the user.
+ * This class is configured with an arbitrary data model represented by content
+ * and label provider objects. The <code>getResult</code> method returns the
+ * selected elements.
+ * <p>
+ * This class may be instantiated; it is not intended to be subclassed.
+ * </p>
+ * <p>
+ * Example:
+ * <pre>
+ * ListSelectionDialog dlg =
+ *   new ListSelectionDialog(
+ *       getShell(),
+ *       input,
+ *       new BaseWorkbenchContentProvider(),
+ *		 new WorkbenchLabelProvider(),
+ *		 "Select the resources to save:");
+ *	dlg.setInitialSelections(dirtyEditors);
+ *	dlg.setTitle("Save Resources");
+ *	dlg.open();
+ * </pre>
+ * </p>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class ListSelectionDialog extends SelectionDialog {
+    // the root element to populate the viewer with
+    private Object inputElement;
+
+    // providers for populating this dialog
+    private ILabelProvider labelProvider;
+
+    private IStructuredContentProvider contentProvider;
+
+    // the visual selection widget group
+    CheckboxTableViewer listViewer;
+
+    // sizing constants
+    private final static int SIZING_SELECTION_WIDGET_HEIGHT = 250;
+
+    private final static int SIZING_SELECTION_WIDGET_WIDTH = 300;
+
+    /**
+     * Creates a list selection dialog.
+     *
+     * @param parentShell the parent shell
+     * @param input	the root element to populate this dialog with
+     * @param contentProvider the content provider for navigating the model
+     * @param labelProvider the label provider for displaying model elements
+     * @param message the message to be displayed at the top of this dialog, or
+     *    <code>null</code> to display a default message
+     */
+    public ListSelectionDialog(Shell parentShell, Object input,
+            IStructuredContentProvider contentProvider,
+            ILabelProvider labelProvider, String message) {
+        super(parentShell);
+        setTitle(WorkbenchMessages.get().ListSelection_title);
+        inputElement = input;
+        this.contentProvider = contentProvider;
+        this.labelProvider = labelProvider;
+        if (message != null) {
+			setMessage(message);
+		} else {
+			setMessage(WorkbenchMessages.get().ListSelection_message);
+		}
+    }
+
+    /**
+     * Add the selection and deselection buttons to the dialog.
+     * @param composite org.eclipse.swt.widgets.Composite
+     */
+    private void addSelectionButtons(Composite composite) {
+        Composite buttonComposite = new Composite(composite, SWT.NONE);
+        GridLayout layout = new GridLayout();
+        layout.numColumns = 0;
+		layout.marginWidth = 0;
+		layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
+        buttonComposite.setLayout(layout);
+        buttonComposite.setLayoutData(new GridData(SWT.END, SWT.TOP, true, false));
+
+        Button selectButton = createButton(buttonComposite,
+                IDialogConstants.SELECT_ALL_ID, SELECT_ALL_TITLE, false);
+
+        SelectionListener listener = new SelectionAdapter()
+        {
+            /** {@inheritDoc} */
+            @Override
+            public void widgetSelected(SelectionEvent e)
+            {
+                listViewer.setAllChecked(true);
+            }
+        };
+        selectButton.addSelectionListener(listener);
+
+        Button deselectButton = createButton(buttonComposite,
+                IDialogConstants.DESELECT_ALL_ID, DESELECT_ALL_TITLE, false);
+
+        listener = new SelectionAdapter()
+        {
+            /** {@inheritDoc} */
+            @Override
+            public void widgetSelected(SelectionEvent e)
+            {
+                listViewer.setAllChecked(false);
+            }
+        };
+        deselectButton.addSelectionListener(listener);
+    }
+
+    /**
+     * Visually checks the previously-specified elements in this dialog's list
+     * viewer.
+     */
+    private void checkInitialSelections() {
+        Iterator itemsToCheck = getInitialElementSelections().iterator();
+
+        while (itemsToCheck.hasNext()) {
+			listViewer.setChecked(itemsToCheck.next(), true);
+		}
+    }
+
+    @Override
+	protected void configureShell(Shell shell) {
+        super.configureShell(shell);
+        PlatformUI.getWorkbench().getHelpSystem().setHelp(shell,
+				IWorkbenchHelpContextIds.LIST_SELECTION_DIALOG);
+    }
+
+    @Override
+	protected Control createDialogArea(Composite parent) {
+        // page group
+        Composite composite = (Composite) super.createDialogArea(parent);
+
+        initializeDialogUnits(composite);
+
+        createMessageArea(composite);
+
+        listViewer = CheckboxTableViewer.newCheckList(composite, SWT.BORDER);
+        GridData data = new GridData(GridData.FILL_BOTH);
+        data.heightHint = SIZING_SELECTION_WIDGET_HEIGHT;
+        data.widthHint = SIZING_SELECTION_WIDGET_WIDTH;
+        listViewer.getTable().setLayoutData(data);
+
+        listViewer.setLabelProvider(labelProvider);
+        listViewer.setContentProvider(contentProvider);
+
+        addSelectionButtons(composite);
+
+        initializeViewer();
+
+        // initialize page
+        if (!getInitialElementSelections().isEmpty()) {
+			checkInitialSelections();
+		}
+
+        Dialog.applyDialogFont(composite);
+
+        return composite;
+    }
+
+    /**
+     * Returns the viewer used to show the list.
+     *
+     * @return the viewer, or <code>null</code> if not yet created
+     */
+    protected CheckboxTableViewer getViewer() {
+        return listViewer;
+    }
+
+    /**
+     * Initializes this dialog's viewer after it has been laid out.
+     */
+    private void initializeViewer() {
+        listViewer.setInput(inputElement);
+    }
+
+    /**
+     * The <code>ListSelectionDialog</code> implementation of this
+     * <code>Dialog</code> method builds a list of the selected elements for later
+     * retrieval by the client and closes this dialog.
+     */
+    @Override
+	protected void okPressed() {
+
+        // Get the input children.
+        Object[] children = contentProvider.getElements(inputElement);
+
+        // Build a list of selected children.
+        if (children != null) {
+            ArrayList list = new ArrayList();
+            for (Object element : children) {
+                if (listViewer.getChecked(element)) {
+					list.add(element);
+				}
+            }
+            setResult(list);
+        }
+
+        super.okPressed();
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/PatternFilter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/PatternFilter.java
new file mode 100644
index 0000000..1e6fac5
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/PatternFilter.java
@@ -0,0 +1,351 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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
+ *     Sascha Becher - Bug 186404 - Update PatternFilter API to allow extensions
+ *******************************************************************************/
+package org.eclipse.ui.dialogs;
+
+import com.ibm.icu.text.BreakIterator;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.eclipse.jface.viewers.AbstractTreeViewer;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.StructuredViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.ui.internal.misc.StringMatcher;
+
+/**
+ * A filter used in conjunction with <code>FilteredTree</code>. In order to
+ * determine if a node should be filtered it uses the content and label provider
+ * of the tree to do pattern matching on its children. This causes the entire
+ * tree structure to be realized. Note that the label provider must implement
+ * ILabelProvider.
+ *
+ * @see org.eclipse.ui.dialogs.FilteredTree
+ * @since 3.2
+ */
+public class PatternFilter extends ViewerFilter {
+	/*
+	 * Cache of filtered elements in the tree
+	 */
+    private Map cache = new HashMap();
+
+    /*
+     * Maps parent elements to TRUE or FALSE
+     */
+    private Map foundAnyCache = new HashMap();
+
+    private boolean useCache = false;
+
+	/**
+	 * Whether to include a leading wildcard for all provided patterns.  A
+	 * trailing wildcard is always included.
+	 */
+	private boolean includeLeadingWildcard = false;
+
+	/**
+	 * The string pattern matcher used for this pattern filter.
+	 */
+    private StringMatcher matcher;
+
+    private boolean useEarlyReturnIfMatcherIsNull = true;
+
+    private static Object[] EMPTY = new Object[0];
+
+    @Override
+	public Object[] filter(Viewer viewer, Object parent, Object[] elements) {
+    	// we don't want to optimize if we've extended the filter ... this
+    	// needs to be addressed in 3.4
+    	// https://bugs.eclipse.org/bugs/show_bug.cgi?id=186404
+        if (matcher == null && useEarlyReturnIfMatcherIsNull) {
+			return elements;
+		}
+
+        if (!useCache) {
+        	return super.filter(viewer, parent, elements);
+        }
+
+        Object[] filtered = (Object[]) cache.get(parent);
+        if (filtered == null) {
+        	Boolean foundAny = (Boolean) foundAnyCache.get(parent);
+        	if (foundAny != null && !foundAny.booleanValue()) {
+        		filtered = EMPTY;
+        	} else {
+        		filtered = super.filter(viewer, parent, elements);
+        	}
+            cache.put(parent, filtered);
+        }
+        return filtered;
+    }
+
+    /**
+     * Returns true if any of the elements makes it through the filter.
+     * This method uses caching if enabled; the computation is done in
+     * computeAnyVisible.
+     *
+     * @param viewer
+     * @param parent
+     * @param elements the elements (must not be an empty array)
+     * @return true if any of the elements makes it through the filter.
+     */
+    private boolean isAnyVisible(Viewer viewer, Object parent, Object[] elements) {
+    	if (matcher == null) {
+    		return true;
+    	}
+
+    	if (!useCache) {
+    		return computeAnyVisible(viewer, elements);
+    	}
+
+    	Object[] filtered = (Object[]) cache.get(parent);
+    	if (filtered != null) {
+    		return filtered.length > 0;
+    	}
+    	Boolean foundAny = (Boolean) foundAnyCache.get(parent);
+    	if (foundAny == null) {
+    		foundAny = computeAnyVisible(viewer, elements) ? Boolean.TRUE : Boolean.FALSE;
+    		foundAnyCache.put(parent, foundAny);
+    	}
+    	return foundAny.booleanValue();
+    }
+
+	/**
+	 * Returns true if any of the elements makes it through the filter.
+	 *
+	 * @param viewer the viewer
+	 * @param elements the elements to test
+	 * @return <code>true</code> if any of the elements makes it through the filter
+	 */
+	private boolean computeAnyVisible(Viewer viewer, Object[] elements) {
+		boolean elementFound = false;
+		for (int i = 0; i < elements.length && !elementFound; i++) {
+			Object element = elements[i];
+			elementFound = isElementVisible(viewer, element);
+		}
+		return elementFound;
+	}
+
+    @Override
+	public final boolean select(Viewer viewer, Object parentElement,
+			Object element) {
+        return isElementVisible(viewer, element);
+    }
+
+    /**
+	 * Sets whether a leading wildcard should be attached to each pattern
+	 * string.
+	 *
+	 * @param includeLeadingWildcard
+	 *            Whether a leading wildcard should be added.
+	 */
+	public final void setIncludeLeadingWildcard(
+			final boolean includeLeadingWildcard) {
+		this.includeLeadingWildcard = includeLeadingWildcard;
+	}
+
+    /**
+     * The pattern string for which this filter should select
+     * elements in the viewer.
+     *
+     * @param patternString
+     */
+    public void setPattern(String patternString) {
+    	// these 2 strings allow the PatternFilter to be extended in
+    	// 3.3 - https://bugs.eclipse.org/bugs/show_bug.cgi?id=186404
+    	if ("org.eclipse.ui.keys.optimization.true".equals(patternString)) { //$NON-NLS-1$
+    		useEarlyReturnIfMatcherIsNull = true;
+    		return;
+    	} else if ("org.eclipse.ui.keys.optimization.false".equals(patternString)) { //$NON-NLS-1$
+    		useEarlyReturnIfMatcherIsNull = false;
+    		return;
+    	}
+        clearCaches();
+        if (patternString == null || patternString.equals("")) { //$NON-NLS-1$
+			matcher = null;
+		} else {
+			String pattern = patternString + "*"; //$NON-NLS-1$
+			if (includeLeadingWildcard) {
+				pattern = "*" + pattern; //$NON-NLS-1$
+			}
+			matcher = new StringMatcher(pattern, true, false);
+		}
+    }
+
+	/**
+	 * Clears the caches used for optimizing this filter. Needs to be called whenever
+	 * the tree content changes.
+	 */
+	/* package */ void clearCaches() {
+		cache.clear();
+        foundAnyCache.clear();
+	}
+
+    /**
+     * Answers whether the given String matches the pattern.
+     *
+     * @param string the String to test
+     *
+     * @return whether the string matches the pattern
+     */
+    private boolean match(String string) {
+    	if (matcher == null) {
+			return true;
+		}
+        return matcher.match(string);
+    }
+
+    /**
+     * Answers whether the given element is a valid selection in
+     * the filtered tree.  For example, if a tree has items that
+     * are categorized, the category itself may  not be a valid
+     * selection since it is used merely to organize the elements.
+     *
+     * @param element
+     * @return true if this element is eligible for automatic selection
+     */
+    public boolean isElementSelectable(Object element){
+    	return element != null;
+    }
+
+    /**
+     * Answers whether the given element in the given viewer matches
+     * the filter pattern.  This is a default implementation that will
+     * show a leaf element in the tree based on whether the provided
+     * filter text matches the text of the given element's text, or that
+     * of it's children (if the element has any).
+     *
+     * Subclasses may override this method.
+     *
+     * @param viewer the tree viewer in which the element resides
+     * @param element the element in the tree to check for a match
+     *
+     * @return true if the element matches the filter pattern
+     */
+    public boolean isElementVisible(Viewer viewer, Object element){
+    	return isParentMatch(viewer, element) || isLeafMatch(viewer, element);
+    }
+
+    /**
+     * Check if the parent (category) is a match to the filter text.  The default
+     * behavior returns true if the element has at least one child element that is
+     * a match with the filter text.
+     *
+     * Subclasses may override this method.
+     *
+     * @param viewer the viewer that contains the element
+     * @param element the tree element to check
+     * @return true if the given element has children that matches the filter text
+     */
+    protected boolean isParentMatch(Viewer viewer, Object element){
+        Object[] children = ((ITreeContentProvider) ((AbstractTreeViewer) viewer)
+                .getContentProvider()).getChildren(element);
+
+        if ((children != null) && (children.length > 0)) {
+			return isAnyVisible(viewer, element, children);
+		}
+        return false;
+    }
+
+    /**
+     * Check if the current (leaf) element is a match with the filter text.
+     * The default behavior checks that the label of the element is a match.
+     *
+     * Subclasses should override this method.
+     *
+     * @param viewer the viewer that contains the element
+     * @param element the tree element to check
+     * @return true if the given element's label matches the filter text
+     */
+    protected boolean isLeafMatch(Viewer viewer, Object element){
+        String labelText = ((ILabelProvider) ((StructuredViewer) viewer)
+                .getLabelProvider()).getText(element);
+
+        if(labelText == null) {
+			return false;
+		}
+        return wordMatches(labelText);
+    }
+
+    /**
+     * Take the given filter text and break it down into words using a
+     * BreakIterator.
+     *
+     * @param text
+     * @return an array of words
+     */
+    private String[] getWords(String text){
+    	List words = new ArrayList();
+		// Break the text up into words, separating based on whitespace and
+		// common punctuation.
+		// Previously used String.split(..., "\\W"), where "\W" is a regular
+		// expression (see the Javadoc for class Pattern).
+		// Need to avoid both String.split and regular expressions, in order to
+		// compile against JCL Foundation (bug 80053).
+		// Also need to do this in an NL-sensitive way. The use of BreakIterator
+		// was suggested in bug 90579.
+		BreakIterator iter = BreakIterator.getWordInstance();
+		iter.setText(text);
+		int i = iter.first();
+		while (i != java.text.BreakIterator.DONE && i < text.length()) {
+			int j = iter.following(i);
+			if (j == java.text.BreakIterator.DONE) {
+				j = text.length();
+			}
+			// match the word
+			if (Character.isLetterOrDigit(text.charAt(i))) {
+				String word = text.substring(i, j);
+				words.add(word);
+			}
+			i = j;
+		}
+		return (String[]) words.toArray(new String[words.size()]);
+    }
+
+	/**
+	 * Return whether or not if any of the words in text satisfy the
+	 * match critera.
+	 *
+	 * @param text the text to match
+	 * @return boolean <code>true</code> if one of the words in text
+	 * 					satisifes the match criteria.
+	 */
+	protected boolean wordMatches(String text) {
+		if (text == null) {
+			return false;
+		}
+
+		//If the whole text matches we are all set
+		if(match(text)) {
+			return true;
+		}
+
+		// Otherwise check if any of the words of the text matches
+		String[] words = getWords(text);
+		for (String word : words) {
+			if (match(word)) {
+				return true;
+			}
+		}
+
+		return false;
+	}
+
+	/**
+	 * Can be called by the filtered tree to turn on caching.
+	 *
+	 * @param useCache The useCache to set.
+	 */
+	void setUseCache(boolean useCache) {
+		this.useCache = useCache;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/PreferenceLinkArea.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/PreferenceLinkArea.java
new file mode 100644
index 0000000..20ff5bb
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/PreferenceLinkArea.java
@@ -0,0 +1,112 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.dialogs;
+
+import java.util.Iterator;
+
+import org.eclipse.jface.preference.IPreferenceNode;
+import org.eclipse.jface.preference.PreferenceManager;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Link;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer;
+
+import com.ibm.icu.text.MessageFormat;
+
+/**
+ * The PreferenceLinkArea is the link area used to open a specific preference
+ * page.
+ *
+ * @since 3.1
+ */
+public class PreferenceLinkArea extends Object {
+
+    private Link pageLink;
+
+    /**
+     * Create a new instance of the receiver
+     *
+     * @param parent
+     *            the parent Composite
+     * @param style
+     *            the SWT style
+     * @param pageId
+     *            the page id
+     * @param message
+     *            the message to use as text. If this message has {0} in
+     *            its value it will be bound with the displayed name of
+     *            the preference page. This message must be well formed
+     *            html if you wish to link to another page.
+     * @param pageContainer -
+     *            The container another page will be opened in.
+     * @param pageData -
+     *            The data to apply to the page.
+     */
+    public PreferenceLinkArea(Composite parent, int style, final String pageId,
+            String message, final IWorkbenchPreferenceContainer pageContainer,
+            final Object pageData) {
+        pageLink = new Link(parent, style);
+
+        IPreferenceNode node = getPreferenceNode(pageId);
+        String result;
+        if (node == null) {
+			result = NLS.bind(
+                    WorkbenchMessages.get().PreferenceNode_NotFound, pageId);
+		} else {
+			result = MessageFormat.format(message, node.getLabelText());
+
+            //Only add the selection listener if the node is found
+            pageLink.addSelectionListener(new SelectionAdapter()
+            {
+                /** {@inheritDoc} */
+                @Override
+                public void widgetSelected(SelectionEvent e)
+                {
+                    pageContainer.openPage(pageId, pageData);
+                }
+            });
+        }
+        pageLink.setText(result);
+
+    }
+
+    /**
+     * Get the preference node with pageId.
+     *
+     * @param pageId
+     * @return IPreferenceNode
+     */
+    private IPreferenceNode getPreferenceNode(String pageId) {
+        Iterator iterator = PlatformUI.getWorkbench().getPreferenceManager()
+                .getElements(PreferenceManager.PRE_ORDER).iterator();
+        while (iterator.hasNext()) {
+            IPreferenceNode next = (IPreferenceNode) iterator.next();
+            if (next.getId().equals(pageId)) {
+				return next;
+			}
+        }
+        return null;
+    }
+
+    /**
+     * Return the control for the receiver.
+     *
+     * @return Control
+     */
+    public Control getControl() {
+        return pageLink;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/PreferencesUtil.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/PreferencesUtil.java
new file mode 100644
index 0000000..f8b5b02
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/PreferencesUtil.java
@@ -0,0 +1,328 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.dialogs;
+
+import java.util.Collection;
+import java.util.List;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.jface.preference.IPreferenceNode;
+import org.eclipse.jface.preference.IPreferencePage;
+import org.eclipse.jface.preference.PreferenceDialog;
+import org.eclipse.jface.preference.PreferenceManager;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.internal.dialogs.FilteredPreferenceDialog;
+import org.eclipse.ui.internal.dialogs.PropertyDialog;
+import org.eclipse.ui.internal.dialogs.PropertyPageContributorManager;
+import org.eclipse.ui.internal.dialogs.PropertyPageManager;
+import org.eclipse.ui.internal.dialogs.WorkbenchPreferenceDialog;
+
+/**
+ * The PreferencesUtil class is the class that opens a properties or preference
+ * dialog on a set of ids.
+ *
+ * @since 3.1
+ */
+public final class PreferencesUtil {
+
+	/**
+	 * Constant denoting no option.
+	 * @since 3.5
+	 */
+	public final static int OPTION_NONE = 0;
+
+	/**
+	 * Constant for configuring a preferences or properties dialog in which the
+	 * user cannot "unfilter" to show a larger set of pages than was passed to
+	 * {@link #createPreferenceDialogOn(Shell, String, String[], Object, int)}
+	 * or
+	 * {@link #createPropertyDialogOn(Shell, IAdaptable, String, String[], Object, int)}
+	 * .
+	 * @since 3.5
+	 */
+	public final static int OPTION_FILTER_LOCKED = 1;
+
+	/**
+	 * Apply the data to the first page if there is any.
+	 *
+	 * @param data
+	 *            The data to be applied
+	 * @param displayedIds
+	 *            The ids to filter to.
+	 * @param dialog
+	 *            The dialog to apply to.
+	 * @param options
+	 */
+	private static void applyOptions(Object data, String[] displayedIds,
+			FilteredPreferenceDialog dialog, int options) {
+		if (data != null) {
+			dialog.setPageData(data);
+			IPreferencePage page = dialog.getCurrentPage();
+			if (page instanceof PreferencePage) {
+				((PreferencePage) page).applyData(data);
+			}
+		}
+
+		if (displayedIds != null) {
+			dialog.showOnly(displayedIds);
+		}
+
+		if ((options & OPTION_FILTER_LOCKED) != 0) {
+			dialog.setLocked(true);
+		}
+	}
+
+	/**
+	 * Creates a workbench preference dialog and selects particular preference
+	 * page. If there is already a preference dialog open this dialog is used
+	 * and its selection is set to the page with id preferencePageId. Show the
+	 * other pages as filtered results using whatever filtering criteria the
+	 * search uses. It is the responsibility of the caller to then call
+	 * <code>open()</code>. The call to <code>open()</code> will not return
+	 * until the dialog closes, so this is the last chance to manipulate the
+	 * dialog.
+	 *
+	 * @param shell
+	 *            The Shell to parent the dialog off of if it is not already
+	 *            created. May be <code>null</code> in which case the active
+	 *            workbench window will be used if available.
+	 * @param preferencePageId
+	 *            The identifier of the preference page to open; may be
+	 *            <code>null</code>. If it is <code>null</code>, then the
+	 *            preference page is not selected or modified in any way.
+	 * @param displayedIds
+	 *            The ids of the other pages to be displayed using the same
+	 *            filtering criterea as search. If this is <code>null</code>,
+	 *            then the all preference pages are shown.
+	 * @param data
+	 *            Data that will be passed to all of the preference pages to be
+	 *            applied as specified within the page as they are created. If
+	 *            the data is <code>null</code> nothing will be called.
+	 *
+	 * @return a preference dialog.
+	 * @since 3.1
+	 * @see PreferenceDialog#PreferenceDialog(Shell, PreferenceManager)
+	 */
+	public static final PreferenceDialog createPreferenceDialogOn(Shell shell,
+			String preferencePageId, String[] displayedIds, Object data) {
+		return createPreferenceDialogOn(shell, preferencePageId, displayedIds, data,
+				OPTION_NONE);
+	}
+
+	/**
+	 * Creates a workbench preference dialog to a particular preference page.
+	 * Show the other pages as filtered results using whatever filtering
+	 * criteria the search uses. It is the responsibility of the caller to then
+	 * call <code>open()</code>. The call to <code>open()</code> will not
+	 * return until the dialog closes, so this is the last chance to manipulate
+	 * the dialog.
+	 *
+	 * @param shell
+	 *            The shell to use to parent the dialog if required.
+	 * @param propertyPageId
+	 *            The identifier of the preference page to open; may be
+	 *            <code>null</code>. If it is <code>null</code>, then the
+	 *            dialog is opened with no selected page.
+	 * @param element
+	 *            IAdaptable An adaptable element to open the dialog on.
+	 * @param displayedIds
+	 *            The ids of the other pages to be displayed using the same
+	 *            filtering criterea as search. If this is <code>null</code>,
+	 *            then the all preference pages are shown.
+	 * @param data
+	 *            Data that will be passed to all of the preference pages to be
+	 *            applied as specified within the page as they are created. If
+	 *            the data is <code>null</code> nothing will be called.
+	 *
+	 * @return A preference dialog showing properties for the selection or
+	 *         <code>null</code> if it could not be created.
+	 * @since 3.1
+	 */
+	public static final PreferenceDialog createPropertyDialogOn(Shell shell,
+			final IAdaptable element, String propertyPageId,
+			String[] displayedIds, Object data) {
+		return createPropertyDialogOn(shell, element, propertyPageId, displayedIds, data,
+				OPTION_NONE);
+	}
+
+	/**
+	 * Creates a workbench preference dialog and selects particular preference
+	 * page. If there is already a preference dialog open this dialog is used
+	 * and its selection is set to the page with id preferencePageId. Show the
+	 * other pages as filtered results using whatever filtering criteria the
+	 * search uses. It is the responsibility of the caller to then call
+	 * <code>open()</code>. The call to <code>open()</code> will not return
+	 * until the dialog closes, so this is the last chance to manipulate the
+	 * dialog.
+	 *
+	 * @param shell
+	 *            The Shell to parent the dialog off of if it is not already
+	 *            created. May be <code>null</code> in which case the active
+	 *            workbench window will be used if available.
+	 * @param preferencePageId
+	 *            The identifier of the preference page to open; may be
+	 *            <code>null</code>. If it is <code>null</code>, then the
+	 *            preference page is not selected or modified in any way.
+	 * @param displayedIds
+	 *            The ids of the other pages to be displayed using the same
+	 *            filtering criterea as search. If this is <code>null</code>,
+	 *            then the all preference pages are shown.
+	 * @param data
+	 *            Data that will be passed to all of the preference pages to be
+	 *            applied as specified within the page as they are created. If
+	 *            the data is <code>null</code> nothing will be called.
+	 * @param options
+	 *            a bitwise OR of option constants
+	 *
+	 * @return a preference dialog.
+	 * @since 3.5
+	 * @see PreferenceDialog#PreferenceDialog(Shell, PreferenceManager)
+	 */
+	public static final PreferenceDialog createPreferenceDialogOn(Shell shell,
+			String preferencePageId, String[] displayedIds, Object data, int options) {
+		FilteredPreferenceDialog dialog = WorkbenchPreferenceDialog
+		.createDialogOn(shell, preferencePageId);
+
+		applyOptions(data, displayedIds, dialog, options);
+
+		return dialog;
+	}
+
+	/**
+	 * Creates a workbench preference dialog to a particular preference page.
+	 * Show the other pages as filtered results using whatever filtering
+	 * criteria the search uses. It is the responsibility of the caller to then
+	 * call <code>open()</code>. The call to <code>open()</code> will not return
+	 * until the dialog closes, so this is the last chance to manipulate the
+	 * dialog.
+	 *
+	 * @param shell
+	 *            The shell to use to parent the dialog if required.
+	 * @param propertyPageId
+	 *            The identifier of the preference page to open; may be
+	 *            <code>null</code>. If it is <code>null</code>, then the dialog
+	 *            is opened with no selected page.
+	 * @param element
+	 *            IAdaptable An adaptable element to open the dialog on.
+	 * @param displayedIds
+	 *            The ids of the other pages to be displayed using the same
+	 *            filtering criteria as search. If this is <code>null</code>,
+	 *            then the all preference pages are shown.
+	 * @param data
+	 *            Data that will be passed to all of the preference pages to be
+	 *            applied as specified within the page as they are created. If
+	 *            the data is <code>null</code> nothing will be called.
+	 * @param options
+	 *            a bitwise OR of option constants
+	 *
+	 * @return A preference dialog showing properties for the selection or
+	 *         <code>null</code> if it could not be created.
+	 * @since 3.5
+	 */
+	public static final PreferenceDialog createPropertyDialogOn(Shell shell,
+			final IAdaptable element, String propertyPageId,
+			String[] displayedIds, Object data, int options) {
+
+		FilteredPreferenceDialog dialog = PropertyDialog.createDialogOn(shell,
+				propertyPageId, element);
+
+		if (dialog == null) {
+			return null;
+		}
+
+		applyOptions(data, displayedIds, dialog, options);
+
+		return dialog;
+
+	}
+
+	/**
+	 * Creates a workbench preference dialog to a particular preference page.
+	 * Show the other pages as filtered results using whatever filtering
+	 * criteria the search uses. It is the responsibility of the caller to then
+	 * call <code>open()</code>. The call to <code>open()</code> will not return
+	 * until the dialog closes, so this is the last chance to manipulate the
+	 * dialog.
+	 *
+	 * @param shell
+	 *            The shell to use to parent the dialog if required.
+	 * @param propertyPageId
+	 *            The identifier of the preference page to open; may be
+	 *            <code>null</code>. If it is <code>null</code>, then the dialog
+	 *            is opened with no selected page.
+	 * @param element
+	 *            An element to open the dialog on.
+	 * @param displayedIds
+	 *            The IDs of the other pages to be displayed using the same
+	 *            filtering criteria as search. If this is <code>null</code>,
+	 *            then the all preference pages are shown.
+	 * @param data
+	 *            Data that will be passed to all of the preference pages to be
+	 *            applied as specified within the page as they are created. If
+	 *            the data is <code>null</code> nothing will be called.
+	 * @param options
+	 *            a bitwise OR of option constants
+	 *
+	 * @return A preference dialog showing properties for the selection or
+	 *         <code>null</code> if it could not be created.
+	 * @since 3.6
+	 */
+	public static final PreferenceDialog createPropertyDialogOn(Shell shell,
+			final Object element, String propertyPageId, String[] displayedIds,
+			Object data, int options) {
+		FilteredPreferenceDialog dialog = PropertyDialog.createDialogOn(shell,
+				propertyPageId, element);
+		if (dialog == null)
+			return null;
+		applyOptions(data, displayedIds, dialog, options);
+		return dialog;
+	}
+
+	/**
+	 * Indicates whether the specified element has at least one property page
+	 * contributor.
+	 *
+	 * @param element
+	 *            an adapter element of a property page
+	 * @return true for having at least one contributor; false otherwise
+	 * @since 3.4
+	 */
+	public static boolean hasPropertiesContributors(Object element) {
+		if (element == null || !(element instanceof IAdaptable))
+			return false;
+		Collection contributors = PropertyPageContributorManager.getManager()
+				.getApplicableContributors(element);
+		return contributors != null && contributors.size() > 0;
+	}
+
+	/**
+	 * Return all of the properties page contributors for an element.
+	 * @param element
+	 * @return {@link IPreferenceNode}[]
+	 * @since 3.4
+	 */
+	public static IPreferenceNode[] propertiesContributorsFor(Object element) {
+		PropertyPageManager pageManager = new PropertyPageManager();
+			if (element == null) {
+			return null;
+		}
+		// load pages for the selection
+		// fill the manager with contributions from the matching contributors
+		PropertyPageContributorManager.getManager().contribute(pageManager,
+				element);
+		// testing if there are pages in the manager
+		List pages =  pageManager.getElements(PreferenceManager.PRE_ORDER);
+		IPreferenceNode[] nodes = new IPreferenceNode[pages.size()];
+		pages.toArray(nodes);
+		return nodes;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/PropertyDialogAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/PropertyDialogAction.java
new file mode 100644
index 0000000..04fc299
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/PropertyDialogAction.java
@@ -0,0 +1,182 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     James Blackburn (Broadcom Corp.) - Bug 294628 multiple selection
+ *******************************************************************************/
+package org.eclipse.ui.dialogs;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.preference.PreferenceDialog;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.window.IShellProvider;
+import org.eclipse.jface.window.SameShellProvider;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.SelectionProviderAction;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.dialogs.PropertyDialog;
+import org.eclipse.ui.internal.dialogs.PropertyPageContributorManager;
+
+/**
+ * Standard action for opening a Property Pages Dialog on the currently selected
+ * element.
+ * <p>
+ * This class may be instantiated; it is not intended to be subclassed.
+ * </p>
+ * <p>
+ * Generally speaking, this action is useful in pop-up menus because it allows
+ * the user to browse and change properties of selected elements. When
+ * performed, the action will bring up a Property Pages Dialog containing
+ * property pages registered with the workbench for elements of the selected
+ * type.
+ * </p>
+ * <p>
+ * Although the action is capable of calculating if there are any applicable
+ * pages for the current selection, this calculation is costly because it
+ * require searching the workbench registry. Where performance is critical, the
+ * action can simply be added to the pop-up menu. In the event of no applicable
+ * pages, the action will just open an appropriate message dialog.
+ * </p>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class PropertyDialogAction extends SelectionProviderAction {
+    /**
+     * Provides the shell in which to open the property dialog.
+     */
+    private IShellProvider shellProvider;
+
+	/**
+	 * The id of the page to open up on.
+	 */
+	private String initialPageId;
+
+
+	/**
+	 * Creates a new action for opening a property dialog on the elements from
+	 * the given selection provider.
+     *
+	 * @param shell
+	 *            the shell in which the dialog will open
+	 * @param provider
+	 *            the selection provider whose elements the property dialog will
+	 *            describe
+     * @deprecated use PropertyDialogAction(IShellProvider, ISelectionProvider)
+	 */
+	@Deprecated
+	public PropertyDialogAction(Shell shell, ISelectionProvider provider) {
+        this(new SameShellProvider(shell), provider);
+	}
+
+    /**
+     * Creates a new action for opening a property dialog on the elements from
+     * the given selection provider.
+     *
+     * @param shell
+     *            provides the shell in which the dialog will open
+     * @param provider
+     *            the selection provider whose elements the property dialog will
+     *            describe
+     * @since 3.1
+     */
+    public PropertyDialogAction(IShellProvider shell, ISelectionProvider provider) {
+        super(provider, WorkbenchMessages.get().PropertyDialog_text);
+        Assert.isNotNull(shell);
+        this.shellProvider = shell;
+        setToolTipText(WorkbenchMessages.get().PropertyDialog_toolTip);
+        PlatformUI.getWorkbench().getHelpSystem().setHelp(this,
+                IWorkbenchHelpContextIds.PROPERTY_DIALOG_ACTION);
+    }
+
+	/**
+	 * Returns whether the provided selection has pages registered in the property
+	 * page manager.
+	 *
+	 * @param object
+	 * @return boolean
+	 */
+	private boolean hasPropertyPagesFor(IStructuredSelection object) {
+		return PropertyPageContributorManager.getManager().getApplicableContributors(object).size() != 0;
+	}
+
+	/**
+	 * Returns whether this action is actually applicable to the current
+	 * selection. If this action is disabled, it will return <code>false</code>
+	 * without further calculation. If it is enabled, it will check with the
+	 * workbench's property page manager to see if there are any property pages
+	 * registered for the selected element's type.
+	 * <p>
+	 * This method is generally too expensive to use when updating the enabled
+	 * state of the action on each selection change.
+	 * </p>
+	 *
+	 * @return <code>true</code> if the selection is not empty and there are
+	 *         property pages for the selected element, and <code>false</code>
+	 *         otherwise
+	 */
+	public boolean isApplicableForSelection() {
+		if (!isEnabled()) {
+			return false;
+		}
+		return isApplicableForSelection(getStructuredSelection());
+	}
+
+	/**
+	 * Returns whether this action is applicable to the current selection. This
+	 * checks that the selection is not empty, and checks with the workbench's
+	 * property page manager to see if there are any property pages registered
+	 * for the selected element's type.
+	 * <p>
+	 * This method is generally too expensive to use when updating the enabled
+	 * state of the action on each selection change.
+	 * </p>
+	 *
+	 * @param selection
+	 *            The selection to test
+	 * @return <code>true</code> if the selection is of not empty and there are
+	 *         property pages for the selected element, and <code>false</code>
+	 *         otherwise
+	 */
+	public boolean isApplicableForSelection(IStructuredSelection selection) {
+		return !selection.isEmpty() && hasPropertyPagesFor(selection);
+	}
+
+
+	@Override
+	public void run() {
+
+		PreferenceDialog dialog = createDialog();
+		if (dialog != null) {
+			dialog.open();
+		}
+	}
+
+	/**
+	 * Create the dialog for the receiver. If no pages are found, an informative
+	 * message dialog is presented instead.
+	 *
+	 * @return PreferenceDialog or <code>null</code> if no applicable pages
+	 *         are found.
+	 * @since 3.1
+	 */
+	public PreferenceDialog createDialog() {
+		if (getStructuredSelection().isEmpty())
+			return null;
+
+		return PropertyDialog
+				.createDialogOn(shellProvider.getShell(), initialPageId, getStructuredSelection());
+	}
+
+
+	@Override
+	public void selectionChanged(IStructuredSelection selection) {
+		setEnabled(!selection.isEmpty());
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/PropertyPage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/PropertyPage.java
new file mode 100644
index 0000000..ccab7fd
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/PropertyPage.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.dialogs;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.ui.IWorkbenchPropertyPage;
+import org.eclipse.ui.IWorkbenchPropertyPageMulti;
+
+/**
+ * Abstract base implementation of a workbench property page (
+ * <code>IWorkbenchPropertyPage</code>). The implementation is a JFace
+ * preference page with an adaptable element.
+ * <p>
+ * Property pages that support multiple selected objects should
+ * implement {@link IWorkbenchPropertyPageMulti} instead.
+ * <p>
+ * Subclasses must implement the <code>createContents</code> framework method to
+ * supply the property page's main control.
+ * </p>
+ * <p>
+ * Subclasses should extend the <code>doComputeSize</code> framework method to
+ * compute the size of the page's control.
+ * </p>
+ * <p>
+ * Subclasses may override the <code>performOk</code>, <code>performApply</code>,<code>performDefaults</code>, <code>performCancel</code>, and
+ * <code>performHelp</code> framework methods to react to the standard button
+ * events.
+ * </p>
+ * <p>
+ * Subclasses may call the <code>noDefaultAndApplyButton</code> framework method
+ * before the page's control has been created to suppress the standard Apply and
+ * Defaults buttons.
+ * </p>
+ *
+ * @see IWorkbenchPropertyPage
+ * @see IWorkbenchPropertyPageMulti
+ */
+public abstract class PropertyPage extends PreferencePage implements IWorkbenchPropertyPage {
+    /**
+     * The element.
+     */
+    private IAdaptable element;
+
+    /**
+     * Creates a new property page.
+     */
+    public PropertyPage() {
+    }
+
+    @Override
+	public IAdaptable getElement() {
+        return element;
+    }
+
+    /**
+     * Sets the element that owns properties shown on this page.
+     *
+     * @param element
+     *            the element
+     */
+    @Override
+	public void setElement(IAdaptable element) {
+        this.element = element;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/SearchPattern.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/SearchPattern.java
new file mode 100644
index 0000000..4ab7749
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/SearchPattern.java
@@ -0,0 +1,688 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.dialogs;
+
+import org.eclipse.jface.util.Util;
+import org.eclipse.ui.internal.misc.StringMatcher;
+
+/**
+ * A search pattern defines how search results are found.
+ *
+ * <p>
+ * This class is intended to be subclassed by clients. A default behavior is
+ * provided for each of the methods above, that clients can override if they
+ * wish.
+ * </p>
+ *
+ * @since 3.3
+ */
+public class SearchPattern {
+
+	// Rules for pattern matching: (exact, prefix, pattern) [ | case sensitive]
+	/**
+	 * Match rule: The search pattern matches exactly the search result, that
+	 * is, the source of the search result equals the search pattern. Search pattern
+	 * should start from lowerCase char.
+	 */
+	public static final int RULE_EXACT_MATCH = 0;
+
+	/**
+	 * Match rule: The search pattern is a prefix of the search result.
+	 */
+	public static final int RULE_PREFIX_MATCH = 0x0001;
+
+	/**
+	 * Match rule: The search pattern contains one or more wild cards ('*' or
+	 * '?'). A '*' wild-card can replace 0 or more characters in the search
+	 * result. A '?' wild-card replaces exactly 1 character in the search
+	 * result.
+	 */
+	public static final int RULE_PATTERN_MATCH = 0x0002;
+
+	/**
+	 * Match rule: The search pattern matches the search result only if cases
+	 * are the same. Can be combined to previous rules, e.g.
+	 * {@link #RULE_EXACT_MATCH} | {@link #RULE_CASE_SENSITIVE}
+	 */
+	public static final int RULE_CASE_SENSITIVE = 0x0008;
+
+	/**
+	 * Match rule: The search pattern is blank.
+	 */
+	public static final int RULE_BLANK_MATCH = 0x0020;
+
+	/**
+	 * Match rule: The search pattern contains a Camel Case expression. <br>
+	 * Examples:
+	 * <ul>
+	 * <li><code>NPE</code> type string pattern will match
+	 * <code>NullPointerException</code> and
+	 * <code>NpPermissionException</code> types,</li>
+	 * <li><code>NuPoEx</code> type string pattern will only match
+	 * <code>NullPointerException</code> type.</li>
+	 * </ul>
+	 *
+	 *
+	 * <br>
+	 * Can be combined to {@link #RULE_PREFIX_MATCH} match rule. For example,
+	 * when prefix match rule is combined with Camel Case match rule,
+	 * <code>"nPE"</code> pattern will match <code>nPException</code>. <br>
+	 * Match rule {@link #RULE_PATTERN_MATCH} may also be combined but both
+	 * rules will not be used simultaneously as they are mutually exclusive.
+	 * Used match rule depends on whether string pattern contains specific
+	 * pattern characters (e.g. '*' or '?') or not. If it does, then only
+	 * Pattern match rule will be used, otherwise only Camel Case match will be
+	 * used. For example, with <code>"NPE"</code> string pattern, search will
+	 * only use Camel Case match rule, but with <code>N*P*E*</code> string
+	 * pattern, it will use only Pattern match rule.
+	 *
+	 */
+	public static final int RULE_CAMELCASE_MATCH = 0x0080;
+
+	private int matchRule;
+
+	private String stringPattern;
+
+	private String initialPattern;
+
+	private StringMatcher stringMatcher;
+
+	private static final char END_SYMBOL = '<';
+
+	private static final char ANY_STRING = '*';
+
+	private static final char BLANK = ' ';
+
+	private int allowedRules;
+
+	/**
+	 * Creates new instance of SearchPattern Default allowedRules for it is
+	 * result of belong logic operation: ( RULE_EXACT_MATCH | RULE_PREFIX_MATCH |
+	 * RULE_PATTERN_MATCH | RULE_CAMELCASE_MATCH )
+	 *
+	 */
+	public SearchPattern() {
+		this(RULE_EXACT_MATCH | RULE_PREFIX_MATCH | RULE_PATTERN_MATCH
+				| RULE_CAMELCASE_MATCH | RULE_BLANK_MATCH);
+	}
+
+	/**
+	 * Creates a search pattern with the rule to apply for matching index keys.
+	 * It can be exact match, prefix match, pattern match or camelCase match.
+	 * Rule can also be combined with a case sensitivity flag.
+	 *
+	 * @param allowedRules
+	 *            one of {@link #RULE_EXACT_MATCH}, {@link #RULE_PREFIX_MATCH},
+	 *            {@link #RULE_PATTERN_MATCH}, {@link #RULE_CASE_SENSITIVE},
+	 *            {@link #RULE_CAMELCASE_MATCH} combined with one of following
+	 *            values: {@link #RULE_EXACT_MATCH}, {@link #RULE_PREFIX_MATCH},
+	 *            {@link #RULE_PATTERN_MATCH} or {@link #RULE_CAMELCASE_MATCH}.
+	 *            e.g. {@link #RULE_EXACT_MATCH} | {@link #RULE_CASE_SENSITIVE}
+	 *            if an exact and case sensitive match is requested,
+	 *            {@link #RULE_PREFIX_MATCH} if a prefix non case sensitive
+	 *            match is requested or {@link #RULE_EXACT_MATCH} if a non case
+	 *            sensitive and erasure match is requested.<br>
+	 *            Note also that default behavior for generic types/methods
+	 *            search is to find exact matches.
+	 */
+	public SearchPattern(int allowedRules) {
+		this.allowedRules = allowedRules;
+	}
+
+	/**
+	 * Gets string pattern used by matcher
+	 *
+	 * @return pattern
+	 */
+	public String getPattern() {
+		return this.stringPattern;
+	}
+
+	/**
+	 * @param stringPattern
+	 *            The stringPattern to set.
+	 */
+	public void setPattern(String stringPattern) {
+		this.initialPattern = stringPattern;
+		this.stringPattern = stringPattern;
+		initializePatternAndMatchRule(stringPattern);
+		matchRule = matchRule & this.allowedRules;
+		if (matchRule == RULE_PATTERN_MATCH) {
+			stringMatcher = new StringMatcher(this.stringPattern, true, false);
+		}
+	}
+
+	/**
+	 * Matches text with pattern. matching is determine by matchKind.
+	 *
+	 * @param text
+	 * @return true if search pattern was matched with text false in other way
+	 */
+	public boolean matches(String text) {
+		switch (matchRule) {
+		case RULE_BLANK_MATCH:
+			return true;
+		case RULE_PATTERN_MATCH:
+			return stringMatcher.match(text);
+		case RULE_EXACT_MATCH:
+			return stringPattern.equalsIgnoreCase(text);
+		case RULE_CAMELCASE_MATCH:
+			if (camelCaseMatch(stringPattern, text)) {
+				return true;
+			}
+			//$FALL-THROUGH$
+			default:
+			return startsWithIgnoreCase(text, stringPattern);
+		}
+	}
+
+	private void initializePatternAndMatchRule(String pattern) {
+		int length = pattern.length();
+		if (length == 0) {
+			matchRule = RULE_BLANK_MATCH;
+			stringPattern = pattern;
+			return;
+		}
+		char last = pattern.charAt(length - 1);
+
+		if (pattern.indexOf('*') != -1 || pattern.indexOf('?') != -1) {
+			matchRule = RULE_PATTERN_MATCH;
+			switch (last) {
+			case END_SYMBOL:
+			case BLANK:
+				stringPattern = pattern.substring(0, length - 1);
+				break;
+			case ANY_STRING:
+				stringPattern = pattern;
+				break;
+			default:
+				stringPattern = pattern + ANY_STRING;
+			}
+			return;
+		}
+
+		if (validateMatchRule(pattern, RULE_CAMELCASE_MATCH) == RULE_CAMELCASE_MATCH) {
+			matchRule = RULE_CAMELCASE_MATCH;
+			stringPattern = pattern;
+			return;
+		}
+
+		if (last == END_SYMBOL || last == BLANK) {
+			matchRule = RULE_EXACT_MATCH;
+			stringPattern = pattern.substring(0, length - 1);
+			return;
+		}
+
+		matchRule = RULE_PREFIX_MATCH;
+		stringPattern = pattern;
+
+	}
+
+	/**
+	 * @param text
+	 * @param prefix
+	 * @return true if text starts with given prefix, ignoring case false in
+	 *         other way
+	 */
+	private boolean startsWithIgnoreCase(String text, String prefix) {
+		int textLength = text.length();
+		int prefixLength = prefix.length();
+		if (textLength < prefixLength)
+			return false;
+		for (int i = prefixLength - 1; i >= 0; i--) {
+			if (Character.toLowerCase(prefix.charAt(i)) != Character
+					.toLowerCase(text.charAt(i)))
+				return false;
+		}
+		return true;
+	}
+
+	/**
+	 * Answers true if the pattern matches the given name using CamelCase rules,
+	 * or false otherwise. CamelCase matching does NOT accept explicit
+	 * wild-cards '*' and '?' and is inherently case sensitive. <br>
+	 * CamelCase denotes the convention of writing compound names without
+	 * spaces, and capitalizing every term. This function recognizes both upper
+	 * and lower CamelCase, depending whether the leading character is
+	 * capitalized or not. The leading part of an upper CamelCase pattern is
+	 * assumed to contain a sequence of capitals which are appearing in the
+	 * matching name; e.g. 'NPE' will match 'NullPointerException', but not
+	 * 'NewPerfData'. A lower CamelCase pattern uses a lowercase first
+	 * character. In Java, type names follow the upper CamelCase convention,
+	 * whereas method or field names follow the lower CamelCase convention. <br>
+	 * The pattern may contain lowercase characters, which will be match in a
+	 * case sensitive way. These characters must appear in sequence in the name.
+	 * For instance, 'NPExcep' will match 'NullPointerException', but not
+	 * 'NullPointerExCEPTION' or 'NuPoEx' will match 'NullPointerException', but
+	 * not 'NoPointerException'. <br>
+	 * <br>
+	 * Examples:
+	 * <ol>
+	 * <li>
+	 *
+	 * <pre>
+	 *                 pattern = &quot;NPE&quot;
+	 *                 name = NullPointerException / NoPermissionException
+	 *                 result =&gt; true
+	 * </pre>
+	 *
+	 * </li>
+	 * <li>
+	 *
+	 * <pre>
+	 *                 pattern = &quot;NuPoEx&quot;
+	 *                 name = NullPointerException
+	 *                 result =&gt; true
+	 * </pre>
+	 *
+	 * </li>
+	 * <li>
+	 *
+	 * <pre>
+	 *                 pattern = &quot;npe&quot;
+	 *                 name = NullPointerException
+	 *                 result =&gt; false
+	 * </pre>
+	 *
+	 * </li>
+	 * </ol>
+	 *
+	 * @param pattern
+	 *            the given pattern
+	 * @param name
+	 *            the given name
+	 * @return true if the pattern matches the given name, false otherwise
+	 *
+	 */
+	private boolean camelCaseMatch(String pattern, String name) {
+		if (pattern == null)
+			return true; // null pattern is equivalent to '*'
+		if (name == null)
+			return false; // null name cannot match
+
+		return camelCaseMatch(pattern, 0, pattern.length(), name, 0, name
+				.length());
+	}
+
+	/**
+	 * Answers true if a sub-pattern matches the subpart of the given name using
+	 * CamelCase rules, or false otherwise. CamelCase matching does NOT accept
+	 * explicit wild-cards '*' and '?' and is inherently case sensitive. Can
+	 * match only subset of name/pattern, considering end positions as
+	 * non-inclusive. The subpattern is defined by the patternStart and
+	 * patternEnd positions. <br>
+	 * CamelCase denotes the convention of writing compound names without
+	 * spaces, and capitalizing every term. This function recognizes both upper
+	 * and lower CamelCase, depending whether the leading character is
+	 * capitalized or not. The leading part of an upper CamelCase pattern is
+	 * assumed to contain a sequence of capitals which are appearing in the
+	 * matching name; e.g. 'NPE' will match 'NullPointerException', but not
+	 * 'NewPerfData'. A lower CamelCase pattern uses a lowercase first
+	 * character. In Java, type names follow the upper CamelCase convention,
+	 * whereas method or field names follow the lower CamelCase convention. <br>
+	 * The pattern may contain lowercase characters, which will be match in a
+	 * case sensitive way. These characters must appear in sequence in the name.
+	 * For instance, 'NPExcep' will match 'NullPointerException', but not
+	 * 'NullPointerExCEPTION' or 'NuPoEx' will match 'NullPointerException', but
+	 * not 'NoPointerException'. <br>
+	 * <br>
+	 * Examples:
+	 * <ol>
+	 * <li>
+	 *
+	 * <pre>
+	 *                 pattern = &quot;NPE&quot;
+	 *                 patternStart = 0
+	 *                 patternEnd = 3
+	 *                 name = NullPointerException
+	 *                 nameStart = 0
+	 *                 nameEnd = 20
+	 *                 result =&gt; true
+	 * </pre>
+	 *
+	 * </li>
+	 * <li>
+	 *
+	 * <pre>
+	 *                 pattern = &quot;NPE&quot;
+	 *                 patternStart = 0
+	 *                 patternEnd = 3
+	 *                 name = NoPermissionException
+	 *                 nameStart = 0
+	 *                 nameEnd = 21
+	 *                 result =&gt; true
+	 * </pre>
+	 *
+	 * </li>
+	 * <li>
+	 *
+	 * <pre>
+	 *                 pattern = &quot;NuPoEx&quot;
+	 *                 patternStart = 0
+	 *                 patternEnd = 6
+	 *                 name = NullPointerException
+	 *                 nameStart = 0
+	 *                 nameEnd = 20
+	 *                 result =&gt; true
+	 * </pre>
+	 *
+	 * </li>
+	 * <li>
+	 *
+	 * <pre>
+	 *                 pattern = &quot;NuPoEx&quot;
+	 *                 patternStart = 0
+	 *                 patternEnd = 6
+	 *                 name = NoPermissionException
+	 *                 nameStart = 0
+	 *                 nameEnd = 21
+	 *                 result =&gt; false
+	 * </pre>
+	 *
+	 * </li>
+	 * <li>
+	 *
+	 * <pre>
+	 *                 pattern = &quot;npe&quot;
+	 *                 patternStart = 0
+	 *                 patternEnd = 3
+	 *                 name = NullPointerException
+	 *                 nameStart = 0
+	 *                 nameEnd = 20
+	 *                 result =&gt; false
+	 * </pre>
+	 *
+	 * </li>
+	 * </ol>
+	 *
+	 * @param pattern
+	 *            the given pattern
+	 * @param patternStart
+	 *            the start index of the pattern, inclusive
+	 * @param patternEnd
+	 *            the end index of the pattern, exclusive
+	 * @param name
+	 *            the given name
+	 * @param nameStart
+	 *            the start index of the name, inclusive
+	 * @param nameEnd
+	 *            the end index of the name, exclusive
+	 * @return true if a sub-pattern matches the subpart of the given name,
+	 *         false otherwise
+	 */
+	private boolean camelCaseMatch(String pattern, int patternStart,
+			int patternEnd, String name, int nameStart, int nameEnd) {
+		if (name == null)
+			return false; // null name cannot match
+		if (pattern == null)
+			return true; // null pattern is equivalent to '*'
+		if (patternEnd < 0)
+			patternEnd = pattern.length();
+		if (nameEnd < 0)
+			nameEnd = name.length();
+
+		if (patternEnd <= patternStart)
+			return nameEnd <= nameStart;
+		if (nameEnd <= nameStart)
+			return false;
+		// check first pattern char
+		if (name.charAt(nameStart) != pattern.charAt(patternStart)) {
+			// first char must strictly match (upper/lower)
+			return false;
+		}
+
+		int patternLength = patternEnd;
+
+		if (pattern.charAt(patternEnd - 1) == END_SYMBOL || pattern.charAt(patternEnd - 1) == BLANK )
+			patternLength = patternEnd - 1;
+
+
+		char patternChar, nameChar;
+		int iPattern = patternStart;
+		int iName = nameStart;
+
+		// Main loop is on pattern characters
+		while (true) {
+
+			iPattern++;
+			iName++;
+
+				if (iPattern == patternEnd) {
+				// We have exhausted pattern, so it's a match
+				return true;
+			}
+
+			if (iName == nameEnd) {
+				if (iPattern == patternLength)
+					return true;
+				// We have exhausted name (and not pattern), so it's not a match
+				return false;
+			}
+
+			// For as long as we're exactly matching, bring it on (even if it's
+			// a lower case character)
+			if ((patternChar = pattern.charAt(iPattern)) == name.charAt(iName)) {
+				continue;
+			}
+
+			// If characters are not equals, then it's not a match if
+			// patternChar is lowercase
+			if (!isPatternCharAllowed(patternChar))
+				return false;
+
+			// patternChar is uppercase, so let's find the next uppercase in
+			// name
+			while (true) {
+				if (iName == nameEnd) {
+					if ((iPattern == patternLength) && (patternChar == END_SYMBOL || patternChar == BLANK))
+						return true;
+					return false;
+				}
+
+				nameChar = name.charAt(iName);
+
+				if ((iPattern == patternLength) && (patternChar == END_SYMBOL || patternChar == BLANK)) {
+					if (isNameCharAllowed(nameChar)) {
+						return false;
+					}
+					iName++;
+					continue;
+				}
+
+				if (Character.isDigit(nameChar)) {
+					// nameChar is digit => break if the digit is current pattern character otherwise consume it
+					if (patternChar == nameChar) break;
+					iName++;
+				} else if (!isNameCharAllowed(nameChar)) {
+					// nameChar is lowercase
+					iName++;
+				// nameChar is uppercase...
+				} else if (patternChar != nameChar) {
+					// .. and it does not match patternChar, so it's not a match
+					return false;
+				} else {
+					// .. and it matched patternChar. Back to the big loop
+					break;
+				}
+			}
+			// At this point, either name has been exhausted, or it is at an
+			// uppercase letter.
+			// Since pattern is also at an uppercase letter
+		}
+	}
+
+	/**
+	 * Checks pattern's character is allowed for specified set. It could be
+	 * override if you want change logic of camelCaseMatch methods.
+	 *
+	 * @param patternChar
+	 * @return true if patternChar is in set of allowed characters for pattern
+	 */
+	protected boolean isPatternCharAllowed(char patternChar) {
+		return patternChar == END_SYMBOL || patternChar == BLANK
+			|| Character.isUpperCase(patternChar) || Character.isDigit(patternChar);
+	}
+
+	/**
+	 * Checks character of element's name is allowed for specified set. It could
+	 * be override if you want change logic of camelCaseMatch methods.
+	 *
+	 * @param nameChar -
+	 *            name of searched element
+	 * @return if nameChar is in set of allowed characters for name of element
+	 */
+	protected boolean isNameCharAllowed(char nameChar) {
+		return Character.isUpperCase(nameChar);
+	}
+
+	/**
+	 * Returns the rule to apply for matching keys. Can be exact match, prefix
+	 * match, pattern match or camelcase match. Rule can also be combined with a
+	 * case sensitivity flag.
+	 *
+	 * @return one of RULE_EXACT_MATCH, RULE_PREFIX_MATCH, RULE_PATTERN_MATCH,
+	 *         RULE_CAMELCASE_MATCH, combined with RULE_CASE_SENSITIVE, e.g.
+	 *         RULE_EXACT_MATCH | RULE_CASE_SENSITIVE if an exact and case
+	 *         sensitive match is requested, or RULE_PREFIX_MATCH if a prefix
+	 *         non case sensitive match is requested.
+	 */
+	public final int getMatchRule() {
+		return this.matchRule;
+	}
+
+	/**
+	 * Validate compatibility between given string pattern and match rule. <br>
+	 * Optimized (ie. returned match rule is modified) combinations are:
+	 * <ul>
+	 * <li>{@link #RULE_PATTERN_MATCH} without any '*' or '?' in string pattern: pattern match bit
+	 * is unset,</li>
+	 * <li>{@link #RULE_PATTERN_MATCH} and {@link #RULE_PREFIX_MATCH} bits simultaneously set:
+	 * prefix match bit is unset,</li>
+	 * <li>{@link #RULE_PATTERN_MATCH} and {@link #RULE_CAMELCASE_MATCH} bits simultaneously set:
+	 * camel case match bit is unset,</li>
+	 * <li>{@link #RULE_CAMELCASE_MATCH} with invalid combination of uppercase and lowercase
+	 * characters: camel case match bit is unset and replaced with prefix match pattern,</li>
+	 * <li>{@link #RULE_CAMELCASE_MATCH} combined with {@link #RULE_PREFIX_MATCH} and
+	 * {@link #RULE_CASE_SENSITIVE} bits is reduced to only {@link #RULE_CAMELCASE_MATCH} as Camel
+	 * Case search is already prefix and case sensitive,</li>
+	 * </ul>
+	 * <br>
+	 * Rejected (ie. returned match rule -1) combinations are:
+	 * <ul>
+	 * <li>{@link #RULE_PATTERN_MATCH} with any other match mode bit set,</li>
+	 * </ul>
+	 *
+	 * @param stringPattern The string pattern
+	 * @param matchRule The match rule
+	 * @return Optimized valid match rule or -1 if an incompatibility was detected.
+	 */
+	private int validateMatchRule(String stringPattern, int matchRule) {
+
+		// Verify Pattern match rule
+		int starIndex = stringPattern.indexOf('*');
+		int questionIndex = stringPattern.indexOf('?');
+		if (starIndex < 0 && questionIndex < 0) {
+			// reset pattern match bit if any
+			matchRule &= ~RULE_PATTERN_MATCH;
+		} else {
+			// force Pattern rule
+			matchRule |= RULE_PATTERN_MATCH;
+		}
+		if ((matchRule & RULE_PATTERN_MATCH) != 0) {
+			// remove Camel Case and Prefix match bits if any
+			matchRule &= ~RULE_CAMELCASE_MATCH;
+			matchRule &= ~RULE_PREFIX_MATCH;
+		}
+
+		// Verify Camel Case match rule
+		if ((matchRule & RULE_CAMELCASE_MATCH) != 0) {
+			// Verify sting pattern validity
+			int length = stringPattern.length();
+			boolean validCamelCase = true;
+			for (int i = 0; i < length && validCamelCase; i++) {
+				char ch = stringPattern.charAt(i);
+				validCamelCase = isValidCamelCaseChar(ch);
+			}
+			validCamelCase = validCamelCase && Character.isUpperCase(stringPattern.charAt(0));
+			// Verify bits compatibility
+			if (validCamelCase) {
+				if ((matchRule & RULE_PREFIX_MATCH) != 0) {
+					if ((matchRule & RULE_CASE_SENSITIVE) != 0) {
+						// This is equivalent to Camel Case match rule
+						matchRule &= ~RULE_PREFIX_MATCH;
+						matchRule &= ~RULE_CASE_SENSITIVE;
+					}
+				}
+			} else {
+				matchRule &= ~RULE_CAMELCASE_MATCH;
+				if ((matchRule & RULE_PREFIX_MATCH) == 0) {
+					matchRule |= RULE_PREFIX_MATCH;
+					matchRule |= RULE_CASE_SENSITIVE;
+				}
+			}
+		}
+		return matchRule;
+	}
+
+	/**
+	 * Check if character is valid camelCase character
+	 *
+	 * @param ch
+	 *            character to be validated
+	 * @return true if character is valid
+	 */
+	protected boolean isValidCamelCaseChar(char ch) {
+		return true;
+	}
+
+	/**
+	 * Tells whether the given <code>SearchPattern</code> equals this pattern.
+	 *
+	 * @param pattern
+	 *            pattern to be checked
+	 * @return true if the given pattern equals this search pattern
+	 */
+	public boolean equalsPattern(SearchPattern pattern) {
+		return trimWildcardCharacters(pattern.initialPattern).equals(
+				trimWildcardCharacters(this.initialPattern));
+	}
+
+	/**
+	 * Tells whether the given <code>SearchPattern</code> is a sub-pattern of
+	 * this pattern.
+	 * <p>
+	 * <i>WARNING: This method is <b>not</b> defined in reading order, i.e.
+	 * <code>a.isSubPattern(b)</code> is <code>true</code> iff
+	 * <code>b</code> is a sub-pattern of <code>a</code>, and not vice-versa.
+	 * </i>
+	 * </p>
+	 *
+	 * @param pattern
+	 *            pattern to be checked
+	 * @return true if the given pattern is a sub pattern of this search pattern
+	 */
+	public boolean isSubPattern(SearchPattern pattern) {
+		return trimWildcardCharacters(pattern.initialPattern).startsWith(
+				trimWildcardCharacters(this.initialPattern));
+	}
+
+	/**
+	 * Trims sequences of '*' characters
+	 *
+	 * @param pattern
+	 *            string to be trimmed
+	 * @return trimmed pattern
+	 */
+	private String trimWildcardCharacters(String pattern) {
+		return Util.replaceAll(pattern, "\\*+", "\\*"); //$NON-NLS-1$ //$NON-NLS-2$		}
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/SelectionDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/SelectionDialog.java
new file mode 100644
index 0000000..366a5a8
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/SelectionDialog.java
@@ -0,0 +1,304 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.dialogs;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.dialogs.TrayDialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.internal.WorkbenchMessages;
+
+/**
+ * The abstract implementation of a selection dialog. It can be primed with
+ * initial selections (<code>setInitialSelections</code>), and returns the
+ * final selection (via <code>getResult</code>) after completion.
+ * <p>
+ * Clients may subclass this dialog to inherit its selection facilities.
+ * </p>
+ */
+public abstract class SelectionDialog extends TrayDialog {
+	// the final collection of selected elements, or null if this dialog was
+	// canceled
+	private Object[] result;
+
+	// a collection of the initially-selected elements
+	private List initialSelections = new ArrayList();
+
+	// title of dialog
+	private String title;
+
+	// message to show user
+	private String message = ""; //$NON-NLS-1$
+
+	// dialog bounds strategy (since 3.2)
+	private int dialogBoundsStrategy = Dialog.DIALOG_PERSISTLOCATION | Dialog.DIALOG_PERSISTSIZE;
+
+	// dialog settings for storing bounds (since 3.2)
+	private IDialogSettings dialogBoundsSettings = null;
+
+	static String SELECT_ALL_TITLE = WorkbenchMessages.get().SelectionDialog_selectLabel;
+
+	static String DESELECT_ALL_TITLE = WorkbenchMessages.get().SelectionDialog_deselectLabel;
+
+	/**
+	 * Creates a dialog instance. Note that the dialog will have no visual
+	 * representation (no widgets) until it is told to open.
+	 *
+	 * @param parentShell
+	 *            the parent shell
+	 */
+	protected SelectionDialog(Shell parentShell) {
+		super(parentShell);
+	}
+
+	@Override
+	protected void configureShell(Shell shell) {
+		super.configureShell(shell);
+		if (title != null) {
+			shell.setText(title);
+		}
+	}
+
+	@Override
+	protected void createButtonsForButtonBar(Composite parent) {
+		createButton(parent, IDialogConstants.OK_ID, IDialogConstants.get().OK_LABEL, true);
+		createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.get().CANCEL_LABEL, false);
+	}
+
+	/**
+	 * Creates the message area for this dialog.
+	 * <p>
+	 * This method is provided to allow subclasses to decide where the message
+	 * will appear on the screen.
+	 * </p>
+	 *
+	 * @param composite
+	 *            the parent composite
+	 * @return the message label
+	 */
+	protected Label createMessageArea(Composite composite) {
+		Label label = new Label(composite, SWT.NONE);
+		if (message != null) {
+			label.setText(message);
+		}
+		label.setFont(composite.getFont());
+		return label;
+	}
+
+	/**
+	 * Returns the initial selection in this selection dialog.
+	 *
+	 * @deprecated use getInitialElementSelections() instead
+	 * @return the list of initial selected elements or null
+	 */
+	@Deprecated
+	protected List getInitialSelections() {
+		if (initialSelections.isEmpty()) {
+			return null;
+		}
+		return getInitialElementSelections();
+	}
+
+	/**
+	 * Returns the list of initial element selections.
+	 *
+	 * @return List
+	 */
+	protected List getInitialElementSelections() {
+		return initialSelections;
+	}
+
+	/**
+	 * Returns the message for this dialog.
+	 *
+	 * @return the message for this dialog
+	 */
+	protected String getMessage() {
+		return message;
+	}
+
+	/**
+	 * Returns the ok button.
+	 *
+	 * @return the ok button or <code>null</code> if the button is not created
+	 *         yet.
+	 */
+	public Button getOkButton() {
+		return getButton(IDialogConstants.OK_ID);
+	}
+
+	/**
+	 * Returns the list of selections made by the user, or <code>null</code>
+	 * if the selection was canceled.
+	 *
+	 * @return the array of selected elements, or <code>null</code> if Cancel
+	 *         was pressed
+	 */
+	public Object[] getResult() {
+		return result;
+	}
+
+	/**
+	 * Sets the initial selection in this selection dialog to the given
+	 * elements.
+	 *
+	 * @param selectedElements
+	 *            the array of elements to select
+	 */
+	public void setInitialSelections(Object[] selectedElements) {
+		initialSelections = new ArrayList(selectedElements.length);
+		for (Object selectedElement : selectedElements) {
+			initialSelections.add(selectedElement);
+		}
+	}
+
+	/**
+	 * Sets the initial selection in this selection dialog to the given
+	 * elements.
+	 *
+	 * @param selectedElements
+	 *            the List of elements to select
+	 */
+	public void setInitialElementSelections(List selectedElements) {
+		initialSelections = selectedElements;
+	}
+
+	/**
+	 * Sets the message for this dialog.
+	 *
+	 * @param message
+	 *            the message
+	 */
+	public void setMessage(String message) {
+		this.message = message;
+	}
+
+	/**
+	 * Set the selections made by the user, or <code>null</code> if the
+	 * selection was canceled.
+	 *
+	 * @param newResult
+	 *            list of selected elements, or <code>null</code> if Cancel
+	 *            was pressed
+	 */
+	protected void setResult(List newResult) {
+		if (newResult == null) {
+			result = null;
+		} else {
+			result = new Object[newResult.size()];
+			newResult.toArray(result);
+		}
+	}
+
+	/**
+	 * Set the selections made by the user, or <code>null</code> if the
+	 * selection was canceled.
+	 * <p>
+	 * The selections may accessed using <code>getResult</code>.
+	 * </p>
+	 *
+	 * @param newResult -
+	 *            the new values
+	 * @since 2.0
+	 */
+	protected void setSelectionResult(Object[] newResult) {
+		result = newResult;
+	}
+
+	/**
+	 * Sets the title for this dialog.
+	 *
+	 * @param title
+	 *            the title
+	 */
+	public void setTitle(String title) {
+		this.title = title;
+	}
+
+	/**
+	 * Set the dialog settings that should be used to save the bounds of this
+	 * dialog. This method is provided so that clients that directly use
+	 * SelectionDialogs without subclassing them may specify how the bounds of
+	 * the dialog are to be saved.
+	 *
+	 * @param settings
+	 *            the {@link IDialogSettings} that should be used to store the
+	 *            bounds of the dialog
+	 *
+	 * @param strategy
+	 *            the integer constant specifying how the bounds are saved.
+	 *            Specified using {@link Dialog#DIALOG_PERSISTLOCATION}
+	 *            and {@link Dialog#DIALOG_PERSISTSIZE}.
+	 *
+	 * @since 3.2
+	 *
+	 * @see Dialog#getDialogBoundsStrategy()
+	 * @see Dialog#getDialogBoundsSettings()
+	 */
+	public void setDialogBoundsSettings(IDialogSettings settings, int strategy) {
+		dialogBoundsStrategy = strategy;
+		dialogBoundsSettings = settings;
+	}
+
+	/**
+	 * Gets the dialog settings that should be used for remembering the bounds
+	 * of the dialog, according to the dialog bounds strategy. Overridden to
+	 * provide the dialog settings that were set using
+	 * {@link #setDialogBoundsSettings(IDialogSettings, int)}.
+	 *
+	 * @return the dialog settings used to store the dialog's location and/or
+	 *         size, or <code>null</code> if the dialog's bounds should not be
+	 *         stored.
+	 *
+	 * @since 3.2
+	 *
+	 * @see Dialog#getDialogBoundsStrategy()
+	 * @see #setDialogBoundsSettings(IDialogSettings, int)
+	 */
+	@Override
+	protected IDialogSettings getDialogBoundsSettings() {
+		return dialogBoundsSettings;
+	}
+
+	/**
+	 * Get the integer constant that describes the strategy for persisting the
+	 * dialog bounds. Overridden to provide the dialog bounds strategy that was
+	 * set using {@link #setDialogBoundsSettings(IDialogSettings, int)}.
+	 *
+	 * @return the constant describing the strategy for persisting the dialog
+	 *         bounds.
+	 *
+	 * @since 3.2
+	 * @see Dialog#DIALOG_PERSISTLOCATION
+	 * @see Dialog#DIALOG_PERSISTSIZE
+	 * @see Dialog#getDialogBoundsSettings()
+	 * @see #setDialogBoundsSettings(IDialogSettings, int)
+	 */
+	@Override
+	protected int getDialogBoundsStrategy() {
+		return dialogBoundsStrategy;
+	}
+
+    /**
+	 * @since 3.4
+	 */
+    @Override
+	protected boolean isResizable() {
+    	return true;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/SelectionStatusDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/SelectionStatusDialog.java
new file mode 100644
index 0000000..68aa8f7
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/SelectionStatusDialog.java
@@ -0,0 +1,192 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Sebastian Davids <sdavids@gmx.de> - Fix for bug 19346 - Dialog
+ *     font should be activated and used by other components.
+ *******************************************************************************/
+package org.eclipse.ui.dialogs;
+
+import java.util.Arrays;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.internal.MessageLine;
+
+/**
+ * An abstract base class for dialogs with a status bar and ok/cancel buttons.
+ * The status message must be passed over as StatusInfo object and can be
+ * an error, warning or ok. The OK button is enabled or disabled depending
+ * on the status.
+ *
+ * @since 2.0
+ */
+public abstract class SelectionStatusDialog extends SelectionDialog {
+
+    private MessageLine fStatusLine;
+
+    private IStatus fLastStatus;
+
+    private Image fImage;
+
+    private boolean fStatusLineAboveButtons = false;
+
+    /**
+     * Creates an instance of a <code>SelectionStatusDialog</code>.
+     * @param parent
+     */
+    public SelectionStatusDialog(Shell parent) {
+        super(parent);
+    }
+
+    /**
+     * Controls whether status line appears to the left of the buttons (default)
+     * or above them.
+     *
+     * @param aboveButtons if <code>true</code> status line is placed above buttons; if
+     * 	<code>false</code> to the right
+     */
+    public void setStatusLineAboveButtons(boolean aboveButtons) {
+        fStatusLineAboveButtons = aboveButtons;
+    }
+
+    /**
+     * Sets the image for this dialog.
+     * @param image the image.
+     */
+    public void setImage(Image image) {
+        fImage = image;
+    }
+
+    /**
+     * Returns the first element from the list of results. Returns <code>null</code>
+     * if no element has been selected.
+     *
+     * @return the first result element if one exists. Otherwise <code>null</code> is
+     *  returned.
+     */
+    public Object getFirstResult() {
+        Object[] result = getResult();
+        if (result == null || result.length == 0) {
+			return null;
+		}
+        return result[0];
+    }
+
+    /**
+     * Sets a result element at the given position.
+     * @param position
+     * @param element
+     */
+    protected void setResult(int position, Object element) {
+        Object[] result = getResult();
+        result[position] = element;
+        setResult(Arrays.asList(result));
+    }
+
+    /**
+     * Compute the result and return it.
+     */
+    protected abstract void computeResult();
+
+    @Override
+	protected void configureShell(Shell shell) {
+        super.configureShell(shell);
+        if (fImage != null) {
+			shell.setImage(fImage);
+		}
+    }
+
+    /**
+     * Update the dialog's status line to reflect the given status. It is safe to call
+     * this method before the dialog has been opened.
+     * @param status
+     */
+    protected void updateStatus(IStatus status) {
+        fLastStatus = status;
+        if (fStatusLine != null && !fStatusLine.isDisposed()) {
+            updateButtonsEnableState(status);
+            fStatusLine.setErrorStatus(status);
+        }
+    }
+
+    /**
+     * Update the status of the ok button to reflect the given status. Subclasses
+     * may override this method to update additional buttons.
+     * @param status
+     */
+    protected void updateButtonsEnableState(IStatus status) {
+        Button okButton = getOkButton();
+        if (okButton != null && !okButton.isDisposed()) {
+			okButton.setEnabled(!status.matches(IStatus.ERROR));
+		}
+    }
+
+    @Override
+	protected void okPressed() {
+        computeResult();
+        super.okPressed();
+    }
+
+    @Override
+	public void create() {
+        super.create();
+        if (fLastStatus != null) {
+			updateStatus(fLastStatus);
+		}
+    }
+
+    @Override
+	protected Control createButtonBar(Composite parent) {
+        Font font = parent.getFont();
+        Composite composite = new Composite(parent, SWT.NULL);
+        GridLayout layout = new GridLayout();
+        if (!fStatusLineAboveButtons) {
+            layout.numColumns = 2;
+        }
+        layout.marginHeight = 0;
+        layout.marginLeft = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
+        layout.marginWidth = 0;
+        composite.setLayout(layout);
+        composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+        composite.setFont(font);
+
+        if (!fStatusLineAboveButtons && isHelpAvailable()) {
+        	createHelpControl(composite);
+        }
+        fStatusLine = new MessageLine(composite);
+        fStatusLine.setAlignment(SWT.LEFT);
+        GridData statusData = new GridData(GridData.FILL_HORIZONTAL);
+        fStatusLine.setErrorStatus(null);
+        fStatusLine.setFont(font);
+        if (fStatusLineAboveButtons && isHelpAvailable()) {
+        	statusData.horizontalSpan = 2;
+        	createHelpControl(composite);
+        }
+        fStatusLine.setLayoutData(statusData);
+
+		/*
+		 * Create the rest of the button bar, but tell it not to
+		 * create a help button (we've already created it).
+		 */
+		boolean helpAvailable = isHelpAvailable();
+		setHelpAvailable(false);
+		super.createButtonBar(composite);
+		setHelpAvailable(helpAvailable);
+        return composite;
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/TwoArrayQuickSorter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/TwoArrayQuickSorter.java
new file mode 100644
index 0000000..13e5704
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/TwoArrayQuickSorter.java
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.dialogs;
+
+import java.util.Comparator;
+
+import org.eclipse.core.runtime.Assert;
+
+/**
+ * Quick sort to sort key-value pairs. The keys and arrays are specified
+ * in separate arrays.
+ *
+ * @since 2.0
+ */
+/* package */class TwoArrayQuickSorter {
+
+    private Comparator fComparator;
+
+    /**
+     * Default comparator.
+     */
+    public static final class StringComparator implements Comparator {
+        private boolean fIgnoreCase;
+
+        StringComparator(boolean ignoreCase) {
+            fIgnoreCase = ignoreCase;
+        }
+
+        @Override
+		public int compare(Object left, Object right) {
+            return fIgnoreCase ? ((String) left)
+                    .compareToIgnoreCase((String) right) : ((String) left)
+                    .compareTo((String) right);
+        }
+    }
+
+    /**
+     * Creates a sorter with default string comparator.
+     * The keys are assumed to be strings.
+     * @param ignoreCase specifies whether sorting is case sensitive or not.
+     */
+    public TwoArrayQuickSorter(boolean ignoreCase) {
+        fComparator = new StringComparator(ignoreCase);
+    }
+
+    /**
+     * Creates a sorter with a comparator.
+     * @param comparator the comparator to order the elements. The comparator must not be <code>null</code>.
+     */
+    public TwoArrayQuickSorter(Comparator comparator) {
+        fComparator = comparator;
+    }
+
+    /**
+     * Sorts keys and values in parallel.
+     * @param keys   the keys to use for sorting.
+     * @param values the values associated with the keys.
+     */
+    public void sort(Object[] keys, Object[] values) {
+        if ((keys == null) || (values == null)) {
+            Assert.isTrue(false, "Either keys or values in null"); //$NON-NLS-1$
+            return;
+        }
+
+        if (keys.length <= 1) {
+			return;
+		}
+
+        internalSort(keys, values, 0, keys.length - 1);
+    }
+
+    private void internalSort(Object[] keys, Object[] values, int left,
+            int right) {
+        int original_left = left;
+        int original_right = right;
+
+        Object mid = keys[(left + right) / 2];
+        do {
+            while (fComparator.compare(keys[left], mid) < 0) {
+				left++;
+			}
+
+            while (fComparator.compare(mid, keys[right]) < 0) {
+				right--;
+			}
+
+            if (left <= right) {
+                swap(keys, left, right);
+                swap(values, left, right);
+                left++;
+                right--;
+            }
+        } while (left <= right);
+
+        if (original_left < right) {
+			internalSort(keys, values, original_left, right);
+		}
+
+        if (left < original_right) {
+			internalSort(keys, values, left, original_right);
+		}
+    }
+
+    /*
+     * Swaps x[a] with x[b].
+     */
+    private static final void swap(Object x[], int a, int b) {
+        Object t = x[a];
+        x[a] = x[b];
+        x[b] = t;
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/TwoPaneElementSelector.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/TwoPaneElementSelector.java
new file mode 100644
index 0000000..e627f6e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/TwoPaneElementSelector.java
@@ -0,0 +1,341 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ * 	 Sebastian Davids <sdavids@gmx.de> - Fix for bug 19346 - Dialog
+ *    font should be activated and used by other components.
+ *******************************************************************************/
+package org.eclipse.ui.dialogs;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableItem;
+
+import org.eclipse.core.runtime.IStatus;
+
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.viewers.ILabelProvider;
+
+
+/**
+ * A list selection dialog with two panes. Duplicated entries will be folded
+ * together and are displayed in the lower pane (qualifier).
+ *
+ * @since 2.0
+ */
+public class TwoPaneElementSelector extends AbstractElementListSelectionDialog {
+    private String fUpperListLabel;
+
+    private String fLowerListLabel;
+
+    /**
+     * The comparator used to sort the list in the lower pane.
+     * @since 3.5
+     */
+    private Comparator fLowerListComparator = null;
+
+    private ILabelProvider fQualifierRenderer;
+
+    private Object[] fElements = new Object[0];
+
+    private Table fLowerList;
+
+    private Object[] fQualifierElements;
+
+    /**
+     * Creates the two pane element selector.
+     *
+     * @param parent
+     *            the parent shell.
+     * @param elementRenderer
+     *            the element renderer.
+     * @param qualifierRenderer
+     *            the qualifier renderer.
+     */
+    public TwoPaneElementSelector(Shell parent, ILabelProvider elementRenderer,
+            ILabelProvider qualifierRenderer) {
+        super(parent, elementRenderer);
+        setSize(50, 15);
+        setAllowDuplicates(false);
+        fQualifierRenderer = qualifierRenderer;
+    }
+
+    /**
+     * Sets the upper list label. If the label is <code>null</code> (default),
+     * no label is created.
+     *
+     * @param label
+     */
+    public void setUpperListLabel(String label) {
+        fUpperListLabel = label;
+    }
+
+    /**
+     * Sets the lower list label.
+     *
+     * @param label
+     *            String or <code>null</code>. If the label is
+     *            <code>null</code> (default), no label is created.
+     */
+    public void setLowerListLabel(String label) {
+        fLowerListLabel = label;
+    }
+
+    /**
+     * Sets the comparator used to sort the list in the lower pane.
+     * <p>
+     * Note: the comparator might want to honor
+     * {@link AbstractElementListSelectionDialog#isCaseIgnored()}.
+     * </p>
+     *
+     * @param comparator
+     *            a Comparator or <code>null</code> if <code>String</code>'s
+     *            comparison methods should be used
+     * @since 3.5
+     */
+    public void setLowerListComparator(Comparator comparator) {
+    	fLowerListComparator = comparator;
+    }
+
+    /**
+     * Sets the elements to be displayed.
+     *
+     * @param elements
+     *            the elements to be displayed.
+     */
+    public void setElements(Object[] elements) {
+        fElements = elements;
+    }
+
+    /*
+     * @see Dialog#createDialogArea(Composite)
+     */
+    @Override
+	public Control createDialogArea(Composite parent) {
+        Composite contents = (Composite) super.createDialogArea(parent);
+        createMessageArea(contents);
+        createFilterText(contents);
+        createLabel(contents, fUpperListLabel);
+        createFilteredList(contents);
+        createLabel(contents, fLowerListLabel);
+        createLowerList(contents);
+        setListElements(fElements);
+        List initialSelections = getInitialElementSelections();
+        if (!initialSelections.isEmpty()) {
+            Object element = initialSelections.get(0);
+            setSelection(new Object[] { element });
+            setLowerSelectedElement(element);
+        }
+        return contents;
+    }
+
+    /**
+     * Creates a label if name was not <code>null</code>.
+     *
+     * @param parent
+     *            the parent composite.
+     * @param name
+     *            the name of the label.
+     * @return returns a label if a name was given, <code>null</code>
+     *         otherwise.
+     */
+    protected Label createLabel(Composite parent, String name) {
+        if (name == null) {
+			return null;
+		}
+        Label label = new Label(parent, SWT.NONE);
+        label.setText(name);
+        label.setFont(parent.getFont());
+        return label;
+    }
+
+    /**
+     * Creates the list widget and sets layout data.
+     *
+     * @param parent
+     *            the parent composite.
+     * @return returns the list table widget.
+     */
+    protected Table createLowerList(Composite parent) {
+        Table list = new Table(parent, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
+        list.addListener(SWT.Selection, evt -> handleLowerSelectionChanged());
+        list.addListener(SWT.MouseDoubleClick, evt -> handleDefaultSelected());
+        list.addDisposeListener(e -> fQualifierRenderer.dispose());
+        GridData data = new GridData();
+        data.widthHint = convertWidthInCharsToPixels(50);
+        data.heightHint = convertHeightInCharsToPixels(5);
+        data.grabExcessVerticalSpace = true;
+        data.grabExcessHorizontalSpace = true;
+        data.horizontalAlignment = GridData.FILL;
+        data.verticalAlignment = GridData.FILL;
+        list.setLayoutData(data);
+        list.setFont(parent.getFont());
+        fLowerList = list;
+        return list;
+    }
+
+    /**
+     * @see SelectionStatusDialog#computeResult()
+     */
+    @Override
+	protected void computeResult() {
+        Object[] results = new Object[] { getLowerSelectedElement() };
+        setResult(Arrays.asList(results));
+    }
+
+    /**
+     * @see AbstractElementListSelectionDialog#handleDefaultSelected()
+     */
+    @Override
+	protected void handleDefaultSelected() {
+        if (validateCurrentSelection() && (getLowerSelectedElement() != null)) {
+			buttonPressed(IDialogConstants.OK_ID);
+		}
+    }
+
+    /**
+     * @see AbstractElementListSelectionDialog#handleSelectionChanged()
+     */
+    @Override
+	protected void handleSelectionChanged() {
+        handleUpperSelectionChanged();
+    }
+
+    private void handleUpperSelectionChanged() {
+        int indices[] = getSelectionIndices();
+        fLowerList.removeAll();
+		int elementCount = 0;
+		List elements= new ArrayList(indices.length * 5);
+        for (int index : indices) {
+        	Object[] foldedElements= getFoldedElements(index);
+			if (foldedElements != null) {
+				elementCount = elementCount + foldedElements.length;
+				elements.add(getFoldedElements(index));
+			}
+		}
+		if (elementCount > 0) {
+			fQualifierElements = new Object[elementCount];
+			int destPos = 0;
+			Iterator iterator = elements.iterator();
+			while (iterator.hasNext()) {
+				Object[] objects= (Object[])iterator.next();
+				System.arraycopy(objects, 0, fQualifierElements, destPos, objects.length);
+				destPos = destPos + objects.length;
+			}
+			updateLowerListWidget(fQualifierElements);
+		} else {
+			fQualifierElements = null;
+			updateLowerListWidget(new Object[] {});
+		}
+
+        validateCurrentSelection();
+    }
+
+    private void handleLowerSelectionChanged() {
+        validateCurrentSelection();
+    }
+
+    /**
+     * Selects an element in the lower pane.
+     * @param element
+     */
+    protected void setLowerSelectedElement(Object element) {
+        if (fQualifierElements == null) {
+			return;
+		}
+        // find matching index
+        int i;
+        for (i = 0; i != fQualifierElements.length; i++) {
+			if (fQualifierElements[i].equals(element)) {
+				break;
+			}
+		}
+        // set selection
+        if (i != fQualifierElements.length) {
+			fLowerList.setSelection(i);
+		}
+    }
+
+    /**
+     * Returns the selected element from the lower pane.
+     * @return Object
+     */
+    protected Object getLowerSelectedElement() {
+        int index = fLowerList.getSelectionIndex();
+        if (index >= 0) {
+			return fQualifierElements[index];
+		}
+        return null;
+    }
+
+    private void updateLowerListWidget(Object[] elements) {
+        int length = elements.length;
+        String[] qualifiers = new String[length];
+        for (int i = 0; i != length; i++){
+        	String text = fQualifierRenderer.getText(elements[i]);
+        	if(text == null) {
+				text = ""; //$NON-NLS-1$
+			}
+            qualifiers[i] = text;
+        }
+
+        TwoArrayQuickSorter sorter;
+        if (fLowerListComparator == null) {
+        	sorter = new TwoArrayQuickSorter(isCaseIgnored());
+        } else {
+        	sorter = new TwoArrayQuickSorter(fLowerListComparator);
+        }
+
+        sorter.sort(qualifiers, elements);
+        for (int i = 0; i != length; i++) {
+            TableItem item = new TableItem(fLowerList, SWT.NONE);
+            item.setText(qualifiers[i]);
+            item.setImage(fQualifierRenderer.getImage(elements[i]));
+        }
+        if (fLowerList.getItemCount() > 0) {
+			fLowerList.setSelection(0);
+		}
+    }
+
+    /*
+     * @see AbstractElementListSelectionDialog#handleEmptyList()
+     */
+    @Override
+	protected void handleEmptyList() {
+        super.handleEmptyList();
+        fLowerList.setEnabled(false);
+    }
+
+    /**
+     * @see AbstractElementListSelectionDialog#validateCurrentSelection()
+     * @since 3.5
+     */
+    @Override
+	protected boolean validateCurrentSelection() {
+    	ISelectionStatusValidator validator = getValidator();
+    	Object lowerSelection = getLowerSelectedElement();
+
+    	if (validator != null && lowerSelection != null) {
+    		IStatus status = validator.validate(new Object [] {lowerSelection});
+    		updateStatus(status);
+    		return status.isOK();
+    	}
+        return super.validateCurrentSelection();
+     }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/TypeFilteringDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/TypeFilteringDialog.java
new file mode 100644
index 0000000..628a533
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/TypeFilteringDialog.java
@@ -0,0 +1,310 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Sebastian Davids <sdavids@gmx.de> - Fix for bug 19346 - Dialog font should be
+ *       activated and used by other components.
+ *     Markus Schorn <markus.schorn@windriver.com> - Fix for bug 136591 -
+ *       [Dialogs] TypeFilteringDialog appends unnecessary comma
+ *******************************************************************************/
+package org.eclipse.ui.dialogs;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.CheckboxTableViewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IFileEditorMapping;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.registry.EditorRegistry;
+
+/**
+ * The TypeFilteringDialog is a SelectionDialog that allows the user to select a
+ * file editor.
+ */
+public class TypeFilteringDialog extends SelectionDialog {
+    Button addTypesButton;
+
+    Collection initialSelections;
+
+    // the visual selection widget group
+    CheckboxTableViewer listViewer;
+
+    // sizing constants
+    private final static int SIZING_SELECTION_WIDGET_HEIGHT = 250;
+
+    private final static int SIZING_SELECTION_WIDGET_WIDTH = 300;
+
+    private final static String TYPE_DELIMITER = WorkbenchMessages.get().TypesFiltering_typeDelimiter;
+
+    //Define a title for the filter entry field.
+    private String filterTitle = WorkbenchMessages.get().TypesFiltering_otherExtensions;
+
+    Text userDefinedText;
+
+    IFileEditorMapping[] currentInput;
+
+    /**
+     *  Creates a type filtering dialog using the supplied entries. Set the
+     * initial selections to those whose extensions match the preselections.
+     * @param parentShell The shell to parent the dialog from.
+     * @param preselections
+     *            of String - a Collection of String to define the preselected
+     *            types
+     */
+    public TypeFilteringDialog(Shell parentShell, Collection preselections) {
+        super(parentShell);
+        setTitle(WorkbenchMessages.get().TypesFiltering_title);
+        this.initialSelections = preselections;
+        setMessage(WorkbenchMessages.get().TypesFiltering_message);
+		setShellStyle(getShellStyle() | SWT.SHEET);
+    }
+
+    /**
+     * Creates a type filtering dialog using the supplied entries. Set the
+     * initial selections to those whose extensions match the preselections.
+     *
+     * @param parentShell The shell to parent the dialog from.
+     * @param preselections
+     *            of String - a Collection of String to define the preselected
+     *            types
+     * @param filterText -
+     *            the title of the text entry field for other extensions.
+     */
+    public TypeFilteringDialog(Shell parentShell, Collection preselections,
+            String filterText) {
+        this(parentShell, preselections);
+        this.filterTitle = filterText;
+    }
+
+    /**
+     * Add the selection and deselection buttons to the dialog.
+     *
+     * @param composite
+     *            org.eclipse.swt.widgets.Composite
+     */
+    private void addSelectionButtons(Composite composite) {
+        Composite buttonComposite = new Composite(composite, SWT.RIGHT);
+        GridLayout layout = new GridLayout();
+        layout.numColumns = 2;
+        buttonComposite.setLayout(layout);
+        GridData data = new GridData(GridData.HORIZONTAL_ALIGN_END
+                | GridData.GRAB_HORIZONTAL);
+        data.grabExcessHorizontalSpace = true;
+        composite.setData(data);
+        Button selectButton = createButton(buttonComposite,
+                IDialogConstants.SELECT_ALL_ID, WorkbenchMessages.get().WizardTransferPage_selectAll, false);
+        SelectionListener listener = new SelectionAdapter()
+        {
+             /** {@inheritDoc} */
+            @Override
+            public void widgetSelected(SelectionEvent e)
+            {
+                listViewer.setAllChecked(true);
+            }
+        };
+        selectButton.addSelectionListener(listener);
+        Button deselectButton = createButton(buttonComposite,
+                IDialogConstants.DESELECT_ALL_ID, WorkbenchMessages.get().WizardTransferPage_deselectAll, false);
+        listener = new SelectionAdapter()
+        {
+            /** {@inheritDoc} */
+            @Override
+            public void widgetSelected(SelectionEvent e)
+            {
+                listViewer.setAllChecked(false);
+            }
+        };
+        deselectButton.addSelectionListener(listener);
+    }
+
+    /**
+     * Add the currently-specified extensions to result.
+     * @param result
+     */
+    private void addUserDefinedEntries(List result) {
+        StringTokenizer tokenizer = new StringTokenizer(userDefinedText
+                .getText(), TYPE_DELIMITER);
+        //Allow the *. and . prefix and strip out the extension
+        while (tokenizer.hasMoreTokens()) {
+            String currentExtension = tokenizer.nextToken().trim();
+            if (!currentExtension.equals("")) { //$NON-NLS-1$
+                if (currentExtension.startsWith("*.")) { //$NON-NLS-1$
+					result.add(currentExtension.substring(2));
+				} else {
+                    if (currentExtension.startsWith(".")) { //$NON-NLS-1$
+						result.add(currentExtension.substring(1));
+					} else {
+						result.add(currentExtension);
+					}
+                }
+            }
+        }
+    }
+
+    /**
+     * Visually checks the previously-specified elements in this dialog's list
+     * viewer.
+     */
+    private void checkInitialSelections() {
+        IFileEditorMapping editorMappings[] = ((EditorRegistry) PlatformUI
+				.getWorkbench().getEditorRegistry()).getUnifiedMappings();
+        ArrayList selectedMappings = new ArrayList();
+        for (IFileEditorMapping mapping : editorMappings) {
+            //Check for both extension and label matches
+            if (this.initialSelections.contains(mapping.getExtension())) {
+                listViewer.setChecked(mapping, true);
+                selectedMappings.add(mapping.getExtension());
+            } else {
+                if (this.initialSelections.contains(mapping.getLabel())) {
+                    listViewer.setChecked(mapping, true);
+                    selectedMappings.add(mapping.getLabel());
+                }
+            }
+        }
+        //Now add in the ones not selected to the user defined list
+        Iterator initialIterator = this.initialSelections.iterator();
+        StringBuffer entries = new StringBuffer();
+        while (initialIterator.hasNext()) {
+            String nextExtension = (String) initialIterator.next();
+            if (!selectedMappings.contains(nextExtension)) {
+            	if (entries.length() != 0) {
+					entries.append(',');
+            	}
+                entries.append(nextExtension);
+            }
+        }
+        this.userDefinedText.setText(entries.toString());
+    }
+
+    @Override
+	protected void configureShell(Shell shell) {
+        super.configureShell(shell);
+        PlatformUI.getWorkbench().getHelpSystem().setHelp(shell,
+				IWorkbenchHelpContextIds.TYPE_FILTERING_DIALOG);
+    }
+
+    @Override
+	protected Control createDialogArea(Composite parent) {
+        // page group
+        Composite composite = (Composite) super.createDialogArea(parent);
+        createMessageArea(composite);
+        listViewer = CheckboxTableViewer.newCheckList(composite, SWT.BORDER);
+        GridData data = new GridData(GridData.FILL_BOTH);
+        data.heightHint = SIZING_SELECTION_WIDGET_HEIGHT;
+        data.widthHint = SIZING_SELECTION_WIDGET_WIDTH;
+        listViewer.getTable().setLayoutData(data);
+        listViewer.getTable().setFont(parent.getFont());
+        listViewer.setLabelProvider(FileEditorMappingLabelProvider.INSTANCE);
+		listViewer.setContentProvider(ArrayContentProvider.getInstance());
+        listViewer.setComparator(new ViewerComparator());
+        addSelectionButtons(composite);
+        createUserEntryGroup(composite);
+        initializeViewer();
+        // initialize page
+        if (this.initialSelections != null && !this.initialSelections.isEmpty()) {
+			checkInitialSelections();
+		}
+        return composite;
+    }
+
+    /**
+     * Create the group that shows the user defined entries for the dialog.
+     *
+     * @param parent
+     *            the parent this is being created in.
+     */
+    private void createUserEntryGroup(Composite parent) {
+        Font font = parent.getFont();
+        // destination specification group
+        Composite userDefinedGroup = new Composite(parent, SWT.NONE);
+        GridLayout layout = new GridLayout();
+        layout.numColumns = 2;
+        userDefinedGroup.setLayout(layout);
+        userDefinedGroup.setLayoutData(new GridData(
+                GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_FILL));
+        Label fTitle = new Label(userDefinedGroup, SWT.NONE);
+        fTitle.setFont(font);
+        fTitle.setText(filterTitle);
+        // user defined entry field
+        userDefinedText = new Text(userDefinedGroup, SWT.SINGLE | SWT.BORDER);
+        userDefinedText.setFont(font);
+        GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL
+                | GridData.GRAB_HORIZONTAL);
+        userDefinedText.setLayoutData(data);
+    }
+
+    /**
+     * Return the input to the dialog.
+     * @return IFileEditorMapping[]
+     */
+    private IFileEditorMapping[] getInput() {
+        //Filter the mappings to be just those with a wildcard extension
+        if (currentInput == null) {
+            List wildcardEditors = new ArrayList();
+            IFileEditorMapping[] allMappings = ((EditorRegistry)PlatformUI.getWorkbench()
+                    .getEditorRegistry()).getUnifiedMappings();
+            for (IFileEditorMapping allMapping : allMappings) {
+                if (allMapping.getName().equals("*")) { //$NON-NLS-1$
+					wildcardEditors.add(allMapping);
+				}
+            }
+            currentInput = new IFileEditorMapping[wildcardEditors.size()];
+            wildcardEditors.toArray(currentInput);
+        }
+        return currentInput;
+    }
+
+    /**
+     * Initializes this dialog's viewer after it has been laid out.
+     */
+    private void initializeViewer() {
+        listViewer.setInput(getInput());
+    }
+
+    /**
+     * The <code>TypeFilteringDialog</code> implementation of this
+     * <code>Dialog</code> method builds a list of the selected elements for
+     * later retrieval by the client and closes this dialog.
+     */
+    @Override
+	protected void okPressed() {
+        // Get the input children.
+        IFileEditorMapping[] children = getInput();
+        List list = new ArrayList();
+        // Build a list of selected children.
+        for (IFileEditorMapping element : children) {
+            if (listViewer.getChecked(element)) {
+				list.add(element.getExtension());
+			}
+        }
+        addUserDefinedEntries(list);
+        setResult(list);
+        super.okPressed();
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/WorkingSetConfigurationBlock.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/WorkingSetConfigurationBlock.java
new file mode 100644
index 0000000..81db079
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/WorkingSetConfigurationBlock.java
@@ -0,0 +1,589 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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
+ *     Remy Chi Jian Suen <remy.suen@gmail.com> - bug 201661
+ *     Simon Scholz <simon.scholz@vogella.com> - Bug 483425, 483429, 483435
+ *******************************************************************************/
+package org.eclipse.ui.dialogs;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.window.Window;
+import org.eclipse.jface.wizard.IWizardPage;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.FontMetrics;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkingSet;
+import org.eclipse.ui.IWorkingSetManager;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.dialogs.SimpleWorkingSetSelectionDialog;
+
+import com.ibm.icu.text.Collator;
+
+/**
+ * Instances of this class provide a reusable composite with controls that allow
+ * the selection of working sets. This class is most useful in
+ * {@link IWizardPage} instances that wish to create resources and pre-install
+ * them into particular working sets.
+ *
+ * @since 3.4
+ *
+ */
+public class WorkingSetConfigurationBlock {
+
+	/**
+	 * Filters the given working sets such that the following is true: for each
+	 * IWorkingSet s in result: s.getId() is element of workingSetIds
+	 *
+	 * @param workingSets
+	 *            the array to filter
+	 * @param workingSetIds
+	 *            the acceptable working set ids
+	 * @return the filtered elements
+	 */
+	public static IWorkingSet[] filter(IWorkingSet[] workingSets,
+			String[] workingSetIds) {
+
+		// create a copy so we can sort the array without mucking it up for clients.
+		String[] workingSetIdsCopy = new String[workingSetIds.length];
+		System.arraycopy(workingSetIds, 0, workingSetIdsCopy, 0,
+				workingSetIds.length);
+		Arrays.sort(workingSetIdsCopy);
+
+		List<IWorkingSet> result = new ArrayList<>();
+
+		for (IWorkingSet workingSet : workingSets) {
+			if (Arrays.binarySearch(workingSetIdsCopy, workingSet.getId()) >= 0) {
+				result.add(workingSet);
+			}
+		}
+
+		return result.toArray(new IWorkingSet[result.size()]);
+	}
+
+	/**
+	 * Empty working set array constant.
+	 */
+	private static final IWorkingSet[] EMPTY_WORKING_SET_ARRAY = new IWorkingSet[0];
+
+	private static final String WORKINGSET_SELECTION_HISTORY = "workingset_selection_history"; //$NON-NLS-1$
+	private static final int MAX_HISTORY_SIZE = 5;
+
+	private Label workingSetLabel;
+	private Combo workingSetCombo;
+	private Button selectButton;
+	private Button enableButton;
+	private Button newButton;
+
+	private IWorkingSet[] selectedWorkingSets;
+	private List<String> selectionHistory;
+	private final IDialogSettings dialogSettings;
+	private final String[] workingSetTypeIds;
+
+	private final String selectLabel;
+
+	private final String comboLabel;
+
+	private final String enableButtonLabel;
+
+	private final String newButtonLabel;
+
+	/**
+	 * Create a new instance of this working set block using default labels.
+	 *
+	 * @param settings
+	 *            to store/load the selection history
+	 * @param workingSetIds
+	 *            working set ids from which the user can choose
+	 * @since 3.108
+	 */
+	public WorkingSetConfigurationBlock(IDialogSettings settings, String... workingSetIds) {
+		this(settings, null, null, null, null, workingSetIds);
+	}
+
+	/**
+	 * Create a new instance of this working set block using default labels.
+	 * <br/>
+	 * <br/>
+	 * Note: Consider using the vararg version of this contructor.
+	 *
+	 * @param workingSetIds
+	 *            working set ids from which the user can choose
+	 * @param settings
+	 *            to store/load the selection history
+	 */
+	public WorkingSetConfigurationBlock(String[] workingSetIds, IDialogSettings settings) {
+		this(settings, workingSetIds);
+	}
+
+	/**
+	 * Create a new instance of this working set block using custom labels.
+	 * <br/>
+	 * <br/>
+	 * Note: Consider using the vararg version of this contructor.
+	 *
+	 * @param workingSetIds
+	 *            working set ids from which the user can choose
+	 * @param settings
+	 *            to store/load the selection history
+	 * @param enableButtonLabel
+	 *            the label to use for the checkable enablement button. May be
+	 *            <code>null</code> to use the default value.
+	 * @param comboLabel
+	 *            the label to use for the recent working set combo. May be
+	 *            <code>null</code> to use the default value.
+	 * @param selectLabel
+	 *            the label to use for the select button. May be
+	 *            <code>null</code> to use the default value.
+	 */
+	public WorkingSetConfigurationBlock(String[] workingSetIds, IDialogSettings settings, String enableButtonLabel, String comboLabel, String selectLabel) {
+		this(settings, enableButtonLabel, null, comboLabel, selectLabel, workingSetIds);
+	}
+
+
+	/**
+	 * Create a new instance of this working set block using custom labels.
+	 *
+	 * @param settings
+	 *            to store/load the selection history
+	 * @param enableButtonLabel
+	 *            the label to use for the checkable enablement button. May be
+	 *            <code>null</code> to use the default value.
+	 * @param newButtonLabel
+	 *            the label to use for the new button. May be <code>null</code>
+	 *            to use the default value.
+	 * @param comboLabel
+	 *            the label to use for the recent working set combo. May be
+	 *            <code>null</code> to use the default value.
+	 * @param selectLabel
+	 *            the label to use for the select button. May be
+	 *            <code>null</code> to use the default value.
+	 * @param workingSetIds
+	 *            working set ids from which the user can choose
+	 * @since 3.108
+	 */
+	public WorkingSetConfigurationBlock(IDialogSettings settings, String enableButtonLabel, String newButtonLabel,
+			String comboLabel, String selectLabel, String... workingSetIds) {
+		Assert.isNotNull(workingSetIds);
+		Assert.isNotNull(settings);
+
+		workingSetTypeIds = workingSetIds;
+		Arrays.sort(workingSetIds); // we'll be performing some searches with these later - presort them
+		selectedWorkingSets = EMPTY_WORKING_SET_ARRAY;
+		dialogSettings = settings;
+		selectionHistory = loadSelectionHistory(settings, workingSetIds);
+
+		this.enableButtonLabel = enableButtonLabel == null ? WorkbenchMessages.get().WorkingSetGroup_EnableWorkingSet_button
+				: enableButtonLabel;
+		this.newButtonLabel = newButtonLabel == null
+				? WorkbenchMessages.get().WorkingSetConfigurationBlock_NewWorkingSet_button : newButtonLabel;
+		this.comboLabel = comboLabel == null ? WorkbenchMessages.get().WorkingSetConfigurationBlock_WorkingSetText_name
+				: comboLabel;
+		this.selectLabel = selectLabel == null ? WorkbenchMessages.get().WorkingSetConfigurationBlock_SelectWorkingSet_button
+				: selectLabel;
+	}
+
+	/**
+	 * Set the current selection in the workbench.
+	 *
+	 * @param selection
+	 *            the selection to present in the UI or <b>null</b>
+	 * @deprecated use
+	 *             {@link #setWorkingSets(IWorkingSet[])} and {@link #findApplicableWorkingSets(IStructuredSelection)}
+	 *             instead.
+	 */
+	@Deprecated
+	public void setSelection(IStructuredSelection selection) {
+		selectedWorkingSets = findApplicableWorkingSets(selection);
+
+		if (workingSetCombo != null) {
+			updateSelectedWorkingSets();
+		}
+	}
+
+	/**
+	 * Set the current selection of working sets. This array will be filtered to
+	 * contain only working sets that are applicable to this instance.
+	 *
+	 * @param workingSets
+	 *            the working sets
+	 */
+	public void setWorkingSets(IWorkingSet... workingSets) {
+		selectedWorkingSets = filterWorkingSets(Arrays.asList(workingSets));
+		if (workingSetCombo != null) {
+			updateSelectedWorkingSets();
+		}
+	}
+
+	/**
+	 * Retrieves a working set from the given <code>selection</code> or an
+	 * empty array if no working set could be retrieved. This selection is
+	 * filtered based on the criteria used to construct this instance.
+	 *
+	 * @param selection
+	 *            the selection to retrieve the working set from
+	 * @return the selected working set or an empty array
+	 */
+	public IWorkingSet[] findApplicableWorkingSets(
+			IStructuredSelection selection) {
+		if (selection == null) {
+			return EMPTY_WORKING_SET_ARRAY;
+		}
+
+		return filterWorkingSets(selection.toList());
+	}
+
+	/**
+	 * Prune a list of working sets such that they all match the criteria set
+	 * out by this block.
+	 *
+	 * @param elements
+	 *            the elements to filter
+	 * @return the filtered elements
+	 */
+	private IWorkingSet[] filterWorkingSets(Collection<?> elements) {
+		List<IWorkingSet> result = new ArrayList<>();
+		for (Object element : elements) {
+			if (element instanceof IWorkingSet
+					&& verifyWorkingSet((IWorkingSet) element)) {
+				result.add((IWorkingSet) element);
+			}
+		}
+		return result.toArray(new IWorkingSet[result.size()]);
+	}
+
+	/**
+	 * Verifies that the given working set is suitable for selection in this
+	 * block.
+	 *
+	 * @param workingSetCandidate
+	 *            the candidate to test
+	 * @return whether it is suitable
+	 */
+	private boolean verifyWorkingSet(IWorkingSet workingSetCandidate) {
+		return !workingSetCandidate.isAggregateWorkingSet()
+				&& Arrays.binarySearch(workingSetTypeIds, workingSetCandidate
+						.getId()) >= 0 ;
+	}
+
+	/**
+	 * Return the currently selected working sets. If the controls representing
+	 * this block are disabled this array will be empty regardless of the
+	 * currently selected values.
+	 *
+	 * @return the selected working sets
+	 */
+	public IWorkingSet[] getSelectedWorkingSets() {
+		if (enableButton.getSelection()) {
+			return selectedWorkingSets;
+		}
+		return EMPTY_WORKING_SET_ARRAY;
+	}
+
+	/**
+	 * Add this block to the <code>parent</parent>
+	 *
+	 * @param parent the parent to add the block to
+	 */
+	public void createContent(final Composite parent) {
+		Composite composite = new Composite(parent, SWT.NONE);
+		composite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+		composite.setLayout(new GridLayout(3, false));
+
+		enableButton = new Button(composite, SWT.CHECK);
+		enableButton
+				.setText(enableButtonLabel);
+		GridData enableData = new GridData(SWT.FILL, SWT.CENTER, true, false);
+		enableData.horizontalSpan = 2;
+		enableButton.setLayoutData(enableData);
+		enableButton.setSelection(selectedWorkingSets.length > 0);
+
+		newButton = new Button(composite, SWT.PUSH);
+		newButton.setText(this.newButtonLabel);
+		setButtonLayoutData(newButton);
+		newButton.addSelectionListener(new SelectionAdapter()
+        {
+		    /** {@inheritDoc} */
+		    @Override
+		    public void widgetSelected(SelectionEvent e)
+		    {
+		        createNewWorkingSet(newButton.getShell());
+		    }
+        });
+
+		workingSetLabel = new Label(composite, SWT.NONE);
+		workingSetLabel
+				.setText(comboLabel);
+
+		workingSetCombo = new Combo(composite, SWT.READ_ONLY | SWT.BORDER);
+		GridData textData = new GridData(SWT.FILL, SWT.CENTER, true, false);
+		textData.horizontalIndent = 0;
+		workingSetCombo.setLayoutData(textData);
+
+		selectButton = new Button(composite, SWT.PUSH);
+		selectButton
+				.setText(selectLabel);
+		setButtonLayoutData(selectButton);
+        selectButton.addSelectionListener(new SelectionAdapter()
+        {
+            /** {@inheritDoc} */
+            @Override
+            public void widgetSelected(SelectionEvent e)
+            {
+                SimpleWorkingSetSelectionDialog dialog = new SimpleWorkingSetSelectionDialog(parent.getShell(),
+                                                                                             workingSetTypeIds,
+                                                                                             selectedWorkingSets,
+                                                                                             false);
+                dialog.setMessage(WorkbenchMessages.get().WorkingSetGroup_WorkingSetSelection_message);
+
+                if (dialog.open() == Window.OK)
+                {
+                    IWorkingSet[] result = dialog.getSelection();
+                    if (result != null && result.length > 0)
+                    {
+                        selectedWorkingSets = result;
+                        PlatformUI.getWorkbench().getWorkingSetManager().addRecentWorkingSet(result[0]);
+                    }
+                    else
+                    {
+                        selectedWorkingSets = EMPTY_WORKING_SET_ARRAY;
+                    }
+                    updateWorkingSetSelection();
+                }
+            }
+        });
+
+		enableButton.addSelectionListener(new SelectionAdapter()
+        {
+		    /** {@inheritDoc} */
+		    @Override
+		    public void widgetSelected(SelectionEvent e)
+		    {
+		        updateEnableState(enableButton.getSelection());
+		    }
+        });
+		updateEnableState(enableButton.getSelection());
+
+		workingSetCombo.addSelectionListener(new SelectionAdapter()
+        {
+		    /** {@inheritDoc} */
+		    @Override
+		    public void widgetSelected(SelectionEvent e)
+		    {
+		        updateSelectedWorkingSets();
+		    }
+        });
+
+		workingSetCombo.setItems(getHistoryEntries());
+		if (selectedWorkingSets.length == 0 && selectionHistory.size() > 0) {
+			workingSetCombo.select(historyIndex(selectionHistory.get(0)));
+			updateSelectedWorkingSets();
+		} else {
+			updateWorkingSetSelection();
+		}
+	}
+
+	private void createNewWorkingSet(Shell shell) {
+		IWorkingSetManager manager = WorkbenchPlugin.getDefault().getWorkingSetManager();
+		IWorkingSetNewWizard wizard = manager.createWorkingSetNewWizard(workingSetTypeIds);
+		// the wizard can never be null since we have at least a resource
+		// working set creation page
+		WizardDialog dialog = new WizardDialog(shell, wizard);
+		dialog.create();
+
+		PlatformUI.getWorkbench().getHelpSystem().setHelp(dialog.getShell(),
+				IWorkbenchHelpContextIds.WORKING_SET_NEW_WIZARD);
+		if (dialog.open() == Window.OK) {
+			IWorkingSet workingSet = wizard.getSelection();
+			if (workingSet != null) {
+				manager.addWorkingSet(workingSet);
+				selectedWorkingSets = new IWorkingSet[] { workingSet };
+				PlatformUI.getWorkbench().getWorkingSetManager().addRecentWorkingSet(workingSet);
+			}
+			enableButton.setSelection(true);
+			updateEnableState(true);
+			updateWorkingSetSelection();
+		}
+	}
+
+	private void updateEnableState(boolean enabled) {
+		workingSetLabel.setEnabled(enabled);
+		workingSetCombo
+				.setEnabled(enabled
+						&& (selectedWorkingSets.length > 0 || getHistoryEntries().length > 0));
+		selectButton.setEnabled(enabled);
+	}
+
+	private void updateWorkingSetSelection() {
+		if (selectedWorkingSets.length > 0) {
+			workingSetCombo.setEnabled(true);
+			StringBuffer buf = new StringBuffer();
+
+			buf.append(selectedWorkingSets[0].getLabel());
+			for (int i = 1; i < selectedWorkingSets.length; i++) {
+				IWorkingSet ws = selectedWorkingSets[i];
+				buf.append(',').append(' ');
+				buf.append(ws.getLabel());
+			}
+
+			String currentSelection = buf.toString();
+			int index = historyIndex(currentSelection);
+			historyInsert(currentSelection);
+			if (index >= 0) {
+				workingSetCombo.select(index);
+			} else {
+				workingSetCombo.setItems(getHistoryEntries());
+				workingSetCombo.select(historyIndex(currentSelection));
+			}
+		} else {
+			enableButton.setSelection(false);
+			updateEnableState(false);
+		}
+	}
+
+	private String[] getHistoryEntries() {
+		String[] history = selectionHistory
+				.toArray(new String[selectionHistory.size()]);
+		Arrays.sort(history, (o1, o2) -> Collator.getInstance().compare(o1, o2));
+		return history;
+	}
+
+	private void historyInsert(String entry) {
+		selectionHistory.remove(entry);
+		selectionHistory.add(0, entry);
+		storeSelectionHistory(dialogSettings);
+	}
+
+	private int historyIndex(String entry) {
+		for (int i = 0; i < workingSetCombo.getItemCount(); i++) {
+			if (workingSetCombo.getItem(i).equals(entry)) {
+				return i;
+			}
+		}
+
+		return -1;
+	}
+
+	// copied from org.eclipse.jdt.internal.ui.text.JavaCommentScanner
+	private String[] split(String value, String delimiters) {
+		StringTokenizer tokenizer= new StringTokenizer(value, delimiters);
+		int size= tokenizer.countTokens();
+		String[] tokens= new String[size];
+		int i= 0;
+		while (i < size) {
+			tokens[i++]= tokenizer.nextToken();
+		}
+		return tokens;
+	}
+
+	private void updateSelectedWorkingSets() {
+		String item = workingSetCombo.getItem(workingSetCombo
+				.getSelectionIndex());
+		String[] workingSetNames = split(item, ", "); //$NON-NLS-1$
+
+		IWorkingSetManager workingSetManager = PlatformUI.getWorkbench()
+				.getWorkingSetManager();
+		selectedWorkingSets = new IWorkingSet[workingSetNames.length];
+		for (int i = 0; i < workingSetNames.length; i++) {
+			IWorkingSet set = workingSetManager
+					.getWorkingSet(workingSetNames[i]);
+			Assert.isNotNull(set);
+			selectedWorkingSets[i] = set;
+		}
+	}
+
+	private void storeSelectionHistory(IDialogSettings settings) {
+		String[] history;
+		if (selectionHistory.size() > MAX_HISTORY_SIZE) {
+			List<String> subList = selectionHistory.subList(0, MAX_HISTORY_SIZE);
+			history = subList.toArray(new String[subList.size()]);
+		} else {
+			history = selectionHistory
+					.toArray(new String[selectionHistory.size()]);
+		}
+		settings.put(WORKINGSET_SELECTION_HISTORY, history);
+	}
+
+	private List<String> loadSelectionHistory(IDialogSettings settings, String... workingSetIds) {
+		String[] strings = settings.getArray(WORKINGSET_SELECTION_HISTORY);
+		if (strings == null || strings.length == 0) {
+			return new ArrayList<>();
+		}
+
+		List<String> result = new ArrayList<>();
+
+		Set<String> workingSetIdsSet = new HashSet<>(Arrays.asList(workingSetIds));
+
+		IWorkingSetManager workingSetManager = PlatformUI.getWorkbench()
+				.getWorkingSetManager();
+		for (String string : strings) {
+			String[] workingSetNames = split(string, ", "); //$NON-NLS-1$
+			boolean valid = true;
+			for (int j = 0; j < workingSetNames.length && valid; j++) {
+				IWorkingSet workingSet = workingSetManager
+						.getWorkingSet(workingSetNames[j]);
+				if (workingSet == null) {
+					valid = false;
+				} else if (!workingSetIdsSet.contains(workingSet.getId())) {
+					valid = false;
+				}
+			}
+			if (valid) {
+				result.add(string);
+			}
+		}
+
+		return result;
+	}
+
+	/*
+	 * Copy from DialogPage with changes to accomodate the lack of a Dialog context.
+	 */
+	private GridData setButtonLayoutData(Button button) {
+		button.setFont(JFaceResources.getDialogFont());
+
+		GC gc = new GC(button);
+		gc.setFont(button.getFont());
+		FontMetrics fontMetrics = gc.getFontMetrics();
+		gc.dispose();
+
+        GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
+        int widthHint = Dialog.convertHorizontalDLUsToPixels(fontMetrics, IDialogConstants.BUTTON_WIDTH);
+        Point minSize = button.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
+        data.widthHint = Math.max(widthHint, minSize.x);
+        button.setLayoutData(data);
+        return data;
+    }
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/WorkingSetGroup.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/WorkingSetGroup.java
new file mode 100644
index 0000000..749010d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/WorkingSetGroup.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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
+ *     Simon Scholz <simon.scholz@vogella.com> - Bug 483528
+ *******************************************************************************/
+package org.eclipse.ui.dialogs;
+
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.ui.IWorkingSet;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+
+/**
+ * Instances of this class provide a {@link WorkingSetConfigurationBlock}
+ * wrapped with an SWT Group container.
+ *
+ * @since 3.4
+ */
+public final class WorkingSetGroup {
+
+	private WorkingSetConfigurationBlock workingSetBlock;
+
+	/**
+	 * Create a new instance of this class.
+	 *
+	 * @param composite
+	 *            parent composite
+	 * @param currentSelection
+	 *            the initial working set selection to pass to the
+	 *            {@link WorkingSetConfigurationBlock}
+	 * @param workingSetTypes
+	 *            the types of working sets that can be selected by the
+	 *            {@link WorkingSetConfigurationBlock}
+	 */
+	public WorkingSetGroup(Composite composite,
+			IStructuredSelection currentSelection, String[] workingSetTypes) {
+		Group workingSetGroup = new Group(composite, SWT.NONE);
+		workingSetGroup.setFont(composite.getFont());
+		workingSetGroup
+				.setText(WorkbenchMessages.get().WorkingSetGroup_WorkingSets_group);
+		workingSetGroup.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true,
+				false));
+		workingSetGroup.setLayout(new GridLayout(1, false));
+
+		workingSetBlock = new WorkingSetConfigurationBlock(WorkbenchPlugin.getDefault().getDialogSettings(),
+				workingSetTypes);
+		workingSetBlock.setWorkingSets(workingSetBlock
+				.findApplicableWorkingSets(currentSelection));
+		workingSetBlock.createContent(workingSetGroup);
+	}
+
+	/**
+	 * Return the working sets selected by the contained
+	 * {@link WorkingSetConfigurationBlock}.
+	 *
+	 * @return the selected working sets
+	 */
+	public IWorkingSet[] getSelectedWorkingSets() {
+		return workingSetBlock.getSelectedWorkingSets();
+	}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/YesNoCancelListSelectionDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/YesNoCancelListSelectionDialog.java
new file mode 100644
index 0000000..466c82e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/YesNoCancelListSelectionDialog.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.dialogs;
+
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+
+/**
+ * YesNoCancelListSelectionDialog is a list selection dialog that also allows
+ * the user to select no as a result.
+ *
+ * @deprecated Providing Cancel in addition to Yes/No is confusing. It is better
+ *             to subclass the regular ListSelectionDialog, which uses
+ *             OK/Cancel, and provide a separate checkbox if necessary.
+ */
+@Deprecated
+public class YesNoCancelListSelectionDialog extends ListSelectionDialog {
+    /**
+     *
+     * Create a list selection dialog with a possible Yes/No or Cancel result.
+     *
+     * @param parentShell
+     * @param input
+     * @param contentProvider
+     * @param labelProvider
+     * @param message
+     * @deprecated see class comment
+     */
+    @Deprecated
+	public YesNoCancelListSelectionDialog(
+            org.eclipse.swt.widgets.Shell parentShell,
+            Object input,
+            org.eclipse.jface.viewers.IStructuredContentProvider contentProvider,
+            org.eclipse.jface.viewers.ILabelProvider labelProvider,
+            String message) {
+        super(parentShell, input, contentProvider, labelProvider, message);
+    }
+
+    @Override
+	protected void buttonPressed(int buttonId) {
+        switch (buttonId) {
+        case IDialogConstants.YES_ID: {
+            yesPressed();
+            return;
+        }
+        case IDialogConstants.NO_ID: {
+            noPressed();
+            return;
+        }
+        case IDialogConstants.CANCEL_ID: {
+            cancelPressed();
+            return;
+        }
+        }
+    }
+
+    @Override
+	protected void configureShell(Shell shell) {
+        super.configureShell(shell);
+        PlatformUI.getWorkbench().getHelpSystem().setHelp(shell,
+                IWorkbenchHelpContextIds.YES_NO_CANCEL_LIST_SELECTION_DIALOG);
+    }
+
+    @Override
+	protected void createButtonsForButtonBar(Composite parent) {
+        createButton(parent, IDialogConstants.YES_ID,
+                IDialogConstants.get().YES_LABEL, true);
+        createButton(parent, IDialogConstants.NO_ID, IDialogConstants.get().NO_LABEL,
+                false);
+        createButton(parent, IDialogConstants.CANCEL_ID,
+                IDialogConstants.get().CANCEL_LABEL, false);
+    }
+
+    /**
+     * Notifies that the no button of this dialog has been pressed.
+     * <p>
+     * The <code>Dialog</code> implementation of this framework method sets
+     * this dialog's return code to <code>IDialogConstants.NO_ID</code> and
+     * closes the dialog. Subclasses may override if desired.
+     * </p>
+     */
+    protected void noPressed() {
+        setReturnCode(IDialogConstants.NO_ID);
+        close();
+    }
+
+    /**
+     * Notifies that the yes button of this dialog has been pressed. Do the same
+     * as an OK but set the return code to YES_ID instead.
+     */
+    protected void yesPressed() {
+        okPressed();
+        setReturnCode(IDialogConstants.YES_ID);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/package.html b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/package.html
new file mode 100644
index 0000000..bb802d7
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dialogs/package.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <meta name="Author" content="IBM">
+   <meta name="GENERATOR" content="Mozilla/4.5 [en] (WinNT; I) [Netscape]">
+   <title>Package-level Javadoc</title>
+</head>
+<body>
+Classes for standard dialogs, wizards, and preference
+pages in the Eclipse Platform User Interface.
+<h2>
+Package Specification</h2>
+This package provides useful classes for the definition of wizards, property
+pages and preference pages.&nbsp; It also provides standard dialogs such
+as the Save As dialog.
+</body>
+</html>
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dnd/IDragAndDropService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dnd/IDragAndDropService.java
new file mode 100644
index 0000000..12e8dfa
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dnd/IDragAndDropService.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.dnd;
+
+import org.eclipse.swt.dnd.DropTargetListener;
+import org.eclipse.swt.dnd.Transfer;
+import org.eclipse.swt.widgets.Control;
+
+/**
+ * This interface specifies the API for a service to be used by part authors to
+ * access methods which provide support for Drag and Drop operations within the
+ * workbench.
+ * <p>
+ * Authors should access this service using the PartSite's
+ * <code>getService</code> method, passing this interface as the argument.
+ * </p>
+ * <p>
+ * <b>NOTE:</b> This interface it not expected to be implemented by clients; it
+ * is provided only to allow access to the service's methods.
+ * </p>
+ * <p>
+ *
+ * @since 3.3
+ *
+ */
+public interface IDragAndDropService {
+	/**
+	 * Causes a drop target to be added to the given control that respects the
+	 * existing site's drop behaviour in addition to the behaviour being
+	 * specified for the given control.
+	 * <p>
+	 * If a transfer type specified for the control matches one used by the site
+	 * then the control's listener is called (the client is overriding the
+	 * existing site behaviour which will no longer work).
+	 * </p>
+	 * <p>
+	 * NOTE: Site authors <b>must</b> use this method to add drop behaviour;
+	 * directly adding drop targets using SWT onto a site will cause the
+	 * standard site behaviour (i.e. dragging files / markers into the
+	 * EditorSite...) to not work when that editor is active.
+	 * </p>
+	 * <p>
+	 * Note that this method may be used more than once should the part author
+	 * wish to register different drop targets for internal controls (i.e. to
+	 * support internal DnD).
+	 * </p>
+	 * <p>
+	 *
+	 * @param control
+	 *            The control to add the drop behaviour to
+	 * @param ops
+	 *            The Drop operations used by this target
+	 * @param transfers
+	 *            The TransferTypes used by this target
+	 * @param listener
+	 *            The listener controlling the target's behaviour
+	 */
+	public void addMergedDropTarget(Control control, int ops, Transfer[] transfers, DropTargetListener listener);
+
+	/**
+	 * Remove any previously 'merged' drop target for this Control
+	 *
+	 * @param control The control to remove the drop target for
+	 */
+	public void removeMergedDropTarget(Control control);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dnd/package.html b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dnd/package.html
new file mode 100644
index 0000000..605c979
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/dnd/package.html
@@ -0,0 +1,16 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <meta name="Author" content="IBM">
+   <meta name="GENERATOR" content="Mozilla/4.5 [en] (WinNT; I) [Netscape]">
+   <title>Package-level Javadoc</title>
+</head>
+<body>
+Classes and Interface specifications for Drag and Drop in the Eclipse Platform User Interface.
+<h2>
+Package Specification</h2>
+This package provides useful classes and interfaces for the definition of Drag and Drop
+behaviour in the Eclipse workbench. 
+</body>
+</html>
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/fieldassist/ContentAssistCommandAdapter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/fieldassist/ContentAssistCommandAdapter.java
new file mode 100644
index 0000000..25a3715
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/fieldassist/ContentAssistCommandAdapter.java
@@ -0,0 +1,300 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *******************************************************************************/
+
+package org.eclipse.ui.fieldassist;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.jface.fieldassist.ContentProposalAdapter;
+import org.eclipse.jface.fieldassist.ControlDecoration;
+import org.eclipse.jface.fieldassist.FieldDecoration;
+import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
+import org.eclipse.jface.fieldassist.IContentProposalProvider;
+import org.eclipse.jface.fieldassist.IControlContentAdapter;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.handlers.IHandlerActivation;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.keys.IBindingService;
+
+/**
+ * ContentAssistCommandAdapter extends {@link ContentProposalAdapter} to invoke
+ * content proposals using a specified {@link org.eclipse.core.commands.Command}.
+ * The ability to specify a {@link org.eclipse.jface.bindings.keys.KeyStroke}
+ * that explicitly invokes content proposals is hidden by this class, and
+ * instead the String id of a command is used. If no command id is specified by
+ * the client, then the default workbench content assist command is used.
+ * <p>
+ * As of 3.3, ContentAssistCommandAdapter can be optionally configured to
+ * install the content assist decoration on its control.
+ * <p>
+ * This class is not intended to be subclassed.
+ *
+ * @since 3.2
+ */
+public class ContentAssistCommandAdapter extends ContentProposalAdapter {
+
+	private static final String CONTENT_ASSIST_DECORATION_ID = "org.eclipse.ui.fieldAssist.ContentAssistField"; //$NON-NLS-1$
+	private String commandId;
+
+	/**
+	 * The command id used for content assist. (value
+	 * <code>"org.eclipse.ui.edit.text.contentAssist.proposals"</code>)
+	 *
+	 * @deprecated As of 3.5, replaced by {@link IWorkbenchCommandConstants#EDIT_CONTENT_ASSIST}
+	 */
+	@Deprecated
+	public static final String CONTENT_PROPOSAL_COMMAND= IWorkbenchCommandConstants.EDIT_CONTENT_ASSIST;
+
+	// Default autoactivation delay in milliseconds
+	// TODO: This should eventually be controlled by
+	// a platform UI preference.
+	private static final int DEFAULT_AUTO_ACTIVATION_DELAY = 500;
+
+	private IHandlerService handlerService;
+
+	private IHandlerActivation activeHandler;
+
+	private IHandler proposalHandler = new AbstractHandler() {
+		@Override
+		public Object execute(ExecutionEvent event) {
+			openProposalPopup();
+			return null;
+		}
+
+	};
+	private ControlDecoration decoration;
+
+	/**
+	 * Construct a content proposal adapter that can assist the user with
+	 * choosing content for the field. No visual indicator of content assist is
+	 * shown.
+	 *
+	 * @param control
+	 *            the control for which the adapter is providing content assist.
+	 *            May not be <code>null</code>.
+	 * @param controlContentAdapter
+	 *            the <code>IControlContentAdapter</code> used to obtain and
+	 *            update the control's contents as proposals are accepted. May
+	 *            not be <code>null</code>.
+	 * @param proposalProvider
+	 *            the <code>IContentProposalProvider</code> used to obtain
+	 *            content proposals for this control, or <code>null</code> if
+	 *            no content proposal is available.
+	 * @param commandId
+	 *            the String id of the command that will invoke the content
+	 *            assistant. If not supplied, the default value will be
+	 *            "org.eclipse.ui.edit.text.contentAssist.proposals".
+	 * @param autoActivationCharacters
+	 *            An array of characters that trigger auto-activation of content
+	 *            proposal. If specified, these characters will trigger
+	 *            auto-activation of the proposal popup, regardless of the
+	 *            specified command id.
+	 */
+	public ContentAssistCommandAdapter(Control control,
+			IControlContentAdapter controlContentAdapter,
+			IContentProposalProvider proposalProvider, String commandId,
+			char[] autoActivationCharacters) {
+		this(control, controlContentAdapter, proposalProvider, commandId,
+				autoActivationCharacters, false);
+	}
+
+	/**
+	 * Construct a content proposal adapter that can assist the user with
+	 * choosing content for the field.
+	 *
+	 * @param control
+	 *            the control for which the adapter is providing content assist.
+	 *            May not be <code>null</code>.
+	 * @param controlContentAdapter
+	 *            the <code>IControlContentAdapter</code> used to obtain and
+	 *            update the control's contents as proposals are accepted. May
+	 *            not be <code>null</code>.
+	 * @param proposalProvider
+	 *            the <code>IContentProposalProvider</code> used to obtain
+	 *            content proposals for this control, or <code>null</code> if
+	 *            no content proposal is available.
+	 * @param commandId
+	 *            the String id of the command that will invoke the content
+	 *            assistant. If not supplied, the default value will be
+	 *            "org.eclipse.ui.edit.text.contentAssist.proposals".
+	 * @param autoActivationCharacters
+	 *            An array of characters that trigger auto-activation of content
+	 *            proposal. If specified, these characters will trigger
+	 *            auto-activation of the proposal popup, regardless of the
+	 *            specified command id.
+	 * @param installDecoration
+	 *            A boolean that specifies whether a content assist control
+	 *            decoration should be installed. The client is responsible for
+	 *            ensuring that adequate space is reserved for the decoration.
+	 *            Clients that want more fine-grained control of the
+	 *            decoration's location or appearance should use
+	 *            <code>false</code> for this parameter, creating their own
+	 *            {@link ControlDecoration} and managing it directly.
+	 * @since 3.3
+	 */
+	public ContentAssistCommandAdapter(Control control,
+			IControlContentAdapter controlContentAdapter,
+			IContentProposalProvider proposalProvider, String commandId,
+			char[] autoActivationCharacters, boolean installDecoration) {
+		super(control, controlContentAdapter, proposalProvider, null,
+				autoActivationCharacters);
+		this.commandId = commandId;
+		if (commandId == null) {
+			this.commandId= IWorkbenchCommandConstants.EDIT_CONTENT_ASSIST;
+		}
+
+		// If no autoactivation characters were specified, set them to the empty
+		// array so that we don't get the alphanumeric auto-trigger of our
+		// superclass.
+		if (autoActivationCharacters == null) {
+			this.setAutoActivationCharacters(new char[] {});
+		}
+		// Set a default autoactivation delay.
+		setAutoActivationDelay(DEFAULT_AUTO_ACTIVATION_DELAY);
+
+		// Cache the handler service so we don't have to retrieve it each time
+		this.handlerService = PlatformUI.getWorkbench()
+				.getService(IHandlerService.class);
+
+		// Add listeners to the control to manage activation of the handler
+		addListeners(control);
+
+		if (control.isFocusControl()) {
+			activateHandler();
+		}
+
+		if (installDecoration) {
+			// Note top left is used for compatibility with 3.2, although
+			// this may change to center alignment in the future.
+			decoration = new ControlDecoration(control, SWT.TOP | SWT.LEFT);
+			decoration.setShowOnlyOnFocus(true);
+			FieldDecoration dec = getContentAssistFieldDecoration();
+			decoration.setImage(dec.getImage());
+			decoration.setDescriptionText(dec.getDescription());
+		}
+
+	}
+
+	/*
+	 * Add the listeners needed in order to activate the content assist command
+	 * on the control.
+	 */
+	private void addListeners(Control control) {
+		control.addFocusListener(new FocusListener() {
+			@Override
+			public void focusLost(FocusEvent e) {
+				deactivateHandler();
+			}
+
+			@Override
+			public void focusGained(FocusEvent e) {
+				if (isEnabled()) {
+					activateHandler();
+				} else {
+					deactivateHandler();
+				}
+			}
+		});
+		control.addDisposeListener(e -> deactivateHandler());
+	}
+
+	/**
+	 * Return the string command ID of the command used to invoke content
+	 * assist.
+	 *
+	 * @return the command ID of the command that invokes content assist.
+	 */
+	public String getCommandId() {
+		return commandId;
+	}
+
+	/*
+	 * Return the field decoration that should be used to indicate that content
+	 * assist is available for a field. Ensure that the decoration text includes
+	 * the correct key binding.
+	 *
+	 * @return the {@link FieldDecoration} that should be used to show content
+	 * assist.
+	 *
+	 * @since 3.3
+	 */
+	private FieldDecoration getContentAssistFieldDecoration() {
+		FieldDecorationRegistry registry = FieldDecorationRegistry.getDefault();
+		// Look for a decoration installed for this particular command id.
+		String decId = CONTENT_ASSIST_DECORATION_ID + getCommandId();
+		FieldDecoration dec = registry.getFieldDecoration(decId);
+
+		// If there is not one, base ours on the standard JFace one.
+		if (dec == null) {
+			FieldDecoration originalDec = registry
+					.getFieldDecoration(FieldDecorationRegistry.DEC_CONTENT_PROPOSAL);
+
+			registry.registerFieldDecoration(decId, null, originalDec
+					.getImage());
+			dec = registry.getFieldDecoration(decId);
+		}
+		// Always update the decoration text since the key binding may
+		// have changed since it was last retrieved.
+		IBindingService bindingService = PlatformUI
+				.getWorkbench().getService(IBindingService.class);
+		dec
+				.setDescription(NLS
+						.bind(
+								WorkbenchMessages.get().ContentAssist_Cue_Description_Key,
+								bindingService
+										.getBestActiveBindingFormattedFor(getCommandId())));
+
+		// Now return the field decoration
+		return dec;
+	}
+
+	@Override
+	public void setEnabled(boolean enabled) {
+		super.setEnabled(enabled);
+		if (decoration != null) {
+			if (enabled) {
+				decoration.show();
+			} else {
+				decoration.hide();
+			}
+		}
+		if (getControl().isFocusControl()) {
+			if (enabled) {
+				activateHandler();
+			} else {
+				deactivateHandler();
+			}
+		}
+	}
+
+	private void activateHandler() {
+		if (activeHandler == null) {
+			activeHandler = handlerService.activateHandler(commandId,
+					proposalHandler);
+		}
+	}
+
+	private void deactivateHandler() {
+		if (activeHandler != null) {
+			handlerService.deactivateHandler(activeHandler);
+			activeHandler = null;
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/fieldassist/ContentAssistField.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/fieldassist/ContentAssistField.java
new file mode 100644
index 0000000..bb4e0e9
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/fieldassist/ContentAssistField.java
@@ -0,0 +1,154 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *******************************************************************************/
+
+package org.eclipse.ui.fieldassist;
+
+import org.eclipse.jface.fieldassist.DecoratedField;
+import org.eclipse.jface.fieldassist.FieldDecoration;
+import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
+import org.eclipse.jface.fieldassist.IContentProposalProvider;
+import org.eclipse.jface.fieldassist.IControlContentAdapter;
+import org.eclipse.jface.fieldassist.IControlCreator;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.keys.IBindingService;
+
+/**
+ * ContentAssistField utilizes the concepts of a {@link DecoratedField} and the
+ * {@link ContentAssistCommandAdapter} to provide a decorated field that shows a
+ * content assist cue when it gets focus and invokes content assist for a
+ * specified command.
+ * <p>
+ * This class is not intended to be subclassed.
+ *
+ * @since 3.2
+ * @deprecated As of 3.3, clients should use
+ *             {@link org.eclipse.jface.fieldassist.ControlDecoration} and
+ *             {@link ContentAssistCommandAdapter} instead of this class.
+ */
+@Deprecated
+public class ContentAssistField extends DecoratedField {
+
+	private ContentAssistCommandAdapter adapter;
+
+	private static final String CONTENT_ASSIST_DECORATION_ID = "org.eclipse.ui.fieldAssist.ContentAssistField"; //$NON-NLS-1$
+
+	/**
+	 * Construct a content assist field that shows a content assist cue and can
+	 * assist the user with choosing content for the field.
+	 *
+	 * @param parent
+	 *            the parent of the decorated field.
+	 * @param style
+	 *            the desired style bits for the field.
+	 * @param controlCreator
+	 *            the IControlCreator used to specify the specific kind of
+	 *            control that is to be decorated.
+	 * @param controlContentAdapter
+	 *            the <code>IControlContentAdapter</code> used to obtain and
+	 *            update the control's contents as proposals are accepted. May
+	 *            not be <code>null</code>.
+	 * @param proposalProvider
+	 *            the <code>IContentProposalProvider</code> used to obtain
+	 *            content proposals for this control, or <code>null</code> if
+	 *            no content proposal is available.
+	 * @param commandId
+	 *            the String id of the command that will invoke the content
+	 *            assistant. If not supplied, the default value will be
+	 *            "org.eclipse.ui.edit.text.contentAssist.proposals".
+	 * @param autoActivationCharacters
+	 *            An array of characters that trigger auto-activation of content
+	 *            proposal. If specified, these characters will trigger
+	 *            auto-activation of the proposal popup, regardless of the
+	 *            specified command id.
+	 */
+	public ContentAssistField(Composite parent, int style,
+			IControlCreator controlCreator,
+			IControlContentAdapter controlContentAdapter,
+			IContentProposalProvider proposalProvider, String commandId,
+			char[] autoActivationCharacters) {
+
+		super(parent, style, controlCreator);
+		adapter = new ContentAssistCommandAdapter(getControl(),
+				controlContentAdapter, proposalProvider, commandId,
+				autoActivationCharacters);
+
+		addFieldDecoration(getFieldDecoration(), SWT.LEFT | SWT.TOP, true);
+
+	}
+
+	/**
+	 * Set the boolean flag that determines whether the content assist is
+	 * enabled.
+	 *
+	 * @param enabled
+	 *            <code>true</code> if content assist is enabled and
+	 *            responding to user input, <code>false</code> if it is
+	 *            ignoring user input.
+	 *
+	 */
+	public void setEnabled(boolean enabled) {
+		adapter.setEnabled(enabled);
+		if (enabled) {
+			showDecoration(getFieldDecoration());
+		} else {
+			hideDecoration(getFieldDecoration());
+		}
+	}
+
+	/*
+	 * Get a field decoration appropriate for cueing the user, including a
+	 * description of the active key binding.
+	 *
+	 */
+	private FieldDecoration getFieldDecoration() {
+		FieldDecorationRegistry registry = FieldDecorationRegistry.getDefault();
+		// Look for a decoration installed for this particular command id.
+		String decId = CONTENT_ASSIST_DECORATION_ID + adapter.getCommandId();
+		FieldDecoration dec = registry.getFieldDecoration(decId);
+
+		// If there is not one, base ours on the standard JFace one.
+		if (dec == null) {
+			FieldDecoration originalDec = registry
+					.getFieldDecoration(FieldDecorationRegistry.DEC_CONTENT_PROPOSAL);
+
+			registry.registerFieldDecoration(decId, null, originalDec
+					.getImage());
+			dec = registry.getFieldDecoration(decId);
+		}
+		// Always update the decoration text since the key binding may
+		// have changed since it was last retrieved.
+		IBindingService bindingService = PlatformUI
+				.getWorkbench().getService(IBindingService.class);
+		dec.setDescription(NLS.bind(
+				WorkbenchMessages.get().ContentAssist_Cue_Description_Key,
+				bindingService.getBestActiveBindingFormattedFor(adapter
+						.getCommandId())));
+
+		// Now return the field decoration
+		return dec;
+	}
+
+	/**
+	 * Return the ContentAssistCommandAdapter installed on the receiver. This
+	 * adapter is provided so that clients can configure the adapter if the
+	 * default values are not appropriate.
+	 *
+	 * @return the ContentAssistCommandAdapter installed on the field.
+	 */
+	public ContentAssistCommandAdapter getContentAssistCommandAdapter() {
+		return adapter;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/fieldassist/package.html b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/fieldassist/package.html
new file mode 100644
index 0000000..caa4bf8
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/fieldassist/package.html
@@ -0,0 +1,19 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <meta name="Author" content="IBM">
+   <meta name="GENERATOR" content="Mozilla/4.5 [en] (WinNT; I) [Netscape]">
+   <title>Package-level Javadoc</title>
+</head>
+<body>
+Classes that provide workbench-level UI support for content assistance 
+and common workbench field decorations.
+<h2>
+Package Specification</h2>
+This package provides workbench-level utilities that use the JFace-level
+field assist support.  It includes the WorkbenchContentAssistAdapter, which
+can invoke content assistance using a command and key binding rather than
+specifying the invocation explicitly with a KeyStroke.  
+</body>
+</html>
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/handlers/CollapseAllHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/handlers/CollapseAllHandler.java
new file mode 100644
index 0000000..23b1a7f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/handlers/CollapseAllHandler.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2015 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.ui.handlers;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+
+import org.eclipse.core.runtime.Assert;
+
+import org.eclipse.jface.viewers.AbstractTreeViewer;
+
+import org.eclipse.ui.IWorkbenchCommandConstants;
+
+/**
+ * Collapse a tree viewer.
+ * <p>
+ * It can be used in a part's createPartControl(Composite) method:
+ *
+ * <pre>
+ * IHandlerService handlerService = (IHandlerService) getSite().getService(
+ * 		IHandlerService.class);
+ * collapseHandler = new CollapseAllHandler(myViewer);
+ * handlerService.activateHandler(CollapseAllHandler.COMMAND_ID, collapseHandler);
+ * </pre>
+ *
+ * The part should dispose the handler in its own dispose() method. The part
+ * can provide its own collapse all handler if desired, or if it needs to
+ * delegate to multiple tree viewers.
+ * </p>
+ * <p>
+ * <b>Note</b>: This class can be instantiated. It should not be subclasses.
+ * </p>
+ *
+ * @since 3.4
+ */
+public class CollapseAllHandler extends AbstractHandler {
+	/**
+	 * The command id for collapse all.
+	 */
+	public static final String COMMAND_ID = IWorkbenchCommandConstants.NAVIGATE_COLLAPSE_ALL;
+
+	private AbstractTreeViewer treeViewer;
+
+	/**
+	 * Create the handler for this tree viewer.
+	 *
+	 * @param viewer
+	 *            The viewer to collapse. Must not be <code>null</code>.
+	 */
+	public CollapseAllHandler(AbstractTreeViewer viewer) {
+		Assert.isNotNull(viewer);
+		treeViewer = viewer;
+	}
+
+	@Override
+	public Object execute(ExecutionEvent event) {
+		treeViewer.collapseAll();
+		return null;
+	}
+
+	@Override
+	public void dispose() {
+		treeViewer = null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/handlers/ExpandAllHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/handlers/ExpandAllHandler.java
new file mode 100644
index 0000000..994c383
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/handlers/ExpandAllHandler.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2015 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
+ *
+ *     @author Prakash G. R.
+ ******************************************************************************/
+
+package org.eclipse.ui.handlers;
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.viewers.AbstractTreeViewer;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+
+/**
+ * Expand a tree viewer.
+ * <p>
+ * It can be used in a part's createPartControl(Composite) method:
+ *
+ * <pre>
+ * IHandlerService handlerService = (IHandlerService) getSite().getService(
+ * 		IHandlerService.class);
+ * expandHandler = new ExpandAllHandler(myViewer);
+ * handlerService.activateHandler(ExpandAllHandler.COMMAND_ID, expandHandler);
+ * </pre>
+ *
+ * The part should dispose the handler in its own dispose() method. The part can
+ * provide its own expand all handler if desired, or if it needs to delegate to
+ * multiple tree viewers.
+ * </p>
+ * <p>
+ * <b>Note</b>: This class can be instantiated. It should not be subclasses.
+ * </p>
+ *
+ * @since 3.6
+ */
+public class ExpandAllHandler extends AbstractHandler {
+	/**
+	 * The command id for collapse all.
+	 */
+	public static final String COMMAND_ID = IWorkbenchCommandConstants.NAVIGATE_EXPAND_ALL;
+
+	private AbstractTreeViewer treeViewer;
+
+	/**
+	 * Create the handler for this tree viewer.
+	 *
+	 * @param viewer
+	 *            The viewer to expand. Must not be <code>null</code>.
+	 */
+	public ExpandAllHandler(AbstractTreeViewer viewer) {
+		Assert.isNotNull(viewer);
+		treeViewer = viewer;
+	}
+
+	@Override
+	public Object execute(ExecutionEvent event) {
+		treeViewer.expandAll();
+		return null;
+	}
+
+	@Override
+	public void dispose() {
+		treeViewer = null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/handlers/HandlerUtil.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/handlers/HandlerUtil.java
new file mode 100644
index 0000000..3bbdd57
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/handlers/HandlerUtil.java
@@ -0,0 +1,724 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2016 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 420479
+ *******************************************************************************/
+
+package org.eclipse.ui.handlers;
+
+import java.util.Collection;
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.State;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchSite;
+import org.eclipse.ui.IWorkbenchWindow;
+
+/**
+ * Some common utilities for working with handlers in Platform UI.
+ * <p>
+ * <b>Note</b>: this class should not be instantiated or extended by clients.
+ * </p>
+ *
+ * @since 3.3
+ * @noextend This class is not intended to be subclassed by clients.
+ * @noinstantiate This class is not intended to be instantiated by clients.
+ */
+public class HandlerUtil {
+	private static void noVariableFound(ExecutionEvent event, String name)
+			throws ExecutionException {
+		throw new ExecutionException("No " + name //$NON-NLS-1$
+				+ " found while executing " + event.getCommand().getId()); //$NON-NLS-1$
+	}
+
+	private static void incorrectTypeFound(ExecutionEvent event, String name,
+			Class expectedType, Class wrongType) throws ExecutionException {
+		throw new ExecutionException("Incorrect type for " //$NON-NLS-1$
+				+ name
+				+ " found while executing " //$NON-NLS-1$
+				+ event.getCommand().getId()
+				+ ", expected " + expectedType.getName() //$NON-NLS-1$
+				+ " found " + wrongType.getName()); //$NON-NLS-1$
+	}
+
+	/**
+	 * Extract the variable.
+	 *
+	 * @param event
+	 *            The execution event that contains the application context
+	 * @param name
+	 *            The variable name to extract.
+	 * @return The object from the application context, or <code>null</code>
+	 *         if it could not be found.
+	 */
+	public static Object getVariable(ExecutionEvent event, String name) {
+		if (event.getApplicationContext() instanceof IEvaluationContext) {
+			Object var = ((IEvaluationContext) event.getApplicationContext()).getVariable(name);
+			return var == IEvaluationContext.UNDEFINED_VARIABLE ? null : var;
+		}
+		return null;
+	}
+
+	/**
+	 * Extract the variable.
+	 *
+	 * @param event
+	 *            The execution event that contains the application context
+	 * @param name
+	 *            The variable name to extract.
+	 * @return The object from the application context. Will not return
+	 *         <code>null</code>.
+	 * @throws ExecutionException
+	 *             if the variable is not found.
+	 */
+	public static Object getVariableChecked(ExecutionEvent event, String name)
+			throws ExecutionException {
+		Object o = getVariable(event, name);
+		if (o == null) {
+			noVariableFound(event, name);
+		}
+		return o;
+	}
+
+	/**
+	 * Extract the variable.
+	 *
+	 * @param context
+	 *            The IEvaluationContext or <code>null</code>
+	 * @param name
+	 *            The variable name to extract.
+	 * @return The object from the application context, or <code>null</code>
+	 *         if it could not be found.
+	 * @since 3.4
+	 */
+	public static Object getVariable(Object context, String name) {
+		if (context instanceof IEvaluationContext) {
+			Object var = ((IEvaluationContext) context).getVariable(name);
+			return var == IEvaluationContext.UNDEFINED_VARIABLE ? null : var;
+		}
+		return null;
+	}
+
+	/**
+	 * Return the active contexts.
+	 *
+	 * @param event
+	 *            The execution event that contains the application context
+	 * @return a collection of String contextIds, or <code>null</code>.
+	 */
+	public static Collection getActiveContexts(ExecutionEvent event) {
+		Object o = getVariable(event, ISources.ACTIVE_CONTEXT_NAME);
+		if (o instanceof Collection) {
+			return (Collection) o;
+		}
+		return null;
+	}
+
+	/**
+	 * Return the active contexts.
+	 *
+	 * @param event
+	 *            The execution event that contains the application context
+	 * @return a collection of String contextIds. Will not return
+	 *         <code>null</code>.
+	 * @throws ExecutionException
+	 *             If the context variable is not found.
+	 */
+	public static Collection getActiveContextsChecked(ExecutionEvent event)
+			throws ExecutionException {
+		Object o = getVariableChecked(event, ISources.ACTIVE_CONTEXT_NAME);
+		if (!(o instanceof Collection)) {
+			incorrectTypeFound(event, ISources.ACTIVE_CONTEXT_NAME,
+					Collection.class, o.getClass());
+		}
+		return (Collection) o;
+	}
+
+	/**
+	 * Return the active shell. Is not necessarily the active workbench window
+	 * shell.
+	 *
+	 * @param event
+	 *            The execution event that contains the application context
+	 * @return the active shell, or <code>null</code>.
+	 */
+	public static Shell getActiveShell(ExecutionEvent event) {
+		Object o = getVariable(event, ISources.ACTIVE_SHELL_NAME);
+		if (o instanceof Shell) {
+			return (Shell) o;
+		}
+		return null;
+	}
+
+	/**
+	 * Return the active shell. Is not necessarily the active workbench window
+	 * shell.
+	 *
+	 * @param event
+	 *            The execution event that contains the application context
+	 * @return the active shell. Will not return <code>null</code>.
+	 * @throws ExecutionException
+	 *             If the active shell variable is not found.
+	 */
+	public static Shell getActiveShellChecked(ExecutionEvent event)
+			throws ExecutionException {
+		Object o = getVariableChecked(event, ISources.ACTIVE_SHELL_NAME);
+		if (!(o instanceof Shell)) {
+			incorrectTypeFound(event, ISources.ACTIVE_SHELL_NAME, Shell.class, o.getClass());
+		}
+		return (Shell) o;
+	}
+
+	/**
+	 * Return the active workbench window.
+	 *
+	 * @param event
+	 *            The execution event that contains the application context
+	 * @return the active workbench window, or <code>null</code>.
+	 */
+	public static IWorkbenchWindow getActiveWorkbenchWindow(ExecutionEvent event) {
+		Object o = getVariable(event, ISources.ACTIVE_WORKBENCH_WINDOW_NAME);
+		if (o instanceof IWorkbenchWindow) {
+			return (IWorkbenchWindow) o;
+		}
+		return null;
+	}
+
+	/**
+	 * Return the active workbench window.
+	 *
+	 * @param event
+	 *            The execution event that contains the application context
+	 * @return the active workbench window. Will not return <code>null</code>.
+	 * @throws ExecutionException
+	 *             If the active workbench window variable is not found.
+	 */
+	public static IWorkbenchWindow getActiveWorkbenchWindowChecked(
+			ExecutionEvent event) throws ExecutionException {
+		Object o = getVariableChecked(event, ISources.ACTIVE_WORKBENCH_WINDOW_NAME);
+		if (!(o instanceof IWorkbenchWindow)) {
+			incorrectTypeFound(event, ISources.ACTIVE_WORKBENCH_WINDOW_NAME, IWorkbenchWindow.class, o.getClass());
+		}
+		return (IWorkbenchWindow) o;
+	}
+
+	/**
+	 * Return the active editor.
+	 *
+	 * @param event
+	 *            The execution event that contains the application context
+	 * @return the active editor, or <code>null</code>.
+	 */
+	public static IEditorPart getActiveEditor(ExecutionEvent event) {
+		Object o = getVariable(event, ISources.ACTIVE_EDITOR_NAME);
+		if (o instanceof IEditorPart) {
+			return (IEditorPart) o;
+		}
+		return null;
+	}
+
+	/**
+	 * Return the active editor.
+	 *
+	 * @param event
+	 *            The execution event that contains the application context
+	 * @return the active editor. Will not return <code>null</code>.
+	 * @throws ExecutionException
+	 *             If the active editor variable is not found.
+	 */
+	public static IEditorPart getActiveEditorChecked(ExecutionEvent event)
+			throws ExecutionException {
+		Object o = getVariableChecked(event, ISources.ACTIVE_EDITOR_NAME);
+		if (!(o instanceof IEditorPart)) {
+			incorrectTypeFound(event, ISources.ACTIVE_EDITOR_NAME, IEditorPart.class, o.getClass());
+		}
+		return (IEditorPart) o;
+	}
+
+	/**
+	 * Return the part id of the active editor.
+	 *
+	 * @param event
+	 *            The execution event that contains the application context
+	 * @return the part id of the active editor, or <code>null</code>.
+	 */
+	public static String getActiveEditorId(ExecutionEvent event) {
+		Object o = getVariable(event, ISources.ACTIVE_EDITOR_ID_NAME);
+		if (o instanceof String) {
+			return (String) o;
+		}
+		return null;
+	}
+
+	/**
+	 * Return the part id of the active editor.
+	 *
+	 * @param event
+	 *            The execution event that contains the application context
+	 * @return the part id of the active editor. Will not return
+	 *         <code>null</code>.
+	 * @throws ExecutionException
+	 *             If the active editor id variable is not found.
+	 */
+	public static String getActiveEditorIdChecked(ExecutionEvent event)
+			throws ExecutionException {
+		Object o = getVariableChecked(event, ISources.ACTIVE_EDITOR_ID_NAME);
+		if (!(o instanceof String)) {
+			incorrectTypeFound(event, ISources.ACTIVE_EDITOR_ID_NAME, String.class, o.getClass());
+		}
+		return (String) o;
+	}
+
+	/**
+	 * Return the input of the active editor.
+	 *
+	 * @param event
+	 *            The execution event that contains the application context
+	 * @return the input of the active editor, or <code>null</code>.
+	 * @since 3.7
+	 */
+	public static IEditorInput getActiveEditorInput(ExecutionEvent event) {
+		Object o = getVariable(event, ISources.ACTIVE_EDITOR_INPUT_NAME);
+		if (o instanceof IEditorInput) {
+			return (IEditorInput) o;
+		}
+		return null;
+	}
+
+	/**
+	 * Return the input of the active editor.
+	 *
+	 * @param event
+	 *            The execution event that contains the application context
+	 * @return the input of the active editor. Will not return <code>null</code>
+	 *         .
+	 * @throws ExecutionException
+	 *             If the active editor input variable is not found.
+	 * @since 3.7
+	 */
+	public static IEditorInput getActiveEditorInputChecked(ExecutionEvent event)
+			throws ExecutionException {
+		Object o = getVariableChecked(event, ISources.ACTIVE_EDITOR_INPUT_NAME);
+		if (!(o instanceof IEditorInput)) {
+			incorrectTypeFound(event, ISources.ACTIVE_EDITOR_INPUT_NAME, IEditorInput.class, o.getClass());
+		}
+		return (IEditorInput) o;
+	}
+
+	/**
+	 * Return the active part.
+	 *
+	 * @param event
+	 *            The execution event that contains the application context
+	 * @return the active part, or <code>null</code>.
+	 */
+	public static IWorkbenchPart getActivePart(ExecutionEvent event) {
+		Object o = getVariable(event, ISources.ACTIVE_PART_NAME);
+		if (o instanceof IWorkbenchPart) {
+			return (IWorkbenchPart) o;
+		}
+		return null;
+	}
+
+	/**
+	 * Return the active part.
+	 *
+	 * @param event
+	 *            The execution event that contains the application context
+	 * @return the active part. Will not return <code>null</code>.
+	 * @throws ExecutionException
+	 *             If the active part variable is not found.
+	 */
+	public static IWorkbenchPart getActivePartChecked(ExecutionEvent event)
+			throws ExecutionException {
+		Object o = getVariableChecked(event, ISources.ACTIVE_PART_NAME);
+		if (!(o instanceof IWorkbenchPart)) {
+			incorrectTypeFound(event, ISources.ACTIVE_PART_NAME, IWorkbenchPart.class, o.getClass());
+		}
+		return (IWorkbenchPart) o;
+	}
+
+	/**
+	 * Return the part id of the active part.
+	 *
+	 * @param event
+	 *            The execution event that contains the application context
+	 * @return the part id of the active part, or <code>null</code>.
+	 */
+	public static String getActivePartId(ExecutionEvent event) {
+		Object o = getVariable(event, ISources.ACTIVE_PART_ID_NAME);
+		if (o instanceof String) {
+			return (String) o;
+		}
+		return null;
+	}
+
+	/**
+	 * Return the part id of the active part.
+	 *
+	 * @param event
+	 *            The execution event that contains the application context
+	 * @return the part id of the active part. Will not return <code>null</code>.
+	 * @throws ExecutionException
+	 *             If the active part id variable is not found.
+	 */
+	public static String getActivePartIdChecked(ExecutionEvent event)
+			throws ExecutionException {
+		Object o = getVariableChecked(event, ISources.ACTIVE_PART_ID_NAME);
+		if (!(o instanceof String)) {
+			incorrectTypeFound(event, ISources.ACTIVE_PART_ID_NAME, String.class, o.getClass());
+		}
+		return (String) o;
+	}
+
+	/**
+	 * Return the active part site.
+	 *
+	 * @param event
+	 *            The execution event that contains the application context
+	 * @return the active part site, or <code>null</code>.
+	 */
+	public static IWorkbenchSite getActiveSite(ExecutionEvent event) {
+		Object o = getVariable(event, ISources.ACTIVE_SITE_NAME);
+		if (o instanceof IWorkbenchSite) {
+			return (IWorkbenchSite) o;
+		}
+		return null;
+	}
+
+	/**
+	 * Return the active part site.
+	 *
+	 * @param event
+	 *            The execution event that contains the application context
+	 * @return the active part site. Will not return <code>null</code>.
+	 * @throws ExecutionException
+	 *             If the active part site variable is not found.
+	 */
+	public static IWorkbenchSite getActiveSiteChecked(ExecutionEvent event)
+			throws ExecutionException {
+		Object o = getVariableChecked(event, ISources.ACTIVE_SITE_NAME);
+		if (!(o instanceof IWorkbenchSite)) {
+			incorrectTypeFound(event, ISources.ACTIVE_SITE_NAME, IWorkbenchSite.class, o.getClass());
+		}
+		return (IWorkbenchSite) o;
+	}
+
+	/**
+	 * Return the current selection.
+	 *
+	 * @param event
+	 *            The execution event that contains the application context
+	 * @return the current selection, or <code>null</code>.
+	 */
+	public static ISelection getCurrentSelection(ExecutionEvent event) {
+		Object o = getVariable(event, ISources.ACTIVE_CURRENT_SELECTION_NAME);
+		if (o instanceof ISelection) {
+			return (ISelection) o;
+		}
+		return null;
+	}
+
+	/**
+	 * Return the current structured selection, or <code>StructuredSelection.EMPTY</code>
+	 * if the current selection is not a structured selection or <code>null</code>.
+	 *
+	 * @param event
+	 *            The execution event that contains the application context
+	 * @return the current IStructuredSelection, or
+	 *         <code>StructuredSelection.EMPTY</code>.
+	 * @since 3.108
+	 *
+	 */
+	public static IStructuredSelection getCurrentStructuredSelection(ExecutionEvent event) {
+		ISelection selection = getCurrentSelection(event);
+		if (selection instanceof IStructuredSelection) {
+			return (IStructuredSelection) selection;
+		}
+		return StructuredSelection.EMPTY;
+	}
+
+	/**
+	 * Return the current selection.
+	 *
+	 * @param event
+	 *            The execution event that contains the application context
+	 * @return the current selection. Will not return <code>null</code>.
+	 * @throws ExecutionException
+	 *             If the current selection variable is not found.
+	 */
+	public static ISelection getCurrentSelectionChecked(ExecutionEvent event)
+			throws ExecutionException {
+		Object o = getVariableChecked(event,
+				ISources.ACTIVE_CURRENT_SELECTION_NAME);
+		if (!(o instanceof ISelection)) {
+			incorrectTypeFound(event, ISources.ACTIVE_CURRENT_SELECTION_NAME, ISelection.class, o.getClass());
+		}
+		return (ISelection) o;
+	}
+
+	/**
+	 * Return the menu IDs that were applied to the registered context menu. For
+	 * example, #CompilationUnitEditorContext.
+	 *
+	 * @param event
+	 *            The execution event that contains the application context
+	 * @return the menu IDs, or <code>null</code>.
+	 */
+	public static Collection getActiveMenus(ExecutionEvent event) {
+		Object o = getVariable(event, ISources.ACTIVE_MENU_NAME);
+		if (o instanceof Collection) {
+			return (Collection) o;
+		}
+		return null;
+	}
+
+	/**
+	 * Return the menu IDs that were applied to the registered context menu. For
+	 * example, #CompilationUnitEditorContext.
+	 *
+	 * @param event
+	 *            The execution event that contains the application context
+	 * @return the menu IDs. Will not return <code>null</code>.
+	 * @throws ExecutionException
+	 *             If the active menus variable is not found.
+	 */
+	public static Collection getActiveMenusChecked(ExecutionEvent event)
+			throws ExecutionException {
+		Object o = getVariableChecked(event, ISources.ACTIVE_MENU_NAME);
+		if (!(o instanceof Collection)) {
+			incorrectTypeFound(event, ISources.ACTIVE_MENU_NAME, Collection.class, o.getClass());
+		}
+		return (Collection) o;
+	}
+
+	/**
+	 * Return the active menu selection. The active menu is a registered context
+	 * menu.
+	 *
+	 * @param event
+	 *            The execution event that contains the application context
+	 * @return the active menu selection, or <code>null</code>.
+	 */
+	public static ISelection getActiveMenuSelection(ExecutionEvent event) {
+		Object o = getVariable(event, ISources.ACTIVE_MENU_SELECTION_NAME);
+		if (o instanceof ISelection) {
+			return (ISelection) o;
+		}
+		return null;
+	}
+
+	/**
+	 * Return the active menu selection. The active menu is a registered context
+	 * menu.
+	 *
+	 * @param event
+	 *            The execution event that contains the application context
+	 * @return the active menu selection. Will not return <code>null</code>.
+	 * @throws ExecutionException
+	 *             If the active menu selection variable is not found.
+	 */
+	public static ISelection getActiveMenuSelectionChecked(ExecutionEvent event)
+			throws ExecutionException {
+		Object o = getVariableChecked(event,
+				ISources.ACTIVE_MENU_SELECTION_NAME);
+		if (!(o instanceof ISelection)) {
+			incorrectTypeFound(event, ISources.ACTIVE_MENU_SELECTION_NAME, ISelection.class, o.getClass());
+		}
+		return (ISelection) o;
+	}
+
+	/**
+	 * Return the active menu editor input, if available. The active menu is a
+	 * registered context menu.
+	 *
+	 * @param event
+	 *            The execution event that contains the application context
+	 * @return the active menu editor, or <code>null</code>.
+	 */
+	public static ISelection getActiveMenuEditorInput(ExecutionEvent event) {
+		Object o = getVariable(event, ISources.ACTIVE_MENU_EDITOR_INPUT_NAME);
+		if (o instanceof ISelection) {
+			return (ISelection) o;
+		}
+		return null;
+	}
+
+	/**
+	 * Return the active menu editor input. The active menu is a registered
+	 * context menu. Some context menus do not include the editor input which
+	 * will throw an exception.
+	 *
+	 * @param event
+	 *            The execution event that contains the application context
+	 * @return the active menu editor input. Will not return <code>null</code>.
+	 * @throws ExecutionException
+	 *             If the active menu editor input variable is not found.
+	 */
+	public static ISelection getActiveMenuEditorInputChecked(
+			ExecutionEvent event) throws ExecutionException {
+		Object o = getVariableChecked(event,
+				ISources.ACTIVE_MENU_EDITOR_INPUT_NAME);
+		if (!(o instanceof ISelection)) {
+			incorrectTypeFound(event, ISources.ACTIVE_MENU_EDITOR_INPUT_NAME, ISelection.class, o.getClass());
+		}
+		return (ISelection) o;
+	}
+
+	/**
+	 * Return the ShowInContext selection.
+	 *
+	 * @param event
+	 *            The execution event that contains the application context
+	 * @return the show in selection, or <code>null</code>.
+	 * @since 3.4
+	 */
+	public static ISelection getShowInSelection(ExecutionEvent event) {
+		Object o = getVariable(event, ISources.SHOW_IN_SELECTION);
+		if (o instanceof ISelection) {
+			return (ISelection) o;
+		}
+		return null;
+	}
+
+	/**
+	 * Return the ShowInContext selection. Will not return <code>null</code>.
+	 *
+	 * @param event
+	 *            The execution event that contains the application context
+	 * @return the show in selection, or <code>null</code>.
+	 * @throws ExecutionException
+	 *             If the show in selection variable is not found.
+	 * @since 3.4
+	 */
+	public static ISelection getShowInSelectionChecked(ExecutionEvent event)
+			throws ExecutionException {
+		Object o = getVariableChecked(event, ISources.SHOW_IN_SELECTION);
+		if (!(o instanceof ISelection)) {
+			incorrectTypeFound(event, ISources.SHOW_IN_SELECTION,
+					ISelection.class, o.getClass());
+		}
+		return (ISelection) o;
+	}
+
+	/**
+	 * Return the ShowInContext input.
+	 *
+	 * @param event
+	 *            The execution event that contains the application context
+	 * @return the show in input, or <code>null</code>.
+	 * @since 3.4
+	 */
+	public static Object getShowInInput(ExecutionEvent event) {
+		Object var = getVariable(event, ISources.SHOW_IN_INPUT);
+		return var;
+	}
+
+	/**
+	 * Return the ShowInContext input. Will not return <code>null</code>.
+	 *
+	 * @param event
+	 *            The execution event that contains the application context
+	 * @return the show in input, or <code>null</code>.
+	 * @throws ExecutionException
+	 *             If the show in input variable is not found.
+	 * @since 3.4
+	 */
+	public static Object getShowInInputChecked(ExecutionEvent event)
+			throws ExecutionException {
+		Object var = getVariableChecked(event, ISources.SHOW_IN_INPUT);
+		return var;
+	}
+
+	/**
+	 * Toggles the command's state.
+	 *
+	 * @param command The command whose state needs to be toggled
+	 * @return the original value before toggling
+	 *
+	 * @throws ExecutionException
+	 * 	When the command doesn't contain the toggle state or when the state doesn't contain a boolean value
+	 *
+	 * @since 3.5
+	 */
+	public static boolean toggleCommandState(Command command) throws ExecutionException {
+		State state = command.getState(RegistryToggleState.STATE_ID);
+		if(state == null)
+			throw new ExecutionException("The command does not have a toggle state"); //$NON-NLS-1$
+		 if(!(state.getValue() instanceof Boolean))
+			throw new ExecutionException("The command's toggle state doesn't contain a boolean value"); //$NON-NLS-1$
+
+		boolean oldValue = ((Boolean) state.getValue()).booleanValue();
+		state.setValue(Boolean.valueOf(!oldValue));
+		return oldValue;
+	}
+
+	/**
+	 * Checks whether the radio state of the command is same as the radio state
+	 * parameter's value
+	 *
+	 * @param event
+	 *            The execution event that contains the application context
+	 * @return <code>true</code> whe the values are same, <code>false</code>
+	 *         otherwise
+	 *
+	 * @throws ExecutionException
+	 *             When the command doesn't have the radio state or the event
+	 *             doesn't have the radio state parameter
+	 * @since 3.5
+	 */
+	public static boolean matchesRadioState(ExecutionEvent event)
+			throws ExecutionException {
+
+		String parameter = event.getParameter(RadioState.PARAMETER_ID);
+		if (parameter == null)
+			throw new ExecutionException(
+					"The event does not have the radio state parameter"); //$NON-NLS-1$
+
+		Command command = event.getCommand();
+		State state = command.getState(RadioState.STATE_ID);
+		if (state == null)
+			throw new ExecutionException("The command does not have a radio state"); //$NON-NLS-1$
+		if (!(state.getValue() instanceof String))
+			throw new ExecutionException("The command's radio state doesn't contain a String value"); //$NON-NLS-1$
+
+		return parameter.equals(state.getValue());
+	}
+
+	/**
+	 * Updates the radio state of the command to the given value
+	 *
+	 * @param command
+	 *            the command whose state should be updated
+	 * @param newState
+	 *            the new state
+	 *
+	 * @throws ExecutionException
+	 *             When the command doesn't have a radio state
+	 * @since 3.5
+	 */
+	public static void updateRadioState(Command command, String newState)
+			throws ExecutionException {
+
+		State state = command.getState(RadioState.STATE_ID);
+		if (state == null)
+			throw new ExecutionException("The command does not have a radio state"); //$NON-NLS-1$
+		state.setValue(newState);
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/handlers/IHandlerActivation.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/handlers/IHandlerActivation.java
new file mode 100644
index 0000000..5a04ad2
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/handlers/IHandlerActivation.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.handlers;
+
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.ui.internal.services.IEvaluationResultCache;
+
+/**
+ * <p>
+ * A token representing the activation of a handler. This token can later be
+ * used to cancel that activation. Without this token, then handler will only
+ * become inactive if the component in which the handler was activated is
+ * destroyed.
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented or extended by clients.
+ * </p>
+ *
+ * @since 3.1
+ * @see org.eclipse.ui.ISources
+ * @see org.eclipse.ui.ISourceProvider
+ */
+public interface IHandlerActivation extends IEvaluationResultCache, Comparable {
+
+	/**
+	 * The depth at which the root exists.
+	 *
+	 * @since 3.2
+	 */
+	public static final int ROOT_DEPTH = 1;
+
+	/**
+	 * Clears the cached computation of the <code>isActive</code> method, if
+	 * any. This method is only intended for internal use. It provides a
+	 * mechanism by which <code>ISourceProvider</code> events can invalidate
+	 * state on a <code>IHandlerActivation</code> instance.
+	 *
+	 * @deprecated Use {@link IEvaluationResultCache#clearResult()} instead.
+	 */
+	@Deprecated
+	public void clearActive();
+
+	/**
+	 * Returns the identifier of the command whose handler is being activated.
+	 *
+	 * @return The command identifier; never <code>null</code>.
+	 */
+	public String getCommandId();
+
+	/**
+	 * Returns the depth at which this activation was created within the
+	 * services hierarchy. The root of the hierarchy is at a depth of
+	 * <code>1</code>. This is used as the final tie-breaker in the event
+	 * that no other method can be used to determine a winner.
+	 *
+	 * @return The depth at which the handler was inserted into the services
+	 *         hierarchy; should be a positive integer.
+	 * @since 3.2
+	 */
+	public int getDepth();
+
+	/**
+	 * Returns the handler that should be activated.
+	 *
+	 * @return The handler; may be <code>null</code>.
+	 */
+	public IHandler getHandler();
+
+	/**
+	 * Returns the handler service from which this activation was requested.
+	 * This is used to ensure that an activation can only be retracted from the
+	 * same service which issued it.
+	 *
+	 * @return The handler service; never <code>null</code>.
+	 */
+	public IHandlerService getHandlerService();
+
+	/**
+	 * Returns whether this handler activation is currently active -- given the
+	 * current state of the workbench. This method should cache its computation.
+	 * The cache will be cleared by a call to <code>clearActive</code>.
+	 *
+	 * @param context
+	 *            The context in which this state should be evaluated; must not
+	 *            be <code>null</code>.
+	 * @return <code>true</code> if the activation is currently active;
+	 *         <code>false</code> otherwise.
+	 * @deprecated Use
+	 *             {@link IEvaluationResultCache#evaluate(IEvaluationContext)}
+	 *             instead.
+	 */
+	@Deprecated
+	public boolean isActive(IEvaluationContext context);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/handlers/IHandlerService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/handlers/IHandlerService.java
new file mode 100644
index 0000000..eb629df
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/handlers/IHandlerService.java
@@ -0,0 +1,408 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.handlers;
+
+import java.util.Collection;
+
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.core.commands.IHandler2;
+import org.eclipse.core.commands.NotEnabledException;
+import org.eclipse.core.commands.NotHandledException;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.ui.services.IServiceWithSources;
+
+/**
+ * <p>
+ * Provides services related to activating and deactivating handlers within the
+ * workbench.
+ * </p>
+ * <p>
+ * This service can be acquired from your service locator:
+ * <pre>
+ * 	IHandlerService service = (IHandlerService) getSite().getService(IHandlerService.class);
+ * </pre>
+ * <ul>
+ * <li>This service is available globally.</li>
+ * </ul>
+ * </p>
+
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noextend This interface is not intended to be extended by clients.
+ *
+ * @since 3.1
+ */
+public interface IHandlerService extends IServiceWithSources {
+
+	/**
+	 * <p>
+	 * Activates the given handler from a child service. This is used by slave
+	 * and nested services to promote handler activations up to the root. By
+	 * using this method, it is possible for handlers coming from a more nested
+	 * component to override the nested component.
+	 * </p>
+	 *
+	 * @param activation
+	 *            The activation that is local to the child service; must not be
+	 *            <code>null</code>.
+	 * @return A token which can be used to later cancel the activation. Only
+	 *         someone with access to this token can cancel the activation. The
+	 *         activation will automatically be cancelled if the service locator
+	 *         context from which this service was retrieved is destroyed. This
+	 *         activation is local to this service (i.e., it is not the
+	 *         activation that is passed as a parameter).
+	 * @since 3.2
+	 */
+	public IHandlerActivation activateHandler(IHandlerActivation activation);
+
+	/**
+	 * <p>
+	 * Activates the given handler within the context of this service. If this
+	 * service was retrieved from the workbench, then this handler will be
+	 * active globally. If the service was retrieved from a nested component,
+	 * then the handler will only be active within that component.
+	 * </p>
+	 * <p>
+	 * Also, it is guaranteed that the handlers submitted through a particular
+	 * service will be cleaned up when that services is destroyed. So, for
+	 * example, a service retrieved from a <code>IWorkbenchPartSite</code>
+	 * would deactivate all of its handlers when the site is destroyed.
+	 * </p>
+	 *
+	 * @param commandId
+	 *            The identifier for the command which this handler handles;
+	 *            must not be <code>null</code>.
+	 * @param handler
+	 *            The handler to activate; must not be <code>null</code>.
+	 * @return A token which can be used to later cancel the activation. Only
+	 *         someone with access to this token can cancel the activation. The
+	 *         activation will automatically be cancelled if the context from
+	 *         which this service was retrieved is destroyed.
+	 */
+	public IHandlerActivation activateHandler(String commandId, IHandler handler);
+
+	/**
+	 * <p>
+	 * Activates the given handler within the context of this service. The
+	 * handler becomes active when <code>expression</code> evaluates to
+	 * <code>true</code>. This is the same as calling
+	 * {@link #activateHandler(String, IHandler, Expression, boolean)} with
+	 * global==false.
+	 * </p>
+	 * <p>
+	 * Also, it is guaranteed that the handlers submitted through a particular
+	 * service will be cleaned up when that service is destroyed. So, for
+	 * example, a service retrieved from a <code>IWorkbenchPartSite</code>
+	 * would deactivate all of its handlers when the site is destroyed.
+	 * </p>
+	 *
+	 * @param commandId
+	 *            The identifier for the command which this handler handles;
+	 *            must not be <code>null</code>.
+	 * @param handler
+	 *            The handler to activate; must not be <code>null</code>.
+	 * @param expression
+	 *            This expression must evaluate to <code>true</code> before
+	 *            this handler will really become active. The expression may be
+	 *            <code>null</code> if the handler should always be active.
+	 * @return A token which can be used to later cancel the activation. Only
+	 *         someone with access to this token can cancel the activation. The
+	 *         activation will automatically be cancelled if the context from
+	 *         which this service was retrieved is destroyed.
+	 *
+	 * @see org.eclipse.ui.ISources
+	 * @since 3.2
+	 */
+	public IHandlerActivation activateHandler(String commandId,
+			IHandler handler, Expression expression);
+
+	/**
+	 * <p>
+	 * Activates the given handler within the context of this service. The
+	 * handler becomes active when <code>expression</code> evaluates to
+	 * <code>true</code>. if global==<code>false</code>, then this
+	 * handler service must also be the active service to active the handler.
+	 * For example, the handler service on a part is active when that part is
+	 * active.
+	 * </p>
+	 * <p>
+	 * Also, it is guaranteed that the handlers submitted through a particular
+	 * service will be cleaned up when that services is destroyed. So, for
+	 * example, a service retrieved from a <code>IWorkbenchPartSite</code>
+	 * would deactivate all of its handlers when the site is destroyed.
+	 * </p>
+	 *
+	 * @param commandId
+	 *            The identifier for the command which this handler handles;
+	 *            must not be <code>null</code>.
+	 * @param handler
+	 *            The handler to activate; must not be <code>null</code>.
+	 * @param expression
+	 *            This expression must evaluate to <code>true</code> before
+	 *            this handler will really become active. The expression may be
+	 *            <code>null</code> if the handler should always be active.
+	 * @param global
+	 *            Indicates that the handler should be activated irrespectively
+	 *            of whether the corresponding workbench component (e.g.,
+	 *            window, part, etc.) is active.
+	 * @return A token which can be used to later cancel the activation. Only
+	 *         someone with access to this token can cancel the activation. The
+	 *         activation will automatically be cancelled if the context from
+	 *         which this service was retrieved is destroyed.
+	 *
+	 * @see org.eclipse.ui.ISources
+	 * @since 3.2
+	 */
+	public IHandlerActivation activateHandler(String commandId,
+			IHandler handler, Expression expression, boolean global);
+
+	/**
+	 * <p>
+	 * Activates the given handler within the context of this service. The
+	 * handler becomes active when <code>expression</code> evaluates to
+	 * <code>true</code>.
+	 * </p>
+	 * <p>
+	 * Also, it is guaranteed that the handlers submitted through a particular
+	 * service will be cleaned up when that services is destroyed. So, for
+	 * example, a service retrieved from a <code>IWorkbenchPartSite</code>
+	 * would deactivate all of its handlers when the site is destroyed.
+	 * </p>
+	 *
+	 * @param commandId
+	 *            The identifier for the command which this handler handles;
+	 *            must not be <code>null</code>.
+	 * @param handler
+	 *            The handler to activate; must not be <code>null</code>.
+	 * @param expression
+	 *            This expression must evaluate to <code>true</code> before
+	 *            this handler will really become active. The expression may be
+	 *            <code>null</code> if the handler should always be active.
+	 * @param sourcePriorities
+	 *            The source priorities for the expression.
+	 * @return A token which can be used to later cancel the activation. Only
+	 *         someone with access to this token can cancel the activation. The
+	 *         activation will automatically be cancelled if the context from
+	 *         which this service was retrieved is destroyed.
+	 *
+	 * @see org.eclipse.ui.ISources
+	 * @deprecated Use
+	 *             {@link IHandlerService#activateHandler(String, IHandler, Expression)}
+	 *             instead.
+	 */
+	@Deprecated
+	public IHandlerActivation activateHandler(String commandId,
+			IHandler handler, Expression expression, int sourcePriorities);
+
+	/**
+	 * Creates an execution event based on an SWT event. This execution event
+	 * can then be passed to a command for execution.
+	 *
+	 * @param command
+	 *            The command for which an execution event should be created;
+	 *            must not be <code>null</code>.
+	 * @param event
+	 *            The SWT event triggering the command execution; may be
+	 *            <code>null</code>.
+	 * @return An execution event suitable for calling
+	 *         {@link Command#executeWithChecks(ExecutionEvent)}.
+	 * @since 3.2
+	 * @see Command#executeWithChecks(ExecutionEvent)
+	 */
+	public ExecutionEvent createExecutionEvent(Command command, Event event);
+
+	/**
+	 * Creates a parameterized execution event based on an SWT event and a
+	 * parameterized command. This execution event can then be passed to a
+	 * command for execution.
+	 *
+	 * @param command
+	 *            The parameterized command for which an execution event should
+	 *            be created; must not be <code>null</code>.
+	 * @param event
+	 *            The SWT event triggering the command execution; may be
+	 *            <code>null</code>.
+	 * @return An execution event suitable for calling
+	 *         {@link Command#executeWithChecks(ExecutionEvent)}.
+	 * @since 3.2
+	 * @see ParameterizedCommand#getCommand()
+	 * @see Command#executeWithChecks(ExecutionEvent)
+	 */
+	public ExecutionEvent createExecutionEvent(ParameterizedCommand command,
+			Event event);
+
+	/**
+	 * Deactivates the given handler within the context of this service. If the
+	 * handler was activated with a different service, then it must be
+	 * deactivated from that service instead. It is only possible to retract a
+	 * handler activation with this method. That is, you must have the same
+	 * <code>IHandlerActivation</code> used to activate the handler.
+	 *
+	 * @param activation
+	 *            The token that was returned from a call to
+	 *            <code>activateHandler</code>; must not be <code>null</code>.
+	 */
+	public void deactivateHandler(IHandlerActivation activation);
+
+	/**
+	 * Deactivates the given handlers within the context of this service. If the
+	 * handler was activated with a different service, then it must be
+	 * deactivated from that service instead. It is only possible to retract a
+	 * handler activation with this method. That is, you must have the same
+	 * <code>IHandlerActivation</code> used to activate the handler.
+	 *
+	 * @param activations
+	 *            The tokens that were returned from a call to
+	 *            <code>activateHandler</code>. This collection must only
+	 *            contain instances of <code>IHandlerActivation</code>. The
+	 *            collection must not be <code>null</code>.
+	 */
+	public void deactivateHandlers(Collection activations);
+
+	/**
+	 * Executes the command with the given identifier and no parameters.
+	 *
+	 * @param commandId
+	 *            The identifier of the command to execute; must not be
+	 *            <code>null</code>.
+	 * @param event
+	 *            The SWT event triggering the command execution; may be
+	 *            <code>null</code>.
+	 * @return The return value from the execution; may be <code>null</code>.
+	 * @throws ExecutionException
+	 *             If the handler has problems executing this command.
+	 * @throws NotDefinedException
+	 *             If the command you are trying to execute is not defined.
+	 * @throws NotEnabledException
+	 *             If the command you are trying to execute is not enabled.
+	 * @throws NotHandledException
+	 *             If there is no handler.
+	 * @since 3.2
+	 * @see Command#executeWithChecks(ExecutionEvent)
+	 */
+	public Object executeCommand(String commandId, Event event)
+			throws ExecutionException, NotDefinedException,
+			NotEnabledException, NotHandledException;
+
+	/**
+	 * Executes the given parameterized command.
+	 *
+	 * @param command
+	 *            The parameterized command to be executed; must not be
+	 *            <code>null</code>.
+	 * @param event
+	 *            The SWT event triggering the command execution; may be
+	 *            <code>null</code>.
+	 * @return The return value from the execution; may be <code>null</code>.
+	 * @throws ExecutionException
+	 *             If the handler has problems executing this command.
+	 * @throws NotDefinedException
+	 *             If the command you are trying to execute is not defined.
+	 * @throws NotEnabledException
+	 *             If the command you are trying to execute is not enabled.
+	 * @throws NotHandledException
+	 *             If there is no handler.
+	 * @since 3.2
+	 * @see Command#executeWithChecks(ExecutionEvent)
+	 */
+	public Object executeCommand(ParameterizedCommand command, Event event)
+			throws ExecutionException, NotDefinedException,
+			NotEnabledException, NotHandledException;
+
+	/**
+	 * Executes the given parameterized command in the provided context. It
+	 * takes care of finding the correct active handler given the context, calls
+	 * {@link IHandler2#setEnabled(Object)} to update the enabled state if
+	 * supported, and executes with that handler.
+	 *
+	 * @param command
+	 *            The parameterized command to be executed; must not be
+	 *            <code>null</code>.
+	 * @param event
+	 *            The SWT event triggering the command execution; may be
+	 *            <code>null</code>.
+	 * @param context
+	 *            the evaluation context to run against. Must not be
+	 *            <code>null</code>
+	 * @return The return value from the execution; may be <code>null</code>.
+	 * @throws ExecutionException
+	 *             If the handler has problems executing this command.
+	 * @throws NotDefinedException
+	 *             If the command you are trying to execute is not defined.
+	 * @throws NotEnabledException
+	 *             If the command you are trying to execute is not enabled.
+	 * @throws NotHandledException
+	 *             If there is no handler.
+	 * @since 3.4
+	 * @see Command#executeWithChecks(ExecutionEvent)
+	 * @see #createContextSnapshot(boolean)
+	 */
+	public Object executeCommandInContext(ParameterizedCommand command,
+			Event event, IEvaluationContext context) throws ExecutionException,
+			NotDefinedException, NotEnabledException, NotHandledException;
+
+	/**
+	 * This method creates a copy of the application context returned by
+	 * {@link #getCurrentState()}.
+	 *
+	 * @param includeSelection
+	 *            if <code>true</code>, include the default variable and
+	 *            selection variables
+	 * @return an context filled with the current set of variables. If selection
+	 *         is not included, the default variable is an empty collection
+	 * @since 3.4
+	 */
+	public IEvaluationContext createContextSnapshot(boolean includeSelection);
+
+	/**
+	 * Returns an evaluation context representing the current state of the
+	 * world. This is equivalent to the application context required by
+	 * {@link ExecutionEvent}.
+	 *
+	 * @return the current state of the application; never <code>null</code>.
+	 * @see ParameterizedCommand#executeWithChecks(Object, Object)
+	 * @see ExecutionEvent#ExecutionEvent(Command, java.util.Map, Object,
+	 *      Object)
+	 * @see org.eclipse.ui.services.IEvaluationService
+	 */
+	public IEvaluationContext getCurrentState();
+
+	/**
+	 * <p>
+	 * Reads the handler information from the registry. This will overwrite any
+	 * of the existing information in the handler service. This method is
+	 * intended to be called during start-up. When this method completes, this
+	 * handler service will reflect the current state of the registry.
+	 * </p>
+	 */
+	public void readRegistry();
+
+	/**
+	 * Sets the help context identifier to associate with a particular handler.
+	 *
+	 * @param handler
+	 *            The handler with which to register a help context identifier;
+	 *            must not be <code>null</code>.
+	 * @param helpContextId
+	 *            The help context identifier to register; may be
+	 *            <code>null</code> if the help context identifier should be
+	 *            removed.
+	 * @since 3.2
+	 */
+	public void setHelpContextId(IHandler handler, String helpContextId);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/handlers/RadioState.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/handlers/RadioState.java
new file mode 100644
index 0000000..973306e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/handlers/RadioState.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2015 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.ui.handlers;
+
+import java.util.Hashtable;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExecutableExtension;
+import org.eclipse.jface.commands.PersistentState;
+import org.eclipse.jface.preference.IPreferenceStore;
+
+/**
+ * This state supports a radio-button like command, where the value of the
+ * parameterized command is stored as state. The command must define a state
+ * using the {@link #STATE_ID} id and a string commandParameter using the
+ * {@link #PARAMETER_ID} id. Menu contributions supplied by
+ * <code>org.eclipse.ui.menus</code> can then set the {@link #PARAMETER_ID}.
+ * <p>
+ * When parsing from the registry, this state understands two parameters:
+ * <code>default</code>, which is the default value for this item; and
+ * <code>persisted</code>, which is whether the state should be persisted
+ * between sessions. The <code>default</code> parameter has no default value and
+ * must be specified in one of its forms, and the <code>persisted</code>
+ * parameter defaults to <code>true</code>. If only one parameter is passed
+ * (i.e., using the class name followed by a colon), then it is assumed to be
+ * the <code>default</code> parameter.
+ * </p>
+ *
+ * @see HandlerUtil#updateRadioState(org.eclipse.core.commands.Command, String)
+ * @see HandlerUtil#matchesRadioState(org.eclipse.core.commands.ExecutionEvent)
+ * @since 3.5
+ */
+public final class RadioState extends PersistentState implements
+		IExecutableExtension {
+
+	/**
+	 * The state ID for a radio state understood by the system.
+	 */
+	public final static String STATE_ID = "org.eclipse.ui.commands.radioState"; //$NON-NLS-1$
+
+	/**
+	 * The parameter ID for a radio state understood by the system.
+	 */
+	public final static String PARAMETER_ID = "org.eclipse.ui.commands.radioStateParameter"; //$NON-NLS-1$
+
+	public RadioState() {
+		setShouldPersist(true);
+	}
+
+	@Override
+	public void setInitializationData(IConfigurationElement config,
+			String propertyName, Object data) {
+
+		boolean shouldPersist = true; // persist by default
+		if (data instanceof String) {
+			setValue(data);
+		} else if (data instanceof Hashtable) {
+			final Hashtable parameters = (Hashtable) data;
+			final Object defaultObject = parameters.get("default"); //$NON-NLS-1$
+			if (defaultObject instanceof String) {
+				setValue(defaultObject);
+			}
+
+			final Object persistedObject = parameters.get("persisted"); //$NON-NLS-1$
+			if (persistedObject instanceof String
+					&& "false".equalsIgnoreCase(((String) persistedObject))) //$NON-NLS-1$
+				shouldPersist = false;
+		}
+		setShouldPersist(shouldPersist);
+
+	}
+
+	@Override
+	public void load(IPreferenceStore store, String preferenceKey) {
+		if (!shouldPersist())
+			return;
+		final String value = store.getString(preferenceKey);
+		if (value.length() != 0)
+			setValue(value);
+	}
+
+	@Override
+	public void save(IPreferenceStore store, String preferenceKey) {
+		if (!shouldPersist())
+			return;
+		final Object value = getValue();
+		if (value instanceof String) {
+			store.setValue(preferenceKey, (String) value);
+		}
+	}
+
+	@Override
+	public void setValue(Object value) {
+		if (!(value instanceof String))
+			return; // we set only String values
+		super.setValue(value);
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/handlers/RegistryRadioState.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/handlers/RegistryRadioState.java
new file mode 100644
index 0000000..c2cb93b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/handlers/RegistryRadioState.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.handlers;
+
+import java.util.Hashtable;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExecutableExtension;
+import org.eclipse.jface.commands.RadioState;
+
+/**
+ * <p>
+ * A radio state that can be read from the registry. This stores a piece of
+ * boolean state information that is grouped with other boolean state to form a
+ * radio group. In a single radio group, there can be at most one state who
+ * value is {@link Boolean#TRUE} all the others must be {@link Boolean#FALSE}.
+ * </p>
+ * <p>
+ * When parsing from the registry, this state understands three parameters:
+ * <code>default</code>, which is the default value for this item;
+ * <code>persisted</code>, which is whether the state should be persisted
+ * between sessions; <code>id</code>, which is the identifier of the group to
+ * which this radio handler belongs. The <code>default</code> parameter
+ * defaults to <code>false</code>, and the <code>persisted</code> parameter
+ * defaults to <code>true</code>. If only one parameter is passed (i.e.,
+ * using the class name followed by a colon), then it is assumed to be the
+ * <code>id</code> parameter. The <code>id</code> is required for this class
+ * to function properly.
+ * </p>
+ * <p>
+ * Clients may instantiate this class, but must not extend.
+ * </p>
+ *
+ * @since 3.2
+ */
+public final class RegistryRadioState extends RadioState implements
+		IExecutableExtension {
+
+	/**
+	 * Reads the <code>default</code> parameter from the given string. This
+	 * converts the string to a boolean, using <code>true</code> as the
+	 * default.
+	 *
+	 * @param defaultString
+	 *            The string to parse; may be <code>null</code>.
+	 */
+	private final void readDefault(final String defaultString) {
+		if ("true".equalsIgnoreCase(defaultString)) { //$NON-NLS-1$
+			setValue(Boolean.TRUE);
+		}
+	}
+
+	/**
+	 * Reads the <code>persisted</code> parameter from the given string. This
+	 * converts the string to a boolean, using <code>true</code> as the
+	 * default.
+	 *
+	 * @param persistedString
+	 *            The string to parse; may be <code>null</code>.
+	 */
+	private final void readPersisted(final String persistedString) {
+		if ("false".equalsIgnoreCase(persistedString)) { //$NON-NLS-1$
+			setShouldPersist(false);
+		}
+
+		setShouldPersist(true);
+	}
+
+	@Override
+	public final void setInitializationData(
+			final IConfigurationElement configurationElement,
+			final String propertyName, final Object data) {
+		if (data instanceof String) {
+			// This is the default value.
+			setRadioGroupIdentifier((String) data);
+			setValue(Boolean.FALSE);
+			setShouldPersist(true);
+
+		} else if (data instanceof Hashtable) {
+			final Hashtable parameters = (Hashtable) data;
+
+			final Object defaultObject = parameters.get("default"); //$NON-NLS-1$
+			if (defaultObject instanceof String) {
+				readDefault((String) defaultObject);
+			}
+
+			final Object persistedObject = parameters.get("persisted"); //$NON-NLS-1$
+			if (persistedObject instanceof String) {
+				readPersisted((String) persistedObject);
+			}
+
+			final Object idObject = parameters.get("id"); //$NON-NLS-1$
+			if (idObject instanceof String) {
+				setRadioGroupIdentifier((String) idObject);
+			}
+
+		} else {
+			setShouldPersist(true);
+
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/handlers/RegistryToggleState.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/handlers/RegistryToggleState.java
new file mode 100644
index 0000000..2d65cf4
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/handlers/RegistryToggleState.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.handlers;
+
+import java.util.Hashtable;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExecutableExtension;
+import org.eclipse.jface.commands.ToggleState;
+
+/**
+ * <p>
+ * A toggle state that can be read from the registry. This stores a piece of
+ * boolean state information.
+ * </p>
+ * <p>
+ * When parsing from the registry, this state understands two parameters:
+ * <code>default</code>, which is the default value for this item; and
+ * <code>persisted</code>, which is whether the state should be persisted
+ * between sessions. The <code>default</code> parameter defaults to
+ * <code>false</code>, and the <code>persisted</code> parameter defaults to
+ * <code>true</code>. If only one parameter is passed (i.e., using the class
+ * name followed by a colon), then it is assumed to be the <code>default</code>
+ * parameter.
+ * </p>
+ * <p>
+ * Clients may instantiate this class, but must not extend.
+ * </p>
+ *
+ * @since 3.2
+ */
+public final class RegistryToggleState extends ToggleState implements
+		IExecutableExtension {
+
+	/**
+	 * The state ID for a toggle state understood by the system.
+	 *
+	 * @since 3.5
+	 */
+	public final static String STATE_ID = "org.eclipse.ui.commands.toggleState";  //$NON-NLS-1$
+
+	/**
+	 * Reads the <code>default</code> parameter from the given string. This
+	 * converts the string to a boolean, using <code>true</code> as the
+	 * default.
+	 *
+	 * @param defaultString
+	 *            The string to parse; may be <code>null</code>.
+	 */
+	private final void readDefault(final String defaultString) {
+		if ("true".equalsIgnoreCase(defaultString)) { //$NON-NLS-1$
+			setValue(Boolean.TRUE);
+		}
+	}
+
+	/**
+	 * Reads the <code>persisted</code> parameter from the given string. This
+	 * converts the string to a boolean, using <code>true</code> as the
+	 * default.
+	 *
+	 * @param persistedString
+	 *            The string to parse; may be <code>null</code>.
+	 */
+	private final void readPersisted(final String persistedString) {
+		if ("false".equalsIgnoreCase(persistedString)) { //$NON-NLS-1$
+			setShouldPersist(false);
+		}else {
+			setShouldPersist(true);
+		}
+	}
+
+	@Override
+	public final void setInitializationData(
+			final IConfigurationElement configurationElement,
+			final String propertyName, final Object data) {
+		if (data instanceof String) {
+			// This is the default value.
+			readDefault((String) data);
+			setShouldPersist(true);
+
+		} else if (data instanceof Hashtable) {
+			final Hashtable parameters = (Hashtable) data;
+			final Object defaultObject = parameters.get("default"); //$NON-NLS-1$
+			if (defaultObject instanceof String) {
+				readDefault((String) defaultObject);
+			}
+
+			final Object persistedObject = parameters.get("persisted"); //$NON-NLS-1$
+			if (persistedObject instanceof String) {
+				readPersisted((String) persistedObject);
+			}
+
+		} else {
+			setShouldPersist(true);
+
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/handlers/ShowPerspectiveHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/handlers/ShowPerspectiveHandler.java
new file mode 100644
index 0000000..8ba827c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/handlers/ShowPerspectiveHandler.java
@@ -0,0 +1,157 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Remy Chi Jian Suen <remy.suen@gmail.com> - Bug 218540 [Perspectives] Perspectives always open in same window, regardless of preference
+ *******************************************************************************/
+package org.eclipse.ui.handlers;
+
+import java.util.Map;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.jface.dialogs.ErrorDialog;
+import org.eclipse.jface.window.Window;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.WorkbenchException;
+import org.eclipse.ui.internal.IPreferenceConstants;
+import org.eclipse.ui.internal.Workbench;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.dialogs.SelectPerspectiveDialog;
+
+/**
+ * Shows the given perspective. If no perspective is specified in the
+ * parameters, then this opens the perspective selection dialog.
+ *
+ * @since 3.1
+ */
+public final class ShowPerspectiveHandler extends AbstractHandler {
+
+
+	@Override
+	public final Object execute(final ExecutionEvent event)
+			throws ExecutionException {
+		IWorkbenchWindow window = HandlerUtil
+				.getActiveWorkbenchWindowChecked(event);
+
+		// Get the view identifier, if any.
+		final Map parameters = event.getParameters();
+		final Object value = parameters
+				.get(IWorkbenchCommandConstants.PERSPECTIVES_SHOW_PERSPECTIVE_PARM_ID);
+		final String newWindow = (String) parameters
+				.get(IWorkbenchCommandConstants.PERSPECTIVES_SHOW_PERSPECTIVE_PARM_NEWWINDOW);
+
+		if (value == null) {
+			openOther(window);
+		} else {
+
+			if (newWindow == null || newWindow.equalsIgnoreCase("false")) { //$NON-NLS-1$
+				openPerspective((String) value, window);
+			} else {
+				openNewWindowPerspective((String) value, window);
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Opens the specified perspective in a new window.
+	 *
+	 * @param perspectiveId
+	 *            The perspective to open; must not be <code>null</code>
+	 * @throws ExecutionException
+	 *             If the perspective could not be opened.
+	 */
+	private void openNewWindowPerspective(String perspectiveId,
+			IWorkbenchWindow activeWorkbenchWindow) throws ExecutionException {
+		final IWorkbench workbench = PlatformUI.getWorkbench();
+		try {
+			IAdaptable input = ((Workbench) workbench).getDefaultPageInput();
+			workbench.openWorkbenchWindow(perspectiveId, input);
+		} catch (WorkbenchException e) {
+			ErrorDialog.openError(activeWorkbenchWindow.getShell(),
+					WorkbenchMessages.get().ChangeToPerspectiveMenu_errorTitle, e
+							.getMessage(), e.getStatus());
+		}
+	}
+
+	/**
+	 * Opens a view selection dialog, allowing the user to chose a view.
+	 *
+	 * @throws ExecutionException
+	 *             If the perspective could not be opened.
+	 */
+	private final void openOther(final IWorkbenchWindow activeWorkbenchWindow)
+			throws ExecutionException {
+		final SelectPerspectiveDialog dialog = new SelectPerspectiveDialog(
+				activeWorkbenchWindow.getShell(), WorkbenchPlugin.getDefault()
+						.getPerspectiveRegistry());
+		dialog.open();
+		if (dialog.getReturnCode() == Window.CANCEL) {
+			return;
+		}
+
+		final IPerspectiveDescriptor descriptor = dialog.getSelection();
+		if (descriptor != null) {
+			int openPerspMode = WorkbenchPlugin.getDefault().getPreferenceStore()
+					.getInt(IPreferenceConstants.OPEN_PERSP_MODE);
+			IWorkbenchPage page = activeWorkbenchWindow.getActivePage();
+			IPerspectiveDescriptor persp = page == null ? null : page.getPerspective();
+			String perspectiveId = descriptor.getId();
+			// only open it in a new window if the preference is set and the
+			// current workbench page doesn't have an active perspective
+			if (IPreferenceConstants.OPM_NEW_WINDOW == openPerspMode && persp != null) {
+				openNewWindowPerspective(perspectiveId, activeWorkbenchWindow);
+			} else {
+				openPerspective(perspectiveId, activeWorkbenchWindow);
+			}
+		}
+	}
+
+	/**
+	 * Opens the perspective with the given identifier.
+	 *
+	 * @param perspectiveId
+	 *            The perspective to open; must not be <code>null</code>
+	 * @throws ExecutionException
+	 *             If the perspective could not be opened.
+	 */
+	private final void openPerspective(final String perspectiveId,
+			final IWorkbenchWindow activeWorkbenchWindow)
+			throws ExecutionException {
+		final IWorkbench workbench = PlatformUI.getWorkbench();
+
+		final IWorkbenchPage activePage = activeWorkbenchWindow.getActivePage();
+		IPerspectiveDescriptor desc = activeWorkbenchWindow.getWorkbench()
+				.getPerspectiveRegistry().findPerspectiveWithId(perspectiveId);
+		if (desc == null) {
+			throw new ExecutionException("Perspective " + perspectiveId //$NON-NLS-1$
+					+ " cannot be found."); //$NON-NLS-1$
+		}
+
+		try {
+			if (activePage != null) {
+				activePage.setPerspective(desc);
+			} else {
+				IAdaptable input = ((Workbench) workbench)
+						.getDefaultPageInput();
+				activeWorkbenchWindow.openPage(perspectiveId, input);
+			}
+		} catch (WorkbenchException e) {
+			throw new ExecutionException("Perspective could not be opened.", e); //$NON-NLS-1$
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/handlers/ShowViewHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/handlers/ShowViewHandler.java
new file mode 100644
index 0000000..ef1444a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/handlers/ShowViewHandler.java
@@ -0,0 +1,170 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 430988
+ *     Simon Scholz <simon.scholz@vogella.com> - Bug 455527
+ *******************************************************************************/
+package org.eclipse.ui.handlers;
+
+import java.util.List;
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.descriptor.basic.MPartDescriptor;
+import org.eclipse.e4.ui.model.application.ui.advanced.MPlaceholder;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+import org.eclipse.e4.ui.workbench.modeling.EPartService;
+import org.eclipse.e4.ui.workbench.modeling.EPartService.PartState;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.internal.dialogs.ShowViewDialog;
+import org.eclipse.ui.internal.e4.compatibility.CompatibilityPart;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+/**
+ * Shows the given view. If no view is specified in the parameters, then this
+ * opens the view selection dialog.
+ *
+ * @since 3.1
+ */
+public final class ShowViewHandler extends AbstractHandler {
+
+
+    /**
+     * Creates a new ShowViewHandler that will open the view in its default location.
+     */
+    public ShowViewHandler() {
+    }
+
+    /**
+     * Creates a new ShowViewHandler that will optionally force the view to become
+     * a fast view.
+     *
+     * @param makeFast if true, the view will be moved to the fast view bar (even if it already
+     * exists elsewhere). If false, the view will be shown in its default location. Calling with
+     * false is equivalent to using the default constructor.
+     */
+    public ShowViewHandler(boolean makeFast) {
+
+    }
+
+	@Override
+	public final Object execute(final ExecutionEvent event) throws ExecutionException {
+		IWorkbenchWindow workbenchWindow = HandlerUtil.getActiveWorkbenchWindowChecked(event);
+		EPartService partService = workbenchWindow.getService(EPartService.class);
+		MApplication app = workbenchWindow.getService(MApplication.class);
+
+		// Get the view identifier, if any.
+		final Object id = event.getParameters().get(IWorkbenchCommandConstants.VIEWS_SHOW_VIEW_PARM_ID);
+
+		// let user select one or more
+		if (!(id instanceof String)) {
+			openOther(event, workbenchWindow, app, partService);
+			return null;
+		}
+
+		MPartDescriptor viewDescriptor = getViewDescriptor(app, (String) id);
+		if (viewDescriptor == null) {
+			handleMissingView(id);
+			return null;
+		}
+
+		openView(workbenchWindow, viewDescriptor, partService);
+		return null;
+	}
+
+	/**
+	 * Opens a view selection dialog, allowing the user to chose a view.
+	 */
+	private static final void openOther(ExecutionEvent event, IWorkbenchWindow workbenchWindow, MApplication app,
+			EPartService partService) {
+		Shell shell = HandlerUtil.getActiveShell(event);
+		IEclipseContext ctx = workbenchWindow.getService(IEclipseContext.class);
+		EModelService modelService = workbenchWindow.getService(EModelService.class);
+		MWindow window = workbenchWindow.getService(MWindow.class);
+
+		final ShowViewDialog dialog = new ShowViewDialog(shell, app, window, modelService, partService, ctx);
+		dialog.open();
+
+		if (dialog.getReturnCode() == Window.CANCEL) {
+			return;
+		}
+
+		final MPartDescriptor[] descriptors = dialog.getSelection();
+		for (MPartDescriptor descriptor : descriptors) {
+			openView(workbenchWindow, descriptor, partService);
+		}
+	}
+
+	/**
+	 * Opens the view with the given descriptor.
+	 *
+	 * @param viewDescriptor
+	 *            The view to open; must not be <code>null</code>
+	 */
+	private static final void openView(IWorkbenchWindow window, final MPartDescriptor viewDescriptor,
+			EPartService partService) {
+		/*
+		 * TODO: see bug 483699: the code below duplicates the code in
+		 * org.eclipse.ui.internal.quickaccess.ViewElement#execute() and should
+		 * be refactored to some user friendly API
+		 */
+		String viewId = viewDescriptor.getElementId();
+		if (CompatibilityPart.COMPATIBILITY_VIEW_URI.equals(viewDescriptor.getContributionURI())) {
+			IWorkbenchPage page = window.getActivePage();
+			if (page != null) {
+				try {
+					page.showView(viewId);
+				} catch (PartInitException e) {
+					handleViewError(viewId, e);
+				}
+			}
+		} else {
+			MPart part = partService.findPart(viewId);
+			if (part == null) {
+				MPlaceholder placeholder = partService.createSharedPart(viewId);
+				part = (MPart) placeholder.getRef();
+			}
+			partService.showPart(part, PartState.ACTIVATE);
+		}
+	}
+
+	private static MPartDescriptor getViewDescriptor(MApplication app, String id) {
+		List<MPartDescriptor> descriptors = app.getDescriptors();
+		for (MPartDescriptor descriptor : descriptors) {
+			if (id.equals(descriptor.getElementId()) && isView(descriptor)) {
+				return descriptor;
+			}
+		}
+		return null;
+	}
+
+	private static boolean isView(MPartDescriptor descriptor) {
+		return descriptor.getTags().contains("View"); //$NON-NLS-1$
+	}
+
+	private static void handleViewError(String id, PartInitException e) {
+		StatusUtil.handleStatus(e.getStatus(), "View could not be opened: " + id, //$NON-NLS-1$
+				StatusManager.SHOW);
+	}
+
+	private static void handleMissingView(final Object id) {
+		ExecutionException e = new ExecutionException("View could not be found: " + id); //$NON-NLS-1$
+		StatusUtil.handleStatus(e, StatusManager.SHOW);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/handlers/package.html b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/handlers/package.html
new file mode 100644
index 0000000..11bcb8d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/handlers/package.html
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <meta name="Author" content="IBM">
+   <meta name="GENERATOR" content="Mozilla/4.5 [en] (Win98; I) [Netscape]">
+   <title>Package-level Javadoc</title>
+</head>
+<body>
+<p>Provides support for integrating handlers into the Eclipse workbench.</p>
+
+<h2>Package Specification</h2>
+<p>
+This package provides the classes required to integrate handlers into the
+Eclipse workbench.
+</p>
+<p>
+To use the handler integration, the method <code>getAdapter</code> is called on
+the Eclipse workbench, with the argument <code>IHandlerService.class</code>.
+This will return an instance of <code>IHandlerService</code>.
+</p>
+</body>
+</html>
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/help/AbstractHelpUI.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/help/AbstractHelpUI.java
new file mode 100644
index 0000000..869cc46
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/help/AbstractHelpUI.java
@@ -0,0 +1,145 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.help;
+
+import java.net.URL;
+
+import org.eclipse.help.IContext;
+
+/**
+ * Abstract base class for the help system UI.
+ * <p>
+ * The Eclipse platform provides an extension point (<code>"org.eclipse.ui.helpSupport"</code>)
+ * for plugging in a help system UI. The help system UI is an optional
+ * component; applications may provide a UI for presenting help to the user by
+ * implementing a subclass and including the name of their class in the
+ * <code>&lt;config&gt;</code> element in an extension to the
+ * <code>"org.eclipse.ui.helpSupport"</code> extension point.
+ * </p>
+ * <p>
+ * Note that the standard implementation of the help system UI is provided by
+ * the <code>"org.eclipse.help.ui"</code> plug-in. Since the platform can only
+ * make use of a single help system UI implementation, make sure that the
+ * platform is not configured with more than one plug-in trying to extend this
+ * extension point.
+ * </p>
+ *
+ * @since 3.0
+ */
+public abstract class AbstractHelpUI {
+
+	/**
+	 * Displays the entire help bookshelf.
+	 */
+	public abstract void displayHelp();
+
+	/**
+	 * Displays the help search facility. For backward compatibility, the
+	 * default implementation does nothing.
+	 *
+	 * @since 3.1
+	 */
+	public void displaySearch() {
+		// do nothing
+	}
+
+	/**
+	 * Displays the dynamic help for the active context. For backward
+	 * compatibility, the default implementation does nothing.
+	 *
+	 * @since 3.1
+	 */
+	public void displayDynamicHelp() {
+		// do nothing
+	}
+
+	/**
+	 * Starts the help search using the help search facility. For backward
+	 * compatibility, the default implementation does nothing.
+	 *
+	 * @param expression
+	 *            the search expression
+	 * @since 3.1
+	 */
+	public void search(String expression) {
+		// do nothing
+	}
+
+	/**
+	 * Resolves the help resource href according to the help system
+	 * implementation.
+	 *
+	 * @param href
+	 *            the help resource
+	 * @param documentOnly
+	 *            if <code>true</code>, the resulting URL must point at the
+	 *            document referenced by href. Otherwise, it can be a URL that
+	 *            contains additional elements like navigation that the help
+	 *            system adds to the document.
+	 * @return the fully resolved URL of the help resource or <code>null</code>
+	 *         if not supported. Help systems that use application servers
+	 *         typically return URLs with http: protocol. Simple help system
+	 *         implementations can return URLs with file: protocol.
+	 *
+	 * @since 3.1
+	 */
+	public URL resolve(String href, boolean documentOnly) {
+		return null;
+	}
+
+	/**
+	 * Displays context-sensitive help for the given context.
+	 * <p>
+	 * (x,y) coordinates specify the location where the context sensitive help
+	 * UI will be presented. These coordinates are screen-relative (ie: (0,0) is
+	 * the top left-most screen corner). The platform is responsible for calling
+	 * this method and supplying the appropriate location.
+	 * </p>
+	 *
+	 * @param context
+	 *            the context to display
+	 * @param x
+	 *            horizontal position
+	 * @param y
+	 *            verifical position
+	 */
+	public abstract void displayContext(IContext context, int x, int y);
+
+	/**
+	 * Displays help content for the help resource with the given URL.
+	 * <p>
+	 * This method is called by the platform to launch the help system UI,
+	 * displaying the documentation identified by the <code>href</code>
+	 * parameter.
+	 * </p>
+	 * <p>
+	 * The help system makes no guarantee that all the help resources can be
+	 * displayed or how they are displayed.
+	 * </p>
+	 *
+	 * @param href
+	 *            the URL of the help resource.
+	 *            <p>
+	 *            Valid href are as described in
+	 *            {@link  org.eclipse.help.IHelpResource#getHref() IHelpResource.getHref()}
+	 *            </p>
+	 */
+	public abstract void displayHelpResource(String href);
+
+	/**
+	 * Returns whether the context-sensitive help window is currently being
+	 * displayed.
+	 *
+	 * @return <code>true</code> if the context-sensitive help window is
+	 *         currently being displayed, <code>false</code> if not
+	 */
+	public abstract boolean isContextHelpDisplayed();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/help/DialogPageContextComputer.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/help/DialogPageContextComputer.java
new file mode 100644
index 0000000..b30b77a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/help/DialogPageContextComputer.java
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.help;
+
+import java.util.ArrayList;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.help.IContext;
+import org.eclipse.jface.dialogs.IDialogPage;
+import org.eclipse.swt.events.HelpEvent;
+import org.eclipse.swt.widgets.Control;
+
+/**
+ * For determining the help context for controls in a dialog page.
+ * <p>
+ * This class may be instantiated; it is not intended to be subclassed.
+ * </p>
+ *
+ * @deprecated marked for deletion, see Bug 442961, nested contexts are no
+ *             longer supported by the help support system
+ * @noextend This class is not intended to be subclassed by clients.
+ * @noinstantiate This class is not intended to be instantiated by clients.
+ * @noreference This class is not intended to be referenced by clients.
+ *
+ */
+@Deprecated
+public class DialogPageContextComputer implements IContextComputer {
+    private IDialogPage page;
+
+    private ArrayList contextList;
+
+    private Object context;
+
+    /**
+     * Creates a new context computer for the given dialog page and help context.
+     *
+     * @param page the dialog page
+     * @param helpContext a single help context id (type <code>String</code>) or
+     *  help context object (type <code>IContext</code>)
+     */
+    public DialogPageContextComputer(IDialogPage page, Object helpContext) {
+        Assert.isTrue(helpContext instanceof String
+                || helpContext instanceof IContext);
+        this.page = page;
+        context = helpContext;
+    }
+
+    /**
+     * Add the contexts to the context list.
+     *
+     * @param object the contexts (<code>Object[]</code> or <code>IContextComputer</code>)
+     * @param event the help event
+     */
+    private void addContexts(Object object, HelpEvent event) {
+        Assert.isTrue(object instanceof Object[]
+                || object instanceof IContextComputer
+                || object instanceof String);
+
+        if (object instanceof String) {
+            contextList.add(object);
+            return;
+        }
+
+        Object[] contexts;
+        if (object instanceof IContextComputer) {
+			// get local contexts
+            contexts = ((IContextComputer) object).getLocalContexts(event);
+		} else {
+			contexts = (Object[]) object;
+		}
+
+        // copy the contexts into our list
+        for (Object ctx : contexts) {
+			contextList.add(ctx);
+		}
+    }
+
+    /**
+     * Add the contexts for the given control to the context list.
+     *
+     * @param control the control from which to obtain the contexts
+     * @param event the help event
+     */
+    private void addContextsForControl(Control control, HelpEvent event) {
+        // See if there is are help contexts on the control
+        Object object = WorkbenchHelp.getHelp(control);
+
+        if (object == null || object == this) {
+			// We need to check for this in order to avoid recursion
+            return;
+		}
+
+        addContexts(object, event);
+    }
+
+    @Override
+	public Object[] computeContexts(HelpEvent event) {
+        contextList = new ArrayList();
+
+        // Add the local context
+        contextList.add(context);
+
+        // Add the contexts for the page
+        addContextsForControl(page.getControl(), event);
+
+        // Add the contexts for the container shell
+        addContextsForControl(page.getControl().getShell(), event);
+
+        // Return the contexts
+        return contextList.toArray();
+    }
+
+    @Override
+	public Object[] getLocalContexts(HelpEvent event) {
+        return new Object[] { context };
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/help/IContextComputer.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/help/IContextComputer.java
new file mode 100644
index 0000000..df09065
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/help/IContextComputer.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.help;
+
+import org.eclipse.swt.events.HelpEvent;
+
+/**
+ * A content computer is used to dynamically calculate help support contexts at
+ * the time the user requests help.
+ * <p>
+ * This interface may be implemented by clients.
+ * </p>
+ *
+ *
+ *
+ * @deprecated marked for deletion, see Bug 442961, nested contexts are no
+ *             longer supported by the help support system
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noreference This interface is not intended to be referenced by clients.
+ *
+ */
+
+@Deprecated
+public interface IContextComputer {
+    /**
+     * Computes contexts for the help system.
+     *
+     * @param event the help event which triggered this request for help
+     * @return a mixed-type array of context ids (type <code>String</code>)
+     *   and/or help contexts (type <code>IContext</code>)
+     * @see org.eclipse.help.IContext
+     */
+    public Object[] computeContexts(HelpEvent event);
+
+    /**
+     * Returns the local contexts for this context computer.
+     * <p>
+     * Typically this method is called by other instances of
+     * <code>IContextComputer</code> in their <code>computeContexts</code>
+     * method.
+     * </p>
+     * <p>
+     * The important concept here is that the value returned by
+     * <code>computeContexts</code> represents the complete help
+     * contexts and is passed directly to the help support system.
+     * </p>
+     * <p>
+     * However the value returned by this method represents the
+     * only the contexts for the particular control with which this
+     * <code>IContextComputer</code> is associated.
+     * </p>
+     * @param event the help event which triggered this request for help
+     * @return a mixed-type array of context ids (type <code>String</code>)
+     *   and/or help contexts (type <code>IContext</code>)
+     * @see org.eclipse.help.IContext
+     */
+    public Object[] getLocalContexts(HelpEvent event);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/help/IWorkbenchHelpSystem.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/help/IWorkbenchHelpSystem.java
new file mode 100644
index 0000000..20bc936
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/help/IWorkbenchHelpSystem.java
@@ -0,0 +1,211 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2014 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 448674
+ *******************************************************************************/
+package org.eclipse.ui.help;
+
+import java.net.URL;
+import org.eclipse.help.IContext;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+
+/**
+ * <p>
+ * The interface that is used to access the workbench help system. Replaces
+ * static methods on <code>WorkbenchHelp</code>.
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ *
+ * @since 3.1
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IWorkbenchHelpSystem {
+
+	/**
+	 * Returns whether there is a UI help system installed.
+	 *
+	 * @return whether there is a UI help system installed
+	 */
+	boolean hasHelpUI();
+
+	/**
+	 * Displays the entire help bookshelf.
+	 * <p>
+	 * Ignored if no help UI is available.
+	 * </p>
+	 */
+	void displayHelp();
+
+	/**
+	 * Displays the help search system.
+	 * <p>
+	 * Ignored if no help UI is available.
+	 * </p>
+	 */
+	void displaySearch();
+
+	/**
+	 * Displays the dynamic help for the current UI context.
+	 * <p>
+	 * Ignored if no help UI is available.
+	 * </p>
+	 */
+	void displayDynamicHelp();
+
+	/**
+	 * Starts the search using the help search system.
+	 * <p>
+	 * Ignored if no help UI is available.
+	 * </p>
+	 *
+	 * @param expression
+	 *            the search expression. The actual syntax rules of the
+	 *            expression are dependent on the active
+	 *            help system. Refer to the help system
+	 *            documentation for more details.
+	 */
+	void search(String expression);
+
+	/**
+	 * Displays context-sensitive help for the given context.
+	 * <p>
+	 * (x,y) coordinates specify the location where the context sensitive help
+	 * UI will be presented. These coordinates are screen-relative (ie: (0,0) is
+	 * the top left-most screen corner). The platform is responsible for calling
+	 * this method and supplying the appropriate location.
+	 * </p>
+	 * <p>
+	 * Ignored if no help UI is available.
+	 * </p>
+	 *
+	 * @param context
+	 *            the context to display
+	 * @param x
+	 *            horizontal position
+	 * @param y
+	 *            vertical position
+	 */
+	void displayContext(IContext context, int x, int y);
+
+	/**
+	 * Displays help content for the help resource with the given URL.
+	 * <p>
+	 * This method is called by the platform to launch the help system UI,
+	 * displaying the documentation identified by the <code>href</code>
+	 * parameter.
+	 * </p>
+	 * <p>
+	 * The help system makes no guarantee that all the help resources can be
+	 * displayed or how they are displayed.
+	 * </p>
+	 * <p>
+	 * Ignored if no help UI is available.
+	 * </p>
+	 *
+	 * @param href
+	 *            the URL of the help resource.
+	 *            <p>
+	 *            Valid href are as described in
+	 *            {@link  org.eclipse.help.IHelpResource#getHref() IHelpResource.getHref()}
+	 *            </p>
+	 */
+	void displayHelpResource(String href);
+
+	/**
+	 * Calls the help support system to display the given help id.
+	 * <p>
+	 * May only be called from a UI thread.
+	 * <p>
+	 *
+	 * @param helpContextId
+	 *            the id of the context to display
+	 */
+	void displayHelp(String helpContextId);
+
+	/**
+	 * Displays context-sensitive help for the given context.
+	 * <p>
+	 * May only be called from a UI thread.
+	 * <p>
+	 *
+	 * @param context
+	 *            the context to display
+	 */
+	void displayHelp(IContext context);
+
+	/**
+	 * Returns whether the context-sensitive help window is currently being
+	 * displayed. Returns <code>false</code> if the help UI has not been
+	 * activated yet.
+	 *
+	 * @return <code>true</code> if the context-sensitive help window is
+	 *         currently being displayed, <code>false</code> otherwise
+	 */
+	boolean isContextHelpDisplayed();
+
+	/**
+	 * Sets the given help id on the given action.
+	 *
+	 * @param action
+	 *            the action on which to register the id
+	 * @param helpContextId
+	 *            the id to use when F1 help is invoked
+	 */
+	void setHelp(IAction action, String helpContextId);
+
+	/**
+	 * Sets the given help id on the given control.
+	 *
+	 * @param control
+	 *            the control on which to register the id
+	 * @param helpContextId
+	 *            the id to use when F1 help is invoked
+	 */
+	void setHelp(Control control, String helpContextId);
+
+	/**
+	 * Sets the given help id on the given menu.
+	 *
+	 * @param menu
+	 *            the menu on which to register the id
+	 * @param helpContextId
+	 *            the id to use when F1 help is invoked
+	 */
+	void setHelp(Menu menu, String helpContextId);
+
+	/**
+	 * Sets the given help id on the given menu item.
+	 *
+	 * @param item
+	 *            the menu item on which to register the id
+	 * @param helpContextId
+	 *            the id to use when F1 help is invoked
+	 */
+	void setHelp(MenuItem item, String helpContextId);
+
+	/**
+	 * Resolves the help resource href by converting it into a legitimate URL
+	 * according to the implementation of the help system. Help resources that
+	 * already have a protocol will be unchanged.
+	 *
+	 * @param href
+	 * @param documentOnly if <code>true</code>, the resulting URL must point
+	 * at the document referenced by href. Otherwise, it can be a URL that
+	 * contains additional elements like navigation that the help system
+	 * adds to the document.
+	 * @return the resolved URL or <code>null</code> if no help UI is
+	 *         available.
+	 */
+	URL resolve(String href, boolean documentOnly);
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/help/ViewContextComputer.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/help/ViewContextComputer.java
new file mode 100644
index 0000000..e38075e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/help/ViewContextComputer.java
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.help;
+
+import java.util.ArrayList;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.help.IContext;
+import org.eclipse.swt.events.HelpEvent;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IViewPart;
+
+/**
+ * For determining the help context for controls in a view.
+ * <p>
+ * This class may be instantiated; it is not intended to be subclassed.
+ * </p>
+ *
+ * @deprecated marked for deletion, see Bug 442961, nested contexts are no
+ *             longer supported by the help support system
+ * @noextend This class is not intended to be subclassed by clients.
+ * @noinstantiate This class is not intended to be instantiated by clients.
+ * @noreference This class is not intended to be referenced by clients.
+ *
+ */
+@Deprecated
+public class ViewContextComputer implements IContextComputer {
+    private IViewPart view;
+
+    private ArrayList contextList;
+
+    private Object context;
+
+    /**
+     * Creates a new context computer for the given view and help context.
+     *
+     * @param viewPart the view
+     * @param helpContext a single help context id (type <code>String</code>) or
+     *  help context object (type <code>IContext</code>)
+     */
+    public ViewContextComputer(IViewPart viewPart, Object helpContext) {
+        Assert.isTrue(helpContext instanceof String
+                || helpContext instanceof IContext);
+        view = viewPart;
+        context = helpContext;
+    }
+
+    /**
+     * Add the contexts to the context list.
+     *
+     * @param object the contexts (<code>Object[]</code> or <code>IContextComputer</code>)
+     * @param event the help event
+     */
+    private void addContexts(Object object, HelpEvent event) {
+        Assert.isTrue(object instanceof Object[]
+                || object instanceof IContextComputer
+                || object instanceof String);
+
+        if (object instanceof String) {
+            contextList.add(object);
+            return;
+        }
+
+        Object[] contexts;
+        if (object instanceof IContextComputer) {
+			// get local contexts
+            contexts = ((IContextComputer) object).getLocalContexts(event);
+		} else {
+			contexts = (Object[]) object;
+		}
+
+        // copy the contexts into our list
+        for (Object ctx : contexts) {
+			contextList.add(ctx);
+		}
+    }
+
+    /**
+     * Add the contexts for the given control to the context list.
+     *
+     * @param control the control from which to obtain the contexts
+     * @param event the help event
+     */
+    private void addContextsForControl(Control control, HelpEvent event) {
+        // See if there is are help contexts on the control
+        Object object = WorkbenchHelp.getHelp(control);
+
+        if (object == null || object == this) {
+			// We need to check for this in order to avoid recursion
+            return;
+		}
+
+        addContexts(object, event);
+    }
+
+    @Override
+	public Object[] computeContexts(HelpEvent event) {
+        contextList = new ArrayList();
+
+        // Add the local context
+        contextList.add(context);
+
+        // Add the contexts for the window shell
+        addContextsForControl(view.getSite().getShell(), event);
+
+        // Return the contexts
+        return contextList.toArray();
+    }
+
+    @Override
+	public Object[] getLocalContexts(HelpEvent event) {
+        return new Object[] { context };
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/help/WorkbenchHelp.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/help/WorkbenchHelp.java
new file mode 100644
index 0000000..1cdc01c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/help/WorkbenchHelp.java
@@ -0,0 +1,441 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.help;
+
+import org.eclipse.help.IContext;
+import org.eclipse.help.IHelp;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.swt.events.HelpListener;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.commands.ICommand;
+import org.eclipse.ui.internal.help.WorkbenchHelpSystem;
+
+/**
+ * Provides methods for accessing the help UI.
+ * <p>
+ * The help UI is optional, to allow applications to be configured without one.
+ * </p>
+ * <p>
+ * The various <code>setHelp</code> methods allow context help to be hooked in
+ * to SWT menus, menu items, and controls, and into JFace actions. This involves
+ * furnishing a help context id. When the user requests help for one of the
+ * established widgets (for instance, by hitting F1), the context id is
+ * retrieved and passed to the help UI using
+ * <code>WorkbenchHelp.displayContext(helpContext, xposition, yposition)</code>.
+ * </p>
+ * <p>
+ * In cases more dynamic situations, clients may hook their own help listener
+ * and call <code>WorkbenchHelp.displayContext</code> with an
+ * <code>IContext</code>.
+ * </p>
+ * <p>
+ * This class provides static methods only; it is not intended to be
+ * instantiated or subclassed.
+ * </p>
+ *
+ * @deprecated marked for deletion, see Bug 442959, clients should use
+ *             <code>IWorkbenchHelpSystem</code> instead
+ *
+ * @see org.eclipse.help.HelpSystem
+ * @see org.eclipse.ui.help.IWorkbenchHelpSystem
+ * @see org.eclipse.ui.IWorkbench#getHelpSystem()
+ * @noinstantiate This class is not intended to be instantiated by clients.
+ * @noextend This class is not intended to be subclassed by clients.
+ * @noreference This class is not intended to be referenced by clients.
+ */
+@Deprecated
+public class WorkbenchHelp {
+
+    /**
+     * This class is not intented to be instantiated
+     */
+    private WorkbenchHelp() {
+    }
+
+    /**
+     * Displays the entire help bookshelf.
+     * <p>
+     * Ignored if no help UI is available.
+     * </p>
+     *
+     * @since 3.0
+     */
+    public static void displayHelp() {
+    	PlatformUI.getWorkbench().getHelpSystem().displayHelp();
+    }
+
+    /**
+     * Displays context-sensitive help for the given context.
+     * <p>
+     * (x,y) coordinates specify the location where the context sensitive
+     * help UI will be presented. These coordinates are screen-relative
+     * (ie: (0,0) is the top left-most screen corner).
+     * The platform is responsible for calling this method and supplying the
+     * appropriate location.
+     * </p>
+     * <p>
+     * Ignored if no help UI is available.
+     * </p>
+     *
+     * @param context the context to display
+     * @param x horizontal position
+     * @param y verifical position
+     * @since 3.0
+     */
+    public static void displayContext(IContext context, int x, int y) {
+    	PlatformUI.getWorkbench().getHelpSystem().displayContext(context, x, y);
+    }
+
+    /**
+     * Displays help content for the help resource with the given URL.
+     * <p>
+     * This method is called by the platform to launch the help system UI, displaying
+     * the documentation identified by the <code>href</code> parameter.
+     * </p>
+     * <p>
+     * The help system makes no guarantee that all the help resources can be displayed or how they are displayed.
+     * </p>
+     * <p>
+     * Ignored if no help UI is available.
+     * </p>
+     *
+     * @param href the URL of the help resource.
+     * <p>Valid href are as described in
+     * 	{@link  org.eclipse.help.IHelpResource#getHref() IHelpResource.getHref()}
+     * </p>
+     * @since 3.0
+     */
+    public static void displayHelpResource(String href) {
+    	PlatformUI.getWorkbench().getHelpSystem().displayHelpResource(href);
+    }
+
+    /**
+     * Creates a new help listener for the given command. This retrieves the
+     * help context ID from the command, and creates an appropriate listener
+     * based on this.
+     *
+     * @param command
+     *            The command for which the listener should be created; must
+     *            not be <code>null</code>.
+     * @return A help listener; never <code>null</code>.
+     */
+    public static HelpListener createHelpListener(ICommand command) {
+    	return WorkbenchHelpSystem.getInstance().createHelpListener(command);
+    }
+
+    /**
+     * Calls the help support system to display the given help context id.
+     * <p>
+     * May only be called from a UI thread.
+     * <p>
+     *
+     * @param contextId the id of the context to display
+     * @since 2.0
+     */
+    public static void displayHelp(String contextId) {
+    	PlatformUI.getWorkbench().getHelpSystem().displayHelp(contextId);
+    }
+
+    /**
+     * Displays context-sensitive help for the given context.
+     * <p>
+     * May only be called from a UI thread.
+     * <p>
+     *
+     * @param context the context to display
+     * @since 2.0
+     */
+    public static void displayHelp(IContext context) {
+    	PlatformUI.getWorkbench().getHelpSystem().displayHelp(context);
+    }
+
+    /**
+     * Returns the help contexts on the given control.
+     * <p>
+     * Instances of <code>IContextComputer</code> may use this method
+     * to obtain the previously registered help contexts of a control.
+     * </p>
+     *
+     * @param control the control on which the contexts are registered
+     * @return contexts the contexts to use when F1 help is invoked; a mixed-type
+     *   array of context ids (type <code>String</code>) and/or help contexts (type
+     *   <code>IContext</code>) or an <code>IContextComputer</code> or
+     *   <code>null</code> if no contexts have been set.
+     * @deprecated as context computers are no longer supported
+     */
+    @Deprecated
+	public static Object getHelp(Control control) {
+        return control.getData(WorkbenchHelpSystem.HELP_KEY);
+    }
+
+    /**
+     * Returns the help contexts on the given menu.
+     * <p>
+     * Instances of <code>IContextComputer</code> may use this method
+     * to obtain the previously registered help contexts of a menu.
+     * </p>
+     *
+     * @param menu the menu on which the contexts are registered
+     * @return contexts the contexts to use when F1 help is invoked; a mixed-type
+     *   array of context ids (type <code>String</code>) and/or help contexts (type
+     *   <code>IContext</code>) or an <code>IContextComputer</code> or
+     *   <code>null</code> if no contexts have been set.
+     * @deprecated as context computers are no longer supported
+     */
+    @Deprecated
+	public static Object getHelp(Menu menu) {
+        return menu.getData(WorkbenchHelpSystem.HELP_KEY);
+    }
+
+    /**
+     * Returns the help contexts on the given menu item.
+     * <p>
+     * Instances of <code>IContextComputer</code> may use this method
+     * to obtain the previously registered help contexts of a menu.
+     * </p>
+     *
+     * @param menuItem the menu item on which the contexts are registered
+     * @return contexts the contexts to use when F1 help is invoked; a mixed-type
+     *   array of context ids (type <code>String</code>) and/or help contexts (type
+     *   <code>IContext</code>) or an <code>IContextComputer</code> or
+     *   <code>null</code> if no contexts have been set.
+     * @deprecated as context computers are no longer supported
+     */
+    @Deprecated
+	public static Object getHelp(MenuItem menuItem) {
+        return menuItem.getData(WorkbenchHelpSystem.HELP_KEY);
+    }
+
+    /**
+     * Returns the help support system for the platform, if available.
+     *
+     * @return the help support system, or <code>null</code> if none
+     * @deprecated Use the static methods on this class and on
+     * {@link org.eclipse.help.HelpSystem HelpSystem} instead of the IHelp methods
+     * on the object returned by this method.
+     */
+    @Deprecated
+	public static IHelp getHelpSupport() {
+    	return WorkbenchHelpSystem.getInstance().getHelpSupport();
+    }
+
+
+    /**
+     * Returns whether the context-sensitive help window is currently being
+     * displayed. Returns <code>false</code> if the help UI has not been
+     * activated yet.
+     *
+     * @return <code>true</code> if the context-sensitive help
+     * window is currently being displayed, <code>false</code> otherwise
+     */
+    public static boolean isContextHelpDisplayed() {
+    	return PlatformUI.getWorkbench().getHelpSystem().isContextHelpDisplayed();
+    }
+
+    /**
+     * Sets the given help contexts on the given action.
+     * <p>
+     * Use this method when the list of help contexts is known in advance.
+     * Help contexts can either supplied as a static list, or calculated with a
+     * context computer (but not both).
+     * </p>
+     *
+     * @param action the action on which to register the computer
+     * @param contexts the contexts to use when F1 help is invoked; a mixed-type
+     *   array of context ids (type <code>String</code>) and/or help contexts (type
+     *   <code>IContext</code>)
+     * @deprecated use setHelp with a single context id parameter
+     */
+    @Deprecated
+	public static void setHelp(IAction action, final Object[] contexts) {
+    	WorkbenchHelpSystem.getInstance().setHelp(action, contexts);
+    }
+
+    /**
+     * Sets the given help context computer on the given action.
+     * <p>
+     * Use this method when the help contexts cannot be computed in advance.
+     * Help contexts can either supplied as a static list, or calculated with a
+     * context computer (but not both).
+     * </p>
+     *
+     * @param action the action on which to register the computer
+     * @param computer the computer to determine the help contexts for the control
+     *    when F1 help is invoked
+     * @deprecated context computers are no longer supported, clients should implement
+     *  their own help listener
+     */
+    @Deprecated
+	public static void setHelp(IAction action, final IContextComputer computer) {
+    	WorkbenchHelpSystem.getInstance().setHelp(action, computer);
+    }
+
+    /**
+     * Sets the given help contexts on the given control.
+     * <p>
+     * Use this method when the list of help contexts is known in advance.
+     * Help contexts can either supplied as a static list, or calculated with a
+     * context computer (but not both).
+     * </p>
+     *
+     * @param control the control on which to register the contexts
+     * @param contexts the contexts to use when F1 help is invoked; a mixed-type
+     *   array of context ids (type <code>String</code>) and/or help contexts (type
+     *   <code>IContext</code>)
+     * @deprecated use setHelp with single context id parameter
+     */
+    @Deprecated
+	public static void setHelp(Control control, Object[] contexts) {
+    	WorkbenchHelpSystem.getInstance().setHelp(control, contexts);
+    }
+
+    /**
+     * Sets the given help context computer on the given control.
+     * <p>
+     * Use this method when the help contexts cannot be computed in advance.
+     * Help contexts can either supplied as a static list, or calculated with a
+     * context computer (but not both).
+     * </p>
+     *
+     * @param control the control on which to register the computer
+     * @param computer the computer to determine the help contexts for the control
+     *    when F1 help is invoked
+     * @deprecated context computers are no longer supported, clients should implement
+     *  their own help listener
+     */
+    @Deprecated
+	public static void setHelp(Control control, IContextComputer computer) {
+    	WorkbenchHelpSystem.getInstance().setHelp(control, computer);
+    }
+
+    /**
+     * Sets the given help contexts on the given menu.
+     * <p>
+     * Use this method when the list of help contexts is known in advance.
+     * Help contexts can either supplied as a static list, or calculated with a
+     * context computer (but not both).
+     * </p>
+     *
+     * @param menu the menu on which to register the context
+     * @param contexts the contexts to use when F1 help is invoked; a mixed-type
+     *   array of context ids (type <code>String</code>) and/or help contexts (type
+     *   <code>IContext</code>)
+     * @deprecated use setHelp with single context id parameter
+     */
+    @Deprecated
+	public static void setHelp(Menu menu, Object[] contexts) {
+    	WorkbenchHelpSystem.getInstance().setHelp(menu, contexts);
+    }
+
+    /**
+     * Sets the given help context computer on the given menu.
+     * <p>
+     * Use this method when the help contexts cannot be computed in advance.
+     * Help contexts can either supplied as a static list, or calculated with a
+     * context computer (but not both).
+     * </p>
+     *
+     * @param menu the menu on which to register the computer
+     * @param computer the computer to determine the help contexts for the control
+     *    when F1 help is invoked
+     * @deprecated context computers are no longer supported, clients should implement
+     *  their own help listener
+     */
+    @Deprecated
+	public static void setHelp(Menu menu, IContextComputer computer) {
+    	WorkbenchHelpSystem.getInstance().setHelp(menu, computer);
+    }
+
+    /**
+     * Sets the given help contexts on the given menu item.
+     * <p>
+     * Use this method when the list of help contexts is known in advance.
+     * Help contexts can either supplied as a static list, or calculated with a
+     * context computer (but not both).
+     * </p>
+     *
+     * @param item the menu item on which to register the context
+     * @param contexts the contexts to use when F1 help is invoked; a mixed-type
+     *   array of context ids (type <code>String</code>) and/or help contexts (type
+     *   <code>IContext</code>)
+     * @deprecated use setHelp with single context id parameter
+     */
+    @Deprecated
+	public static void setHelp(MenuItem item, Object[] contexts) {
+    	WorkbenchHelpSystem.getInstance().setHelp(item, contexts);
+    }
+
+    /**
+     * Sets the given help context computer on the given menu item.
+     * <p>
+     * Use this method when the help contexts cannot be computed in advance.
+     * Help contexts can either supplied as a static list, or calculated with a
+     * context computer (but not both).
+     * </p>
+     *
+     * @param item the menu item on which to register the computer
+     * @param computer the computer to determine the help contexts for the control
+     *    when F1 help is invoked
+     * @deprecated context computers are no longer supported, clients should implement
+     *  their own help listener
+     */
+    @Deprecated
+	public static void setHelp(MenuItem item, IContextComputer computer) {
+    	WorkbenchHelpSystem.getInstance().setHelp(item, computer);
+    }
+
+    /**
+     * Sets the given help context id on the given action.
+     *
+     * @param action the action on which to register the context id
+     * @param contextId the context id to use when F1 help is invoked
+     * @since 2.0
+     */
+    public static void setHelp(IAction action, final String contextId) {
+    	PlatformUI.getWorkbench().getHelpSystem().setHelp(action, contextId);
+    }
+
+    /**
+     * Sets the given help context id on the given control.
+     *
+     * @param control the control on which to register the context id
+     * @param contextId the context id to use when F1 help is invoked
+     * @since 2.0
+     */
+    public static void setHelp(Control control, String contextId) {
+    	PlatformUI.getWorkbench().getHelpSystem().setHelp(control, contextId);
+    }
+
+    /**
+     * Sets the given help context id on the given menu.
+     *
+     * @param menu the menu on which to register the context id
+     * @param contextId the context id to use when F1 help is invoked
+     * @since 2.0
+     */
+    public static void setHelp(Menu menu, String contextId) {
+    	PlatformUI.getWorkbench().getHelpSystem().setHelp(menu, contextId);
+    }
+
+    /**
+     * Sets the given help context id on the given menu item.
+     *
+     * @param item the menu item on which to register the context id
+     * @param contextId the context id to use when F1 help is invoked
+     * @since 2.0
+     */
+    public static void setHelp(MenuItem item, String contextId) {
+    	PlatformUI.getWorkbench().getHelpSystem().setHelp(item, contextId);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/help/package.html b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/help/package.html
new file mode 100644
index 0000000..e18c5bc
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/help/package.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <meta name="Author" content="IBM">
+   <meta name="GENERATOR" content="Mozilla/4.5 [en] (WinNT; I) [Netscape]">
+   <title>Package-level Javadoc</title>
+</head>
+<body>
+Classes for integration with the help support system
+in the Eclipse Platform User Interface.
+<h2>
+Package Specification</h2>
+Within the Eclipse Platform UI each user interface component should integrate
+with the help support system.&nbsp; The simplest form of help integration
+is accomplished using <b>WorkbenchHelp</b>.&nbsp; This class provides the
+client with methods to define a help context for SWT Controls.&nbsp; Once
+defined, the help support system will automatically launch help with the
+appropriate context if a user request for help occurs.
+</body>
+</html>
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/AbstractEnabledHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/AbstractEnabledHandler.java
new file mode 100644
index 0000000..aff673c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/AbstractEnabledHandler.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.HandlerEvent;
+
+/**
+ * Abstract base class that provides the enabled state, where changing the state
+ * fires the HandlerEvent.
+ *
+ * @since 3.3
+ */
+public abstract class AbstractEnabledHandler extends AbstractHandler {
+
+	private boolean enabled = true;
+
+	@Override
+	public boolean isEnabled() {
+		return enabled;
+	}
+
+	protected void setEnabled(boolean isEnabled) {
+		if (enabled != isEnabled) {
+			enabled = isEnabled;
+			fireHandlerChanged(new HandlerEvent(this, true, false));
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/AbstractEvaluationHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/AbstractEvaluationHandler.java
new file mode 100644
index 0000000..7385d26
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/AbstractEvaluationHandler.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ ******************************************************************************/
+
+package org.eclipse.ui.internal;
+
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.services.IEvaluationReference;
+import org.eclipse.ui.services.IEvaluationService;
+
+/**
+ * This internal class serves as a foundation for any handler that would like
+ * its enabled state controlled by core expressions and the IEvaluationService.
+ *
+ * @since 3.3
+ */
+public abstract class AbstractEvaluationHandler extends AbstractEnabledHandler {
+	private final static String PROP_ENABLED = "enabled"; //$NON-NLS-1$
+	private IEvaluationService evaluationService;
+	private IPropertyChangeListener enablementListener;
+	private IEvaluationReference enablementRef;
+
+	protected IEvaluationService getEvaluationService() {
+		if (evaluationService == null) {
+			evaluationService = PlatformUI.getWorkbench()
+					.getService(IEvaluationService.class);
+		}
+		return evaluationService;
+	}
+
+	protected void registerEnablement() {
+		enablementRef = getEvaluationService().addEvaluationListener(
+				getEnabledWhenExpression(), getEnablementListener(),
+				PROP_ENABLED);
+	}
+
+	protected abstract Expression getEnabledWhenExpression();
+
+	/**
+	 * @return
+	 */
+	private IPropertyChangeListener getEnablementListener() {
+		if (enablementListener == null) {
+			enablementListener = event -> {
+				if (event.getProperty() == PROP_ENABLED) {
+					if (event.getNewValue() instanceof Boolean) {
+						setEnabled(((Boolean) event.getNewValue())
+								.booleanValue());
+					} else {
+						setEnabled(false);
+					}
+				}
+			};
+		}
+		return enablementListener;
+	}
+
+	@Override
+	public void dispose() {
+		if (enablementRef != null) {
+			evaluationService.removeEvaluationListener(enablementRef);
+			enablementRef = null;
+			enablementListener = null;
+			evaluationService = null;
+		}
+		super.dispose();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/AbstractPartSelectionTracker.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/AbstractPartSelectionTracker.java
new file mode 100644
index 0000000..03cae8a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/AbstractPartSelectionTracker.java
@@ -0,0 +1,164 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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.ui.internal;
+
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.jface.util.SafeRunnable;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.ui.INullSelectionListener;
+import org.eclipse.ui.ISelectionListener;
+import org.eclipse.ui.IWorkbenchPart;
+
+/**
+ * Provides per-part selection tracking for the selection service.
+ */
+public abstract class AbstractPartSelectionTracker {
+    /**
+     * List of selection listeners for this tracker
+     */
+	private ListenerList<ISelectionListener> fListeners = new ListenerList<>();
+
+    /**
+     * List of post selection listeners for this tracker
+     */
+	private ListenerList<ISelectionListener> postListeners = new ListenerList<>();
+
+    /**
+     * The id of the part this tracls
+     */
+    private String fPartId;
+
+    /**
+     * Constructs a part selection tracker for the part with the given id.
+     *
+     * @param id part identifier
+     */
+    public AbstractPartSelectionTracker(String partId) {
+        setPartId(partId);
+    }
+
+    /**
+     * Adds a selection listener to this tracker
+     *
+     * @param listener the listener to add
+     */
+    public void addSelectionListener(ISelectionListener listener) {
+        fListeners.add(listener);
+    }
+
+    /**
+     * Adds a post selection listener to this tracker
+     *
+     * @param listener the listener to add
+     */
+    public void addPostSelectionListener(ISelectionListener listener) {
+        postListeners.add(listener);
+    }
+
+    /**
+     * Returns the selection from the part being tracked,
+     * or <code>null</code> if the part is closed or has no selection.
+     */
+    public abstract ISelection getSelection();
+
+    /**
+     * Removes a selection listener from this tracker.
+     *
+     * @param listener the listener to remove
+     */
+    public void removeSelectionListener(ISelectionListener listener) {
+        fListeners.remove(listener);
+    }
+
+    /**
+     * Removes a post selection listener from this tracker.
+     *
+     * @param listener the listener to remove
+     */
+    public void removePostSelectionListener(ISelectionListener listener) {
+        postListeners.remove(listener);
+    }
+
+    /**
+     * Disposes this selection tracker.  This removes all listeners currently registered.
+     */
+    public void dispose() {
+        synchronized (fListeners) {
+			for (Object listener : fListeners.getListeners()) {
+                fListeners.remove(listener);
+                postListeners.remove(listener);
+            }
+        }
+    }
+
+    /**
+     * Fires a selection event to the listeners.
+     *
+     * @param part the part or <code>null</code> if no active part
+     * @param sel the selection or <code>null</code> if no active selection
+     * @param listeners the list of listeners to notify
+     */
+    protected void fireSelection(final IWorkbenchPart part, final ISelection sel) {
+		for (final ISelectionListener l : fListeners) {
+            if ((part != null && sel != null)
+                    || l instanceof INullSelectionListener) {
+                SafeRunner.run(new SafeRunnable() {
+                    @Override
+					public void run() {
+                        l.selectionChanged(part, sel);
+                    }
+                });
+            }
+        }
+    }
+
+    /**
+     * Fires a post selection event to the listeners.
+     *
+     * @param part the part or <code>null</code> if no active part
+     * @param sel the selection or <code>null</code> if no active selection
+     * @param listeners the list of listeners to notify
+     */
+    protected void firePostSelection(final IWorkbenchPart part,
+            final ISelection sel) {
+		for (final ISelectionListener l : postListeners) {
+            if ((part != null && sel != null)
+                    || l instanceof INullSelectionListener) {
+                SafeRunner.run(new SafeRunnable() {
+                    @Override
+					public void run() {
+                        l.selectionChanged(part, sel);
+                    }
+                });
+            }
+        }
+    }
+
+    /**
+     * Sets the id of the part that this tracks.
+     *
+     * @param id view identifier
+     */
+    private void setPartId(String partId) {
+        fPartId = partId;
+    }
+
+    /**
+     * Returns the id of the part that this tracks.
+     *
+     * @return part identifier
+     */
+    protected String getPartId() {
+        return fPartId;
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/AbstractSelectionService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/AbstractSelectionService.java
new file mode 100644
index 0000000..08471cb
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/AbstractSelectionService.java
@@ -0,0 +1,366 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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.ui.internal;
+
+import java.util.Hashtable;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.jface.viewers.IPostSelectionProvider;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.ui.INullSelectionListener;
+import org.eclipse.ui.ISelectionListener;
+import org.eclipse.ui.ISelectionService;
+import org.eclipse.ui.IWorkbenchPart;
+
+/**
+ * Abstract selection service.
+ */
+public abstract class AbstractSelectionService implements ISelectionService {
+
+    /**
+     * The list of selection listeners (not per-part).
+     */
+	private ListenerList<ISelectionListener> listeners = new ListenerList<>();
+
+    /**
+     * The list of post selection listeners (not per-part).
+     */
+	private ListenerList<ISelectionListener> postListeners = new ListenerList<>();
+
+    /**
+     * The currently active part.
+     */
+    private IWorkbenchPart activePart;
+
+    /**
+     * The active part's selection provider, remembered in case the part
+     * replaces its selection provider after we hooked a listener.
+     */
+    private ISelectionProvider activeProvider;
+
+    /**
+     * Map from part id (String) to per-part tracker (AbstractPartSelectionTracker).
+     */
+    private Hashtable perPartTrackers;
+
+    /**
+     * The JFace selection listener to hook on the active part's selection provider.
+     */
+    private ISelectionChangedListener selListener = event -> fireSelection(activePart, event.getSelection());
+
+    /**
+     * The JFace post selection listener to hook on the active part's selection provider.
+     */
+    private ISelectionChangedListener postSelListener = event -> firePostSelection(activePart, event.getSelection());
+
+    /**
+     * Creates a new SelectionService.
+     */
+    protected AbstractSelectionService() {
+    }
+
+    @Override
+	public void addSelectionListener(ISelectionListener l) {
+        listeners.add(l);
+    }
+
+    @Override
+	public void addSelectionListener(String partId, ISelectionListener listener) {
+        getPerPartTracker(partId).addSelectionListener(listener);
+    }
+
+    @Override
+	public void addPostSelectionListener(ISelectionListener l) {
+        postListeners.add(l);
+    }
+
+    @Override
+	public void addPostSelectionListener(String partId,
+            ISelectionListener listener) {
+        getPerPartTracker(partId).addPostSelectionListener(listener);
+    }
+
+    @Override
+	public void removeSelectionListener(ISelectionListener l) {
+        listeners.remove(l);
+    }
+
+    @Override
+	public void removePostSelectionListener(String partId,
+            ISelectionListener listener) {
+        getPerPartTracker(partId).removePostSelectionListener(listener);
+    }
+
+    @Override
+	public void removePostSelectionListener(ISelectionListener l) {
+        postListeners.remove(l);
+    }
+
+    @Override
+	public void removeSelectionListener(String partId,
+            ISelectionListener listener) {
+        getPerPartTracker(partId).removeSelectionListener(listener);
+    }
+
+    /**
+     * Fires a selection event to the given listeners.
+     *
+     * @param part the part or <code>null</code> if no active part
+     * @param sel the selection or <code>null</code> if no active selection
+     */
+    protected void fireSelection(final IWorkbenchPart part, final ISelection sel) {
+		for (final ISelectionListener l : listeners) {
+			if ((part != null && sel != null) || l instanceof INullSelectionListener) {
+                try {
+                    l.selectionChanged(part, sel);
+                } catch (Exception e) {
+                    WorkbenchPlugin.log(e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Fires a selection event to the given listeners.
+     *
+     * @param part the part or <code>null</code> if no active part
+     * @param sel the selection or <code>null</code> if no active selection
+     */
+    protected void firePostSelection(final IWorkbenchPart part,
+            final ISelection sel) {
+		for (final ISelectionListener l : postListeners) {
+			if ((part != null && sel != null) || l instanceof INullSelectionListener) {
+                try {
+                    l.selectionChanged(part, sel);
+                } catch (Exception e) {
+                    WorkbenchPlugin.log(e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns the per-part selection tracker for the given part id.
+     *
+     * @param partId part identifier
+     * @return per-part selection tracker
+     */
+    protected AbstractPartSelectionTracker getPerPartTracker(String partId) {
+        if (perPartTrackers == null) {
+            perPartTrackers = new Hashtable(4);
+        }
+        AbstractPartSelectionTracker tracker = (AbstractPartSelectionTracker) perPartTrackers
+                .get(partId);
+        if (tracker == null) {
+            tracker = createPartTracker(partId);
+            perPartTrackers.put(partId, tracker);
+        }
+        return tracker;
+    }
+
+    /**
+     * Creates a new per-part selection tracker for the given part id.
+     *
+     * @param partId part identifier
+     * @return per-part selection tracker
+     */
+    protected abstract AbstractPartSelectionTracker createPartTracker(
+            String partId);
+
+    /**
+     * Returns the selection.
+     */
+    @Override
+	public ISelection getSelection() {
+        if (activeProvider != null) {
+			return activeProvider.getSelection();
+		} else {
+			return null;
+		}
+    }
+
+    /*
+     * @see ISelectionService#getSelection(String)
+     */
+    @Override
+	public ISelection getSelection(String partId) {
+        return getPerPartTracker(partId).getSelection();
+    }
+
+    /**
+     * Sets the current-active part (or null if none)
+     *
+     * @since 3.1
+     *
+     * @param newPart the new active part (or null if none)
+     */
+    public void setActivePart(IWorkbenchPart newPart) {
+        // Optimize.
+        if (newPart == activePart) {
+			return;
+		}
+
+        ISelectionProvider selectionProvider = null;
+
+        if (newPart != null) {
+            selectionProvider = newPart.getSite().getSelectionProvider();
+
+            if (selectionProvider == null) {
+                newPart = null;
+            }
+        }
+
+        if (newPart == activePart) {
+			return;
+		}
+
+        if (activePart != null) {
+            if (activeProvider != null) {
+                activeProvider.removeSelectionChangedListener(selListener);
+                if (activeProvider instanceof IPostSelectionProvider) {
+					((IPostSelectionProvider) activeProvider)
+                            .removePostSelectionChangedListener(postSelListener);
+				} else {
+					activeProvider
+                            .removeSelectionChangedListener(postSelListener);
+				}
+                activeProvider = null;
+            }
+            activePart = null;
+        }
+
+        activePart = newPart;
+
+        if (newPart != null) {
+            activeProvider = selectionProvider;
+            // Fire an event if there's an active provider
+            activeProvider.addSelectionChangedListener(selListener);
+            ISelection sel = activeProvider.getSelection();
+            fireSelection(newPart, sel);
+            if (activeProvider instanceof IPostSelectionProvider) {
+				((IPostSelectionProvider) activeProvider)
+                        .addPostSelectionChangedListener(postSelListener);
+			} else {
+				activeProvider.addSelectionChangedListener(postSelListener);
+			}
+            firePostSelection(newPart, sel);
+        } else {
+            fireSelection(null, null);
+            firePostSelection(null, null);
+        }
+    }
+
+//    /**
+//     * Notifies the listener that a part has been activated.
+//     */
+//    public void partActivated(IWorkbenchPart newPart) {
+//        // Optimize.
+//        if (newPart == activePart)
+//            return;
+//
+//        // Unhook selection from the old part.
+//        reset();
+//
+//        // Update active part.
+//        activePart = newPart;
+//
+//        // Hook selection on the new part.
+//        if (activePart != null) {
+//            activeProvider = activePart.getSite().getSelectionProvider();
+//            if (activeProvider != null) {
+//                // Fire an event if there's an active provider
+//                activeProvider.addSelectionChangedListener(selListener);
+//                ISelection sel = activeProvider.getSelection();
+//                fireSelection(newPart, sel);
+//                if (activeProvider instanceof IPostSelectionProvider)
+//                    ((IPostSelectionProvider) activeProvider)
+//                            .addPostSelectionChangedListener(postSelListener);
+//                else
+//                    activeProvider.addSelectionChangedListener(postSelListener);
+//                firePostSelection(newPart, sel);
+//            } else {
+//                //Reset active part. activeProvider may not be null next time this method is called.
+//                activePart = null;
+//            }
+//        }
+//        // No need to fire an event if no active provider, since this was done in reset()
+//    }
+//
+//    /**
+//     * Notifies the listener that a part has been brought to the front.
+//     */
+//    public void partBroughtToTop(IWorkbenchPart newPart) {
+//        // do nothing, the active part has not changed,
+//        // so the selection is unaffected
+//    }
+//
+//    /**
+//     * Notifies the listener that a part has been closed
+//     */
+//    public void partClosed(IWorkbenchPart part) {
+//        // Unhook selection from the part.
+//        if (part == activePart) {
+//            reset();
+//        }
+//    }
+//
+//    /**
+//     * Notifies the listener that a part has been deactivated.
+//     */
+//    public void partDeactivated(IWorkbenchPart part) {
+//        // Unhook selection from the part.
+//        if (part == activePart) {
+//            reset();
+//        }
+//    }
+//
+//    /**
+//     * Notifies the listener that a part has been opened.
+//     */
+//    public void partOpened(IWorkbenchPart part) {
+//        // Wait for activation.
+//    }
+//
+//    /**
+//     * Notifies the listener that a part has been opened.
+//     */
+//    public void partInputChanged(IWorkbenchPart part) {
+//        // 36501 - only process if part is active
+//        if (activePart == part) {
+//            reset();
+//            partActivated(part);
+//        }
+//    }
+//
+//    /**
+//     * Resets the service.  The active part and selection provider are
+//     * dereferenced.
+//     */
+//    public void reset() {
+//        if (activePart != null) {
+//            fireSelection(null, null);
+//            firePostSelection(null, null);
+//            if (activeProvider != null) {
+//                activeProvider.removeSelectionChangedListener(selListener);
+//                if (activeProvider instanceof IPostSelectionProvider)
+//                    ((IPostSelectionProvider) activeProvider)
+//                            .removePostSelectionChangedListener(postSelListener);
+//                else
+//                    activeProvider
+//                            .removeSelectionChangedListener(postSelListener);
+//                activeProvider = null;
+//            }
+//            activePart = null;
+//        }
+//    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/AbstractWorkingSet.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/AbstractWorkingSet.java
new file mode 100644
index 0000000..f7ad163
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/AbstractWorkingSet.java
@@ -0,0 +1,231 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2016 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
+ *     Tomasz Zarna <tomasz.zarna@tasktop.com> - Bug 37183
+ *******************************************************************************/
+
+package org.eclipse.ui.internal;
+
+import java.util.ArrayList;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IPersistableElement;
+import org.eclipse.ui.IWorkingSet;
+import org.eclipse.ui.IWorkingSetManager;
+import org.eclipse.ui.internal.util.Util;
+
+/**
+ * Abstract baseclass for IWorkingSet implementations.
+ *
+ * @since 3.2
+ */
+public abstract class AbstractWorkingSet implements IAdaptable, IWorkingSet, Cloneable {
+
+	protected static final String FACTORY_ID = "org.eclipse.ui.internal.WorkingSetFactory"; //$NON-NLS-1$
+
+	static final String TAG_AGGREGATE = "aggregate"; //$NON-NLS-1$
+
+	private String name;
+
+	protected ArrayList elements;
+
+	private IWorkingSetManager manager;
+
+	protected IMemento workingSetMemento;
+
+	private String label;
+
+	//Workspace wide unique id for workingsets
+	private String uniqueId;
+
+	private static int counter;
+
+	/**
+	 * Whether or not the label value should follow the name value. It should do
+	 * this until a call to setLabel() differentiates it from the name.
+	 */
+	private boolean labelBoundToName;
+
+	/**
+	 * Create a new instance of this class
+	 *
+	 * @param name the unique name for this working set
+	 * @param label the user-friendly name for this working set
+	 */
+	public AbstractWorkingSet(String name, String label) {
+		Assert.isNotNull(name, "name must not be null"); //$NON-NLS-1$
+		this.name = name;
+		this.label = label;
+		labelBoundToName = Util.equals(name, label);
+		uniqueId = Long.toString(System.currentTimeMillis()) + "_" + counter++; //$NON-NLS-1$
+	}
+
+	/**
+	 * Returns the receiver if the requested type is either IWorkingSet
+	 * or IPersistableElement.
+	 *
+	 * @param adapter the requested type
+	 * @return the receiver if the requested type is either IWorkingSet
+	 * 	or IPersistableElement.
+	 */
+	@Override
+	public <T> T getAdapter(Class<T> adapter) {
+	    if (adapter == IWorkingSet.class
+	            || adapter == IPersistableElement.class) {
+			return adapter.cast(this);
+	    }
+	    return Platform.getAdapterManager().getAdapter(this, adapter);
+	}
+
+	@Override
+	public String getName() {
+	    return name;
+	}
+
+	@Override
+	public void setName(String newName) {
+	    Assert.isNotNull(newName, "Working set name must not be null"); //$NON-NLS-1$
+		if (manager != null) {
+			IWorkingSet wSet = manager.getWorkingSet(newName);
+			if (wSet != this) {
+				Assert.isTrue(wSet == null,
+						"working set with same name already registered"); //$NON-NLS-1$
+			}
+	    }
+
+	    AbstractWorkingSet oldWorkingSet = clone();
+	    name = newName;
+
+	    fireWorkingSetChanged(IWorkingSetManager.CHANGE_WORKING_SET_NAME_CHANGE, oldWorkingSet);
+
+	    if (labelBoundToName) {
+	    		setLabel(newName);
+	    }
+	}
+
+	/**
+	 * Connect this working set to a manger.
+	 *
+	 * @param manager the manager to connect to
+	 */
+	public void connect(IWorkingSetManager manager) {
+		Assert.isTrue(this.manager == null, "A working set can only be connected to one manager"); //$NON-NLS-1$
+		this.manager= manager;
+	}
+
+	/**
+	 * Disconnect this working set from its manager, if any.
+	 */
+	public void disconnect() {
+		this.manager= null;
+	}
+
+	protected void fireWorkingSetChanged(String property, Object oldValue) {
+		AbstractWorkingSetManager receiver= manager != null
+			? (AbstractWorkingSetManager)manager
+			: (AbstractWorkingSetManager)WorkbenchPlugin.getDefault().getWorkingSetManager();
+		receiver.workingSetChanged(this, property, oldValue);
+	}
+
+	/**
+	 * Create a copy of the elements to store in the receiver.
+	 *
+	 * @param elements the elements to store a copy of in the
+	 * 	receiver.
+	 */
+	protected void internalSetElements(IAdaptable[] newElements) {
+	    Assert.isNotNull(newElements,
+	            "Working set elements array must not be null"); //$NON-NLS-1$
+
+	    elements = new ArrayList(newElements.length);
+	    for (IAdaptable newElement : newElements) {
+	        elements.add(newElement);
+	    }
+	}
+
+	@Override
+	public IAdaptable[] getElements() {
+	    ArrayList list = getElementsArray();
+	    return (IAdaptable[]) list.toArray(new IAdaptable[list.size()]);
+	}
+
+	/**
+	 * Returns the elements array list. Lazily restores the elements from
+	 * persistence memento.
+	 *
+	 * @return the elements array list
+	 */
+	protected ArrayList getElementsArray() {
+	    if (elements == null) {
+	        restoreWorkingSet();
+	        workingSetMemento = null;
+	    }
+	    return elements;
+	}
+
+	abstract void restoreWorkingSet();
+
+	protected IWorkingSetManager getManager() {
+		return manager;
+	}
+
+	@Override
+	public String getFactoryId() {
+	    return FACTORY_ID;
+	}
+
+	@Override
+	public String getLabel() {
+		return label;
+	}
+
+	@Override
+	public void setLabel(String label) {
+		AbstractWorkingSet oldWorkingSet = clone();
+
+		this.label = label == null ? getName() : label;
+		labelBoundToName = Util.equals(label, name);  // rebind the label to the name
+
+		fireWorkingSetChanged(IWorkingSetManager.CHANGE_WORKING_SET_LABEL_CHANGE, oldWorkingSet);
+	}
+
+	@Override
+	public boolean isEmpty() {
+		return getElementsArray().isEmpty();
+	}
+
+    @Override
+	public final ImageDescriptor getImage() {
+        return getImageDescriptor();
+    }
+
+
+    /*package*/String getUniqueId() {
+		return uniqueId;
+	}
+
+	/*package*/void setUniqueId(String uniqueId) {
+		this.uniqueId = uniqueId;
+	}
+
+	@Override
+	protected AbstractWorkingSet clone() {
+		try {
+			AbstractWorkingSet clone = (AbstractWorkingSet) super.clone();
+			clone.disconnect();
+			return clone;
+		} catch (CloneNotSupportedException e) {
+			// ignore
+		}
+		return null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/AbstractWorkingSetManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/AbstractWorkingSetManager.java
new file mode 100644
index 0000000..8d890a6
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/AbstractWorkingSetManager.java
@@ -0,0 +1,900 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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.ui.internal;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import org.eclipse.core.commands.common.EventManager;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.dynamichelpers.ExtensionTracker;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IElementFactory;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IPersistableElement;
+import org.eclipse.ui.IWorkbenchPreferenceConstants;
+import org.eclipse.ui.IWorkingSet;
+import org.eclipse.ui.IWorkingSetElementAdapter;
+import org.eclipse.ui.IWorkingSetManager;
+import org.eclipse.ui.IWorkingSetUpdater;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.XMLMemento;
+import org.eclipse.ui.dialogs.IWorkingSetEditWizard;
+import org.eclipse.ui.dialogs.IWorkingSetNewWizard;
+import org.eclipse.ui.dialogs.IWorkingSetPage;
+import org.eclipse.ui.dialogs.IWorkingSetSelectionDialog;
+import org.eclipse.ui.internal.dialogs.WorkingSetEditWizard;
+import org.eclipse.ui.internal.dialogs.WorkingSetNewWizard;
+import org.eclipse.ui.internal.dialogs.WorkingSetSelectionDialog;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.registry.WorkingSetDescriptor;
+import org.eclipse.ui.internal.registry.WorkingSetRegistry;
+import org.eclipse.ui.internal.util.PrefUtil;
+import org.eclipse.ui.progress.WorkbenchJob;
+import org.eclipse.ui.statushandlers.StatusManager;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleListener;
+
+
+/**
+ * Abstract implementation of <code>IWorkingSetManager</code>.
+ */
+public abstract class AbstractWorkingSetManager extends EventManager implements
+		IWorkingSetManager, BundleListener, IExtensionChangeHandler {
+
+	static abstract class WorkingSetRunnable implements ISafeRunnable {
+
+		@Override
+		public void handleException(Throwable exception) {
+			StatusManager.getManager().handle(
+					StatusUtil.newStatus(PlatformUI.PLUGIN_ID, exception));
+		}
+	}
+
+	private SortedSet<AbstractWorkingSet> workingSets = new TreeSet<>((o1, o2) -> o1.getUniqueId().compareTo(o2.getUniqueId()));
+
+	private List<IWorkingSet> recentWorkingSets = new ArrayList<>();
+
+	private BundleContext bundleContext;
+	private Map<String, IWorkingSetUpdater> updaters = new HashMap<>();
+
+	private Map<String, IWorkingSetElementAdapter> elementAdapters = new HashMap<>();
+
+	private static final IWorkingSetUpdater NULL_UPDATER = new IWorkingSetUpdater() {
+		@Override
+		public void add(IWorkingSet workingSet) {
+		}
+		@Override
+		public boolean remove(IWorkingSet workingSet) {
+			return true;
+		}
+		@Override
+		public boolean contains(IWorkingSet workingSet) {
+			return true;
+		}
+		@Override
+		public void dispose() {
+		}
+	};
+
+	private static final IWorkingSetElementAdapter IDENTITY_ADAPTER = new IWorkingSetElementAdapter() {
+
+		@Override
+		public IAdaptable[] adaptElements(IWorkingSet ws, IAdaptable[] elements) {
+			return elements;
+		}
+
+		@Override
+		public void dispose() {
+		}
+	};
+
+	/**
+	 * Returns the descriptors for the given editable working set ids. If an id
+	 * refers to a missing descriptor, or one that is non-editable, it is
+	 * skipped. If <code>null</code> is passed, all editable descriptors are
+	 * returned.
+	 *
+	 * @param supportedWorkingSetIds
+	 *            the ids for the working set descriptors, or <code>null</code>
+	 *            for all editable descriptors
+	 * @return the descriptors corresponding to the given editable working set
+	 *         ids
+	 */
+	private static WorkingSetDescriptor[] getSupportedEditableDescriptors(String[] supportedWorkingSetIds) {
+		WorkingSetRegistry registry = WorkbenchPlugin.getDefault().getWorkingSetRegistry();
+		if (supportedWorkingSetIds == null) {
+			return registry.getNewPageWorkingSetDescriptors();
+		}
+		List<WorkingSetDescriptor> result = new ArrayList<>(supportedWorkingSetIds.length);
+		for (String supportedWorkingSetId : supportedWorkingSetIds) {
+			WorkingSetDescriptor desc = registry.getWorkingSetDescriptor(supportedWorkingSetId);
+			if (desc != null && desc.isEditable()) {
+				result.add(desc);
+			}
+		}
+		return result.toArray(new WorkingSetDescriptor[result.size()]);
+	}
+
+    protected AbstractWorkingSetManager(BundleContext context) {
+    	bundleContext= context;
+    	bundleContext.addBundleListener(this);
+    	PlatformUI.getWorkbench().getExtensionTracker().registerHandler(this, ExtensionTracker
+				.createExtensionPointFilter(getExtensionPointFilter()));
+	}
+
+	/**
+	 * Returns the working sets extension point.
+	 *
+	 * @return the working sets extension point
+	 * @since 3.3
+	 */
+	private IExtensionPoint getExtensionPointFilter() {
+        // RAP [bm]: namespace
+        return Platform.getExtensionRegistry().getExtensionPoint(
+                PlatformUI.PLUGIN_EXTENSION_NAME_SPACE,
+                IWorkbenchRegistryConstants.PL_WORKINGSETS);
+	}
+
+	@Override
+	public void dispose() {
+		bundleContext.removeBundleListener(this);
+		for (IWorkingSetUpdater next : updaters.values()) {
+			SafeRunner.run(new WorkingSetRunnable() {
+				@Override
+				public void run() throws Exception {
+					next.dispose();
+				}
+			});
+		}
+
+		for (IWorkingSetElementAdapter next : elementAdapters.values()) {
+			SafeRunner.run(new WorkingSetRunnable() {
+				@Override
+				public void run() throws Exception {
+					next.dispose();
+				}
+			});
+		}
+	}
+
+    //---- working set creation -----------------------------------------------------
+
+    @Override
+	public IWorkingSet createWorkingSet(String name, IAdaptable[] elements) {
+        return new WorkingSet(name, name, elements);
+    }
+
+    @Override
+	public IWorkingSet createAggregateWorkingSet(String name, String label,
+			IWorkingSet[] components) {
+		return new AggregateWorkingSet(name, label, components);
+	}
+
+    @Override
+	public IWorkingSet createWorkingSet(IMemento memento) {
+        return restoreWorkingSet(memento);
+    }
+
+    //---- working set management ---------------------------------------------------
+
+    @Override
+	public void addWorkingSet(IWorkingSet workingSet) {
+		IWorkingSet wSet = getWorkingSet(workingSet.getName());
+    	Assert.isTrue(wSet==null,"working set with same name already registered"); //$NON-NLS-1$
+        internalAddWorkingSet(workingSet);
+    }
+
+    private void internalAddWorkingSet(IWorkingSet workingSet) {
+		AbstractWorkingSet abstractWorkingSet = (AbstractWorkingSet) workingSet;
+		workingSets.add(abstractWorkingSet);
+		abstractWorkingSet.connect(this);
+		addToUpdater(workingSet);
+		firePropertyChange(CHANGE_WORKING_SET_ADD, null, workingSet);
+	}
+
+    protected boolean internalRemoveWorkingSet(IWorkingSet workingSet) {
+        boolean workingSetRemoved = workingSets.remove(workingSet);
+        boolean recentWorkingSetRemoved = recentWorkingSets.remove(workingSet);
+
+        if (workingSetRemoved) {
+        	((AbstractWorkingSet)workingSet).disconnect();
+        	removeFromUpdater(workingSet);
+            firePropertyChange(CHANGE_WORKING_SET_REMOVE, workingSet, null);
+        }
+        return workingSetRemoved || recentWorkingSetRemoved;
+    }
+
+	@Override
+	public IWorkingSet[] getWorkingSets() {
+		SortedSet<IWorkingSet> visibleSubset = new TreeSet<IWorkingSet>(WorkingSetComparator.getInstance());
+		for (IWorkingSet workingSet : workingSets) {
+			if (workingSet.isVisible()) {
+				visibleSubset.add(workingSet);
+			}
+		}
+		return visibleSubset.toArray(new IWorkingSet[visibleSubset.size()]);
+	}
+
+	@Override
+	public IWorkingSet[] getAllWorkingSets() {
+		IWorkingSet[] sets = workingSets.toArray(new IWorkingSet[workingSets.size()]);
+		Arrays.sort(sets, WorkingSetComparator.getInstance());
+		return sets;
+	}
+
+	@Override
+	public IWorkingSet getWorkingSet(String name) {
+		if (name == null || workingSets == null) {
+			return null;
+		}
+
+		for (IWorkingSet workingSet : workingSets) {
+			if (name.equals(workingSet.getName())) {
+				return workingSet;
+			}
+		}
+
+		return null;
+	}
+
+    // ---- recent working set management --------------------------------------
+
+    @Override
+	public IWorkingSet[] getRecentWorkingSets() {
+        return recentWorkingSets.toArray(new IWorkingSet[recentWorkingSets.size()]);
+    }
+
+    /**
+     * Adds the specified working set to the list of recently used
+     * working sets.
+     *
+     * @param workingSet working set to added to the list of recently
+     * 	used working sets.
+     */
+    protected void internalAddRecentWorkingSet(IWorkingSet workingSet) {
+    		if (!workingSet.isVisible()) {
+				return;
+			}
+        recentWorkingSets.remove(workingSet);
+        recentWorkingSets.add(0, workingSet);
+		sizeRecentWorkingSets();
+    }
+
+    //---- equals and hash code -----------------------------------------------
+
+    /**
+     * Tests the receiver and the object for equality
+     *
+     * @param object object to compare the receiver to
+     * @return true=the object equals the receiver, it has the same
+     * 	working sets. false otherwise
+     */
+    @Override
+	public boolean equals(Object object) {
+        if (this == object) {
+            return true;
+        }
+        if (!getClass().getName().equals(object.getClass().getName())) {
+			return false;
+		}
+        AbstractWorkingSetManager other= (AbstractWorkingSetManager)object;
+        return other.workingSets.equals(workingSets);
+    }
+
+    /**
+     * Returns the hash code.
+     *
+     * @return the hash code.
+     */
+    @Override
+	public int hashCode() {
+        return workingSets.hashCode();
+    }
+
+    //---- property listeners -------------------------------------------------
+
+    @Override
+	public void addPropertyChangeListener(IPropertyChangeListener listener) {
+        addListenerObject(listener);
+    }
+
+    @Override
+	public void removePropertyChangeListener(IPropertyChangeListener listener) {
+        removeListenerObject(listener);
+    }
+
+    /**
+     * Notify property change listeners about a change to the list of
+     * working sets.
+     *
+     * @param changeId one of
+     * 	IWorkingSetManager#CHANGE_WORKING_SET_ADD
+     * 	IWorkingSetManager#CHANGE_WORKING_SET_REMOVE
+     * 	IWorkingSetManager#CHANGE_WORKING_SET_CONTENT_CHANGE
+     * 	IWorkingSetManager#CHANGE_WORKING_SET_NAME_CHANGE
+     * @param oldValue the removed working set or null if a working set
+     * 	was added or changed.
+     * @param newValue the new or changed working set or null if a working
+     * 	set was removed.
+     */
+    protected void firePropertyChange(String changeId, Object oldValue,
+            Object newValue) {
+        final Object[] listeners = getListeners();
+
+        if (listeners.length == 0) {
+			return;
+		}
+
+        final PropertyChangeEvent event = new PropertyChangeEvent(this,
+                changeId, oldValue, newValue);
+		Runnable notifier = () -> {
+			for (Object listener : listeners) {
+				final IPropertyChangeListener propertyChangeListener = (IPropertyChangeListener) listener;
+				ISafeRunnable safetyWrapper = new ISafeRunnable() {
+
+					@Override
+					public void run() throws Exception {
+						propertyChangeListener.propertyChange(event);
+					}
+
+					@Override
+					public void handleException(Throwable exception) {
+						// logged by the runner
+					}
+				};
+				SafeRunner.run(safetyWrapper);
+			}
+		};
+		// Notifications are sent on the UI thread.
+		if (Display.getCurrent() != null) {
+			notifier.run();
+		} else {
+			// Use an asyncExec to avoid deadlocks.
+			Display.getDefault().asyncExec(notifier);
+		}
+	}
+
+	/**
+	 * Fires a property change event for the changed working set. Should only be
+	 * called by org.eclipse.ui.internal.WorkingSet.
+	 *
+	 * @param changedWorkingSet
+	 *            the working set that has changed
+	 * @param propertyChangeId
+	 *            the changed property. one of
+	 *            CHANGE_WORKING_SET_CONTENT_CHANGE,
+	 *            CHANGE_WORKING_SET_LABEL_CHANGE, and
+	 *            CHANGE_WORKING_SET_NAME_CHANGE
+	 * @param oldValue
+	 *            the old value
+	 */
+	public void workingSetChanged(IWorkingSet changedWorkingSet,
+			String propertyChangeId, Object oldValue) {
+		firePropertyChange(propertyChangeId, oldValue, changedWorkingSet);
+	}
+
+    // ---- Persistence
+	// ----------------------------------------------------------------
+
+    /**
+     * Saves all persistable working sets in the persistence store.
+     *
+     * @param memento the persistence store
+     * @see IPersistableElement
+     */
+    public void saveWorkingSetState(IMemento memento) {
+		Iterator<AbstractWorkingSet> iterator = workingSets.iterator();
+
+        // break the sets into aggregates and non aggregates.  The aggregates should be saved after the non-aggregates
+        // so that on restoration all necessary aggregate components can be found.
+
+		ArrayList<IWorkingSet> standardSets = new ArrayList<>();
+		ArrayList<IWorkingSet> aggregateSets = new ArrayList<>();
+		while (iterator.hasNext()) {
+			IWorkingSet set = iterator.next();
+			if (set instanceof AggregateWorkingSet) {
+				aggregateSets.add(set);
+			} else {
+				standardSets.add(set);
+			}
+		}
+
+        saveWorkingSetState(memento, standardSets);
+        saveWorkingSetState(memento, aggregateSets);
+    }
+
+	/**
+	 * @param memento the memento to save to
+	 * @param list the working sets to save
+	 * @since 3.2
+	 */
+	private void saveWorkingSetState(final IMemento memento, List list) {
+		for (Iterator i = list.iterator(); i.hasNext();) {
+            final IPersistableElement persistable = (IWorkingSet) i.next();
+			SafeRunner.run(new WorkingSetRunnable() {
+
+				@Override
+				public void run() throws Exception {
+					// create a dummy node to write too - the write could fail so we
+					// shouldn't soil the final memento until we're sure it succeeds.
+					XMLMemento dummy = XMLMemento.createWriteRoot(IWorkbenchConstants.TAG_WORKING_SET);
+					dummy.putString(IWorkbenchConstants.TAG_FACTORY_ID,
+							persistable.getFactoryId());
+					persistable.saveState(dummy);
+
+					// if the dummy was created successfully copy it to the real output
+					IMemento workingSetMemento = memento
+							.createChild(IWorkbenchConstants.TAG_WORKING_SET);
+					workingSetMemento.putMemento(dummy);
+				}
+			});
+
+        }
+	}
+
+    /**
+     * Recreates all working sets from the persistence store
+     * and adds them to the receiver.
+     *
+     * @param memento the persistence store
+     */
+	protected void restoreWorkingSetState(IMemento memento) {
+		for (IMemento child : memento.getChildren(IWorkbenchConstants.TAG_WORKING_SET)) {
+			AbstractWorkingSet workingSet = (AbstractWorkingSet) restoreWorkingSet(child);
+			if (workingSet != null) {
+				internalAddWorkingSet(workingSet);
+			}
+		}
+	}
+
+    /**
+     * Recreates a working set from the persistence store.
+     *
+     * @param memento the persistence store
+     * @return the working set created from the memento or null if
+     * 	creation failed.
+     */
+    protected IWorkingSet restoreWorkingSet(final IMemento memento) {
+        String factoryID = memento
+                .getString(IWorkbenchConstants.TAG_FACTORY_ID);
+
+        if (factoryID == null) {
+            // if the factory id was not set in the memento
+            // then assume that the memento was created using
+            // IMemento.saveState, and should be restored using WorkingSetFactory
+            factoryID = AbstractWorkingSet.FACTORY_ID;
+        }
+        final IElementFactory factory = PlatformUI.getWorkbench().getElementFactory(
+                factoryID);
+        if (factory == null) {
+            WorkbenchPlugin
+                    .log("Unable to restore working set - cannot instantiate factory: " + factoryID); //$NON-NLS-1$
+            return null;
+        }
+		final IAdaptable[] adaptable = new IAdaptable[1];
+		SafeRunner.run(new WorkingSetRunnable() {
+
+			@Override
+			public void run() throws Exception {
+				adaptable[0] = factory.createElement(memento);
+			}
+		});
+        if (adaptable[0] == null) {
+            WorkbenchPlugin
+                    .log("Unable to restore working set - cannot instantiate working set: " + factoryID); //$NON-NLS-1$
+            return null;
+        }
+        if ((adaptable[0] instanceof IWorkingSet) == false) {
+            WorkbenchPlugin
+                    .log("Unable to restore working set - element is not an IWorkingSet: " + factoryID); //$NON-NLS-1$
+            return null;
+        }
+        return (IWorkingSet) adaptable[0];
+    }
+
+    /**
+     * Saves the list of most recently used working sets in the persistence
+     * store.
+     *
+     * @param memento the persistence store
+     */
+    protected void saveMruList(IMemento memento) {
+        Iterator iterator = recentWorkingSets.iterator();
+
+        while (iterator.hasNext()) {
+            IWorkingSet workingSet = (IWorkingSet) iterator.next();
+            IMemento mruMemento = memento
+                    .createChild(IWorkbenchConstants.TAG_MRU_LIST);
+
+            mruMemento.putString(IWorkbenchConstants.TAG_NAME, workingSet
+                    .getName());
+        }
+    }
+
+   /**
+     * Restores the list of most recently used working sets from the
+     * persistence store.
+     *
+     * @param memento the persistence store
+     */
+    protected void restoreMruList(IMemento memento) {
+        IMemento[] mruWorkingSets = memento
+                .getChildren(IWorkbenchConstants.TAG_MRU_LIST);
+
+        for (int i = mruWorkingSets.length - 1; i >= 0; i--) {
+            String workingSetName = mruWorkingSets[i]
+                    .getString(IWorkbenchConstants.TAG_NAME);
+            if (workingSetName != null) {
+                IWorkingSet workingSet = getWorkingSet(workingSetName);
+                if (workingSet != null) {
+                    internalAddRecentWorkingSet(workingSet);
+                }
+            }
+        }
+    }
+
+    //---- user interface support -----------------------------------------------------
+
+    /**
+     * @see org.eclipse.ui.IWorkingSetManager#createWorkingSetEditWizard(org.eclipse.ui.IWorkingSet)
+     * @since 2.1
+     */
+    @Override
+	public IWorkingSetEditWizard createWorkingSetEditWizard(
+            IWorkingSet workingSet) {
+        String editPageId = workingSet.getId();
+        WorkingSetRegistry registry = WorkbenchPlugin.getDefault()
+                .getWorkingSetRegistry();
+        IWorkingSetPage editPage = null;
+
+        if (editPageId != null) {
+            editPage = registry.getWorkingSetPage(editPageId);
+        }
+
+        // the following block kind of defeats IWorkingSet.isEditable() and it
+		// doesn't make sense for there to be a default page in such a case.
+
+	     if (editPage == null) {
+			editPage = registry.getDefaultWorkingSetPage();
+			if (editPage == null) {
+				return null;
+			}
+		}
+
+        WorkingSetEditWizard editWizard = new WorkingSetEditWizard(editPage);
+        editWizard.setSelection(workingSet);
+        return editWizard;
+    }
+
+    /**
+     * @deprecated use createWorkingSetSelectionDialog(parent, true) instead
+     */
+    @Deprecated
+	@Override
+	public IWorkingSetSelectionDialog createWorkingSetSelectionDialog(
+            Shell parent) {
+        return createWorkingSetSelectionDialog(parent, true);
+    }
+
+    @Override
+	public IWorkingSetSelectionDialog createWorkingSetSelectionDialog(
+            Shell parent, boolean multi) {
+        return createWorkingSetSelectionDialog(parent, multi, null);
+    }
+
+    /**
+	 * {@inheritDoc}
+	 */
+    @Override
+	public IWorkingSetNewWizard createWorkingSetNewWizard(String[] workingSetIds) {
+         WorkingSetDescriptor[] descriptors= getSupportedEditableDescriptors(workingSetIds);
+         if (descriptors.length == 0) {
+			return null;
+		}
+         return new WorkingSetNewWizard(descriptors);
+}
+
+    //---- working set delta handling -------------------------------------------------
+
+	@Override
+	public void bundleChanged(BundleEvent event) {
+		String symbolicName = event.getBundle().getSymbolicName();
+		if (symbolicName == null)
+			return;
+		// If the workbench isn't running anymore simply return.
+		if (!PlatformUI.isWorkbenchRunning()) {
+			return;
+		}
+
+		if (event.getBundle().getState() == Bundle.ACTIVE) {
+			final WorkingSetDescriptor[] descriptors = WorkbenchPlugin.getDefault()
+					.getWorkingSetRegistry().getUpdaterDescriptorsForNamespace(
+							symbolicName);
+
+			Job job = new WorkbenchJob(
+					NLS
+							.bind(
+									WorkbenchMessages.get().AbstractWorkingSetManager_updatersActivating,
+									symbolicName)) {
+
+				@Override
+				public IStatus runInUIThread(IProgressMonitor monitor) {
+					synchronized (updaters) {
+						for (WorkingSetDescriptor descriptor : descriptors) {
+							List workingSets = getWorkingSetsForId(descriptor
+									.getId());
+							if (workingSets.size() == 0) {
+								continue;
+							}
+							final IWorkingSetUpdater updater = getUpdater(descriptor);
+							for (Iterator iter = workingSets.iterator(); iter
+									.hasNext();) {
+								final IWorkingSet workingSet = (IWorkingSet) iter
+										.next();
+								SafeRunner.run(new WorkingSetRunnable() {
+
+									@Override
+									public void run() throws Exception {
+										if (!updater.contains(workingSet)) {
+											updater.add(workingSet);
+										}
+									}
+								});
+							}
+						}
+					}
+					return Status.OK_STATUS;
+				}
+			};
+			job.setSystem(true);
+			job.schedule();
+		}
+	}
+
+	private List getWorkingSetsForId(String id) {
+		List result= new ArrayList();
+		for (IWorkingSet ws : workingSets) {
+    		if (id.equals(ws.getId())) {
+				result.add(ws);
+			}
+		}
+    	return result;
+	}
+
+    private void addToUpdater(final IWorkingSet workingSet) {
+    	WorkingSetDescriptor descriptor= WorkbenchPlugin.getDefault()
+			.getWorkingSetRegistry().getWorkingSetDescriptor(workingSet.getId());
+    	if (descriptor == null || !descriptor.isUpdaterClassLoaded()) {
+			return;
+		}
+		synchronized(updaters) {
+	    	final IWorkingSetUpdater updater= getUpdater(descriptor);
+	    	SafeRunner.run(new WorkingSetRunnable() {
+
+				@Override
+				public void run() throws Exception {
+					if (!updater.contains(workingSet)) {
+						updater.add(workingSet);
+					}
+				}});
+		}
+    }
+
+	private IWorkingSetUpdater getUpdater(WorkingSetDescriptor descriptor) {
+		IWorkingSetUpdater updater = updaters.get(descriptor.getId());
+		if (updater == null) {
+			updater = descriptor.createWorkingSetUpdater();
+			if (updater == null) {
+				updater = NULL_UPDATER;
+			} else {
+				firePropertyChange(CHANGE_WORKING_SET_UPDATER_INSTALLED, null, updater);
+				PlatformUI.getWorkbench().getExtensionTracker().registerObject(
+						descriptor.getConfigurationElement().getDeclaringExtension(), updater,
+						IExtensionTracker.REF_WEAK);
+
+			}
+			updaters.put(descriptor.getId(), updater);
+		}
+		return updater;
+	}
+
+	IWorkingSetElementAdapter getElementAdapter(WorkingSetDescriptor descriptor) {
+		IWorkingSetElementAdapter elementAdapter = elementAdapters.get(descriptor.getId());
+		if (elementAdapter == null) {
+			elementAdapter = descriptor.createWorkingSetElementAdapter();
+			if (elementAdapter == null) {
+				elementAdapter = IDENTITY_ADAPTER;
+			} else {
+				elementAdapters.put(descriptor.getId(), elementAdapter);
+			}
+		}
+		return elementAdapter;
+	}
+
+	private void removeFromUpdater(final IWorkingSet workingSet) {
+		synchronized (updaters) {
+			final IWorkingSetUpdater updater = updaters.get(workingSet.getId());
+			if (updater != null) {
+				SafeRunner.run(new WorkingSetRunnable() {
+
+					@Override
+					public void run() throws Exception {
+						updater.remove(workingSet);
+					}
+				});
+			}
+		}
+	}
+
+    @Override
+	public IWorkingSetSelectionDialog createWorkingSetSelectionDialog(Shell parent, boolean multi, String[] workingsSetIds) {
+        return new WorkingSetSelectionDialog(parent, multi, workingsSetIds);
+    }
+
+	/**
+	 * Save the state to the state file.
+	 *
+	 * @param stateFile
+	 * @throws IOException
+	 */
+	public void saveState(File stateFile) throws IOException {
+		XMLMemento memento = XMLMemento
+				.createWriteRoot(IWorkbenchConstants.TAG_WORKING_SET_MANAGER);
+		saveWorkingSetState(memento);
+		saveMruList(memento);
+
+		FileOutputStream stream = new FileOutputStream(stateFile);
+		OutputStreamWriter writer = new OutputStreamWriter(stream, StandardCharsets.UTF_8);
+		memento.save(writer);
+		writer.close();
+
+	}
+
+	@Override
+	public void addExtension(IExtensionTracker tracker, IExtension extension) {
+		// nothing - this is handled lazily.  These items are only created as needed by the getUpdater() and getElementAdapter() methods
+
+	}
+
+	@Override
+	public void removeExtension(IExtension extension, Object[] objects) {
+		for (Object object : objects) {
+			if (object instanceof IWorkingSetUpdater) {
+				removeUpdater((IWorkingSetUpdater)object);
+
+			}
+			if (object instanceof IWorkingSetElementAdapter) {
+				removeElementAdapter((IWorkingSetElementAdapter) object);
+			}
+		}
+	}
+
+	/**
+	 * Remove the element adapter from the manager and dispose of it.
+	 *
+	 * @param elementAdapter
+	 * @since 3.3
+	 */
+	private void removeElementAdapter(
+			final IWorkingSetElementAdapter elementAdapter) {
+		SafeRunner.run(new WorkingSetRunnable() {
+
+			@Override
+			public void run() throws Exception {
+				elementAdapter.dispose();
+
+			}
+		});
+		synchronized (elementAdapters) {
+			elementAdapters.values().remove(elementAdapter);
+		}
+	}
+
+	/**
+	 * Remove the updater from the manager and dispose of it.
+	 *
+	 * @param updater
+	 * @since 3.3
+	 */
+	private void removeUpdater(final IWorkingSetUpdater updater) {
+		SafeRunner.run(new WorkingSetRunnable() {
+
+			@Override
+			public void run() throws Exception {
+				updater.dispose();
+
+			}
+		});
+		synchronized (updaters) {
+			updaters.values().remove(updater);
+		}
+		firePropertyChange(IWorkingSetManager.CHANGE_WORKING_SET_UPDATER_UNINSTALLED, updater, null);
+	}
+
+	@Override
+	public void addToWorkingSets(final IAdaptable element, IWorkingSet[] workingSets) {
+		// ideally this method would be in a static util class of some kind but
+		// we dont have any such beast for working sets and making one for one
+		// method is overkill.
+		for (final IWorkingSet workingSet : workingSets) {
+			SafeRunner.run(new WorkingSetRunnable() {
+
+				@Override
+				public void run() throws Exception {
+					IAdaptable[] adaptedNewElements = workingSet
+							.adaptElements(new IAdaptable[] { element });
+					if (adaptedNewElements.length == 1) {
+						IAdaptable[] elements = workingSet.getElements();
+						IAdaptable[] newElements = new IAdaptable[elements.length + 1];
+						System.arraycopy(elements, 0, newElements, 0,
+								elements.length);
+						newElements[newElements.length - 1] = adaptedNewElements[0];
+						workingSet.setElements(newElements);
+					}
+				}});
+		}
+	}
+
+	@Override
+	public void setRecentWorkingSetsLength(int length) {
+		if (length < 1 || length > 99)
+			throw new IllegalArgumentException("Invalid recent working sets length: " + length); //$NON-NLS-1$
+		IPreferenceStore store = PrefUtil.getAPIPreferenceStore();
+		store.setValue(IWorkbenchPreferenceConstants.RECENTLY_USED_WORKINGSETS_SIZE, length);
+		// adjust length
+		sizeRecentWorkingSets();
+	}
+
+	private void sizeRecentWorkingSets() {
+		int maxLength = getRecentWorkingSetsLength();
+		while (recentWorkingSets.size() > maxLength) {
+			int lastPosition = recentWorkingSets.size() - 1;
+			recentWorkingSets.remove(lastPosition);
+		}
+	}
+
+	@Override
+	public int getRecentWorkingSetsLength() {
+		IPreferenceStore store = PrefUtil.getAPIPreferenceStore();
+		return store.getInt(IWorkbenchPreferenceConstants.RECENTLY_USED_WORKINGSETS_SIZE);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ActionDescriptor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ActionDescriptor.java
new file mode 100644
index 0000000..2274ec2
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ActionDescriptor.java
@@ -0,0 +1,382 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.ActionContributionItem;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IPluginContribution;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IWorkbenchActionConstants;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+/**
+ * When 'action' tag is found in the registry, an object of this
+ * class is created. It creates the appropriate action object
+ * and captures information that is later used to add this action
+ * object into menu/tool bar. This class is reused for
+ * global (workbench) menu/tool bar, popup menu actions,
+ * as well as view's pulldown and local tool bar.
+ */
+public class ActionDescriptor implements IPluginContribution {
+    private PluginAction action;
+
+    private String toolbarId;
+
+    private String menuPath;
+
+    private String id;
+
+    private String pluginId;
+
+    private String menuGroup;
+
+    private String toolbarGroupId;
+
+	private int mode = 0;
+
+    /**
+     * Popup constant.  Value <code>0x1</code>.
+     */
+    public static final int T_POPUP = 0x1;
+
+    /**
+     * View constant.  Value <code>0x2</code>.
+     */
+    public static final int T_VIEW = 0x2;
+
+    /**
+     * Workbench constant.  Value <code>0x3</code>.
+     */
+    public static final int T_WORKBENCH = 0x3;
+
+    /**
+     * Editor constant.  Value <code>0x4</code>.
+     */
+    public static final int T_EDITOR = 0x4;
+
+    /**
+     * Workbench pulldown constant.  Value <code>0x5</code>.
+     */
+    public static final int T_WORKBENCH_PULLDOWN = 0x5;
+
+    /**
+     * Push style constant.  Value <code>push</code>.
+     */
+    public static final String STYLE_PUSH = "push"; //$NON-NLS-1$
+
+    /**
+     * Radio style constant.  Value <code>radio</code>.
+     */
+    public static final String STYLE_RADIO = "radio"; //$NON-NLS-1$
+
+    /***
+     * Toggle style constant.  Value <code>toggle</code>.
+     */
+    public static final String STYLE_TOGGLE = "toggle"; //$NON-NLS-1$
+
+    /**
+     * Pulldown style constant.  Value <code>pulldown</code>.
+     */
+    public static final String STYLE_PULLDOWN = "pulldown"; //$NON-NLS-1$
+
+    /**
+     * Creates a new descriptor with the specified target.
+     *
+     * @param actionElement the configuration element
+     * @param targetType the type of action
+     */
+    public ActionDescriptor(IConfigurationElement actionElement, int targetType) {
+        this(actionElement, targetType, null);
+    }
+
+    /**
+     * Creates a new descriptor with the target and destination workbench part
+     * it will go into.
+     *
+     * @param actionElement the configuration element
+     * @param targetType the type of action
+     * @param target the target object
+     */
+    public ActionDescriptor(IConfigurationElement actionElement,
+            int targetType, Object target) {
+        // Load attributes.
+        id = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+        pluginId = actionElement.getNamespace();
+        String label = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_LABEL);
+        String tooltip = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_TOOLTIP);
+        String helpContextId = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_HELP_CONTEXT_ID);
+        String mpath = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_MENUBAR_PATH);
+        String tpath = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_TOOLBAR_PATH);
+        String style = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_STYLE);
+        String icon = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_ICON);
+        String hoverIcon = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_HOVERICON);
+        String disabledIcon = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_DISABLEDICON);
+        String description = actionElement.getAttribute(IWorkbenchRegistryConstants.TAG_DESCRIPTION);
+        String accelerator = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_ACCELERATOR);
+        if ("FORCE_TEXT".equals(actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_MODE))) { //$NON-NLS-1$
+        	mode  = ActionContributionItem.MODE_FORCE_TEXT;
+        }
+
+        // Verify input.
+        if (label == null) {
+            WorkbenchPlugin
+                    .log("Invalid action declaration (label == null): " + id); //$NON-NLS-1$
+            label = WorkbenchMessages.get().ActionDescriptor_invalidLabel;
+        }
+
+        // Calculate menu and toolbar paths.
+        String mgroup = null;
+        String tgroup = null;
+        if (mpath != null) {
+            int loc = mpath.lastIndexOf('/');
+            if (loc != -1) {
+                mgroup = mpath.substring(loc + 1);
+                mpath = mpath.substring(0, loc);
+            } else {
+                mgroup = mpath;
+                mpath = null;
+            }
+        }
+        if (targetType == T_POPUP && mgroup == null) {
+			mgroup = IWorkbenchActionConstants.MB_ADDITIONS;
+		}
+        if (tpath != null) {
+            int loc = tpath.lastIndexOf('/');
+            if (loc != -1) {
+                tgroup = tpath.substring(loc + 1);
+                tpath = tpath.substring(0, loc);
+            } else {
+                tgroup = tpath;
+                tpath = null;
+            }
+        }
+        menuPath = mpath;
+        menuGroup = mgroup;
+        if ((tpath != null) && tpath.equals("Normal")) { //$NON-NLS-1$
+			tpath = ""; //$NON-NLS-1$
+		}
+        toolbarId = tpath;
+        toolbarGroupId = tgroup;
+
+        // Create action.
+        action = createAction(targetType, actionElement, target, style);
+        if (action.getText() == null) {
+			action.setText(label);
+		}
+        if (action.getToolTipText() == null && tooltip != null) {
+			action.setToolTipText(tooltip);
+		}
+        if (helpContextId != null) {
+            String fullID = helpContextId;
+            if (helpContextId.indexOf(".") == -1) { //$NON-NLS-1$
+				// For backward compatibility we auto qualify the id if it is not
+                // qualified)
+                fullID = actionElement.getNamespace()
+                        + "." + helpContextId;//$NON-NLS-1$
+			}
+            PlatformUI.getWorkbench().getHelpSystem().setHelp(action, fullID);
+        }
+        if (description != null) {
+			action.setDescription(description);
+		}
+
+        if (style != null) {
+            // Since 2.1, the "state" and "pulldown" attributes means something different
+            // when the new "style" attribute has been set. See doc for more info.
+            String state = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_STATE);
+            if (state != null) {
+                if (style.equals(STYLE_RADIO) || style.equals(STYLE_TOGGLE)) {
+					action.setChecked(state.equals("true"));//$NON-NLS-1$
+				}
+            }
+        } else {
+            // Keep for backward compatibility for actions not using the
+            // new style attribute.
+            String state = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_STATE);
+            if (state != null) {
+                action.setChecked(state.equals("true"));//$NON-NLS-1$
+            }
+        }
+
+        String extendingPluginId = actionElement.getDeclaringExtension()
+                .getNamespace();
+
+        if (icon != null) {
+            action.setImageDescriptor(AbstractUIPlugin
+                    .imageDescriptorFromPlugin(extendingPluginId, icon));
+        }
+        if (hoverIcon != null) {
+            action.setHoverImageDescriptor(AbstractUIPlugin
+                    .imageDescriptorFromPlugin(extendingPluginId, hoverIcon));
+        }
+        if (disabledIcon != null) {
+            action
+                    .setDisabledImageDescriptor(AbstractUIPlugin
+                            .imageDescriptorFromPlugin(extendingPluginId,
+                                    disabledIcon));
+        }
+
+        if (accelerator != null) {
+			processAccelerator(action, accelerator);
+		}
+    }
+
+    /**
+     * Creates an instance of PluginAction. Depending on the target part,
+     * subclasses of this class may be created.
+     */
+    private PluginAction createAction(int targetType,
+            IConfigurationElement actionElement, Object target, String style) {
+        int actionStyle = IAction.AS_UNSPECIFIED;
+        if (style != null) {
+            if (style.equals(STYLE_RADIO)) {
+                actionStyle = IAction.AS_RADIO_BUTTON;
+            } else if (style.equals(STYLE_TOGGLE)) {
+                actionStyle = IAction.AS_CHECK_BOX;
+            } else if (style.equals(STYLE_PULLDOWN)) {
+                actionStyle = IAction.AS_DROP_DOWN_MENU;
+            } else if (style.equals(STYLE_PUSH)) {
+                actionStyle = IAction.AS_PUSH_BUTTON;
+            }
+        }
+
+        switch (targetType) {
+        case T_VIEW:
+            return new ViewPluginAction(actionElement, (IViewPart) target, id,
+                    actionStyle);
+        case T_EDITOR:
+            return new EditorPluginAction(actionElement, (IEditorPart) target,
+                    id, actionStyle);
+        case T_WORKBENCH:
+            return new WWinPluginAction(actionElement,
+                    (IWorkbenchWindow) target, id, actionStyle);
+        case T_WORKBENCH_PULLDOWN:
+            actionStyle = IAction.AS_DROP_DOWN_MENU;
+            return new WWinPluginPulldown(actionElement,
+                    (IWorkbenchWindow) target, id, actionStyle);
+        case T_POPUP:
+            return new ObjectPluginAction(actionElement, id, actionStyle);
+        default:
+            WorkbenchPlugin.log("Unknown Action Type: " + targetType);//$NON-NLS-1$
+            return null;
+        }
+    }
+
+    /**
+     * Returns the action object held in this descriptor.
+     *
+     * @return the action
+     */
+    public PluginAction getAction() {
+        return action;
+    }
+
+    /**
+     * Returns action's id as defined in the registry.
+     *
+     * @return the id
+     */
+    public String getId() {
+        return id;
+    }
+
+    /**
+     * Returns named slot (group) in the menu where this action
+     * should be added.
+     *
+     * @return the menu group
+     */
+    public String getMenuGroup() {
+        return menuGroup;
+    }
+
+    /**
+     * Returns menu path where this action should be added. If null,
+     * the action will not be added into the menu.
+     *
+     * @return the menubar path
+     */
+    public String getMenuPath() {
+        return menuPath;
+    }
+
+    /**
+     * Returns the named slot (group) in the tool bar where this
+     * action should be added.
+     *
+     * @return the toolbar group id
+     */
+    public String getToolbarGroupId() {
+        return toolbarGroupId;
+    }
+
+    /**
+     * Returns id of the tool bar where this action should be added.
+     * If null, action will not be added to the tool bar.
+     *
+     * @return the toolbar id
+     */
+    public String getToolbarId() {
+        return toolbarId;
+    }
+
+    /**
+     * For debugging only.
+     */
+    @Override
+	public String toString() {
+        return "ActionDescriptor(" + id + ")";//$NON-NLS-2$//$NON-NLS-1$
+    }
+
+    /**
+     * Process the accelerator definition. If it is a number
+     * then process the code directly - if not then parse it
+     * and create the code
+     */
+    private void processAccelerator(IAction action, String acceleratorText) {
+
+        if (acceleratorText.length() == 0) {
+			return;
+		}
+
+        //Is it a numeric definition?
+        if (Character.isDigit(acceleratorText.charAt(0))) {
+            try {
+                action.setAccelerator(Integer.valueOf(acceleratorText)
+                        .intValue());
+            } catch (NumberFormatException e) {
+                WorkbenchPlugin.log("Invalid accelerator declaration for action: " + id, e); //$NON-NLS-1$
+            }
+        } else {
+			action.setAccelerator(Action.convertAccelerator(acceleratorText));
+		}
+    }
+
+    @Override
+	public String getLocalId() {
+        return getId();
+    }
+
+    @Override
+	public String getPluginId() {
+        return pluginId;
+    }
+
+    public int getMode() {
+    	return mode;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ActionExpression.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ActionExpression.java
new file mode 100644
index 0000000..666222d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ActionExpression.java
@@ -0,0 +1,1058 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.IActionFilter;
+import org.eclipse.ui.internal.util.BundleUtility;
+import org.eclipse.ui.internal.util.Util;
+import org.osgi.framework.Bundle;
+
+/**
+ * An ActionExpression is used to evaluate the enablement / visibility criteria
+ * for an action.
+ */
+public class ActionExpression {
+
+	private static abstract class AbstractExpression {
+
+		/**
+		 * The hash code for this object. This value is computed lazily, and
+		 * marked as invalid when one of the values on which it is based
+		 * changes.
+		 */
+		protected transient int expressionHashCode = HASH_CODE_NOT_COMPUTED;
+
+		/**
+		 * Extract the object class tests from the expression. This allows
+		 * clients (e.g. the decorator manager) to handle object class testing
+		 * in a more optimized way. This method extracts the objectClass test
+		 * from the expression and returns the object classes. The expression is
+		 * not changed and a <code>null</code> is returned if no object class
+		 * is found.
+		 *
+		 * @return String[] the object class names or <code>null</code> if
+		 *         none was found.
+		 */
+		public String[] extractObjectClasses() {
+			return null;
+		}
+
+		/**
+		 * Returns whether the expression is valid for the given object.
+		 *
+		 * @param object
+		 *            the object to validate against (can be <code>null</code>)
+		 * @return boolean whether the expression is valid for the object.
+		 */
+		public abstract boolean isEnabledFor(Object object);
+
+		/**
+		 * Returns whether or not the receiver is potentially valid for the
+		 * object via just the extension type. Currently the only supported
+		 * expression type is <code>EXP_TYPE_OBJECT_CLASS</code>.
+		 *
+		 * @param object
+		 *            the object to validate against (can be <code>null</code>)
+		 * @param expressionType
+		 *            the expression type to consider
+		 * @return boolean whether the expression is potentially valid for the
+		 *         object.
+		 */
+		public boolean isEnabledForExpression(Object object,
+				String expressionType) {
+			return false;
+		}
+
+		/**
+		 * Return the value of the expression type that the receiver is enabled
+		 * for. If the receiver is not enabled for the expressionType then
+		 * return <code>null</code>.
+		 *
+		 * @param expressionType
+		 *            the expression type to consider
+		 * @return Collection of String if there are values for this expression
+		 *         or <code>null</code> if this is not possible in the
+		 *         receiver or any of it's children
+		 */
+		public Collection valuesForExpression(String expressionType) {
+			return null;
+		}
+	}
+
+	private static class AndExpression extends CompositeExpression {
+
+		/**
+		 * Creates and populates the expression from the attributes and sub-
+		 * elements of the configuration element.
+		 *
+		 * @param element
+		 *            The element that will be used to determine the expressions
+		 *            for And.
+		 * @throws IllegalStateException
+		 *             if the expression tag is not defined in the schema.
+		 */
+		public AndExpression(IConfigurationElement element)
+				throws IllegalStateException {
+			super(element);
+		}
+
+		@Override
+		public final boolean equals(final Object object) {
+			if (object instanceof AndExpression) {
+				final AndExpression that = (AndExpression) object;
+				return Util.equals(this.list, that.list);
+			}
+
+			return false;
+		}
+
+		@Override
+		public boolean isEnabledFor(Object object) {
+			Iterator iter = list.iterator();
+			while (iter.hasNext()) {
+				AbstractExpression expr = (AbstractExpression) iter.next();
+				if (!expr.isEnabledFor(object)) {
+					return false;
+				}
+			}
+			return true;
+		}
+	}
+
+	private static abstract class CompositeExpression extends
+			AbstractExpression {
+		/**
+		 *
+		 */
+		protected ArrayList list;
+
+		/**
+		 * Creates and populates the expression from the attributes and sub-
+		 * elements of the configuration element.
+		 *
+		 * @param element
+		 *            The composite element we will create the expression from.
+		 * @throws IllegalStateException
+		 *             if the expression tag is not defined in the schema.
+		 */
+		public CompositeExpression(IConfigurationElement element)
+				throws IllegalStateException {
+			super();
+
+			IConfigurationElement[] children = element.getChildren();
+			if (children.length == 0) {
+				throw new IllegalStateException(
+						"Composite expression cannot be empty"); //$NON-NLS-1$
+			}
+
+			list = new ArrayList(children.length);
+			for (IConfigurationElement configElement : children) {
+				String tag = configElement.getName();
+				AbstractExpression expr = createExpression(configElement);
+				if (EXP_TYPE_OBJECT_CLASS.equals(tag)) {
+					list.add(0, expr);
+				} else {
+					list.add(expr);
+				}
+			}
+		}
+
+		@Override
+		public String[] extractObjectClasses() {
+			Iterator iterator = list.iterator();
+			List classNames = null;
+			while (iterator.hasNext()) {
+				AbstractExpression next = (AbstractExpression) iterator.next();
+				String[] objectClasses = next.extractObjectClasses();
+				if (objectClasses != null) {
+					if (classNames == null) {
+						classNames = new ArrayList();
+					}
+					for (String objectClass : objectClasses) {
+						classNames.add(objectClass);
+					}
+				}
+			}
+			if (classNames == null) {
+				return null;
+			}
+
+			String[] returnValue = new String[classNames.size()];
+			classNames.toArray(returnValue);
+			return returnValue;
+		}
+
+		/**
+		 * Computes the hash code for this object based on the id.
+		 *
+		 * @return The hash code for this object.
+		 */
+		@Override
+		public final int hashCode() {
+			if (expressionHashCode == HASH_CODE_NOT_COMPUTED) {
+				expressionHashCode = HASH_INITIAL * HASH_FACTOR + Util.hashCode(list);
+				if (expressionHashCode == HASH_CODE_NOT_COMPUTED) {
+					expressionHashCode++;
+				}
+			}
+			return expressionHashCode;
+		}
+
+		@Override
+		public boolean isEnabledForExpression(Object object,
+				String expressionType) {
+			Iterator iterator = list.iterator();
+			while (iterator.hasNext()) {
+				AbstractExpression next = (AbstractExpression) iterator.next();
+				if (next.isEnabledForExpression(object, expressionType)) {
+					return true;
+				}
+			}
+			return false;
+		}
+
+		@Override
+		public Collection valuesForExpression(String expressionType) {
+			Iterator iterator = list.iterator();
+			Collection allValues = null;
+			while (iterator.hasNext()) {
+				AbstractExpression next = (AbstractExpression) iterator.next();
+				Collection values = next.valuesForExpression(expressionType);
+				if (values != null) {
+					if (allValues == null) {
+						allValues = values;
+					} else {
+						allValues.addAll(values);
+					}
+				}
+
+			}
+			return allValues;
+		}
+	}
+
+	private static class NotExpression extends SingleExpression {
+
+		/**
+		 * Creates and populates the expression from the attributes and sub-
+		 * elements of the configuration element.
+		 *
+		 * @param element
+		 *            The element that will be used to create the definition for
+		 *            the receiver.
+		 * @throws IllegalStateException
+		 *             if the expression tag is not defined in the schema.
+		 */
+		public NotExpression(IConfigurationElement element)
+				throws IllegalStateException {
+			super(element);
+		}
+
+		@Override
+		public boolean isEnabledFor(Object object) {
+			return !super.isEnabledFor(object);
+		}
+	}
+
+	private static class ObjectClassExpression extends AbstractExpression {
+		private String className;
+
+		private boolean extracted;
+
+		/**
+		 * Creates and populates the expression from the attributes and sub-
+		 * elements of the configuration element.
+		 *
+		 * @param element
+		 *            The element that will be used to determine the expressions
+		 *            for objectClass.
+		 * @throws IllegalStateException
+		 *             if the expression tag is not defined in the schema.
+		 */
+		public ObjectClassExpression(IConfigurationElement element)
+				throws IllegalStateException {
+			super();
+
+			className = element.getAttribute(ATT_NAME);
+			if (className == null) {
+				throw new IllegalStateException(
+						"Object class expression missing name attribute"); //$NON-NLS-1$
+			}
+		}
+
+		/**
+		 * Create an ObjectClass expression based on the className. Added for
+		 * backwards compatibility.
+		 *
+		 * @param className
+		 */
+		public ObjectClassExpression(String className) {
+			super();
+
+			if (className != null) {
+				this.className = className;
+			} else {
+				throw new IllegalStateException(
+						"Object class expression must have class name"); //$NON-NLS-1$
+			}
+		}
+
+		/**
+		 * Check the interfaces the whole way up. If one of them matches
+		 * className return <code>true</code>.
+		 *
+		 * @param interfaceToCheck
+		 *            The interface whose name we are testing against.
+		 * @return <code>true</code> if one of the interfaces in the hierarchy
+		 *         matches className, <code>false</code> otherwise.
+		 */
+		private boolean checkInterfaceHierarchy(Class interfaceToCheck) {
+			if (interfaceToCheck.getName().equals(className)) {
+				return true;
+			}
+			Class[] superInterfaces = interfaceToCheck.getInterfaces();
+			for (Class superInterface : superInterfaces) {
+				if (checkInterfaceHierarchy(superInterface)) {
+					return true;
+				}
+			}
+			return false;
+		}
+
+		@Override
+		public final boolean equals(final Object object) {
+			if (object instanceof ObjectClassExpression) {
+				final ObjectClassExpression that = (ObjectClassExpression) object;
+				return Util.equals(this.className, that.className)
+						&& Util.equals(this.extracted, that.extracted);
+			}
+
+			return false;
+		}
+
+		@Override
+		public String[] extractObjectClasses() {
+			extracted = true;
+			return new String[] { className };
+		}
+
+		/**
+		 * Computes the hash code for this object based on the id.
+		 *
+		 * @return The hash code for this object.
+		 */
+		@Override
+		public final int hashCode() {
+			if (expressionHashCode == HASH_CODE_NOT_COMPUTED) {
+				expressionHashCode = HASH_INITIAL * HASH_FACTOR
+						+ Util.hashCode(className);
+				expressionHashCode = expressionHashCode * HASH_FACTOR + Util.hashCode(extracted);
+				if (expressionHashCode == HASH_CODE_NOT_COMPUTED) {
+					expressionHashCode++;
+				}
+			}
+			return expressionHashCode;
+		}
+
+		@Override
+		public boolean isEnabledFor(Object object) {
+			if (object == null) {
+				return false;
+			}
+			if (extracted) {
+				return true;
+			}
+
+			Class clazz = object.getClass();
+			while (clazz != null) {
+				// test the class itself
+				if (clazz.getName().equals(className)) {
+					return true;
+				}
+
+				// test all the interfaces the class implements
+				Class[] interfaces = clazz.getInterfaces();
+				for (Class currentInterface : interfaces) {
+					if (checkInterfaceHierarchy(currentInterface)) {
+						return true;
+					}
+				}
+
+				// get the superclass
+				clazz = clazz.getSuperclass();
+			}
+
+			return false;
+		}
+
+		@Override
+		public boolean isEnabledForExpression(Object object,
+				String expressionType) {
+			if (expressionType.equals(EXP_TYPE_OBJECT_CLASS)) {
+				return isEnabledFor(object);
+			}
+			return false;
+		}
+	}
+
+	private static class ObjectStateExpression extends AbstractExpression {
+		private String name;
+
+		private String value;
+
+		/**
+		 * Creates and populates the expression from the attributes and sub-
+		 * elements of the configuration element.
+		 *
+		 * @param element
+		 *            The element that will be used to determine the expressions
+		 *            for objectState.
+		 * @throws IllegalStateException
+		 *             if the expression tag is not defined in the schema.
+		 */
+		public ObjectStateExpression(IConfigurationElement element)
+				throws IllegalStateException {
+			super();
+
+			name = element.getAttribute(ATT_NAME);
+			value = element.getAttribute(ATT_VALUE);
+			if (name == null || value == null) {
+				throw new IllegalStateException(
+						"Object state expression missing attribute"); //$NON-NLS-1$
+			}
+		}
+
+		@Override
+		public final boolean equals(final Object object) {
+			if (object instanceof ObjectStateExpression) {
+				final ObjectStateExpression that = (ObjectStateExpression) object;
+				return Util.equals(this.name, that.name)
+						&& Util.equals(this.value, that.value);
+			}
+
+			return false;
+		}
+
+		private IActionFilter getActionFilter(Object object) {
+			return Adapters.adapt(object, IActionFilter.class);
+		}
+
+		/**
+		 * Computes the hash code for this object based on the id.
+		 *
+		 * @return The hash code for this object.
+		 */
+		@Override
+		public final int hashCode() {
+			if (expressionHashCode == HASH_CODE_NOT_COMPUTED) {
+				expressionHashCode = HASH_INITIAL * HASH_FACTOR + Util.hashCode(name);
+				expressionHashCode = expressionHashCode * HASH_FACTOR + Util.hashCode(value);
+				if (expressionHashCode == HASH_CODE_NOT_COMPUTED) {
+					expressionHashCode++;
+				}
+			}
+			return expressionHashCode;
+		}
+
+		@Override
+		public boolean isEnabledFor(Object object) {
+			if (object == null) {
+				return false;
+			}
+
+			// Try out the object first.
+			if (preciselyMatches(object)) {
+				return true;
+			}
+
+			// Try out the underlying resource.
+			Class resourceClass = LegacyResourceSupport.getResourceClass();
+			if (resourceClass == null) {
+				return false;
+			}
+
+			if (resourceClass.isInstance(object)) {
+				return false;
+			}
+
+			Object res = Adapters.adapt(object, resourceClass);
+			if (res == null) {
+				return false;
+			}
+
+			return preciselyMatches(res);
+
+		}
+
+		private boolean preciselyMatches(Object object) {
+			// Get the action filter.
+			IActionFilter filter = getActionFilter(object);
+			if (filter == null) {
+				return false;
+			}
+
+			// Run the action filter.
+			return filter.testAttribute(object, name, value);
+		}
+
+		@Override
+		public Collection valuesForExpression(String expressionType) {
+			if (expressionType.equals(name)) {
+				Collection returnValue = new HashSet();
+				returnValue.add(value);
+				return returnValue;
+			}
+			return null;
+		}
+
+	}
+
+	private static class OrExpression extends CompositeExpression {
+
+		/**
+		 * Creates and populates the expression from the attributes and sub-
+		 * elements of the configuration element.
+		 *
+		 * @param element
+		 *            The element that will be used to determine the expressions
+		 *            for Or.
+		 * @throws IllegalStateException
+		 *             if the expression tag is not defined in the schema.
+		 */
+		public OrExpression(IConfigurationElement element)
+				throws IllegalStateException {
+			super(element);
+		}
+
+		@Override
+		public final boolean equals(final Object object) {
+			if (object instanceof OrExpression) {
+				final OrExpression that = (OrExpression) object;
+				return Util.equals(this.list, that.list);
+			}
+
+			return false;
+		}
+
+		@Override
+		public boolean isEnabledFor(Object object) {
+			Iterator iter = list.iterator();
+			while (iter.hasNext()) {
+				AbstractExpression expr = (AbstractExpression) iter.next();
+				if (expr.isEnabledFor(object)) {
+					return true;
+				}
+			}
+			return false;
+		}
+	}
+
+	private static class PluginStateExpression extends AbstractExpression {
+		private String id;
+
+		private String value;
+
+		/**
+		 * Creates and populates the expression from the attributes and sub-
+		 * elements of the configuration element.
+		 *
+		 * @param element
+		 *            The element that will be used to determine the expressions
+		 *            for pluginState.
+		 * @throws IllegalStateException
+		 *             if the expression tag is not defined in the schema.
+		 */
+		public PluginStateExpression(IConfigurationElement element)
+				throws IllegalStateException {
+			super();
+
+			id = element.getAttribute(ATT_ID);
+			value = element.getAttribute(ATT_VALUE);
+			if (id == null || value == null) {
+				throw new IllegalStateException(
+						"Plugin state expression missing attribute"); //$NON-NLS-1$
+			}
+		}
+
+		@Override
+		public final boolean equals(final Object object) {
+			if (object instanceof PluginStateExpression) {
+				final PluginStateExpression that = (PluginStateExpression) object;
+				return Util.equals(this.id, that.id)
+						&& Util.equals(this.value, that.value);
+			}
+
+			return false;
+		}
+
+		/**
+		 * Computes the hash code for this object based on the id.
+		 *
+		 * @return The hash code for this object.
+		 */
+		@Override
+		public final int hashCode() {
+			if (expressionHashCode == HASH_CODE_NOT_COMPUTED) {
+				expressionHashCode = HASH_INITIAL * HASH_FACTOR + Util.hashCode(id);
+				expressionHashCode = expressionHashCode * HASH_FACTOR + Util.hashCode(value);
+				if (expressionHashCode == HASH_CODE_NOT_COMPUTED) {
+					expressionHashCode++;
+				}
+			}
+			return expressionHashCode;
+		}
+
+		@Override
+		public boolean isEnabledFor(Object object) {
+			Bundle bundle = Platform.getBundle(id);
+			if (!BundleUtility.isReady(bundle)) {
+				return false;
+			}
+			if (value.equals(PLUGIN_INSTALLED)) {
+				return true;
+			}
+			if (value.equals(PLUGIN_ACTIVATED)) {
+				return BundleUtility.isActivated(bundle);
+			}
+			return false;
+		}
+	}
+
+	private static class SingleExpression extends AbstractExpression {
+		private AbstractExpression child;
+
+		/**
+		 * Create a single expression from the abstract definition.
+		 *
+		 * @param expression
+		 *            The expression that will be the child of the new single
+		 *            expression.
+		 * @throws IllegalStateException
+		 *             if the expression tag is not defined in the schema.
+		 */
+		public SingleExpression(AbstractExpression expression)
+				throws IllegalStateException {
+			super();
+
+			if (expression != null) {
+				child = expression;
+			} else {
+				throw new IllegalStateException(
+						"Single expression must contain 1 expression"); //$NON-NLS-1$
+			}
+		}
+
+		/**
+		 * Creates and populates the expression from the attributes and sub-
+		 * elements of the configuration element.
+		 *
+		 * @param element
+		 *            The element to create the expression from.
+		 * @throws IllegalStateException
+		 *             if the expression tag is not defined in the schema.
+		 */
+		public SingleExpression(IConfigurationElement element)
+				throws IllegalStateException {
+			super();
+
+			IConfigurationElement[] children = element.getChildren();
+			if (children.length != 1) {
+				throw new IllegalStateException(
+						"Single expression does not contain only 1 expression"); //$NON-NLS-1$
+			}
+			child = createExpression(children[0]);
+		}
+
+		@Override
+		public final boolean equals(final Object object) {
+			if (object instanceof SingleExpression) {
+				final SingleExpression that = (SingleExpression) object;
+				return Util.equals(this.child, that.child);
+			}
+
+			return false;
+		}
+
+		@Override
+		public String[] extractObjectClasses() {
+			return child.extractObjectClasses();
+		}
+
+		/**
+		 * Computes the hash code for this object based on the id.
+		 *
+		 * @return The hash code for this object.
+		 */
+		@Override
+		public final int hashCode() {
+			if (expressionHashCode == HASH_CODE_NOT_COMPUTED) {
+				expressionHashCode = HASH_INITIAL * HASH_FACTOR + Util.hashCode(child);
+				if (expressionHashCode == HASH_CODE_NOT_COMPUTED) {
+					expressionHashCode++;
+				}
+			}
+			return expressionHashCode;
+		}
+
+		@Override
+		public boolean isEnabledFor(Object object) {
+			return child.isEnabledFor(object);
+		}
+
+		@Override
+		public boolean isEnabledForExpression(Object object,
+				String expressionType) {
+			return child.isEnabledForExpression(object, expressionType);
+		}
+
+		@Override
+		public Collection valuesForExpression(String expressionType) {
+			return child.valuesForExpression(expressionType);
+		}
+
+	}
+
+	private static class SystemPropertyExpression extends AbstractExpression {
+		private String name;
+
+		private String value;
+
+		/**
+		 * Creates and populates the expression from the attributes and sub-
+		 * elements of the configuration element.
+		 *
+		 * @param element
+		 *            The element that will be used to determine the expressions
+		 *            for systemProperty.
+		 * @throws IllegalStateException
+		 *             if the expression tag is not defined in the schema.
+		 */
+		public SystemPropertyExpression(IConfigurationElement element)
+				throws IllegalStateException {
+			super();
+
+			name = element.getAttribute(ATT_NAME);
+			value = element.getAttribute(ATT_VALUE);
+			if (name == null || value == null) {
+				throw new IllegalStateException(
+						"System property expression missing attribute"); //$NON-NLS-1$
+			}
+		}
+
+		@Override
+		public boolean isEnabledFor(Object object) {
+			String str = System.getProperty(name);
+			if (str == null) {
+				return false;
+			}
+			return value.equals(str);
+		}
+
+		@Override
+		public final boolean equals(final Object object) {
+			if (object instanceof SystemPropertyExpression) {
+				final SystemPropertyExpression that = (SystemPropertyExpression) object;
+				return Util.equals(this.name, that.name)
+						&& Util.equals(this.value, that.value);
+			}
+
+			return false;
+		}
+
+		/**
+		 * Computes the hash code for this object based on the id.
+		 *
+		 * @return The hash code for this object.
+		 */
+		@Override
+		public final int hashCode() {
+			if (expressionHashCode == HASH_CODE_NOT_COMPUTED) {
+				expressionHashCode = HASH_INITIAL * HASH_FACTOR + Util.hashCode(name);
+				expressionHashCode = expressionHashCode * HASH_FACTOR + Util.hashCode(value);
+				if (expressionHashCode == HASH_CODE_NOT_COMPUTED) {
+					expressionHashCode++;
+				}
+			}
+			return expressionHashCode;
+		}
+	}
+
+	private static final String ATT_ID = "id"; //$NON-NLS-1$
+
+	private static final String ATT_NAME = "name"; //$NON-NLS-1$
+
+	private static final String ATT_VALUE = "value"; //$NON-NLS-1$
+
+	/**
+	 * Constant definition for AND.
+	 *
+	 */
+	public static final String EXP_TYPE_AND = "and"; //$NON-NLS-1$
+
+	/**
+	 * Constant definition for NOT.
+	 *
+	 */
+	public static final String EXP_TYPE_NOT = "not"; //$NON-NLS-1$
+
+	/**
+	 * Constant definition for objectClass.
+	 *
+	 */
+	public static final String EXP_TYPE_OBJECT_CLASS = "objectClass"; //$NON-NLS-1$
+
+	/**
+	 * Constant definition for objectState.
+	 *
+	 */
+	public static final String EXP_TYPE_OBJECT_STATE = "objectState"; //$NON-NLS-1$
+
+	/**
+	 * Constant definition for OR.
+	 *
+	 */
+	public static final String EXP_TYPE_OR = "or"; //$NON-NLS-1$
+
+	/**
+	 * Constant definition for pluginState.
+	 *
+	 */
+	public static final String EXP_TYPE_PLUG_IN_STATE = "pluginState"; //$NON-NLS-1$
+
+	/**
+	 * Constant definition for systemProperty.
+	 *
+	 */
+	public static final String EXP_TYPE_SYSTEM_PROPERTY = "systemProperty"; //$NON-NLS-1$
+
+	/**
+	 * The constant integer hash code value meaning the hash code has not yet
+	 * been computed.
+	 */
+	private static final int HASH_CODE_NOT_COMPUTED = -1;
+
+	/**
+	 * A factor for computing the hash code for all schemes.
+	 */
+	private static final int HASH_FACTOR = 89;
+
+	/**
+	 * The seed for the hash code for all schemes.
+	 */
+	private static final int HASH_INITIAL = ActionExpression.class.getName()
+			.hashCode();
+
+	private static final String PLUGIN_ACTIVATED = "activated"; //$NON-NLS-1$
+
+	private static final String PLUGIN_INSTALLED = "installed"; //$NON-NLS-1$
+
+	/**
+	 * Create an expression from the attributes and sub-elements of the
+	 * configuration element.
+	 *
+	 * @param element
+	 *            The IConfigurationElement with a tag defined in the public
+	 *            constants.
+	 * @return AbstractExpression based on the definition
+	 * @throws IllegalStateException
+	 *             if the expression tag is not defined in the schema.
+	 */
+	private static AbstractExpression createExpression(
+			IConfigurationElement element) throws IllegalStateException {
+		String tag = element.getName();
+		if (tag.equals(EXP_TYPE_OR)) {
+			return new OrExpression(element);
+		}
+		if (tag.equals(EXP_TYPE_AND)) {
+			return new AndExpression(element);
+		}
+		if (tag.equals(EXP_TYPE_NOT)) {
+			return new NotExpression(element);
+		}
+		if (tag.equals(EXP_TYPE_OBJECT_STATE)) {
+			return new ObjectStateExpression(element);
+		}
+		if (tag.equals(EXP_TYPE_OBJECT_CLASS)) {
+			return new ObjectClassExpression(element);
+		}
+		if (tag.equals(EXP_TYPE_PLUG_IN_STATE)) {
+			return new PluginStateExpression(element);
+		}
+		if (tag.equals(EXP_TYPE_SYSTEM_PROPERTY)) {
+			return new SystemPropertyExpression(element);
+		}
+
+		throw new IllegalStateException(
+				"Action expression unrecognized element: " + tag); //$NON-NLS-1$
+	}
+
+	/**
+	 * The hash code for this object. This value is computed lazily, and marked
+	 * as invalid when one of the values on which it is based changes.
+	 */
+	private transient int hashCode = HASH_CODE_NOT_COMPUTED;
+
+	private SingleExpression root;
+
+	/**
+	 * Creates an action expression for the given configuration element.
+	 *
+	 * @param element
+	 *            The element to build the expression from.
+	 */
+	public ActionExpression(IConfigurationElement element) {
+		try {
+			root = new SingleExpression(element);
+		} catch (IllegalStateException e) {
+			WorkbenchPlugin.log(e);
+			root = null;
+		}
+	}
+
+	/**
+	 * Create an instance of the receiver with the given expression type and
+	 * value. Currently the only supported expression type is
+	 * <code>EXP_TYPE_OBJECT_CLASS</code>.
+	 *
+	 * @param expressionType
+	 *            The expression constant we are creating an instance of.
+	 * @param expressionValue
+	 *            The name of the class we are creating an expression for.
+	 */
+	public ActionExpression(String expressionType, String expressionValue) {
+		if (expressionType.equals(EXP_TYPE_OBJECT_CLASS)) {
+			root = new SingleExpression(new ObjectClassExpression(
+					expressionValue));
+		}
+	}
+
+	@Override
+	public final boolean equals(final Object object) {
+		if (object instanceof ActionExpression) {
+			final ActionExpression that = (ActionExpression) object;
+			return Util.equals(this.root, that.root);
+		}
+
+		return false;
+	}
+
+	/**
+	 * Extract the object class test from the expression. This allows clients
+	 * (e.g. the decorator manager) to handle object class testing in a more
+	 * optimized way. This method removes the objectClass test from the
+	 * expression and returns the object class. The expression is not changed
+	 * and a <code>null</code> is returned if no object class is found.
+	 *
+	 * @return the object class or <code>null</code> if none was found.
+	 */
+	public String[] extractObjectClasses() {
+		return root.extractObjectClasses();
+	}
+
+	/**
+	 * Computes the hash code for this object based on the id.
+	 *
+	 * @return The hash code for this object.
+	 */
+	@Override
+	public final int hashCode() {
+		if (hashCode == HASH_CODE_NOT_COMPUTED) {
+			hashCode = HASH_INITIAL * HASH_FACTOR + Util.hashCode(root);
+			if (hashCode == HASH_CODE_NOT_COMPUTED) {
+				hashCode++;
+			}
+		}
+		return hashCode;
+	}
+
+	/**
+	 * Returns whether the expression is valid for all elements of the given
+	 * selection.
+	 *
+	 * @param selection
+	 *            the structured selection to use
+	 * @return boolean whether the expression is valid for the selection.
+	 */
+	public boolean isEnabledFor(IStructuredSelection selection) {
+		if (root == null) {
+			return false;
+		}
+
+		if (selection == null || selection.isEmpty()) {
+			return root.isEnabledFor(null);
+		}
+
+		Iterator elements = selection.iterator();
+		while (elements.hasNext()) {
+			if (!isEnabledFor(elements.next())) {
+				return false;
+			}
+		}
+		return true;
+	}
+
+	/**
+	 * Returns whether the expression is valid for the given object.
+	 *
+	 * @param object
+	 *            the object to validate against (can be <code>null</code>)
+	 * @return boolean whether the expression is valid for the object.
+	 */
+	public boolean isEnabledFor(Object object) {
+		if (root == null) {
+			return false;
+		}
+		return root.isEnabledFor(object);
+	}
+
+	/**
+	 * Returns whether or not the receiver is potentially valid for the object
+	 * via just the extension type. Currently the only supported expression type
+	 * is <code>EXP_TYPE_OBJECT_CLASS</code>.
+	 *
+	 * @param object
+	 *            the object to validate against (can be <code>null</code>)
+	 * @param expressionType
+	 *            the expression type to consider
+	 * @return boolean whether the expression is potentially valid for the
+	 *         object.
+	 */
+	public boolean isEnabledForExpression(Object object, String expressionType) {
+		if (root == null) {
+			return false;
+		}
+		return root.isEnabledForExpression(object, expressionType);
+	}
+
+	/**
+	 * Return the values of the expression type that the receiver is enabled
+	 * for. If the receiver is not enabled for the expressionType then return
+	 * <code>null</code>.
+	 *
+	 * @param expressionType
+	 *            the expression type to consider
+	 * @return Collection if there are values for this expression or
+	 *         <code>null</code> if this is not possible in the receiver or
+	 *         any of it's children
+	 */
+	public Collection valuesForExpression(String expressionType) {
+		return root.valuesForExpression(expressionType);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ActionPresentation.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ActionPresentation.java
new file mode 100644
index 0000000..5e2b638
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ActionPresentation.java
@@ -0,0 +1,217 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
+import org.eclipse.ui.SubActionBars;
+import org.eclipse.ui.internal.provisional.application.IActionBarConfigurer2;
+import org.eclipse.ui.internal.registry.IActionSet;
+import org.eclipse.ui.internal.registry.IActionSetDescriptor;
+
+/**
+ * Manage the configurable actions for one window.
+ */
+public class ActionPresentation {
+    private WorkbenchWindow window;
+
+    private HashMap mapDescToRec = new HashMap(3);
+
+    private HashMap invisibleBars = new HashMap(3);
+
+    private class SetRec {
+        public SetRec(IActionSet set,
+                SubActionBars bars) {
+            this.set = set;
+            this.bars = bars;
+        }
+
+        public IActionSet set;
+
+        public SubActionBars bars;
+    }
+
+    /**
+     * ActionPresentation constructor comment.
+     */
+    public ActionPresentation(WorkbenchWindow window) {
+        super();
+        this.window = window;
+    }
+
+    /**
+     * Remove all action sets.
+     */
+    public void clearActionSets() {
+        // Get all of the action sets -- both visible and invisible.
+        final List oldList = new ArrayList();
+        oldList.addAll(mapDescToRec.keySet());
+        oldList.addAll(invisibleBars.keySet());
+
+        Iterator iter = oldList.iterator();
+        while (iter.hasNext()) {
+            IActionSetDescriptor desc = (IActionSetDescriptor) iter.next();
+            removeActionSet(desc);
+        }
+    }
+
+    /**
+     * Destroy an action set.
+     */
+    public void removeActionSet(IActionSetDescriptor desc) {
+        SetRec rec = (SetRec) mapDescToRec.remove(desc);
+        if (rec == null) {
+            rec = (SetRec) invisibleBars.remove(desc);
+        }
+        if (rec != null) {
+            IActionSet set = rec.set;
+            SubActionBars bars = rec.bars;
+            if (bars != null) {
+                bars.dispose();
+            }
+            if (set != null) {
+                set.dispose();
+            }
+        }
+    }
+
+    /**
+     * Sets the list of visible action set.
+     */
+    public void setActionSets(IActionSetDescriptor[] newArray) {
+        // Convert array to list.
+        HashSet newList = new HashSet();
+
+        for (IActionSetDescriptor descriptor : newArray) {
+            newList.add(descriptor);
+        }
+        List oldList = new ArrayList(mapDescToRec.keySet());
+
+        // Remove obsolete actions.
+        Iterator iter = oldList.iterator();
+        while (iter.hasNext()) {
+            IActionSetDescriptor desc = (IActionSetDescriptor) iter.next();
+            if (!newList.contains(desc)) {
+                SetRec rec = (SetRec) mapDescToRec.get(desc);
+                if (rec != null) {
+                    mapDescToRec.remove(desc);
+                    IActionSet set = rec.set;
+                    SubActionBars bars = rec.bars;
+                    if (bars != null) {
+                        SetRec invisibleRec = new SetRec(set, bars);
+                        invisibleBars.put(desc, invisibleRec);
+                        bars.deactivate();
+                    }
+                }
+            }
+        }
+
+        // Add new actions.
+        ArrayList sets = new ArrayList();
+
+		for (IActionSetDescriptor desc : newArray) {
+            if (!mapDescToRec.containsKey(desc)) {
+                try {
+                    SetRec rec;
+                    // If the action bars and sets have already been created
+                    // then
+                    // reuse those action sets
+                    if (invisibleBars.containsKey(desc)) {
+                        rec = (SetRec) invisibleBars.get(desc);
+                        if (rec.bars != null) {
+                            rec.bars.activate();
+                        }
+                        invisibleBars.remove(desc);
+                    } else {
+                        IActionSet set = desc.createActionSet();
+                        SubActionBars bars = new ActionSetActionBars(window
+								.getActionBars(), window,
+								(IActionBarConfigurer2) window.getWindowConfigurer()
+										.getActionBarConfigurer(), desc.getId());
+                        rec = new SetRec(set, bars);
+                        set.init(window, bars);
+                        sets.add(set);
+
+                        // only register against the tracker once - check for
+                        // other registrations against the provided extension
+                        Object[] existingRegistrations = window
+                                .getExtensionTracker().getObjects(
+                                        desc.getConfigurationElement()
+                                                .getDeclaringExtension());
+                        if (existingRegistrations.length == 0
+                                || !containsRegistration(existingRegistrations,
+                                        desc)) {
+                            //register the set with the page tracker
+                            //this will be cleaned up by WorkbenchWindow listener
+                            window.getExtensionTracker().registerObject(
+                                    desc.getConfigurationElement().getDeclaringExtension(),
+                                    desc, IExtensionTracker.REF_WEAK);
+                        }
+                    }
+                    mapDescToRec.put(desc, rec);
+                } catch (CoreException e) {
+                    WorkbenchPlugin
+                            .log("Unable to create ActionSet: " + desc.getId(), e);//$NON-NLS-1$
+                }
+            }
+        }
+        // We process action sets in two passes for coolbar purposes. First we
+        // process base contributions
+        // (i.e., actions that the action set contributes to its toolbar), then
+        // we process adjunct contributions
+        // (i.e., actions that the action set contributes to other toolbars).
+        // This type of processing is
+        // necessary in order to maintain group order within a coolitem.
+        PluginActionSetBuilder.processActionSets(sets, window);
+
+        iter = sets.iterator();
+        while (iter.hasNext()) {
+            PluginActionSet set = (PluginActionSet) iter.next();
+            set.getBars().activate();
+        }
+    }
+
+    /**
+     * Return whether the array contains the given action set.
+     *
+     * @param existingRegistrations the array to check
+     * @param set the set to look for
+     * @return whether the set is in the array
+     * @since 3.1
+     */
+    private boolean containsRegistration(Object[] existingRegistrations, IActionSetDescriptor set) {
+        for (Object existingRegistration : existingRegistrations) {
+            if (existingRegistration == set) {
+				return true;
+			}
+        }
+        return false;
+    }
+
+    /**
+     */
+    public IActionSet[] getActionSets() {
+        Collection setRecCollection = mapDescToRec.values();
+        IActionSet result[] = new IActionSet[setRecCollection.size()];
+        int i = 0;
+        for (Iterator iterator = setRecCollection.iterator(); iterator
+                .hasNext(); i++) {
+			result[i] = ((SetRec) iterator.next()).set;
+		}
+        return result;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ActionSetActionBars.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ActionSetActionBars.java
new file mode 100644
index 0000000..a7fe1b2
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ActionSetActionBars.java
@@ -0,0 +1,327 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import org.eclipse.jface.action.ContributionItem;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.IContributionManager;
+import org.eclipse.jface.action.ICoolBarManager;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.action.SubMenuManager;
+import org.eclipse.jface.action.SubToolBarManager;
+import org.eclipse.jface.internal.provisional.action.IToolBarContributionItem;
+import org.eclipse.ui.IActionBars2;
+import org.eclipse.ui.IWorkbenchActionConstants;
+import org.eclipse.ui.SubActionBars2;
+import org.eclipse.ui.internal.provisional.application.IActionBarConfigurer2;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * This class represents the action bars for an action set.
+ */
+public class ActionSetActionBars extends SubActionBars2 {
+
+	private IActionBarConfigurer2 actionBarConfigurer = null;
+
+	private String actionSetId;
+
+	private ArrayList adjunctContributions = new ArrayList();
+
+	private IToolBarManager coolItemToolBarMgr = null;
+
+	private IToolBarContributionItem toolBarContributionItem = null;
+
+	/**
+     * Constructs a new action bars object
+     */
+    public ActionSetActionBars(IActionBars2 parent, IServiceLocator serviceLocator, IActionBarConfigurer2 actionBarConfigurer, String actionSetId) {
+    	super(parent, serviceLocator);
+		this.actionSetId = actionSetId;
+        this.actionBarConfigurer = actionBarConfigurer;
+    }
+
+	/**
+	 * Adds to the list all the actions that are part of this action set but
+	 * belong to different cool bar items.
+	 *
+	 * @param item
+	 *            the item defined in this actionset but in a different tool Bar
+	 *            contribution item
+	 */
+	/* package */void addAdjunctContribution(IContributionItem item) {
+		adjunctContributions.add(item);
+	}
+
+	@Override
+	protected SubMenuManager createSubMenuManager(IMenuManager parent) {
+		return new ActionSetMenuManager(parent, actionSetId);
+	}
+
+	@Override
+	protected SubToolBarManager createSubToolBarManager(IToolBarManager parent) {
+		// return null, action sets are managed by CoolItemToolBarManagers
+		return null;
+	}
+
+	/**
+	 * Dispose the contributions.
+	 */
+	@Override
+	public void dispose() {
+		super.dispose();
+		if (coolItemToolBarMgr == null) {
+			return;
+		}
+		// remove the action set's items from its action bar, don't use
+		// removeAll since other items from other actions sets may be in
+		// the action bar's cool item
+		for (IContributionItem item : coolItemToolBarMgr.getItems()) {
+			if (item instanceof PluginActionCoolBarContributionItem) {
+				PluginActionCoolBarContributionItem actionSetItem = (PluginActionCoolBarContributionItem) item;
+				if (actionSetItem.getActionSetId().equals(actionSetId)) {
+					coolItemToolBarMgr.remove(item);
+					item.dispose();
+				}
+			} else {
+				// leave separators and group markers intact, doing
+				// so allows ordering to be maintained when action sets
+				// are removed then added back
+			}
+		}
+
+		// remove items from this action set that are in other action bars
+		for (int i = 0; i < adjunctContributions.size(); i++) {
+			ContributionItem item = (ContributionItem) adjunctContributions
+					.get(i);
+			IContributionManager parent = item.getParent();
+			if (parent != null) {
+				parent.remove(item);
+				item.dispose();
+			}
+		}
+		toolBarContributionItem = null;
+		coolItemToolBarMgr = null;
+		adjunctContributions = new ArrayList();
+	}
+
+	/**
+	 * Returns the contribution item that the given contribution item should be
+	 * inserted after.
+	 *
+	 * @param startId
+	 *            the location to start looking alphabetically.
+	 * @param itemId
+	 *            the target item id.
+	 * @param mgr
+	 *            the contribution manager.
+	 * @return the contribution item that the given items should be returned
+	 *         after.
+	 *
+	 * @since 3.0
+	 */
+	private IContributionItem findAlphabeticalOrder(String startId,
+			String itemId, IContributionManager mgr) {
+		IContributionItem[] items = mgr.getItems();
+		int insertIndex = 0;
+
+		// look for starting point
+		while (insertIndex < items.length) {
+			IContributionItem item = items[insertIndex];
+			if (item.getId() != null && item.getId().equals(startId)) {
+				break;
+			}
+			++insertIndex;
+		}
+
+		// Find the index that this item should be inserted in
+		for (int i = insertIndex + 1; i < items.length; i++) {
+			IContributionItem item = items[i];
+			String testId = item.getId();
+
+			if (item.isGroupMarker()) {
+				break;
+			}
+
+			if (itemId != null && testId != null) {
+				if (itemId.compareTo(testId) < 1) {
+					break;
+				}
+			}
+			insertIndex = i;
+		}
+		// Should be inserted at the end
+		if (insertIndex >= items.length) {
+			return null;
+		}
+		return items[insertIndex];
+	}
+
+	/* package */String getActionSetId() {
+		return actionSetId;
+	}
+
+	/**
+	 * Returns a tool bar manager for this Item.
+	 *
+	 * @return the tool bar manager
+	 */
+	@Override
+	public IToolBarManager getToolBarManager() {
+		ICoolBarManager coolBarManager = getCastedParent().getCoolBarManager();
+		if (coolBarManager == null) {
+			return null;
+		}
+        return actionBarConfigurer.createToolBarManager();
+	}
+
+	/**
+	 * Returns the correct tool bar for the given action id. If this action is
+	 * an adjunct type the it returns the toolbar manager from the cool bar
+	 * manager.
+	 *
+	 * @param id
+	 *            the id of the action
+	 * @return the tool bar manager
+	 */
+	public IToolBarManager getToolBarManager(String actionId) {
+		// Check if a tool bar manager for an adjunct type is being requested
+		String toolBarId = actionSetId;
+		boolean isAdjunctType = false;
+		if (!actionId.equals(actionSetId)) {
+			// Adjunct type
+			toolBarId = actionId;
+			isAdjunctType = true;
+		}
+
+		// Rereive the cool bar manager
+		ICoolBarManager coolBarManager = getCastedParent().getCoolBarManager();
+		if (coolBarManager == null) {
+			return null;
+		}
+
+		// Check to see that there isn't already a tool bar created
+		// and the tool bar being requested is not for an adjunct action
+		if ((coolItemToolBarMgr != null) && (!isAdjunctType)) {
+			return coolItemToolBarMgr;
+		}
+
+		// Search for toolBarId in the cool Bar manager
+		IContributionItem cbItem = coolBarManager.find(toolBarId);
+		// If there hasn't been a tool bar contribution item created for this
+		// tool bar
+		// id then create one. Otherwise retrieve the tool bar contribution
+		// item
+		if (cbItem instanceof IToolBarContributionItem) {
+
+			IToolBarContributionItem tbcbItem = (IToolBarContributionItem) cbItem;
+			coolItemToolBarMgr = tbcbItem.getToolBarManager();
+			// If this not an adjuct type then we can cashe the tool bar
+			// contribution type
+			if (!isAdjunctType) {
+				toolBarContributionItem = tbcbItem;
+			}
+		} else {
+
+			coolItemToolBarMgr = actionBarConfigurer.createToolBarManager();
+
+			// If this is not an adjunct type then create a tool bar
+			// contribution item
+			// we don't create one for an adjunct type because another action
+			// set action bars contains one
+
+            IContributionItem toolBarContributionItem = actionBarConfigurer
+					.createToolBarContributionItem(coolItemToolBarMgr,
+							toolBarId);
+
+			toolBarContributionItem.setParent(coolItemToolBarMgr);
+			toolBarContributionItem.setVisible(getActive());
+			coolItemToolBarMgr.markDirty();
+
+			// Now add the tool bar contribution Item to the cool bar manager
+			IContributionItem refItem = findAlphabeticalOrder(
+					IWorkbenchActionConstants.MB_ADDITIONS, toolBarId,
+					coolBarManager);
+			if (refItem != null) {
+				coolBarManager.insertAfter(refItem.getId(),
+						toolBarContributionItem);
+			} else {
+				coolBarManager.add(toolBarContributionItem);
+			}
+		}
+		return coolItemToolBarMgr;
+	}
+
+	// for dynamic UI
+	/* package */void removeAdjunctContribution(ContributionItem item) {
+		adjunctContributions.remove(item);
+	}
+
+	/**
+	 * Activate / Deactivate the contributions.
+	 */
+	@Override
+	protected void setActive(boolean set) {
+		super.setActive(set);
+
+		ICoolBarManager coolBarManager = getCastedParent().getCoolBarManager();
+		if (coolBarManager == null) {
+			return;
+		}
+
+		// 1. Need to set visibility for all non-adjunct actions
+		if (coolItemToolBarMgr != null) {
+			for (IContributionItem item : coolItemToolBarMgr.getItems()) {
+				if (item instanceof PluginActionCoolBarContributionItem) {
+					PluginActionCoolBarContributionItem actionSetItem = (PluginActionCoolBarContributionItem) item;
+					// Only if the action set id for this contribution item is
+					// the same
+					// as this object
+					if (actionSetItem.getActionSetId().equals(actionSetId)) {
+						item.setVisible(set);
+						coolItemToolBarMgr.markDirty();
+						if (!coolBarManager.isDirty()) {
+							coolBarManager.markDirty();
+						}
+					}
+				}
+			}
+			// Update the manager
+			coolItemToolBarMgr.update(false);
+			if (toolBarContributionItem != null) {
+				toolBarContributionItem.update(ICoolBarManager.SIZE);
+			}
+		}
+
+		// 2. Need to set visibility for all adjunct actions
+		if (adjunctContributions.size() > 0) {
+			for (Iterator i = adjunctContributions.iterator(); i.hasNext();) {
+				IContributionItem item = (IContributionItem) i.next();
+				if (item instanceof ContributionItem) {
+					item.setVisible(set);
+					IContributionManager manager = ((ContributionItem) item)
+							.getParent();
+					manager.markDirty();
+					manager.update(false);
+					if (!coolBarManager.isDirty()) {
+						coolBarManager.markDirty();
+					}
+					item.update(ICoolBarManager.SIZE);
+				}
+
+			}
+
+		}
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ActionSetContributionItem.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ActionSetContributionItem.java
new file mode 100644
index 0000000..002722b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ActionSetContributionItem.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.SubContributionItem;
+
+/**
+ * This class marks a sub contribution item as belonging to
+ * an action set.
+ */
+public class ActionSetContributionItem extends SubContributionItem implements
+        IActionSetContributionItem {
+
+    /**
+     * The action set id.
+     */
+    private String actionSetId;
+
+    /**
+     * Constructs a new item
+     */
+    public ActionSetContributionItem(IContributionItem item, String actionSetId) {
+        super(item);
+        this.actionSetId = actionSetId;
+    }
+
+    /**
+     * Returns the action set id.
+     */
+    @Override
+	public String getActionSetId() {
+        return actionSetId;
+    }
+
+    /**
+     * Sets the action set id.
+     */
+    @Override
+	public void setActionSetId(String newActionSetId) {
+        actionSetId = newActionSetId;
+    }
+
+	@Override
+	public String toString() {
+		return "ActionSetContributionItem [id=" + actionSetId + //$NON-NLS-1$
+				", visible=" + isVisible() + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ActionSetManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ActionSetManager.java
new file mode 100644
index 0000000..82f5b54
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ActionSetManager.java
@@ -0,0 +1,199 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2016 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *******************************************************************************/
+package org.eclipse.ui.internal;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.ui.IPropertyListener;
+import org.eclipse.ui.contexts.IContextActivation;
+import org.eclipse.ui.contexts.IContextService;
+import org.eclipse.ui.internal.registry.IActionSetDescriptor;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * Maintains a reference counted set of action sets, with a visibility mask.
+ * This is used to determine the visibility of actions in a workbench page. In a
+ * workbench page, there may be may be many conditions that can cause an action
+ * set to become visible (such as the active part, the active editor, the
+ * default visibility of the action, the properties of the perspective, etc.)
+ * The user can also explicitly mask off particular action sets in each
+ * perspective.
+ * <p>
+ * The reference count indicates how many conditions have requested that the
+ * actions be active and the mask indicates whether or not the set was disabled
+ * by the user.
+ * </p>
+ *
+ * @since 3.1
+ */
+public class ActionSetManager {
+
+    private static class ActionSetRec {
+        int showCount;
+
+        int maskCount;
+
+        public boolean isVisible() {
+            return maskCount == 0 && showCount > 0;
+        }
+
+        public boolean isEmpty() {
+            return maskCount == 0 && showCount == 0;
+        }
+    }
+
+    private HashMap actionSets = new HashMap();
+    private HashSet visibleItems = new HashSet();
+
+    public static final int PROP_VISIBLE = 0;
+    public static final int PROP_HIDDEN = 1;
+    public static final int CHANGE_MASK = 0;
+    public static final int CHANGE_UNMASK = 1;
+    public static final int CHANGE_SHOW = 2;
+    public static final int CHANGE_HIDE = 3;
+
+	private ListenerList<IPropertyListener> listeners = new ListenerList<>();
+	private IPropertyListener contextListener;
+	private Map activationsById = new HashMap();
+	private IContextService contextService;
+
+    public ActionSetManager(IServiceLocator locator) {
+    	contextService = locator.getService(IContextService.class);
+		addListener(getContextListener());
+    }
+
+    /**
+	 * @return
+	 */
+	private IPropertyListener getContextListener() {
+		if (contextListener == null) {
+			contextListener = (source, propId) -> {
+				if (source instanceof IActionSetDescriptor) {
+					IActionSetDescriptor desc = (IActionSetDescriptor) source;
+					String id = desc.getId();
+					if (propId == PROP_VISIBLE) {
+						activationsById.put(id, contextService
+								.activateContext(id));
+					} else if (propId == PROP_HIDDEN) {
+						IContextActivation act = (IContextActivation) activationsById
+								.remove(id);
+						if (act != null) {
+							contextService.deactivateContext(act);
+						}
+					}
+				}
+			};
+		}
+		return contextListener;
+	}
+
+	public void addListener(IPropertyListener l) {
+        listeners.add(l);
+    }
+
+    public void removeListener(IPropertyListener l) {
+        listeners.remove(l);
+    }
+
+    private void firePropertyChange(IActionSetDescriptor descriptor, int id) {
+		for (IPropertyListener listener : listeners) {
+            listener.propertyChanged(descriptor, id);
+        }
+    }
+
+    private ActionSetRec getRec(IActionSetDescriptor descriptor) {
+        ActionSetRec rec = (ActionSetRec)actionSets.get(descriptor);
+
+        if (rec == null) {
+            rec = new ActionSetRec();
+            actionSets.put(descriptor, rec);
+        }
+
+        return rec;
+    }
+
+    public void showAction(IActionSetDescriptor descriptor) {
+        ActionSetRec rec = getRec(descriptor);
+
+        boolean wasVisible = rec.isVisible();
+        rec.showCount++;
+        if (!wasVisible && rec.isVisible()) {
+            visibleItems.add(descriptor);
+            firePropertyChange(descriptor, PROP_VISIBLE);
+            if (rec.isEmpty()) {
+                actionSets.remove(descriptor);
+            }
+        }
+    }
+
+    public void hideAction(IActionSetDescriptor descriptor) {
+        ActionSetRec rec = getRec(descriptor);
+
+        boolean wasVisible = rec.isVisible();
+        rec.showCount--;
+        if (wasVisible && !rec.isVisible()) {
+            visibleItems.remove(descriptor);
+            firePropertyChange(descriptor, PROP_HIDDEN);
+            if (rec.isEmpty()) {
+                actionSets.remove(descriptor);
+            }
+        }
+    }
+
+    public void maskAction(IActionSetDescriptor descriptor) {
+        ActionSetRec rec = getRec(descriptor);
+
+        boolean wasVisible = rec.isVisible();
+        rec.maskCount++;
+        if (wasVisible && !rec.isVisible()) {
+            visibleItems.remove(descriptor);
+            firePropertyChange(descriptor, PROP_HIDDEN);
+            if (rec.isEmpty()) {
+                actionSets.remove(descriptor);
+            }
+        }
+    }
+
+    public void unmaskAction(IActionSetDescriptor descriptor) {
+        ActionSetRec rec = getRec(descriptor);
+
+        boolean wasVisible = rec.isVisible();
+        rec.maskCount--;
+        if (!wasVisible && rec.isVisible()) {
+            visibleItems.add(descriptor);
+            firePropertyChange(descriptor, PROP_VISIBLE);
+            if (rec.isEmpty()) {
+                actionSets.remove(descriptor);
+            }
+        }
+    }
+
+    public Collection getVisibleItems() {
+        return visibleItems;
+    }
+
+    public void change(IActionSetDescriptor descriptor, int changeType) {
+        switch(changeType) {
+        case CHANGE_SHOW:
+            showAction(descriptor); break;
+        case CHANGE_HIDE:
+            hideAction(descriptor); break;
+        case CHANGE_MASK:
+            maskAction(descriptor); break;
+        case CHANGE_UNMASK:
+            unmaskAction(descriptor); break;
+        }
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ActionSetMenuManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ActionSetMenuManager.java
new file mode 100644
index 0000000..de4055a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ActionSetMenuManager.java
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.SubContributionItem;
+import org.eclipse.jface.action.SubMenuManager;
+
+/**
+ * An <code>EditorMenuManager</code> is used to sort the contributions
+ * made by an editor so that they always appear after the action sets.
+ */
+public class ActionSetMenuManager extends SubMenuManager {
+    private String actionSetId;
+
+    /**
+     * Constructs a new editor manager.
+     */
+    public ActionSetMenuManager(IMenuManager mgr, String actionSetId) {
+        super(mgr);
+        this.actionSetId = actionSetId;
+    }
+
+	/**
+	 * Returns the item passed to us, not the wrapper. In the case of menu's not
+	 * added by this manager, ensure that we return a wrapper for the menu.
+	 */
+    @Override
+	public IContributionItem find(String id) {
+        IContributionItem item = getParentMenuManager().find(id);
+        if (item instanceof SubContributionItem) {
+			// Return the item passed to us, not the wrapper.
+            item = unwrap(item);
+		}
+
+        if (item instanceof IMenuManager) {
+            // if it is a menu manager wrap it before returning
+            IMenuManager menu = (IMenuManager) item;
+            if (menu instanceof SubMenuManager) {
+				// it it is already wrapped then remover the wrapper and
+                // rewrap. We have a table of wrappers so we reuse wrappers
+                // we create.
+                menu = (IMenuManager) ((SubMenuManager) menu).getParent();
+			}
+            item = getWrapper(menu);
+        }
+
+        return item;
+    }
+
+	/**
+	 * @return Returns the actionSetId.
+	 */
+	public String getActionSetId() {
+		return actionSetId;
+	}
+
+    @Override
+	public IContributionItem[] getItems() {
+        return getParentMenuManager().getItems();
+    }
+
+    @Override
+	protected SubContributionItem wrap(IContributionItem item) {
+        return new ActionSetContributionItem(item, actionSetId);
+    }
+
+    @Override
+	protected SubMenuManager wrapMenu(IMenuManager menu) {
+        return new ActionSetMenuManager(menu, actionSetId);
+    }
+
+	@Override
+	public String toString() {
+		return "ActionSetMenuManager [id=" + actionSetId + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ActionSetSeparator.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ActionSetSeparator.java
new file mode 100644
index 0000000..d3279a1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ActionSetSeparator.java
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.jface.action.ContributionItem;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+
+/**
+ * This class represents a pseudo-group defined by an action set.
+ * It is not a real group ( aka GroupMarker ) because that would interfere with
+ * the pre-existing groups in a menu or toolbar.
+ */
+public class ActionSetSeparator extends ContributionItem implements
+        IActionSetContributionItem {
+    private String actionSetId;
+
+    /**
+     * Constructs a new group marker.
+     */
+    public ActionSetSeparator(String groupName, String newActionSetId) {
+        super(groupName);
+        actionSetId = newActionSetId;
+    }
+
+    @Override
+	public void fill(Menu menu, int index) {
+        if (index >= 0) {
+			new MenuItem(menu, SWT.SEPARATOR, index);
+		} else {
+			new MenuItem(menu, SWT.SEPARATOR);
+		}
+    }
+
+    @Override
+	public void fill(ToolBar toolbar, int index) {
+        if (index >= 0) {
+			new ToolItem(toolbar, SWT.SEPARATOR, index);
+		} else {
+			new ToolItem(toolbar, SWT.SEPARATOR);
+		}
+    }
+
+    /**
+     * Returns the action set id.
+     */
+    @Override
+	public String getActionSetId() {
+        return actionSetId;
+    }
+
+    /**
+     * The <code>Separator</code> implementation of this <code>IContributionItem</code>
+     * method returns <code>true</code>
+     */
+    @Override
+	public boolean isSeparator() {
+        return true;
+    }
+
+    /**
+     * Sets the action set id.
+     */
+    @Override
+	public void setActionSetId(String newActionSetId) {
+        actionSetId = newActionSetId;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ActionSetsEvent.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ActionSetsEvent.java
new file mode 100644
index 0000000..30fc5d5
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ActionSetsEvent.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal;
+
+import org.eclipse.ui.internal.registry.IActionSetDescriptor;
+
+/**
+ * <p>
+ * An event indicating changes to the action sets in a particular workbench
+ * window.
+ * </p>
+ * <p>
+ * This class is only intended for internal use within
+ * <code>org.eclipse.ui.workbench</code>.
+ * </p>
+ * <p>
+ * <strong>PROVISIONAL</strong>. This class or interface has been added as part
+ * of a work in progress. There is a guarantee neither that this API will work
+ * nor that it will remain the same. Please do not use this API without
+ * consulting with the Platform/UI team.
+ * </p>
+ * <p>
+ * This class is eventually intended to exist in
+ * <code>org.eclipse.jface.menus</code>.
+ * </p>
+ *
+ * @since 3.2
+ */
+public final class ActionSetsEvent {
+
+	/**
+	 * The array of action sets that are now active. This value may be
+	 * <code>null</code>.
+	 */
+	private final IActionSetDescriptor[] newActionSets;
+
+	/**
+	 * Constructs a new instance of {@link ActionSetsEvent}.
+	 *
+	 * @param newActionSets
+	 *            The action sets that are now active; may be <code>null</code>.
+	 */
+	ActionSetsEvent(final IActionSetDescriptor[] newActionSets) {
+		this.newActionSets = newActionSets;
+	}
+
+	/**
+	 * Returns the currently active action sets.
+	 *
+	 * @return The action sets that are now active; may be <code>null</code>.
+	 */
+	public final IActionSetDescriptor[] getNewActionSets() {
+		return newActionSets;
+	}
+}
+
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ActivateEditorHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ActivateEditorHandler.java
new file mode 100644
index 0000000..772a543
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ActivateEditorHandler.java
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.ExpressionInfo;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.IViewReference;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPartReference;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * Activates the most recently used editor in the current window.
+ * <p>
+ * Replacement for: ActivateEditorAction
+ * </p>
+ *
+ * @since 3.3
+ */
+public class ActivateEditorHandler extends AbstractEvaluationHandler {
+
+	private Expression enabledWhen;
+
+	public ActivateEditorHandler() {
+		registerEnablement();
+	}
+
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		IWorkbenchWindow window = HandlerUtil
+				.getActiveWorkbenchWindowChecked(event);
+		IWorkbenchPage page = window.getActivePage();
+		if (page != null) {
+			IEditorPart part = HandlerUtil.getActiveEditor(event);
+			if (part != null) {
+				page.activate(part);
+			} else {
+				IWorkbenchPartReference ref = page.getActivePartReference();
+				if (ref instanceof IViewReference) {
+					// if (((WorkbenchPage) page).isFastView((IViewReference)
+					// ref)) {
+					// ((WorkbenchPage) page)
+					// .toggleFastView((IViewReference) ref);
+					// }
+				}
+			}
+		}
+		return null;
+	}
+
+	@Override
+	protected Expression getEnabledWhenExpression() {
+		if (enabledWhen == null) {
+			enabledWhen = new Expression() {
+				@Override
+				public EvaluationResult evaluate(IEvaluationContext context)
+						throws CoreException {
+					IWorkbenchWindow window = InternalHandlerUtil
+							.getActiveWorkbenchWindow(context);
+					if (window != null) {
+						if (window.getActivePage() != null) {
+							return EvaluationResult.TRUE;
+						}
+					}
+					return EvaluationResult.FALSE;
+				}
+
+				@Override
+				public void collectExpressionInfo(ExpressionInfo info) {
+					info
+							.addVariableNameAccess(ISources.ACTIVE_WORKBENCH_WINDOW_NAME);
+				}
+			};
+		}
+		return enabledWhen;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ActiveEditorAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ActiveEditorAction.java
new file mode 100644
index 0000000..be64989
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ActiveEditorAction.java
@@ -0,0 +1,194 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction;
+
+/**
+ * The abstract superclass for actions that depend on the active editor.
+ * This implementation tracks the active editor (see <code>getActiveEditor</code>)
+ * and updates the availability of the action when an editor becomes
+ * active.
+ * <p>
+ * Subclasses must implement the following <code>IAction</code> method:
+ * <ul>
+ *   <li><code>run</code> - to do the action's work</li>
+ * </ul>
+ * </p>
+ * <p>
+ * Subclasses may extend any of the <code>IPartListener</code> methods if the
+ * action availablity needs to be recalculated:
+ * <ul>
+ *   <li><code>partActivated</code></li>
+ *   <li><code>partDeactivated</code></li>
+ *   <li><code>partOpened</code></li>
+ *   <li><code>partClosed</code></li>
+ *   <li><code>partBroughtToTop</code></li>
+ * </ul>
+ * </p>
+ * <p>
+ * Subclasses may extend any of the <code>IPageListener</code> methods if the
+ * action availablity needs to be recalculated:
+ * <ul>
+ *   <li><code>pageActivated</code></li>
+ *   <li><code>pageClosed</code></li>
+ *   <li><code>pageOpened</code></li>
+ * </ul>
+ * </p>
+ * <p>
+ * This method implements the <code>IPartListener</code> and
+ * <code>IPageListener</code>interfaces, and automatically registers listeners
+ * so that it can keep its enablement state up to date. Ordinarily, the
+ * window's references to these listeners will be dropped automatically when
+ * the window closes. However, if the client needs to get rid of an action
+ * while the window is still open, the client must call
+ * {@link IWorkbenchAction#dispose dispose} to give the action an
+ * opportunity to deregister its listeners and to perform any other cleanup.
+ * </p>
+ */
+public abstract class ActiveEditorAction extends PageEventAction {
+
+    private IEditorPart activeEditor;
+
+    /**
+     * Creates a new action with the given text.
+     *
+     * @param text the string used as the text for the action,
+     *   or <code>null</code> if there is no text
+     * @param window the workbench window this action is
+     *   registered with.
+     */
+    protected ActiveEditorAction(String text, IWorkbenchWindow window) {
+        super(text, window);
+        updateState();
+    }
+
+    /**
+     * Notification that the active editor tracked
+     * by the action is being activated.
+     *
+     * Subclasses may override.
+     */
+    protected void editorActivated(IEditorPart part) {
+    }
+
+    /**
+     * Notification that the active editor tracked
+     * by the action is being deactivated.
+     *
+     * Subclasses may override.
+     */
+    protected void editorDeactivated(IEditorPart part) {
+    }
+
+    /**
+     * Return the active editor
+     *
+     * @return the page's active editor, and <code>null</code>
+     *		if no active editor or no active page.
+     */
+    public final IEditorPart getActiveEditor() {
+        return activeEditor;
+    }
+
+    @Override
+	public void pageActivated(IWorkbenchPage page) {
+        super.pageActivated(page);
+        updateActiveEditor();
+        updateState();
+    }
+
+    @Override
+	public void pageClosed(IWorkbenchPage page) {
+        super.pageClosed(page);
+        updateActiveEditor();
+        updateState();
+    }
+
+    @Override
+	public void partActivated(IWorkbenchPart part) {
+        super.partActivated(part);
+        if (part instanceof IEditorPart) {
+            updateActiveEditor();
+            updateState();
+        }
+    }
+
+    @Override
+	public void partBroughtToTop(IWorkbenchPart part) {
+        super.partBroughtToTop(part);
+        if (part instanceof IEditorPart) {
+            updateActiveEditor();
+            updateState();
+        }
+    }
+
+    @Override
+	public void partClosed(IWorkbenchPart part) {
+        super.partClosed(part);
+        if (part instanceof IEditorPart) {
+            updateActiveEditor();
+            updateState();
+        }
+    }
+
+    @Override
+	public void partDeactivated(IWorkbenchPart part) {
+        super.partDeactivated(part);
+        if (part instanceof IEditorPart) {
+            updateActiveEditor();
+            updateState();
+        }
+    }
+
+    /**
+     * Set the active editor
+     */
+    private void setActiveEditor(IEditorPart part) {
+        if (activeEditor == part) {
+            return;
+        }
+        if (activeEditor != null) {
+            editorDeactivated(activeEditor);
+        }
+        activeEditor = part;
+        if (activeEditor != null) {
+            editorActivated(activeEditor);
+        }
+    }
+
+    /**
+     * Update the active editor based on the current
+     * active page.
+     */
+    private void updateActiveEditor() {
+        if (getActivePage() == null) {
+            setActiveEditor(null);
+        } else {
+            setActiveEditor(getActivePage().getActiveEditor());
+        }
+    }
+
+    /**
+     * Update the state of the action. By default, the action
+     * is enabled if there is an active editor.
+     *
+     * Subclasses may override or extend this method.
+     */
+    protected void updateState() {
+        setEnabled(getActiveEditor() != null);
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ActivityPersistanceHelper.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ActivityPersistanceHelper.java
new file mode 100644
index 0000000..283537a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ActivityPersistanceHelper.java
@@ -0,0 +1,291 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.internal;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.activities.ActivityManagerEvent;
+import org.eclipse.ui.activities.IActivity;
+import org.eclipse.ui.activities.IActivityManager;
+import org.eclipse.ui.activities.IActivityManagerListener;
+import org.eclipse.ui.activities.IActivityRequirementBinding;
+import org.eclipse.ui.activities.IWorkbenchActivitySupport;
+import org.eclipse.ui.activities.NotDefinedException;
+
+/**
+ * Utility class that manages the persistance of enabled activities.
+ *
+ * @since 3.0
+ */
+final class ActivityPersistanceHelper {
+
+    /**
+     * Prefix for all activity preferences
+     */
+    protected final static String PREFIX = "UIActivities."; //$NON-NLS-1$
+
+    /**
+     * Singleton instance.
+     */
+    private static ActivityPersistanceHelper singleton;
+
+    /**
+     * The listener that responds to changes in the <code>IActivityManager</code>
+     */
+    private final IActivityManagerListener activityManagerListener = new IActivityManagerListener() {
+
+        @Override
+		public void activityManagerChanged(
+                ActivityManagerEvent activityManagerEvent) {
+            //process newly defined activities.
+            if (activityManagerEvent.haveDefinedActivityIdsChanged()) {
+                Set delta = new HashSet(activityManagerEvent
+                        .getActivityManager().getDefinedActivityIds());
+                delta.removeAll(activityManagerEvent
+                        .getPreviouslyDefinedActivityIds());
+                // whatever is still in delta are new activities - restore their
+                // state
+                loadEnabledStates(activityManagerEvent
+                        .getActivityManager().getEnabledActivityIds(), delta);
+            }
+            if (activityManagerEvent.haveEnabledActivityIdsChanged()) {
+				saveEnabledStates();
+			}
+        }
+    };
+
+    /**
+     * The listener that responds to preference changes
+     */
+    private final IPropertyChangeListener propertyChangeListener = new IPropertyChangeListener() {
+
+        @Override
+		public void propertyChange(PropertyChangeEvent event) {
+            // dont process property events if we're in the process of
+            // serializing state.
+            if (!saving && event.getProperty().startsWith(PREFIX)) {
+                String activityId = event.getProperty().substring(PREFIX.length());
+                IWorkbenchActivitySupport support = PlatformUI.getWorkbench().getActivitySupport();
+                IActivityManager activityManager = support.getActivityManager();
+
+                boolean enabled = Boolean.valueOf(event.getNewValue().toString()).booleanValue();
+                // if we're turning an activity off we'll need to create its dependency tree to ensuure that all dependencies are also disabled.
+                Set set = new HashSet(activityManager.getEnabledActivityIds());
+                if (enabled == false) {
+                    Set dependencies = buildDependencies(activityManager, activityId);
+                    set.removeAll(dependencies);
+                }
+                else {
+                    set.add(activityId);
+                }
+                support.setEnabledActivityIds(set);
+            }
+        }
+    };
+
+    /**
+     * Whether we are currently saving the state of activities to the preference
+     * store.
+     */
+    protected boolean saving = false;
+
+    /**
+     * Get the singleton instance of this class.
+     *
+     * @return the singleton instance of this class.
+     */
+    public static ActivityPersistanceHelper getInstance() {
+        if (singleton == null) {
+            singleton = new ActivityPersistanceHelper();
+        }
+        return singleton;
+    }
+
+    /**
+     * Returns a set of activity IDs that depend on the provided ID in order to be enabled.
+     *
+     * @param activityManager the activity manager to query
+     * @param activityId the activity whos dependencies should be added
+     * @return a set of activity IDs
+     */
+    protected Set buildDependencies(IActivityManager activityManager, String activityId) {
+        Set set = new HashSet();
+        for (Iterator i = activityManager.getDefinedActivityIds().iterator(); i.hasNext(); ) {
+            IActivity activity = activityManager.getActivity((String) i.next());
+            for (Iterator j = activity.getActivityRequirementBindings().iterator(); j.hasNext(); ) {
+                IActivityRequirementBinding binding = (IActivityRequirementBinding) j.next();
+                if (activityId.equals(binding.getRequiredActivityId())) {
+                    set.addAll(buildDependencies(activityManager, activity.getId()));
+                }
+            }
+        }
+        set.add(activityId);
+        return set;
+    }
+
+    /**
+     * Create a new <code>ActivityPersistanceHelper</code> which will restore
+     * previously enabled activity states.
+     */
+    private ActivityPersistanceHelper() {
+        loadEnabledStates();
+        hookListeners();
+    }
+
+    /**
+     * Hook the listener that will respond to any activity state changes.
+     */
+    private void hookListeners() {
+        IWorkbenchActivitySupport support = PlatformUI.getWorkbench()
+                .getActivitySupport();
+
+        IActivityManager activityManager = support.getActivityManager();
+
+        activityManager.addActivityManagerListener(activityManagerListener);
+
+        IPreferenceStore store = WorkbenchPlugin.getDefault()
+                .getPreferenceStore();
+
+        store.addPropertyChangeListener(propertyChangeListener);
+    }
+
+    /**
+     * Hook the listener that will respond to any activity state changes.
+     */
+    private void unhookListeners() {
+        IWorkbenchActivitySupport support = PlatformUI.getWorkbench()
+                .getActivitySupport();
+
+        IActivityManager activityManager = support.getActivityManager();
+
+        activityManager.removeActivityManagerListener(activityManagerListener);
+
+        IPreferenceStore store = WorkbenchPlugin.getDefault()
+                .getPreferenceStore();
+
+        store.removePropertyChangeListener(propertyChangeListener);
+    }
+
+    /**
+     * Create the preference key for the activity.
+     *
+     * @param activityId the activity id.
+     * @return String a preference key representing the activity.
+     */
+    private String createPreferenceKey(String activityId) {
+        return PREFIX + activityId;
+    }
+
+    /**
+     * Loads the enabled states from the preference store.
+     */
+    void loadEnabledStates() {
+        loadEnabledStates(Collections.EMPTY_SET, PlatformUI.getWorkbench()
+                .getActivitySupport().getActivityManager()
+                .getDefinedActivityIds());
+    }
+
+    /**
+     * Load the enabled states for the given activity IDs.
+     *
+     * @param previouslyEnabledActivities the activity states to maintain.  This set must be writabe.
+     * @param activityIdsToProcess the activity ids to process
+     */
+    protected void loadEnabledStates(Set previouslyEnabledActivities, Set activityIdsToProcess) {
+        if (activityIdsToProcess.isEmpty()) {
+			return;
+		}
+
+        Set enabledActivities = new HashSet(previouslyEnabledActivities);
+        IPreferenceStore store = WorkbenchPlugin.getDefault()
+                .getPreferenceStore();
+
+        IWorkbenchActivitySupport support = PlatformUI.getWorkbench()
+                .getActivitySupport();
+
+        IActivityManager activityManager = support.getActivityManager();
+
+        for (Iterator i = activityIdsToProcess.iterator(); i
+                .hasNext();) {
+            String activityId = (String) i.next();
+            String preferenceKey = createPreferenceKey(activityId);
+			try {
+				IActivity activity = activityManager.getActivity(activityId);
+				if (activity.getExpression() != null) {
+					continue;
+				}
+                if ("".equals(store.getDefaultString(preferenceKey))) { //$NON-NLS-1$ // no override has been provided in the customization file
+                	store // the default should be whatever the XML specifies
+					.setDefault(preferenceKey, activity
+							.isDefaultEnabled());
+
+                }
+
+            } catch (NotDefinedException e) {
+                // can't happen - we're iterating over defined activities
+            }
+
+            if (store.getBoolean(preferenceKey)) {
+				enabledActivities.add(activityId);
+			} else {
+				enabledActivities.remove(activityId);
+			}
+        }
+
+        support.setEnabledActivityIds(enabledActivities);
+    }
+
+    /**
+     * Save the enabled states in the preference store.
+     */
+    protected void saveEnabledStates() {
+        try {
+            saving = true;
+
+	        IPreferenceStore store = WorkbenchPlugin.getDefault()
+	                .getPreferenceStore();
+
+	        IWorkbenchActivitySupport support = PlatformUI.getWorkbench()
+	                .getActivitySupport();
+	        IActivityManager activityManager = support.getActivityManager();
+	        Iterator values = activityManager.getDefinedActivityIds().iterator();
+	        while (values.hasNext()) {
+	            IActivity activity = activityManager.getActivity((String) values
+	                    .next());
+	            if (activity.getExpression() != null) {
+	            	continue;
+	            }
+
+	            store.setValue(createPreferenceKey(activity.getId()), activity
+	                    .isEnabled());
+	        }
+	        WorkbenchPlugin.getDefault().savePluginPreferences();
+        }
+        finally {
+            saving = false;
+        }
+    }
+
+    /**
+     * Save the enabled state of all activities.
+     */
+    public void shutdown() {
+        unhookListeners();
+        saveEnabledStates();
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/AggregateWorkingSet.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/AggregateWorkingSet.java
new file mode 100644
index 0000000..ad1d816
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/AggregateWorkingSet.java
@@ -0,0 +1,320 @@
+/* Copyright (c) 2005, 2015 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.ui.internal;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.IAggregateWorkingSet;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IWorkingSet;
+import org.eclipse.ui.IWorkingSetManager;
+import org.eclipse.ui.internal.util.Util;
+
+/**
+ *
+ * @since 3.2
+ */
+public class AggregateWorkingSet extends AbstractWorkingSet implements
+		IAggregateWorkingSet, IPropertyChangeListener {
+
+	private IWorkingSet[] components;
+
+	/**
+	 * Prevents stack overflow on cyclic element inclusions.
+	 */
+	private boolean inElementConstruction = false;
+
+	/**
+	 *
+	 * @param name
+	 * @param label
+	 * @param components
+	 */
+	public AggregateWorkingSet(String name, String label,
+			IWorkingSet[] components) {
+		super(name, label);
+
+		IWorkingSet[] componentCopy = new IWorkingSet[components.length];
+		System.arraycopy(components, 0, componentCopy, 0, components.length);
+		internalSetComponents(componentCopy);
+		constructElements(false);
+	}
+
+	/**
+	 *
+	 * @param name
+	 * @param label
+	 * @param memento
+	 */
+	public AggregateWorkingSet(String name, String label, IMemento memento) {
+		super(name, label);
+		workingSetMemento = memento;
+		if (workingSetMemento != null) {
+			String uniqueId = workingSetMemento
+					.getString(IWorkbenchConstants.TAG_ID);
+			if (uniqueId != null) {
+				setUniqueId(uniqueId);
+			}
+		}
+	}
+
+	void setComponents(IWorkingSet[] components) {
+		internalSetComponents(components);
+		constructElements(true);
+	}
+
+	private void internalSetComponents(IWorkingSet[] components) {
+		this.components = components;
+	}
+
+	/**
+	 * Takes the elements from all component working sets and sets them to be
+	 * the elements of this working set. Any duplicates are trimmed.
+	 *
+	 * @param fireEvent whether a working set change event should be fired
+	 */
+	private void constructElements(boolean fireEvent) {
+		if (inElementConstruction) {
+			String msg = NLS.bind(WorkbenchMessages.get().ProblemCyclicDependency, getName());
+            WorkbenchPlugin.log(msg);
+            throw new IllegalStateException(msg);
+		}
+		inElementConstruction = true;
+		try {
+			// use *linked* set to maintain predictable elements order
+			Set<IAdaptable> elements = new LinkedHashSet<>();
+			IWorkingSet[] localComponents = getComponentsInternal();
+			for (int i = 0; i < localComponents.length; i++) {
+				IWorkingSet workingSet = localComponents[i];
+				try {
+					IAdaptable[] componentElements = workingSet.getElements();
+					elements.addAll(Arrays.asList(componentElements));
+				} catch (IllegalStateException e) { // an invalid component; remove it
+					IWorkingSet[] tmp = new IWorkingSet[components.length - 1];
+					if (i > 0)
+						System.arraycopy(components, 0, tmp, 0, i);
+					if (components.length - i - 1 > 0)
+						System.arraycopy(components, i + 1, tmp, i, components.length - i - 1);
+					components = tmp;
+					workingSetMemento = null; // toss cached info
+					fireWorkingSetChanged(IWorkingSetManager.CHANGE_WORKING_SET_CONTENT_CHANGE, null);
+					continue;
+				}
+			}
+			internalSetElements(elements.toArray(new IAdaptable[elements.size()]));
+			if (fireEvent) {
+				fireWorkingSetChanged(
+					IWorkingSetManager.CHANGE_WORKING_SET_CONTENT_CHANGE, null);
+			}
+		} finally {
+			inElementConstruction = false;
+		}
+	}
+
+	@Override
+	public String getId() {
+		return null;
+	}
+
+	@Override
+	public ImageDescriptor getImageDescriptor() {
+		return WorkbenchImages
+				.getImageDescriptor(IWorkbenchGraphicConstants.IMG_OBJ_WORKING_SETS);
+	}
+
+	/**
+	 * A no-op for aggregates - their contents should be derived.
+	 */
+	@Override
+	public void setElements(IAdaptable[] elements) {
+	}
+
+	@Override
+	public void setId(String id) {
+
+	}
+
+	/**
+	 * Aggregates are not editable.
+	 */
+	@Override
+	public boolean isEditable() {
+		return false;
+	}
+
+	/**
+	 * Aggregates should not generally be visible in the UI.
+	 */
+	@Override
+	public boolean isVisible() {
+		return false;
+	}
+
+	@Override
+	public void saveState(IMemento memento) {
+		if (workingSetMemento != null) {
+			// just re-save the previous memento if the working set has
+			// not been restored
+			memento.putMemento(workingSetMemento);
+		} else {
+			memento.putString(IWorkbenchConstants.TAG_NAME, getName());
+			memento.putString(IWorkbenchConstants.TAG_LABEL, getLabel());
+			memento.putString(IWorkbenchConstants.TAG_ID, getUniqueId());
+			memento.putString(AbstractWorkingSet.TAG_AGGREGATE, Boolean.TRUE
+					.toString());
+
+			for (IWorkingSet workingSet : getComponentsInternal()) {
+				memento.createChild(IWorkbenchConstants.TAG_WORKING_SET, workingSet.getName());
+			}
+		}
+	}
+
+	@Override
+	public void connect(IWorkingSetManager manager) {
+		manager.addPropertyChangeListener(this);
+		super.connect(manager);
+	}
+
+	@Override
+	public void disconnect() {
+		IWorkingSetManager connectedManager = getManager();
+		if (connectedManager != null)
+			connectedManager.removePropertyChangeListener(this);
+		super.disconnect();
+	}
+
+	/**
+	 * Return the component working sets.
+	 *
+	 * @return the component working sets
+	 */
+	@Override
+	public IWorkingSet[] getComponents() {
+		IWorkingSet[] localComponents = getComponentsInternal();
+		IWorkingSet[] copiedArray = new IWorkingSet[localComponents.length];
+		System.arraycopy(localComponents, 0, copiedArray, 0, localComponents.length);
+		return copiedArray;
+	}
+
+	private IWorkingSet[] getComponentsInternal() {
+		if (components == null) {
+			restoreWorkingSet();
+			workingSetMemento = null;
+		}
+		return components;
+	}
+
+	@Override
+	public void propertyChange(PropertyChangeEvent event) {
+		String property = event.getProperty();
+		if (property.equals(IWorkingSetManager.CHANGE_WORKING_SET_REMOVE)) {
+			IWorkingSet[] localComponents = getComponentsInternal();
+			for (int i = 0; i < localComponents.length; i++) {
+				IWorkingSet set = localComponents[i];
+				if (set.equals(event.getOldValue())) {
+					IWorkingSet[] newComponents = new IWorkingSet[localComponents.length - 1];
+					Util
+							.arrayCopyWithRemoval(localComponents,
+									newComponents, i);
+					setComponents(newComponents);
+				}
+			}
+		} else if (property
+				.equals(IWorkingSetManager.CHANGE_WORKING_SET_CONTENT_CHANGE)) {
+			IWorkingSet[] localComponents = getComponentsInternal();
+			for (IWorkingSet set : localComponents) {
+				if (set.equals(event.getNewValue())) {
+					constructElements(true);
+					break;
+				}
+			}
+		}
+	}
+
+	@Override
+	void restoreWorkingSet() {
+		IWorkingSetManager manager = getManager();
+		if (manager == null) {
+			throw new IllegalStateException();
+		}
+		IMemento[] workingSetReferences = workingSetMemento
+				.getChildren(IWorkbenchConstants.TAG_WORKING_SET);
+		ArrayList list = new ArrayList(workingSetReferences.length);
+
+		for (IMemento memento : workingSetReferences) {
+			String setId = memento.getID();
+			IWorkingSet set = manager.getWorkingSet(setId);
+			if (set != null) {
+				list.add(set);
+			}
+		}
+		internalSetComponents((IWorkingSet[]) list
+				.toArray(new IWorkingSet[list.size()]));
+		constructElements(false);
+	}
+
+	@Override
+	public boolean equals(Object object) {
+		if (this == object) {
+			return true;
+		}
+		if (object instanceof AggregateWorkingSet) {
+			AggregateWorkingSet workingSet = (AggregateWorkingSet) object;
+
+			return Util.equals(workingSet.getName(), getName())
+					&& Util.equals(workingSet.getComponentsInternal(), getComponentsInternal());
+		}
+		return false;
+	}
+
+	@Override
+	public int hashCode() {
+		int hashCode = getName().hashCode() & java.util.Arrays.hashCode(getComponentsInternal());
+		return hashCode;
+	}
+
+	@Override
+	public boolean isSelfUpdating() {
+		IWorkingSet[] localComponents = getComponentsInternal();
+		if (localComponents == null || localComponents.length == 0) {
+			return false;
+		}
+		for (int i= 0; i < localComponents.length; i++) {
+			if (!localComponents[i].isSelfUpdating()) {
+				return false;
+			}
+		}
+		return true;
+	}
+
+	@Override
+	public boolean isAggregateWorkingSet() {
+		return true;
+	}
+
+	@Override
+	public IAdaptable[] adaptElements(IAdaptable[] objects) {
+		return new IAdaptable[0];
+	}
+
+	@Override
+	public String toString() {
+		return "AWS [name=" + getName() + ", components=" + Arrays.toString(getComponentsInternal()) + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/AnimatedTabFeedback.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/AnimatedTabFeedback.java
new file mode 100644
index 0000000..f7ca55a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/AnimatedTabFeedback.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal;
+
+import org.eclipse.swt.custom.CTabItem;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Shell;
+
+public class AnimatedTabFeedback extends ImageCycleFeedbackBase {
+
+	private CTabItem tabItem;
+
+	public AnimatedTabFeedback(Shell parentShell) {
+		super(parentShell);
+	}
+
+	public AnimatedTabFeedback(Shell parentShell, CTabItem item, Image[] images) {
+		super(parentShell, images);
+		tabItem = item;
+	}
+
+	@Override
+	public void initialize(AnimationEngine engine) {
+		background = tabItem.getParent().getBackground();
+		display = tabItem.getParent().getDisplay();
+	}
+
+	@Override
+	public void saveStoppedImage() {
+		stoppedImage = tabItem.getImage();
+	}
+
+	@Override
+	public void setStoppedImage(Image image) {
+		tabItem.setImage(image);
+	}
+
+	@Override
+	public void showImage(Image image) {
+		if (tabItem.isDisposed()) {
+			return;
+		}
+		tabItem.setImage(image);
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/AnimationEngine.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/AnimationEngine.java
new file mode 100644
index 0000000..c139cee
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/AnimationEngine.java
@@ -0,0 +1,216 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal;
+
+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.preference.IPreferenceStore;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkbenchPreferenceConstants;
+import org.eclipse.ui.internal.tweaklets.Animations;
+import org.eclipse.ui.internal.tweaklets.Tweaklets;
+import org.eclipse.ui.internal.util.PrefUtil;
+
+/**
+ * This job creates an Animation Engine that uses an Animation Feedback to render
+ * the animation. To begin the animation, instantiate this
+ * object then call schedule().
+ * @since 3.3
+ *
+ */
+public class AnimationEngine extends Job {
+	public static final int TICK_TIMER = 1;
+	public static final int FRAME_COUNT = 2;
+	public static final int unlimitedDuration = -1;
+
+	private boolean enableAnimations;
+	private long startTime;
+	private long curTime;
+	private long prevTime;
+	private int timingStyle = TICK_TIMER;
+	private long frameCount;
+	private boolean animationCanceled = false;
+	private long sleepAmount;
+
+	private Display display;
+	private AnimationFeedbackBase feedbackRenderer;
+	private int duration;
+
+	public AnimationEngine(AnimationFeedbackBase animationFeedback,
+			int durationIn) {
+		this(animationFeedback, durationIn, 0);
+	}
+
+	/**
+	 * Creates an Animation that will run for the given number of milliseconds.
+	 *
+	 * @param animationFeedback provides renderStep(), initialize() and jobInit() methods
+	 * @param durationIn number of milliseconds over which the animation will run
+	 * @param sleepAmountIn number of milliseconds to slow/delay the animation
+	 */
+	public AnimationEngine(AnimationFeedbackBase animationFeedback,
+			int durationIn, long sleepAmountIn) {
+		super(WorkbenchMessages.get().RectangleAnimation_Animating_Rectangle);
+		sleepAmount = sleepAmountIn;
+		feedbackRenderer = animationFeedback;
+		duration = durationIn;
+
+		// if animations aren't on this is a NO-OP
+		IPreferenceStore preferenceStore = PrefUtil.getAPIPreferenceStore();
+		enableAnimations = preferenceStore
+				.getBoolean(IWorkbenchPreferenceConstants.ENABLE_ANIMATIONS);
+		if (!enableAnimations) {
+			return;
+		}
+
+		animationCanceled = false;
+
+		// Capture parameters
+		display = feedbackRenderer.getAnimationShell().getDisplay();
+
+		animationFeedback.getAnimationShell().addDisposeListener(e -> cancelAnimation());
+
+		// Don't show the job in monitors
+		setSystem(true);
+
+		// Set it up
+		feedbackRenderer.initialize(this);
+
+		// Set the animation's initial state
+		curTime = startTime = System.currentTimeMillis();
+
+	}
+
+	/**
+	 * @return The current renderer
+	 */
+	public AnimationFeedbackBase getFeedback() {
+		return feedbackRenderer;
+	}
+
+	private Runnable animationStep = () -> {
+		if (animationCanceled)
+			return;
+
+		// Capture time
+		prevTime = curTime;
+		curTime = System.currentTimeMillis();
+
+		if (isUpdateStep()) {
+			updateDisplay();
+			frameCount++;
+		}
+	};
+
+	protected void updateDisplay() {
+		if (animationCanceled)
+			return;
+
+		feedbackRenderer.renderStep(this);
+	}
+
+	protected boolean isUpdateStep() {
+		if (duration == unlimitedDuration || timingStyle == FRAME_COUNT) {
+			return true;
+		}
+
+		// Default to 'TICK_TIMER', update when the system timer changes
+		return prevTime != curTime;
+	}
+
+	private boolean done() {
+		return animationCanceled || amount() >= 1.0;
+	}
+
+	public double amount() {
+		if (duration == unlimitedDuration) {
+			return 0;
+		}
+		double amount = 0.0;
+		switch (timingStyle) {
+			case TICK_TIMER:
+				amount = (double) (curTime - startTime) / (double) duration;
+				break;
+
+			// For testing purposes
+			case FRAME_COUNT:
+				amount = (double) frameCount / (double) duration;
+		}
+
+		if (amount > 1.0)
+			amount = 1.0;
+
+		return amount;
+	}
+
+	@Override
+	protected IStatus run(IProgressMonitor monitor) {
+		// We use preference value to indicate that the animation should be skipped on this platform.
+		if (!enableAnimations) {
+			return Status.OK_STATUS;
+		}
+
+		// We're starting, initialize
+		display.syncExec(() -> {
+			// 'jobInit' returns 'false' if it doesn't want to run...
+			if (!animationCanceled)
+				animationCanceled = !feedbackRenderer.jobInit(AnimationEngine.this);
+		});
+
+		if (animationCanceled)
+			return Status.CANCEL_STATUS;
+
+		// Only start the animation timer -after- we've initialized
+		curTime = startTime = System.currentTimeMillis();
+
+		while (!done() && !animationCanceled) {
+			display.syncExec(animationStep);
+
+			// Don't pin the CPU
+			try {
+				Thread.sleep(sleepAmount);
+			} catch (InterruptedException e) {
+			}
+		}
+
+		if (animationCanceled)
+			return Status.CANCEL_STATUS;
+
+		// We're done, clean up
+		display.syncExec(() -> feedbackRenderer.dispose());
+
+		return Status.OK_STATUS;
+	}
+
+	public void cancelAnimation() {
+		animationCanceled = true;
+		feedbackRenderer.dispose();
+		cancel();
+	}
+
+	public long getFrameCount() {
+		return frameCount;
+	}
+
+	public static void createTweakedAnimation(Shell shell, int duration, Rectangle start, Rectangle end) {
+		RectangleAnimationFeedbackBase feedback = ((Animations) Tweaklets
+				.get(Animations.KEY)).createFeedback(shell);
+		feedback.addStartRect(start);
+		feedback.addEndRect(end);
+
+		AnimationEngine animation = new AnimationEngine(feedback, 400);
+		animation.schedule();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/AnimationFeedbackBase.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/AnimationFeedbackBase.java
new file mode 100644
index 0000000..971bacc
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/AnimationFeedbackBase.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * AnimationFeedBackBase is an abstract class which provides renderStep(), jobInit() and
+ * initialize() methods for AnimationEngine.
+ * Its the base class for all the
+ * animationFeedbacks
+ *
+ * @since 3.3
+ *
+ */
+public abstract class AnimationFeedbackBase {
+	private AnimationEngine engine;
+	private Shell baseShell;
+	private Shell animationShell = null;
+
+	/**
+	 * Creates an AnimationFeedback
+	 *
+	 * @param parentShell specifies the composite where the animation will be drawn
+	 */
+	public AnimationFeedbackBase(Shell parentShell) {
+		baseShell = parentShell;
+
+		baseShell.addDisposeListener(e -> {
+			if (engine != null)
+				engine.cancelAnimation();
+		});
+	}
+
+	/**
+	 * Perform any initialization you want to do -prior- to the Job actually
+	 * gets scheduled.
+	 *
+	 * @param animationEngine The engine we're hosted in.
+	 */
+	public abstract void initialize(AnimationEngine animationEngine);
+
+	/**
+	 * Its a draw method. All the code to render an animation goes in this
+	 * method.
+	 *
+	 * @param engine
+	 */
+	public abstract void renderStep(AnimationEngine engine);
+
+	/**
+	 * Perform any initialization you want to have happen -before- the animation
+	 * starts. Subclasses may subclass but not override (i.e. you have to call super).
+	 *
+	 * @param engine The AnimationEngine hosting the feedback
+	 * @return 'true' iff the animation is capable of running
+	 */
+	public boolean jobInit(AnimationEngine engine) {
+		this.engine = engine;
+		return engine != null;
+	}
+
+	/**
+	 * Dispose any locally created resources
+	 */
+	public void dispose() {
+		if (animationShell != null && !animationShell.isDisposed())
+			animationShell.dispose();
+	}
+
+	/**
+	 * @return The shell this animation is being rendered 'on'
+	 */
+	public Shell getBaseShell() {
+		return baseShell;
+	}
+
+	/**
+	 * @return A shell that can be used to render the animation on
+	 */
+	public Shell getAnimationShell() {
+		if (animationShell == null) {
+			animationShell = new Shell(getBaseShell(), SWT.NO_TRIM | SWT.ON_TOP);
+
+			animationShell.addDisposeListener(e -> {
+				if (engine != null)
+					engine.cancelAnimation();
+			});
+		}
+
+		return animationShell;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/BindingToModelProcessor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/BindingToModelProcessor.java
new file mode 100644
index 0000000..a23a1e5
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/BindingToModelProcessor.java
@@ -0,0 +1,179 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ ******************************************************************************/
+
+package org.eclipse.ui.internal;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.eclipse.core.commands.CommandManager;
+import org.eclipse.core.commands.contexts.ContextManager;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.e4.ui.bindings.EBindingService;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.commands.MBindingContext;
+import org.eclipse.e4.ui.model.application.commands.MBindingTable;
+import org.eclipse.e4.ui.model.application.commands.MCommand;
+import org.eclipse.e4.ui.model.application.commands.MCommandsFactory;
+import org.eclipse.e4.ui.model.application.commands.MKeyBinding;
+import org.eclipse.e4.ui.model.application.commands.impl.CommandsFactoryImpl;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.jface.bindings.Binding;
+import org.eclipse.jface.bindings.BindingManager;
+import org.eclipse.ui.internal.keys.BindingPersistence;
+import org.eclipse.ui.internal.keys.BindingService;
+
+public class BindingToModelProcessor {
+
+	private Map<String, MBindingContext> contexts = new HashMap<>();
+	private Map<String, MCommand> commands = new HashMap<>();
+	private Map<String, MBindingTable> tables = new HashMap<>();
+	private Set<MKeyBinding> keys = new HashSet<>();
+
+	@Execute
+	void process(final MApplication application, IEclipseContext context) {
+		gatherContexts(application.getRootContext());
+		gatherCommands(application.getCommands());
+		gatherTables(application.getBindingTables());
+
+		CommandManager commandManager = context.get(CommandManager.class);
+		if (commandManager == null) {
+			WorkbenchPlugin
+					.log("Command manager was null in org.eclipse.ui.internal.BindingToModelProcessor"); //$NON-NLS-1$
+		}
+		ContextManager contextManager = context.get(ContextManager.class);
+		if (contextManager == null) {
+			WorkbenchPlugin
+					.log("Context manager was null in org.eclipse.ui.internal.BindingToModelProcessor"); //$NON-NLS-1$
+		}
+		BindingManager bindingManager = new BindingManager(contextManager, commandManager);
+		context.set(BindingManager.class, bindingManager);
+		BindingPersistence persistence = new BindingPersistence(bindingManager, commandManager);
+//		persistence.read();
+
+		// we'll make this available, although I doubt we have a use for it
+//		application.getTags().add(
+//				EBindingService.ACTIVE_SCHEME_TAG + ':' + bindingManager.getActiveScheme().getId());
+
+		Collection<?> activeBindingsForScheme = bindingManager
+				.getActiveBindingsDisregardingContextFlat();
+
+		for (Object obj : activeBindingsForScheme) {
+			Binding binding = (Binding) obj;
+			addBinding(application, binding);
+		}
+
+		removeBindings();
+
+		persistence.dispose();
+		contexts.clear();
+		commands.clear();
+		tables.clear();
+		keys.clear();
+	}
+
+	private void gatherTables(List<MBindingTable> bindingTables) {
+		for (MBindingTable table : bindingTables) {
+			tables.put(table.getBindingContext().getElementId(), table);
+			keys.addAll(table.getBindings());
+		}
+	}
+
+	public final void addBinding(final MApplication application, final Binding binding) {
+
+
+		MBindingTable table = tables.get(binding.getContextId());
+		if (table == null) {
+			table = createTable(application, binding.getContextId());
+		}
+		MKeyBinding model = BindingService.createORupdateMKeyBinding(application, table, binding);
+		keys.remove(model);
+	}
+
+	private void removeBindings() {
+		for (MKeyBinding key : keys) {
+			if (!key.getTags().contains("type:user")) { //$NON-NLS-1$
+				EObject obj = ((EObject) key).eContainer();
+				if (obj instanceof MBindingTable) {
+					MBindingTable table = (MBindingTable) obj;
+					table.getBindings().remove(key);
+				}
+			}
+		}
+	}
+
+	public MBindingContext getBindingContext(MApplication application, String id) {
+		// cache
+		MBindingContext result = contexts.get(id);
+		if (result == null) {
+			// search
+			result = searchContexts(id, application.getRootContext());
+			if (result == null) {
+				// create
+				result = MCommandsFactory.INSTANCE.createBindingContext();
+				result.setElementId(id);
+				result.setName("Auto::" + id); //$NON-NLS-1$
+				application.getRootContext().add(result);
+			}
+			if (result != null) {
+				contexts.put(id, result);
+			}
+		}
+		return result;
+	}
+
+	private MBindingContext searchContexts(String id, List<MBindingContext> rootContext) {
+		for (MBindingContext context : rootContext) {
+			if (context.getElementId().equals(id)) {
+				return context;
+			}
+			MBindingContext result = searchContexts(id, context.getChildren());
+			if (result != null) {
+				return result;
+			}
+		}
+		return null;
+	}
+
+	private MBindingTable createTable(MApplication application, String contextId) {
+		MBindingTable table = CommandsFactoryImpl.eINSTANCE.createBindingTable();
+		table.setBindingContext(getBindingContext(application, contextId));
+		table.setElementId(contextId);
+		application.getBindingTables().add(table);
+		tables.put(table.getBindingContext().getElementId(), table);
+		return table;
+	}
+
+	private void gatherCommands(List<MCommand> commandList) {
+		for (MCommand cmd : commandList) {
+			commands.put(cmd.getElementId(), cmd);
+		}
+	}
+
+	private void gatherContexts(List<MBindingContext> contextList) {
+		for (MBindingContext ctx : contextList) {
+			gatherContexts(ctx);
+		}
+	}
+
+	private void gatherContexts(MBindingContext ctx) {
+		if (ctx == null) {
+			return;
+		}
+		contexts.put(ctx.getElementId(), ctx);
+		gatherContexts(ctx.getChildren());
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/BrandingProperties.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/BrandingProperties.java
new file mode 100644
index 0000000..ce6cce2
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/BrandingProperties.java
@@ -0,0 +1,128 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.osgi.framework.Bundle;
+
+/**
+ * The branding properties are retrieved as strings, but often used as other
+ * types (e.g., <code>java.net.URL</code>s. This class provides some utility
+ * functions for converting the string values to these well known classes. This
+ * may be subclassed by clients that use more than just these few types.
+ */
+public abstract class BrandingProperties {
+
+    /**
+     * Create an url from the argument absolute or relative path. The bundle
+     * parameter is used as the base for relative paths and is allowed to be
+     * null.
+     *
+     * @param value
+     *            the absolute or relative path
+     * @param definingBundle
+     *            bundle to be used for relative paths (may be null)
+     * @return
+     */
+    public static URL getUrl(String value, Bundle definingBundle) {
+        try {
+            if (value != null) {
+				return new URL(value);
+			}
+        } catch (MalformedURLException e) {
+            if (definingBundle != null) {
+				return Platform.find(definingBundle, new Path(value));
+			}
+        }
+
+        return null;
+    }
+
+    /**
+     * Create a descriptor from the argument absolute or relative path to an
+     * image file. bundle parameter is used as the base for relative paths and
+     * is allowed to be null.
+     *
+     * @param value
+     *            the absolute or relative path
+     * @param definingBundle
+     *            bundle to be used for relative paths (may be null)
+     * @return
+     */
+    public static ImageDescriptor getImage(String value, Bundle definingBundle) {
+        URL url = getUrl(value, definingBundle);
+        return url == null ? null : ImageDescriptor.createFromURL(url);
+    }
+
+    /**
+     * Returns a array of URL for the given property or <code>null</code>.
+     * The property value should be a comma separated list of urls (either
+     * absolute or relative to the argument bundle). Tokens that do not
+     * represent a valid url will be represented with a null entry in the
+     * returned array.
+     *
+     * @param value
+     *            value of a property that contains a comma-separated list of
+     *            product relative urls
+     * @param definingBundle
+     *            bundle to be used as base for relative paths (may be null)
+     * @return a URL for the given property, or <code>null</code>
+     */
+    public static URL[] getURLs(String value, Bundle definingBundle) {
+        if (value == null) {
+			return null;
+		}
+
+        StringTokenizer tokens = new StringTokenizer(value, ","); //$NON-NLS-1$
+        ArrayList array = new ArrayList(10);
+        while (tokens.hasMoreTokens()) {
+			array.add(getUrl(tokens.nextToken().trim(), definingBundle));
+		}
+
+        return (URL[]) array.toArray(new URL[array.size()]);
+    }
+
+    /**
+     * Returns an array of image descriptors for the given property, or
+     * <code>null</code>. The property value should be a comma separated list
+     * of image paths. Each path should either be absolute or relative to the
+     * optional bundle parameter.
+     *
+     * @param value
+     *            value of a property that contains a comma-separated list of
+     *            product relative urls describing images
+     * @param definingBundle
+     *            bundle to be used for relative paths (may be null)
+     * @return an array of image descriptors for the given property, or
+     *         <code>null</code>
+     */
+    public static ImageDescriptor[] getImages(String value,
+            Bundle definingBundle) {
+        URL[] urls = getURLs(value, definingBundle);
+        if (urls == null || urls.length <= 0) {
+			return null;
+		}
+
+        ImageDescriptor[] images = new ImageDescriptor[urls.length];
+        for (int i = 0; i < images.length; ++i) {
+			images[i] = ImageDescriptor.createFromURL(urls[i]);
+		}
+
+        return images;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/BundleGroupProperties.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/BundleGroupProperties.java
new file mode 100644
index 0000000..f4fdb0f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/BundleGroupProperties.java
@@ -0,0 +1,284 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal;
+
+import java.net.URL;
+
+import org.eclipse.core.runtime.IBundleGroup;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.branding.IBundleGroupConstants;
+
+/**
+ * A class that converts the strings returned by
+ * <code>org.eclipse.core.runtime.IBundleGroup.getProperty</code> to the
+ * appropriate class. This implementation is tightly bound to the properties
+ * provided in IBundleGroupConstants. Clients adding their own properties could
+ * choose to subclass this.
+ *
+ * @see org.eclipse.ui.branding.IBundleGroupConstants
+ * @since 3.0
+ */
+public class BundleGroupProperties extends BrandingProperties implements
+        IBundleGroupConstants {
+
+    private final IBundleGroup bundleGroup;
+
+    private ImageDescriptor featureImageDescriptor;
+
+    private URL featureImageUrl;
+
+    private String tipsAndTricksHref;
+
+    private URL welcomePageUrl;
+
+    private String welcomePerspective;
+
+    private URL licenseUrl;
+
+    private String featureLabel;
+
+    private String featureId;
+
+    private String providerName;
+
+    private String versionId;
+
+	private String brandingId;
+
+	private String brandingVersion;
+
+    /**
+     * This instance will return properties from the given bundle group.  The properties are
+     * retrieved in a lazy fashion and cached for later retrieval.
+     * @param bundleGroup must not be null
+     */
+    public BundleGroupProperties(IBundleGroup bundleGroup) {
+        if (bundleGroup == null) {
+			throw new IllegalArgumentException();
+		}
+        this.bundleGroup = bundleGroup;
+    }
+
+    /**
+     * An image which can be shown in an "about features" dialog (32x32).
+     */
+    public ImageDescriptor getFeatureImage() {
+        if (featureImageDescriptor == null) {
+			featureImageDescriptor = getFeatureImage(bundleGroup);
+		}
+        return featureImageDescriptor;
+    }
+
+    /**
+     * The URL to an image which can be shown in an "about features" dialog (32x32).
+     */
+    public URL getFeatureImageUrl() {
+        if (featureImageUrl == null) {
+			featureImageUrl = getFeatureImageUrl(bundleGroup);
+		}
+        return featureImageUrl;
+    }
+
+    /**
+     * A help reference for the feature's tips and tricks page (optional).
+     */
+    public String getTipsAndTricksHref() {
+        if (tipsAndTricksHref == null) {
+			tipsAndTricksHref = getTipsAndTricksHref(bundleGroup);
+		}
+        return tipsAndTricksHref;
+    }
+
+    /**
+     * A URL for the feature's welcome page (special XML-based format) ($nl$/
+     * prefix to permit locale-specific translations of entire file). Products
+     * designed to run "headless" typically would not have such a page.
+     */
+    public URL getWelcomePageUrl() {
+        if (welcomePageUrl == null) {
+			welcomePageUrl = getWelcomePageUrl(bundleGroup);
+		}
+        return welcomePageUrl;
+    }
+
+    /**
+     * The id of a perspective in which to show the welcome page (optional).
+     */
+    public String getWelcomePerspective() {
+        if (welcomePerspective == null) {
+			welcomePerspective = getWelcomePerspective(bundleGroup);
+		}
+        return welcomePerspective;
+    }
+
+    /**
+     * A URL for the feature's license page.
+     */
+    public URL getLicenseUrl() {
+        if (licenseUrl == null) {
+			licenseUrl = getLicenseUrl(bundleGroup);
+		}
+        return licenseUrl;
+    }
+
+    /**
+     * Returns a label for the feature plugn, or <code>null</code>.
+     */
+    public String getFeatureLabel() {
+        if (featureLabel == null) {
+			featureLabel = getFeatureLabel(bundleGroup);
+		}
+        return featureLabel;
+    }
+
+    /**
+     * Returns the id for this bundleGroup.
+     */
+    public String getFeatureId() {
+        if (featureId == null) {
+			featureId = getFeatureId(bundleGroup);
+		}
+        return featureId;
+    }
+
+    /**
+     * Returns the provider name.
+     */
+    public String getProviderName() {
+        if (providerName == null) {
+			providerName = getProviderName(bundleGroup);
+		}
+        return providerName;
+    }
+
+    /**
+     * Returns the feature version id.
+     */
+    public String getFeatureVersion() {
+        if (versionId == null) {
+			versionId = getFeatureVersion(bundleGroup);
+		}
+        return versionId;
+    }
+
+	/**
+	 * @return the branding plugin id, or <code>null</code>
+	 */
+	public String getBrandingBundleId() {
+		if (brandingId == null) {
+			brandingId = getBrandingBundleId(bundleGroup);
+		}
+		return brandingId;
+	}
+
+	/**
+	 * @return the branding plugin version, or <code>null</code>
+	 */
+	public String getBrandingBundleVersion() {
+		if (brandingVersion == null) {
+			brandingVersion = getBrandingBundleVersion(bundleGroup);
+		}
+		return brandingVersion;
+	}
+
+    /**
+     * An image which can be shown in an "about features" dialog (32x32).
+     */
+    public static ImageDescriptor getFeatureImage(IBundleGroup bundleGroup) {
+        return getImage(bundleGroup.getProperty(FEATURE_IMAGE), null);
+    }
+
+    /**
+     * The URL to an image which can be shown in an "about features" dialog (32x32).
+     */
+    public static URL getFeatureImageUrl(IBundleGroup bundleGroup) {
+        return getUrl(bundleGroup.getProperty(FEATURE_IMAGE), null);
+    }
+
+    /**
+     * A help reference for the feature's tips and tricks page (optional).
+     */
+    public static String getTipsAndTricksHref(IBundleGroup bundleGroup) {
+        return bundleGroup.getProperty(TIPS_AND_TRICKS_HREF);
+    }
+
+    /**
+     * A URL for the feature's welcome page (special XML-based format) ($nl$/
+     * prefix to permit locale-specific translations of entire file). Products
+     * designed to run "headless" typically would not have such a page.
+     */
+    public static URL getWelcomePageUrl(IBundleGroup bundleGroup) {
+        return getUrl(bundleGroup.getProperty(WELCOME_PAGE), null);
+    }
+
+    /**
+     * The id of a perspective in which to show the welcome page (optional).
+     */
+    public static String getWelcomePerspective(IBundleGroup bundleGroup) {
+        String property = bundleGroup.getProperty(WELCOME_PERSPECTIVE);
+        return property == null ? null : property;
+    }
+
+    /**
+     * A URL for the feature's license page.
+     */
+    public static URL getLicenseUrl(IBundleGroup bundleGroup) {
+        return getUrl(bundleGroup.getProperty(LICENSE_HREF), null);
+    }
+
+    /**
+     * Returns a label for the feature plugn, or <code>null</code>.
+     */
+    public static String getFeatureLabel(IBundleGroup bundleGroup) {
+        return bundleGroup.getName();
+    }
+
+    /**
+     * Returns the id for this bundleGroup.
+     */
+    public static String getFeatureId(IBundleGroup bundleGroup) {
+        return bundleGroup.getIdentifier();
+    }
+
+    /**
+     * Returns the provider name.
+     */
+    public static String getProviderName(IBundleGroup bundleGroup) {
+        return bundleGroup.getProviderName();
+    }
+
+    /**
+     * Returns the feature version id.
+     */
+    public static String getFeatureVersion(IBundleGroup bundleGroup) {
+        return bundleGroup.getVersion();
+    }
+
+	/**
+	 * A Feature's branding plugin id.
+	 *
+	 * @param bundleGroup
+	 * @return the ID or <code>null</code> if not provided.
+	 */
+	public static String getBrandingBundleId(IBundleGroup bundleGroup) {
+		return bundleGroup.getProperty(BRANDING_BUNDLE_ID);
+	}
+
+	/**
+	 * A Feature's branding plugin version.
+	 *
+	 * @param bundleGroup
+	 * @return the version, or <code>null</code> if not provided.
+	 */
+	public static String getBrandingBundleVersion(IBundleGroup bundleGroup) {
+		return bundleGroup.getProperty(BRANDING_BUNDLE_VERSION);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ChangeToPerspectiveMenu.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ChangeToPerspectiveMenu.java
new file mode 100644
index 0000000..099955b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ChangeToPerspectiveMenu.java
@@ -0,0 +1,114 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *******************************************************************************/
+package org.eclipse.ui.internal;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.NotEnabledException;
+import org.eclipse.core.commands.NotHandledException;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.actions.PerspectiveMenu;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.internal.util.PrefUtil;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+/**
+ * Change the perspective of the active page in the window
+ * to the selected one.
+ */
+public class ChangeToPerspectiveMenu extends PerspectiveMenu {
+
+    /**
+     * Constructor for ChangeToPerspectiveMenu.
+     *
+     * @param window the workbench window this action applies to
+     * @param id the menu id
+     */
+    public ChangeToPerspectiveMenu(IWorkbenchWindow window, String id) {
+        super(window, id);
+        // indicate that a open perspectives submenu has been created
+		if (window instanceof WorkbenchWindow) {
+			((WorkbenchWindow) window)
+					.addSubmenu(WorkbenchWindow.OPEN_PERSPECTIVE_SUBMENU);
+		}
+        showActive(true);
+    }
+
+    @Override
+	protected void run(IPerspectiveDescriptor desc) {
+		IPreferenceStore store = PrefUtil.getInternalPreferenceStore();
+		int mode = store.getInt(IPreferenceConstants.OPEN_PERSP_MODE);
+		IWorkbenchPage page = getWindow().getActivePage();
+		IPerspectiveDescriptor persp = null;
+		if (page != null) {
+			persp = page.getPerspective();
+		}
+
+		IHandlerService handlerService = getWindow()
+				.getService(IHandlerService.class);
+		ICommandService commandService = getWindow()
+				.getService(ICommandService.class);
+
+		Command command = commandService
+				.getCommand(IWorkbenchCommandConstants.PERSPECTIVES_SHOW_PERSPECTIVE);
+		Map parameters = new HashMap();
+		parameters
+				.put(
+						IWorkbenchCommandConstants.PERSPECTIVES_SHOW_PERSPECTIVE_PARM_ID,
+						desc.getId());
+
+		// Only open a new window if user preference is set and the window
+		// has an active perspective.
+		if (IPreferenceConstants.OPM_NEW_WINDOW == mode && persp != null) {
+
+			//Call the handler!
+			//Set up the param for newWindow!
+			parameters
+					.put(
+							"org.eclipse.ui.perspectives.showPerspective.newWindow", "true"); //$NON-NLS-1$//$NON-NLS-2$
+		}
+
+		ParameterizedCommand pCommand = ParameterizedCommand.generateCommand(
+				command, parameters);
+		try {
+			handlerService.executeCommand(pCommand, null);
+		} catch (ExecutionException e) {
+			StatusManager.getManager().handle(
+					new Status(IStatus.WARNING, WorkbenchPlugin.PI_WORKBENCH,
+							"Failed to execute " + IWorkbenchCommandConstants.PERSPECTIVES_SHOW_PERSPECTIVE, e)); //$NON-NLS-1$
+		} catch (NotDefinedException e) {
+			StatusManager.getManager().handle(
+					new Status(IStatus.WARNING, WorkbenchPlugin.PI_WORKBENCH,
+							"Failed to execute " + IWorkbenchCommandConstants.PERSPECTIVES_SHOW_PERSPECTIVE, e)); //$NON-NLS-1$
+		} catch (NotEnabledException e) {
+			StatusManager.getManager().handle(
+					new Status(IStatus.WARNING, WorkbenchPlugin.PI_WORKBENCH,
+							"Failed to execute " + IWorkbenchCommandConstants.PERSPECTIVES_SHOW_PERSPECTIVE, e)); //$NON-NLS-1$
+		} catch (NotHandledException e) {
+			StatusManager.getManager().handle(
+					new Status(IStatus.WARNING, WorkbenchPlugin.PI_WORKBENCH,
+							"Failed to execute " + IWorkbenchCommandConstants.PERSPECTIVES_SHOW_PERSPECTIVE, e)); //$NON-NLS-1$
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/CloseAllHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/CloseAllHandler.java
new file mode 100644
index 0000000..672c961
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/CloseAllHandler.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.ExpressionInfo;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.ui.IEditorReference;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * Closes all active editors
+ * <p>
+ * Replacement for CloseAllAction
+ * </p>
+ *
+ * @since 3.3
+ *
+ */
+public class CloseAllHandler extends AbstractEvaluationHandler {
+	private Expression enabledWhen;
+
+	public CloseAllHandler() {
+		registerEnablement();
+	}
+
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		IWorkbenchWindow window = HandlerUtil
+				.getActiveWorkbenchWindowChecked(event);
+		IWorkbenchPage page = window.getActivePage();
+		if (page != null) {
+			page.closeAllEditors(true);
+		}
+
+		return null;
+	}
+
+	@Override
+	protected Expression getEnabledWhenExpression() {
+		if (enabledWhen == null) {
+			enabledWhen = new Expression() {
+				@Override
+				public EvaluationResult evaluate(IEvaluationContext context)
+						throws CoreException {
+					IWorkbenchPart part = InternalHandlerUtil.getActivePart(context);
+					Object perspective = InternalHandlerUtil.getVariable(context,
+							ISources.ACTIVE_WORKBENCH_WINDOW_ACTIVE_PERSPECTIVE_NAME);
+					if (part != null && perspective != null) {
+						IWorkbenchPage page = part.getSite().getPage();
+						if (page != null) {
+							IEditorReference[] refArray = page.getEditorReferences();
+							if (refArray != null && refArray.length > 0) {
+								return EvaluationResult.TRUE;
+							}
+						}
+					}
+					return EvaluationResult.FALSE;
+				}
+
+				@Override
+				public void collectExpressionInfo(ExpressionInfo info) {
+					info.addVariableNameAccess(ISources.ACTIVE_PART_NAME);
+					info.addVariableNameAccess(ISources.ACTIVE_WORKBENCH_WINDOW_ACTIVE_PERSPECTIVE_NAME);
+				}
+			};
+		}
+		return enabledWhen;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/CloseAllSavedAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/CloseAllSavedAction.java
new file mode 100644
index 0000000..cf18312
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/CloseAllSavedAction.java
@@ -0,0 +1,133 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2014 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.ui.internal;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorReference;
+import org.eclipse.ui.IPropertyListener;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+
+/**
+ *	Closes all editors except ones with unsaved changes.
+ */
+public class CloseAllSavedAction extends PageEventAction implements
+        IPropertyListener {
+
+    /**
+     * List of parts (element type: <code>IWorkbenchPart</code>)
+     * against which this class has outstanding property listeners registered.
+     */
+    private List partsWithListeners = new ArrayList(1);
+
+    /**
+     * Create an instance of this class.
+     * @param window the window
+     */
+    public CloseAllSavedAction(IWorkbenchWindow window) {
+        super(WorkbenchMessages.get().CloseAllSavedAction_text, window);
+        setToolTipText(WorkbenchMessages.get().CloseAllSavedAction_toolTip);
+        // @issue Should create a ID in IWorkbenchActionConstants when it becames API?
+        setId("closeAllSaved"); //$NON-NLS-1$
+        updateState();
+        window.getWorkbench().getHelpSystem().setHelp(this,
+				IWorkbenchHelpContextIds.CLOSE_ALL_SAVED_ACTION);
+        setActionDefinitionId("org.eclipse.ui.file.closeAllSaved"); //$NON-NLS-1$
+    }
+
+    @Override
+	public void pageActivated(IWorkbenchPage page) {
+        super.pageActivated(page);
+        updateState();
+    }
+
+    @Override
+	public void pageClosed(IWorkbenchPage page) {
+        super.pageClosed(page);
+        updateState();
+    }
+
+    @Override
+	public void partClosed(IWorkbenchPart part) {
+        super.partClosed(part);
+        if (part instanceof IEditorPart) {
+            part.removePropertyListener(this);
+            partsWithListeners.remove(part);
+            updateState();
+        }
+    }
+
+    @Override
+	public void partOpened(IWorkbenchPart part) {
+        super.partOpened(part);
+        if (part instanceof IEditorPart) {
+            part.addPropertyListener(this);
+            partsWithListeners.add(part);
+            updateState();
+        }
+    }
+
+    @Override
+	public void propertyChanged(Object source, int propID) {
+        if (source instanceof IEditorPart) {
+            if (propID == IEditorPart.PROP_DIRTY) {
+                updateState();
+            }
+        }
+    }
+
+    @Override
+	public void run() {
+        if (getWorkbenchWindow() == null) {
+            // action has been dispose
+            return;
+        }
+        IWorkbenchPage page = getActivePage();
+        if (page != null) {
+            ((WorkbenchPage) page).closeAllSavedEditors();
+        }
+    }
+
+    /**
+     * Enable the action if there at least one editor open.
+     */
+    private void updateState() {
+        IWorkbenchPage page = getActivePage();
+        if (page == null) {
+            setEnabled(false);
+            return;
+        }
+        IEditorReference editors[] = page.getEditorReferences();
+        for (int i = 0; i < editors.length; i++) {
+            if (!editors[i].isDirty()) {
+                setEnabled(true);
+                return;
+            }
+        }
+        setEnabled(false);
+    }
+
+    @Override
+	public void dispose() {
+        super.dispose();
+        for (Iterator it = partsWithListeners.iterator(); it.hasNext();) {
+            IWorkbenchPart part = (IWorkbenchPart) it.next();
+            part.removePropertyListener(this);
+        }
+        partsWithListeners.clear();
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/CloseEditorHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/CloseEditorHandler.java
new file mode 100644
index 0000000..bb79d79
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/CloseEditorHandler.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.ExpressionInfo;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * Closes the active editor.
+ * <p>
+ * Replacement for CloseEditorAction
+ * </p>
+ *
+ * @since 3.3
+ *
+ */
+public class CloseEditorHandler extends AbstractEvaluationHandler {
+
+	private Expression enabledWhen;
+
+	public CloseEditorHandler() {
+		registerEnablement();
+	}
+
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		IWorkbenchWindow window = HandlerUtil
+				.getActiveWorkbenchWindowChecked(event);
+		IEditorPart part = HandlerUtil.getActiveEditorChecked(event);
+		window.getActivePage().closeEditor(part, true);
+
+		return null;
+	}
+
+	@Override
+	protected Expression getEnabledWhenExpression() {
+		if (enabledWhen == null) {
+			enabledWhen = new Expression() {
+				@Override
+				public EvaluationResult evaluate(IEvaluationContext context)
+						throws CoreException {
+					IEditorPart part = InternalHandlerUtil
+							.getActiveEditor(context);
+					if (part != null) {
+						return EvaluationResult.TRUE;
+
+					}
+					return EvaluationResult.FALSE;
+				}
+
+				@Override
+				public void collectExpressionInfo(ExpressionInfo info) {
+					info.addVariableNameAccess(ISources.ACTIVE_EDITOR_NAME);
+				}
+			};
+		}
+		return enabledWhen;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/CloseOthersHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/CloseOthersHandler.java
new file mode 100644
index 0000000..66dc21f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/CloseOthersHandler.java
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.ExpressionInfo;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.ui.IEditorReference;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * Closes all editors except the one that is active.
+ * <p>
+ * Replacement for CloseOthersHandler
+ * </p>
+ *
+ * @since 3.3
+ *
+ */
+public class CloseOthersHandler extends AbstractEvaluationHandler {
+	private Expression enabledWhen;
+
+	public CloseOthersHandler() {
+		registerEnablement();
+	}
+
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		IWorkbenchWindow window = HandlerUtil
+				.getActiveWorkbenchWindowChecked(event);
+		IWorkbenchPage page = window.getActivePage();
+		if (page != null) {
+			IEditorReference[] refArray = page.getEditorReferences();
+			if (refArray != null && refArray.length > 1) {
+				IEditorReference[] otherEditors = new IEditorReference[refArray.length - 1];
+				IEditorReference activeEditor = (IEditorReference) page
+						.getReference(page.getActiveEditor());
+				for (int i = 0; i < refArray.length; i++) {
+					if (refArray[i] != activeEditor)
+						continue;
+					System.arraycopy(refArray, 0, otherEditors, 0, i);
+					System.arraycopy(refArray, i + 1, otherEditors, i,
+							refArray.length - 1 - i);
+					break;
+				}
+				page.closeEditors(otherEditors, true);
+			}
+		}
+
+		return null;
+	}
+
+	@Override
+	protected Expression getEnabledWhenExpression() {
+		if (enabledWhen == null) {
+			enabledWhen = new Expression() {
+				@Override
+				public EvaluationResult evaluate(IEvaluationContext context)
+						throws CoreException {
+					IWorkbenchWindow window = InternalHandlerUtil
+							.getActiveWorkbenchWindow(context);
+					if (window != null) {
+						IWorkbenchPage page = window.getActivePage();
+						if (page != null) {
+							IEditorReference[] refArray = page
+									.getEditorReferences();
+							if (refArray != null && refArray.length > 1) {
+								return EvaluationResult.TRUE;
+
+							}
+						}
+					}
+					return EvaluationResult.FALSE;
+				}
+
+				@Override
+				public void collectExpressionInfo(ExpressionInfo info) {
+					info
+							.addVariableNameAccess(ISources.ACTIVE_WORKBENCH_WINDOW_NAME);
+				}
+			};
+		}
+		return enabledWhen;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/CommandToModelProcessor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/CommandToModelProcessor.java
new file mode 100644
index 0000000..a5910b0
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/CommandToModelProcessor.java
@@ -0,0 +1,129 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ ******************************************************************************/
+
+package org.eclipse.ui.internal;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.commands.Category;
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.CommandManager;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.e4.core.commands.internal.HandlerServiceImpl;
+import org.eclipse.e4.core.contexts.ContextFunction;
+import org.eclipse.e4.core.contexts.ContextInjectionFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.e4.ui.internal.workbench.addons.CommandProcessingAddon;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.commands.MCategory;
+import org.eclipse.e4.ui.model.application.commands.MCommand;
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+import org.eclipse.ui.internal.commands.CommandPersistence;
+
+/**
+ * @since 3.5
+ *
+ */
+public class CommandToModelProcessor {
+
+	private Map<String, MCategory> categories = new HashMap<>();
+
+	private Map<String, MCommand> commands = new HashMap<>();
+
+	private EModelService modelService;
+
+	@Execute
+	void process(MApplication application, final IEclipseContext context, EModelService modelService) {
+		this.modelService = modelService;
+		for (MCategory catModel : application.getCategories()) {
+			categories.put(catModel.getElementId(), catModel);
+		}
+
+		for (MCommand cmdModel : application.getCommands()) {
+			commands.put(cmdModel.getElementId(), cmdModel);
+		}
+		CommandManager commandManager = context.get(CommandManager.class);
+		if (commandManager == null) {
+			HandlerServiceImpl.handlerGenerator = new ContextFunction() {
+			    @Override
+                public Object compute(IEclipseContext paramContext, String contextKey) {
+                    IEclipseContext cont = paramContext;
+                    if (paramContext == null)
+                    {
+                        cont = context;
+                    }
+                    return new WorkbenchHandlerServiceHandler(contextKey, cont);
+                }
+			};
+			commandManager = new CommandManager();
+			// setCommandFireEvents(commandManager, false);
+			context.set(CommandManager.class, commandManager);
+		}
+
+		CommandPersistence cp = new CommandPersistence(commandManager);
+		ContextInjectionFactory.inject(cp, context);
+		cp.reRead();
+		generateCategories(application, commandManager);
+		generateCommands(application, commandManager);
+		cp.dispose();
+	}
+
+	/**
+	 * @param application
+	 * @param commandManager
+	 */
+	private void generateCommands(MApplication application, CommandManager commandManager) {
+		for (Command cmd : commandManager.getDefinedCommands()) {
+			if (commands.containsKey(cmd.getId())) {
+				continue;
+			}
+			try {
+				final MCategory categoryModel = categories.get(cmd.getCategory().getId());
+
+				MCommand command = CommandProcessingAddon.createCommand(cmd, modelService, categoryModel);
+
+				application.getCommands().add(command);
+				commands.put(command.getElementId(), command);
+			} catch (NotDefinedException e) {
+				WorkbenchPlugin.log(e);
+			}
+		}
+	}
+
+
+
+	/**
+	 * @param commandManager
+	 */
+	private void generateCategories(MApplication application, CommandManager commandManager) {
+		for (Category cat : commandManager.getDefinedCategories()) {
+			if (categories.containsKey(cat.getId())) {
+				continue;
+			}
+			try {
+				MCategory catModel = modelService.createModelElement(MCategory.class);
+				catModel.setElementId(cat.getId());
+				catModel.setName(cat.getName());
+				catModel.setDescription(cat.getDescription());
+				application.getCategories().add(catModel);
+				categories.put(catModel.getElementId(), catModel);
+			} catch (NotDefinedException e) {
+				// Since we asked for defined commands, this shouldn't be an
+				// issue
+				WorkbenchPlugin.log(e);
+			}
+		}
+	}
+
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ConfigurationInfo.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ConfigurationInfo.java
new file mode 100644
index 0000000..432bcce
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ConfigurationInfo.java
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2015 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.ui.internal;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.Locale;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.about.ISystemSummarySection;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+
+import com.ibm.icu.text.Collator;
+import com.ibm.icu.text.DateFormat;
+
+/**
+ * This class contains utility methods that clients may use to obtain
+ * information about the system configuration.
+ *
+ * @since 3.4
+ *
+ */
+public final class ConfigurationInfo {
+
+	/**
+	 * Return the build id for this instance. This may be <code>null</code> in
+	 * the event that this property is undefined.
+	 *
+	 * @return the build id or <code>null</code>
+	 */
+	public static String getBuildId() {
+		return System.getProperty("eclipse.buildId", null); //$NON-NLS-1$
+	}
+
+	/**
+	 * Return a multi-line String that describes the current configuration. This
+	 * may include but is not limited to system properties, installed bundles,
+	 * and installed features. The specific format of this message is undefined
+	 * and may change at any time.
+	 *
+	 * <p>
+	 * The contents of this String are in part constructed via
+	 * {@link ISystemSummarySection} that are registered with this running
+	 * instance of the workbench.
+	 * </p>
+	 *
+	 * @return the configuration info
+	 */
+	public static String getSystemSummary() {
+		StringWriter out = new StringWriter();
+		PrintWriter writer = new PrintWriter(out);
+		writer.println(NLS.bind(WorkbenchMessages.get().SystemSummary_timeStamp,
+				DateFormat
+						.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL)
+						.format(new Date())));
+
+		ConfigurationInfo.appendExtensions(writer);
+		writer.close();
+		return out.toString();
+	}
+
+	/*
+	 * Appends the contents of all extensions to the configurationLogSections
+	 * extension point.
+	 */
+	private static void appendExtensions(PrintWriter writer) {
+	    // RAP [bm] namespace
+	    IConfigurationElement[] configElements = getSortedExtensions(Platform
+				.getExtensionRegistry().getConfigurationElementsFor(
+						PlatformUI.PLUGIN_EXTENSION_NAME_SPACE,
+						IWorkbenchRegistryConstants.PL_SYSTEM_SUMMARY_SECTIONS));
+		for (IConfigurationElement element : configElements) {
+			Object obj = null;
+			try {
+				obj = WorkbenchPlugin.createExtension(element,
+						IWorkbenchConstants.TAG_CLASS);
+			} catch (CoreException e) {
+				WorkbenchPlugin.log(
+						"could not create class attribute for extension", //$NON-NLS-1$
+						e.getStatus());
+			}
+
+			writer.println();
+			writer.println(NLS.bind(
+					WorkbenchMessages.get().SystemSummary_sectionTitle, element
+							.getAttribute("sectionTitle"))); //$NON-NLS-1$
+
+			if (obj instanceof ISystemSummarySection) {
+				ISystemSummarySection logSection = (ISystemSummarySection) obj;
+				logSection.write(writer);
+			} else {
+				writer.println(WorkbenchMessages.get().SystemSummary_sectionError);
+			}
+		}
+	}
+
+	public static IConfigurationElement[] getSortedExtensions(IConfigurationElement[] configElements) {
+
+		Arrays.sort(configElements, new Comparator() {
+			Collator collator = Collator.getInstance(Locale.getDefault());
+
+			@Override
+			public int compare(Object a, Object b) {
+				IConfigurationElement element1 = (IConfigurationElement) a;
+				IConfigurationElement element2 = (IConfigurationElement) b;
+
+				String id1 = element1.getAttribute("id"); //$NON-NLS-1$
+				String id2 = element2.getAttribute("id"); //$NON-NLS-1$
+
+				if (id1 != null && id2 != null && !id1.equals(id2)) {
+					return collator.compare(id1, id2);
+				}
+
+				String title1 = element1.getAttribute("sectionTitle"); //$NON-NLS-1$
+				String title2 = element2.getAttribute("sectionTitle"); //$NON-NLS-1$
+
+				if (title1 == null) {
+					title1 = ""; //$NON-NLS-1$
+				}
+				if (title2 == null) {
+					title2 = ""; //$NON-NLS-1$
+				}
+
+				return collator.compare(title1, title2);
+			}
+		});
+
+		return configElements;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ContextToModelProcessor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ContextToModelProcessor.java
new file mode 100644
index 0000000..a30f43d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ContextToModelProcessor.java
@@ -0,0 +1,115 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ ******************************************************************************/
+
+package org.eclipse.ui.internal;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.core.commands.contexts.Context;
+import org.eclipse.core.commands.contexts.ContextManager;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.commands.MBindingContext;
+import org.eclipse.e4.ui.model.application.commands.impl.CommandsFactoryImpl;
+import org.eclipse.ui.internal.contexts.ContextPersistence;
+
+/**
+ * @since 3.5
+ *
+ */
+public class ContextToModelProcessor {
+	private Map<String, MBindingContext> contexts = new HashMap<>();
+
+
+	@Execute
+	void process(MApplication application, IEclipseContext context) {
+		gatherContexts(application.getRootContext());
+		ContextManager contextManager = context.get(ContextManager.class);
+		if (contextManager == null) {
+			contextManager = new ContextManager();
+			context.set(ContextManager.class, contextManager);
+		}
+		ContextPersistence cp = new ContextPersistence(contextManager);
+		cp.reRead();
+		generateContexts(application, contextManager);
+		cp.dispose();
+	}
+
+	/**
+	 * @param application
+	 * @param contextManager
+	 */
+	private void generateContexts(MApplication application, ContextManager contextManager) {
+		for (Context ctx : contextManager.getDefinedContexts()) {
+			try {
+				MBindingContext contextModel = contexts.get(ctx.getId());
+				if (contextModel == null) {
+					contextModel = CommandsFactoryImpl.eINSTANCE.createBindingContext();
+					contexts.put(ctx.getId(), contextModel);
+				}
+				contextModel.setElementId(ctx.getId());
+				contextModel.setName(ctx.getName());
+				contextModel.setDescription(ctx.getDescription());
+
+			} catch (NotDefinedException e) {
+				WorkbenchPlugin.log(e);
+			}
+		}
+		for (Context ctx : contextManager.getDefinedContexts()) {
+			try {
+				MBindingContext contextModel = contexts.get(ctx.getId());
+				String parentId = ctx.getParentId();
+				if (parentId == null) {
+					if (!application.getRootContext().contains(contextModel)) {
+						application.getRootContext().add(contextModel);
+					}
+				} else {
+					MBindingContext parentContextModel = contexts.get(parentId);
+					if (parentContextModel == null) {
+						System.err.println("Could not find parent " + parentId + " for child " //$NON-NLS-1$ //$NON-NLS-2$
+								+ ctx.getId());
+					} else {
+						if (!parentContextModel.getChildren().contains(contextModel)) {
+							parentContextModel.getChildren().add(contextModel);
+						}
+					}
+				}
+			} catch (NotDefinedException e) {
+				WorkbenchPlugin.log(e);
+			}
+		}
+	}
+
+	/**
+	 * @param contextList
+	 */
+	private void gatherContexts(List<MBindingContext> contextList) {
+		for (MBindingContext ctx : contextList) {
+			gatherContexts(ctx);
+		}
+	}
+
+	/**
+	 * @param ctx
+	 */
+	private void gatherContexts(MBindingContext ctx) {
+		if (ctx == null) {
+			return;
+		}
+		contexts.put(ctx.getElementId(), ctx);
+		gatherContexts(ctx.getChildren());
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/CoolBarToTrimManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/CoolBarToTrimManager.java
new file mode 100644
index 0000000..43bf539
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/CoolBarToTrimManager.java
@@ -0,0 +1,741 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *     Maxime Porhel <maxime.porhel@obeo.fr> Obeo - Bug 430116
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 457237, 472654
+ *     Andrey Loskutov <loskutov@gmx.de> - Bugs 383569, 420956, 457198, 395601, 445538
+ *     Patrik Suzzi <psuzzi@gmail.com> - Bug 409633
+ ******************************************************************************/
+
+package org.eclipse.ui.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.eclipse.e4.core.contexts.ContextInjectionFactory;
+import org.eclipse.e4.ui.internal.workbench.OpaqueElementUtil;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.ui.MUIElement;
+import org.eclipse.e4.ui.model.application.ui.SideValue;
+import org.eclipse.e4.ui.model.application.ui.basic.MTrimBar;
+import org.eclipse.e4.ui.model.application.ui.basic.MTrimElement;
+import org.eclipse.e4.ui.model.application.ui.basic.MTrimmedWindow;
+import org.eclipse.e4.ui.model.application.ui.menu.MHandledToolItem;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolBar;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolBarElement;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolBarSeparator;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolItem;
+import org.eclipse.e4.ui.model.application.ui.menu.MTrimContribution;
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+import org.eclipse.e4.ui.workbench.renderers.swt.HandledContributionItem;
+import org.eclipse.e4.ui.workbench.renderers.swt.ToolBarManagerRenderer;
+import org.eclipse.e4.ui.workbench.swt.factories.IRendererFactory;
+import org.eclipse.jface.action.AbstractGroupMarker;
+import org.eclipse.jface.action.ContributionManager;
+import org.eclipse.jface.action.GroupMarker;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.IContributionManager;
+import org.eclipse.jface.action.IContributionManagerOverrides;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.action.ToolBarContributionItem;
+import org.eclipse.jface.action.ToolBarManager;
+import org.eclipse.jface.internal.provisional.action.ICoolBarManager2;
+import org.eclipse.jface.internal.provisional.action.IToolBarContributionItem;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.ui.IWorkbenchActionConstants;
+import org.eclipse.ui.internal.menus.ActionSet;
+import org.eclipse.ui.internal.menus.MenuHelper;
+import org.eclipse.ui.menus.CommandContributionItem;
+
+/**
+ * @since 3.5
+ *
+ */
+public class CoolBarToTrimManager extends ContributionManager implements ICoolBarManager2 {
+
+	private final class ToolBarContributionItemExtension extends ToolBarContributionItem {
+		private final MToolBar tb;
+
+		private ToolBarContributionItemExtension(IToolBarManager toolBarManager, MToolBar tb) {
+			super(toolBarManager, tb.getElementId());
+			this.tb = tb;
+		}
+
+		@Override
+		public void setVisible(boolean visible) {
+			super.setVisible(visible);
+			tb.setVisible(visible);
+		}
+	}
+
+	private static final String TOOLBAR_SEPARATOR = "toolbarSeparator"; //$NON-NLS-1$
+	private static final String MAIN_TOOLBAR_ID = ActionSet.MAIN_TOOLBAR;
+	public static final String OBJECT = "coolbar.object"; //$NON-NLS-1$
+	private static final String PREV_CHILD_VISIBLE = "prevChildVisible"; //$NON-NLS-1$
+	private MTrimBar topTrim;
+	private List<MTrimElement> workbenchTrimElements;
+	private IRendererFactory rendererFactory;
+	private ToolBarManagerRenderer renderer;
+	private MApplication application;
+	private MTrimmedWindow window;
+	private IContributionManagerOverrides toolbarOverrides;
+
+	/**
+	 * Field to indicate whether the trim bars have been added to the window's
+	 * model or not. They should only ever be added once.
+	 */
+	private boolean trimBarsAdded;
+	private EModelService modelService;
+
+	public CoolBarToTrimManager(MApplication app, MTrimmedWindow window,
+			List<MTrimElement> workbenchTrimElements, IRendererFactory rf) {
+		application = app;
+		this.window = window;
+		rendererFactory = rf;
+		this.workbenchTrimElements = workbenchTrimElements;
+
+		modelService = window.getContext().get(EModelService.class);
+		topTrim = (MTrimBar) modelService.find(MAIN_TOOLBAR_ID, window);
+		if (topTrim == null) {
+			topTrim = modelService.getTrim(window, SideValue.TOP);
+			topTrim.setElementId(MAIN_TOOLBAR_ID);
+		}
+		topTrim.setToBeRendered(false);
+		MToolBar mToolBar = modelService.createModelElement(MToolBar.class);
+		renderer = (ToolBarManagerRenderer) rendererFactory.getRenderer(mToolBar, null);
+	}
+
+	@Override
+	public void add(IAction action) {
+		throw new UnsupportedOperationException();
+	}
+
+	@Override
+	public void add(IContributionItem item) {
+		add(topTrim, -1, item);
+	}
+
+	private void add(MTrimBar trimBar, int idx, IContributionItem item) {
+		// Special check to make sure that new additions are *before* the SPACER
+		if (idx == -1) {
+			MUIElement spacer = modelService.find(WorkbenchWindow.PERSPECTIVE_SPACER_ID, trimBar);
+			if (spacer != null) {
+				idx = trimBar.getChildren().indexOf(spacer);
+			}
+		}
+
+		if (item instanceof IToolBarContributionItem) {
+			IToolBarContributionItem tbc = (IToolBarContributionItem) item;
+			IToolBarManager mgr = tbc.getToolBarManager();
+			if (!(mgr instanceof ToolBarManager)) {
+				return;
+			}
+			ToolBarManager manager = (ToolBarManager) mgr;
+
+			if (renderer.getToolBarModel(manager) != null) {
+				return;
+			}
+
+			MToolBar toolBar = (MToolBar) modelService.find(item.getId(), window);
+			boolean tbFound = toolBar != null;
+			if (!tbFound) {
+				toolBar = modelService.createModelElement(MToolBar.class);
+			} else {
+				toolBar.getChildren().clear();
+			}
+			toolBar.setElementId(item.getId());
+			toolBar.getTransientData().put(OBJECT, item);
+			String toolbarLabel = getToolbarLabel(application, item.getId());
+			if (toolbarLabel != null) {
+				toolBar.getTransientData().put("Name", toolbarLabel); //$NON-NLS-1$
+			}
+			renderer.linkModelToManager(toolBar, manager);
+			toolBar.setToBeRendered(true);
+			if (!tbFound) {
+				if (idx < 0) {
+					trimBar.getChildren().add(toolBar);
+				} else {
+					trimBar.getChildren().add(idx, toolBar);
+				}
+			}
+			workbenchTrimElements.add(toolBar);
+			manager.setOverrides(toolbarOverrides);
+		} else if (item instanceof IContributionManager) {
+			throw new IllegalStateException();
+		} else if (item instanceof AbstractGroupMarker) {
+			if (item.getId() == null) {
+				return;
+			}
+			for (MTrimElement toolBar : topTrim.getChildren()) {
+				if (item.getId().equals(toolBar.getElementId())
+						&& toolBar.getTags().contains(TOOLBAR_SEPARATOR)) {
+					// already in the coolbar
+					return;
+				}
+			}
+			MToolBarSeparator separator = modelService.createModelElement(MToolBarSeparator.class);
+			separator.setToBeRendered(false);
+			separator.setElementId(item.getId());
+
+			List<MToolBar> toolbars = modelService.findElements(window, item.getId(), MToolBar.class, null);
+			MToolBar toolBar = toolbars.isEmpty() ? null : toolbars.get(0);
+			boolean tbFound = toolBar != null;
+			if (!tbFound) {
+				toolBar = modelService.createModelElement(MToolBar.class);
+			} else {
+				toolBar.getChildren().clear();
+			}
+			toolBar.getTransientData().put(OBJECT, item);
+			toolBar.getTags().add(TOOLBAR_SEPARATOR);
+			toolBar.setElementId(item.getId());
+			toolBar.getChildren().add(separator);
+			toolBar.setToBeRendered(false);
+			if (!tbFound) {
+				if (idx < 0) {
+					topTrim.getChildren().add(toolBar);
+				} else {
+					topTrim.getChildren().add(idx, toolBar);
+				}
+			}
+			workbenchTrimElements.add(toolBar);
+		}
+
+	}
+
+	public static String getToolbarLabel(MApplication application, MUIElement elt) {
+		String name = getTransientName(elt);
+		if (name != null) {
+			return name;
+		}
+		String elementId = elt.getElementId();
+		return getToolbarLabel(application, elementId);
+	}
+
+	// See MenuAdditionCacheEntry
+	private static String getToolbarLabel(MApplication application, String elementId) {
+		String name;
+		if (IWorkbenchActionConstants.TOOLBAR_FILE.equalsIgnoreCase(elementId)) {
+			return WorkbenchMessages.get().WorkbenchWindow_FileToolbar;
+		}
+		if (IWorkbenchActionConstants.TOOLBAR_NAVIGATE.equalsIgnoreCase(elementId)) {
+			return WorkbenchMessages.get().WorkbenchWindow_NavigateToolbar;
+		}
+		if (IWorkbenchActionConstants.TOOLBAR_HELP.equalsIgnoreCase(elementId)) {
+			return WorkbenchMessages.get().WorkbenchWindow_HelpToolbar;
+		}
+		List<MTrimContribution> trimContributions = application.getTrimContributions();
+		for (MTrimContribution mtb : trimContributions) {
+			for (MTrimElement e : mtb.getChildren()) {
+				if (e.getElementId().equals(elementId)) {
+					name = getTransientName(e);
+					if (name != null) {
+						return name;
+					}
+				}
+			}
+		}
+		return null;
+	}
+
+	static String getTransientName(MUIElement elt) {
+		Object name = elt.getTransientData().get("Name"); //$NON-NLS-1$
+		if (name instanceof String) {
+			return (String) name;
+		}
+		return null;
+	}
+
+	@Override
+	public void add(final IToolBarManager toolBarManager) {
+		if (toolBarManager instanceof ToolBarManager) {
+			add(new ToolBarContributionItem(toolBarManager));
+		}
+	}
+
+	@Override
+	public void appendToGroup(String groupName, IAction action) {
+		throw new UnsupportedOperationException();
+	}
+
+	@Override
+	public void appendToGroup(String groupName, IContributionItem item) {
+		List<MToolBar> toolBars = modelService.findElements(window, groupName, MToolBar.class, null);
+		if (toolBars.size() == 1) {
+			MToolBar el = toolBars.get(0);
+			MTrimBar trimBar = getTrim(el);
+			int index = trimBar.getChildren().indexOf(el);
+			index = index + 1 < trimBar.getChildren().size() ? index : -1;
+			add(trimBar, index, item);
+		}
+
+		add(topTrim, -1, item);
+	}
+
+	@Override
+	public Control createControl2(Composite parent) {
+		throw new UnsupportedOperationException();
+	}
+
+	@Override
+	public void dispose() {
+		ArrayList<MToolBarElement> toRemove = new ArrayList<>();
+		for (MTrimElement child : topTrim.getChildren()) {
+			if (child instanceof MToolBar) {
+				MToolBar toolbar = (MToolBar) child;
+				for (MToolBarElement element : toolbar.getChildren()) {
+					if (OpaqueElementUtil.isOpaqueToolItem(element)) {
+						toRemove.add(element);
+					}
+				}
+				if (!toRemove.isEmpty()) {
+					toolbar.getChildren().removeAll(toRemove);
+					toRemove.clear();
+				}
+			}
+		}
+
+	}
+
+	@Override
+	public IContributionItem find(String id) {
+		List<MToolBar> toolbars = modelService.findElements(window, id, MToolBar.class, null);
+		if (toolbars.isEmpty()) {
+			return null;
+		}
+
+		final MToolBar model = toolbars.get(0);
+		if (model.getTransientData().get(OBJECT) != null) {
+			return (IContributionItem) model.getTransientData().get(OBJECT);
+		}
+		ToolBarManagerRenderer renderer = (ToolBarManagerRenderer) rendererFactory.getRenderer(model, null);
+		final ToolBarManager manager = renderer.getManager(model);
+		if (manager != null) {
+			final ToolBarContributionItem toolBarContributionItem = new ToolBarContributionItemExtension(manager, model);
+			model.getTransientData().put(OBJECT, toolBarContributionItem);
+			return toolBarContributionItem;
+		} else if (model.getTags().contains(TOOLBAR_SEPARATOR)) {
+			if (model.getTransientData().get(OBJECT) != null) {
+				return (IContributionItem) model.getTransientData().get(OBJECT);
+			}
+			return new GroupMarker(model.getElementId());
+		}
+		return null;
+	}
+
+	@Override
+	public IMenuManager getContextMenuManager() {
+		throw new UnsupportedOperationException();
+	}
+
+	@Override
+	public Control getControl2() {
+		throw new UnsupportedOperationException();
+	}
+
+	@Override
+	public IContributionItem[] getItems() {
+		ArrayList<IContributionItem> items = new ArrayList<>();
+
+		List<MToolBar> toolBars = modelService.findElements(window, null, MToolBar.class, null);
+		for (final MToolBar tb : toolBars) {
+			if (tb.getTransientData().get(OBJECT) != null) {
+				items.add((IContributionItem) tb.getTransientData().get(OBJECT));
+			} else {
+				ToolBarManagerRenderer renderer = (ToolBarManagerRenderer) rendererFactory.getRenderer(tb, null);
+				final ToolBarManager manager = renderer.getManager(tb);
+				if (manager != null) {
+					ToolBarContributionItem toolBarContributionItem = new ToolBarContributionItemExtension(manager, tb);
+					tb.getTransientData().put(OBJECT, toolBarContributionItem);
+					items.add(toolBarContributionItem);
+				} else if (tb.getTags().contains(TOOLBAR_SEPARATOR)) {
+					if (tb.getTransientData().get(OBJECT) != null) {
+						items.add((IContributionItem) tb.getTransientData().get(OBJECT));
+					}
+					items.add(new GroupMarker(tb.getElementId()));
+				}
+			}
+		}
+
+		return items.toArray(new IContributionItem[items.size()]);
+	}
+
+	@Override
+	public boolean getLockLayout() {
+		return false;
+	}
+
+	@Override
+	public IContributionManagerOverrides getOverrides() {
+		return toolbarOverrides;
+	}
+
+	@Override
+	public int getStyle() {
+		return 0;
+	}
+
+	@Override
+	public void insertAfter(String id, IAction action) {
+		throw new UnsupportedOperationException();
+	}
+
+	private MTrimBar getTrim(MTrimElement te) {
+		if (te == null) {
+			return null;
+		}
+
+		MUIElement parentElement = te.getParent();
+		return (MTrimBar) (parentElement instanceof MTrimBar ? parentElement : null);
+	}
+
+	private MToolBar getToolBar(String id) {
+		List<MToolBar> toolbars = modelService.findElements(window, id, MToolBar.class, null);
+		if (toolbars.size() == 1) {
+			return toolbars.get(0);
+		}
+
+		return null;
+	}
+
+	@Override
+	public void insertAfter(String id, IContributionItem item) {
+		MToolBar afterElement = getToolBar(id);
+		if (afterElement == null || getTrim(afterElement) == null) {
+			return;
+		}
+
+		MTrimBar trimBar = getTrim(afterElement);
+		int index = trimBar.getChildren().indexOf(afterElement);
+		index = index + 1 < trimBar.getChildren().size() ? index + 1 : -1;
+		add(trimBar, index, item);
+	}
+
+	@Override
+	public void insertBefore(String id, IAction action) {
+		throw new UnsupportedOperationException();
+	}
+
+	@Override
+	public void insertBefore(String id, IContributionItem item) {
+		MToolBar beforeElement = getToolBar(id);
+		if (beforeElement == null || getTrim(beforeElement) == null) {
+			return;
+		}
+
+		MTrimBar trimBar = getTrim(beforeElement);
+		int index = trimBar.getChildren().indexOf(beforeElement);
+		add(trimBar, index, item);
+	}
+
+	@Override
+	public boolean isDirty() {
+		return false;
+	}
+
+	@Override
+	public boolean isEmpty() {
+		return topTrim.getChildren().isEmpty();
+	}
+
+	@Override
+	public void markDirty() {
+	}
+
+	@Override
+	public void prependToGroup(String groupName, IAction action) {
+		throw new UnsupportedOperationException();
+	}
+
+	@Override
+	public void prependToGroup(String groupName, IContributionItem item) {
+		MUIElement gnElement = modelService.find(groupName, window);
+		if (gnElement instanceof MToolBar) {
+			MTrimBar trimBar = getTrim((MTrimElement) gnElement);
+			int index = trimBar.getChildren().indexOf(gnElement);
+			add(trimBar, index, item);
+		}
+		add(topTrim, -1, item);
+	}
+
+	@Override
+	public void refresh() {
+	}
+
+	@Override
+	public IContributionItem remove(IContributionItem item) {
+		final List<MToolBar> children = modelService.findElements(window, null, MToolBar.class, null);
+		for (int i = 0; i < children.size(); i++) {
+			final MToolBar child = children.get(i);
+			final Object obj = child.getTransientData().get(OBJECT);
+			if (obj != null && obj.equals(item)) {
+				if (child instanceof MToolBarElement) {
+					renderer.clearModelToContribution((MToolBarElement) child, item);
+				}
+
+				if (item instanceof IToolBarContributionItem) {
+					IToolBarManager parent = ((IToolBarContributionItem) item).getToolBarManager();
+					if (parent instanceof ToolBarManager) {
+						renderer.clearModelToManager(child, (ToolBarManager) parent);
+					}
+				}
+				workbenchTrimElements.remove(child);
+
+				child.setToBeRendered(false);
+				child.getParent().getChildren().remove(child);
+				return (IContributionItem) obj;
+			}
+			if (item.getId() != null && item.getId().equals(child.getElementId())) {
+				throw new IllegalStateException();
+			}
+		}
+		return null;
+	}
+
+	@Override
+	public IContributionItem remove(String id) {
+		throw new UnsupportedOperationException();
+	}
+
+	@Override
+	public void removeAll() {
+		throw new UnsupportedOperationException();
+	}
+
+	@Override
+	public void resetItemOrder() {
+		updateAll(true);
+	}
+
+	@Override
+	public void setContextMenuManager(IMenuManager menuManager) {
+	}
+
+	@Override
+	public void setItems(IContributionItem[] newItems) {
+		throw new UnsupportedOperationException();
+	}
+
+	@Override
+	public void setLockLayout(boolean value) {
+		// 409633 Not implemented, see LockToolBarHandler
+	}
+
+	@Override
+	public void setOverrides(IContributionManagerOverrides newOverrides) {
+		this.toolbarOverrides = newOverrides;
+		// this is required when we need to set the overrides for the
+		// new ToolbarManager when it is created in ToolbarManagerRenderer
+		topTrim.getTransientData().put(IContributionManagerOverrides.class.getName(), newOverrides);
+	}
+
+	@Override
+	public void update(boolean force) {
+		final List<MToolBar> children = modelService.findElements(window, null, MToolBar.class, null);
+
+		for (MToolBar el : children) {
+			ToolBarManagerRenderer renderer = (ToolBarManagerRenderer) rendererFactory.getRenderer(el, null);
+			final ToolBarManager manager = renderer.getManager(el);
+			if (manager != null) {
+				boolean wasVisible = el.isVisible();
+				boolean needUpdate = fill(el, manager);
+				// fix for bug 383569#25: if the toolbar model changed the
+				// visibility we must create (or remove) SWT toolbar widgets
+				if (needUpdate || el.isVisible() != wasVisible) {
+					manager.markDirty();
+					manager.update(true);
+				}
+				// TODO: Hack to work around Bug 370961
+				ToolBar toolbar = manager.getControl();
+				if (toolbar != null && !toolbar.isDisposed()) {
+					toolbar.requestLayout();
+				}
+			}
+		}
+		// and now add it to the model, start the rendering
+		if (!trimBarsAdded) {
+			boolean hidden = !topTrim.isVisible();
+			if (hidden) {
+				topTrim.setVisible(true);
+			}
+			topTrim.setToBeRendered(true);
+			if (hidden) {
+				topTrim.setVisible(false);
+			}
+			trimBarsAdded = true;
+		}
+	}
+
+	/**
+	 * @param force
+	 */
+	public void updateAll(boolean force) {
+		final List<MToolBar> children = modelService.findElements(window, null, MToolBar.class, null);
+		for (MToolBar mToolbar : children) {
+			if (mToolbar == null) {
+				continue;
+			}
+			ToolBarManagerRenderer renderer = (ToolBarManagerRenderer) rendererFactory.getRenderer(mToolbar, null);
+			final ToolBarManager manager = renderer.getManager(mToolbar);
+			if (manager != null) {
+				manager.update(true);
+				// TODO: Hack to work around Bug 370961
+				ToolBar toolbar = manager.getControl();
+				if (toolbar != null && !toolbar.isDisposed()) {
+					toolbar.requestLayout();
+				}
+			}
+		}
+	}
+
+	/**
+	 * @return true if the contribution manager needs to be updated because item
+	 *         visibility is changed
+	 */
+	private boolean fill(MToolBar container, IContributionManager manager) {
+		boolean needUpdate = false;
+		ToolBarManagerRenderer renderer = (ToolBarManagerRenderer) rendererFactory.getRenderer(container, null);
+
+		IContributionItem[] items = manager.getItems();
+		for (int index = 0; index < items.length; index++) {
+			IContributionItem item = items[index];
+			if (item == null) {
+				continue;
+			}
+			MToolBarElement toolBarElem = renderer.getToolElement(item);
+			if (toolBarElem != null) {
+				if (container.isVisible()) {
+					needUpdate |= applyOverridenVisibility(toolBarElem, item, manager);
+					continue;
+				}
+				if (item.isSeparator() || item.isGroupMarker()) {
+					continue;
+				}
+				// partial fix for bug 383569, introduced via fix for bug 402429
+				// If the toolbar is hidden but one of the children is not,
+				// make both the child and the toolbar visible
+				if (isChildVisible(item, manager)) {
+					needUpdate |= applyOverridenVisibility(toolBarElem, item, manager);
+					container.setVisible(true);
+				}
+				continue;
+			}
+			if (item instanceof IToolBarContributionItem) {
+				IToolBarManager manager2 = ((IToolBarContributionItem) item).getToolBarManager();
+				needUpdate |= fill(container, manager2);
+			} else if (item instanceof IMenuManager) {
+				// No element to add in toolbar:
+				// let the menu manager control its contributions.
+				continue;
+			} else if (item instanceof IContributionManager) {
+				needUpdate |= fill(container, (IContributionManager) item);
+			} else if (item instanceof CommandContributionItem) {
+				MHandledToolItem toolItem = MenuHelper.createToolItem(application, (CommandContributionItem) item);
+				if (toolItem == null) {
+					continue;
+				}
+				// this section below should match what's in
+				// org.eclipse.e4.ui.workbench.renderers.swt.ToolBarManagerRenderer.processHandledItem(ToolBarManager,
+				// MHandledToolItem)
+				toolItem.setRenderer(renderer);
+				HandledContributionItem ci = ContextInjectionFactory.make(HandledContributionItem.class,
+						window.getContext());
+
+				if (manager instanceof ContributionManager) {
+					// set basic attributes to the item before adding to the manager
+					ci.setId(toolItem.getElementId());
+					ci.setVisible(toolItem.isVisible());
+
+					ContributionManager cm = (ContributionManager) manager;
+					cm.insert(index, ci);
+					cm.remove(item);
+
+					// explicitly dispose contribution since it is now
+					// disconnected from manager
+					item.dispose();
+				}
+				ci.setModel(toolItem);
+				renderer.linkModelToContribution(toolItem, ci);
+				container.getChildren().add(toolItem);
+			} else {
+				MToolItem toolItem = OpaqueElementUtil.createOpaqueToolItem();
+				toolItem.setElementId(item.getId());
+				OpaqueElementUtil.setOpaqueItem(toolItem, item);
+				if (item instanceof AbstractGroupMarker) {
+					toolItem.setVisible(item.isVisible());
+				}
+				// make sure the renderer knows this has already been processed
+				renderer.linkModelToContribution(toolItem, item);
+				container.getChildren().add(toolItem);
+			}
+		}
+		return needUpdate;
+	}
+
+	/**
+	 * @return true if the contribution manager needs to be updated because item
+	 *         visibility is changed
+	 */
+	private boolean applyOverridenVisibility(MToolBarElement modelItem, IContributionItem item,
+			IContributionManager manager) {
+		boolean needUpdate = false;
+		Boolean overridenVisibility = getOverridenVisibility(item, manager);
+		Boolean prevChildVisible = (Boolean) modelItem.getTransientData().get(PREV_CHILD_VISIBLE);
+
+		if (overridenVisibility != null) {
+			if (prevChildVisible == null) {
+				boolean modelVisible = modelItem.isVisible();
+				boolean itemVisible = item.isVisible();
+				if (modelVisible != overridenVisibility || itemVisible != overridenVisibility) {
+					needUpdate = true;
+				}
+				modelItem.getTransientData().put(PREV_CHILD_VISIBLE, itemVisible);
+				modelItem.setVisible(overridenVisibility);
+			} else {
+				return needUpdate;
+			}
+		} else if (prevChildVisible != null) {
+			boolean oldVisible = modelItem.isVisible();
+			if (oldVisible != prevChildVisible) {
+				needUpdate = true;
+			}
+			modelItem.setVisible(prevChildVisible);
+			modelItem.getTransientData().remove(PREV_CHILD_VISIBLE);
+		} else {
+			return needUpdate;
+		}
+		return needUpdate;
+	}
+
+	/**
+	 * Checks if the item's visibility is overridden by the given manager
+	 *
+	 * @return non null overridden visibility value (if it is overridden), null
+	 *         otherwise
+	 */
+	private Boolean getOverridenVisibility(IContributionItem item, IContributionManager manager) {
+		IContributionManagerOverrides overrides = manager.getOverrides();
+		return overrides == null ? null : overrides.getVisible(item);
+		}
+
+	/**
+	 * Computes real item visibility considering possibly overridden state from
+	 * manager
+	 */
+	private boolean isChildVisible(IContributionItem item, IContributionManager manager) {
+		Boolean v = getOverridenVisibility(item, manager);
+		return v == null ? item.isVisible() : v.booleanValue();
+	}
+
+	public MTrimBar getTopTrim() {
+		return topTrim;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/CycleBaseHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/CycleBaseHandler.java
new file mode 100644
index 0000000..116e428
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/CycleBaseHandler.java
@@ -0,0 +1,526 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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
+ *     Dina Sayed, dsayed@eg.ibm.com, IBM -  bug 276324
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *     Simon Scholz <simon.scholz@vogella.com> - Bug 454143
+ *     Patrik Suzzi <psuzzi@gmail.com> - Bug 481416
+ ******************************************************************************/
+
+package org.eclipse.ui.internal;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExecutableExtension;
+import org.eclipse.e4.ui.model.application.ui.basic.MStackElement;
+import org.eclipse.e4.ui.workbench.modeling.EPartService;
+import org.eclipse.e4.ui.workbench.modeling.EPartService.PartState;
+import org.eclipse.jface.bindings.Trigger;
+import org.eclipse.jface.bindings.TriggerSequence;
+import org.eclipse.jface.bindings.keys.KeyStroke;
+import org.eclipse.jface.bindings.keys.SWTKeySupport;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.MouseMoveListener;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.ui.IEditorReference;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartReference;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.contexts.IContextService;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.eclipse.ui.keys.IBindingService;
+
+/**
+ * Its a base class for switching between views/editors/perspectives.
+ *
+ * @since 3.3
+ *
+ */
+
+public abstract class CycleBaseHandler extends AbstractHandler implements
+		IExecutableExtension {
+	private Object selection;
+	protected IWorkbenchWindow window;
+	// true to go to next and false to go to previous part
+	protected boolean gotoDirection;
+	/**
+	 * The list of key bindings for the backward command when it is open. This
+	 * value is <code>null</code> if the dialog is not open.
+	 */
+	private TriggerSequence[] backwardTriggerSequences = null;
+
+	protected ParameterizedCommand commandBackward = null;
+
+	protected ParameterizedCommand commandForward = null;
+	/**
+	 * The list of key bindings for the forward command when it is open. This
+	 * value is <code>null</code> if the dialog is not open.
+	 */
+	private TriggerSequence[] forwardTriggerSequences = null;
+
+
+	/**
+	 * Add all items to the dialog in the activation order
+	 */
+	protected abstract void addItems(Table table, WorkbenchPage page);
+
+	/**
+	 * Get the index of the current item (not valid if there are no items).
+	 */
+	protected int getCurrentItemIndex() {
+		return 0;
+	}
+
+	/**
+	 * Get the backward command.
+	 */
+	protected abstract ParameterizedCommand getBackwardCommand();
+
+	/**
+	 * Get the forward command.
+	 */
+	protected abstract ParameterizedCommand getForwardCommand();
+
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		window = HandlerUtil.getActiveWorkbenchWindowChecked(event);
+
+		IWorkbenchPage page = window.getActivePage();
+		IWorkbenchPart activePart= page.getActivePart();
+		getTriggers();
+		openDialog((WorkbenchPage) page, activePart);
+		clearTriggers();
+		activate(page, selection);
+
+		return null;
+	}
+
+	/*
+	 * Open a dialog showing all views in the activation order
+	 */
+	protected void openDialog(WorkbenchPage page, IWorkbenchPart activePart) {
+		final int MAX_ITEMS = 22;
+		Shell shell = null;
+		selection = null;
+
+		if (activePart != null)
+			shell = activePart.getSite().getShell();
+		if (shell == null)
+			shell = window.getShell();
+		final Shell dialog = new Shell(shell, SWT.MODELESS);
+		Display display = dialog.getDisplay();
+		dialog.setLayout(new FillLayout());
+
+		final Table table = new Table(dialog, SWT.SINGLE | SWT.FULL_SELECTION);
+		table.setHeaderVisible(true);
+		table.setLinesVisible(true);
+		TableColumn tc = new TableColumn(table, SWT.NONE);
+		tc.setResizable(false);
+		tc.setText(getTableHeader(activePart));
+		addItems(table, page);
+		int tableItemCount = table.getItemCount();
+
+		switch (tableItemCount) {
+		case 0:
+			cancel(dialog);
+			return;
+		case 1:
+			table.setSelection(0);
+			break;
+		default:
+			int i;
+			if (gotoDirection) {
+				i= getCurrentItemIndex() + 1;
+				if (i >= tableItemCount)
+					i= 0;
+			} else {
+				i= getCurrentItemIndex() - 1;
+				if (i < 0)
+					i= tableItemCount - 1;
+			}
+			table.setSelection(i);
+		}
+
+		tc.pack();
+		table.pack();
+		dialog.pack();
+
+		Rectangle tableBounds = table.getBounds();
+		tableBounds.height = Math.min(tableBounds.height, table.getItemHeight()
+				* MAX_ITEMS);
+		table.setBounds(tableBounds);
+
+		dialog.setBounds(dialog.computeTrim(tableBounds.x, tableBounds.y,
+				tableBounds.width, tableBounds.height));
+
+		tc.setWidth(table.getClientArea().width);
+		table.setFocus();
+		table.addFocusListener(new FocusListener() {
+			@Override
+			public void focusGained(FocusEvent e) {
+				// Do nothing
+			}
+
+			@Override
+			public void focusLost(FocusEvent e) {
+				cancel(dialog);
+			}
+		});
+
+		// RAP [bm] MouseMoveListener
+//		table.addMouseMoveListener(new MouseMoveListener() {
+//			TableItem lastItem = null;
+//
+//			public void mouseMove(MouseEvent e) {
+//				if (table.equals(e.getSource())) {
+//					Object o = table.getItem(new Point(e.x, e.y));
+//					if (lastItem == null ^ o == null) {
+//						table.setCursor(o == null ? null : table.getDisplay().getSystemCursor(
+//								SWT.CURSOR_HAND));
+//					}
+//					if (o instanceof TableItem) {
+//						if (!o.equals(lastItem)) {
+//							lastItem = (TableItem) o;
+//							table.setSelection(new TableItem[] { lastItem });
+//						}
+//					} else if (o == null) {
+//						lastItem = null;
+//					}
+//				}
+//			}
+//		});
+
+		setDialogLocation(dialog, activePart);
+
+		final IContextService contextService = window
+				.getWorkbench().getService(IContextService.class);
+		try {
+			dialog.open();
+			addMouseListener(table, dialog);
+			contextService.registerShell(dialog, IContextService.TYPE_NONE);
+			addKeyListener(table, dialog);
+			addTraverseListener(table);
+
+			while (!dialog.isDisposed()) {
+				if (!display.readAndDispatch()) {
+					display.sleep();
+				}
+			}
+		} finally {
+			if (!dialog.isDisposed()) {
+				cancel(dialog);
+			}
+			contextService.unregisterShell(dialog);
+		}
+	}
+
+	/**
+	 * Sets the dialog's location on the screen.
+	 *
+	 * @param dialog
+	 */
+	protected void setDialogLocation(final Shell dialog, IWorkbenchPart activePart) {
+		Display display = dialog.getDisplay();
+		Rectangle dialogBounds = dialog.getBounds();
+		Rectangle parentBounds = dialog.getParent().getBounds();
+
+		// the bounds of the monitor that contains the currently active part.
+		Rectangle monitorBounds = activePart == null ? display
+.getPrimaryMonitor().getBounds()
+				: ((Control) ((PartSite) activePart.getSite()).getModel().getWidget()).getMonitor()
+						.getBounds();
+
+		// Place it in the center of its parent;
+		dialogBounds.x = parentBounds.x
+				+ ((parentBounds.width - dialogBounds.width) / 2);
+		dialogBounds.y = parentBounds.y
+				+ ((parentBounds.height - dialogBounds.height) / 2);
+		if (!monitorBounds.contains(dialogBounds.x, dialogBounds.y)
+				|| !monitorBounds.contains(dialogBounds.x + dialogBounds.width,
+						dialogBounds.y + dialogBounds.height)) {
+			// Place it in the center of the monitor if it is not visible
+			// when placed in the center of its parent.
+			// Ensure the origin is visible on the screen.
+			dialogBounds.x = Math.max(0,
+					monitorBounds.x + (monitorBounds.width - dialogBounds.width) / 2);
+			dialogBounds.y =  Math.max(0,
+					monitorBounds.y + (monitorBounds.height - dialogBounds.height) / 2);
+		}
+
+		dialog.setLocation(dialogBounds.x, dialogBounds.y);
+	}
+
+	/**
+	 * Clears the forward and backward trigger sequences.
+	 */
+	protected void clearTriggers() {
+		forwardTriggerSequences = null;
+		backwardTriggerSequences = null;
+	}
+
+	/**
+	 * Fetch the key bindings for the forward and backward commands. They will
+	 * not change while the dialog is open, but the context will. Bug 55581.
+	 */
+	protected void getTriggers() {
+		commandForward = getForwardCommand();
+		commandBackward = getBackwardCommand();
+
+		final IBindingService bindingService = window
+				.getWorkbench().getService(IBindingService.class);
+		forwardTriggerSequences = bindingService
+				.getActiveBindingsFor(commandForward);
+		backwardTriggerSequences = bindingService
+				.getActiveBindingsFor(commandBackward);
+	}
+
+	protected void addKeyListener(final Table table, final Shell dialog) {
+		table.addKeyListener(new KeyListener() {
+			private boolean firstKey = true;
+
+			private boolean quickReleaseMode = false;
+
+			@Override
+			public void keyPressed(KeyEvent e) {
+				int keyCode = e.keyCode;
+				char character = e.character;
+				int accelerator = SWTKeySupport
+						.convertEventToUnmodifiedAccelerator(e);
+				KeyStroke keyStroke = SWTKeySupport
+						.convertAcceleratorToKeyStroke(accelerator);
+
+				boolean acceleratorForward = false;
+				boolean acceleratorBackward = false;
+
+				if (commandForward != null) {
+					if (forwardTriggerSequences != null) {
+						final int forwardCount = forwardTriggerSequences.length;
+						for (int i = 0; i < forwardCount; i++) {
+							final TriggerSequence triggerSequence = forwardTriggerSequences[i];
+
+							// Compare the last key stroke of the binding.
+							final Trigger[] triggers = triggerSequence
+									.getTriggers();
+							final int triggersLength = triggers.length;
+							if ((triggersLength > 0)
+									&& (triggers[triggersLength - 1]
+											.equals(keyStroke))) {
+								acceleratorForward = true;
+								break;
+							}
+						}
+					}
+				}
+
+				if (commandBackward != null) {
+					if (backwardTriggerSequences != null) {
+						final int backwardCount = backwardTriggerSequences.length;
+						for (int i = 0; i < backwardCount; i++) {
+							final TriggerSequence triggerSequence = backwardTriggerSequences[i];
+
+							// Compare the last key stroke of the binding.
+							final Trigger[] triggers = triggerSequence
+									.getTriggers();
+							final int triggersLength = triggers.length;
+							if ((triggersLength > 0)
+									&& (triggers[triggersLength - 1]
+											.equals(keyStroke))) {
+								acceleratorBackward = true;
+								break;
+							}
+						}
+					}
+				}
+
+				if (character == SWT.CR || character == SWT.LF) {
+					ok(dialog, table);
+				} else if (acceleratorForward) {
+					if (firstKey && e.stateMask != 0) {
+						quickReleaseMode = true;
+					}
+
+					int index = table.getSelectionIndex();
+					table.setSelection((index + 1) % table.getItemCount());
+				} else if (acceleratorBackward) {
+					if (firstKey && e.stateMask != 0) {
+						quickReleaseMode = true;
+					}
+
+					int index = table.getSelectionIndex();
+					table.setSelection(index >= 1 ? index - 1 : table
+							.getItemCount() - 1);
+				} else if (keyCode != SWT.ALT && keyCode != SWT.COMMAND
+						&& keyCode != SWT.CTRL && keyCode != SWT.SHIFT
+						&& keyCode != SWT.ARROW_DOWN && keyCode != SWT.ARROW_UP
+						&& keyCode != SWT.ARROW_LEFT
+						&& keyCode != SWT.ARROW_RIGHT) {
+					cancel(dialog);
+				}
+
+				firstKey = false;
+			}
+
+			@Override
+			public void keyReleased(KeyEvent e) {
+				int keyCode = e.keyCode;
+				int stateMask = e.stateMask;
+
+				final IPreferenceStore store = WorkbenchPlugin.getDefault()
+						.getPreferenceStore();
+				final boolean stickyCycle = store
+						.getBoolean(IPreferenceConstants.STICKY_CYCLE);
+				if ((!stickyCycle && (firstKey || quickReleaseMode))
+						&& keyCode == stateMask) {
+					ok(dialog, table);
+				}
+			}
+		});
+	}
+
+	/**
+	 * Adds a listener to the given table that blocks all traversal operations.
+	 *
+	 * @param table
+	 *            The table to which the traversal suppression should be added;
+	 *            must not be <code>null</code>.
+	 */
+	protected final void addTraverseListener(final Table table) {
+		table.addTraverseListener(event -> event.doit = false);
+	}
+
+	/**
+	 * Activate the selected item.
+	 *
+	 * @param page
+	 *            the page
+	 * @param selectedItem
+	 *            the selected item
+	 */
+	protected void activate(IWorkbenchPage page, Object selectedItem) {
+		if (selectedItem != null) {
+			if (selectedItem instanceof MStackElement) {
+				EPartService partService = page.getWorkbenchWindow().getService(EPartService.class);
+				partService.showPart(((MStackElement) selectedItem).getElementId(), PartState.ACTIVATE);
+
+				// the if conditions below do not need to be checked then
+				return;
+			}
+			if (selectedItem instanceof IEditorReference) {
+				page.setEditorAreaVisible(true);
+			}
+			if (selectedItem instanceof IWorkbenchPartReference) {
+				IWorkbenchPart part = ((IWorkbenchPartReference) selectedItem)
+						.getPart(true);
+				if (part != null) {
+					page.activate(part);
+				}
+				// the if conditions below do not need to be checked then
+				return;
+			}
+			if (selectedItem instanceof IPerspectiveDescriptor){
+	            IPerspectiveDescriptor persp = (IPerspectiveDescriptor) selectedItem;
+	            page.setPerspective(persp);
+				IWorkbenchPart activePart = page.getActivePart();
+				if (activePart != null) {
+					activePart.setFocus();
+				}
+			}
+		}
+	}
+
+	/*
+	 * Close the dialog and set selection to null.
+	 */
+	protected void cancel(Shell dialog) {
+		selection = null;
+		dialog.close();
+	}
+
+	/*
+	 * Close the dialog saving the selection
+	 */
+	protected void ok(Shell dialog, final Table table) {
+		TableItem[] items = table.getSelection();
+
+		if (items != null && items.length == 1) {
+			selection = items[0].getData();
+		}
+
+		dialog.close();
+	}
+
+	/*
+	 * Add mouse listener to the table closing it when the mouse is pressed.
+	 */
+	protected void addMouseListener(final Table table, final Shell dialog) {
+		table.addMouseListener(new MouseListener() {
+			@Override
+			public void mouseDoubleClick(MouseEvent e) {
+				ok(dialog, table);
+			}
+
+			@Override
+			public void mouseDown(MouseEvent e) {
+				ok(dialog, table);
+			}
+
+			@Override
+			public void mouseUp(MouseEvent e) {
+				ok(dialog, table);
+			}
+		});
+	}
+
+	protected abstract String getTableHeader(IWorkbenchPart activePart);
+
+	// return WorkbenchMessages.CyclePartAction_header;
+
+	public Object getSelection() {
+		return selection;
+	}
+
+	public IWorkbenchWindow getWindow() {
+		return window;
+	}
+
+	public TriggerSequence[] getBackwardTriggerSequences() {
+		return backwardTriggerSequences;
+	}
+
+	public TriggerSequence[] getForwardTriggerSequences() {
+		return forwardTriggerSequences;
+	}
+
+	@Override
+	public void setInitializationData(IConfigurationElement config,
+			String propertyName, Object data) throws CoreException {
+		gotoDirection = "true".equals(data); //$NON-NLS-1$
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/CycleEditorHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/CycleEditorHandler.java
new file mode 100644
index 0000000..c04c63e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/CycleEditorHandler.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2016 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *     Friederike Schertel <friederike@schertel.org> - Bug 478336
+ *     Patrik Suzzi <psuzzi@gmail.com> - Bug 504088
+ ******************************************************************************/
+
+package org.eclipse.ui.internal;
+
+import java.util.List;
+
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.commands.ICommandService;
+
+/**
+ * This is the handler for NextEditor and PrevEditor commands.
+ * <p>
+ * Replacement for CycleEditorAction
+ * </p>
+ *
+ * @since 3.3
+ */
+public class CycleEditorHandler extends FilteredTableBaseHandler {
+
+	@Override
+	protected Object getInput(WorkbenchPage page) {
+		List<EditorReference> refs = page.getSortedEditorReferences();
+		return refs;
+	}
+
+	@Override
+	protected ParameterizedCommand getBackwardCommand() {
+		final ICommandService commandService = window.getWorkbench().getService(ICommandService.class);
+		final Command command = commandService.getCommand(IWorkbenchCommandConstants.WINDOW_PREVIOUS_EDITOR);
+		ParameterizedCommand commandBack = new ParameterizedCommand(command, null);
+		return commandBack;
+	}
+
+	@Override
+	protected ParameterizedCommand getForwardCommand() {
+		final ICommandService commandService = window.getWorkbench().getService(ICommandService.class);
+		final Command command = commandService.getCommand(IWorkbenchCommandConstants.WINDOW_NEXT_EDITOR);
+		ParameterizedCommand commandF = new ParameterizedCommand(command, null);
+		return commandF;
+	}
+
+	@Override
+	protected String getTableHeader(IWorkbenchPart activePart) {
+		return WorkbenchMessages.get().CycleEditorAction_header;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/CyclePerspectiveHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/CyclePerspectiveHandler.java
new file mode 100644
index 0000000..3056712
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/CyclePerspectiveHandler.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2016 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *     Patrik Suzzi <psuzzi@gmail.com> - Bug 504090
+ ******************************************************************************/
+
+package org.eclipse.ui.internal;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.model.PerspectiveLabelProvider;
+
+/**
+ * This handler is used to switch between perspectives using the keyboard.
+ * <p>
+ * Replacement for CyclePerspectiveAction
+ * </p>
+ *
+ * @since 3.3
+ */
+public class CyclePerspectiveHandler extends FilteredTableBaseHandler {
+	private PerspectiveLabelProvider labelProvider = new PerspectiveLabelProvider(
+            false);
+
+	@Override
+	protected Object getInput(WorkbenchPage page) {
+		List<IPerspectiveDescriptor> refs = Arrays.asList(page.getSortedPerspectives());
+		Collections.reverse(refs);
+		return refs;
+	}
+
+	@Override
+	protected ParameterizedCommand getBackwardCommand() {
+		final ICommandService commandService = window.getWorkbench().getService(ICommandService.class);
+		final Command command = commandService.getCommand(IWorkbenchCommandConstants.WINDOW_PREVIOUS_PERSPECTIVE);
+		ParameterizedCommand commandBack = new ParameterizedCommand(command, null);
+		return commandBack;
+	}
+
+	@Override
+	protected ParameterizedCommand getForwardCommand() {
+		final ICommandService commandService = window.getWorkbench().getService(ICommandService.class);
+		final Command command = commandService.getCommand(IWorkbenchCommandConstants.WINDOW_NEXT_PERSPECTIVE);
+		ParameterizedCommand commandF = new ParameterizedCommand(command, null);
+		return commandF;
+	}
+
+	@Override
+	protected String getTableHeader(IWorkbenchPart activePart) {
+		return WorkbenchMessages.get().CyclePerspectiveAction_header;
+	}
+
+	@Override
+	public void dispose() {
+		if (labelProvider!=null) {
+			labelProvider.dispose();
+			labelProvider = null;
+		}
+		super.dispose();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/CycleViewHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/CycleViewHandler.java
new file mode 100644
index 0000000..83438dd
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/CycleViewHandler.java
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *     Simon Scholz <simon.scholz@vogella.com> - Bug 454143, 461063, 495917
+ *     Friederike Schertel <friederike@schertel.org> - Bug 478336
+ *     Patrik Suzzi <psuzzi@gmail.com> - Bug 504089, 509224, 509232
+ ******************************************************************************/
+
+package org.eclipse.ui.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+import org.eclipse.e4.ui.workbench.modeling.EPartService;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartReference;
+import org.eclipse.ui.commands.ICommandService;
+
+/**
+ * This handler is used to switch between parts using the keyboard.
+ * <p>
+ * Replacement for CyclePartAction
+ * </p>
+ *
+ * @since 3.3
+ *
+ */
+public class CycleViewHandler extends FilteredTableBaseHandler {
+
+	@Override
+	protected Object getInput(WorkbenchPage page) {
+		List<IWorkbenchPartReference> refs = new ArrayList<>();
+
+		EPartService partService = page.getWorkbenchWindow().getService(EPartService.class);
+		EModelService modelService = page.getWorkbenchWindow().getService(EModelService.class);
+		MPerspective currentPerspective = page.getCurrentPerspective();
+
+		
+		List<MPart> parts = modelService.findElements(currentPerspective, null, MPart.class, null,
+				EModelService.PRESENTATION);
+
+		boolean includeEditor = true;
+
+		for (MPart part : parts) {
+			if (!partService.isPartOrPlaceholderInPerspective(part.getElementId(), currentPerspective)) {
+				continue;
+			}
+			if (part.getTags().contains("Editor")) { //$NON-NLS-1$
+				if (includeEditor) {
+					addExistingReference(refs, part);
+					includeEditor = false;
+				}
+			} else {
+				addExistingReference(refs, part);
+			}
+		}
+		return refs;
+
+	}
+
+	/*
+	 * Specialized to get the static label that was shown in the past (509232)
+	 */
+	@Override
+	protected String getWorkbenchPartReferenceText(WorkbenchPartReference ref) {
+		if (ref instanceof EditorReference) {
+			return WorkbenchMessages.get().CyclePartAction_editor;
+		} else if (ref instanceof ViewReference) {
+			return ref.getPartName();
+		}
+		return super.getWorkbenchPartReferenceText(ref);
+	}
+
+	/**
+	 * Adds the {@link IWorkbenchPartReference} contained in part's transient
+	 * data, if exists.
+	 */
+	protected void addExistingReference(List<IWorkbenchPartReference> refs, MPart part) {
+		Object tData = part.getTransientData().get(IWorkbenchPartReference.class.getName());
+		if (tData instanceof IWorkbenchPartReference) {
+			// instanceof checks also for non null values
+			refs.add((IWorkbenchPartReference) tData);
+		}
+	}
+
+	@Override
+	protected ParameterizedCommand getBackwardCommand() {
+		return getParametrizedCommand(IWorkbenchCommandConstants.WINDOW_PREVIOUS_VIEW);
+	}
+
+	@Override
+	protected ParameterizedCommand getForwardCommand() {
+		return getParametrizedCommand(IWorkbenchCommandConstants.WINDOW_NEXT_VIEW);
+	}
+
+    private ParameterizedCommand getParametrizedCommand(String workbenchCommand)
+	{
+		final ICommandService commandService = window.getWorkbench().getService(ICommandService.class);
+		final Command command = commandService.getCommand(workbenchCommand);
+		ParameterizedCommand parameterizedCommand = new ParameterizedCommand(command, null);
+		return parameterizedCommand;
+	}
+
+	@Override
+	protected String getTableHeader(IWorkbenchPart activePart) {
+		return WorkbenchMessages.get().CyclePartAction_header;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/DefaultSaveable.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/DefaultSaveable.java
new file mode 100644
index 0000000..7fea798
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/DefaultSaveable.java
@@ -0,0 +1,129 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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
+ *     Andrey Loskutov <loskutov@gmx.de> - Bug 372799
+ ******************************************************************************/
+
+package org.eclipse.ui.internal;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.ISaveablePart;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPart2;
+import org.eclipse.ui.IWorkbenchPartReference;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.Saveable;
+
+/**
+ * A default {@link Saveable} implementation that wrappers a regular
+ * workbench part (one that does not itself adapt to Saveable).
+ *
+ * @since 3.2
+ */
+public class DefaultSaveable extends Saveable {
+
+	private IWorkbenchPart part;
+
+	/**
+	 * Creates a new DefaultSaveable.
+	 *
+	 * @param part
+	 *            the part represented by this model
+	 */
+	public DefaultSaveable(IWorkbenchPart part) {
+		this.part = part;
+	}
+
+	@Override
+	public void doSave(IProgressMonitor monitor) {
+		ISaveablePart saveable = SaveableHelper.getSaveable(part);
+		if (saveable != null) {
+			saveable.doSave(monitor);
+		}
+	}
+
+	@Override
+	public String getName() {
+		if (part instanceof IWorkbenchPart2) {
+			return ((IWorkbenchPart2) part).getPartName();
+		}
+		return part.getTitle();
+	}
+
+	@Override
+	public ImageDescriptor getImageDescriptor() {
+		Image image = part.getTitleImage();
+		if (image == null) {
+			return null;
+		}
+		return ImageDescriptor.createFromImage(image);
+	}
+
+	@Override
+	public String getToolTipText() {
+		return part.getTitleToolTip();
+	}
+
+	@Override
+	public boolean isDirty() {
+		ISaveablePart saveable = SaveableHelper.getSaveable(part);
+		if (saveable != null) {
+			return saveable.isDirty();
+		}
+		return false;
+	}
+
+	@Override
+	public int hashCode() {
+		return part.hashCode();
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		final DefaultSaveable other = (DefaultSaveable) obj;
+		if (part == null) {
+			if (other.part != null)
+				return false;
+		} else if (!part.equals(other.part))
+			return false;
+		return true;
+	}
+
+	@Override
+	public boolean show(IWorkbenchPage page) {
+		IWorkbenchPartReference reference = page.getReference(part);
+		if (reference != null) {
+			page.activate(part);
+			return true;
+		}
+		if (part instanceof IViewPart) {
+			IViewPart viewPart = (IViewPart) part;
+			try {
+				page.showView(viewPart.getViewSite().getId(), viewPart
+						.getViewSite().getSecondaryId(),
+						IWorkbenchPage.VIEW_ACTIVATE);
+			} catch (PartInitException e) {
+				return false;
+			}
+			return true;
+		}
+		return false;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/DirtyPerspectiveMarker.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/DirtyPerspectiveMarker.java
new file mode 100644
index 0000000..0696207
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/DirtyPerspectiveMarker.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal;
+
+/**
+ * @since 3.1
+ */
+public class DirtyPerspectiveMarker {
+	/**
+	 * @param id
+	 */
+	public DirtyPerspectiveMarker(String id) {
+		perspectiveId = id;
+	}
+
+	public String perspectiveId;
+
+	@Override
+	public int hashCode() {
+		return perspectiveId.hashCode();
+	}
+
+	@Override
+	public boolean equals(Object o) {
+		if (o instanceof DirtyPerspectiveMarker) {
+			return perspectiveId
+					.equals(((DirtyPerspectiveMarker) o).perspectiveId);
+		}
+		return false;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/DragCursors.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/DragCursors.java
new file mode 100644
index 0000000..dfc9bcb
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/DragCursors.java
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Cursor;
+import org.eclipse.swt.widgets.Display;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+
+import org.eclipse.ui.ISharedImages;
+
+/**
+ * Provides the set of cursors used for drag-and-drop.
+ */
+public class DragCursors {
+    public static final int INVALID = 0;
+
+    public static final int LEFT = 1;
+
+    public static final int RIGHT = 2;
+
+    public static final int TOP = 3;
+
+    public static final int BOTTOM = 4;
+
+    public static final int CENTER = 5;
+
+    public static final int OFFSCREEN = 6;
+
+    public static final int FASTVIEW = 7;
+
+    private final static Cursor cursors[] = new Cursor[8];
+
+    public static int positionToDragCursor(int swtPositionConstant) {
+        switch (swtPositionConstant) {
+        case SWT.LEFT:
+            return LEFT;
+        case SWT.RIGHT:
+            return RIGHT;
+        case SWT.TOP:
+            return TOP;
+        case SWT.BOTTOM:
+            return BOTTOM;
+        case SWT.CENTER:
+            return CENTER;
+        }
+
+        return INVALID;
+    }
+
+    /**
+     * Converts a drag cursor (LEFT, RIGHT, TOP, BOTTOM, CENTER) into an SWT constant
+     * (SWT.LEFT, SWT.RIGHT, SWT.TOP, SWT.BOTTOM, SWT.CENTER)
+     *
+     * @param dragCursorId
+     * @return an SWT.* constant
+     */
+    public static int dragCursorToSwtConstant(int dragCursorId) {
+        switch (dragCursorId) {
+        case LEFT:
+            return SWT.LEFT;
+        case RIGHT:
+            return SWT.RIGHT;
+        case TOP:
+            return SWT.TOP;
+        case BOTTOM:
+            return SWT.BOTTOM;
+        case CENTER:
+            return SWT.CENTER;
+        }
+
+        return SWT.DEFAULT;
+    }
+
+	/**
+     * Return the cursor for a drop scenario, as identified by code. Code must be one of INVALID,
+     * LEFT, RIGHT, TOP, etc. If the code is not found default to INVALID.
+     *
+     * @param code the code
+     * @return the cursor
+	 */
+    public static Cursor getCursor(int code) {
+        Display display = Display.getCurrent();
+        if (cursors[code] == null) {
+            ImageDescriptor source = null;
+            ImageDescriptor mask = null;
+            switch (code) {
+            case LEFT:
+                source = WorkbenchImages
+                        .getImageDescriptor(ISharedImages.IMG_OBJS_DND_LEFT_SOURCE);
+                mask = WorkbenchImages
+                        .getImageDescriptor(ISharedImages.IMG_OBJS_DND_LEFT_MASK);
+                cursors[LEFT] = new Cursor(display, SWT.CURSOR_HAND);
+                break;
+            case RIGHT:
+                source = WorkbenchImages
+                        .getImageDescriptor(ISharedImages.IMG_OBJS_DND_RIGHT_SOURCE);
+                mask = WorkbenchImages
+                        .getImageDescriptor(ISharedImages.IMG_OBJS_DND_RIGHT_MASK);
+                cursors[RIGHT] = new Cursor(display, SWT.CURSOR_HAND);
+                break;
+            case TOP:
+                source = WorkbenchImages
+                        .getImageDescriptor(ISharedImages.IMG_OBJS_DND_TOP_SOURCE);
+                mask = WorkbenchImages
+                        .getImageDescriptor(ISharedImages.IMG_OBJS_DND_TOP_MASK);
+                cursors[TOP] = new Cursor(display, SWT.CURSOR_HAND);
+                break;
+            case BOTTOM:
+                source = WorkbenchImages
+                        .getImageDescriptor(ISharedImages.IMG_OBJS_DND_BOTTOM_SOURCE);
+                mask = WorkbenchImages
+                        .getImageDescriptor(ISharedImages.IMG_OBJS_DND_BOTTOM_MASK);
+                cursors[BOTTOM] = new Cursor(display, SWT.CURSOR_HAND);
+                break;
+            case CENTER:
+                source = WorkbenchImages
+                        .getImageDescriptor(ISharedImages.IMG_OBJS_DND_STACK_SOURCE);
+                mask = WorkbenchImages
+                        .getImageDescriptor(ISharedImages.IMG_OBJS_DND_STACK_MASK);
+                cursors[CENTER] = new Cursor(display, SWT.CURSOR_HAND);
+                break;
+            case OFFSCREEN:
+                source = WorkbenchImages
+                        .getImageDescriptor(ISharedImages.IMG_OBJS_DND_OFFSCREEN_SOURCE);
+                mask = WorkbenchImages
+                        .getImageDescriptor(ISharedImages.IMG_OBJS_DND_OFFSCREEN_MASK);
+                cursors[OFFSCREEN] = new Cursor(display, SWT.CURSOR_NO);
+                break;
+            case FASTVIEW:
+                source = WorkbenchImages
+                        .getImageDescriptor(ISharedImages.IMG_OBJS_DND_TOFASTVIEW_SOURCE);
+                mask = WorkbenchImages
+                        .getImageDescriptor(ISharedImages.IMG_OBJS_DND_TOFASTVIEW_MASK);
+                cursors[FASTVIEW] = new Cursor(Display.getCurrent(), SWT.CURSOR_HAND);
+                break;
+            default:
+            case INVALID:
+                source = WorkbenchImages
+                        .getImageDescriptor(ISharedImages.IMG_OBJS_DND_INVALID_SOURCE);
+                mask = WorkbenchImages
+                        .getImageDescriptor(ISharedImages.IMG_OBJS_DND_INVALID_MASK);
+                cursors[INVALID] = new Cursor(display,SWT.CURSOR_NO);
+                break;
+            }
+        }
+        return cursors[code];
+    }
+
+    /**
+     * Disposes all drag-and-drop cursors.
+     */
+    public static void dispose() {
+        for (int idx = 0; idx < cursors.length; idx++) {
+            cursors[idx].dispose();
+            cursors[idx] = null;
+        }
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/DragHandle.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/DragHandle.java
new file mode 100644
index 0000000..df90da2
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/DragHandle.java
@@ -0,0 +1,136 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 422040
+ *******************************************************************************/
+package org.eclipse.ui.internal;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.graphics.Cursor;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+public class DragHandle extends Composite implements PaintListener {
+
+    Cursor dragCursor;
+    Image handleImage;
+    ImageDescriptor descriptor;
+    private boolean isHorizontal;
+
+    private static int margin = 2;
+
+public DragHandle(Composite parent) {
+    super(parent, SWT.NONE);
+
+    dragCursor = new Cursor(parent.getDisplay(),
+            SWT.CURSOR_SIZEALL);
+
+//    addPaintListener(this);
+
+    descriptor = AbstractUIPlugin.imageDescriptorFromPlugin(WorkbenchPlugin.PI_WORKBENCH, "icons/misc/handle.png");  //$NON-NLS-1$
+
+    // RAP
+//    handleImage = new Image(parent.getDisplay(), 4, 4);
+//    GC context = new GC(handleImage);
+//    context.setForeground(parent.getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
+//    context.drawPoint(0,0);
+//    context.drawPoint(2,0);
+//    context.drawPoint(3,0);
+//    context.drawPoint(3,1);
+//    context.drawPoint(0,2);
+//    context.drawPoint(3,2);
+//    context.drawPoint(0,3);
+//    context.drawPoint(1,3);
+//    context.drawPoint(2,3);
+//    context.drawPoint(3,3);
+//
+//    context.setForeground(parent.getDisplay().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW));
+//    context.drawPoint(1,0);
+//    context.drawPoint(0,1);
+//
+//    context.setForeground(parent.getDisplay().getSystemColor(SWT.COLOR_WIDGET_DARK_SHADOW));
+//    context.drawPoint(1,1);
+//
+//    context.setForeground(parent.getDisplay().getSystemColor(SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW));
+//    context.drawPoint(1,2);
+//    context.drawPoint(2,1);
+//    context.drawPoint(2,2);
+//
+//    context.dispose();
+
+    setCursor(dragCursor);
+}
+
+@Override
+public void paintControl(PaintEvent e) {
+    Point size = getSize();
+
+    if (handleImage != null) {
+        Rectangle ibounds = handleImage.getBounds();
+
+
+        int x = ((size.x - 2 * margin) % ibounds.width) / 2 + margin;
+        int y = ((size.y - 2 * margin) % ibounds.height) / 2 + margin;
+
+        for (;;) {
+            e.gc.drawImage(handleImage, x, y);
+            if (isHorizontal) {
+                x += ibounds.width;
+                if (x + ibounds.width > size.x - margin) {
+					break;
+				}
+            } else {
+                y += ibounds.height;
+                if (y + ibounds.height > size.y - margin) {
+					break;
+				}
+            }
+        }
+    }
+}
+@Override
+public Point computeSize(int wHint, int hHint, boolean changed) {
+    Point result = new Point(wHint, hHint);
+
+    Rectangle ibounds = handleImage.getBounds();
+
+    if (wHint == SWT.DEFAULT) {
+        result.x = ibounds.width + 2 * margin;
+    }
+
+    if (hHint == SWT.DEFAULT) {
+        result.y = ibounds.height + 2 * margin;
+    }
+
+    return result;
+}
+
+public void setHorizontal(boolean isHorizontal) {
+    this.isHorizontal = isHorizontal;
+}
+
+@Override
+public void dispose() {
+    if (isDisposed()) {
+        return;
+    }
+    super.dispose();
+    dragCursor.dispose();
+    handleImage.dispose();
+    JFaceResources.getResources().destroyImage(descriptor);
+}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/E4PartWrapper.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/E4PartWrapper.java
new file mode 100644
index 0000000..8dc9141
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/E4PartWrapper.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2014 David Berger <david.berger@logicals.com> 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:
+ *     David Berger <david.berger@logicals.com> - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ui.internal;
+
+import org.eclipse.e4.core.contexts.ContextInjectionFactory;
+import org.eclipse.e4.ui.di.Focus;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.part.ViewPart;
+
+public class E4PartWrapper extends ViewPart {
+
+	public static final String E4_WRAPPER_KEY = "e4Wrapper"; //$NON-NLS-1$
+	MPart wrappedPart;
+
+	private E4PartWrapper(MPart part) {
+		wrappedPart = part;
+		setPartName(part.getLabel());
+	}
+
+	public static E4PartWrapper getE4PartWrapper(MPart part) {
+		if (part != null) {
+			if (part.getTransientData().get(E4_WRAPPER_KEY) instanceof E4PartWrapper) {
+				return (E4PartWrapper) part.getTransientData().get(E4_WRAPPER_KEY);
+			}
+			E4PartWrapper newWrapper = new E4PartWrapper(part);
+			part.getTransientData().put(E4_WRAPPER_KEY, newWrapper);
+			return newWrapper;
+		}
+		return null;
+	}
+
+	@Override
+	public void createPartControl(Composite parent) {
+	}
+
+	@Override
+	public void setFocus() {
+		if (wrappedPart.getObject() != null && wrappedPart.getContext() != null)
+			ContextInjectionFactory.invoke(wrappedPart.getObject(), Focus.class,
+					wrappedPart.getContext());
+	}
+}
+
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/EarlyStartupRunnable.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/EarlyStartupRunnable.java
new file mode 100644
index 0000000..6468ded
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/EarlyStartupRunnable.java
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 445484, 457132, 473947
+ *******************************************************************************/
+package org.eclipse.ui.internal;
+
+import com.ibm.icu.text.MessageFormat;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.util.SafeRunnable;
+import org.eclipse.ui.IStartup;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.misc.UIStats;
+
+/**
+ * A utility class used to call #earlyStartup on the proper instance for a given
+ * configuration element.
+ *
+ * @since 3.0
+ */
+public class EarlyStartupRunnable extends SafeRunnable {
+
+    private IExtension extension;
+
+    /**
+     * @param extension
+     *            must not be null
+     */
+    public EarlyStartupRunnable(IExtension extension) {
+        this.extension = extension;
+    }
+
+    @Override
+	public void run() throws Exception {
+		IConfigurationElement[] configElements = extension.getConfigurationElements();
+		if (configElements.length == 0) {
+			missingStartupElementMessage("The org.eclipse.ui.IStartup extension from '" + //$NON-NLS-1$
+						extension.getNamespaceIdentifier() + "' does not provide a valid '" //$NON-NLS-1$
+					+ IWorkbenchConstants.TAG_STARTUP + "' element."); //$NON-NLS-1$
+		}
+        // look for the startup tag in each element and run the extension
+        for (IConfigurationElement element : configElements) {
+            if (element != null&& element.getName().equals(IWorkbenchConstants.TAG_STARTUP)) {
+                runEarlyStartup(WorkbenchPlugin.createExtension(element, IWorkbenchConstants.TAG_CLASS));
+            }
+        }
+    }
+
+	private void missingStartupElementMessage(String message) {
+		IStatus status = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0, message, null);
+		WorkbenchPlugin.log(status);
+	}
+
+    @Override
+	public void handleException(Throwable exception) {
+		IStatus status = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0,
+				"Unable to execute early startup code for the org.eclipse.ui.IStartup extension contributed by the '" //$NON-NLS-1$
+						+ extension.getNamespaceIdentifier() + "' plug-in.", //$NON-NLS-1$
+                exception);
+		WorkbenchPlugin.log(status);
+    }
+
+    private void runEarlyStartup(Object executableExtension) {
+		if (executableExtension instanceof IStartup) {
+			String methodName = executableExtension.getClass().getName() + ".earlyStartup"; //$NON-NLS-1$
+			try {
+				UIStats.start(UIStats.EARLY_STARTUP, methodName);
+				((IStartup) executableExtension).earlyStartup();
+			} finally {
+				UIStats.end(UIStats.EARLY_STARTUP, executableExtension, methodName);
+			}
+		} else {
+			String message = executableExtension == null ?
+					"The org.eclipse.ui.IStartup extension from '" + extension.getNamespaceIdentifier() //$NON-NLS-1$
+					+ "' does not provide a valid class attribute." : //$NON-NLS-1$
+					MessageFormat.format("Startup class {0} must implement org.eclipse.ui.IStartup", //$NON-NLS-1$
+							executableExtension.getClass().getName());
+			IStatus status =
+					new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0, message, null);
+			WorkbenchPlugin.log(status);
+        }
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/EditorActionBars.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/EditorActionBars.java
new file mode 100644
index 0000000..82bd528
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/EditorActionBars.java
@@ -0,0 +1,496 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.jface.action.ActionContributionItem;
+import org.eclipse.jface.action.ContributionManager;
+import org.eclipse.jface.action.GroupMarker;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.IContributionManager;
+import org.eclipse.jface.action.IContributionManagerOverrides;
+import org.eclipse.jface.action.ICoolBarManager;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.action.SubContributionManager;
+import org.eclipse.jface.action.SubCoolBarManager;
+import org.eclipse.jface.action.SubMenuManager;
+import org.eclipse.jface.action.SubStatusLineManager;
+import org.eclipse.jface.action.SubToolBarManager;
+import org.eclipse.jface.internal.provisional.action.IToolBarContributionItem;
+import org.eclipse.jface.internal.provisional.action.ToolBarContributionItem2;
+import org.eclipse.jface.internal.provisional.action.ToolBarManager2;
+import org.eclipse.swt.SWT;
+import org.eclipse.ui.IActionBars2;
+import org.eclipse.ui.IEditorActionBarContributor;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchActionConstants;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.SubActionBars2;
+import org.eclipse.ui.actions.RetargetAction;
+import org.eclipse.ui.internal.expressions.LegacyEditorActionBarExpression;
+import org.eclipse.ui.internal.misc.Policy;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * The action bars for an editor.
+ */
+public class EditorActionBars extends SubActionBars2 {
+
+	private class Overrides implements IContributionManagerOverrides {
+
+		@Override
+		public Integer getAccelerator(IContributionItem item) {
+			return null;
+		}
+
+		@Override
+		public String getAcceleratorText(IContributionItem item) {
+			return null;
+		}
+
+		@Override
+		public Boolean getEnabled(IContributionItem item) {
+			if (((item instanceof ActionContributionItem) && (((ActionContributionItem) item)
+					.getAction() instanceof RetargetAction))
+					|| enabledAllowed) {
+				return null;
+			} else {
+				return Boolean.FALSE;
+			}
+		}
+
+		@Override
+		public String getText(IContributionItem item) {
+			return null;
+		}
+
+		@Override
+		public Boolean getVisible(IContributionItem item) {
+			return null;
+		}
+	}
+
+	/**
+	 * A switch controlling verbose debugging options surrounding the disposal
+	 * of tool bar contribution items. There have been problems in the past with
+	 * reusing disposed items, and leaking memory by failing to drop references
+	 * to disposed items.
+	 */
+	private static final boolean DEBUG_TOOLBAR_DISPOSAL = Policy.DEBUG_TOOLBAR_DISPOSAL;
+
+	private IToolBarManager coolItemToolBarMgr = null;
+
+	private IEditorActionBarContributor editorContributor;
+
+	private boolean enabledAllowed = false;
+
+	private IEditorActionBarContributor extensionContributor;
+
+	private int refCount;
+
+	private IToolBarContributionItem toolBarContributionItem = null;
+
+	private String type;
+
+	private WorkbenchPage page;
+
+	/**
+	 * Constructs the EditorActionBars for an editor.
+	 */
+	public EditorActionBars(WorkbenchPage page, final IServiceLocator serviceLocator, String type) {
+		super((IActionBars2) page.getActionBars(), serviceLocator);
+		this.page = page;
+		this.type = type;
+	}
+
+	public WorkbenchPage getPage() {
+		return page;
+	}
+
+	/**
+	 * Activate the contributions.
+	 */
+	@Override
+	public void activate(boolean forceVisibility) {
+		setActive(true, forceVisibility);
+	}
+
+	/**
+	 * Add one ref to the bars.
+	 */
+	public void addRef() {
+		++refCount;
+	}
+
+	@Override
+	protected SubMenuManager createSubMenuManager(IMenuManager parent) {
+		return new EditorMenuManager(parent);
+	}
+
+	@Override
+	protected SubToolBarManager createSubToolBarManager(IToolBarManager parent) {
+		// return null, editor actions are managed by CoolItemToolBarManagers
+		return null;
+	}
+
+	/**
+	 * Deactivate the contributions.
+	 */
+	@Override
+	public void deactivate(boolean forceVisibility) {
+		setActive(false, forceVisibility);
+	}
+
+	/**
+	 * Dispose the contributions.
+	 */
+	@Override
+	public void dispose() {
+		super.dispose();
+		if (editorContributor != null) {
+			editorContributor.dispose();
+		}
+		if (extensionContributor != null) {
+			extensionContributor.dispose();
+		}
+
+		/*
+		 * Dispose of the contribution item, but also make sure that no one else
+		 * is holding on to it. In this case, go through the SubCoolBarManager
+		 * to its parent (the real CoolBarManager), and replace the reference
+		 * with a placeholder.
+		 */
+		if (toolBarContributionItem != null) {
+			// Create a placeholder and place it in the cool bar manager.
+			ICoolBarManager coolBarManager = getCoolBarManager();
+			if (coolBarManager instanceof SubContributionManager) {
+				SubContributionManager subManager = (SubContributionManager) coolBarManager;
+				IContributionManager manager = subManager.getParent();
+				if (manager instanceof CoolBarToTrimManager) {
+					CoolBarToTrimManager trimManager = (CoolBarToTrimManager) manager;
+					trimManager.remove(toolBarContributionItem);
+				} else if (manager instanceof ContributionManager) {
+					final IContributionItem replacementItem = new PlaceholderContributionItem(
+							toolBarContributionItem);
+					boolean succeeded = ((ContributionManager) manager).replaceItem(replacementItem
+							.getId(), replacementItem);
+					if (!succeeded && DEBUG_TOOLBAR_DISPOSAL) {
+						System.out.println("FAILURE WHILE DISPOSING EditorActionBars"); //$NON-NLS-1$
+						System.out
+								.println("Could not replace " + replacementItem.getId() + " in the contribution manager."); //$NON-NLS-1$ //$NON-NLS-2$
+					}
+				} else if (DEBUG_TOOLBAR_DISPOSAL) {
+					System.out.println("FAILURE WHILE DISPOSING EditorActionBars"); //$NON-NLS-1$
+					System.out.println("The manager was not a ContributionManager."); //$NON-NLS-1$
+					System.out.println("It was a " + manager.getClass().getName()); //$NON-NLS-1$
+				}
+			} else if (DEBUG_TOOLBAR_DISPOSAL) {
+				System.out.println("FAILURE WHILE DISPOSING EditorActionBars"); //$NON-NLS-1$
+				System.out.println("The coolBarManager was not a SubContributionManager"); //$NON-NLS-1$
+				System.out.println("It was a " + coolBarManager.getClass().getName()); //$NON-NLS-1$
+			}
+
+			// Dispose of the replaced item.
+			toolBarContributionItem.dispose();
+		}
+		toolBarContributionItem = null;
+		// Remove actions
+		if (coolItemToolBarMgr != null) {
+			coolItemToolBarMgr.removeAll();
+		}
+		coolItemToolBarMgr = null;
+		editorHandlerExpression = null;
+	}
+
+	/**
+	 * Gets the editor contributor
+	 */
+	public IEditorActionBarContributor getEditorContributor() {
+		return editorContributor;
+	}
+
+	/**
+	 * Returns the editor type.
+	 */
+	public String getEditorType() {
+		return type;
+	}
+
+	/**
+	 * Gets the extension contributor
+	 */
+	public IEditorActionBarContributor getExtensionContributor() {
+		return extensionContributor;
+	}
+
+	/**
+	 * Returns the reference count.
+	 */
+	public int getRef() {
+		return refCount;
+	}
+
+	/**
+	 * Returns the tool bar manager. If items are added or removed from the
+	 * manager be sure to call <code>updateActionBars</code>. Overridden to
+	 * support CoolBars.
+	 *
+	 * @return the tool bar manager
+	 */
+	@Override
+	public IToolBarManager getToolBarManager() {
+
+		// by pass the sub coolBar and use the real cool bar.
+		ICoolBarManager coolBarManager = getCastedParent().getCoolBarManager();
+		if (coolBarManager == null) {
+			return null;
+		}
+
+		// add the editor group if the app did not add it already,
+		// otherwise the references to it below will fail
+		if (coolBarManager.find(IWorkbenchActionConstants.GROUP_EDITOR) == null) {
+			coolBarManager.add(new GroupMarker(IWorkbenchActionConstants.GROUP_EDITOR));
+		}
+		if (toolBarContributionItem == null) {
+			IContributionItem foundItem = coolBarManager.find(type);
+			if ((foundItem instanceof IToolBarContributionItem)) {
+				toolBarContributionItem = (IToolBarContributionItem) foundItem;
+				coolItemToolBarMgr = toolBarContributionItem.getToolBarManager();
+				if (coolItemToolBarMgr == null) {
+					coolItemToolBarMgr = new ToolBarManager2(SWT.FLAT);
+					toolBarContributionItem = new ToolBarContributionItem2(coolItemToolBarMgr, type);
+					// Add editor item to group
+					coolBarManager.prependToGroup(IWorkbenchActionConstants.GROUP_EDITOR,
+							toolBarContributionItem);
+				}
+			} else {
+				coolItemToolBarMgr = new ToolBarManager2(SWT.FLAT);
+				if ((coolBarManager instanceof ContributionManager)
+						&& (foundItem instanceof PlaceholderContributionItem)) {
+					PlaceholderContributionItem placeholder = (PlaceholderContributionItem) foundItem;
+					toolBarContributionItem = createToolBarContributionItem(coolItemToolBarMgr,
+							placeholder);
+					// Restore from a placeholder
+					((ContributionManager) coolBarManager).replaceItem(type,
+							toolBarContributionItem);
+				} else {
+					toolBarContributionItem = new ToolBarContributionItem2(coolItemToolBarMgr, type);
+					// Add editor item to group
+					coolBarManager.prependToGroup(IWorkbenchActionConstants.GROUP_EDITOR,
+							toolBarContributionItem);
+				}
+			}
+			((ContributionManager) coolItemToolBarMgr).setOverrides(new Overrides());
+			toolBarContributionItem.setVisible(getActive());
+			coolItemToolBarMgr.markDirty();
+		}
+
+		return coolItemToolBarMgr;
+	}
+
+	/*
+	 * Creates a new tool bar contribution item on the given manager -- using
+	 * the stored data to initialize some of its properties.
+	 */
+	IToolBarContributionItem createToolBarContributionItem(final IToolBarManager manager,
+			PlaceholderContributionItem item) {
+		IToolBarContributionItem toolBarContributionItem = new ToolBarContributionItem2(manager,
+				item.getId());
+		toolBarContributionItem.setCurrentHeight(item.getHeight());
+		toolBarContributionItem.setCurrentWidth(item.getWidth());
+		toolBarContributionItem.setMinimumItemsToShow(item.getMinimumItemsToShow());
+		toolBarContributionItem.setUseChevron(item.getUseChevron());
+		return toolBarContributionItem;
+	}
+
+	/**
+	 * Returns whether the contribution list is visible. If the visibility is
+	 * <code>true</code> then each item within the manager appears within the
+	 * parent manager. Otherwise, the items are not visible.
+	 *
+	 * @return <code>true</code> if the manager is visible
+	 */
+	private boolean isVisible() {
+		if (toolBarContributionItem != null) {
+			return toolBarContributionItem.isVisible();
+		}
+		return false;
+	}
+
+	/**
+	 * Sets the target part for the action bars. For views this is ignored
+	 * because each view has its own action vector. For editors this is
+	 * important because the action vector is shared by editors of the same
+	 * type.
+	 */
+	@Override
+	public void partChanged(IWorkbenchPart part) {
+		super.partChanged(part);
+		if (part instanceof IEditorPart) {
+			IEditorPart editor = (IEditorPart) part;
+			if (editorContributor != null) {
+				editorContributor.setActiveEditor(editor);
+			}
+			if (extensionContributor != null) {
+				extensionContributor.setActiveEditor(editor);
+			}
+		}
+	}
+
+	/**
+	 * Remove one ref to the bars.
+	 */
+	public void removeRef() {
+		--refCount;
+	}
+
+	/**
+	 * Activate / Deactivate the contributions.
+	 *
+	 * Workaround for flashing when editor contributes many menu/tool
+	 * contributions. In this case, the force visibility flag determines if the
+	 * contributions should be actually made visible/hidden or just change the
+	 * enablement state.
+	 */
+	private void setActive(boolean set, boolean forceVisibility) {
+		basicSetActive(set);
+		if (isSubMenuManagerCreated()) {
+			((EditorMenuManager) getMenuManager()).setVisible(set, forceVisibility);
+		}
+
+		if (isSubStatusLineManagerCreated()) {
+			((SubStatusLineManager) getStatusLineManager()).setVisible(set);
+		}
+
+		setVisible(set, forceVisibility);
+	}
+
+	/**
+	 * Sets the editor contributor
+	 */
+	public void setEditorContributor(IEditorActionBarContributor c) {
+		editorContributor = c;
+	}
+
+	/**
+	 * Sets the enablement ability of all the items contributed by the editor.
+	 *
+	 * @param enabledAllowed
+	 *            <code>true</code> if the items may enable
+	 * @since 2.0
+	 */
+	private void setEnabledAllowed(boolean enabledAllowed) {
+		if (this.enabledAllowed == enabledAllowed) {
+			return;
+		}
+		this.enabledAllowed = enabledAllowed;
+		if (coolItemToolBarMgr != null) {
+			for (IContributionItem item : coolItemToolBarMgr.getItems()) {
+				if (item != null) {
+					item.update(IContributionManagerOverrides.P_ENABLED);
+				}
+			}
+		}
+	}
+
+	/**
+	 * Sets the extension contributor
+	 */
+	public void setExtensionContributor(IEditorActionBarContributor c) {
+		extensionContributor = c;
+	}
+
+	/**
+	 * Sets the visibility of the manager. If the visibility is
+	 * <code>true</code> then each item within the manager appears within the
+	 * parent manager. Otherwise, the items are not visible.
+	 *
+	 * @param visible
+	 *            the new visibility
+	 */
+	private void setVisible(boolean visible) {
+		if (toolBarContributionItem != null) {
+			toolBarContributionItem.setVisible(visible);
+			if (toolBarContributionItem.getParent() != null) {
+				toolBarContributionItem.getParent().markDirty();
+			}
+		}
+	}
+
+	/**
+	 * Sets the visibility of the manager. If the visibility is
+	 * <code>true</code> then each item within the manager appears within the
+	 * parent manager. Otherwise, the items are not visible if force visibility
+	 * is <code>true</code>, or grayed out if force visibility is
+	 * <code>false</code>
+	 * <p>
+	 * This is a workaround for the layout flashing when editors contribute
+	 * large amounts of items.
+	 * </p>
+	 *
+	 * @param visible
+	 *            the new visibility
+	 * @param forceVisibility
+	 *            <code>true</code> to change the visibility or
+	 *            <code>false</code> to change just the enablement state. This
+	 *            parameter is ignored if visible is <code>true</code>.
+	 */
+	private void setVisible(boolean visible, boolean forceVisibility) {
+		if (visible) {
+			setEnabledAllowed(true);
+			if (!isVisible()) {
+				setVisible(true);
+			}
+		} else {
+			if (forceVisibility) {
+				// Remove the editor tool bar items
+				setVisible(false);
+			} else {
+				// Disabled the tool bar items.
+				setEnabledAllowed(false);
+			}
+		}
+
+		ICoolBarManager coolBarManager = getCastedParent().getCoolBarManager();
+		if ((coolItemToolBarMgr != null) && (coolBarManager != null)) {
+			for (IContributionItem item : coolItemToolBarMgr.getItems()) {
+				item.setVisible(visible || !forceVisibility);
+				coolItemToolBarMgr.markDirty();
+				if (!coolBarManager.isDirty()) {
+					coolBarManager.markDirty();
+				}
+			}
+			// Update the manager
+			coolItemToolBarMgr.update(false);
+			if (toolBarContributionItem != null) {
+				toolBarContributionItem.setVisible(visible || !forceVisibility);
+			}
+			if (getCoolBarManager() != null) {
+				((SubCoolBarManager) getCoolBarManager()).setVisible(visible || !forceVisibility);
+			}
+		}
+	}
+
+	private LegacyEditorActionBarExpression editorHandlerExpression = null;
+
+	/**
+	 * Returns the expression used for action handler activation.
+	 *
+	 * @return the expression used for action handler activation.
+	 */
+	public Expression getHandlerExpression() {
+		if (editorHandlerExpression == null) {
+			editorHandlerExpression = new LegacyEditorActionBarExpression(type);
+		}
+		return editorHandlerExpression;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/EditorActionBuilder.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/EditorActionBuilder.java
new file mode 100644
index 0000000..1e6e6e6
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/EditorActionBuilder.java
@@ -0,0 +1,133 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2014 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.ui.internal;
+
+import java.util.ArrayList;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IEditorActionBarContributor;
+import org.eclipse.ui.IEditorDescriptor;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+
+/**
+ * This class reads the registry for extensions that plug into
+ * 'editorActions' extension point.
+ */
+public class EditorActionBuilder extends PluginActionBuilder {
+    private static final String TAG_CONTRIBUTION_TYPE = "editorContribution"; //$NON-NLS-1$
+
+    /**
+     * The constructor.
+     */
+    public EditorActionBuilder() {
+    }
+
+    @Override
+	protected ActionDescriptor createActionDescriptor(
+            IConfigurationElement element) {
+        return new ActionDescriptor(element, ActionDescriptor.T_EDITOR);
+    }
+
+    @Override
+	protected BasicContribution createContribution() {
+        return new EditorContribution();
+    }
+
+    /**
+     * Reads and apply all external contributions for this editor's ID
+     * registered in 'editorActions' extension point.
+     */
+    public IEditorActionBarContributor readActionExtensions(
+            IEditorDescriptor desc) {
+        ExternalContributor ext = null;
+        readContributions(desc.getId(), TAG_CONTRIBUTION_TYPE,
+                IWorkbenchRegistryConstants.PL_EDITOR_ACTIONS);
+        if (cache != null) {
+            ext = new ExternalContributor(cache);
+            cache = null;
+        }
+        return ext;
+    }
+
+    /**
+     * Helper class to collect the menus and actions defined within a
+     * contribution element.
+     */
+    private static class EditorContribution extends BasicContribution {
+        @Override
+		public void dispose() {
+			disposeActions();
+			super.dispose();
+        }
+
+        public void editorChanged(IEditorPart editor) {
+            if (actions != null) {
+                for (int i = 0; i < actions.size(); i++) {
+                    ActionDescriptor ad = (ActionDescriptor) actions.get(i);
+                    EditorPluginAction action = (EditorPluginAction) ad
+                            .getAction();
+                    action.editorChanged(editor);
+                }
+            }
+        }
+    }
+
+    /**
+     * Helper class that will populate the menu and toobar with the external
+     * editor contributions.
+     */
+    public static class ExternalContributor implements
+            IEditorActionBarContributor {
+        private ArrayList cache;
+
+        public ExternalContributor(ArrayList cache) {
+            this.cache = cache;
+        }
+
+        @Override
+		public void dispose() {
+            for (int i = 0; i < cache.size(); i++) {
+                ((EditorContribution) cache.get(i)).dispose();
+            }
+        }
+
+        public ActionDescriptor[] getExtendedActions() {
+            ArrayList results = new ArrayList();
+            for (int i = 0; i < cache.size(); i++) {
+                EditorContribution ec = (EditorContribution) cache.get(i);
+                if (ec.actions != null) {
+					results.addAll(ec.actions);
+				}
+            }
+            return (ActionDescriptor[]) results
+                    .toArray(new ActionDescriptor[results.size()]);
+        }
+
+        @Override
+		public void init(IActionBars bars, IWorkbenchPage page) {
+            for (int i = 0; i < cache.size(); i++) {
+                ((EditorContribution) cache.get(i)).contribute(bars
+                        .getMenuManager(), false, bars.getToolBarManager(),
+                        true);
+            }
+        }
+
+        @Override
+		public void setActiveEditor(IEditorPart editor) {
+            for (int i = 0; i < cache.size(); i++) {
+                ((EditorContribution) cache.get(i)).editorChanged(editor);
+            }
+        }
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/EditorHistory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/EditorHistory.java
new file mode 100644
index 0000000..70b4172
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/EditorHistory.java
@@ -0,0 +1,156 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.ui.IEditorDescriptor;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IMemento;
+
+/**
+ * This class is used to record "open editor" actions as they
+ * happen.  The input and type of each editor are recorded so that
+ * the user can reopen an item from the recently used files list.
+ */
+public class EditorHistory {
+    /**
+     * The maximum of entries in the history.
+     */
+    public static final int MAX_SIZE = 15;
+
+    /**
+     * The list of editor entries, in FIFO order.
+     */
+    private ArrayList fifoList = new ArrayList(MAX_SIZE);
+
+    /**
+     * Constructs a new history.
+     */
+    public EditorHistory() {
+        super();
+    }
+
+    /**
+     * Adds an item to the history.  Added in fifo fashion.
+     */
+    public void add(IEditorInput input, IEditorDescriptor desc) {
+		if (input != null && input.exists()) {
+			add(new EditorHistoryItem(input, desc), 0);
+		}
+    }
+
+    /**
+     * Adds an item to the history.
+     */
+    private void add(EditorHistoryItem newItem, int index) {
+        // Remove the item if it already exists so that it will be put
+        // at the top of the list.
+        if (newItem.isRestored()) {
+            remove(newItem.getInput());
+        }
+
+        // Remove the oldest one
+        if (fifoList.size() == MAX_SIZE) {
+            fifoList.remove(MAX_SIZE - 1);
+        }
+
+        // Add the new item.
+        fifoList.add(index < MAX_SIZE ? index : MAX_SIZE - 1, newItem);
+    }
+
+    /**
+     * Returns an array of editor history items.  The items are returned in order
+     * of most recent first.
+     */
+    public EditorHistoryItem[] getItems() {
+        refresh();
+        EditorHistoryItem[] array = new EditorHistoryItem[fifoList.size()];
+        fifoList.toArray(array);
+        return array;
+    }
+
+    /**
+     * Refresh the editor list.  Any stale items are removed.
+     * Only restored items are considered.
+     */
+    public void refresh() {
+        Iterator iter = fifoList.iterator();
+        while (iter.hasNext()) {
+            EditorHistoryItem item = (EditorHistoryItem) iter.next();
+            if (item.isRestored()) {
+                IEditorInput input = item.getInput();
+                if (input != null && !input.exists()) {
+					iter.remove();
+				}
+            }
+        }
+    }
+
+    /**
+     * Removes the given history item.
+     */
+    public void remove(EditorHistoryItem item) {
+        fifoList.remove(item);
+    }
+
+    /**
+     * Removes all traces of an editor input from the history.
+     */
+    public void remove(IEditorInput input) {
+        if (input == null) {
+            return;
+        }
+        Iterator iter = fifoList.iterator();
+        while (iter.hasNext()) {
+            EditorHistoryItem item = (EditorHistoryItem) iter.next();
+            if (item.matches(input)) {
+                iter.remove();
+            }
+        }
+    }
+
+    /**
+     * Restore the most-recently-used history from the given memento.
+     *
+     * @param memento the memento to restore the mru history from
+     */
+    public IStatus restoreState(IMemento memento) {
+		for (IMemento childMemento : memento.getChildren(IWorkbenchConstants.TAG_FILE)) {
+			EditorHistoryItem item = new EditorHistoryItem(childMemento);
+            if (!"".equals(item.getName()) || !"".equals(item.getToolTipText())) { //$NON-NLS-1$ //$NON-NLS-2$
+                add(item, fifoList.size());
+            }
+        }
+        return Status.OK_STATUS;
+    }
+
+    /**
+     * Save the most-recently-used history in the given memento.
+     *
+     * @param memento the memento to save the mru history in
+     */
+    public IStatus saveState(IMemento memento) {
+        Iterator iterator = fifoList.iterator();
+        while (iterator.hasNext()) {
+            EditorHistoryItem item = (EditorHistoryItem) iterator.next();
+            if (item.canSave()) {
+                IMemento itemMemento = memento
+                        .createChild(IWorkbenchConstants.TAG_FILE);
+                item.saveState(itemMemento);
+            }
+        }
+        return Status.OK_STATUS;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/EditorHistoryItem.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/EditorHistoryItem.java
new file mode 100644
index 0000000..1d7ea7c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/EditorHistoryItem.java
@@ -0,0 +1,240 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.ui.IEditorDescriptor;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorRegistry;
+import org.eclipse.ui.IElementFactory;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IPersistableElement;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * An item in the editor history.
+ */
+public class EditorHistoryItem {
+
+    private IEditorInput input;
+
+    private IEditorDescriptor descriptor;
+
+    private IMemento memento;
+
+    /**
+     * Constructs a new item.
+     */
+    public EditorHistoryItem(IEditorInput input, IEditorDescriptor descriptor) {
+        this.input = input;
+        this.descriptor = descriptor;
+    }
+
+    /**
+     * Constructs a new item from a memento.
+     */
+    public EditorHistoryItem(IMemento memento) {
+        this.memento = memento;
+    }
+
+    /**
+     * Returns the editor descriptor.
+     *
+     * @return the editor descriptor.
+     */
+    public IEditorDescriptor getDescriptor() {
+        return descriptor;
+    }
+
+    /**
+     * Returns the editor input.
+     *
+     * @return the editor input.
+     */
+    public IEditorInput getInput() {
+        return input;
+    }
+
+    /**
+     * Returns whether this item has been restored from the memento.
+     */
+    public boolean isRestored() {
+        return memento == null;
+    }
+
+    /**
+     * Returns the name of this item, either from the input if restored,
+     * otherwise from the memento.
+     */
+    public String getName() {
+        if (isRestored() && getInput() != null) {
+            return getInput().getName();
+        } else if (memento != null) {
+            String name = memento.getString(IWorkbenchConstants.TAG_NAME);
+            if (name != null) {
+                return name;
+            }
+        }
+        return ""; //$NON-NLS-1$
+    }
+
+    /**
+     * Returns the tooltip text of this item, either from the input if restored,
+     * otherwise from the memento.
+     */
+    public String getToolTipText() {
+        if (isRestored() && getInput() != null) {
+            return getInput().getToolTipText();
+        } else if (memento != null) {
+            String name = memento.getString(IWorkbenchConstants.TAG_TOOLTIP);
+            if (name != null) {
+                return name;
+            }
+        }
+        return ""; //$NON-NLS-1$
+    }
+
+    /**
+     * Returns whether this item matches the given editor input.
+     */
+    public boolean matches(IEditorInput input) {
+        if (isRestored()) {
+			return input.equals(getInput());
+		}
+        // if not restored, compare name, tool tip text and factory id,
+        // avoiding as much work as possible
+        if (!getName().equals(input.getName())) {
+			return false;
+		}
+        if (!getToolTipText().equals(input.getToolTipText())) {
+			return false;
+		}
+        IPersistableElement persistable = input.getPersistable();
+        String inputId = persistable == null ? null : persistable
+                .getFactoryId();
+        String myId = getFactoryId();
+        return myId == null ? inputId == null : myId.equals(inputId);
+    }
+
+    /**
+     * Returns the factory id of this item, either from the input if restored,
+     * otherwise from the memento.
+     * Returns <code>null</code> if there is no factory id.
+     */
+    public String getFactoryId() {
+        if (isRestored()) {
+            if (input != null) {
+                IPersistableElement persistable = input.getPersistable();
+                if (persistable != null) {
+                    return persistable.getFactoryId();
+                }
+            }
+        } else if (memento != null) {
+            return memento.getString(IWorkbenchConstants.TAG_FACTORY_ID);
+        }
+        return null;
+    }
+
+    /**
+     * Restores the object state from the memento.
+     */
+    public IStatus restoreState() {
+        Assert.isTrue(!isRestored());
+
+        IStatus result = Status.OK_STATUS;
+        IMemento memento = this.memento;
+        this.memento = null;
+
+        String factoryId = memento
+                .getString(IWorkbenchConstants.TAG_FACTORY_ID);
+        if (factoryId == null) {
+            WorkbenchPlugin
+                    .log("Unable to restore mru list - no input factory ID.");//$NON-NLS-1$
+            return result;
+        }
+        IElementFactory factory = PlatformUI.getWorkbench().getElementFactory(
+                factoryId);
+        if (factory == null) {
+            return result;
+        }
+        IMemento persistableMemento = memento
+                .getChild(IWorkbenchConstants.TAG_PERSISTABLE);
+        if (persistableMemento == null) {
+            WorkbenchPlugin
+                    .log("Unable to restore mru list - no input element state: " + factoryId);//$NON-NLS-1$
+            return result;
+        }
+        IAdaptable adaptable = factory.createElement(persistableMemento);
+        if (adaptable == null || (adaptable instanceof IEditorInput) == false) {
+            return result;
+        }
+        input = (IEditorInput) adaptable;
+        // Get the editor descriptor.
+        String editorId = memento.getString(IWorkbenchConstants.TAG_ID);
+        if (editorId != null) {
+            IEditorRegistry registry = WorkbenchPlugin.getDefault()
+                    .getEditorRegistry();
+            descriptor = registry.findEditor(editorId);
+        }
+        return result;
+    }
+
+    /**
+     * Returns whether this history item can be saved.
+     */
+    public boolean canSave() {
+        return !isRestored()
+                || (getInput() != null && getInput().getPersistable() != null);
+    }
+
+    /**
+     * Saves the object state in the given memento.
+     *
+     * @param memento the memento to save the object state in
+     */
+    public IStatus saveState(IMemento memento) {
+        if (!isRestored()) {
+            memento.putMemento(this.memento);
+        } else if (input != null) {
+
+            IPersistableElement persistable = input.getPersistable();
+            if (persistable != null) {
+                /*
+                 * Store IPersistable of the IEditorInput in a separate section
+                 * since it could potentially use a tag already used in the parent
+                 * memento and thus overwrite data.
+                 */
+                IMemento persistableMemento = memento
+                        .createChild(IWorkbenchConstants.TAG_PERSISTABLE);
+                persistable.saveState(persistableMemento);
+                memento.putString(IWorkbenchConstants.TAG_FACTORY_ID,
+                        persistable.getFactoryId());
+                if (descriptor != null && descriptor.getId() != null) {
+                    memento.putString(IWorkbenchConstants.TAG_ID, descriptor
+                            .getId());
+                }
+                // save the name and tooltip separately so they can be restored
+                // without having to instantiate the input, which can activate plugins
+                memento
+                        .putString(IWorkbenchConstants.TAG_NAME, input
+                                .getName());
+                memento.putString(IWorkbenchConstants.TAG_TOOLTIP, input
+                        .getToolTipText());
+            }
+        }
+        return Status.OK_STATUS;
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/EditorMenuManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/EditorMenuManager.java
new file mode 100644
index 0000000..b2e8c2a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/EditorMenuManager.java
@@ -0,0 +1,223 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import org.eclipse.jface.action.ActionContributionItem;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.IContributionManagerOverrides;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.SubMenuManager;
+import org.eclipse.ui.actions.RetargetAction;
+
+/**
+ * An <code>EditorMenuManager</code> is used to sort the contributions
+ * made by an editor so that they always appear after the action sets.
+ */
+public class EditorMenuManager extends SubMenuManager {
+    private ArrayList wrappers;
+
+    private boolean enabledAllowed = true;
+
+    private class Overrides implements IContributionManagerOverrides {
+        /**
+         * Indicates that the items of this manager are allowed to enable;
+         * <code>true</code> by default.
+         */
+        public void updateEnabledAllowed() {
+            // update the items in the map
+			for (IContributionItem item : EditorMenuManager.super.getItems()) {
+                item.update(IContributionManagerOverrides.P_ENABLED);
+            }
+            // update the wrapped menus
+            if (wrappers != null) {
+                for (int i = 0; i < wrappers.size(); i++) {
+                    EditorMenuManager manager = (EditorMenuManager) wrappers
+                            .get(i);
+                    manager.setEnabledAllowed(enabledAllowed);
+                }
+            }
+        }
+
+        @Override
+		public Boolean getEnabled(IContributionItem item) {
+            if (((item instanceof ActionContributionItem) && (((ActionContributionItem) item)
+                    .getAction() instanceof RetargetAction))
+                    || enabledAllowed) {
+				return null;
+			} else {
+				return Boolean.FALSE;
+			}
+        }
+
+        @Override
+		public Integer getAccelerator(IContributionItem item) {
+            if (getEnabled(item) == null) {
+				return getParentMenuManager().getOverrides().getAccelerator(
+                        item);
+			} else {
+				// no acclerator if the item is disabled
+				return Integer.valueOf(0);
+			}
+        }
+
+        @Override
+		public String getAcceleratorText(IContributionItem item) {
+            return getParentMenuManager().getOverrides().getAcceleratorText(
+                    item);
+        }
+
+        @Override
+		public String getText(IContributionItem item) {
+            return getParentMenuManager().getOverrides().getText(item);
+        }
+
+        @Override
+		public Boolean getVisible(IContributionItem item) {
+        	return getParentMenuManager().getOverrides().getVisible(item);
+        }
+    }
+
+    private Overrides overrides = new Overrides();
+
+    /**
+     * Constructs a new editor manager.
+     */
+	public EditorMenuManager(IMenuManager mgr) {
+        super(mgr);
+    }
+
+    @Override
+	public IContributionItem[] getItems() {
+        return getParentMenuManager().getItems();
+    }
+
+    @Override
+	public IContributionManagerOverrides getOverrides() {
+        return overrides;
+    }
+
+	/*
+	 * Inserts the new item after any action set contributions which may exist
+	 * within the toolbar to ensure a consistent order for actions.
+	 */
+    @Override
+	public void prependToGroup(String groupName, IContributionItem item) {
+        insertAfter(groupName, item);
+    }
+
+	@Override
+	public void appendToGroup(String groupName, IContributionItem item) {
+		try {
+			// FIXME: this is killing at least SSE editors, see bug 318034
+			super.appendToGroup(groupName, item);
+		} catch (RuntimeException e) {
+			WorkbenchPlugin.log(e);
+		}
+	}
+
+    /**
+     * Sets the visibility of the manager. If the visibility is <code>true</code>
+     * then each item within the manager appears within the parent manager.
+     * Otherwise, the items are not visible.
+     * <p>
+     * If force visibility is <code>true</code>, or grayed out if force visibility is <code>false</code>
+     * <p>
+     * This is a workaround for the layout flashing when editors contribute
+     * large amounts of items.</p>
+     *
+     * @param visible the new visibility
+     * @param forceVisibility whether to change the visibility or just the
+     * 		enablement state.
+     */
+    public void setVisible(boolean visible, boolean forceVisibility) {
+        if (visible) {
+            if (forceVisibility) {
+                // Make the items visible
+                if (!enabledAllowed) {
+					setEnabledAllowed(true);
+				}
+            } else {
+                if (enabledAllowed) {
+					setEnabledAllowed(false);
+				}
+            }
+            if (!isVisible()) {
+				setVisible(true);
+			}
+        } else {
+            if (forceVisibility) {
+				// Remove the editor menu items
+                setVisible(false);
+			} else {
+				// Disable the editor menu items.
+                setEnabledAllowed(false);
+			}
+        }
+    }
+
+    /**
+     * Sets the enablement ability of all the items contributed by the editor.
+     *
+     * @param enabledAllowed <code>true</code> if the items may enable
+     * @since 2.0
+     */
+    public void setEnabledAllowed(boolean enabledAllowed) {
+        if (this.enabledAllowed == enabledAllowed) {
+			return;
+		}
+        this.enabledAllowed = enabledAllowed;
+        overrides.updateEnabledAllowed();
+    }
+
+    @Override
+	protected SubMenuManager wrapMenu(IMenuManager menu) {
+        if (wrappers == null) {
+			wrappers = new ArrayList();
+		}
+		EditorMenuManager manager = new EditorMenuManager(menu);
+        wrappers.add(manager);
+        return manager;
+    }
+
+    protected IAction[] getAllContributedActions() {
+        HashSet set = new HashSet();
+        getAllContributedActions(set);
+        return (IAction[]) set.toArray(new IAction[set.size()]);
+    }
+
+    protected void getAllContributedActions(HashSet set) {
+		for (IContributionItem item : super.getItems()) {
+			getAllContributedActions(set, item);
+		}
+        if (wrappers == null) {
+			return;
+		}
+        for (Iterator iter = wrappers.iterator(); iter.hasNext();) {
+            EditorMenuManager element = (EditorMenuManager) iter.next();
+            element.getAllContributedActions(set);
+        }
+    }
+
+    protected void getAllContributedActions(HashSet set, IContributionItem item) {
+        if (item instanceof MenuManager) {
+			for (IContributionItem subItem : ((MenuManager) item).getItems()) {
+				getAllContributedActions(set, subItem);
+			}
+        } else if (item instanceof ActionContributionItem) {
+            set.add(((ActionContributionItem) item).getAction());
+        }
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/EditorPluginAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/EditorPluginAction.java
new file mode 100644
index 0000000..51ae2d3
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/EditorPluginAction.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.ui.IActionDelegate;
+import org.eclipse.ui.IEditorActionDelegate;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.WorkbenchException;
+
+/**
+ * Extends PartPluginAction for usage in editor parts. Objects
+ * of this class are created by reading the registry (extension point "editorActions").
+ */
+public final class EditorPluginAction extends PartPluginAction {
+    private IEditorPart currentEditor;
+
+    /**
+     * This class adds the requirement that action delegates
+     * loaded on demand implement IViewActionDelegate
+     */
+    public EditorPluginAction(IConfigurationElement actionElement,
+            IEditorPart part, String id, int style) {
+        super(actionElement, id, style);
+        if (part != null) {
+			editorChanged(part);
+		}
+    }
+
+    @Override
+	protected IActionDelegate validateDelegate(Object obj)
+            throws WorkbenchException {
+        if (obj instanceof IEditorActionDelegate) {
+			return (IEditorActionDelegate) obj;
+		} else {
+			throw new WorkbenchException(
+                    "Action must implement IEditorActionDelegate"); //$NON-NLS-1$
+		}
+    }
+
+    @Override
+	protected void initDelegate() {
+        super.initDelegate();
+        ((IEditorActionDelegate) getDelegate()).setActiveEditor(this,
+                currentEditor);
+    }
+
+    /**
+     * Handles editor change by re-registering for selection
+     * changes and updating IEditorActionDelegate.
+     */
+    public void editorChanged(IEditorPart part) {
+        if (currentEditor != null) {
+			unregisterSelectionListener(currentEditor);
+		}
+
+        currentEditor = part;
+
+        if (getDelegate() == null && isOkToCreateDelegate()) {
+			createDelegate();
+		}
+        if (getDelegate() != null) {
+			((IEditorActionDelegate) getDelegate()).setActiveEditor(this, part);
+		}
+
+        if (part != null) {
+			registerSelectionListener(part);
+		}
+    }
+
+	@Override
+	public void dispose() {
+        if (currentEditor != null) {
+            unregisterSelectionListener(currentEditor);
+			currentEditor = null;
+        }
+		super.dispose();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/EditorReference.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/EditorReference.java
new file mode 100644
index 0000000..abf1b22
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/EditorReference.java
@@ -0,0 +1,482 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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
+ *     Nikolay Botev - bug 240651
+ *     Andrey Loskutov <loskutov@gmx.de> - Bug 459964
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ *******************************************************************************/
+package org.eclipse.ui.internal;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.workbench.IPresentationEngine;
+import org.eclipse.jface.internal.provisional.action.ICoolBarManager2;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.IEditorActionBarContributor;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorReference;
+import org.eclipse.ui.IEditorRegistry;
+import org.eclipse.ui.IElementFactory;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IPersistableEditor;
+import org.eclipse.ui.IPersistableElement;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPart3;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.WorkbenchException;
+import org.eclipse.ui.XMLMemento;
+import org.eclipse.ui.internal.editorsupport.ComponentSupport;
+import org.eclipse.ui.internal.part.NullEditorInput;
+import org.eclipse.ui.internal.registry.EditorDescriptor;
+import org.eclipse.ui.internal.registry.EditorRegistry;
+import org.eclipse.ui.internal.util.Util;
+
+public class EditorReference extends WorkbenchPartReference implements IEditorReference {
+
+	private IEditorInput input;
+	private EditorDescriptor descriptor;
+	private final String descriptorId;
+	private final IMemento editorState;
+	private final String factoryId;
+
+	public EditorReference(IEclipseContext windowContext, IWorkbenchPage page, MPart part,
+			IEditorInput input, EditorDescriptor descriptor, IMemento editorState) {
+		super(windowContext, page, part);
+		this.input = input;
+		this.descriptor = descriptor;
+		this.editorState = editorState;
+
+		String factory = null;
+		if (descriptor == null) {
+				String memento = getModel().getPersistedState().get(MEMENTO_KEY);
+				if (memento == null) {
+					descriptorId = EditorRegistry.EMPTY_EDITOR_ID;
+				} else {
+					XMLMemento createReadRoot;
+					try {
+						createReadRoot = XMLMemento
+								.createReadRoot(new StringReader(memento));
+					} catch (WorkbenchException e) {
+						WorkbenchPlugin.log(e);
+						descriptorId = EditorRegistry.EMPTY_EDITOR_ID;
+						factoryId = null;
+						return;
+					}
+					IEditorRegistry registry = getPage().getWorkbenchWindow().getWorkbench()
+							.getEditorRegistry();
+					descriptorId = createReadRoot.getString(IWorkbenchConstants.TAG_ID);
+					this.descriptor = (EditorDescriptor) registry.findEditor(descriptorId);
+
+					boolean pinnedVal = "true".equals(createReadRoot.getString(IWorkbenchConstants.TAG_PINNED)); //$NON-NLS-1$
+					setPinned(pinnedVal);
+
+					String ttip = createReadRoot.getString(IWorkbenchConstants.TAG_TOOLTIP);
+					part.getTransientData().put(IPresentationEngine.OVERRIDE_TITLE_TOOL_TIP_KEY,
+							ttip);
+
+					IMemento inputMem = createReadRoot.getChild(IWorkbenchConstants.TAG_INPUT);
+					if (inputMem != null) {
+						factory = inputMem.getString(IWorkbenchConstants.TAG_FACTORY_ID);
+					}
+				}
+		} else {
+			descriptorId = this.descriptor.getId();
+		}
+		factoryId = factory;
+	}
+
+	boolean persist() {
+		XMLMemento persistedState = (XMLMemento) getEditorState();
+		if (persistedState == null)
+			return false;
+
+		StringWriter writer = new StringWriter();
+		try {
+			persistedState.save(writer);
+			getModel().getPersistedState().put(MEMENTO_KEY, writer.toString());
+		} catch (IOException e) {
+			WorkbenchPlugin.log(e);
+			return false;
+		}
+
+		return true;
+	}
+
+	IMemento getEditorState() {
+		IEditorPart editor = getEditor(false);
+
+		// If the editor hasn't been rendered yet then see if we can grab the
+		// info from the model
+		if (editor == null && getModel() != null) {
+			String savedState = getModel().getPersistedState().get(MEMENTO_KEY);
+			if (savedState != null) {
+				StringReader sr = new StringReader(savedState);
+				try {
+					XMLMemento memento = XMLMemento.createReadRoot(sr);
+					return memento;
+				} catch (WorkbenchException e) {
+					WorkbenchPlugin.log(e);
+					return null;
+				}
+			}
+			return null;
+		}
+
+		IEditorInput input = editor.getEditorInput();
+		if (input == null) {
+			return null;
+		}
+
+		IPersistableElement persistable = input.getPersistable();
+		if (persistable == null) {
+			return null;
+		}
+
+		XMLMemento editorMem = XMLMemento.createWriteRoot(IWorkbenchConstants.TAG_EDITOR);
+		editorMem.putString(IWorkbenchConstants.TAG_ID, descriptor.getId());
+		editorMem.putString(IWorkbenchConstants.TAG_TITLE, getTitle());
+		editorMem.putString(IWorkbenchConstants.TAG_NAME, getName());
+		editorMem.putString(IWorkbenchConstants.TAG_ID, getId());
+		editorMem.putString(IWorkbenchConstants.TAG_TOOLTIP, getTitleToolTip());
+		editorMem.putString(IWorkbenchConstants.TAG_PART_NAME, getPartName());
+
+		if (editor instanceof IWorkbenchPart3) {
+			Map<String, String> properties = ((IWorkbenchPart3) editor).getPartProperties();
+			if (!properties.isEmpty()) {
+				IMemento propBag = editorMem.createChild(IWorkbenchConstants.TAG_PROPERTIES);
+				for (Map.Entry<String, String> entry : properties.entrySet()) {
+					IMemento p = propBag.createChild(IWorkbenchConstants.TAG_PROPERTY,
+ entry.getKey());
+					p.putTextData(entry.getValue());
+				}
+			}
+		}
+
+		if (isPinned()) {
+			editorMem.putString(IWorkbenchConstants.TAG_PINNED, "true"); //$NON-NLS-1$
+		}
+
+		IMemento inputMem = editorMem.createChild(IWorkbenchConstants.TAG_INPUT);
+		inputMem.putString(IWorkbenchConstants.TAG_FACTORY_ID, persistable.getFactoryId());
+		persistable.saveState(inputMem);
+
+		if (editor instanceof IPersistableEditor) {
+			IMemento editorStateMem = editorMem.createChild(IWorkbenchConstants.TAG_EDITOR_STATE);
+			((IPersistableEditor) editor).saveState(editorStateMem);
+		}
+
+		return editorMem;
+	}
+
+	public EditorDescriptor getDescriptor() {
+		return descriptor;
+	}
+
+	@Override
+	public String getId() {
+		// by default we delegate to the model part, which is not correct for
+		// editors
+		return descriptorId;
+	}
+
+	@Override
+	public String getFactoryId() {
+		IEditorPart editor = getEditor(false);
+		if (editor == null) {
+			if (input == null) {
+				return factoryId;
+			}
+
+			IPersistableElement persistable = input.getPersistable();
+			return persistable == null ? null : persistable.getFactoryId();
+		}
+
+		IPersistableElement persistable = editor.getEditorInput().getPersistable();
+		return persistable == null ? null : persistable.getFactoryId();
+	}
+
+	@Override
+	public String getName() {
+		IEditorPart editor = getEditor(false);
+		if (input == null) {
+			return editor == null ? getModel().getLocalizedLabel() : editor.getEditorInput()
+					.getName();
+		}
+		return editor == null ? input.getName() : editor.getEditorInput().getName();
+	}
+
+	@Override
+	public String getTitle() {
+		String label = Util.safeString(getModel().getLocalizedLabel());
+		if (label.length() == 0) {
+			if (input == null) {
+				if (descriptor != null) {
+					return descriptor.getLabel();
+				}
+			} else {
+				return Util.safeString(input.getName());
+			}
+		}
+		return label;
+	}
+
+	private IEditorInput restoreInput(IMemento editorMem) throws PartInitException {
+		return createInput(editorMem);
+	}
+
+	public static IEditorInput createInput(IMemento editorMem)
+			throws PartInitException {
+		String editorId = editorMem.getString(IWorkbenchConstants.TAG_ID);
+
+		IMemento inputMem = editorMem.getChild(IWorkbenchConstants.TAG_INPUT);
+
+		String editorName = null;
+		String factoryID = null;
+		if (inputMem != null) {
+			editorName = inputMem.getString(IWorkbenchConstants.TAG_PATH);
+			factoryID = inputMem.getString(IWorkbenchConstants.TAG_FACTORY_ID);
+		}
+		if (factoryID == null) {
+			throw new PartInitException(NLS.bind(
+					WorkbenchMessages.get().EditorManager_no_input_factory_ID, editorId, editorName));
+		}
+		IAdaptable input = null;
+		IElementFactory factory = PlatformUI.getWorkbench().getElementFactory(factoryID);
+		if (factory == null) {
+			throw new PartInitException(NLS.bind(
+					WorkbenchMessages.get().EditorManager_bad_element_factory, new Object[] { factoryID,
+							editorId, editorName }));
+		}
+
+		// Get the input element.
+		input = factory.createElement(inputMem);
+		if (input == null) {
+			throw new PartInitException(NLS.bind(
+					WorkbenchMessages.get().EditorManager_create_element_returned_null, new Object[] {
+							factoryID, editorId, editorName }));
+		}
+		if (!(input instanceof IEditorInput)) {
+			throw new PartInitException(NLS.bind(
+					WorkbenchMessages.get().EditorManager_wrong_createElement_result, new Object[] {
+							factoryID, editorId, editorName }));
+		}
+		return (IEditorInput) input;
+	}
+
+	@Override
+	public IEditorPart getEditor(boolean restore) {
+		return (IEditorPart) getPart(restore);
+	}
+
+	@Override
+	public IEditorInput getEditorInput() throws PartInitException {
+		IEditorPart editor = getEditor(false);
+		if (editor != null) {
+			return editor.getEditorInput();
+		}
+
+		if (input == null) {
+			String memento = getModel().getPersistedState().get(MEMENTO_KEY);
+			if (memento == null) {
+				input = new NullEditorInput();
+			} else {
+				try {
+					XMLMemento createReadRoot = XMLMemento
+							.createReadRoot(new StringReader(memento));
+					input = restoreInput(createReadRoot);
+				} catch (WorkbenchException e) {
+					throw new PartInitException(e.getStatus());
+				}
+			}
+		}
+		return input;
+	}
+
+	@Override
+	public IWorkbenchPart createPart() throws PartInitException {
+		try {
+			if (descriptor == null) {
+				return createErrorPart();
+			} else if (descriptor.getId().equals(IEditorRegistry.SYSTEM_INPLACE_EDITOR_ID)) {
+				IEditorPart part = ComponentSupport.getSystemInPlaceEditor();
+				if (part == null) {
+					throw new PartInitException(WorkbenchMessages.get().EditorManager_no_in_place_support);
+				}
+				return part;
+			}
+			return descriptor.createEditor();
+		} catch (CoreException e) {
+			IStatus status = e.getStatus();
+			throw new PartInitException(new Status(IStatus.ERROR, WorkbenchPlugin.PI_WORKBENCH,
+					status.getCode(), status.getMessage(), e));
+		}
+	}
+
+	@Override
+	IWorkbenchPart createErrorPart() {
+		IStatus status = new Status(IStatus.ERROR, WorkbenchPlugin.PI_WORKBENCH, NLS.bind(
+				WorkbenchMessages.get().EditorManager_missing_editor_descriptor, descriptorId), new Exception());
+		IEditorRegistry registry = getPage().getWorkbenchWindow().getWorkbench()
+				.getEditorRegistry();
+		descriptor = (EditorDescriptor) registry.findEditor(EditorRegistry.EMPTY_EDITOR_ID);
+		return createErrorPart(status);
+	}
+
+	@Override
+	public IWorkbenchPart createErrorPart(IStatus status) {
+		return new ErrorEditorPart(status);
+	}
+
+	@Override
+	public void initialize(IWorkbenchPart part) throws PartInitException {
+		IConfigurationElement element = descriptor.getConfigurationElement();
+		EditorSite editorSite = new EditorSite(getModel(), part, this, element);
+		if (element == null) {
+			editorSite.setExtensionId(descriptor.getId());
+		}
+		editorSite.setActionBars(createEditorActionBars((WorkbenchPage) getPage(), descriptor));
+		IEditorPart editor = (IEditorPart) part;
+		try {
+			editor.init(editorSite, getEditorInput());
+		} catch (PartInitException e) {
+			if (editor instanceof ErrorEditorPart) {
+				editor.init(editorSite, new NullEditorInput(this));
+			} else {
+				throw e;
+			}
+		}
+
+		if (editor.getSite() != editorSite || editor.getEditorSite() != editorSite) {
+			String id = descriptor == null ? getModel().getElementId() : descriptor.getId();
+			throw new PartInitException(NLS.bind(WorkbenchMessages.get().EditorManager_siteIncorrect, id));
+		}
+
+		if (part instanceof IPersistableEditor) {
+			if (editorState != null) {
+				((IPersistableEditor) part).restoreState(editorState);
+			} else if (useIPersistableEditor()) {
+				String mementoString = getModel().getPersistedState().get(MEMENTO_KEY);
+				if (mementoString != null) {
+					try {
+						IMemento createReadRoot = XMLMemento.createReadRoot(new StringReader(
+								mementoString));
+						IMemento editorStateMemento = createReadRoot
+								.getChild(IWorkbenchConstants.TAG_EDITOR_STATE);
+						if (editorStateMemento != null) {
+							((IPersistableEditor) part).restoreState(editorStateMemento);
+						}
+					} catch (WorkbenchException e) {
+						throw new PartInitException(e.getStatus());
+					}
+				}
+			}
+		}
+
+		legacyPart = part;
+		addPropertyListeners();
+	}
+
+	@Override
+	public PartSite getSite() {
+		if (legacyPart != null) {
+			return (PartSite) legacyPart.getSite();
+		}
+		return null;
+	}
+
+	private static HashMap<String, Set<EditorActionBars>> actionCache = new HashMap<>();
+
+	/*
+	 * Creates the action bars for an editor. Editors of the same type should
+	 * share a single editor action bar, so this implementation may return an
+	 * existing action bar vector.
+	 */
+	private static EditorActionBars createEditorActionBars(WorkbenchPage page, EditorDescriptor desc) {
+		// Get the editor type.
+		String type = desc.getId();
+
+		// If an action bar already exists for this editor type return it.
+		Set<EditorActionBars> candidates = actionCache.get(type);
+		if (candidates != null) {
+			for (EditorActionBars candidate : candidates) {
+				if (candidate.getPage() == page) {
+					candidate.addRef();
+					return candidate;
+				}
+			}
+		}
+
+		// Create a new action bar set.
+		EditorActionBars actionBars = new EditorActionBars(page, page.getWorkbenchWindow(), type);
+		actionBars.addRef();
+		if (candidates == null) {
+			candidates = new HashSet<>(3);
+			candidates.add(actionBars);
+			actionCache.put(type, candidates);
+		} else
+			candidates.add(actionBars);
+
+		// Read base contributor.
+		IEditorActionBarContributor contr = desc.createActionBarContributor();
+		if (contr != null) {
+			actionBars.setEditorContributor(contr);
+			contr.init(actionBars, page);
+		}
+
+		// Read action extensions.
+		EditorActionBuilder builder = new EditorActionBuilder();
+		contr = builder.readActionExtensions(desc);
+		if (contr != null) {
+			actionBars.setExtensionContributor(contr);
+			contr.init(actionBars, page);
+		}
+
+		// Return action bars.
+		return actionBars;
+	}
+
+	public static void disposeEditorActionBars(EditorActionBars actionBars) {
+		actionBars.removeRef();
+		if (actionBars.getRef() <= 0) {
+			String type = actionBars.getEditorType();
+			Set<EditorActionBars> set = actionCache.get(type);
+			if (set != null) {
+				set.remove(actionBars);
+			}
+			// refresh the cool bar manager before disposing of a cool item
+			ICoolBarManager2 coolBar = (ICoolBarManager2) ((WorkbenchWindow) actionBars.getPage()
+					.getWorkbenchWindow()).getCoolBarManager2();
+			if (coolBar != null) {
+				coolBar.refresh();
+			}
+			actionBars.dispose();
+		}
+	}
+
+	private static boolean useIPersistableEditor() {
+		IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore();
+		return store.getBoolean(IPreferenceConstants.USE_IPERSISTABLE_EDITORS);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/EditorSite.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/EditorSite.java
new file mode 100644
index 0000000..ebd60f0
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/EditorSite.java
@@ -0,0 +1,163 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import java.util.ArrayList;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.ui.IActionBars2;
+import org.eclipse.ui.IEditorActionBarContributor;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartReference;
+import org.eclipse.ui.SubActionBars;
+import org.eclipse.ui.SubActionBars2;
+import org.eclipse.ui.dnd.IDragAndDropService;
+
+/**
+ * An editor container manages the services for an editor.
+ */
+public class EditorSite extends PartSite implements IEditorSite {
+    /* package */ //static final int PROP_REUSE_EDITOR = -0x101;
+
+
+    //private ListenerList propChangeListeners = new ListenerList(1);
+
+    private SubActionBars ab = null;
+
+    /**
+     * Constructs an EditorSite for an editor.
+     */
+	public EditorSite(MPart model, IWorkbenchPart part, IWorkbenchPartReference ref,
+			IConfigurationElement element) {
+		super(model, part, ref, element);
+
+		// Initialize the services specific to this editor site.
+        initializeDefaultServices();
+    }
+
+	/**
+	 * Initialize the local services.
+	 */
+	private void initializeDefaultServices() {
+		// Register an implementation of the service appropriate for the
+		// EditorSite.
+		final IDragAndDropService editorDTService = new EditorSiteDragAndDropServiceImpl();
+		serviceLocator.registerService(IDragAndDropService.class, editorDTService);
+		serviceLocator.registerService(IEditorPart.class, getPart());
+	}
+
+    @Override
+	public void setActionBars(SubActionBars bars) {
+        super.setActionBars(bars);
+
+        if (bars instanceof IActionBars2) {
+            ab = new SubActionBars2((IActionBars2)bars, this);
+        } else {
+            ab = new SubActionBars(bars, this);
+        }
+    }
+
+    @Override
+	public void activateActionBars(boolean forceVisibility) {
+        if (ab != null) {
+            ab.activate(forceVisibility);
+        }
+        super.activateActionBars(forceVisibility);
+    }
+
+    @Override
+	public void deactivateActionBars(boolean forceHide) {
+        if (ab != null) {
+            ab.deactivate(forceHide);
+        }
+        super.deactivateActionBars(forceHide);
+    }
+
+    /**
+     * Returns the editor action bar contributor for this editor.
+     * <p>
+     * An action contributor is responsable for the creation of actions.
+     * By design, this contributor is used for one or more editors of the same type.
+     * Thus, the contributor returned by this method is not owned completely
+     * by the editor.  It is shared.
+     * </p>
+     *
+     * @return the editor action bar contributor
+     */
+    @Override
+	public IEditorActionBarContributor getActionBarContributor() {
+        EditorActionBars bars = (EditorActionBars) getActionBars();
+        if (bars != null) {
+			return bars.getEditorContributor();
+		}
+
+        return null;
+    }
+
+    /**
+     * Returns the extension editor action bar contributor for this editor.
+     */
+    public IEditorActionBarContributor getExtensionActionBarContributor() {
+        EditorActionBars bars = (EditorActionBars) getActionBars();
+        if (bars != null) {
+			return bars.getExtensionContributor();
+		}
+
+        return null;
+    }
+
+    /**
+     * Returns the editor
+     */
+    public IEditorPart getEditorPart() {
+        return (IEditorPart) getPart();
+    }
+
+    @Override
+	protected String getInitialScopeId() {
+        return "org.eclipse.ui.textEditorScope"; //$NON-NLS-1$
+    }
+
+    @Override
+	public void dispose() {
+        super.dispose();
+
+        if (ab != null) {
+            ab.dispose();
+			ab = null;
+        }
+    }
+
+    @Override
+	public final void registerContextMenu(final MenuManager menuManager,
+            final ISelectionProvider selectionProvider,
+            final boolean includeEditorInput) {
+        registerContextMenu(getId(), menuManager, selectionProvider,
+                includeEditorInput);
+    }
+
+    @Override
+	public final void registerContextMenu(final String menuId,
+            final MenuManager menuManager,
+            final ISelectionProvider selectionProvider,
+            final boolean includeEditorInput) {
+        if (menuExtenders == null) {
+            menuExtenders = new ArrayList(1);
+        }
+
+		PartSite.registerContextMenu(menuId, menuManager, selectionProvider, includeEditorInput,
+				getPart(), getModel().getContext(), menuExtenders);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/EditorSiteDragAndDropServiceImpl.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/EditorSiteDragAndDropServiceImpl.java
new file mode 100644
index 0000000..1ffacce
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/EditorSiteDragAndDropServiceImpl.java
@@ -0,0 +1,212 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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
+ *     Stephan Wahlbrink <stephan.wahlbrink@walware.de> - Wrong operations mode/feedback for text drag over/drop in text editors - https://bugs.eclipse.org/bugs/show_bug.cgi?id=206043
+ *******************************************************************************/
+
+package org.eclipse.ui.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.eclipse.swt.dnd.DND;
+import org.eclipse.swt.dnd.DropTarget;
+import org.eclipse.swt.dnd.DropTargetEvent;
+import org.eclipse.swt.dnd.DropTargetListener;
+import org.eclipse.swt.dnd.Transfer;
+import org.eclipse.swt.dnd.TransferData;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.dnd.IDragAndDropService;
+import org.eclipse.ui.services.IDisposable;
+
+/**
+ * Implementation for the <code>IDragAndDropService</code> to be used from
+ * <code>EditorSite</code>'s.
+ * </p><p>
+ * Adds a drop target to the given control that merges the site's
+ * drop behaviour with that specified by the <code>addMergedDropTarget</code> call.
+ * </p><p>
+ * The current implementation is only defined for EditorSite's and merges the
+ * given drop handling with the existing EditorSashContainer's behaviour.
+ * </p><p>
+ * NOTE: There is no cleanup (i.e. 'dispose') handling necessary for merged
+ * Drop Targets but the hooks are put into place to maintain the consistency
+ * of the implementation pattern.
+ * </p>
+ * @since 3.3
+ *
+ */
+public class EditorSiteDragAndDropServiceImpl implements IDragAndDropService, IDisposable {
+	// Key used to store/retrieve the MergedDropTarget instance from the real DropTarget
+	private static String MDT_KEY = "MDT"; //$NON-NLS-1$
+
+	/**
+	 * Implementation of a DropTarget wrapper that will either delegate to the
+	 * <code>primaryListener</code> if the event's <code>currentDataType</code>
+	 * can be handled by it; otherwise the event is forwarded on to the
+	 * listener specified by <code>secondaryListener</code>.
+	 * </p><p>
+	 * NOTE: we should perhaps refactor this out into an external class
+	 * </p>
+	 * @since 3.3
+	 *
+	 */
+	private static class MergedDropTarget {
+		private DropTarget realDropTarget;
+
+		private Transfer[] secondaryTransfers;
+		private DropTargetListener secondaryListener;
+		private int secondaryOps;
+
+		private Transfer[] primaryTransfers;
+		private DropTargetListener primaryListener;
+		private int primaryOps;
+
+		public MergedDropTarget(Control control,
+				int priOps, Transfer[] priTransfers, DropTargetListener priListener,
+				int secOps, Transfer[] secTransfers, DropTargetListener secListener) {
+			realDropTarget = new DropTarget(control, priOps | secOps);
+			realDropTarget.setData(MDT_KEY, this);
+
+			// Cache the editor's transfers and listener
+			primaryTransfers = priTransfers;
+			primaryListener = priListener;
+			primaryOps = priOps;
+
+			// Cache the editor area's current transfers & listener
+	        secondaryTransfers = secTransfers;
+	        secondaryListener = secListener;
+	        secondaryOps = secOps;
+
+			// Combine the two sets of transfers into one array
+			Transfer[] allTransfers = new Transfer[secondaryTransfers.length+primaryTransfers.length];
+			int curTransfer = 0;
+			for (Transfer primaryTransfer : primaryTransfers) {
+				allTransfers[curTransfer++] = primaryTransfer;
+			}
+			for (Transfer secondaryTransfer : secondaryTransfers) {
+				allTransfers[curTransfer++] = secondaryTransfer;
+			}
+			realDropTarget.setTransfer(allTransfers);
+
+			// Create a listener that will delegate to the appropriate listener
+			// NOTE: the -editor- wins (i.e. it can over-ride WB behaviour if it wants
+			realDropTarget.addDropListener(new DropTargetListener() {
+				@Override
+				public void dragEnter(DropTargetEvent event) {
+					getAppropriateListener(event, true).dragEnter(event);
+				}
+				@Override
+				public void dragLeave(DropTargetEvent event) {
+					getAppropriateListener(event, false).dragLeave(event);
+				}
+				@Override
+				public void dragOperationChanged(DropTargetEvent event) {
+					getAppropriateListener(event, true).dragOperationChanged(event);
+				}
+				@Override
+				public void dragOver(DropTargetEvent event) {
+					getAppropriateListener(event, true).dragOver(event);
+				}
+				@Override
+				public void drop(DropTargetEvent event) {
+					getAppropriateListener(event, true).drop(event);
+				}
+				@Override
+				public void dropAccept(DropTargetEvent event) {
+					getAppropriateListener(event, true).dropAccept(event);
+				}
+			});
+		}
+
+		private DropTargetListener getAppropriateListener(DropTargetEvent event, boolean checkOperation) {
+			if (isSupportedType(primaryTransfers, event.currentDataType)) {
+				if (checkOperation && !isSupportedOperation(primaryOps, event.detail)) {
+					event.detail = DND.DROP_NONE;
+				}
+				return primaryListener;
+			}
+			if (checkOperation && !isSupportedOperation(secondaryOps, event.detail)) {
+				event.detail = DND.DROP_NONE;
+			}
+			return secondaryListener;
+		}
+
+		private boolean isSupportedType(Transfer[] transfers, TransferData transferType) {
+			for (Transfer transfer : transfers) {
+				if (transfer.isSupportedType(transferType))
+					return true;
+			}
+			return false;
+		}
+
+		private boolean isSupportedOperation(int dropOps, int eventDetail) {
+				return ((dropOps | DND.DROP_DEFAULT) & eventDetail) != 0;
+		}
+	}
+
+	// Cache any listeners for cleanup
+	List addedListeners = new ArrayList();
+
+	@Override
+	public void addMergedDropTarget(Control control, int ops, Transfer[] transfers,
+			DropTargetListener listener) {
+		 // First we have to remove any existing drop target from the control
+		removeMergedDropTarget(control);
+
+		// Capture the editor area's current ops, transfers & listener
+		int editorSiteOps = DND.DROP_DEFAULT | DND.DROP_COPY | DND.DROP_LINK;
+
+		WorkbenchWindow ww = (WorkbenchWindow) PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+        WorkbenchWindowConfigurer winConfigurer = ww.getWindowConfigurer();
+        Transfer[] editorSiteTransfers = winConfigurer.getTransfers();
+        DropTargetListener editorSiteListener = winConfigurer.getDropTargetListener();
+
+        // Create a new 'merged' drop Listener using combination of the desired
+        // transfers and the ones used by the EditorArea
+		MergedDropTarget newTarget = new MergedDropTarget(control, ops, transfers, listener,
+				editorSiteOps, editorSiteTransfers, editorSiteListener);
+		addedListeners.add(newTarget);
+
+		newTarget.realDropTarget.addDisposeListener(e -> {
+			Object mdt = e.widget.getData(MDT_KEY);
+			addedListeners.remove(mdt);
+		});
+	}
+
+	/**
+	 * This method will return the current drop target for the control
+	 * (whether or not it was created using this service.
+	 *
+	 * @param control The control to get the drop target for
+	 * @return The DropTarget for that control (could be null
+	 */
+	private DropTarget getCurrentDropTarget(Control control) {
+		if (control == null)
+			return null;
+
+		Object curDT = control.getData(DND.DROP_TARGET_KEY);
+		return (DropTarget)curDT;
+	}
+
+	@Override
+	public void removeMergedDropTarget(Control control) {
+		DropTarget targetForControl = getCurrentDropTarget(control);
+		if (targetForControl != null) {
+			targetForControl.dispose();
+			addedListeners.remove(targetForControl);
+		}
+	}
+
+	@Override
+	public void dispose() {
+		addedListeners.clear();
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ErrorEditorPart.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ErrorEditorPart.java
new file mode 100644
index 0000000..d510d23
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ErrorEditorPart.java
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.internal.part.StatusPart;
+import org.eclipse.ui.part.EditorPart;
+
+/**
+ * This part is shown instead the editors with errors.
+ *
+ * @since 3.3
+ */
+public class ErrorEditorPart extends EditorPart {
+
+	private IStatus error;
+	private Composite parentControl;
+
+	/**
+	 * Creates instance of the class
+	 */
+	public ErrorEditorPart() {
+	}
+
+	/**
+	 * Creates instance of the class
+	 *
+	 * @param error the status
+	 */
+	public ErrorEditorPart(IStatus error) {
+		this.error = error;
+	}
+
+	@Override
+	public void doSave(IProgressMonitor monitor) {
+	}
+
+	@Override
+	public void doSaveAs() {
+	}
+
+	@Override
+	public void createPartControl(Composite parent) {
+		this.parentControl = parent;
+		if (error != null) {
+			new StatusPart(parent, error);
+		}
+	}
+
+	@Override
+	public void init(IEditorSite site, IEditorInput input) {
+		setSite(site);
+		setInput(input);
+		setPartName(input.getName());
+	}
+
+	@Override
+	public boolean isDirty() {
+		return false;
+	}
+
+	@Override
+	public boolean isSaveAsAllowed() {
+		return false;
+	}
+
+	@Override
+	public void setFocus() {
+		parentControl.setFocus();
+	}
+
+	@Override
+	public void setPartName(String newName) {
+		super.setPartName(newName);
+	}
+
+	@Override
+	public void dispose() {
+		super.dispose();
+		parentControl = null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ErrorViewPart.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ErrorViewPart.java
new file mode 100644
index 0000000..bf323bc
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ErrorViewPart.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal;
+
+import org.eclipse.swt.widgets.Composite;
+
+import org.eclipse.core.runtime.IStatus;
+
+import org.eclipse.ui.internal.part.StatusPart;
+import org.eclipse.ui.part.ViewPart;
+
+/**
+ * This part is shown instead the views with errors.
+ *
+ * @since 3.3
+ */
+public class ErrorViewPart extends ViewPart {
+
+	private IStatus error;
+	private Composite parentControl;
+
+	/**
+	 * Creates instance of the class
+	 */
+	public ErrorViewPart() {
+	}
+
+	/**
+	 * Creates instance of the class
+	 *
+	 * @param error the status
+	 */
+	public ErrorViewPart(IStatus error) {
+		this.error = error;
+	}
+
+	@Override
+	public void createPartControl(Composite parent) {
+		parentControl = parent;
+		if (error != null) {
+			new StatusPart(parent, error);
+		}
+	}
+
+	@Override
+	public void setPartName(String newName) {
+		super.setPartName(newName);
+	}
+
+	@Override
+	public void setFocus() {
+		parentControl.setFocus();
+	}
+
+	@Override
+	public void dispose() {
+		super.dispose();
+		parentControl = null;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ExceptionHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ExceptionHandler.java
new file mode 100644
index 0000000..4910840
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ExceptionHandler.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.jface.window.Window;
+
+/**
+ * This handler will pass along to the workbench advisor exceptions
+ * and errors thrown while running the event loop. However, the
+ * <code>ThreadDeath</code> error is simply thrown again, and is not
+ * passed along.
+ */
+public final class ExceptionHandler implements Window.IExceptionHandler {
+
+    private static final ExceptionHandler instance = new ExceptionHandler();
+
+    /**
+     * Returns the singleton exception handler.
+     *
+     * @return the singleton exception handler
+     */
+    public static ExceptionHandler getInstance() {
+        return instance;
+    }
+
+    private int exceptionCount = 0; // To avoid recursive errors
+
+    private ExceptionHandler() {
+        // prevents instantiation
+    }
+
+    @Override
+	public void handleException(Throwable t) {
+        try {
+            // Ignore ThreadDeath error as its normal to get this when thread dies
+            if (t instanceof ThreadDeath) {
+                throw (ThreadDeath) t;
+            }
+
+            // Check to avoid recursive errors
+            exceptionCount++;
+            if (exceptionCount > 2) {
+                if (t instanceof RuntimeException) {
+					throw (RuntimeException) t;
+				} else if (t instanceof Error) {
+					throw (Error) t;
+				} else {
+					throw new RuntimeException(t);
+				}
+            }
+
+            // Let the advisor handle this now
+            Workbench wb = Workbench.getInstance();
+            if (wb != null) {
+                wb.getAdvisor().eventLoopException(t);
+            }
+        } finally {
+            exceptionCount--;
+        }
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ExtensionEventHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ExtensionEventHandler.java
new file mode 100644
index 0000000..ff7a569
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ExtensionEventHandler.java
@@ -0,0 +1,238 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionDelta;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IRegistryChangeEvent;
+import org.eclipse.core.runtime.IRegistryChangeListener;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.themes.ColorDefinition;
+import org.eclipse.ui.internal.themes.FontDefinition;
+//import org.eclipse.ui.internal.themes.ThemeElementHelper;
+import org.eclipse.ui.internal.themes.ThemeRegistry;
+import org.eclipse.ui.internal.themes.ThemeRegistryReader;
+import org.eclipse.ui.internal.util.PrefUtil;
+import org.eclipse.ui.themes.ITheme;
+import org.eclipse.ui.themes.IThemeManager;
+
+class ExtensionEventHandler implements IRegistryChangeListener {
+
+    private Workbench workbench;
+
+    private List changeList = new ArrayList(10);
+
+    public ExtensionEventHandler(Workbench workbench) {
+        this.workbench = workbench;
+    }
+
+    @Override
+	public void registryChanged(IRegistryChangeEvent event) {
+        try {
+            // RAP [bm]: replaced namespace
+            IExtensionDelta delta[] = event
+                    .getExtensionDeltas(PlatformUI.PLUGIN_EXTENSION_NAME_SPACE);
+            IExtension ext;
+            IExtensionPoint extPt;
+// RAP [rh] fix for bug 290920
+//            IWorkbenchWindow[] win = PlatformUI.getWorkbench()
+//                    .getWorkbenchWindows();
+            IWorkbenchWindow[] win = workbench.getWorkbenchWindows();
+// End of fix
+            if (win.length == 0) {
+				return;
+			}
+            Display display = win[0].getShell().getDisplay();
+            if (display == null) {
+				return;
+			}
+            ArrayList appearList = new ArrayList(5);
+            ArrayList revokeList = new ArrayList(5);
+            String id = null;
+            int numPerspectives = 0;
+            int numActionSetPartAssoc = 0;
+
+            // push action sets and perspectives to the top because incoming
+            // actionSetPartAssociations and perspectiveExtensions may depend upon
+            // them for their bindings.
+            for (IExtensionDelta extensionDelta : delta) {
+                id = extensionDelta.getExtensionPoint().getSimpleIdentifier();
+                if (extensionDelta.getKind() == IExtensionDelta.ADDED) {
+                    if (id.equals(IWorkbenchRegistryConstants.PL_ACTION_SETS)) {
+						appearList.add(0, extensionDelta);
+					} else if (!id.equals(IWorkbenchRegistryConstants.PL_PERSPECTIVES)
+                            && !id.equals(IWorkbenchRegistryConstants.PL_VIEWS)
+                            && !id.equals(IWorkbenchRegistryConstants.PL_ACTION_SETS)) {
+						appearList.add(appearList.size() - numPerspectives,
+                                extensionDelta);
+					}
+                } else {
+                    if (extensionDelta.getKind() == IExtensionDelta.REMOVED) {
+                        if (id
+                                .equals(IWorkbenchRegistryConstants.PL_ACTION_SET_PART_ASSOCIATIONS)) {
+                            revokeList.add(0, extensionDelta);
+                            numActionSetPartAssoc++;
+                        } else if (id
+                                .equals(IWorkbenchRegistryConstants.PL_PERSPECTIVES)) {
+							revokeList.add(numActionSetPartAssoc, extensionDelta);
+						} else {
+							revokeList.add(extensionDelta);
+						}
+                    }
+                }
+            }
+            Iterator iter = appearList.iterator();
+            IExtensionDelta extDelta = null;
+            while (iter.hasNext()) {
+                extDelta = (IExtensionDelta) iter.next();
+                extPt = extDelta.getExtensionPoint();
+                ext = extDelta.getExtension();
+                asyncAppear(display, extPt, ext);
+            }
+            // Suspend support for removing a plug-in until this is more stable
+            //		iter = revokeList.iterator();
+            //		while(iter.hasNext()) {
+            //			extDelta = (IExtensionDelta) iter.next();
+            //			extPt = extDelta.getExtensionPoint();
+            //			ext = extDelta.getExtension();
+            //			asyncRevoke(display, extPt, ext);
+            //		}
+
+            resetCurrentPerspective(display);
+        } finally {
+            //ensure the list is cleared for the next pass through
+            changeList.clear();
+        }
+
+    }
+
+    private void asyncAppear(Display display, final IExtensionPoint extpt,
+            final IExtension ext) {
+        Runnable run = () -> appear(extpt, ext);
+        display.syncExec(run);
+    }
+
+    private void appear(IExtensionPoint extPt, IExtension ext) {
+        String name = extPt.getSimpleIdentifier();
+        if (name.equalsIgnoreCase(IWorkbenchRegistryConstants.PL_FONT_DEFINITIONS)) {
+            loadFontDefinitions(ext);
+            return;
+        }
+        if (name.equalsIgnoreCase(IWorkbenchRegistryConstants.PL_THEMES)) {
+            loadThemes(ext);
+            return;
+        }
+    }
+
+    /**
+     * @param ext
+     */
+    private void loadFontDefinitions(IExtension ext) {
+        ThemeRegistryReader reader = new ThemeRegistryReader();
+        reader.setRegistry((ThemeRegistry) WorkbenchPlugin.getDefault()
+                .getThemeRegistry());
+		for (IConfigurationElement configElement : ext.getConfigurationElements()) {
+			reader.readElement(configElement);
+		}
+
+        Collection fonts = reader.getFontDefinitions();
+        FontDefinition[] fontDefs = (FontDefinition[]) fonts
+                .toArray(new FontDefinition[fonts.size()]);
+        // RAP
+//        ThemeElementHelper.populateRegistry(workbench.getThemeManager()
+//				.getTheme(IThemeManager.DEFAULT_THEME), fontDefs, PrefUtil
+//				.getInternalPreferenceStore());
+    }
+
+    //TODO: confirm
+    private void loadThemes(IExtension ext) {
+        ThemeRegistryReader reader = new ThemeRegistryReader();
+        ThemeRegistry registry = (ThemeRegistry) WorkbenchPlugin.getDefault()
+                .getThemeRegistry();
+        reader.setRegistry(registry);
+		for (IConfigurationElement configElement : ext.getConfigurationElements()) {
+			reader.readElement(configElement);
+		}
+
+        Collection colors = reader.getColorDefinitions();
+        ColorDefinition[] colorDefs = (ColorDefinition[]) colors
+                .toArray(new ColorDefinition[colors.size()]);
+
+        ITheme theme = workbench.getThemeManager().getTheme(
+                IThemeManager.DEFAULT_THEME);
+        // RAP
+//        ThemeElementHelper.populateRegistry(theme, colorDefs, PrefUtil
+//				.getInternalPreferenceStore());
+//
+//        Collection fonts = reader.getFontDefinitions();
+//        FontDefinition[] fontDefs = (FontDefinition[]) fonts
+//                .toArray(new FontDefinition[fonts.size()]);
+//        ThemeElementHelper.populateRegistry(theme, fontDefs, PrefUtil
+//				.getInternalPreferenceStore());
+
+        Map data = reader.getData();
+        registry.addData(data);
+    }
+
+    private void resetCurrentPerspective(Display display) {
+        if (changeList.isEmpty()) {
+			return;
+		}
+
+        final StringBuffer message = new StringBuffer(
+                ExtensionEventHandlerMessages.ExtensionEventHandler_following_changes);
+
+        for (Iterator i = changeList.iterator(); i.hasNext();) {
+            message.append(i.next());
+        }
+
+        message.append(ExtensionEventHandlerMessages.ExtensionEventHandler_need_to_reset);
+
+        display.asyncExec(() -> {
+		    Shell parentShell = null;
+		    IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
+		    if (window == null) {
+		        if (workbench.getWorkbenchWindowCount() == 0) {
+					return;
+				}
+		        window = workbench.getWorkbenchWindows()[0];
+		    }
+
+		    parentShell = window.getShell();
+
+		    if (MessageDialog
+		            .openQuestion(
+		                    parentShell,
+		                    ExtensionEventHandlerMessages.ExtensionEventHandler_reset_perspective, message.toString())) {
+		        IWorkbenchPage page = window.getActivePage();
+		        if (page == null) {
+					return;
+				}
+		        page.resetPerspective();
+		    }
+		});
+
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ExtensionEventHandler.properties b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ExtensionEventHandler.properties
new file mode 100644
index 0000000..6b4aefc
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ExtensionEventHandler.properties
@@ -0,0 +1,16 @@
+###############################################################################
+# Copyright (c) 2003, 2013 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
+###############################################################################
+ExtensionEventHandler_new_action_set=action set(s).
+ExtensionEventHandler_following_changes=The following changes have been detected:\n\n
+ExtensionEventHandler_change_format=  * {0} has contributed {1}\n
+ExtensionEventHandler_need_to_reset=\nYou will need to reset your perspectives in order for these changes to be recognized.  Would you like to reset your current perspective?
+ExtensionEventHandler_reset_perspective=Reset Perspective?
+
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ExtensionEventHandlerMessages.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ExtensionEventHandlerMessages.java
new file mode 100644
index 0000000..e37c741
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ExtensionEventHandlerMessages.java
@@ -0,0 +1,37 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2015 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 - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.ui.internal;
+
+import org.eclipse.osgi.util.NLS;
+
+public class ExtensionEventHandlerMessages extends NLS {
+	private static final String BUNDLE_NAME = "org.eclipse.ui.internal.ExtensionEventHandler";//$NON-NLS-1$
+	//
+	// Copyright (c) 2003, 2004 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
+	//
+	public static String ExtensionEventHandler_new_action_set;
+	public static String ExtensionEventHandler_following_changes;
+	public static String ExtensionEventHandler_change_format;
+	public static String ExtensionEventHandler_need_to_reset;
+	public static String ExtensionEventHandler_reset_perspective;
+
+
+	static {
+		// load message values from bundle file
+		NLS.initializeMessages(BUNDLE_NAME, ExtensionEventHandlerMessages.class);
+	}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/FaderAnimationFeedback.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/FaderAnimationFeedback.java
new file mode 100644
index 0000000..fa35685
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/FaderAnimationFeedback.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal;
+
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * Creates an animation effect where the Shell's image is captured and
+ * over-lain (in its own shell) on top of the real one. This image
+ * masks the changes to the 'real' shell and then the covering image
+ * fades to transparent, revealing the new state.
+ *
+ * This provides a nice cross-fade effect for operations like a
+ * perspective change (where the overall effect on the shell is large.
+ *
+ * @since 3.3
+ *
+ */
+public class FaderAnimationFeedback extends	AnimationFeedbackBase {
+	private Image backingStore;
+
+	public FaderAnimationFeedback(Shell parentShell) {
+		super(parentShell);
+	}
+
+	@Override
+	public void dispose() {
+		super.dispose();
+
+		if (!backingStore.isDisposed())
+			backingStore.dispose();
+	}
+
+	@Override
+	public void initialize(AnimationEngine engine) {
+		Rectangle psRect = getBaseShell().getBounds();
+		getAnimationShell().setBounds(psRect);
+
+		// Capture the background image
+		Display display = getBaseShell().getDisplay();
+		backingStore = new Image(display, psRect.width, psRect.height);
+		GC gc = new GC(display);
+		// gc.copyArea(backingStore, psRect.x, psRect.y);
+		
+		// RAP
+//		gc.copyArea(backingStore, psRect.x, psRect.y);
+		gc.dispose();
+
+		getAnimationShell().setAlpha(254);
+		getAnimationShell().setBackgroundImage(backingStore);
+		getAnimationShell().setVisible(true);
+	}
+
+	@Override
+	public void renderStep(AnimationEngine engine) {
+		getAnimationShell().setAlpha((int) (255 - (engine.amount()*255)));
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/FilteredTableBaseHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/FilteredTableBaseHandler.java
new file mode 100644
index 0000000..9981d6d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/FilteredTableBaseHandler.java
@@ -0,0 +1,956 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Patrik Suzzi 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:
+ *     Patrik Suzzi <psuzzi@gmail.com> - Bug 368977, 504088, 504089, 504090, 504091, 509232, 506019
+ ******************************************************************************/
+
+package org.eclipse.ui.internal;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExecutableExtension;
+import org.eclipse.e4.ui.internal.workbench.renderers.swt.AbstractTableInformationControl;
+import org.eclipse.e4.ui.model.application.ui.basic.MStackElement;
+import org.eclipse.e4.ui.workbench.modeling.EPartService;
+import org.eclipse.e4.ui.workbench.modeling.EPartService.PartState;
+import org.eclipse.jface.bindings.Trigger;
+import org.eclipse.jface.bindings.TriggerSequence;
+import org.eclipse.jface.bindings.keys.KeyStroke;
+import org.eclipse.jface.bindings.keys.SWTKeySupport;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusAdapter;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.MouseMoveListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IEditorReference;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartReference;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.contexts.IContextService;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.eclipse.ui.keys.IBindingService;
+import org.eclipse.ui.model.PerspectiveLabelProvider;
+
+/**
+ * Base class to open a dialog to filter and select elements of a {@link Table}.
+ *
+ * @see AbstractTableInformationControl and CycleBaseHandler
+ * @since 4.6.2
+ *
+ */
+
+public abstract class FilteredTableBaseHandler extends AbstractHandler implements
+		IExecutableExtension {
+
+	private static final String EMPTY_STRING = ""; //$NON-NLS-1$
+
+	private boolean bypassFocusLost;
+
+	private Object selection;
+
+	protected IWorkbenchWindow window;
+
+	protected WorkbenchPage page;
+
+	// true to go to next and false to go to previous part
+	protected boolean gotoDirection;
+
+	/**
+	 * The list of key bindings for the backward command when it is open. This
+	 * value is <code>null</code> if the dialog is not open.
+	 */
+	private TriggerSequence[] backwardTriggerSequences = null;
+
+	protected ParameterizedCommand commandBackward = null;
+
+	protected ParameterizedCommand commandForward = null;
+	/**
+	 * The list of key bindings for the forward command when it is open. This
+	 * value is <code>null</code> if the dialog is not open.
+	 */
+	private TriggerSequence[] forwardTriggerSequences = null;
+
+
+	/**
+	 * Get the index of the current item (not valid if there are no items).
+	 */
+	protected int getCurrentItemIndex() {
+		return 0;
+	}
+
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		window = HandlerUtil.getActiveWorkbenchWindowChecked(event);
+		page = (WorkbenchPage) window.getActivePage();
+		IWorkbenchPart activePart= page.getActivePart();
+		getTriggers();
+		openDialog(page, activePart);
+		clearTriggers();
+		activate(page, selection);
+
+		return null;
+	}
+
+	protected Object result;
+	protected Shell dialog;
+	private Text text;
+	private Label labelTitle = null;
+	private Label labelSeparator;
+	private Table table;
+	private TableViewer tableViewer;
+	private TableColumn tc;
+	private TableViewerColumn tableViewerColumn;
+
+	/*
+	 * Open a dialog showing all views in the activation order
+	 */
+	public void openDialog(WorkbenchPage page, IWorkbenchPart activePart) {
+		final int MAX_ITEMS = 15;
+		Shell shell = null;
+		selection = null;
+
+		if (activePart != null)
+			shell = activePart.getSite().getShell();
+		if (shell == null)
+			shell = window.getShell();
+		dialog = new Shell(shell, SWT.MODELESS);
+		dialog.setBackground(getBackground());
+		dialog.setMinimumSize(new Point(120, 50));
+		Display display = dialog.getDisplay();
+		dialog.setLayout(new FillLayout());
+
+		Composite composite = new Composite(dialog, SWT.NONE);
+		composite.setBackground(getBackground());
+		GridLayout gl_composite = new GridLayout(1, false);
+		composite.setLayout(gl_composite);
+
+		if (isFiltered()) {
+			text = new Text(composite, SWT.NONE);
+			text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1));
+			text.setBackground(getBackground());
+		} else {
+			/*
+			 * For issues with dark theme, don't use
+			 * table.setHeaderVisible(true); and table.setLinesVisible(true);
+			 * see: https://bugs.eclipse.org/bugs/attachment.cgi?id=264527
+			 */
+			labelTitle = new Label(composite, SWT.NONE);
+			labelTitle.setText(getTableHeader(activePart));
+			labelTitle.setBackground(getBackground());
+			labelTitle.setForeground(getForeground());
+		}
+
+		/* for issues with dark theme, don't use SWT.SEPARATOR as style */
+		labelSeparator = new Label(composite, SWT.HORIZONTAL);
+		labelSeparator.setBackgroundImage(getSeparatorBgImage());
+		GridData gd_label = new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1);
+		gd_label.heightHint = 1;
+		labelSeparator.setLayoutData(gd_label);
+
+		tableViewer = new TableViewer(composite, SWT.SINGLE | SWT.FULL_SELECTION);
+		table = tableViewer.getTable();
+		table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
+		table.setBackground(getBackground());
+
+		tableViewerColumn = new TableViewerColumn(tableViewer, SWT.NONE);
+		setLabelProvider(tableViewerColumn);
+		tc = tableViewerColumn.getColumn();
+		tc.setResizable(false);
+
+		tableViewer.setContentProvider(ArrayContentProvider.getInstance());
+
+		if (isFiltered()) {
+			tableViewer.addFilter(getFilter());
+			addModifyListener(text);
+			addKeyListener(text);
+			text.setMessage(WorkbenchMessages.FilteredTableBase_Filter);
+			text.setText(EMPTY_STRING);
+		}
+
+		// gets the input from the concrete subclass
+		tableViewer.setInput(getInput(page));
+
+		int tableItemCount = table.getItemCount();
+
+		switch (tableItemCount) {
+		case 0:
+			cancel(dialog);
+			return;
+		case 1:
+			table.setSelection(0);
+			break;
+		default:
+			int i;
+			int currentItemIndex = getCurrentItemIndex();
+			if (gotoDirection) {
+				i= currentItemIndex + 1;
+				if (i >= tableItemCount) {
+					i = 0;
+				}
+			} else {
+				i= currentItemIndex - 1;
+				if (i < 0) {
+					i = tableItemCount - 1;
+				}
+			}
+			table.setSelection(i);
+		}
+
+		tc.pack();
+		table.pack();
+		dialog.pack();
+
+		Rectangle tableBounds = table.getBounds();
+		tableBounds.height = Math.min(tableBounds.height, table.getItemHeight() * MAX_ITEMS);
+		table.setBounds(tableBounds);
+
+		Rectangle dialogBounds = dialog.getBounds();
+		if (!isFiltered()) {
+			dialogBounds.height = labelTitle.getBounds().height + labelSeparator.getBounds().height + tableBounds.height
+					+ gl_composite.marginHeight * 2 + gl_composite.verticalSpacing * 2;
+		} else {
+			dialogBounds.height = text.getBounds().height + +labelSeparator.getBounds().height + tableBounds.height
+					+ gl_composite.marginHeight * 2 + gl_composite.verticalSpacing * 2;
+		}
+		dialog.setBounds(dialogBounds);
+		tc.setWidth(table.getClientArea().width);
+
+		if (isFiltered()) {
+			text.setFocus();
+			text.addFocusListener(fAdapter);
+		} else {
+			table.setFocus();
+		}
+		table.addFocusListener(fAdapter);
+		dialog.addFocusListener(fAdapter);
+
+		// RAP [DM] No mouse move listener
+//		table.addMouseMoveListener(new MouseMoveListener() {
+//			TableItem fLastItem = null;
+//
+//			@Override
+//			public void mouseMove(MouseEvent e) {
+//				if (table.equals(e.getSource())) {
+//					Object o = table.getItem(new Point(e.x, e.y));
+//					if (fLastItem == null ^ o == null) {
+//						table.setCursor(o == null ? null : table.getDisplay().getSystemCursor(
+//								SWT.CURSOR_HAND));
+//					}
+//					if (o instanceof TableItem) {
+//						if (!o.equals(fLastItem)) {
+//							fLastItem = (TableItem) o;
+//							table.setSelection(new TableItem[] { fLastItem });
+//						}
+//					} else if (o == null) {
+//						fLastItem = null;
+//					}
+//				}
+//			}
+//		});
+
+		setDialogLocation(dialog, activePart);
+
+		final IContextService contextService = window
+				.getWorkbench().getService(IContextService.class);
+		try {
+			dialog.open();
+			addMouseListener(table, dialog);
+			contextService.registerShell(dialog, IContextService.TYPE_NONE);
+			addKeyListener(table, dialog);
+			addTraverseListener(table);
+
+			while (!dialog.isDisposed()) {
+				if (!display.readAndDispatch()) {
+					display.sleep();
+				}
+			}
+		} finally {
+			if (!dialog.isDisposed()) {
+				cancel(dialog);
+			}
+			contextService.unregisterShell(dialog);
+		}
+	}
+
+	/**
+	 * Build a 1x1 px gray image to be used as separator. This color, halfway
+	 * between white and black, looks good both in Classic and in Dark Theme
+	 */
+	private Image getSeparatorBgImage() {
+		Image backgroundImage = new Image(Display.getDefault(), 1, 1);
+		// RAP [DM] RAP
+//		GC gc = new GC(backgroundImage);
+		GC gc = new GC(backgroundImage.getDevice());
+		gc.setBackground(new Color(dialog.getDisplay(), 127, 127, 127));
+		gc.fillRectangle(0, 0, 1, 1);
+		gc.dispose();
+		return backgroundImage;
+	}
+
+	/**
+	 * {@link FocusListener} for active controls. When the focus event is
+	 * complete, the listener check if focus is still on one of the active
+	 * components. If not, closes the dialog.
+	 *
+	 */
+	private FocusAdapter fAdapter = new FocusAdapter() {
+		@Override
+		public void focusLost(FocusEvent e) {
+			dialog.getDisplay().asyncExec(() -> {
+				// once event complete, if dialog still open..
+				if (dialog.isDisposed()) {
+					return;
+				}
+				// check if the focus is still in dialog elements
+				Control fc = dialog.getDisplay().getFocusControl();
+				if (fc != text && fc != table && fc != dialog && !bypassFocusLost) {
+					// otherwise, close
+					cancel(dialog);
+				}
+			});
+		}
+	};
+
+	/**
+	 * Sets the dialog's location on the screen.
+	 *
+	 * @param dialog
+	 */
+	protected void setDialogLocation(final Shell dialog, IWorkbenchPart activePart) {
+		Display display = dialog.getDisplay();
+		Rectangle dialogBounds = dialog.getBounds();
+		Rectangle parentBounds = dialog.getParent().getBounds();
+
+		// the bounds of the monitor that contains the currently active part.
+		Rectangle monitorBounds = activePart == null ? display.getPrimaryMonitor().getBounds()
+				: ((Control) ((PartSite) activePart.getSite()).getModel().getWidget()).getMonitor().getBounds();
+
+		// Place it in the center of its parent;
+		dialogBounds.x = parentBounds.x
+				+ ((parentBounds.width - dialogBounds.width) / 2);
+		dialogBounds.y = parentBounds.y
+				+ ((parentBounds.height - dialogBounds.height) / 2);
+		if (!monitorBounds.contains(dialogBounds.x, dialogBounds.y)
+				|| !monitorBounds.contains(dialogBounds.x + dialogBounds.width,
+						dialogBounds.y + dialogBounds.height)) {
+			// Place it in the center of the monitor if it is not visible
+			// when placed in the center of its parent.
+			// Ensure the origin is visible on the screen.
+			dialogBounds.x = Math.max(0,
+					monitorBounds.x + (monitorBounds.width - dialogBounds.width) / 2);
+			dialogBounds.y =  Math.max(0,
+					monitorBounds.y + (monitorBounds.height - dialogBounds.height) / 2);
+		}
+
+		dialog.setLocation(dialogBounds.x, dialogBounds.y);
+	}
+
+	/**
+	 * Clears the forward and backward trigger sequences.
+	 */
+	protected void clearTriggers() {
+		forwardTriggerSequences = null;
+		backwardTriggerSequences = null;
+	}
+
+	/**
+	 * Fetch the key bindings for the forward and backward commands. They will
+	 * not change while the dialog is open, but the context will. Bug 55581.
+	 */
+	protected void getTriggers() {
+		commandForward = getForwardCommand();
+		commandBackward = getBackwardCommand();
+
+		final IBindingService bindingService = window
+				.getWorkbench().getService(IBindingService.class);
+		forwardTriggerSequences = bindingService
+				.getActiveBindingsFor(commandForward);
+		backwardTriggerSequences = bindingService
+				.getActiveBindingsFor(commandBackward);
+	}
+
+	private KeyStroke computeKeyStroke(KeyEvent e) {
+		int accelerator = SWTKeySupport.convertEventToUnmodifiedAccelerator(e);
+		return SWTKeySupport.convertAcceleratorToKeyStroke(accelerator);
+	}
+
+	boolean computeAcceleratorForward(KeyEvent e) {
+		boolean acceleratorForward = false;
+		if (commandForward != null) {
+			if (forwardTriggerSequences != null) {
+				final int forwardCount = forwardTriggerSequences.length;
+				for (int i = 0; i < forwardCount; i++) {
+					final TriggerSequence triggerSequence = forwardTriggerSequences[i];
+
+					// Compare the last key stroke of the binding.
+					final Trigger[] triggers = triggerSequence.getTriggers();
+					final int triggersLength = triggers.length;
+					if ((triggersLength > 0) && (triggers[triggersLength - 1].equals(computeKeyStroke(e)))) {
+						acceleratorForward = true;
+						break;
+					}
+				}
+			}
+		}
+		return acceleratorForward;
+	}
+
+	boolean computeAcceleratorBackward(KeyEvent e) {
+		boolean acceleratorBackward = false;
+		if (commandBackward != null) {
+			if (backwardTriggerSequences != null) {
+				final int backwardCount = backwardTriggerSequences.length;
+				for (int i = 0; i < backwardCount; i++) {
+					final TriggerSequence triggerSequence = backwardTriggerSequences[i];
+
+					// Compare the last key stroke of the binding.
+					final Trigger[] triggers = triggerSequence.getTriggers();
+					final int triggersLength = triggers.length;
+					if ((triggersLength > 0) && (triggers[triggersLength - 1].equals(computeKeyStroke(e)))) {
+						acceleratorBackward = true;
+						break;
+					}
+				}
+			}
+		}
+		return acceleratorBackward;
+	}
+
+	/**
+	 * Add modify listener to the search text, trigger search each time text
+	 * changes. After the search the first matching result is selected. 
+	 */
+	protected void addModifyListener(Text text) {
+		text.addModifyListener(e -> {
+			String searchText = ((Text) e.widget).getText();
+			setMatcherString(searchText);
+			tableViewer.refresh();
+			if (tableViewer.getTable().getColumnCount() > 0) {
+				tableViewer.getTable().select(0);
+			}
+		});
+	}
+
+	/** Add Key Listener to the search text. manage key events on search text */
+	protected void addKeyListener(Text text) {
+		text.addKeyListener(new KeyListener() {
+			@Override
+			public void keyPressed(KeyEvent e) {
+				if (computeAcceleratorForward(e)) {
+					moveForward();
+				} else if (computeAcceleratorBackward(e)) {
+					moveBackward();
+				}
+				switch (e.keyCode) {
+				case SWT.CR:
+				case SWT.KEYPAD_CR:
+					ok(dialog, table);
+					break;
+				case SWT.PAGE_DOWN:
+				case SWT.ARROW_DOWN:
+					moveForward();
+					break;
+				case SWT.PAGE_UP:
+				case SWT.ARROW_UP:
+					moveBackward();
+					break;
+				case SWT.ESC:
+					cancel(dialog);
+					break;
+				case SWT.DEL:
+					// no filter text, closes selected item
+					if (text.getText().length() == 0) {
+						deleteSelectedItem();
+					}
+					break;
+				}
+			}
+
+			@Override
+			public void keyReleased(KeyEvent e) {
+				// do nothing
+			}
+		});
+	}
+
+	protected Color getForeground(){
+		return dialog.getDisplay().getSystemColor(SWT.COLOR_LIST_FOREGROUND);
+	}
+	protected Color getBackground() {
+		return dialog.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND);
+	}
+
+	/**
+	 * User can type these characters while navigating the table.
+	 */
+	private static String RE_TEXT = "[ \\w\\d_\\-\\+\\.\\*\\?\\$\\|\\(\\)\\[\\]\\{\\}@#]"; //$NON-NLS-1$
+
+	/**
+	 * Add Keylistener to the table, user actions can influence the dialog.
+	 */
+	protected void addKeyListener(final Table table, final Shell dialog) {
+		table.addKeyListener(new KeyListener() {
+			private boolean firstKey = true;
+
+			private boolean quickReleaseMode = false;
+
+			@Override
+			public void keyPressed(KeyEvent e) {
+				int keyCode = e.keyCode;
+				char character = e.character;
+
+				boolean acceleratorForward = computeAcceleratorForward(e);
+				boolean acceleratorBackward = computeAcceleratorBackward(e);
+
+				if (character == SWT.CR || character == SWT.LF) {
+					ok(dialog, table);
+				} else if (acceleratorForward) {
+					if (firstKey && e.stateMask != 0) {
+						quickReleaseMode = true;
+					}
+
+					moveForward();
+				} else if (acceleratorBackward) {
+					if (firstKey && e.stateMask != 0) {
+						quickReleaseMode = true;
+					}
+
+					moveBackward();
+				} else if (keyCode == SWT.DEL && isFiltered()) {
+					e.doit = false;
+					deleteSelectedItem();
+				} else if (keyCode != SWT.ALT && keyCode != SWT.COMMAND
+						&& keyCode != SWT.CTRL && keyCode != SWT.SHIFT
+						&& keyCode != SWT.ARROW_DOWN && keyCode != SWT.ARROW_UP
+						&& keyCode != SWT.PAGE_DOWN && keyCode != SWT.PAGE_UP
+						&& keyCode != SWT.ARROW_LEFT
+						&& keyCode != SWT.ARROW_RIGHT) {
+					if (!isFiltered()) {
+						cancel(dialog);
+					} else {
+						String s = Character.toString(e.character);
+						if (e.keyCode == SWT.BS) {
+							// backspace remove last char from text
+							String curText = text.getText();
+							if (curText.length() > 0) {
+								text.setText(curText.substring(0, curText.length() - 1));
+							}
+						} else if (s.matches(RE_TEXT)) {
+							// alphanumeric, add to text
+							text.append(Character.toString(e.character));
+						}
+						else {
+							cancel(dialog);
+						}
+					}
+				} else if ((keyCode == SWT.ARROW_DOWN || keyCode == SWT.PAGE_DOWN)
+						&& table.getSelectionIndex() == table.getItemCount() - 1) {
+					/** DOWN is managed by table, except when "rotating" */
+					moveForward();
+					e.doit = false;
+				} else if ((keyCode == SWT.ARROW_UP || keyCode == SWT.PAGE_UP) && table.getSelectionIndex() == 0) {
+					/** UP is managed by table, except when "rotating" */
+					moveBackward();
+					e.doit = false;
+				}
+
+				firstKey = false;
+			}
+
+			@Override
+			public void keyReleased(KeyEvent e) {
+				int keyCode = e.keyCode;
+				int stateMask = e.stateMask;
+
+				final IPreferenceStore store = WorkbenchPlugin.getDefault()
+						.getPreferenceStore();
+				final boolean stickyCycle = store
+						.getBoolean(IPreferenceConstants.STICKY_CYCLE);
+				if (!isFiltered() && (!stickyCycle && (firstKey || quickReleaseMode))
+						&& keyCode == stateMask) {
+					ok(dialog, table);
+				}
+			}
+		});
+	}
+
+	/**
+	 * Move to the next element, usually triggered by command, or arrow down
+	 */
+	private void moveForward() {
+		int index = table.getSelectionIndex();
+		if (isFiltered()) {
+			if (text.isFocusControl()) {
+				table.setFocus();
+			} else if (index == table.getItemCount() - 1) {
+				text.setFocus();
+				return;
+			}
+		}
+
+		// always set +1%count, unless text gets focus
+		table.setSelection((index + 1) % table.getItemCount());
+
+	}
+
+	/**
+	 * Move to the previous element, usually triggered by command or arrow up
+	 */
+	private void moveBackward() {
+		int index = table.getSelectionIndex();
+		if (!isFiltered()) {
+			table.setSelection(index >= 1 ? index - 1 : table.getItemCount() - 1);
+		} else {
+			if (text.isFocusControl()) {
+				table.setFocus();
+				table.setSelection(index >= 1 ? index - 1 : table.getItemCount() - 1);
+			} else if (index == 0) {
+				text.setFocus();
+			} else {
+				table.setSelection(index >= 1 ? index - 1 : table.getItemCount() - 1);
+			}
+		}
+	}
+
+	/** deletes the currently selected item */
+	private void deleteSelectedItem() {
+		int index = table.getSelectionIndex();
+		if (index == -1 || index >= table.getItemCount()) {
+			return;
+		}
+		TableItem item = table.getItem(index);
+		close(item);
+	}
+
+	/** closes the given item */
+	private void close(TableItem ti) {
+		// currently works for editors only (Ctrl+E)
+		if (ti.getData() instanceof EditorReference) {
+			int index = table.indexOf(ti);
+			EditorReference ed = (EditorReference) ti.getData();
+			bypassFocusLost = true;
+			page.closeEditors(new IEditorReference[] { ed }, true);
+			bypassFocusLost = false;
+			// reset focus when closing active editor
+			table.setFocus();
+			tableViewer.setInput(getInput(page));
+
+			if (table.getItemCount() == 0) {
+				cancel(dialog);
+			}
+
+			if (table.isDisposed()) {
+				return;
+			}
+
+			if (index > 0 && index <= table.getItemCount()) {
+				index -= 1;
+			}
+			table.setSelection(index);
+		}
+	}
+
+	/**
+	 * Adds a listener to the given table that blocks all traversal operations.
+	 *
+	 * @param table
+	 *            The table to which the traversal suppression should be added;
+	 *            must not be <code>null</code>.
+	 */
+	protected final void addTraverseListener(final Table table) {
+		table.addTraverseListener(event -> event.doit = false);
+	}
+
+	/**
+	 * Activate the selected item.
+	 *
+	 * @param page
+	 *            the page
+	 * @param selectedItem
+	 *            the selected item
+	 */
+	protected void activate(IWorkbenchPage page, Object selectedItem) {
+		if (selectedItem != null) {
+			if (selectedItem instanceof MStackElement) {
+				EPartService partService = page.getWorkbenchWindow().getService(EPartService.class);
+				partService.showPart(((MStackElement) selectedItem).getElementId(), PartState.ACTIVATE);
+
+				// the if conditions below do not need to be checked then
+				return;
+			}
+			if (selectedItem instanceof IEditorReference) {
+				page.setEditorAreaVisible(true);
+			}
+			if (selectedItem instanceof IWorkbenchPartReference) {
+				IWorkbenchPart part = ((IWorkbenchPartReference) selectedItem)
+						.getPart(true);
+				if (part != null) {
+					page.activate(part);
+				}
+				// the if conditions below do not need to be checked then
+				return;
+			}
+			if (selectedItem instanceof IPerspectiveDescriptor){
+	            IPerspectiveDescriptor persp = (IPerspectiveDescriptor) selectedItem;
+	            page.setPerspective(persp);
+				IWorkbenchPart activePart = page.getActivePart();
+				if (activePart != null) {
+					activePart.setFocus();
+				}
+			}
+		}
+	}
+
+	/**
+	 * Close the dialog and set selection to null.
+	 */
+	protected void cancel(Shell dialog) {
+		selection = null;
+		dialog.close();
+	}
+
+	/**
+	 * Close the dialog saving the selection
+	 */
+	protected void ok(Shell dialog, final Table table) {
+		TableItem[] items = table.getSelection();
+
+		if (items != null && items.length == 1) {
+			selection = items[0].getData();
+		}
+
+		dialog.close();
+	}
+
+	/**
+	 * Add mouse listener to the table closing it when the mouse is pressed.
+	 */
+	protected void addMouseListener(final Table table, final Shell dialog) {
+		table.addMouseListener(new MouseListener() {
+			@Override
+			public void mouseDoubleClick(MouseEvent e) {
+				ok(dialog, table);
+			}
+
+			@Override
+			public void mouseDown(MouseEvent e) {
+				if (e.button == 3) {
+					// right click, nop
+				} else {
+					ok(dialog, table);
+				}
+			}
+
+			@Override
+			public void mouseUp(MouseEvent e) {
+				if (e.button == 3) {
+					if (table.equals(e.getSource())) {
+						TableItem ti = table.getItem(new Point(e.x, e.y));
+						if (ti != null && ti.getData() instanceof EditorReference) {
+							Menu menu = new Menu(table);
+							MenuItem mi = new MenuItem(menu, SWT.NONE);
+							mi.setText(WorkbenchMessages.get().FilteredTableBaseHandler_Close);
+							mi.addListener(SWT.Selection, se -> close(ti));
+							menu.setVisible(true);
+						}
+					}
+				} else {
+					ok(dialog, table);
+				}
+			}
+		});
+	}
+
+	/** True to show search text and enable filtering. False by default */
+	protected boolean isFiltered() {
+		return false;
+	}
+
+	/** Return the filter to use. Null by default */
+	protected ViewerFilter getFilter() {
+		return null;
+	}
+
+	/** Set the filter text entered by the User, does nothing by default */
+	protected void setMatcherString(String pattern) {
+	}
+
+	private PerspectiveLabelProvider perspectiveLabelProvider = null;
+
+	private PerspectiveLabelProvider getPerspectiveLabelProvider() {
+		if (perspectiveLabelProvider == null) {
+			perspectiveLabelProvider = new PerspectiveLabelProvider(false);
+		}
+		return perspectiveLabelProvider;
+	}
+
+	/** Returns the text for the given {@link WorkbenchPartReference} */
+	protected String getWorkbenchPartReferenceText(WorkbenchPartReference ref) {
+		if (ref.isDirty()) {
+			return "*" + ref.getTitle(); //$NON-NLS-1$
+		}
+		return ref.getTitle();
+	}
+
+	/**
+	 * Sets the label provider for the only column visible in the table.
+	 * Subclasses can override this method to style the table, using a
+	 * StyledCellLabelProvider.
+	 *
+	 * @param tableViewerColumn
+	 * @return
+	 */
+	protected void setLabelProvider(TableViewerColumn tableViewerColumn) {
+		tableViewerColumn.setLabelProvider(getColumnLabelProvider());
+	}
+
+	/** Default ColumnLabelProvider. The table has only one column */
+	protected ColumnLabelProvider getColumnLabelProvider() {
+		return new ColumnLabelProvider() {
+			@Override
+			public String getText(Object element) {
+				if (element instanceof FilteredTableItem) {
+					return ((FilteredTableItem) element).text;
+				} else if (element instanceof WorkbenchPartReference) {
+					return getWorkbenchPartReferenceText((WorkbenchPartReference) element);
+				} else if (element instanceof IPerspectiveDescriptor) {
+					IPerspectiveDescriptor desc = (IPerspectiveDescriptor) element;
+					String text = getPerspectiveLabelProvider().getText(desc);
+					return (text == null) ? "" : text; //$NON-NLS-1$
+				}
+				return super.getText(element);
+			}
+
+			@Override
+			public Image getImage(Object element) {
+				if (element instanceof FilteredTableItem) {
+					return ((FilteredTableItem) element).image;
+				} else if (element instanceof WorkbenchPartReference) {
+					return ((WorkbenchPartReference) element).getTitleImage();
+				} else if (element instanceof IPerspectiveDescriptor) {
+					IPerspectiveDescriptor desc = (IPerspectiveDescriptor) element;
+					return getPerspectiveLabelProvider().getImage(desc);
+				}
+				return super.getImage(element);
+			}
+
+			@Override
+			public String getToolTipText(Object element) {
+				if (element instanceof FilteredTableItem) {
+					return ((FilteredTableItem) element).tooltipText;
+				} else if (element instanceof WorkbenchPartReference) {
+					return ((WorkbenchPartReference) element).getTitleToolTip();
+				}
+				return super.getToolTipText(element);
+			};
+		};
+	}
+
+	/** Add all items to the dialog in the activation order */
+	protected abstract Object getInput(WorkbenchPage page);
+
+	/** Get the backward command. */
+	protected abstract ParameterizedCommand getBackwardCommand();
+
+	/** Get the forward command. */
+	protected abstract ParameterizedCommand getForwardCommand();
+
+	/**
+	 * Get TableHeader, return title for non-filtered lists. By default returns
+	 * an empty String. Subclasses can use the active part to detect the type of
+	 * object.
+	 */
+	protected String getTableHeader(IWorkbenchPart activePart) {
+		return EMPTY_STRING;
+	}
+
+	public Object getSelection() {
+		return selection;
+	}
+
+	public IWorkbenchWindow getWindow() {
+		return window;
+	}
+
+	public TriggerSequence[] getBackwardTriggerSequences() {
+		return backwardTriggerSequences;
+	}
+
+	public TriggerSequence[] getForwardTriggerSequences() {
+		return forwardTriggerSequences;
+	}
+
+	@Override
+	public void setInitializationData(IConfigurationElement config,
+			String propertyName, Object data) throws CoreException {
+		// true by default, but depends on data
+		gotoDirection = data == null || "true".equals(data); //$NON-NLS-1$
+	}
+
+	/** Class used to store items to be displayed */
+	public class FilteredTableItem {
+		String text;
+		Image image;
+		String tooltipText;
+		Map<String, Object> dataMap = new HashMap<>();
+
+		public void setText(String text) {
+			this.text = text;
+		}
+
+		public void setImage(Image image) {
+			this.image = image;
+		}
+
+		public void putData(String key, Object value) {
+			this.dataMap.put(key, value);
+		}
+
+		public Object getData(String key) {
+			return dataMap.get(key);
+		}
+
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/HeapStatus.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/HeapStatus.java
new file mode 100644
index 0000000..c01d0f4
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/HeapStatus.java
@@ -0,0 +1,598 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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
+ *     Brock Janicyak - brockj@tpg.com.au
+ *     		- Fix for Bug 11142 [HeapStatus] Heap status is updated too frequently
+ *          - Fix for Bug 192996 [Workbench] Reduce amount of garbage created by HeapStatus
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 422040, 372517, 463652, 466275
+ *******************************************************************************/
+
+package org.eclipse.ui.internal;
+
+import java.lang.reflect.Method;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * The Heap Status control, which shows the heap usage statistics in the window trim.
+ *
+ * @since 3.1
+ */
+public class HeapStatus extends Composite {
+
+	private boolean armed;
+	private Image gcImage;
+	private Image disabledGcImage;
+	private Color bgCol, usedMemCol, lowMemCol, freeMemCol, topLeftCol, bottomRightCol, sepCol, textCol, markCol, armCol;
+    private Canvas button;
+	private IPreferenceStore prefStore;
+	private int updateInterval;
+	private boolean showMax;
+    private long totalMem;
+    private long prevTotalMem = -1L;
+    private long prevUsedMem = -1L;
+    private boolean hasChanged;
+    private long usedMem;
+    private long mark = -1;
+    // start with 12x12
+	private Rectangle imgBounds = new Rectangle(0,0,12,12);
+	private long maxMem = Long.MAX_VALUE;
+	private boolean maxMemKnown;
+	private float lowMemThreshold = 0.05f;
+	private boolean showLowMemThreshold = true;
+	private boolean updateTooltip = false;
+
+	protected volatile boolean isInGC = false;
+
+    private final Runnable timer = new Runnable() {
+        @Override
+		public void run() {
+            if (!isDisposed()) {
+                updateStats();
+                if (hasChanged) {
+                	if (updateTooltip) {
+                		updateToolTip();
+                	}
+                    redraw();
+                    hasChanged = false;
+                }
+                getDisplay().timerExec(updateInterval, this);
+            }
+        }
+    };
+
+    private final IPropertyChangeListener prefListener = event -> {
+		if (IHeapStatusConstants.PREF_UPDATE_INTERVAL.equals(event.getProperty())) {
+			setUpdateIntervalInMS(prefStore.getInt(IHeapStatusConstants.PREF_UPDATE_INTERVAL));
+		}
+		else if (IHeapStatusConstants.PREF_SHOW_MAX.equals(event.getProperty())) {
+			showMax = prefStore.getBoolean(IHeapStatusConstants.PREF_SHOW_MAX);
+		}
+	};
+
+    /**
+     * Creates a new heap status control with the given parent, and using
+     * the given preference store to obtain settings such as the refresh
+     * interval.
+     *
+     * @param parent the parent composite
+     * @param prefStore the preference store
+     */
+	public HeapStatus(Composite parent, IPreferenceStore prefStore) {
+		super(parent, SWT.NONE);
+
+		maxMem = getMaxMem();
+		maxMemKnown = maxMem != Long.MAX_VALUE;
+
+        this.prefStore = prefStore;
+        prefStore.addPropertyChangeListener(prefListener);
+
+        setUpdateIntervalInMS(prefStore.getInt(IHeapStatusConstants.PREF_UPDATE_INTERVAL));
+        showMax = prefStore.getBoolean(IHeapStatusConstants.PREF_SHOW_MAX);
+
+        button = new Canvas(this, SWT.NONE);
+        button.setToolTipText(WorkbenchMessages.get().HeapStatus_buttonToolTip);
+
+		ImageDescriptor imageDesc = WorkbenchImages.getWorkbenchImageDescriptor("elcl16/trash.gif"); //$NON-NLS-1$
+		Display display = getDisplay();
+		gcImage = imageDesc.createImage();
+		if (gcImage != null) {
+			imgBounds = gcImage.getBounds();
+			disabledGcImage = new Image(display, gcImage, SWT.IMAGE_DISABLE);
+		}
+		usedMemCol = display.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW);
+		lowMemCol = new Color(display, 255, 70, 70);  // medium red
+		freeMemCol = new Color(display, 255, 190, 125);  // light orange
+		bgCol = display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
+		sepCol = topLeftCol = armCol = display.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW);
+		bottomRightCol = display.getSystemColor(SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW);
+		markCol = textCol = display.getSystemColor(SWT.COLOR_WIDGET_FOREGROUND);
+
+		createContextMenu();
+
+        Listener listener = event -> {
+		    switch (event.type) {
+		    case SWT.Dispose:
+		    	doDispose();
+		        break;
+		    case SWT.Resize:
+		        Rectangle rect = getClientArea();
+		        button.setBounds(rect.width - imgBounds.width - 1, 1, imgBounds.width, rect.height - 2);
+		        break;
+		    case SWT.Paint:
+		        if (event.widget == HeapStatus.this) {
+		        	paintComposite(event.gc);
+		        }
+		        else if (event.widget == button) {
+		            paintButton(event.gc);
+		        }
+		        break;
+		    case SWT.MouseUp:
+		        if (event.button == 1) {
+					if (!isInGC) {
+						arm(false);
+						gc();
+					}
+		        }
+		        break;
+		    case SWT.MouseDown:
+		        if (event.button == 1) {
+		            if (event.widget == HeapStatus.this) {
+						setMark();
+					} else if (event.widget == button) {
+						if (!isInGC)
+							arm(true);
+					}
+		        }
+		        break;
+		    case SWT.MouseEnter:
+		    	HeapStatus.this.updateTooltip = true;
+		    	updateToolTip();
+		    	break;
+		    case SWT.MouseExit:
+		        if (event.widget == HeapStatus.this) {
+		        	HeapStatus.this.updateTooltip = false;
+				} else if (event.widget == button) {
+					arm(false);
+				}
+		        break;
+		    }
+		};
+        addListener(SWT.Dispose, listener);
+        addListener(SWT.MouseDown, listener);
+        addListener(SWT.Paint, listener);
+        addListener(SWT.Resize, listener);
+        addListener(SWT.MouseEnter, listener);
+        addListener(SWT.MouseExit, listener);
+        button.addListener(SWT.MouseDown, listener);
+        button.addListener(SWT.MouseExit, listener);
+        button.addListener(SWT.MouseUp, listener);
+        button.addListener(SWT.Paint, listener);
+
+		// make sure stats are updated before first paint
+		updateStats();
+
+        getDisplay().asyncExec(() -> {
+			if (!isDisposed()) {
+				getDisplay().timerExec(updateInterval, timer);
+			}
+		});
+   	}
+
+	@Override
+	public void setBackground(Color color) {
+		bgCol = color;
+		button.redraw();
+	}
+
+	@Override
+	public void setForeground(Color color) {
+		if (color == null) {
+			markCol = textCol = getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND);
+		} else {
+			markCol = textCol = color;
+		}
+
+		button.redraw();
+	}
+
+	@Override
+	public Color getForeground() {
+		if (usedMemCol != null) {
+			return usedMemCol;
+		}
+		return getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND);
+	}
+
+	/**
+	 * Returns the maximum memory limit, or Long.MAX_VALUE if the max is not known.
+	 */
+	private long getMaxMem() {
+		long max = Long.MAX_VALUE;
+		try {
+			// Must use reflect to allow compilation against JCL/Foundation
+			Method maxMemMethod = Runtime.class.getMethod("maxMemory", new Class[0]); //$NON-NLS-1$
+			Object o = maxMemMethod.invoke(Runtime.getRuntime(), new Object[0]);
+			if (o instanceof Long) {
+				max = ((Long) o).longValue();
+			}
+		}
+		catch (Exception e) {
+			// ignore if method missing or if there are other failures trying to determine the max
+		}
+		return max;
+	}
+
+	private void setUpdateIntervalInMS(int interval) {
+		updateInterval = Math.max(100, interval);
+	}
+
+	private void doDispose() {
+        prefStore.removePropertyChangeListener(prefListener);
+    	if (gcImage != null) {
+			gcImage.dispose();
+		}
+		if (disabledGcImage != null) {
+			disabledGcImage.dispose();
+		}
+
+        if (lowMemCol != null) {
+			lowMemCol.dispose();
+		}
+        if (freeMemCol != null) {
+			freeMemCol.dispose();
+		}
+	}
+
+	@Override
+	public Point computeSize(int wHint, int hHint, boolean changed) {
+        GC gc = new GC(this);
+        Point p = gc.textExtent(WorkbenchMessages.get().HeapStatus_widthStr);
+        int height = imgBounds.height;
+        // choose the largest of
+        // 	- Text height + margins
+        //	- Image height + margins
+        //	- Default Trim heightin
+        height = Math.max(height, p.y) + 4;
+        height = Math.max(TrimUtil.TRIM_DEFAULT_HEIGHT, height);
+        gc.dispose();
+		return new Point(p.x + 15, height);
+	}
+
+    private void arm(boolean armed) {
+        if (this.armed == armed) {
+			return;
+		}
+        this.armed = armed;
+        button.redraw();
+    }
+
+	private void gcRunning(boolean isInGC) {
+		if (this.isInGC == isInGC) {
+			return;
+		}
+		this.isInGC = isInGC;
+		 button.redraw();
+	}
+
+    /**
+     * Creates the context menu
+     */
+    private void createContextMenu() {
+        MenuManager menuMgr = new MenuManager();
+        menuMgr.setRemoveAllWhenShown(true);
+        menuMgr.addMenuListener(menuMgr1 -> fillMenu(menuMgr1));
+        Menu menu = menuMgr.createContextMenu(this);
+        setMenu(menu);
+    }
+
+    private void fillMenu(IMenuManager menuMgr) {
+        menuMgr.add(new SetMarkAction());
+        menuMgr.add(new ClearMarkAction());
+        menuMgr.add(new ShowMaxAction());
+        menuMgr.add(new CloseHeapStatusAction());
+//        if (isKyrsoftViewAvailable()) {
+//        	menuMgr.add(new ShowKyrsoftViewAction());
+//        }
+    }
+
+    /**
+     * Sets the mark to the current usedMem level.
+     */
+    private void setMark() {
+    	updateStats();  // get up-to-date stats before taking the mark
+        mark = usedMem;
+        hasChanged = true;
+        redraw();
+    }
+
+    /**
+     * Clears the mark.
+     */
+    private void clearMark() {
+        mark = -1;
+        hasChanged = true;
+        redraw();
+    }
+
+    private void gc() {
+		gcRunning(true);
+		Thread t = new Thread() {
+			@Override
+			public void run() {
+				busyGC();
+				getDisplay().asyncExec(() -> {
+					if (!isDisposed()) {
+						gcRunning(false);
+					}
+				});
+			}
+		};
+		t.start();
+    }
+
+    private void busyGC() {
+        for (int i = 0; i < 2; ++i) {
+	        System.gc();
+	        System.runFinalization();
+        }
+    }
+
+    private void paintButton(GC gc) {
+        Rectangle rect = button.getClientArea();
+		if (isInGC) {
+			if (disabledGcImage != null) {
+				int buttonY = (rect.height - imgBounds.height) / 2 + rect.y;
+				gc.drawImage(disabledGcImage, rect.x, buttonY);
+			}
+			return;
+		}
+        if (armed) {
+            gc.setBackground(armCol);
+            gc.fillRectangle(rect.x, rect.y, rect.width, rect.height);
+        }
+        if (gcImage != null) {
+			int by = (rect.height - imgBounds.height) / 2 + rect.y; // button y
+			gc.drawImage(gcImage, rect.x, by);
+        }
+    }
+
+    private void paintComposite(GC gc) {
+		if (showMax && maxMemKnown) {
+			paintCompositeMaxKnown(gc);
+		} else {
+			paintCompositeMaxUnknown(gc);
+		}
+    }
+
+    private void paintCompositeMaxUnknown(GC gc) {
+        Rectangle rect = getClientArea();
+        int x = rect.x;
+        int y = rect.y;
+        int w = rect.width;
+        int h = rect.height;
+        int bw = imgBounds.width; // button width
+        int dx = x + w - bw - 2; // divider x
+        int sw = w - bw - 3; // status width
+        int uw = (int) (sw * usedMem / totalMem); // used mem width
+        int ux = x + 1 + uw; // used mem right edge
+        if (bgCol != null) {
+			gc.setBackground(bgCol);
+		}
+        gc.fillRectangle(rect);
+        gc.setForeground(sepCol);
+		gc.drawLine(dx, y, dx, y + h);
+		gc.drawLine(ux, y, ux, y + h);
+        gc.setForeground(topLeftCol);
+        gc.drawLine(x, y, x+w, y);
+		gc.drawLine(x, y, x, y+h);
+		gc.setForeground(bottomRightCol);
+        gc.drawLine(x+w-1, y, x+w-1, y+h);
+		gc.drawLine(x, y+h-1, x+w, y+h-1);
+
+		gc.setBackground(usedMemCol);
+        gc.fillRectangle(x + 1, y + 1, uw, h - 2);
+
+        String s = NLS.bind(WorkbenchMessages.get().HeapStatus_status, convertToMegString(usedMem), convertToMegString(totalMem));
+        Point p = gc.textExtent(s);
+        int sx = (rect.width - 15 - p.x) / 2 + rect.x + 1;
+        int sy = (rect.height - 2 - p.y) / 2 + rect.y + 1;
+        gc.setForeground(textCol);
+        gc.drawString(s, sx, sy, true);
+
+        // draw an I-shaped bar in the foreground colour for the mark (if present)
+        if (mark != -1) {
+            int ssx = (int) (sw * mark / totalMem) + x + 1;
+            paintMark(gc, ssx, y, h);
+        }
+    }
+
+    private void paintCompositeMaxKnown(GC gc) {
+        Rectangle rect = getClientArea();
+        int x = rect.x;
+        int y = rect.y;
+        int w = rect.width;
+        int h = rect.height;
+        int bw = imgBounds.width; // button width
+        int dx = x + w - bw - 2; // divider x
+        int sw = w - bw - 3; // status width
+        int uw = (int) (sw * usedMem / maxMem); // used mem width
+        int ux = x + 1 + uw; // used mem right edge
+        int tw = (int) (sw * totalMem / maxMem); // current total mem width
+        int tx = x + 1 + tw; // current total mem right edge
+
+		if (bgCol != null) {
+			gc.setBackground(bgCol);
+		}
+        gc.fillRectangle(rect);
+        gc.setForeground(sepCol);
+		gc.drawLine(dx, y, dx, y + h);
+		gc.drawLine(ux, y, ux, y + h);
+		gc.drawLine(tx, y, tx, y + h);
+        gc.setForeground(topLeftCol);
+        gc.drawLine(x, y, x+w, y);
+		gc.drawLine(x, y, x, y+h);
+		gc.setForeground(bottomRightCol);
+        gc.drawLine(x+w-1, y, x+w-1, y+h);
+		gc.drawLine(x, y+h-1, x+w, y+h-1);
+
+        if (lowMemThreshold != 0 && ((double)(maxMem - usedMem) / (double)maxMem < lowMemThreshold)) {
+            gc.setBackground(lowMemCol);
+        } else {
+            gc.setBackground(usedMemCol);
+        }
+        gc.fillRectangle(x + 1, y + 1, uw, h - 2);
+
+        gc.setBackground(freeMemCol);
+        gc.fillRectangle(ux + 1, y + 1, tx - (ux + 1), h - 2);
+
+        // paint line for low memory threshold
+        if (showLowMemThreshold && lowMemThreshold != 0) {
+            gc.setForeground(lowMemCol);
+            int thresholdX = x + 1 + (int) (sw * (1.0 - lowMemThreshold));
+            gc.drawLine(thresholdX, y + 1, thresholdX, y + h - 2);
+        }
+
+        String s = NLS.bind(WorkbenchMessages.get().HeapStatus_status,
+				convertToMegString(usedMem), convertToMegString(totalMem));
+        Point p = gc.textExtent(s);
+        int sx = (rect.width - 15 - p.x) / 2 + rect.x + 1;
+        int sy = (rect.height - 2 - p.y) / 2 + rect.y + 1;
+        gc.setForeground(textCol);
+        gc.drawString(s, sx, sy, true);
+
+        // draw an I-shaped bar in the foreground colour for the mark (if present)
+        if (mark != -1) {
+            int ssx = (int) (sw * mark / maxMem) + x + 1;
+            paintMark(gc, ssx, y, h);
+        }
+    }
+
+	private void paintMark(GC gc, int x, int y, int h) {
+        gc.setForeground(markCol);
+		gc.drawLine(x, y+1, x, y+h-2);
+		gc.drawLine(x-1, y+1, x+1, y+1);
+		gc.drawLine(x-1, y+h-2, x+1, y+h-2);
+	}
+
+    private void updateStats() {
+        Runtime runtime = Runtime.getRuntime();
+        totalMem = runtime.totalMemory();
+        long freeMem = runtime.freeMemory();
+        usedMem = totalMem - freeMem;
+
+        if (convertToMeg(prevUsedMem) != convertToMeg(usedMem)) {
+            prevUsedMem = usedMem;
+            this.hasChanged = true;
+        }
+
+        if (prevTotalMem != totalMem) {
+            prevTotalMem = totalMem;
+            this.hasChanged = true;
+        }
+    }
+
+    private void updateToolTip() {
+    	String usedStr = convertToMegString(usedMem);
+    	String totalStr = convertToMegString(totalMem);
+    	String maxStr = maxMemKnown ? convertToMegString(maxMem) : WorkbenchMessages.get().HeapStatus_maxUnknown;
+    	String markStr = mark == -1 ? WorkbenchMessages.get().HeapStatus_noMark : convertToMegString(mark);
+        String toolTip = NLS.bind(WorkbenchMessages.get().HeapStatus_memoryToolTip, new Object[] { usedStr, totalStr, maxStr, markStr });
+        if (!toolTip.equals(getToolTipText())) {
+            setToolTipText(toolTip);
+        }
+    }
+
+    /**
+     * Converts the given number of bytes to a printable number of megabytes (rounded up).
+     */
+    private String convertToMegString(long numBytes) {
+        return NLS.bind(WorkbenchMessages.get().HeapStatus_meg, new Long(convertToMeg(numBytes)));
+    }
+
+    /**
+     * Converts the given number of bytes to the corresponding number of megabytes (rounded up).
+     */
+	private long convertToMeg(long numBytes) {
+		return (numBytes + (512 * 1024)) / (1024 * 1024);
+	}
+
+
+    class SetMarkAction extends Action {
+        SetMarkAction() {
+            super(WorkbenchMessages.get().SetMarkAction_text);
+        }
+
+        @Override
+		public void run() {
+            setMark();
+        }
+    }
+
+    class ClearMarkAction extends Action {
+        ClearMarkAction() {
+            super(WorkbenchMessages.get().ClearMarkAction_text);
+        }
+
+        @Override
+		public void run() {
+            clearMark();
+        }
+    }
+
+    class ShowMaxAction extends Action {
+    	ShowMaxAction() {
+            super(WorkbenchMessages.get().ShowMaxAction_text, IAction.AS_CHECK_BOX);
+            setEnabled(maxMemKnown);
+            setChecked(showMax);
+        }
+
+        @Override
+		public void run() {
+            prefStore.setValue(IHeapStatusConstants.PREF_SHOW_MAX, isChecked());
+            redraw();
+        }
+    }
+
+    class CloseHeapStatusAction extends Action{
+
+    	CloseHeapStatusAction(){
+    		super(WorkbenchMessages.get().WorkbenchWindow_close );
+    	}
+
+    	@Override
+		public void run(){
+			WorkbenchWindow wbw = (WorkbenchWindow) PlatformUI.getWorkbench()
+					.getActiveWorkbenchWindow();
+			if (wbw != null) {
+				wbw.showHeapStatus(false);
+			}
+    	}
+    }
+
+}
+
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IActionSetContributionItem.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IActionSetContributionItem.java
new file mode 100644
index 0000000..f57e363
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IActionSetContributionItem.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 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.ui.internal;
+
+/**
+ * This interface should be implemented by all contribution items
+ * defined by an action set.
+ */
+public interface IActionSetContributionItem {
+
+    /**
+     * Returns the action set id.
+     */
+    public String getActionSetId();
+
+    /**
+     * Sets the action set id.
+     */
+    public void setActionSetId(String newActionSetId);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IBackgroundSaveListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IBackgroundSaveListener.java
new file mode 100644
index 0000000..4f154cd
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IBackgroundSaveListener.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal;
+
+/**
+ * @since 3.3
+ *
+ */
+interface IBackgroundSaveListener {
+
+	public void handleBackgroundSaveStarted();
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IChangeListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IChangeListener.java
new file mode 100644
index 0000000..bb0283f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IChangeListener.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2006 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.ui.internal;
+
+/**
+ * Interface that can receive change notifiecations
+ * from a Model object
+ */
+public interface IChangeListener {
+    /**
+     * Called with false when the listener is first
+     * attached to the model, and called with true
+     * every time the model's state changes.
+     */
+    void update(boolean changed);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IHeapStatusConstants.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IHeapStatusConstants.java
new file mode 100644
index 0000000..a56eb01
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IHeapStatusConstants.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal;
+
+/**
+ * Preference constants for the heap status.
+ *
+ * @since 3.1
+ */
+public interface IHeapStatusConstants {
+
+	/**
+	 * Preference key for the update interval (value in milliseconds).
+	 */
+    String PREF_UPDATE_INTERVAL = "HeapStatus.updateInterval"; //$NON-NLS-1$
+
+    /**
+     * Preference key for whether to show max heap, if available (value is boolean).
+     */
+    String PREF_SHOW_MAX = "HeapStatus.showMax";   //$NON-NLS-1$
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IObjectActionContributor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IObjectActionContributor.java
new file mode 100644
index 0000000..a32dbc8
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IObjectActionContributor.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import java.util.List;
+
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.ui.IWorkbenchPart;
+
+/**
+ * This interface must be implemented in order to contribute
+ * to context (pop-up) menu for an object. Classes
+ * that implement this interface must register
+ * with the popup menu manager.
+ */
+public interface IObjectActionContributor extends IObjectContributor {
+    /**
+     * Implement this method to add actions that deal with the currently
+     * selected object or objects. Actions should be added to the
+     * provided menu object. Current selection can be obtained from
+     * the given selection provider.
+     *
+     * @return <code>true</code> if any contributions were made, and <code>false</code> otherwise.
+     */
+    public boolean contributeObjectActions(IWorkbenchPart part,
+            IMenuManager menu, ISelectionProvider selProv,
+            List actionIdOverrides);
+
+    /**
+     * Implement this method to add menus that deal with the currently
+     * selected object or objects. Menus should be added to the
+     * provided menu object. Current selection can be obtained from
+     * the given selection provider.
+     *
+     * @return <code>true</code> if any contributions were made, and <code>false</code> otherwise.
+     */
+    public boolean contributeObjectMenus(IMenuManager menu,
+            ISelectionProvider selProv);
+
+    /**
+     * Contribute to the list the action identifiers from other contributions that
+     * this contribution wants to override. Actions of these identifiers will
+     * not be contributed.
+     */
+    public void contributeObjectActionIdOverrides(List actionIdOverrides);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IObjectContributor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IObjectContributor.java
new file mode 100644
index 0000000..d882e09
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IObjectContributor.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 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.ui.internal;
+
+/**
+ * Objects of classes that implement this interface
+ * can be registered for certain object type
+ * in the IObjectContributorManager. Unlike with extenders,
+ * all the matching contributors will be processed
+ * in a sequence.
+ * <p>By implementing 'isApplicableTo' method,
+ * a contributor can tell the manager to skip it
+ * if the object is of the desired type, but its
+ * other properties do not match additional
+ * requirements imposed by the contributor.
+ *
+ */
+
+public interface IObjectContributor {
+    /**
+     * Returns true if this contributor should be considered
+     * for the given object.
+     * @param object the object to text
+     * @return boolean
+     */
+    public boolean isApplicableTo(Object object);
+
+    /**
+     * Return whether or not the receiver can adapt to IResource.
+     * @return boolean
+     */
+    public boolean canAdapt();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IPreferenceConstants.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IPreferenceConstants.java
new file mode 100644
index 0000000..6f4e5ed
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IPreferenceConstants.java
@@ -0,0 +1,284 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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
+ *     Semion Chichelnitsky (semion@il.ibm.com) - bug 278064
+ *     Tristan Hume - <trishume@gmail.com> -
+ *     		Fix for Bug 2369 [Workbench] Would like to be able to save workspace without exiting
+ *     		Implemented workbench auto-save to correctly restore state in case of crash.
+ *     Denis Zygann <d.zygann@web.de> - Bug 330453
+ *     Axel Richard <axel.richard@obeo.fr> - Bug 486644
+ *******************************************************************************/
+
+package org.eclipse.ui.internal;
+
+/**
+ * The IPreferenceConstants are the internal constants used by the Workbench.
+ */
+public interface IPreferenceConstants {
+
+    //Boolean: true = single click opens editor; false = double click opens
+    // it.
+    public static final String OPEN_ON_SINGLE_CLICK = "OPEN_ON_SINGLE_CLICK"; //$NON-NLS-1$
+
+    //Boolean: true = select on hover;
+    public static final String SELECT_ON_HOVER = "SELECT_ON_HOVER"; //$NON-NLS-1$
+
+    //Boolean: true = open after delay
+    public static final String OPEN_AFTER_DELAY = "OPEN_AFTER_DELAY"; //$NON-NLS-1$
+
+	// Boolean: true = bidi support enabled; false = bidi support disabled
+	public static final String BIDI_SUPPORT = "BIDI_SUPPORT"; //$NON-NLS-1$
+
+	// String: Text direction. May have the following values: "ltr", "rtl",
+	// "auto", and "".
+	public static final String TEXT_DIRECTION = "TEXT_DIRECTION"; //$NON-NLS-1$
+
+	// String: Layout direction. May have the following values:
+	// SWT.LEFT_TO_RIGHT, SWT.RIGHT_TO_LEFT, and SWT.NONE.
+	public static final String LAYOUT_DIRECTION = "LAYOUT_DIRECTION"; //$NON-NLS-1$
+
+	// String: Unicode locale extensions
+	public static final String NL_EXTENSIONS = "NL_EXTENSIONS"; //$NON-NLS-1$
+
+    //Do we show color icons in toolbars?
+    public static final String COLOR_ICONS = "COLOR_ICONS"; //$NON-NLS-1$
+
+    //mappings for type/extension to an editor
+    public final static String EDITORS = "editors"; //$NON-NLS-1$
+
+    public final static String RESOURCES = "resourcetypes"; //$NON-NLS-1$
+
+    //saving perspective layouts
+    public final static String PERSPECTIVES = "perspectives"; //$NON-NLS-1$
+
+    // (int) If > 0, an editor will be reused once 'N' editors are opened.
+    public static final String REUSE_EDITORS = "REUSE_OPEN_EDITORS"; //$NON-NLS-1$
+
+    //On/Off option for the two preceding options.
+    public static final String REUSE_EDITORS_BOOLEAN = "REUSE_OPEN_EDITORS_BOOLEAN"; //$NON-NLS-1$
+
+    // (int) N recently viewed files will be listed in the File->Open Recent
+    // menu.
+    public static final String RECENT_FILES = "RECENT_FILES"; //$NON-NLS-1$
+
+    // (int) Mode for opening a new perspective
+    public static final String OPEN_PERSP_MODE = "OPEN_PERSPECTIVE_MODE"; //$NON-NLS-1$
+
+    public static final int OPM_ACTIVE_PAGE = 0;
+
+    //public static final int OPM_NEW_PAGE = 1;
+    public static final int OPM_NEW_WINDOW = 2;
+
+    //Identifier for enabled decorators
+    public static final String ENABLED_DECORATORS = "ENABLED_DECORATORS"; //$NON-NLS-1$
+
+    //Boolean: true = keep cycle part dialog open when keys released
+    public static final String STICKY_CYCLE = "STICKY_CYCLE"; //$NON-NLS-1$
+
+    //List of plugins but that extends "startup" extension point but are
+    // overriden by the user.
+    //String of plugin unique ids separated by ";"
+    public static final String PLUGINS_NOT_ACTIVATED_ON_STARTUP = "PLUGINS_NOT_ACTIVATED_ON_STARTUP"; //$NON-NLS-1$
+
+    //Separator for PLUGINS_NOT_ACTIVATED_ON_STARTUP
+    public static char SEPARATOR = ';';
+
+    //Preference key for default editors
+    public final static String DEFAULT_EDITORS = "defaultEditors"; //$NON-NLS-1$
+
+    //Preference key for default editors
+    public final static String DEFAULT_EDITORS_CACHE = "defaultEditorsCache"; //$NON-NLS-1$
+
+    //Tab width = tab height * scalar value
+    public final static String EDITOR_TAB_WIDTH = "EDITOR_TAB_WIDTH"; //$NON-NLS-1$
+
+    //Boolean: true = show Editors drop down button on CTabFolder
+    public static final String EDITORLIST_PULLDOWN_ACTIVE = "EDITORLIST_PULLDOWN_ACTIVE"; //$NON-NLS-1$
+
+    // Selection scope for EditorList
+    public static final String EDITORLIST_SELECTION_SCOPE = "EDITORLIST_SELECTION_SCOPE"; //$NON-NLS-1$
+
+    public static final int EDITORLIST_SET_WINDOW_SCOPE = 0;
+
+    public static final int EDITORLIST_SET_PAGE_SCOPE = 1;
+
+    public static final int EDITORLIST_SET_TAB_GROUP_SCOPE = 2;
+
+    // Sort criteria for EditorList
+    public static final String EDITORLIST_SORT_CRITERIA = "EDITORLIST_SORT_CRITERIA"; //$NON-NLS-1$
+
+    public static final int EDITORLIST_NAME_SORT = 0;
+
+    public static final int EDITORLIST_MRU_SORT = 1;
+
+    /**
+     * Boolean; true = EditorList displays full path
+     */
+    public static final String EDITORLIST_DISPLAY_FULL_NAME = "EDITORLIST_DISPLAY_FULL_NAME"; //$NON-NLS-1$
+
+
+    /**
+     * Workbench preference id for determining whether the user has chosen to
+     * override some of the settings in the current presentation.
+     * <p>
+     * The default value for this preference is: <code>false</code> (prompt)
+     * </p>
+     *
+     * @since 3.2
+     */
+    public static final String OVERRIDE_PRESENTATION = "overridepresentation"; //$//$NON-NLS-1$
+
+    /**
+     * <p>
+     * The key for the preference indicating which tab is selected in the keys
+     * preference page when last okay was pressed. This value should never
+     * really be directly edited by a user.
+     * </p>
+     * <p>
+     * This preference is an <code>int</code> value. The default value is
+     * <code>0</code>.
+     * </p>
+     *
+     * @since 3.1
+     */
+    public static final String KEYS_PREFERENCE_SELECTED_TAB = "KEYS_PREFERENCE_SELECTED_TAB"; //$NON-NLS-1$
+
+    /**
+     * <p>
+     * The key for the preference indicating whether multi-stroke key sequences
+     * should provide assistance to the user. This means that if the user pauses
+     * after pressing the first key, a window will open showing the possible
+     * completions.
+     * </p>
+     * <p>
+     * This preference is a <code>boolean</code> value. The default value is
+     * <code>false</code>.
+     * </p>
+     *
+     * @since 3.0
+     */
+    public static final String MULTI_KEY_ASSIST = "MULTI_KEY_ASSIST"; //$NON-NLS-1$
+
+    /**
+     * <p>
+     * The key for the preference indicating how long the assist window should
+     * wait before opening. This is a value in milliseconds -- from the time the
+     * first key in a multi-key is received by the system, to the time the
+     * assist window should appear.
+     * </p>
+     * <p>
+     * This preference is an <code>int</code> value. The default value is
+     * <code>1000</code>.
+     * </p>
+     *
+     * @since 3.0
+     */
+    public static final String MULTI_KEY_ASSIST_TIME = "MULTI_KEY_ASSIST_TIME"; //$NON-NLS-1$
+
+    /**
+     * Workbench preference to use the new IPersistableEditor interface
+     * throughout the workbench new editor/open editor calls.
+     *
+     * @since 3.3
+     */
+    public static String USE_IPERSISTABLE_EDITORS = "USE_IPERSISTABLE_EDITORS"; //$NON-NLS-1$
+
+    /**
+     * Preference to show user jobs in a dialog.
+     */
+    public static String RUN_IN_BACKGROUND = "RUN_IN_BACKGROUND"; //$NON-NLS-1$
+
+    /**
+     * Workbench preference id for determining whether the user will be prompted
+     * for activity enablement. If this is false then activities are enabled
+     * automatically. If it is true, then the user is only prompted for
+     * activities that they have not already declared a disinterest in via the
+     * prompt dialog.
+     * <p>
+     * The default value for this preference is: <code>true</code> (prompt)
+     * </p>
+     *
+     * @since 3.0
+     */
+    public static final String SHOULD_PROMPT_FOR_ENABLEMENT = "shouldPromptForEnablement"; //$NON-NLS-1$
+
+	/**
+	 * Preference to show/hide the CoolBar.
+	 *
+	 * @since 3.6
+	 */
+	public static final String COOLBAR_VISIBLE = "coolBarVisible"; //$NON-NLS-1$
+
+	/**
+	 * Preference to show/hide the PerspectiveBar.
+	 *
+	 * @since 3.6
+	 */
+	public static final String PERSPECTIVEBAR_VISIBLE = "perspectiveBarVisible"; //$NON-NLS-1$
+
+    /**
+	 * Preference that restores the 3.2 startup threading behavior. This
+	 * essentially means that there will be no restrictions on what runnables
+	 * will be processed via the UI synchronizer.
+	 *
+	 * <p>
+	 * This preference will likely disappear in 3.5 in favor of a proper
+	 * solution to bug 219913.
+	 * </p>
+	 *
+	 * @since 3.4
+	 */
+	public static final String USE_32_THREADING = "use32Threading"; //$NON-NLS-1$
+
+	/**
+	 * Preference value that specifies the time interval in minutes between
+	 * workbench auto-saves. If the value is zero it disables workbench
+	 * auto-save.
+	 *
+	 * @since 3.105
+	 */
+	public static final String WORKBENCH_SAVE_INTERVAL = "WORKBENCH_SAVE_INTERVAL"; //$NON-NLS-1$
+
+	/**
+	 * This preference is the threshold value to determine whether a document is
+	 * large or not. When the user tries to open a file larger than the
+	 * threshold, then EditorSelectionDialog will be opened, suggesting the user
+	 * to open with an external editor.
+	 * <p>
+	 * This preference is a <code>long</code> value that represents the
+	 * threshold in bytes. The default value is <code>0</code> meaning no
+	 * prompting on editor opening.
+	 * </p>
+	 *
+	 * @since 3.7
+	 */
+	public static final String LARGE_DOC_SIZE_FOR_EDITORS = "LARGE_DOC_SIZE_FOR_EDITORS"; //$NON-NLS-1$
+
+	/**
+	 * Preference id for whether the editors may save automatically.
+	 * <p>
+	 * The boolean default value for this preference is: <code>false</code>.
+	 * </p>
+	 *
+	 * @since 3.8
+	 */
+	public static final String SAVE_AUTOMATICALLY = "SAVE_AUTOMATICALLY"; //$NON-NLS-1$
+
+	/**
+	 * Preference value that specifies the time interval in seconds between
+	 * editors auto-saves.
+	 * <p>
+	 * The integer default value for this preference is: <code>60</code>.
+	 * </p>
+	 *
+	 * @since 3.8
+	 */
+	public static final String SAVE_AUTOMATICALLY_INTERVAL = "SAVE_AUTOMATICALLY_INTERVAL"; //$NON-NLS-1$
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IReorderListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IReorderListener.java
new file mode 100644
index 0000000..ad503a4
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IReorderListener.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal;
+
+
+/**
+ * Simple interface for informing clients of reordering of an object in an ordered list.
+ *
+ */
+interface IReorderListener {
+
+	/**
+	 * An object has been moved, clients might need to react.
+	 *
+	 * @param obj
+	 * @param newIndex
+	 *
+	 */
+	public void reorder(Object obj, int newIndex);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ISelectionConversionService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ISelectionConversionService.java
new file mode 100644
index 0000000..d12ec08
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ISelectionConversionService.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal;
+
+import org.eclipse.jface.viewers.IStructuredSelection;
+
+/**
+ * <p>
+ * A service that is capable of converting a selection into resources.
+ * </p>
+ * <p>
+ * This interface is only intended for use within the
+ * <code>org.eclipse.ui.workbench</code> and <code>org.eclipse.ui.ide</code>
+ * plug-ins.
+ * </p>
+ *
+ * @since 3.2
+ */
+public interface ISelectionConversionService {
+
+	/**
+	 * Attempt to convert the elements in the passed selection into resources by
+	 * asking each for its IResource property (iff it isn't already a resource).
+	 * If all elements in the initial selection can be converted to resources
+	 * then answer a new selection containing these resources; otherwise answer
+	 * an empty selection.
+	 *
+	 * @param originalSelection
+	 *            the original selection; must not be <code>null</code>.
+	 * @return the converted selection or an empty selection; never
+	 *         <code>null</code>.
+	 */
+	public IStructuredSelection convertToResources(
+			IStructuredSelection originalSelection);
+
+}
+
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IWorkbenchConstants.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IWorkbenchConstants.java
new file mode 100644
index 0000000..9145e9e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IWorkbenchConstants.java
@@ -0,0 +1,358 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 440136
+ *******************************************************************************/
+
+package org.eclipse.ui.internal;
+
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * General constants used by the workbench.
+ */
+public interface IWorkbenchConstants {
+
+    /**
+     * @deprecated
+     */
+    @Deprecated
+	public static final String ACCELERATOR_CONFIGURATION_ID = "acceleratorConfigurationId"; //$NON-NLS-1$
+
+    public static final String DEFAULT_PRESENTATION_ID = "org.eclipse.ui.presentations.default"; //$NON-NLS-1$
+        
+    /**
+     * @deprecated
+     */
+    @Deprecated
+	public static final String DEFAULT_ACCELERATOR_CONFIGURATION_ID = "org.eclipse.ui.defaultAcceleratorConfiguration"; //$NON-NLS-1$
+
+    /**
+     * @deprecated
+     */
+    @Deprecated
+	public static final String DEFAULT_ACCELERATOR_SCOPE_ID = "org.eclipse.ui.globalScope"; //$NON-NLS-1$
+
+	// ID of the MPerspectiveStack in the IDE e4 model
+	public static final String PERSPECTIVE_STACK_ID = "org.eclipse.ui.ide.perspectivestack"; //$NON-NLS-1$
+
+    //mappings for type/extension to an editor - backward compatibility only.
+    public final static String EDITOR_FILE_NAME = "editors.xml"; //$NON-NLS-1$
+
+    public final static String RESOURCE_TYPE_FILE_NAME = "resourcetypes.xml"; //$NON-NLS-1$
+
+    // Filename containing the workbench's preferences
+    public static final String PREFERENCE_BUNDLE_FILE_NAME = "workbench.ini"; //$NON-NLS-1$
+
+    // Identifier for visible view parts.
+    public static final String WORKBENCH_VISIBLE_VIEW_ID = "Workbench.visibleViewID"; //$NON-NLS-1$
+
+    // Identifier of workbench info properties page
+    public static final String WORKBENCH_PROPERTIES_PAGE_INFO = PlatformUI.PLUGIN_ID
+            + ".propertypages.info.file"; //$NON-NLS-1$
+
+    // Various editor.
+    public static final String OLE_EDITOR_ID = PlatformUI.PLUGIN_ID
+            + ".OleEditor"; //$NON-NLS-1$
+
+    // Default view category.
+    public static final String DEFAULT_CATEGORY_ID = PlatformUI.PLUGIN_ID;
+
+    // Persistance tags.
+    public static final String TRUE = "true"; //$NON-NLS-1$
+
+    public static final String FALSE = "false"; //$NON-NLS-1$
+
+	public static final String TAG_WORKBENCH_ADVISOR = "workbenchAdvisor"; //$NON-NLS-1$
+
+	public static final String TAG_WORKBENCH_WINDOW_ADVISOR = "workbenchWindowAdvisor"; //$NON-NLS-1$
+
+	public static final String TAG_ACTION_BAR_ADVISOR = "actionBarAdvisor"; //$NON-NLS-1$
+
+    public static final String TAG_ID = "id"; //$NON-NLS-1$
+
+    public static final String TAG_FOCUS = "focus"; //$NON-NLS-1$
+
+    public static final String TAG_EDITOR = "editor"; //$NON-NLS-1$
+
+    public static final String TAG_DEFAULT_EDITOR = "defaultEditor"; //$NON-NLS-1$
+
+    public static final String TAG_DELETED_EDITOR = "deletedEditor"; //$NON-NLS-1$
+
+    public static final String TAG_EDITORS = "editors"; //$NON-NLS-1$
+
+    public static final String TAG_WORKBOOK = "workbook"; //$NON-NLS-1$
+
+    public static final String TAG_ACTIVE_WORKBOOK = "activeWorkbook"; //$NON-NLS-1$
+
+    public static final String TAG_AREA = "editorArea"; //$NON-NLS-1$
+
+    public static final String TAG_AREA_VISIBLE = "editorAreaVisible"; //$NON-NLS-1$
+
+    public static final String TAG_AREA_HIDDEN = "editorAreaHidden"; //$NON-NLS-1$
+
+    public static final String TAG_AREA_TRIM_STATE = "editorAreaTrimState"; //$NON-NLS-1$
+
+    public static final String TAG_INPUT = "input"; //$NON-NLS-1$
+
+    public static final String TAG_FACTORY_ID = "factoryID"; //$NON-NLS-1$
+
+    public static final String TAG_EDITOR_STATE = "editorState"; //$NON-NLS-1$
+
+    public static final String TAG_TITLE = "title"; //$NON-NLS-1$
+
+    public static final String TAG_X = "x"; //$NON-NLS-1$
+
+    public static final String TAG_Y = "y"; //$NON-NLS-1$
+
+    public static final String TAG_FLOAT = "float"; //$NON-NLS-1$
+
+    public static final String TAG_ITEM_WRAP_INDEX = "wrapIndex"; //$NON-NLS-1$
+
+    public static final String TAG_TOOLBAR_LAYOUT = "toolbarLayout"; //$NON-NLS-1$
+
+    public static final String TAG_WIDTH = "width"; //$NON-NLS-1$
+
+    public static final String TAG_HEIGHT = "height"; //$NON-NLS-1$
+
+    public static final String TAG_MINIMIZED = "minimized"; //$NON-NLS-1$
+
+    public static final String TAG_MAXIMIZED = "maximized"; //$NON-NLS-1$
+
+    public static final String TAG_FOLDER = "folder"; //$NON-NLS-1$
+
+    public static final String TAG_INFO = "info"; //$NON-NLS-1$
+
+    public static final String TAG_PART = "part"; //$NON-NLS-1$
+
+    public static final String TAG_PART_NAME = "partName"; //$NON-NLS-1$
+
+	public static final String TAG_PROPERTIES = "properties"; //$NON-NLS-1$
+
+    public static final String TAG_PROPERTY = "property"; //$NON-NLS-1$
+
+    public static final String TAG_RELATIVE = "relative"; //$NON-NLS-1$
+
+    public static final String TAG_RELATIONSHIP = "relationship"; //$NON-NLS-1$
+
+    public static final String TAG_RATIO = "ratio"; //$NON-NLS-1$
+
+    public static final String TAG_RATIO_LEFT = "ratioLeft"; //$NON-NLS-1$
+
+    public static final String TAG_RATIO_RIGHT = "ratioRight"; //$NON-NLS-1$
+
+    public static final String TAG_ACTIVE_PAGE_ID = "activePageID"; //$NON-NLS-1$
+
+    public static final String TAG_EXPANDED = "expanded"; //$NON-NLS-1$
+
+    public static final String TAG_PAGE = "page"; //$NON-NLS-1$
+
+    public static final String TAG_INTRO = "intro"; //$NON-NLS-1$
+
+    public static final String TAG_STANDBY = "standby"; //$NON-NLS-1$
+
+    public static final String TAG_LABEL = "label"; //$NON-NLS-1$
+
+    public static final String TAG_CONTENT = "content"; //$NON-NLS-1$
+
+    public static final String TAG_CLASS = "class"; //$NON-NLS-1$
+
+	public static final String TAG_USE_DEPENDENCY_INJECTION = "inject"; //$NON-NLS-1$
+
+    public static final String TAG_FILE = "file"; //$NON-NLS-1$
+
+    public static final String TAG_DESCRIPTOR = "descriptor"; //$NON-NLS-1$
+
+    public static final String TAG_MAIN_WINDOW = "mainWindow"; //$NON-NLS-1$
+
+    public static final String TAG_DETACHED_WINDOW = "detachedWindow"; //$NON-NLS-1$
+
+    public static final String TAG_HIDDEN_WINDOW = "hiddenWindow"; //$NON-NLS-1$
+
+    public static final String TAG_WORKBENCH = "workbench"; //$NON-NLS-1$
+
+    public static final String TAG_WINDOW = "window"; //$NON-NLS-1$
+
+    public static final String TAG_VERSION = "version"; //$NON-NLS-1$
+
+    public static final String TAG_PROGRESS_COUNT = "progressCount";  //$NON-NLS-1$
+
+    public static final String TAG_PERSPECTIVES = "perspectives"; //$NON-NLS-1$
+
+    public static final String TAG_PERSPECTIVE = "perspective"; //$NON-NLS-1$
+
+    public static final String TAG_ACTIVE_PERSPECTIVE = "activePerspective"; //$NON-NLS-1$
+
+    public static final String TAG_ACTIVE_PART = "activePart"; //$NON-NLS-1$
+
+    public static final String TAG_ACTION_SET = "actionSet"; //$NON-NLS-1$
+
+    public static final String TAG_ALWAYS_ON_ACTION_SET = "alwaysOnActionSet"; //$NON-NLS-1$
+
+    public static final String TAG_ALWAYS_OFF_ACTION_SET = "alwaysOffActionSet"; //$NON-NLS-1$
+
+    public static final String TAG_SHOW_VIEW_ACTION = "show_view_action"; //$NON-NLS-1$
+
+    public static final String TAG_SHOW_IN_TIME = "show_in_time"; //$NON-NLS-1$
+
+    public static final String TAG_TIME = "time"; //$NON-NLS-1$
+
+    public static final String TAG_NEW_WIZARD_ACTION = "new_wizard_action"; //$NON-NLS-1$
+
+    public static final String TAG_PERSPECTIVE_ACTION = "perspective_action"; //$NON-NLS-1$
+
+    public static final String TAG_HIDE_MENU = "hide_menu_item_id"; //$NON-NLS-1$
+
+    public static final String TAG_HIDE_TOOLBAR = "hide_toolbar_item_id"; //$NON-NLS-1$
+
+    public static final String TAG_VIEW = "view"; //$NON-NLS-1$
+
+    public static final String TAG_LAYOUT = "layout"; //$NON-NLS-1$
+
+    public static final String TAG_EXTENSION = "extension"; //$NON-NLS-1$
+
+    public static final String TAG_NAME = "name"; //$NON-NLS-1$
+
+    public static final String TAG_IMAGE = "image"; //$NON-NLS-1$
+
+    public static final String TAG_LAUNCHER = "launcher"; //$NON-NLS-1$
+
+    public static final String TAG_PLUGIN = "plugin"; //$NON-NLS-1$
+
+    /** deprecated - use TAG_OPEN_MODE */
+    public static final String TAG_INTERNAL = "internal"; //$NON-NLS-1$
+
+    /** deprecated - use TAG_OPEN_MODE */
+    public static final String TAG_OPEN_IN_PLACE = "open_in_place"; //$NON-NLS-1$
+
+    public static final String TAG_PROGRAM_NAME = "program_name"; //$NON-NLS-1$
+
+    public static final String TAG_FAST_VIEWS = "fastViews"; //$NON-NLS-1$
+
+    public static final String TAG_FAST_VIEW_BAR = "fastViewBar"; //$NON-NLS-1$
+
+    public static final String TAG_FAST_VIEW_BARS = "fastViewBars"; //$NON-NLS-1$
+
+    public static final String TAG_GLOBAL_FAST_VIEWS = "globalFastViews"; //$NON-NLS-1$
+
+    public static final String TAG_FAST_GROUPS = "fastGroups"; //$NON-NLS-1$
+
+    public static final String TAG_FIXED = "fixed";//$NON-NLS-1$
+
+    public static final String TAG_CLOSEABLE = "closeable";//$NON-NLS-1$
+
+    public static final String TAG_MOVEABLE = "moveable";//$NON-NLS-1$
+
+    public static final String TAG_APPEARANCE = "appearance"; //$NON-NLS-1$
+
+    public static final String TAG_PRESENTATION = "presentation"; //$NON-NLS-1$
+
+    public static final String TAG_STANDALONE = "standalone";//$NON-NLS-1$
+
+    public static final String TAG_SHOW_TITLE = "showTitle";//$NON-NLS-1$
+
+    public static final String TAG_VIEW_STATE = "viewState"; //$NON-NLS-1$
+
+    public static final String TAG_SINGLETON = "singleton"; //$NON-NLS-1$
+
+    public static final String TAG_EDITOR_REUSE_THRESHOLD = "editorReuseThreshold"; //$NON-NLS-1$
+
+    public static final String TAG_PERSISTABLE = "persistable"; //$NON-NLS-1$
+
+    public static final String TAG_MRU_LIST = "mruList"; //$NON-NLS-1$
+
+    public static final String TAG_PERSPECTIVE_HISTORY = "perspHistory"; //$NON-NLS-1$
+
+    public static final String TAG_WORKING_SET_MANAGER = "workingSetManager"; //$NON-NLS-1$
+
+    public static final String TAG_WORKING_SETS = "workingSets"; //$NON-NLS-1$
+
+    public static final String TAG_WORKING_SET = "workingSet"; //$NON-NLS-1$
+
+    public static final String TAG_ITEM = "item"; //$NON-NLS-1$
+
+    public static final String TAG_EDIT_PAGE_ID = "editPageId"; //$NON-NLS-1$
+
+    public static final String TAG_COOLBAR_LAYOUT = "coolbarLayout"; //$NON-NLS-1$
+
+    public static final String TAG_ITEM_SIZE = "itemSize"; //$NON-NLS-1$
+
+    public static final String TAG_ITEM_X = "x"; //$NON-NLS-1$
+
+    public static final String TAG_ITEM_Y = "y"; //$NON-NLS-1$
+
+    public static final String TAG_ITEM_TYPE = "itemType"; //$NON-NLS-1$
+
+    public static final String TAG_TYPE_SEPARATOR = "typeSeparator"; //$NON-NLS-1$
+
+    public static final String TAG_TYPE_GROUPMARKER = "typeGroupMarker"; //$NON-NLS-1$
+
+    public static final String TAG_TYPE_TOOLBARCONTRIBUTION = "typeToolBarContribution"; //$NON-NLS-1$
+
+    public static final String TAG_TYPE_PLACEHOLDER = "typePlaceholder"; //$NON-NLS-1$
+
+    public static final String TAG_COOLITEM = "coolItem"; //$NON-NLS-1$
+
+    public static final String TAG_INDEX = "index"; //$NON-NLS-1$
+
+    public static final String TAG_PINNED = "pinned"; //$NON-NLS-1$
+
+    public static final String TAG_PATH = "path";//$NON-NLS-1$
+
+    public static final String TAG_TOOLTIP = "tooltip";//$NON-NLS-1$
+
+    public static final String TAG_VIEWS = "views";//$NON-NLS-1$
+
+    public static final String TAG_POSITION = "position";//$NON-NLS-1$
+
+    public static final String TAG_NAVIGATION_HISTORY = "navigationHistory";//$NON-NLS-1$
+
+    public static final String TAG_STICKY_STATE = "stickyState"; //$NON-NLS-1$
+
+    public static final String TAG_ACTIVE = "active";//$NON-NLS-1$
+
+    public static final String TAG_REMOVED = "removed";//$NON-NLS-1$
+
+    public static final String TAG_HISTORY_LABEL = "historyLabel";//$NON-NLS-1$
+
+    public static final String TAG_LOCKED = "locked";//$NON-NLS-1$
+
+    public static final String TAG_OPEN_MODE = "openMode"; //$NON-NLS-1$
+
+    public static final String TAG_STARTUP = "startup"; //$NON-NLS-1$
+
+    public static final String TAG_FAST_VIEW_SIDE = "fastViewLocation"; //$NON-NLS-1$
+
+    public static final String TAG_FAST_VIEW_DATA = "fastViewData"; //$NON-NLS-1$
+
+    public static final String TAG_FAST_VIEW_ORIENTATION = "orientation"; //$NON-NLS-1$
+
+    public static final String TAG_FAST_VIEW_SEL_ID = "selectedTabId"; //$NON-NLS-1$
+
+    public static final String TAG_FAST_VIEW_STYLE = "style"; //$NON-NLS-1$
+
+    public static final String TAG_THEME = "theme";//$NON-NLS-1$
+
+    public static final String TAG_VIEW_LAYOUT_REC = "viewLayoutRec"; //$NON-NLS-1$
+
+    public static final String TAG_PERSPECTIVE_BAR = "perspectiveBar"; //$NON-NLS-1$
+
+    public static final String TAG_TRIM = "trimLayout"; //$NON-NLS-1$
+
+    public static final String TAG_TRIM_AREA = "trimArea"; //$NON-NLS-1$
+
+    public static final String TAG_TRIM_ITEM = "trimItem"; //$NON-NLS-1$
+
+    //Fonts
+    public static final String SMALL_FONT = "org.eclipse.ui.smallFont"; //$NON-NLS-1$
+
+    //Colors
+    public static final String COLOR_HIGHLIGHT = "org.eclipse.ui.highlight"; //$NON-NLS-1$
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IWorkbenchGraphicConstants.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IWorkbenchGraphicConstants.java
new file mode 100644
index 0000000..4b6a30e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IWorkbenchGraphicConstants.java
@@ -0,0 +1,161 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+/**
+ * This class defines constants for looking up resources that are available
+ * only within the Eclipse UI and Eclipse UI Standard Components projects.
+ */
+public interface IWorkbenchGraphicConstants {
+
+    public final static String IMG_ETOOL_IMPORT_WIZ = "IMG_ETOOL_IMPORT_WIZ"; //$NON-NLS-1$
+
+    public final static String IMG_ETOOL_EXPORT_WIZ = "IMG_ETOOL_EXPORT_WIZ"; //$NON-NLS-1$
+
+    public final static String IMG_ETOOL_NEW_PAGE = "IMG_ETOOL_NEW_PAGE"; //$NON-NLS-1$
+
+    public final static String IMG_ETOOL_PIN_EDITOR = "IMG_ETOOL_PIN_EDITOR"; //$NON-NLS-1$
+
+    public final static String IMG_ETOOL_PIN_EDITOR_DISABLED = "IMG_ETOOL_PIN_EDITOR_DISABLED"; //$NON-NLS-1$
+
+    public final static String IMG_ETOOL_HELP_CONTENTS = "IMG_ETOOL_HELP_CONTENTS"; //$NON-NLS-1$
+
+    public final static String IMG_ETOOL_HELP_SEARCH = "IMG_ETOOL_HELP_SEARCH"; //$NON-NLS-1$
+
+
+    //Fast view enabled and disabled icons
+    public final static String IMG_ETOOL_NEW_FASTVIEW = "IMG_ETOOL_NEW_FASTVIEW"; //$NON-NLS-1$
+    public final static String IMG_DTOOL_NEW_FASTVIEW = "IMG_DTOOL_NEW_FASTVIEW"; //$NON-NLS-1$
+
+    // TrimStack buttons
+    public final static String IMG_ETOOL_RESTORE_TRIMPART = "IMG_ETOOL_RESTORE_TRIMPART"; //$NON-NLS-1$
+    public final static String IMG_ETOOL_EDITOR_TRIMPART = "IMG_ETOOL_EDITOR_TRIMPART"; //$NON-NLS-1$
+
+    // local toolbars
+
+    public final static String IMG_LCL_CLOSE_VIEW = "IMG_LCL_CLOSE_VIEW"; //$NON-NLS-1$
+
+    public final static String IMG_LCL_PIN_VIEW = "IMG_LCL_PIN_VIEW"; //$NON-NLS-1$
+
+    public final static String IMG_LCL_MIN_VIEW = "IMG_LCL_MIN_VIEW"; //$NON-NLS-1$
+
+    public final static String IMG_LCL_RENDERED_VIEW_MENU = "IMG_LCL_RENDERED_VIEW_MENU"; //$NON-NLS-1$
+
+    public final static String IMG_LCL_VIEW_MENU = "IMG_LCL_VIEW_MENU"; //$NON-NLS-1$
+
+    public final static String IMG_LCL_BUTTON_MENU = "IMG_LCL_BUTTON_MENU"; //$NON-NLS-1$
+
+    public final static String IMG_LCL_SELECTED_MODE = "IMG_LCL_SELECTED_MODE"; //$NON-NLS-1$
+
+    public final static String IMG_LCL_SHOWCHILD_MODE = "IMG_LCL_SHOWCHILD_MODE"; //$NON-NLS-1$
+
+    public final static String IMG_LCL_SHOWSYNC_RN = "IMG_LCL_SHOWSYNC_RN"; //$NON-NLS-1$
+
+    public static final String IMG_LCL_CLOSE_VIEW_THIN = "IMG_LCL_CLOSE_VIEW_THIN"; //$NON-NLS-1$
+
+    public static final String IMG_LCL_MIN_VIEW_THIN = "IMG_LCL_MIN_VIEW_THIN"; //$NON-NLS-1$
+
+    public static final String IMG_LCL_MAX_VIEW_THIN = "IMG_LCL_MAX_VIEW_THIN"; //$NON-NLS-1$
+
+    public static final String IMG_LCL_RESTORE_VIEW_THIN = "IMG_LCL_RESTORE_VIEW_THIN"; //$NON-NLS-1$
+
+    public static final String IMG_LCL_SHOW_TOOLBAR_THIN = "IMG_LCL_SHOW_TOOLBAR_THIN"; //$NON-NLS-1$
+
+    public static final String IMG_LCL_HIDE_TOOLBAR_THIN = "IMG_LCL_HIDE_TOOLBAR_THIN"; //$NON-NLS-1$
+
+    public static final String IMG_LCL_VIEW_MENU_THIN = "IMG_LCL_VIEW_MENU_THIN"; //$NON-NLS-1$
+
+    //wizard images
+    public final static String IMG_WIZBAN_NEW_WIZ = "IMG_WIZBAN_NEW_WIZ"; //$NON-NLS-1$
+
+    public final static String IMG_WIZBAN_EXPORT_WIZ = "IMG_WIZBAN_EXPORT_WIZ"; //$NON-NLS-1$
+
+    public final static String IMG_WIZBAN_IMPORT_WIZ = "IMG_WIZBAN_IMPORT_WIZ"; //$NON-NLS-1$
+
+    public final static String IMG_WIZBAN_EXPORT_PREF_WIZ = "IMG_WIZBAN_EXPORT_PREF_WIZ"; //$NON-NLS-1$
+
+    public final static String IMG_WIZBAN_IMPORT_PREF_WIZ = "IMG_WIZBAN_IMPORT_PREF_WIZ"; //$NON-NLS-1$
+
+    public final static String IMG_WIZBAN_WORKINGSET_WIZ = "IMG_WIZBAN_WORKINGSET_WIZ"; //$NON-NLS-1$
+
+    public final static String IMG_VIEW_DEFAULTVIEW_MISC = "IMG_VIEW_DEFAULTVIEW_MISC"; //$NON-NLS-1$
+
+    /**
+     * Identifies an activity category.
+     *
+     * @since 3.0
+     */
+    public static final String IMG_OBJ_ACTIVITY_CATEGORY = "IMG_OBJ_ACTIVITY_CATEGORY"; //$NON-NLS-1$
+
+    /**
+     * Identifies an activity.
+     *
+     * @since 3.0
+     */
+    public static final String IMG_OBJ_ACTIVITY = "IMG_OBJ_ACTIVITY"; //$NON-NLS-1$
+
+    /**
+     * Identifies a font.
+     *
+     * @since 3.0
+     */
+    public static final String IMG_OBJ_FONT = "IMG_OBJ_FONT"; //$NON-NLS-1$
+
+    /**
+     * Identifies a theme category.
+     *
+     * @since 3.0
+     */
+    public static final String IMG_OBJ_THEME_CATEGORY = "IMG_OBJ_THEME_CATEGORY"; //$NON-NLS-1$
+
+    /**
+     * Generic working set icon.
+     *
+     * @since 3.2
+     */
+    public static final String IMG_OBJ_WORKING_SETS = "IMG_OBJ_WORKING_SETS"; //$NON-NLS-1$
+
+    /**
+     * Separator icon for selection dialogs.
+     */
+    public static final String IMG_OBJ_SEPARATOR = "IMG_OBJ_SEPARATOR"; //$NON-NLS-1$
+
+    /**
+     * Default icon for Quick Access nodes.
+     */
+    public static final String IMG_OBJ_NODE = "IMG_OBJ_NODE"; //$NON-NLS-1$
+
+    /**
+     * Default icon for Quick Access elements.
+     */
+    public static final String IMG_OBJ_ELEMENT = "IMG_OBJ_ELEMENT"; //$NON-NLS-1$
+
+    /**
+     * Icon for signed objects (such as bundles).
+     *
+     * @since 3.3
+     */
+	public static final String IMG_OBJ_SIGNED_YES = "IMG_OBJ_SIGNED_YES"; //$NON-NLS-1$
+
+	/**
+     * Icon for unsigned objects (such as bundles).
+     *
+     * @since 3.3
+     */
+	public static final String IMG_OBJ_SIGNED_NO = "IMG_OBJ_SIGNED_NO"; //$NON-NLS-1$
+
+	/**
+     * Icon for objects whos signing state is not known (such as bundles).
+     *
+     * @since 3.3
+     */
+	public static final String IMG_OBJ_SIGNED_UNKNOWN = "IMG_OBJ_SIGNED_UNKNOWN"; //$NON-NLS-1$
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IWorkbenchHelpContextIds.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IWorkbenchHelpContextIds.java
new file mode 100644
index 0000000..c360a74
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IWorkbenchHelpContextIds.java
@@ -0,0 +1,340 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Sebastian Davids <sdavids@gmx.de> - Fix for bug 95292 - [Intro]
+ *     		Help > Welcome missing F1 context
+ *******************************************************************************/
+
+package org.eclipse.ui.internal;
+
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * Help context ids for the workbench.
+ * <p>
+ * This interface contains constants only; it is not intended to be implemented
+ * or extended.
+ * </p>
+ *
+ * @issue this class has been xcloned to org.eclipse.ui.internal.ide package;
+ *        remove all IDE-specific constants from here
+ */
+public interface IWorkbenchHelpContextIds {
+	public static final String PREFIX = PlatformUI.PLUGIN_ID + "."; //$NON-NLS-1$
+
+	// Missing context help
+	public static final String MISSING = PREFIX + "missing"; //$NON-NLS-1$
+
+	// Actions
+
+	public static final String DOCK_ON_PERSPECTIVE_ACTION = PREFIX
+			+ "dock_on_perspective_action_context"; //$NON-NLS-1$
+
+	public static final String SHOW_TEXT_PERSPECTIVE_ACTION = PREFIX
+			+ "show_text_perspective_action_context"; //$NON-NLS-1$
+
+	public static final String PROPERTY_DIALOG_ACTION = PREFIX
+			+ "property_dialog_action_context"; //$NON-NLS-1$
+
+	public static final String NEW_ACTION = PREFIX + "new_action_context"; //$NON-NLS-1$
+
+	public static final String IMPORT_ACTION = PREFIX + "import_action_context"; //$NON-NLS-1$
+
+	public static final String EXPORT_ACTION = PREFIX + "export_action_context"; //$NON-NLS-1$
+
+	public static final String SAVE_PERSPECTIVE_ACTION = PREFIX
+			+ "save_perspective_action_context"; //$NON-NLS-1$
+
+	public static final String SAVE_AS_ACTION = PREFIX
+			+ "save_as_action_context"; //$NON-NLS-1$
+
+	public static final String SAVE_ALL_ACTION = PREFIX
+			+ "save_all_action_context"; //$NON-NLS-1$
+
+	public static final String SAVE_ACTION = PREFIX + "save_action_context"; //$NON-NLS-1$
+
+	public static final String ABOUT_ACTION = PREFIX + "about_action_context"; //$NON-NLS-1$
+
+	public static final String CLOSE_ALL_ACTION = PREFIX
+			+ "close_all_action_context"; //$NON-NLS-1$
+
+	public static final String CLOSE_OTHERS_ACTION = PREFIX
+			+ "close_others_action_context"; //$NON-NLS-1$
+
+	public static final String LOCK_TOOLBAR_ACTION = PREFIX
+			+ "lock_toolbar_action_context"; //$NON-NLS-1$
+
+	public static final String CLOSE_PAGE_ACTION = PREFIX
+			+ "close_page_action_context"; //$NON-NLS-1$
+
+	public static final String CLOSE_PART_ACTION = PREFIX
+			+ "close_part_action_context"; //$NON-NLS-1$
+
+	public static final String EDIT_ACTION_SETS_ACTION = PREFIX
+			+ "edit_action_sets_action_context"; //$NON-NLS-1$
+
+	public static final String DELETE_RETARGET_ACTION = PREFIX
+			+ "delete_retarget_action_context"; //$NON-NLS-1$
+
+	public static final String CLOSE_ALL_PAGES_ACTION = PREFIX
+			+ "close_all_pages_action_context"; //$NON-NLS-1$
+
+	public static final String OPEN_NEW_WINDOW_ACTION = PREFIX
+			+ "open_new_window_action_context"; //$NON-NLS-1$
+
+	public static final String OPEN_PREFERENCES_ACTION = PREFIX
+			+ "open_preferences_action_context"; //$NON-NLS-1$
+
+	public static final String QUIT_ACTION = PREFIX + "quit_action_context"; //$NON-NLS-1$
+
+	public static final String RESET_PERSPECTIVE_ACTION = PREFIX
+			+ "reset_perspective_action_context"; //$NON-NLS-1$
+
+	public static final String TOGGLE_EDITORS_VISIBILITY_ACTION = PREFIX
+			+ "target_editors_visibility_action_context"; //$NON-NLS-1$
+
+	public static final String SHOW_VIEW_ACTION = PREFIX
+			+ "show_view_action_context"; //$NON-NLS-1$
+
+	public static final String SHOW_VIEW_OTHER_ACTION = PREFIX
+			+ "show_view_other_action_context"; //$NON-NLS-1$
+
+	public static final String OPEN_PERSPECTIVE_ACTION = PREFIX
+			+ "open_perspective_action_context"; //$NON-NLS-1$
+
+	public static final String CLOSE_ALL_SAVED_ACTION = PREFIX
+			+ "close_all_saved_action_context"; //$NON-NLS-1$
+
+	public static final String SHOW_VIEW_MENU_ACTION = PREFIX
+			+ "show_view_menu_action_context"; //$NON-NLS-1$
+
+	public static final String WORKBENCH_EDITORS_ACTION = PREFIX
+			+ "workbench_editors_action_context"; //$NON-NLS-1$
+
+	public static final String CELL_CUT_ACTION = PREFIX
+			+ "cell_cut_action_context"; //$NON-NLS-1$
+
+	public static final String CELL_COPY_ACTION = PREFIX
+			+ "cell_copy_action_context"; //$NON-NLS-1$
+
+	public static final String CELL_PASTE_ACTION = PREFIX
+			+ "cell_paste_action_context"; //$NON-NLS-1$
+
+	public static final String CELL_DELETE_ACTION = PREFIX
+			+ "cell_delete_action_context"; //$NON-NLS-1$
+
+	public static final String CELL_FIND_ACTION = PREFIX
+			+ "cell_find_action_context"; //$NON-NLS-1$
+
+	public static final String CELL_SELECT_ALL_ACTION = PREFIX
+			+ "cell_select_all_action_context"; //$NON-NLS-1$
+
+	public static final String CELL_UNDO_ACTION = PREFIX
+			+ "cell_undo_action_context"; //$NON-NLS-1$
+
+	public static final String CELL_REDO_ACTION = PREFIX
+			+ "cell_redo_action_context"; //$NON-NLS-1$
+
+	public static final String SHOW_PART_PANE_MENU_ACTION = PREFIX
+			+ "show_part_pane_menu_action_context"; //$NON-NLS-1$
+
+	public static final String CYCLE_PART_FORWARD_ACTION = PREFIX
+			+ "cycle_part_forward_action_context"; //$NON-NLS-1$
+
+	public static final String CYCLE_PART_BACKWARD_ACTION = PREFIX
+			+ "cycle_part_backward_action_context"; //$NON-NLS-1$
+
+	public static final String CYCLE_EDITOR_FORWARD_ACTION = PREFIX
+			+ "cycle_editor_forward_action_context"; //$NON-NLS-1$
+
+	public static final String CYCLE_EDITOR_BACKWARD_ACTION = PREFIX
+			+ "cycle_editor_backward_action_context"; //$NON-NLS-1$
+
+	public static final String CYCLE_PERSPECTIVE_FORWARD_ACTION = PREFIX
+			+ "cycle_perspective_forward_action_context"; //$NON-NLS-1$
+
+	public static final String CYCLE_PERSPECTIVE_BACKWARD_ACTION = PREFIX
+			+ "cycle_perspective_backward_action_context"; //$NON-NLS-1$
+
+	public static final String ACTIVATE_EDITOR_ACTION = PREFIX
+			+ "activate_editor_action_context"; //$NON-NLS-1$
+
+	public static final String MAXIMIZE_PART_ACTION = PREFIX
+			+ "maximize_part_action_context"; //$NON-NLS-1$
+
+	public static final String MINIMIZE_PART_ACTION = PREFIX
+			+ "minimize_part_action_context"; //$NON-NLS-1$
+
+	public static final String SELECT_WORKING_SET_ACTION = PREFIX
+			+ "select_working_set_action_context"; //$NON-NLS-1$
+
+	public static final String CLEAR_WORKING_SET_ACTION = PREFIX
+			+ "clear_working_set_action_context"; //$NON-NLS-1$
+
+	public static final String EDIT_WORKING_SET_ACTION = PREFIX
+			+ "edit_working_set_action_context"; //$NON-NLS-1$
+
+	public static final String SHOW_IN_ACTION = PREFIX
+			+ "show_in_action_context"; //$NON-NLS-1$
+
+	public static final String NAVIGATION_HISTORY_FORWARD = PREFIX
+			+ "navigation_history_forward"; //$NON-NLS-1$
+
+	public static final String NAVIGATION_HISTORY_BACKWARD = PREFIX
+			+ "navigation_history_backward"; //$NON-NLS-1$
+
+	public static final String HELP_CONTENTS_ACTION = PREFIX
+			+ "help_contents_action_context"; //$NON-NLS-1$
+
+	public static final String HELP_SEARCH_ACTION = PREFIX
+			+ "help_search_action_context"; //$NON-NLS-1$
+
+	public static final String DYNAMIC_HELP_ACTION = PREFIX
+			+ "dynamic_help_action_context"; //$NON-NLS-1$
+
+	public static final String INTRO_ACTION = PREFIX + "intro_action_context"; //$NON-NLS-1$
+
+	// // Dialogs
+	public static final String ABOUT_DIALOG = PREFIX + "about_dialog_context"; //$NON-NLS-1$
+
+	public static final String ABOUT_PLUGINS_DIALOG = PREFIX
+			+ "about_plugins_dialog_context"; //$NON-NLS-1$
+
+	public static final String ABOUT_FEATURES_PLUGINS_DIALOG = PREFIX
+			+ "about_features_plugins_dialog_context"; //$NON-NLS-1$
+
+	public static final String ABOUT_FEATURES_DIALOG = PREFIX
+			+ "about_features_dialog_context"; //$NON-NLS-1$
+
+	public static final String SYSTEM_SUMMARY_DIALOG = PREFIX
+			+ "system_summary_dialog_context"; //$NON-NLS-1$
+
+	public static final String ACTION_SET_SELECTION_DIALOG = PREFIX
+			+ "action_set_selection_dialog_context"; //$NON-NLS-1$
+
+	public static final String EDITOR_SELECTION_DIALOG = PREFIX
+			+ "editor_selection_dialog_context"; //$NON-NLS-1$
+
+	public static final String FILE_EXTENSION_DIALOG = PREFIX
+			+ "file_extension_dialog_context"; //$NON-NLS-1$
+
+	public static final String PREFERENCE_DIALOG = PREFIX
+			+ "preference_dialog_context"; //$NON-NLS-1$
+
+	public static final String PROBLEMS_VIEW = PREFIX
+			+ "problem_view_context";//$NON-NLS-1$
+
+	public static final String PROPERTY_DIALOG = PREFIX
+			+ "property_dialog_context"; //$NON-NLS-1$
+
+	public static final String SAVE_PERSPECTIVE_DIALOG = PREFIX
+			+ "save_perspective_dialog_context"; //$NON-NLS-1$
+
+	public static final String SELECT_PERSPECTIVE_DIALOG = PREFIX
+			+ "select_perspective_dialog_context"; //$NON-NLS-1$
+
+	public static final String SHOW_VIEW_DIALOG = PREFIX
+			+ "show_view_dialog_context"; //$NON-NLS-1$
+
+	public static final String TYPE_FILTERING_DIALOG = PREFIX
+			+ "type_filtering_dialog_context"; //$NON-NLS-1$
+
+	public static final String LIST_SELECTION_DIALOG = PREFIX
+			+ "list_selection_dialog_context"; //$NON-NLS-1$
+
+	public static final String YES_NO_CANCEL_LIST_SELECTION_DIALOG = PREFIX
+			+ "yes_no_cancel_list_selection_dialog_context"; //$NON-NLS-1$
+
+	public static final String WORKING_SET_SELECTION_DIALOG = PREFIX
+			+ "working_set_selection_dialog_context"; //$NON-NLS-1$
+
+	public static final String WORKBENCH_EDITORS_DIALOG = PREFIX
+			+ "workbench_editors_dialog"; //$NON-NLS-1$
+
+	// // Editors
+	public static final String FILE_EDITORS_PREFERENCE_PAGE = PREFIX
+			+ "file_editors_preference_page_context"; //$NON-NLS-1$
+
+	public static final String PERSPECTIVES_PREFERENCE_PAGE = PREFIX
+			+ "perspectives_preference_page_context"; //$NON-NLS-1$
+
+	public static final String VIEWS_PREFERENCE_PAGE = PREFIX
+			+ "views_preference_page_context"; //$NON-NLS-1$
+
+	public static final String FONTS_PREFERENCE_PAGE = PREFIX
+			+ "font_preference_page_context"; //$NON-NLS-1$
+
+	public static final String KEYS_PREFERENCE_PAGE = PREFIX
+			+ "keys_preference_page_context"; //$NON-NLS-1$
+
+	public static final String WORKBENCH_EDITOR_PREFERENCE_PAGE = PREFIX
+			+ "workbench_editor_preference_page_context"; //$NON-NLS-1$
+
+	public static final String CONTENT_TYPES_PREFERENCE_PAGE = PREFIX
+			+ "content_types_preference_page_context"; //$NON-NLS-1$
+
+	public static final String WORKBENCH_PREFERENCE_PAGE = PREFIX
+			+ "workbench_preference_page_context"; //$NON-NLS-1$
+
+	public static final String GLOBALIZATION_PREFERENCE_PAGE = PREFIX
+			+ "globalization_preference_page_context"; //$NON-NLS-1$
+
+	public static final String DECORATORS_PREFERENCE_PAGE = PREFIX
+			+ "decorators_preference_page_context"; //$NON-NLS-1$
+
+	public static final String STARTUP_PREFERENCE_PAGE = PREFIX
+			+ "startup_preference_page_context"; //$NON-NLS-1$
+
+	public static final String WORKSPACES_PREFERENCE_PAGE = PREFIX
+	+ "workspaces_preference_page_context"; //$NON-NLS-1$
+
+	public static final String RESPONSIVE_UI = PREFIX + "responsive_ui_context"; //$NON-NLS-1$
+
+	// // Windows
+	public static final String DETACHED_WINDOW = PREFIX
+			+ "detached_window_context"; //$NON-NLS-1$
+
+	public static final String WORKBENCH_WINDOW = PREFIX
+			+ "workbench_window_context"; //$NON-NLS-1$
+
+	// // Wizard pages
+
+	public static final String NEW_WIZARD_SELECTION_WIZARD_PAGE = PREFIX
+			+ "new_wizard_selection_wizard_page_context"; //$NON-NLS-1$
+
+	public static final String EXPORT_WIZARD_SELECTION_WIZARD_PAGE = PREFIX
+			+ "export_wizard_selection_wizard_page_context"; //$NON-NLS-1$
+
+	public static final String IMPORT_WIZARD_SELECTION_WIZARD_PAGE = PREFIX
+			+ "import_wizard_selection_wizard_page_context"; //$NON-NLS-1$
+
+	public static final String WORKING_SET_TYPE_PAGE = PREFIX
+			+ "working_set_type_page"; //$NON-NLS-1$
+
+	// Wizards
+	public static final String NEW_WIZARD = PREFIX + "new_wizard_context"; //$NON-NLS-1$
+
+	public static final String NEW_WIZARD_SHORTCUT = PREFIX
+			+ "new_wizard_shortcut_context"; //$NON-NLS-1$
+
+	public static final String IMPORT_WIZARD = PREFIX + "import_wizard_context"; //$NON-NLS-1$
+
+	public static final String EXPORT_WIZARD = PREFIX + "export_wizard_context"; //$NON-NLS-1$
+
+	public static final String WORKING_SET_NEW_WIZARD = PREFIX
+			+ "working_set_new_wizard_context"; //$NON-NLS-1$
+
+	public static final String WORKING_SET_EDIT_WIZARD = PREFIX
+			+ "working_set_edit_wizard_context"; //$NON-NLS-1$
+
+	public static final String CAPABILITY_PREFERENCE_PAGE = PREFIX
+			+ "capabilities_preference_page_context"; //$NON-NLS-1$
+	public static final String TOGGLE_COOLBAR_ACTION = PREFIX
+			+ "toggle_coolbar_action"; //$NON-NLS-1$
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IWorkbenchThemeConstants.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IWorkbenchThemeConstants.java
new file mode 100644
index 0000000..19b3cf8
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IWorkbenchThemeConstants.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal;
+
+/**
+ * A source of color/font/theme data constants used throughout the workbench.
+ *
+ * @since 3.0
+ */
+public interface IWorkbenchThemeConstants {
+    public static final String TAB_TEXT_FONT = "org.eclipse.ui.workbench.TAB_TEXT_FONT"; //$NON-NLS-1$
+
+    public static final String ACTIVE_TAB_TEXT_COLOR = "org.eclipse.ui.workbench.ACTIVE_TAB_TEXT_COLOR"; //$NON-NLS-1$
+
+    public static final String ACTIVE_NOFOCUS_TAB_TEXT_COLOR = "org.eclipse.ui.workbench.ACTIVE_NOFOCUS_TAB_TEXT_COLOR"; //$NON-NLS-1$
+
+    public static final String INACTIVE_TAB_TEXT_COLOR = "org.eclipse.ui.workbench.INACTIVE_TAB_TEXT_COLOR"; //$NON-NLS-1$
+
+    public static final String ACTIVE_TAB_BG_START = "org.eclipse.ui.workbench.ACTIVE_TAB_BG_START"; //$NON-NLS-1$
+
+    public static final String ACTIVE_TAB_BG_END = "org.eclipse.ui.workbench.ACTIVE_TAB_BG_END"; //$NON-NLS-1$
+
+    public static final String ACTIVE_TAB_HIGHLIGHT = "org.eclipse.ui.workbench.ACTIVE_TAB_HIGHLIGHT"; //$NON-NLS-1$
+
+    public static final String ACTIVE_TAB_HIGHLIGHT_START = "org.eclipse.ui.workbench.ACTIVE_TAB_HIGHLIGHT_START"; //$NON-NLS-1$
+
+    public static final String ACTIVE_NOFOCUS_TAB_BG_START = "org.eclipse.ui.workbench.ACTIVE_NOFOCUS_TAB_BG_START"; //$NON-NLS-1$
+
+    public static final String ACTIVE_NOFOCUS_TAB_BG_END = "org.eclipse.ui.workbench.ACTIVE_NOFOCUS_TAB_BG_END"; //$NON-NLS-1$
+
+    public static final String INACTIVE_TAB_BG_START = "org.eclipse.ui.workbench.INACTIVE_TAB_BG_START"; //$NON-NLS-1$
+
+    public static final String INACTIVE_TAB_BG_END = "org.eclipse.ui.workbench.INACTIVE_TAB_BG_END"; //$NON-NLS-1$
+
+    public static final String ACTIVE_TAB_PERCENT = "org.eclipse.ui.workbench.ACTIVE_TAB_PERCENT"; //$NON-NLS-1$
+
+    public static final String ACTIVE_NOFOCUS_TAB_PERCENT = "org.eclipse.ui.workbench.ACTIVE_NOFOCUS_TAB_PERCENT"; //$NON-NLS-1$
+
+    public static final String INACTIVE_TAB_PERCENT = "org.eclipse.ui.workbench.INACTIVE_TAB_PERCENT"; //$NON-NLS-1$
+
+    public static final String ACTIVE_TAB_VERTICAL = "org.eclipse.ui.workbench.ACTIVE_TAB_VERTICAL"; //$NON-NLS-1$
+
+    public static final String ACTIVE_NOFOCUS_TAB_VERTICAL = "org.eclipse.ui.workbench.ACTIVE_NOFOCUS_TAB_VERTICAL"; //$NON-NLS-1$
+
+    public static final String INACTIVE_TAB_VERTICAL = "org.eclipse.ui.workbench.INACTIVE_TAB_VERTICAL"; //$NON-NLS-1$
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ImageCycleFeedbackBase.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ImageCycleFeedbackBase.java
new file mode 100644
index 0000000..08fdcd3
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ImageCycleFeedbackBase.java
@@ -0,0 +1,163 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2016 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
+ *     Friederike Schertel <friederike@schertel.org> - Bug 478336
+ ******************************************************************************/
+
+package org.eclipse.ui.internal;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+/**
+ * Base class for Cyclic animations.
+ *
+ * @since 3.3
+ *
+ */
+public abstract class ImageCycleFeedbackBase extends AnimationFeedbackBase {
+	protected Image[] images;
+	protected Image stoppedImage;
+	private Image offScreenImage;
+	private GC offScreenImageGC;
+	private int imageDataIndex;
+	private Image image;
+	private ImageData imageData;
+	protected Display display;
+	protected Color background;
+
+	/**
+	 * @param parentShell
+	 */
+	public ImageCycleFeedbackBase(Shell parentShell) {
+		super(parentShell);
+		// TODO Auto-generated constructor stub
+	}
+
+	/**
+	 *
+	 * @param parentShell
+	 * @param images :
+	 *            an array of images
+	 */
+	public ImageCycleFeedbackBase(Shell parentShell, Image[] images) {
+		super(parentShell);
+		this.images = images;
+	}
+
+	/**
+	 * Set the image during progress without caching.
+	 *
+	 * @param image
+	 */
+	public abstract void showImage(Image image);
+
+	/**
+	 * Save initial Image which would be stoppedImage
+	 *
+	 */
+	public abstract void saveStoppedImage();
+
+	/**
+	 * Set the stopped Image upon animation completion
+	 *
+	 * @param image
+	 */
+	public abstract void setStoppedImage(Image image);
+
+	@Override
+	public void dispose() {
+		if (stoppedImage == null || stoppedImage.isDisposed())
+			return;
+		setStoppedImage(stoppedImage);
+
+		if (offScreenImageGC != null && !offScreenImageGC.isDisposed())
+			offScreenImageGC.dispose();
+
+		if (offScreenImage != null && !offScreenImage.isDisposed())
+			offScreenImage.dispose();
+	}
+
+	@Override
+	public boolean jobInit(AnimationEngine engine) {
+		return super.jobInit(engine);
+	}
+
+	@Override
+	public void renderStep(AnimationEngine engine) {
+		if (offScreenImage == null) {
+			offScreenImage = getOffscreenImage();
+		}
+
+		try {
+			imageDataIndex = (imageDataIndex + 1) % images.length;
+			image = images[imageDataIndex];
+			imageData = image.getImageData();
+
+			offScreenImageGC.drawImage(image, 0, 0, imageData.width,
+					imageData.height, imageData.x, imageData.y,
+					imageData.width, imageData.height);
+
+			final Image finalImage = image;
+
+			display.syncExec(() -> showImage(finalImage));
+
+			/*
+			 * Sleep for the specified delay time (adding commonly-used
+			 * slow-down fudge factors).
+			 */
+			// try {
+			// Thread.sleep(30);
+			// } catch (InterruptedException e) {
+			// }
+			if (images == null)
+				return;
+		} catch (SWTException ex) {
+			IStatus status = StatusUtil.newStatus(WorkbenchPlugin.PI_WORKBENCH,
+					ex);
+			StatusManager.getManager().handle(status);
+		}
+	}
+
+	private Image getOffscreenImage() {
+		saveStoppedImage();
+		imageDataIndex = 0;
+		image = images[imageDataIndex];
+		imageData = image.getImageData();
+		/*
+		 * Create an off-screen image to draw on, and fill it with the shell
+		 * background.
+		 */
+		offScreenImage = new Image(display, imageData.width, imageData.height);
+
+		//RAP
+//		offScreenImageGC = new GC(offScreenImage);
+//		offScreenImageGC.setBackground(background);
+//		offScreenImageGC.fillRectangle(0, 0, imageData.width, imageData.height);
+//
+//		/*
+//		 * Create the first image and draw it on the off-screen image.
+//		 */
+//
+//		offScreenImageGC.drawImage(image, 0, 0, imageData.width,
+//				imageData.height, imageData.x, imageData.y, imageData.width,
+//				imageData.height);
+
+		return offScreenImage;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IntModel.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IntModel.java
new file mode 100644
index 0000000..7649848
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/IntModel.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal;
+
+/**
+ * Represents a single integer that can send notifications when it changes.
+ * IChangeListeners can be attached which will receive notifications whenever
+ * the integer changes.
+ */
+public class IntModel extends Model {
+    public IntModel(int initialValue) {
+		super(Integer.valueOf(initialValue));
+    }
+
+    /**
+     * Sets the value of the integer and notifies all
+     * change listeners except for the one that caused the change.
+     *
+     * @param newValue the new value of the integer
+     */
+    public void set(int newValue, IChangeListener source) {
+		setState(Integer.valueOf(newValue), source);
+    }
+
+    /**
+     * Sets the value of the integer and notifies all change listeners
+     * of the change.
+     *
+     * @param newValue the new value of the integer
+     */
+    public void set(int newValue) {
+		setState(Integer.valueOf(newValue), null);
+    }
+
+    /**
+     * Returns the value of the integer.
+     *
+     * @return the value of the integer
+     */
+    public int get() {
+        return ((Integer) getState()).intValue();
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/InternalHandlerUtil.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/InternalHandlerUtil.java
new file mode 100644
index 0000000..d60ed13
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/InternalHandlerUtil.java
@@ -0,0 +1,195 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal;
+
+import java.util.Collection;
+
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchSite;
+import org.eclipse.ui.IWorkbenchWindow;
+
+/**
+ * Some common utilities for working with handlers and IEvaluationContexts in
+ * Platform UI.
+ * <p>
+ * <b>Note</b>: this class should not be instantiated or extended by clients.
+ * </p>
+ * <p>
+ * <strong>PROVISIONAL</strong>. This class or interface has been added as part
+ * of a work in progress. There is a guarantee neither that this API will work
+ * nor that it will remain the same. Please do not use this API without
+ * consulting with the Platform/UI team.
+ * </p>
+ *
+ * @since 3.3
+ */
+public class InternalHandlerUtil {
+	/**
+	 * Extract the variable.
+	 *
+	 * @param appContext
+	 *            The application context
+	 * @param name
+	 *            The variable name to extract.
+	 * @return The object from the application context, or <code>null</code>
+	 *         if it could not be found.
+	 */
+	public static Object getVariable(Object appContext, String name) {
+		if (appContext instanceof IEvaluationContext) {
+			return ((IEvaluationContext) appContext).getVariable(name);
+		}
+		return null;
+	}
+
+	/**
+	 * Return the active contexts.
+	 *
+	 * @param appContext
+	 *            The execution appContext that contains the application context
+	 * @return a collection of String contextIds, or <code>null</code>.
+	 */
+	public static Collection getActiveContexts(Object appContext) {
+		Object o = getVariable(appContext, ISources.ACTIVE_CONTEXT_NAME);
+		if (o instanceof Collection) {
+			return (Collection) o;
+		}
+		return null;
+	}
+
+	/**
+	 * Return the active shell. Is not necessarily the active workbench window
+	 * shell.
+	 *
+	 * @param appContext
+	 *            The execution appContext that contains the application context
+	 * @return the active shell, or <code>null</code>.
+	 */
+	public static Shell getActiveShell(Object appContext) {
+		Object o = getVariable(appContext, ISources.ACTIVE_SHELL_NAME);
+		if (o instanceof Shell) {
+			return (Shell) o;
+		}
+		return null;
+	}
+
+	/**
+	 * Return the active workbench window.
+	 *
+	 * @param appContext
+	 *            The execution appContext that contains the application context
+	 * @return the active workbench window, or <code>null</code>.
+	 */
+	public static IWorkbenchWindow getActiveWorkbenchWindow(Object appContext) {
+		Object o = getVariable(appContext,
+				ISources.ACTIVE_WORKBENCH_WINDOW_NAME);
+		if (o instanceof IWorkbenchWindow) {
+			return (IWorkbenchWindow) o;
+		}
+		return null;
+	}
+
+	/**
+	 * Return the active editor.
+	 *
+	 * @param appContext
+	 *            The execution appContext that contains the application context
+	 * @return the active editor, or <code>null</code>.
+	 */
+	public static IEditorPart getActiveEditor(Object appContext) {
+		Object o = getVariable(appContext, ISources.ACTIVE_EDITOR_NAME);
+		if (o instanceof IEditorPart) {
+			return (IEditorPart) o;
+		}
+		return null;
+	}
+
+	/**
+	 * Return the part id of the active editor.
+	 *
+	 * @param appContext
+	 *            The execution appContext that contains the application context
+	 * @return the part id of the active editor, or <code>null</code>.
+	 */
+	public static String getActiveEditorId(Object appContext) {
+		Object o = getVariable(appContext, ISources.ACTIVE_EDITOR_ID_NAME);
+		if (o instanceof String) {
+			return (String) o;
+		}
+		return null;
+	}
+
+	/**
+	 * Return the active part.
+	 *
+	 * @param appContext
+	 *            The execution appContext that contains the application context
+	 * @return the active part, or <code>null</code>.
+	 */
+	public static IWorkbenchPart getActivePart(Object appContext) {
+		Object o = getVariable(appContext, ISources.ACTIVE_PART_NAME);
+		if (o instanceof IWorkbenchPart) {
+			return (IWorkbenchPart) o;
+		}
+		return null;
+	}
+
+	/**
+	 * Return the part id of the active part.
+	 *
+	 * @param appContext
+	 *            The execution appContext that contains the application context
+	 * @return the part id of the active part, or <code>null</code>.
+	 */
+	public static String getActivePartId(Object appContext) {
+		Object o = getVariable(appContext, ISources.ACTIVE_PART_ID_NAME);
+		if (o instanceof String) {
+			return (String) o;
+		}
+		return null;
+	}
+
+	/**
+	 * Return the active part site.
+	 *
+	 * @param appContext
+	 *            The execution appContext that contains the application context
+	 * @return the active part site, or <code>null</code>.
+	 */
+	public static IWorkbenchSite getActiveSite(Object appContext) {
+		Object o = getVariable(appContext, ISources.ACTIVE_SITE_NAME);
+		if (o instanceof IWorkbenchSite) {
+			return (IWorkbenchSite) o;
+		}
+		return null;
+	}
+
+	/**
+	 * Return the current selection.
+	 *
+	 * @param appContext
+	 *            The execution appContext that contains the application context
+	 * @return the current selection, or <code>null</code>.
+	 */
+	public static ISelection getCurrentSelection(Object appContext) {
+		Object o = getVariable(appContext,
+				ISources.ACTIVE_CURRENT_SELECTION_NAME);
+		if (o instanceof ISelection) {
+			return (ISelection) o;
+		}
+		return null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/InternalSaveable.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/InternalSaveable.java
new file mode 100644
index 0000000..39651de
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/InternalSaveable.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal;
+
+import org.eclipse.core.runtime.jobs.Job;
+
+/**
+ * @since 3.3
+ *
+ */
+public class InternalSaveable {
+
+	private Job backgroundSaveJob;
+
+	/* package */Job getBackgroundSaveJob() {
+		return backgroundSaveJob;
+	}
+
+	/* package */void setBackgroundSaveJob(Job backgroundSaveJob) {
+		this.backgroundSaveJob = backgroundSaveJob;
+	}
+
+	/* package */ boolean isSavingInBackground() {
+		Job saveJob = backgroundSaveJob;
+		if (saveJob == null) {
+			return false;
+		}
+		return (backgroundSaveJob.getState() & (Job.WAITING | Job.RUNNING)) != 0;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/JFaceUtil.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/JFaceUtil.java
new file mode 100644
index 0000000..c2d9347
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/JFaceUtil.java
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences.NodeChangeEvent;
+import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.jface.internal.InternalPolicy;
+import org.eclipse.jface.preference.JFacePreferences;
+import org.eclipse.jface.util.Policy;
+import org.eclipse.jface.util.SafeRunnable;
+import org.eclipse.jface.util.StatusHandler;
+import org.eclipse.ui.statushandlers.StatusAdapter;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+/**
+ * Utility class for setting up JFace for use by Eclipse.
+ *
+ * @since 3.1
+ */
+final class JFaceUtil {
+
+	private JFaceUtil() {
+		// prevents intantiation
+	}
+
+	/**
+	 * Initializes JFace for use by Eclipse.
+	 */
+	public static void initializeJFace() {
+		// Set the SafeRunner to run all SafeRunnables
+		SafeRunnable.setRunner(code -> SafeRunner.run(code));
+
+		// Pass all errors and warnings to the status handling facility
+		// and the rest to the main runtime log
+		Policy.setLog(status -> {
+			if (status.getSeverity() == IStatus.WARNING
+					|| status.getSeverity() == IStatus.ERROR) {
+				StatusManager.getManager().handle(status);
+			} else {
+				WorkbenchPlugin.log(status);
+			}
+		});
+
+		Policy.setStatusHandler(new StatusHandler() {
+			@Override
+			public void show(IStatus status, String title) {
+				StatusAdapter statusAdapter = new StatusAdapter(status);
+				statusAdapter.setProperty(StatusAdapter.TITLE_PROPERTY, title);
+				StatusManager.getManager().handle(statusAdapter, StatusManager.SHOW);
+			}
+		});
+
+		// Get all debug options from Platform
+		if ("true".equalsIgnoreCase(Platform.getDebugOption(Policy.JFACE + "/debug"))) { //$NON-NLS-1$ //$NON-NLS-2$
+			Policy.DEBUG_DIALOG_NO_PARENT = "true".equalsIgnoreCase(Platform.getDebugOption(Policy.JFACE + "/debug/dialog/noparent")); //$NON-NLS-1$ //$NON-NLS-2$
+			Policy.TRACE_ACTIONS = "true".equalsIgnoreCase(Platform.getDebugOption(Policy.JFACE + "/trace/actions")); //$NON-NLS-1$ //$NON-NLS-2$
+			Policy.TRACE_TOOLBAR = "true".equalsIgnoreCase(Platform.getDebugOption(Policy.JFACE + "/trace/toolbarDisposal")); //$NON-NLS-1$ //$NON-NLS-2$
+			InternalPolicy.DEBUG_LOG_REENTRANT_VIEWER_CALLS = "true".equalsIgnoreCase(Platform.getDebugOption(Policy.JFACE + "/debug/viewers/reentrantViewerCalls")); //$NON-NLS-1$ //$NON-NLS-2$
+//			InternalPolicy.DEBUG_LOG_EQUAL_VIEWER_ELEMENTS = "true".equalsIgnoreCase(Platform.getDebugOption(Policy.JFACE + "/debug/viewers/equalElements")); //$NON-NLS-1$ //$NON-NLS-2$
+//			InternalPolicy.DEBUG_BIDI_UTILS = "true".equalsIgnoreCase(Platform.getDebugOption(Policy.JFACE + "/debug/bidiUtils")); //$NON-NLS-1$ //$NON-NLS-2$
+//			InternalPolicy.DEBUG_TRACE_URL_IMAGE_DESCRIPTOR = "true".equalsIgnoreCase(Platform.getDebugOption(Policy.JFACE + "/debug/trace/URLImageDescriptor")); //$NON-NLS-1$ //$NON-NLS-2$
+//			InternalPolicy.DEBUG_LOG_URL_IMAGE_DESCRIPTOR_MISSING_2x = "true".equalsIgnoreCase(Platform.getDebugOption(Policy.JFACE + "/debug/logURLImageDescriptorMissing2x")); //$NON-NLS-1$ //$NON-NLS-2$
+//			InternalPolicy.DEBUG_LOAD_URL_IMAGE_DESCRIPTOR_DIRECTLY = "true".equalsIgnoreCase(Platform.getDebugOption(Policy.JFACE + "/debug/loadURLImageDescriptorDirectly")); //$NON-NLS-1$ //$NON-NLS-2$
+//			// loadURLImageDescriptor2x is "true" by default and should stay "true" when absent in the debug options file:
+//			InternalPolicy.DEBUG_LOAD_URL_IMAGE_DESCRIPTOR_2x = !"false".equalsIgnoreCase(Platform.getDebugOption(Policy.JFACE + "/debug/loadURLImageDescriptor2x")); //$NON-NLS-1$ //$NON-NLS-2$
+//			InternalPolicy.DEBUG_LOAD_URL_IMAGE_DESCRIPTOR_2x_PNG_FOR_GIF = "true".equalsIgnoreCase(Platform.getDebugOption(Policy.JFACE + "/debug/loadURLImageDescriptor2xPngForGif")); //$NON-NLS-1$ //$NON-NLS-2$
+		}
+	}
+
+	/**
+	 * Adds a preference listener so that the JFace preference store is initialized
+	 * as soon as the workbench preference store becomes available.
+	 */
+	public static void initializeJFacePreferences() {
+		IEclipsePreferences rootNode = (IEclipsePreferences) Platform.getPreferencesService().getRootNode().node(InstanceScope.SCOPE);
+		final String workbenchName = WorkbenchPlugin.getDefault().getBundle().getSymbolicName();
+
+		rootNode.addNodeChangeListener(new IEclipsePreferences.INodeChangeListener() {
+			@Override
+			public void added(NodeChangeEvent event) {
+				if (!event.getChild().name().equals(workbenchName)) {
+					return;
+				}
+				((IEclipsePreferences) event.getChild()).addPreferenceChangeListener(PlatformUIPreferenceListener.getSingleton());
+
+			}
+			@Override
+			public void removed(NodeChangeEvent event) {
+				// Nothing to do here
+
+			}
+		});
+
+		JFacePreferences.setPreferenceStore(WorkbenchPlugin.getDefault().getPreferenceStore());
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/KeyBindingService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/KeyBindingService.java
new file mode 100644
index 0000000..01f1768
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/KeyBindingService.java
@@ -0,0 +1,432 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 440810, 472654
+ *******************************************************************************/
+package org.eclipse.ui.internal;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.core.commands.contexts.Context;
+import org.eclipse.e4.ui.services.EContextService;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.commands.ActionHandler;
+import org.eclipse.ui.IKeyBindingService;
+import org.eclipse.ui.INestableKeyBindingService;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.IWorkbenchSite;
+import org.eclipse.ui.LegacyHandlerSubmissionExpression;
+import org.eclipse.ui.handlers.IHandlerActivation;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.internal.actions.CommandAction;
+import org.eclipse.ui.internal.handlers.CommandLegacyActionWrapper;
+
+/**
+ * This service provides a nestable implementation of a key binding service.
+ * This class is provided for backwards compatibility only, and might be removed
+ * in the future. All of the functionality is the class can be duplicated by
+ * using the commands and contexts API.
+ *
+ * @since 2.0
+ */
+public final class KeyBindingService implements INestableKeyBindingService {
+    /**
+     * Whether this key binding service has been disposed.  A disposed key
+     * binding service should not be used again.
+     */
+    private boolean disposed;
+
+	private final Map<IWorkbenchSite, IKeyBindingService> nestedServices = new HashMap<>();
+
+    /**
+     * The set of context identifiers enabled in this key binding service (not
+     * counting any nested services). This set may be empty, but it is never
+     * <code>null</code>.
+     */
+	private Set<String> enabledContextIds = Collections.EMPTY_SET;
+
+
+    /**
+     * The site within the workbench at which this service is provided. This
+     * value should not be <code>null</code>.
+     */
+    private IWorkbenchPartSite workbenchPartSite;
+
+	private KeyBindingService parent;
+
+	private IKeyBindingService activeService;
+
+	private Map<IAction, IHandlerActivation> actionToProxy = new HashMap<>();
+
+    /**
+     * Constructs a new instance of <code>KeyBindingService</code> on a given
+     * workbench site. This instance is not nested.
+     *
+     * @param workbenchPartSite
+     *            The site for which this service will be responsible; should
+     *            not be <code>null</code>.
+     */
+    public KeyBindingService(IWorkbenchPartSite workbenchPartSite) {
+        this(workbenchPartSite, null);
+    }
+
+    /**
+     * Constructs a new instance of <code>KeyBindingService</code> on a given
+     * workbench site.
+     *
+     * @param workbenchPartSite
+     *            The site for which this service will be responsible; should
+     *            not be <code>null</code>.
+     * @param parent
+     *            The parent key binding service, if any; <code>null</code> if
+     *            none.
+     */
+    KeyBindingService(IWorkbenchPartSite workbenchPartSite,
+            KeyBindingService parent) {
+        this.workbenchPartSite = workbenchPartSite;
+		this.parent = parent;
+    }
+
+    @Override
+	public boolean activateKeyBindingService(IWorkbenchSite nestedSite) {
+        if (disposed) {
+			return false;
+		}
+
+		// Check if we should do a deactivation.
+		if (nestedSite == null) {
+			// We should do a deactivation, if there is one active.
+			if (activeService == null) {
+				// There is no active service. Do no work.
+				return false;
+			}
+			// Deactivate the currently active nested service.
+			deactivateNestedService();
+			return true;
+		}
+
+		// Attempt to activate a service.
+		final IKeyBindingService service = nestedServices.get(nestedSite);
+
+		if (service == activeService) {
+			// The service is already active, or already null
+			return false;
+		}
+
+		deactivateNestedService();
+		if (service != null) {
+			activateNestedService(service);
+		}
+        return true;
+    }
+
+	private void activateNestedService(IKeyBindingService service) {
+		/*
+		 * If I have a parent, and I'm the active service, then deactivate so
+		 * that I can make changes.
+		 */
+		boolean active = false;
+		boolean haveParent = (parent != null);
+		if (haveParent) {
+			active = (parent.activeService == this);
+			if (active) {
+				parent.deactivateNestedService();
+			}
+		}
+
+		// Update the active service.
+		activeService = service;
+
+		// Check to see that the service isn't null.
+		if (service == null) {
+			return;
+		}
+
+        if (haveParent) {
+			if (active) {
+				parent.activateNestedService(this);
+			}
+
+		} else if (activeService instanceof KeyBindingService) {
+			// add all the nested context ids.
+
+			EContextService cs = ((KeyBindingService) activeService).workbenchPartSite
+					.getService(EContextService.class);
+			for (String id : ((KeyBindingService) activeService).enabledContextIds) {
+				cs.activateContext(id);
+			}
+			/*
+			 * add all of the nested handler submissions.
+			 */
+			IHandlerService hs = ((KeyBindingService) activeService).workbenchPartSite
+					.getService(IHandlerService.class);
+			Iterator<Entry<IAction, IHandlerActivation>> i = ((KeyBindingService) activeService).actionToProxy
+					.entrySet().iterator();
+			while (i.hasNext()) {
+				Entry<IAction, IHandlerActivation> entry = i.next();
+				hs.activateHandler(entry.getValue());
+			}
+		}
+	}
+
+	private void deactivateNestedService() {
+		if (disposed) {
+			return;
+		}
+
+        // Don't do anything if there is no active service.
+		if (activeService == null) {
+			return;
+		}
+
+		// Check to see if there is a parent.
+		boolean active = false;
+		if (parent != null) {
+			// Check if I'm the active service.
+			if (parent.activeService == this) {
+				active = true;
+				// Deactivate myself so I can make changes.
+				parent.deactivateNestedService();
+			}
+
+		} else if (activeService instanceof KeyBindingService) {
+			// Remove all the nested context ids.
+
+			EContextService cs = ((KeyBindingService) activeService).workbenchPartSite
+					.getService(EContextService.class);
+			for (String id : ((KeyBindingService) activeService).enabledContextIds) {
+				cs.deactivateContext(id);
+			}
+			/*
+			 * Remove all of the nested handler submissions. The handlers here
+			 * weren't created by this instance (but by the nest instance), and
+			 * hence can't be disposed here.
+			 */
+			IHandlerService hs = ((KeyBindingService) activeService).workbenchPartSite
+					.getService(IHandlerService.class);
+			hs.deactivateHandlers(((KeyBindingService) activeService).actionToProxy.values());
+		}
+
+		// Clear our reference to the active service.
+		activeService = null;
+
+		// If necessary, let my parent know that changes have occurred.
+		if (active) {
+			parent.activateNestedService(this);
+		}
+	}
+
+    /**
+     * Disposes this key binding service. This clears out all of the submissions
+     * held by this service, and its nested services.
+     */
+	public void dispose() {
+		if (!disposed) {
+			disposed = true;
+			deactivateNestedService();
+			EContextService cs = workbenchPartSite
+					.getService(EContextService.class);
+			for (String id : enabledContextIds) {
+				cs.deactivateContext(id);
+			}
+			enabledContextIds.clear();
+			/*
+			 * Remove all of the nested handler submissions. The handlers here
+			 * weren't created by this instance (but by the nest instance), and
+			 * hence can't be disposed here.
+			 */
+			IHandlerService hs = workbenchPartSite
+					.getService(IHandlerService.class);
+			hs.deactivateHandlers(actionToProxy.values());
+			actionToProxy.clear();
+		}
+
+	}
+
+
+	@Override
+	public IKeyBindingService getKeyBindingService(IWorkbenchSite nestedSite) {
+		if (disposed) {
+			return null;
+		}
+
+		if (nestedSite == null) {
+			return null;
+		}
+
+		IKeyBindingService service = nestedServices.get(nestedSite);
+		if (service == null) {
+			// TODO the INestedKeyBindingService API should be based on
+			// IWorkbenchPartSite..
+			if (nestedSite instanceof IWorkbenchPartSite) {
+				service = new KeyBindingService((IWorkbenchPartSite) nestedSite, this);
+			} else {
+				service = new KeyBindingService(null, this);
+			}
+
+			nestedServices.put(nestedSite, service);
+		}
+
+		return service;
+	}
+
+    @Override
+	public String[] getScopes() {
+        if (disposed) {
+			return null;
+		}
+
+        // Build the list of active scopes
+		final Set<String> activeScopes = new HashSet<>();
+        activeScopes.addAll(enabledContextIds);
+		if (activeService instanceof KeyBindingService) {
+			activeScopes.addAll(((KeyBindingService) activeService).enabledContextIds);
+		}
+
+		return activeScopes.toArray(new String[activeScopes.size()]);
+    }
+
+    @Override
+	public void registerAction(IAction action) {
+        if (disposed) {
+			return;
+		}
+
+        if (action instanceof CommandLegacyActionWrapper) {
+        	// this is a registration of a fake action for an already
+			// registered handler
+			WorkbenchPlugin
+					.log("Cannot register a CommandLegacyActionWrapper back into the system"); //$NON-NLS-1$
+			return;
+        }
+
+        if (action instanceof CommandAction) {
+			// we unfortunately had to allow these out into the wild, but they
+			// still must not feed back into the system
+			return;
+        }
+
+        unregisterAction(action);
+
+		IWorkbenchPartSite partSite = workbenchPartSite;
+		if (parent != null) {
+			KeyBindingService currentParent = parent;
+			while (currentParent != null) {
+				partSite = currentParent.workbenchPartSite;
+				currentParent = currentParent.parent;
+			}
+		}
+
+		String commandId = action.getActionDefinitionId();
+		if (commandId != null) {
+			for (IAction registeredAction : actionToProxy.keySet()) {
+				// we also need to unregister any other action that may have
+				// been registered with the same definition id
+				if (commandId.equals(registeredAction.getActionDefinitionId())) {
+					unregisterAction(registeredAction);
+					break;
+				}
+			}
+
+			IHandlerService hs = workbenchPartSite
+					.getService(IHandlerService.class);
+			actionToProxy.put(action, hs.activateHandler(commandId, new ActionHandler(action),
+					new LegacyHandlerSubmissionExpression(null, partSite.getShell(), partSite)));
+
+		}
+    }
+
+	@Override
+	public boolean removeKeyBindingService(IWorkbenchSite nestedSite) {
+		if (disposed) {
+			return false;
+		}
+
+		final IKeyBindingService service = nestedServices.remove(nestedSite);
+		if (service == null) {
+			return false;
+		}
+
+		if (service.equals(activeService)) {
+			deactivateNestedService();
+		}
+
+		return true;
+	}
+
+    @Override
+	public void setScopes(String[] scopes) {
+        if (disposed) {
+			return;
+		}
+		Set<String> oldContextIds = enabledContextIds;
+		enabledContextIds = new HashSet<>(Arrays.asList(scopes));
+		EContextService cs = workbenchPartSite.getService(EContextService.class);
+		addParents(cs, scopes);
+
+		for (String id : oldContextIds) {
+			if (!enabledContextIds.contains(id)) {
+				cs.deactivateContext(id);
+			}
+        }
+		for (String id : enabledContextIds) {
+			if (!oldContextIds.contains(id)) {
+				cs.activateContext(id);
+			}
+		}
+    }
+
+    /**
+	 * @param cs
+	 * @param scopes
+	 */
+	private void addParents(EContextService cs, String[] scopes) {
+		for (String id : scopes) {
+			try {
+				Context current = cs.getContext(id);
+				String parentId = current.getParentId();
+				while (parentId != null && !enabledContextIds.contains(parentId)) {
+					enabledContextIds.add(parentId);
+					current = cs.getContext(parentId);
+					parentId = current.getParentId();
+				}
+			} catch (NotDefinedException e) {
+				WorkbenchPlugin.log(e);
+			}
+		}
+	}
+
+	@Override
+	public void unregisterAction(IAction action) {
+		if (disposed) {
+			return;
+		}
+
+		if (action instanceof CommandLegacyActionWrapper) {
+			// this is a registration of a fake action for an already
+			// registered handler
+			WorkbenchPlugin.log("Cannot unregister a CommandLegacyActionWrapper out of the system"); //$NON-NLS-1$
+			return;
+		}
+
+		IHandlerActivation activation = actionToProxy.remove(action);
+		if (activation == null) {
+			return;
+		}
+		IHandlerService hs = workbenchPartSite.getService(IHandlerService.class);
+		hs.deactivateHandler(activation);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/LegacyAnimationFeedback.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/LegacyAnimationFeedback.java
new file mode 100644
index 0000000..e813ee2
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/LegacyAnimationFeedback.java
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal;
+
+import java.util.Iterator;
+
+import org.eclipse.jface.util.Geometry;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Rectangle;
+//import org.eclipse.swt.graphics.Region;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * Creates an animation feedback that will morph the start rectangle to the end rectangle
+ * for AnimationEngine.
+ *
+ * @since 3.3
+ *
+ */
+public class LegacyAnimationFeedback extends RectangleAnimationFeedbackBase {
+	private static final int LINE_WIDTH = 1;
+
+	// RAP
+//	private Region shellRegion;
+
+	public LegacyAnimationFeedback(Shell parentShell, Rectangle start,
+			Rectangle end) {
+		super(parentShell, start, end);
+	}
+
+	@Override
+	public void renderStep(AnimationEngine engine) {
+//		if (shellRegion != null) {
+//			shellRegion.dispose();
+//			shellRegion = new Region(getAnimationShell().getDisplay());
+//		}
+//
+//		// Iterate across the set of start/end rects
+//		Iterator currentRects = getCurrentRects(engine.amount()).iterator();
+//		while (currentRects.hasNext()) {
+//			Rectangle curRect = (Rectangle) currentRects.next();
+//			Rectangle rect = Geometry.toControl(getAnimationShell(), curRect);
+//			shellRegion.add(rect);
+//			rect.x += LINE_WIDTH;
+//			rect.y += LINE_WIDTH;
+//			rect.width = Math.max(0, rect.width - 2 * LINE_WIDTH);
+//			rect.height = Math.max(0, rect.height - 2 * LINE_WIDTH);
+//
+//			shellRegion.subtract(rect);
+//		}
+//
+//		getAnimationShell().setRegion(shellRegion);
+//		getAnimationShell().getDisplay().update();
+	}
+
+	@Override
+	public void initialize(AnimationEngine engine) {
+//		Color color = getAnimationShell().getDisplay().getSystemColor(SWT.COLOR_WIDGET_DARK_SHADOW);
+//		getAnimationShell().setBackground(color);
+//
+//		// Ensure that the background won't show on the initial display
+//		shellRegion = new Region(getAnimationShell().getDisplay());
+//		getAnimationShell().setRegion(shellRegion);
+//	}
+//
+//	@Override
+//	public void dispose() {
+//		super.dispose();
+//
+//		if (!shellRegion.isDisposed())
+//			shellRegion.dispose();
+	}
+
+	/**
+	 * Perform any initialization you want to have happen -before- the
+	 * amination starts
+	 */
+	@Override
+	public boolean jobInit(AnimationEngine engine) {
+		if (!super.jobInit(engine))
+			return false;
+
+		// Compute the shell's bounds
+		Rectangle shellBounds = Geometry.copy((Rectangle) getStartRects()
+				.get(0));
+		Iterator startIter = getStartRects().iterator();
+		Iterator endIter = getEndRects().iterator();
+		while (startIter.hasNext()) {
+			shellBounds.add((Rectangle) startIter.next());
+			shellBounds.add((Rectangle) endIter.next());
+		}
+		getAnimationShell().setBounds(shellBounds);
+		// Making the shell visible will be slow on old video cards, so only start
+		// the timer once it is visible.
+		getAnimationShell().setVisible(true);
+
+		return true;  // OK to go...
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/LegacyResourceSupport.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/LegacyResourceSupport.java
new file mode 100644
index 0000000..2c29959
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/LegacyResourceSupport.java
@@ -0,0 +1,687 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.ui.internal.util.BundleUtility;
+import org.osgi.framework.Bundle;
+
+/**
+ * Provides access to resource-specific classes, needed to provide
+ * backwards compatibility for resource-specific functions which
+ * could not be moved up from the generic workbench layer to the
+ * IDE layer.
+ */
+public final class LegacyResourceSupport {
+
+	private static String[] resourceClassNames = {
+        "org.eclipse.core.resources.IResource", //$NON-NLS-1$
+        "org.eclipse.core.resources.IContainer", //$NON-NLS-1$
+        "org.eclipse.core.resources.IFolder", //$NON-NLS-1$
+        "org.eclipse.core.resources.IProject", //$NON-NLS-1$
+        "org.eclipse.core.resources.IFile", //$NON-NLS-1$
+	};
+
+    /**
+     * Cached value of
+     * <code>Class.forName("org.eclipse.core.resources.IResource")</code>;
+     * <code>null</code> if not initialized or not present.
+     * @since 3.0
+     */
+    private static Class iresourceClass = null;
+
+    /**
+     * Cached value of
+     * <code>Class.forName("org.eclipse.core.resources.IFile")</code>;
+     * <code>null</code> if not initialized or not present.
+     * @since 3.1
+     */
+    private static Class ifileClass;
+
+    /**
+     * Cached value of
+     * <code>Class.forName("org.eclipse.ui.IContributorResourceAdapter")</code>;
+     * <code>null</code> if not initialized or not present.
+     * @since 3.0
+     */
+    private static Class icontributorResourceAdapterClass = null;
+
+    /**
+     * Cached value of </code> org.eclipse.ui.IContributorResourceAdapter.getAdaptedResource(IAdaptable) </code>
+     * <code>null</code> if not initialized or not present.
+     *
+     * @since 3.3
+     */
+    private static Method getAdaptedResourceMethod = null;
+
+    /**
+     * Cached value of </code> org.eclipse.ui.IContributorResourceAdapter2.getAdaptedResourceMapping(IAdaptable) </code>
+     * <code>null</code> if not initialized or not present.
+     *
+     * @since 3.3
+     */
+    private static Method getAdaptedResourceMappingMethod = null;
+
+    /**
+     * Cached value of
+     * <code>Class.forName("org.eclipse.ui.ide.IContributorResourceAdapter2")</code>;
+     * <code>null</code> if not initialized or not present.
+     * @since 3.1
+     */
+    private static Class icontributorResourceAdapter2Class = null;
+
+    /**
+     * Cached value of
+     * <code>Class.forName("org.eclipse.ui.internal.ide.DefaultContributorResourceAdapter")</code>;
+     * <code>null</code> if not initialized or not present.
+     * @since 3.0
+     */
+    private static Class defaultContributorResourceAdapterClass = null;
+
+    /**
+     * Cached value for reflective result of <code>DefaultContributorRessourceAdapter.getDefault()</code>.
+     * <code>null</code> if not initialized or not present.
+     *
+     * @since 3.3
+     */
+    private static Object defaultContributorResourceAdapter = null;
+
+    /**
+     * Cached value of
+     * <code>Class.forName("org.eclipse.core.resources.mapping.ResourceMappingr")</code>;
+     * <code>null</code> if not initialized or not present.
+     * @since 3.0
+     */
+    private static Class resourceMappingClass = null;
+
+    /**
+     * Indicates whether the IDE plug-in (which supplies the
+     * resource contribution adapters) is even around.
+     */
+    private static boolean resourceAdapterPossible = true;
+
+
+    /**
+     * Returns <code>IFile.class</code> or <code>null</code> if the
+     * class is not available.
+     * <p>
+     * This method exists to avoid explicit references from the generic
+     * workbench to the resources plug-in.
+     * </p>
+     *
+     * @return <code>IFile.class</code> or <code>null</code> if class
+     * not available
+     * @since 3.1
+     */
+    public static Class getFileClass() {
+        if (ifileClass != null) {
+            // tried before and succeeded
+            return ifileClass;
+        }
+        Class c = loadClass("org.eclipse.core.resources", "org.eclipse.core.resources.IFile"); //$NON-NLS-1$ //$NON-NLS-2$
+        if (c != null) {
+            // The class was found so record it
+            ifileClass = c;
+        }
+        return c;
+    }
+
+    /**
+     * Returns <code>IResource.class</code> or <code>null</code> if the
+     * class is not available.
+     * <p>
+     * This method exists to avoid explicit references from the generic
+     * workbench to the resources plug-in.
+     * </p>
+     *
+     * @return <code>IResource.class</code> or <code>null</code> if class
+     * not available
+     * @since 3.0
+     */
+    public static Class getResourceClass() {
+        if (iresourceClass != null) {
+            // tried before and succeeded
+            return iresourceClass;
+        }
+        Class c = loadClass("org.eclipse.core.resources", "org.eclipse.core.resources.IResource"); //$NON-NLS-1$ //$NON-NLS-2$
+        if (c != null) {
+            // The class was found so record it
+            iresourceClass = c;
+        }
+        return c;
+    }
+
+    /**
+     * Returns <code>ResourceMapping.class</code> or <code>null</code> if the
+     * class is not available.
+     * <p>
+     * This method exists to avoid explicit references from the generic
+     * workbench to the resources plug-in.
+     * </p>
+     *
+     * @return <code>ResourceMapping.class</code> or <code>null</code> if class
+     * not available
+     * @since 3.1
+     */
+    public static Class getResourceMappingClass() {
+        if (resourceMappingClass != null) {
+            // tried before and succeeded
+            return resourceMappingClass;
+        }
+        Class c = loadClass("org.eclipse.core.resources", "org.eclipse.core.resources.mapping.ResourceMapping"); //$NON-NLS-1$ //$NON-NLS-2$
+        if (c != null) {
+            // The class was found so record it
+            resourceMappingClass = c;
+        }
+        return c;
+    }
+
+    /**
+     * Returns <code>IContributorResourceAdapter.class</code> or
+     * <code>null</code> if the class is not available.
+     * <p>
+     * This method exists to avoid explicit references from the generic
+     * workbench to the IDE plug-in.
+     * </p>
+     *
+     * @return <code>IContributorResourceAdapter.class</code> or
+     * <code>null</code> if class not available
+     * @since 3.0
+     */
+    public static Class getIContributorResourceAdapterClass() {
+        if (icontributorResourceAdapterClass != null) {
+            // tried before and succeeded
+            return icontributorResourceAdapterClass;
+        }
+        Class c = loadClass("org.eclipse.ui.ide", "org.eclipse.ui.IContributorResourceAdapter"); //$NON-NLS-1$ //$NON-NLS-2$
+        if (c != null) {
+            // The class was found so record it
+            icontributorResourceAdapterClass = c;
+        }
+        return c;
+    }
+
+    /**
+     * Returns <code>IContributorResourceAdapter2.class</code> or
+     * <code>null</code> if the class is not available.
+     * <p>
+     * This method exists to avoid explicit references from the generic
+     * workbench to the IDE plug-in.
+     * </p>
+     *
+     * @return <code>IContributorResourceAdapter.class</code> or
+     * <code>null</code> if class not available
+     * @since 3.1
+     */
+    public static Class getIContributorResourceAdapter2Class() {
+        if (icontributorResourceAdapter2Class != null) {
+            // tried before and succeeded
+            return icontributorResourceAdapter2Class;
+        }
+        Class c = loadClass("org.eclipse.ui.ide", "org.eclipse.ui.ide.IContributorResourceAdapter2"); //$NON-NLS-1$ //$NON-NLS-2$
+        if (c != null) {
+            // The class was found so record it
+            icontributorResourceAdapter2Class = c;
+        }
+        return c;
+    }
+
+    private static Class loadClass(String bundleName, String className) {
+        if (!resourceAdapterPossible) {
+            // tried before and failed
+            return null;
+        }
+        Bundle bundle = Platform.getBundle(bundleName);
+        if (bundle == null) {
+            // Required plug-in is not around
+            // assume that it will never be around
+            resourceAdapterPossible = false;
+            return null;
+        }
+        // Required plug-in is around
+        // it's not our job to activate the plug-in
+        if (!BundleUtility.isActivated(bundle)) {
+            // assume it might come alive later
+            resourceAdapterPossible = true;
+            return null;
+        }
+        try {
+            return bundle.loadClass(className);
+        } catch (ClassNotFoundException e) {
+            // unable to load the class - sounds pretty serious
+            // treat as if the plug-in were unavailable
+            resourceAdapterPossible = false;
+            return null;
+        }
+    }
+
+    /**
+     * Returns <code>DefaultContributorResourceAdapter.class</code> or
+     * <code>null</code> if the class is not available.
+     * <p>
+     * This method exists to avoid explicit references from the generic
+     * workbench to the IDE plug-in.
+     * </p>
+     *
+     * @return <code>DefaultContributorResourceAdapter.class</code> or
+     * <code>null</code> if class not available
+     * @since 3.0
+     */
+    public static Class getDefaultContributorResourceAdapterClass() {
+        if (defaultContributorResourceAdapterClass != null) {
+            // tried before and succeeded
+            return defaultContributorResourceAdapterClass;
+        }
+        Class c = loadClass("org.eclipse.ui.ide", "org.eclipse.ui.internal.ide.DefaultContributorResourceAdapter"); //$NON-NLS-1$ //$NON-NLS-2$
+        if (c != null) {
+            // The class was found so record it
+            defaultContributorResourceAdapterClass = c;
+        }
+        return c;
+    }
+
+    private static Object getDefaultContributorResourceAdapter() {
+        if (defaultContributorResourceAdapter != null) {
+            return defaultContributorResourceAdapter;
+        }
+
+		// reflective equivalent of
+		//    resourceAdapter = DefaultContributorResourceAdapter.getDefault();
+
+			Class c = LegacyResourceSupport.getDefaultContributorResourceAdapterClass();
+			if (c != null) {
+				try {
+					Method m  = c.getDeclaredMethod("getDefault", new Class[0]);//$NON-NLS-1$
+					defaultContributorResourceAdapter = m.invoke(null, new Object[0]);
+					return defaultContributorResourceAdapter;
+				} catch (SecurityException e) {
+					// shouldn't happen - but play it safe
+				} catch (NoSuchMethodException e) {
+					// shouldn't happen - but play it safe
+				} catch (IllegalArgumentException e) {
+					// shouldn't happen - but play it safe
+				} catch (IllegalAccessException e) {
+					// shouldn't happen - but play it safe
+				} catch (InvocationTargetException e) {
+					// shouldn't happen - but play it safe
+				}
+
+
+			}
+
+		return null;
+
+    }
+
+    /**
+     * Returns <code>true</code> if the provided type name is an
+     * <code>IResource</code>, and <code>false</code> otherwise.
+     * @param objectClassName
+     * @return <code>true</code> if the provided type name is an
+     * <code>IResource</code>, and <code>false</code> otherwise.
+     *
+     * @since 3.1
+     */
+    public static boolean isResourceType(String objectClassName) {
+        for (String resourceClassName : resourceClassNames) {
+            if (resourceClassName.equals(objectClassName)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns <code>true</code> if the provided type name is an
+     * <code>"org.eclipse.core.resources.mapping.ResourceMapping"</code>, and <code>false</code> otherwise.
+     * @param objectClassName
+     * @return <code>true</code> if the provided type name is an
+     * <code>"org.eclipse.core.resources.mapping.ResourceMapping"</code>, and <code>false</code> otherwise.
+     *
+     * @since 3.1
+     */
+    public static boolean isResourceMappingType(String objectClassName) {
+        return objectClassName.equals("org.eclipse.core.resources.mapping.ResourceMapping"); //$NON-NLS-1$
+    }
+
+    /**
+     * Returns the class search order starting with <code>extensibleClass</code>.
+     * The search order is defined in this class' comment.
+     *
+     * @since 3.1
+     */
+    private static boolean isInstanceOf(Class clazz, String type) {
+		if (clazz.getName().equals(type)) {
+			return true;
+		}
+		Class superClass= clazz.getSuperclass();
+		if (superClass != null && isInstanceOf(superClass, type)) {
+			return true;
+		}
+		Class[] interfaces= clazz.getInterfaces();
+		for (Class currentInterface : interfaces) {
+			if (isInstanceOf(currentInterface, type)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+    /**
+     * Returns the adapted resource using the <code>IContributorResourceAdapter</code>
+     * registered for the given object. If the Resources plug-in is not loaded
+     * the object can not be adapted.
+     *
+     * @param object the object to adapt to <code>IResource</code>.
+     * @return returns the adapted resource using the <code>IContributorResourceAdapter</code>
+     * or <code>null</code> if the Resources plug-in is not loaded.
+     *
+     * @since 3.1
+     */
+    public static Object getAdaptedContributorResource(Object object) {
+		Class resourceClass = LegacyResourceSupport.getResourceClass();
+		if (resourceClass == null) {
+			return null;
+		}
+		if (resourceClass.isInstance(object)) {
+			return null;
+		}
+		if (object instanceof IAdaptable) {
+			IAdaptable adaptable = (IAdaptable) object;
+			Class contributorResourceAdapterClass = LegacyResourceSupport.getIContributorResourceAdapterClass();
+			if (contributorResourceAdapterClass == null) {
+				return adaptable.getAdapter(resourceClass);
+			}
+			Object resourceAdapter = adaptable.getAdapter(contributorResourceAdapterClass);
+			if (resourceAdapter == null) {
+			    resourceAdapter = LegacyResourceSupport.getDefaultContributorResourceAdapter();
+			    if (resourceAdapter == null) {
+					return null;
+				}
+			}
+			// reflective equivalent of
+			//    result = ((IContributorResourceAdapter) resourceAdapter).getAdaptedResource(adaptable);
+
+				Method m = getContributorResourceAdapterGetAdaptedResourceMethod();
+				if (m != null) {
+					try {
+						return m.invoke(resourceAdapter, new Object[]{adaptable});
+					} catch (IllegalArgumentException e) {
+						// shouldn't happen - but play it safe
+					} catch (IllegalAccessException e) {
+						// shouldn't happen - but play it safe
+					} catch (InvocationTargetException e) {
+						// shouldn't happen - but play it safe
+					}
+				}
+
+		}
+		return null;
+	}
+
+    private static Method getContributorResourceAdapterGetAdaptedResourceMethod() {
+        if (getAdaptedResourceMethod != null) {
+            return getAdaptedResourceMethod;
+        }
+
+        Class c = getIContributorResourceAdapterClass();
+        if (c != null) {
+            try {
+				getAdaptedResourceMethod = c.getDeclaredMethod("getAdaptedResource", new Class[]{IAdaptable.class}); //$NON-NLS-1$
+				return getAdaptedResourceMethod;
+			} catch (SecurityException e) {
+				// shouldn't happen - but play it safe
+			} catch (NoSuchMethodException e) {
+				// shouldn't happen - but play it safe
+			}
+
+        }
+
+    	return null;
+	}
+
+
+    private static Method getContributorResourceAdapter2GetAdaptedResourceMappingMethod() {
+        if (getAdaptedResourceMappingMethod != null) {
+            return getAdaptedResourceMappingMethod;
+        }
+
+        Class c = getIContributorResourceAdapter2Class();
+        if (c != null) {
+            try {
+				getAdaptedResourceMappingMethod = c.getDeclaredMethod("getAdaptedResourceMapping", new Class[]{IAdaptable.class}); //$NON-NLS-1$
+				return getAdaptedResourceMappingMethod;
+			} catch (SecurityException e) {
+				// do nothing - play it safe
+			} catch (NoSuchMethodException e) {
+				// do nothing - play it safe
+			}
+
+        }
+
+    	return null;
+	}
+
+	/**
+     * Returns the adapted resource mapping using the <code>IContributorResourceAdapter2</code>
+     * registered for the given object. If the Resources plug-in is not loaded
+     * the object can not be adapted.
+     *
+     * @param object the object to adapt to <code>ResourceMapping</code>.
+     * @return returns the adapted resource using the <code>IContributorResourceAdapter2</code>
+     * or <code>null</code> if the Resources plug-in is not loaded.
+     *
+     * @since 3.1
+     */
+    public static Object getAdaptedContributorResourceMapping(Object object) {
+        Class resourceMappingClass = LegacyResourceSupport.getResourceMappingClass();
+        if (resourceMappingClass == null) {
+            return null;
+        }
+        if (resourceMappingClass.isInstance(object)) {
+            return null;
+        }
+        if (object instanceof IAdaptable) {
+            IAdaptable adaptable = (IAdaptable) object;
+            Class contributorResourceAdapterClass = LegacyResourceSupport.getIContributorResourceAdapterClass();
+            if (contributorResourceAdapterClass == null) {
+                return adaptable.getAdapter(resourceMappingClass);
+            }
+            Class contributorResourceAdapter2Class = LegacyResourceSupport.getIContributorResourceAdapter2Class();
+            if (contributorResourceAdapter2Class == null) {
+                return adaptable.getAdapter(resourceMappingClass);
+            }
+            Object resourceAdapter = adaptable.getAdapter(contributorResourceAdapterClass);
+            Object resourceMappingAdapter;
+			if (resourceAdapter != null && contributorResourceAdapter2Class.isInstance(resourceAdapter)) {
+            	// The registered adapter also handles resource mappings
+            	resourceMappingAdapter = resourceAdapter;
+            } else {
+            	// Either there is no registered adapter or it doesn't handle resource mappings.
+            	// In this case, we will use the default contribution adapter
+                resourceMappingAdapter = getDefaultContributorResourceAdapter();
+                if (resourceMappingAdapter == null) {
+                    return null;
+                }
+            }
+
+
+	            // reflective equivalent of
+	            //    result = ((IContributorResourceAdapter2) resourceAdapter).getAdaptedResource(adaptable);
+
+	         Method m = getContributorResourceAdapter2GetAdaptedResourceMappingMethod();
+	         if (m != null) {
+
+				try {
+					Object result  = m.invoke(resourceMappingAdapter, new Object[]{adaptable});
+					if (result != null) {
+		           		return result;
+		           	}
+				} catch (IllegalArgumentException e) {
+					 // shouldn't happen - but play it safe
+				} catch (IllegalAccessException e) {
+					 // shouldn't happen - but play it safe
+				} catch (InvocationTargetException e) {
+					 // shouldn't happen - but play it safe
+				}
+
+	         }
+
+
+            // If we get here, that means that the object in question doesn't adapt to resource mapping
+            // and it's contributed adapter doesn't do the adaptation either.
+            // Before we fail, we will attempt to adapt the object to IResource and then to ResourceMapping
+            Object r = getAdaptedContributorResource(object);
+            if (r != null) {
+            	return Platform.getAdapterManager().getAdapter(r, resourceMappingClass);
+            }
+
+            // we've exhausted every avenue so just return null
+            return null;
+        }
+        // Fallback to querying the adapter manager directly when the object isn't an IAdaptable
+        return Platform.getAdapterManager().getAdapter(object, resourceMappingClass);
+    }
+
+    /**
+     * Adapts a selection to the given objectClass considering the Legacy resource
+     * support. Non resource objectClasses are adapted using the <code>IAdapterManager</code>
+     * and this may load the plug-in that contributes the adapter factory.
+     * <p>
+     * The returned selection will only contain elements successfully adapted.
+     * </p>
+     * @param selection the selection to adapt
+     * @param objectClass the class name to adapt the selection to
+     * @return an adapted selection
+     *
+     * @since 3.1
+     */
+    public static IStructuredSelection adaptSelection(IStructuredSelection selection, String objectClass) {
+		List newSelection = new ArrayList(10);
+		for (Iterator it = selection.iterator(); it.hasNext();) {
+			Object element = it.next();
+			Object adaptedElement = getAdapter(element, objectClass);
+			if (adaptedElement != null) {
+				newSelection.add(adaptedElement);
+			}
+		}
+		return new StructuredSelection(newSelection);
+	}
+
+    /**
+     * Adapts an object to a specified objectClass considering the Legacy resource
+     * support. Non resource objectClasses are adapted using the <code>IAdapterManager</code>
+     * and this may load the plug-in that contributes the adapter factory.
+     * <p>
+     * The returned selection will be of the same size as the original, and elements that could
+     * not be adapted are added to the returned selection as is.
+     * </p>
+     * @param element the element to adapt
+     * @param objectClass the class name to adapt the selection to
+     * @return an adapted element or <code>null</code> if the
+     * element could not be adapted.
+     *
+     * @since 3.1
+     */
+    public static Object getAdapter(Object element, String objectClass) {
+		Object adaptedElement = null;
+		if (isInstanceOf(element.getClass(), objectClass)) {
+			adaptedElement = element;
+		} else {
+			// Handle IResource
+			if (LegacyResourceSupport.isResourceType(objectClass)) {
+				adaptedElement = getAdaptedResource(element);
+            } else if (LegacyResourceSupport.isResourceMappingType(objectClass)) {
+                adaptedElement = getAdaptedResourceMapping(element);
+                if (adaptedElement == null) {
+                    // The object doesn't adapt directly so check if it adapts transitively
+                    Object resource = getAdaptedResource(element);
+                    if (resource != null) {
+                        adaptedElement =( (IAdaptable)resource).getAdapter(LegacyResourceSupport.getResourceMappingClass());
+                    }
+                }
+			} else {
+				// Handle all other types by using the adapter factory.
+				adaptedElement = Platform.getAdapterManager().loadAdapter(element, objectClass);
+			}
+		}
+		return adaptedElement;
+	}
+
+	/**
+     * Adapt the given element to an <code>IResource</code> using the following
+     * search order:
+     * <ol>
+     * <li> using the IContributorResourceAdapter registered for the given element, or
+     * <li> directly asking the element if it adapts.
+     * </ol>
+     *
+     * @param element the element to adapt
+     * @return an <code>IResource</code> instance if the element could be adapted or <code>null</code>
+     * otherwise.
+     * @since 3.1
+     */
+    public static Object getAdaptedResource(Object element) {
+		Class resourceClass = LegacyResourceSupport.getResourceClass();
+		Object adaptedValue = null;
+		if (resourceClass != null) {
+			if (resourceClass.isInstance(element)) {
+				adaptedValue = element;
+			} else {
+				adaptedValue = LegacyResourceSupport.getAdaptedContributorResource(element);
+			}
+		}
+		return adaptedValue;
+	}
+
+    /**
+     * Adapt the given element to an <code>ResourceMapping</code> using the following
+     * search order:
+     * <ol>
+     * <li> using the IContributorResourceAdapter2 registered for the given element, or
+     * <li> directly asking the element if it adapts.
+     * </ol>
+     *
+     * @param element the element to adapt
+     * @return an <code>ResourceMapping</code> instance if the element could be adapted or <code>null</code>
+     * otherwise.
+     * @since 3.1
+     */
+    public static Object getAdaptedResourceMapping(Object element) {
+        Class resourceMappingClass = LegacyResourceSupport.getResourceMappingClass();
+        Object adaptedValue = null;
+        if (resourceMappingClass != null) {
+            if (resourceMappingClass.isInstance(element)) {
+                adaptedValue = element;
+            } else {
+                adaptedValue = LegacyResourceSupport.getAdaptedContributorResourceMapping(element);
+            }
+        }
+        return adaptedValue;
+    }
+
+    /**
+     * Prevents construction
+     */
+    private LegacyResourceSupport() {
+        // do nothing
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/LegacyTrim.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/LegacyTrim.java
new file mode 100644
index 0000000..cc6965f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/LegacyTrim.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (c) 2011 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.ui.internal;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.e4.ui.model.application.ui.MUIElement;
+import org.eclipse.e4.ui.model.application.ui.basic.MTrimBar;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolControl;
+import org.eclipse.jface.menus.AbstractTrimWidget;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.util.Util;
+import org.eclipse.ui.menus.IWorkbenchWidget;
+
+/**
+ * @since 3.5
+ *
+ */
+public class LegacyTrim {
+
+	private IWorkbenchWidget widget;
+
+	@PostConstruct
+	void createWidget(IWorkbenchWindow iwbw, Composite parent, MToolControl toolControl) {
+		IConfigurationElement ice = ((WorkbenchWindow) iwbw).getICEFor(toolControl);
+		if (ice == null)
+			return;
+
+		parent = new Composite(parent, SWT.NONE);
+		parent.setLayout(new RowLayout());
+
+		widget = (IWorkbenchWidget) Util.safeLoadExecutableExtension(ice,
+				IWorkbenchRegistryConstants.ATT_CLASS, IWorkbenchWidget.class);
+		widget.init(iwbw);
+		if (widget instanceof AbstractTrimWidget) {
+			((AbstractTrimWidget) widget).fill(parent, SWT.DEFAULT, getSide(toolControl));
+		} else {
+			widget.fill(parent);
+		}
+	}
+
+	@PreDestroy
+	void destroy() {
+		if (widget != null) {
+			widget.dispose();
+			widget = null;
+		}
+	}
+
+	private int getSide(MUIElement element) {
+		MUIElement parent = element.getParent();
+		if (parent instanceof MTrimBar) {
+			switch (((MTrimBar) parent).getSide()) {
+			case BOTTOM:
+				return SWT.BOTTOM;
+			case LEFT:
+				return SWT.LEFT;
+			case RIGHT:
+				return SWT.RIGHT;
+			case TOP:
+				return SWT.TOP;
+			}
+		}
+		return parent == null ? SWT.DEFAULT : getSide(parent);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/LocalWorkingSetManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/LocalWorkingSetManager.java
new file mode 100644
index 0000000..c57d9e2
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/LocalWorkingSetManager.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.ui.ILocalWorkingSetManager;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IWorkingSet;
+import org.osgi.framework.BundleContext;
+
+
+public class LocalWorkingSetManager extends AbstractWorkingSetManager implements ILocalWorkingSetManager {
+
+	public LocalWorkingSetManager(BundleContext context) {
+		super(context);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void removeWorkingSet(IWorkingSet workingSet) {
+		internalRemoveWorkingSet(workingSet);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void addRecentWorkingSet(IWorkingSet workingSet) {
+		internalAddRecentWorkingSet(workingSet);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void saveState(IMemento memento) {
+        saveWorkingSetState(memento);
+        saveMruList(memento);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void restoreState(IMemento memento) {
+		Assert.isNotNull(memento);
+		Assert.isTrue(getWorkingSets().length == 0);
+        restoreWorkingSetState(memento);
+        restoreMruList(memento);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/MessageLine.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/MessageLine.java
new file mode 100644
index 0000000..95a7d03
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/MessageLine.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2014 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
+ *     Stefan Winkler <stefan@winklerweb.net> - Bug 434189
+ *******************************************************************************/
+package org.eclipse.ui.internal;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CLabel;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * A message line displaying a status.
+ */
+public class MessageLine extends CLabel {
+
+    private Color fNormalMsgAreaBackground;
+
+    /**
+     * Creates a new message line as a child of the given parent.
+     */
+    public MessageLine(Composite parent) {
+        this(parent, SWT.LEFT);
+    }
+
+    /**
+     * Creates a new message line as a child of the parent and with the given SWT stylebits.
+     */
+    public MessageLine(Composite parent, int style) {
+        super(parent, style);
+        fNormalMsgAreaBackground = null;
+    }
+
+    private Image findImage(IStatus status) {
+        if (status.isOK()) {
+            return null;
+        } else if (status.matches(IStatus.ERROR)) {
+            return PlatformUI.getWorkbench().getSharedImages().getImage(
+                    ISharedImages.IMG_OBJS_ERROR_TSK);
+        } else if (status.matches(IStatus.WARNING)) {
+            return PlatformUI.getWorkbench().getSharedImages().getImage(
+                    ISharedImages.IMG_OBJS_WARN_TSK);
+        } else if (status.matches(IStatus.INFO)) {
+            return PlatformUI.getWorkbench().getSharedImages().getImage(
+                    ISharedImages.IMG_OBJS_INFO_TSK);
+        }
+        return null;
+    }
+
+    /**
+     * Sets the message and image to the given status.
+     * <code>null</code> is a valid argument and will set the empty text and no image
+     */
+    public void setErrorStatus(IStatus status) {
+        if (status != null) {
+            String message = status.getMessage();
+            if (message != null && message.length() > 0) {
+                setText(message);
+                setImage(findImage(status));
+                return;
+            }
+        }
+		setText(""); //$NON-NLS-1$
+        setImage(null);
+		super.setBackground(fNormalMsgAreaBackground);
+	}
+
+	@Override
+	public void setBackground(Color color) {
+		fNormalMsgAreaBackground = color;
+    }
+}
+
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/Model.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/Model.java
new file mode 100644
index 0000000..04c75c4
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/Model.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Represents an object with state that will notifies a set of listeners
+ * whenever its state changes
+ */
+public class Model {
+
+    /**
+     * Current state of the model
+     */
+    private Object state;
+
+    /**
+     * Set of objects that will be notified about state changes
+     */
+    private List views = new ArrayList(1);
+
+    /**
+     * Creates a new model with the given initial state.
+     *
+     * @param initialState
+     */
+    public Model(Object initialState) {
+        state = initialState;
+    }
+
+    /**
+     * Returns the current state of the model.
+     *
+     * @return the current model state
+     */
+    public Object getState() {
+        return state;
+    }
+
+    /**
+     * Sets the current state of the model.
+     *
+     * @param newState the new state of the model
+     * @param toOmit change listener that should be omitted from change notifications (or null if all
+     * listeners should be notified).
+     */
+    public void setState(Object newState, IChangeListener toOmit) {
+        if (areEqual(newState, state)) {
+            return;
+        }
+
+        state = newState;
+
+        Iterator iter = views.iterator();
+        while (iter.hasNext()) {
+            IChangeListener next = (IChangeListener) iter.next();
+
+            if (next != toOmit) {
+                next.update(true);
+            }
+        }
+    }
+
+    private boolean areEqual(Object o1, Object o2) {
+        if (o1 == null) {
+            return o2 == null;
+        }
+        if (o2 == null) {
+            return false;
+        }
+
+        return o1.equals(o2);
+    }
+
+    /**
+     * Adds the given listener to the set of listeners that will be
+     * notified when the state changes.
+     *
+     * @param toAdd
+     */
+    public void addChangeListener(IChangeListener changeListener) {
+        changeListener.update(false);
+        views.add(changeListener);
+    }
+
+    /**
+     * Stops this model from sending change events from the given listener.
+     *
+     * @param toRemove
+     */
+    public void removeChangeListener(IChangeListener changeListener) {
+        views.remove(changeListener);
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ModelMigrationProcessor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ModelMigrationProcessor.java
new file mode 100644
index 0000000..fc5e6db
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ModelMigrationProcessor.java
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Copyright (c) 2013, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ ******************************************************************************/
+package org.eclipse.ui.internal;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.commands.MBindingContext;
+import org.eclipse.e4.ui.model.application.commands.MBindingTable;
+import org.eclipse.e4.ui.model.application.commands.MCommand;
+import org.eclipse.e4.ui.model.application.commands.MHandler;
+import org.eclipse.e4.ui.model.application.commands.MKeyBinding;
+
+public class ModelMigrationProcessor {
+	// remove e4 commands from existing IDE models
+	// Bug 411602 - CTRL+Q keyboard shortcut in any dialog closes the workbench
+	// without option to save
+	private static final String MIGRATION_001 = "ModelMigrationProcessor.001"; //$NON-NLS-1$
+
+	@Execute
+	public void process(MApplication application, IEclipseContext context) {
+		if (!application.getTags().contains(MIGRATION_001)) {
+			application.getTags().add(MIGRATION_001);
+			removeE4CommandsFromIDE(application);
+		}
+	}
+
+	/**
+	 * @param application
+	 */
+	private void removeE4CommandsFromIDE(MApplication application) {
+		List<MCommand> commands = application.getCommands();
+		Set<MCommand> toBeRemoved = new HashSet<>();
+		for (MCommand command : commands) {
+			final String elementId = command.getElementId();
+			if ("e4.exit".equals(elementId)) { //$NON-NLS-1$
+				toBeRemoved.add(command);
+			} else if ("e4.show.view".equals(elementId)) { //$NON-NLS-1$
+				toBeRemoved.add(command);
+			} else if ("org.eclipse.e4.ui.saveCommands".equals(elementId)) { //$NON-NLS-1$
+				toBeRemoved.add(command);
+			} else if ("org.eclipse.e4.ui.saveAllCommands".equals(elementId)) { //$NON-NLS-1$
+				toBeRemoved.add(command);
+			}
+			if (toBeRemoved.size() > 3) {
+				break;
+			}
+		}
+		if (toBeRemoved.size() == 0) {
+			return;
+		}
+		List<MHandler> handlers = application.getHandlers();
+		Iterator<MHandler> i = handlers.iterator();
+		int removed = 0;
+		while (i.hasNext() && removed < 4) {
+			MHandler handler = i.next();
+			if (toBeRemoved.contains(handler.getCommand())) {
+				i.remove();
+				removed++;
+			}
+		}
+		List<MBindingContext> bindingContexts = application.getBindingContexts();
+		MBindingContext dialogAndWindow = null;
+		for (MBindingContext c : bindingContexts) {
+			if ("org.eclipse.ui.contexts.dialogAndWindow".equals(c.getElementId())) { //$NON-NLS-1$
+				dialogAndWindow = c;
+				break;
+			}
+		}
+
+		if (dialogAndWindow != null) {
+			List<MBindingTable> bindingTables = application.getBindingTables();
+			MBindingTable dAWTable = null;
+			for (MBindingTable table : bindingTables) {
+				if (dialogAndWindow.equals(table.getBindingContext())) {
+					dAWTable = table;
+					break;
+				}
+			}
+			if (dAWTable != null) {
+				List<MKeyBinding> bindings = dAWTable.getBindings();
+				Iterator<MKeyBinding> j = bindings.iterator();
+				removed = 0;
+				while (j.hasNext() && removed < 3) {
+					MKeyBinding binding = j.next();
+					if (toBeRemoved.contains(binding.getCommand())) {
+						j.remove();
+						removed++;
+					}
+				}
+			}
+		}
+		commands.removeAll(toBeRemoved);
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/NavigationHistory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/NavigationHistory.java
new file mode 100644
index 0000000..42e6131
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/NavigationHistory.java
@@ -0,0 +1,948 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Map;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.INavigationHistory;
+import org.eclipse.ui.INavigationLocation;
+import org.eclipse.ui.INavigationLocationProvider;
+import org.eclipse.ui.IPartListener2;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPartReference;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.internal.StartupThreading.StartupRunnable;
+
+/**
+ * Implementation of the back and forward actions.
+ */
+public class NavigationHistory implements INavigationHistory {
+
+	private static final boolean DEBUG= false;
+
+	private static final int CAPACITY = 50;
+
+    private NavigationHistoryAction backwardAction;
+
+    private NavigationHistoryAction forwardAction;
+
+    private int ignoreEntries;
+
+    private ArrayList history = new ArrayList(CAPACITY);
+
+    Map perTabHistoryMap = new HashMap();
+
+    private ArrayList editors = new ArrayList(CAPACITY);
+
+    private IWorkbenchPage page;
+
+    private int activeEntry = 0;
+
+	/**
+	 * Creates a new NavigationHistory to keep the NavigationLocation entries of the specified page.
+	 *
+	 * @param page the workbench page
+	 */
+    public NavigationHistory(final IWorkbenchPage page) {
+        this.page = page;
+        page.addPartListener(new IPartListener2() {
+            @Override
+			public void partActivated(IWorkbenchPartReference partRef) {
+            }
+
+            @Override
+			public void partBroughtToTop(IWorkbenchPartReference partRef) {
+            }
+
+            @Override
+			public void partDeactivated(IWorkbenchPartReference partRef) {
+            }
+
+            @Override
+			public void partOpened(IWorkbenchPartReference partRef) {
+            }
+
+            @Override
+			public void partHidden(IWorkbenchPartReference partRef) {
+            }
+
+            @Override
+			public void partVisible(IWorkbenchPartReference partRef) {
+            }
+
+            @Override
+			public void partClosed(IWorkbenchPartReference partRef) {
+            	if (isPerTabHistoryEnabled() && partRef instanceof EditorReference) {
+            		if (!((EditorReference)partRef).isDisposed()) {
+						Object editorTabCookie = ((EditorReference) partRef).getModel().getWidget();
+	            		disposeHistoryForTab(editorTabCookie);
+	            		updateActions();
+            		}
+            	}
+				updateNavigationHistory(partRef, true);
+            }
+
+			@Override
+			public void partInputChanged(IWorkbenchPartReference partRef) {
+				updateNavigationHistory(partRef, false);
+			}
+
+			private void updateNavigationHistory(IWorkbenchPartReference partRef, boolean partClosed) {
+                if (partRef != null && partRef.getPart(false) instanceof IEditorPart) {
+                    IEditorPart editor = (IEditorPart) partRef.getPart(false);
+                    IEditorInput input = editor.getEditorInput();
+                    String id = editor.getSite().getId();
+                    Iterator e = editors.iterator();
+                    NavigationHistoryEditorInfo info = null;
+                    NavigationHistoryEditorInfo currentInfo = null;
+                    NavigationHistoryEntry current = getEntry(activeEntry);
+                    if (current != null) {
+						currentInfo = current.editorInfo;
+					}
+                    while (e.hasNext()) {
+                        info = (NavigationHistoryEditorInfo) e.next();
+                        if (id.equals(info.editorID)
+                                && input.equals(info.editorInput)) {
+                            if (partClosed && info != currentInfo) {
+								info.handlePartClosed();
+							}
+                            break;
+                        }
+						info = null;
+                    }
+                    if (info == null) {
+						return;
+					}
+                    boolean isEntryDisposed = false;
+                    e = history.iterator();
+                    int i = 0;
+                    while (e.hasNext()) {
+                        NavigationHistoryEntry entry = (NavigationHistoryEntry) e
+                                .next();
+                        if (entry.editorInfo == info) {
+							if (!entry.handlePartClosed()) {
+                                // update the active entry since we are removing an item
+                                if (i < activeEntry) {
+                                    activeEntry--;
+                                } else if (i == activeEntry) {
+                                    if (i != 0) {
+										activeEntry--;
+									}
+                                } else {
+                                    // activeEntry is before item we deleted
+                                    i++;
+                                }
+                                isEntryDisposed = true;
+                                e.remove();
+                                disposeEntry(entry);
+                            } else {
+                                i++;
+                            }
+						}
+                    }
+
+                    /*
+                     * Promote the entry of the last closed editor to be the active
+                     * one, see: https://bugs.eclipse.org/bugs/show_bug.cgi?id=154431
+                     */
+                    if (!isEntryDisposed && page.getActiveEditor() == null && activeEntry < history.size())
+                    	activeEntry++;
+
+                    updateActions();
+                }
+            }
+        });
+    }
+
+    private Display getDisplay() {
+        return page.getWorkbenchWindow().getShell().getDisplay();
+    }
+
+    private boolean isPerTabHistoryEnabled() {
+		return false;
+    }
+
+    /*
+     * Adds an editor to the editor history without getting its location.
+     */
+    public void markEditor(final IEditorPart part) {
+        if (ignoreEntries > 0 || part == null) {
+			return;
+		}
+        /* Ignore all entries until the async exec runs. Workaround to avoid
+         * extra entry when using Open Declaration (F3) that opens another editor. */
+        ignoreEntries++;
+        getDisplay().asyncExec(() -> {
+		    if (--ignoreEntries == 0) {
+		        if (part.getEditorSite() instanceof EditorSite) {
+					EditorSite site = (EditorSite) part.getEditorSite();
+					Control c = (Control) site.getModel().getWidget();
+		            if (c == null || c.isDisposed()) {
+						return;
+					}
+		            NavigationHistoryEntry e = getEntry(activeEntry);
+		            if (e != null
+		                    && part.getEditorInput() != e.editorInfo.editorInput) {
+						updateEntry(e);
+					}
+		            addEntry(part);
+		        }
+		    }
+		});
+    }
+
+    @Override
+	public void markLocation(IEditorPart part) {
+        addEntry(part);
+    }
+
+    /*
+     * Return the backward history entries.  Return in restore order (i.e., the
+     * first entry is the entry that would become active if the "Backward" action
+     * was executed).
+     * <p>
+     * (Called by NavigationHistoryAction)
+     * </p>
+     */
+    NavigationHistoryEntry[] getBackwardEntries() {
+    	if (isPerTabHistoryEnabled()) {
+    		return getEntriesForTab(false);
+    	}
+        int length = activeEntry;
+        NavigationHistoryEntry[] entries = new NavigationHistoryEntry[length];
+        for (int i = 0; i < activeEntry; i++) {
+            entries[activeEntry - 1 - i] = getEntry(i);
+        }
+        return entries;
+    }
+
+    /*
+     * Return the forward history entries.  Return in restore order (i.e., the first
+     * entry is the entry that would become active if the "Forward" action was
+     * executed).
+     * <p>
+     * (Called by NavigationHistoryAction)
+     * </p>
+     */
+    NavigationHistoryEntry[] getForwardEntries() {
+    	if (isPerTabHistoryEnabled()) {
+    		return getEntriesForTab(true);
+    	}
+        int length = history.size() - activeEntry - 1;
+        length = Math.max(0, length);
+        NavigationHistoryEntry[] entries = new NavigationHistoryEntry[length];
+        for (int i = activeEntry + 1; i < history.size(); i++) {
+            entries[i - activeEntry - 1] = getEntry(i);
+        }
+        return entries;
+    }
+
+    @Override
+	public INavigationLocation[] getLocations() {
+        INavigationLocation result[] = new INavigationLocation[history.size()];
+        for (int i = 0; i < result.length; i++) {
+            NavigationHistoryEntry e = (NavigationHistoryEntry) history.get(i);
+            result[i] = e.location;
+        }
+        return result;
+    }
+
+    @Override
+	public INavigationLocation getCurrentLocation() {
+        NavigationHistoryEntry entry = getEntry(activeEntry);
+        return entry == null ? null : entry.location;
+    }
+
+    /**
+     * Disposes this NavigationHistory and all entries.
+     */
+    public void dispose() {
+    	disposeHistoryForTabs();
+        Iterator e = history.iterator();
+        while (e.hasNext()) {
+            NavigationHistoryEntry entry = (NavigationHistoryEntry) e.next();
+            disposeEntry(entry);
+        }
+    }
+
+    /**
+     * Keeps a reference to the forward action to update its state
+     * whenever needed.
+     * <p>
+     * (Called by NavigationHistoryAction)
+     * </p>
+     */
+    void setForwardAction(NavigationHistoryAction action) {
+        forwardAction = action;
+        updateActions();
+    }
+
+    /**
+     * Keeps a reference to the backward action to update its state
+     * whenever needed.
+     * <p>
+     * (Called by NavigationHistoryAction)
+     * </p>
+     */
+    void setBackwardAction(NavigationHistoryAction action) {
+        backwardAction = action;
+        updateActions();
+    }
+
+    /*
+     * Returns the history entry indexed by <code>index</code>
+     */
+    private NavigationHistoryEntry getEntry(int index) {
+        if (0 <= index && index < history.size()) {
+			return (NavigationHistoryEntry) history.get(index);
+		}
+        return null;
+    }
+
+    /*
+     * Adds the specified entry to the history.
+     */
+    private void add(NavigationHistoryEntry entry) {
+        removeForwardEntries();
+        if (history.size() == CAPACITY) {
+            NavigationHistoryEntry e = (NavigationHistoryEntry) history
+                    .remove(0);
+            disposeEntry(e);
+        }
+        history.add(entry);
+        activeEntry = history.size() - 1;
+    }
+
+    /*
+     * Remove all entries after the active entry.
+     */
+    private void removeForwardEntries() {
+        int length = history.size();
+        for (int i = activeEntry + 1; i < length; i++) {
+            NavigationHistoryEntry e = (NavigationHistoryEntry) history
+                    .remove(activeEntry + 1);
+            disposeEntry(e);
+        }
+    }
+
+    /*
+     * Adds a location to the history.
+     */
+    private void addEntry(IEditorPart part) {
+        if (ignoreEntries > 0 || part == null) {
+			return;
+		}
+
+        if (isPerTabHistoryEnabled()) {
+        	markLocationForTab(part);
+        }
+        INavigationLocation location = null;
+        if (part instanceof INavigationLocationProvider) {
+			location = ((INavigationLocationProvider) part)
+                    .createNavigationLocation();
+		}
+
+        NavigationHistoryEntry current = getEntry(activeEntry);
+        if (current != null && current.editorInfo.memento != null) {
+            current.editorInfo.restoreEditor();
+            checkDuplicates(current.editorInfo);
+        }
+        NavigationHistoryEntry e = createEntry(page, part, location);
+        if (current == null) {
+            add(e);
+        } else {
+            if (e.mergeInto(current)) {
+                disposeEntry(e);
+                removeForwardEntries();
+            } else {
+                add(e);
+            }
+        }
+        printEntries("added entry"); //$NON-NLS-1$
+        updateActions();
+    }
+
+    /*
+     * Prints all the entries in the console. For debug only.
+     */
+    private void printEntries(String label) {
+        if (DEBUG) {
+            System.out.println("+++++ " + label + "+++++ "); //$NON-NLS-1$ //$NON-NLS-2$
+            int size = history.size();
+            for (int i = 0; i < size; i++) {
+                String append = activeEntry == i ? ">>" : ""; //$NON-NLS-1$ //$NON-NLS-2$
+                System.out.println(append
+                        + "Index: " + i + " " + history.get(i)); //$NON-NLS-1$ //$NON-NLS-2$
+            }
+        }
+    }
+
+    /*
+     * Returns true if the forward action can be performed otherwise returns false.
+     * <p>
+     * (Called by NavigationHistoryAction)
+     * </p>
+     */
+    /* package */boolean canForward() {
+    	if (isPerTabHistoryEnabled()) {
+    		return hasEntriesForTab(true);
+    	}
+        return (0 <= activeEntry + 1) && (activeEntry + 1 < history.size());
+    }
+
+    /*
+     * Returns true if the backward action can be performed otherwise returns false.
+     * <p>
+     * (Called by NavigationHistoryAction)
+     * </p>
+     */
+    /* package */boolean canBackward() {
+    	if (isPerTabHistoryEnabled()) {
+    		return hasEntriesForTab(false);
+    	}
+        return (0 <= activeEntry - 1) && (activeEntry - 1 < history.size());
+    }
+
+    /*
+     * Update the actions enable/disable and tooltip state.
+     */
+    private void updateActions() {
+        if (backwardAction != null) {
+			backwardAction.update();
+		}
+        if (forwardAction != null) {
+			forwardAction.update();
+		}
+    }
+
+    /*
+     * Restore the specified entry
+     */
+    private void gotoEntry(NavigationHistoryEntry entry) {
+        if (entry == null) {
+			return;
+		}
+        try {
+            ignoreEntries++;
+            if (entry.editorInfo.memento != null) {
+                entry.editorInfo.restoreEditor();
+                checkDuplicates(entry.editorInfo);
+            }
+            entry.restoreLocation();
+            updateActions();
+            printEntries("goto entry"); //$NON-NLS-1$
+        } finally {
+            ignoreEntries--;
+        }
+    }
+
+    /*
+     * update the active entry
+     */
+    private void updateEntry(NavigationHistoryEntry activeEntry) {
+        if (activeEntry == null || activeEntry.location == null) {
+			return;
+		}
+        activeEntry.location.update();
+        printEntries("updateEntry"); //$NON-NLS-1$
+    }
+
+    /*
+     * Perform the forward action by getting the next location and restoring
+     * its context.
+     * <p>
+     * (Called by NavigationHistoryAction)
+     * </p>
+     */
+    void forward() {
+    	if (isPerTabHistoryEnabled()) {
+    		forwardForTab();
+    		return;
+    	}
+        if (canForward()) {
+			shiftEntry(true);
+		}
+    }
+
+    /*
+     * Perform the backward action by getting the previous location and restoring
+     * its context.
+     * <p>
+     * (Called by NavigationHistoryAction)
+     * </p>
+     */
+    void backward() {
+    	if (isPerTabHistoryEnabled()) {
+    		backwardForTab();
+    		return;
+    	}
+        if (canBackward()) {
+			shiftEntry(false);
+		}
+    }
+
+    /*
+     * Shift the history back or forward
+     */
+    private void shiftEntry(boolean forward) {
+        updateEntry(getEntry(activeEntry));
+        if (forward) {
+			activeEntry++;
+		} else {
+			activeEntry--;
+		}
+        NavigationHistoryEntry entry = getEntry(activeEntry);
+        if (entry != null) {
+			gotoEntry(entry);
+		}
+    }
+
+    /*
+     * Shift the history to the given entry.
+     * <p>
+     * (Called by NavigationHistoryAction)
+     * </p>
+     */
+    void shiftCurrentEntry(NavigationHistoryEntry entry, boolean forward) {
+    	if (isPerTabHistoryEnabled()) {
+    		gotoEntryForTab(entry, forward);
+    		return;
+    	}
+        updateEntry(getEntry(activeEntry));
+        activeEntry = history.indexOf(entry);
+        gotoEntry(entry);
+    }
+
+    /**
+     * Save the state of this history into the memento.
+     */
+    void saveState(IMemento memento) {
+        NavigationHistoryEntry cEntry = getEntry(activeEntry);
+        if (cEntry == null || !cEntry.editorInfo.isPersistable()) {
+			return;
+		}
+
+        ArrayList editors = (ArrayList) this.editors.clone();
+        for (Iterator iter = editors.iterator(); iter.hasNext();) {
+            NavigationHistoryEditorInfo info = (NavigationHistoryEditorInfo) iter
+                    .next();
+            if (!info.isPersistable()) {
+				iter.remove();
+			}
+        }
+        IMemento editorsMem = memento
+                .createChild(IWorkbenchConstants.TAG_EDITORS);
+        for (Iterator iter = editors.iterator(); iter.hasNext();) {
+            NavigationHistoryEditorInfo info = (NavigationHistoryEditorInfo) iter
+                    .next();
+            info.saveState(editorsMem
+                    .createChild(IWorkbenchConstants.TAG_EDITOR));
+        }
+
+        ArrayList list = new ArrayList(history.size());
+        int size = history.size();
+        for (int i = 0; i < size; i++) {
+            NavigationHistoryEntry entry = (NavigationHistoryEntry) history
+                    .get(i);
+            if (entry.editorInfo.isPersistable()) {
+				list.add(entry);
+			}
+        }
+        size = list.size();
+        for (int i = 0; i < size; i++) {
+            NavigationHistoryEntry entry = (NavigationHistoryEntry) list.get(i);
+            IMemento childMem = memento
+                    .createChild(IWorkbenchConstants.TAG_ITEM);
+            if (entry == cEntry) {
+				childMem.putString(IWorkbenchConstants.TAG_ACTIVE, "true"); //$NON-NLS-1$
+			}
+            entry.saveState(childMem, list);
+            childMem.putInteger(IWorkbenchConstants.TAG_INDEX, editors
+                    .indexOf(entry.editorInfo));
+        }
+    }
+
+    /**
+     * Restore the state of this history from the memento.
+     */
+    void restoreState(IMemento memento) {
+        IMemento editorsMem = memento.getChild(IWorkbenchConstants.TAG_EDITORS);
+        IMemento items[] = memento.getChildren(IWorkbenchConstants.TAG_ITEM);
+        if (items.length == 0 || editorsMem == null) {
+            if (page.getActiveEditor() != null) {
+				markLocation(page.getActiveEditor());
+			}
+            return;
+        }
+
+        IMemento children[] = editorsMem
+                .getChildren(IWorkbenchConstants.TAG_EDITOR);
+        NavigationHistoryEditorInfo editorsInfo[] = new NavigationHistoryEditorInfo[children.length];
+        for (int i = 0; i < editorsInfo.length; i++) {
+            editorsInfo[i] = new NavigationHistoryEditorInfo(children[i]);
+            editors.add(editorsInfo[i]);
+        }
+
+        for (int i = 0; i < items.length; i++) {
+            IMemento item = items[i];
+            int index = item.getInteger(IWorkbenchConstants.TAG_INDEX)
+                    .intValue();
+            NavigationHistoryEditorInfo info = editorsInfo[index];
+            info.refCount++;
+            NavigationHistoryEntry entry = new NavigationHistoryEntry(info,
+                    page, null, null);
+            history.add(entry);
+            entry.restoreState(item);
+            if (item.getString(IWorkbenchConstants.TAG_ACTIVE) != null) {
+				activeEntry = i;
+			}
+        }
+
+        final NavigationHistoryEntry entry = getEntry(activeEntry);
+        if (entry != null && entry.editorInfo.editorInput != null) {
+            if (page.getActiveEditor() == page
+                    .findEditor(entry.editorInfo.editorInput)) {
+            	StartupThreading.runWithoutExceptions(new StartupRunnable() {
+
+					@Override
+					public void runWithException() throws Throwable {
+						gotoEntry(entry);
+					}});
+			}
+        }
+    }
+
+    public NavigationHistoryEntry createEntry(IWorkbenchPage page,
+            IEditorPart part, INavigationLocation location) {
+        String editorID = part.getSite().getId();
+        IEditorInput editorInput = part.getEditorInput();
+        NavigationHistoryEditorInfo info = null;
+        for (Iterator iter = editors.iterator(); iter.hasNext();) {
+            info = (NavigationHistoryEditorInfo) iter.next();
+            if (editorID.equals(info.editorID)
+                    && editorInput.equals(info.editorInput)) {
+                info.refCount++;
+                break;
+            }
+			info= null;
+        }
+        if (info == null) {
+            info = new NavigationHistoryEditorInfo(part);
+            info.refCount++;
+            editors.add(info);
+        }
+        return new NavigationHistoryEntry(info, page, part, location);
+    }
+
+    public void disposeEntry(NavigationHistoryEntry entry) {
+        if (entry.editorInfo == null) {
+			return;
+		}
+        entry.editorInfo.refCount--;
+        if (entry.editorInfo.refCount == 0) {
+			editors.remove(entry.editorInfo);
+		}
+        entry.dispose();
+    }
+
+    void checkDuplicates(NavigationHistoryEditorInfo info) {
+        NavigationHistoryEditorInfo dup = null;
+        if (info.editorInput == null) {
+			return;
+		}
+        for (Iterator iter = editors.iterator(); iter.hasNext();) {
+            dup = (NavigationHistoryEditorInfo) iter.next();
+            if (info != dup && info.editorID.equals(dup.editorID)
+                    && info.editorInput.equals(dup.editorInput)) {
+				break;
+			}
+			dup= null;
+        }
+        if (dup == null) {
+			return;
+		}
+        for (Iterator iter = history.iterator(); iter.hasNext();) {
+            NavigationHistoryEntry entry = (NavigationHistoryEntry) iter.next();
+            if (entry.editorInfo == dup) {
+                entry.editorInfo = info;
+                info.refCount++;
+            }
+        }
+        editors.remove(dup);
+    }
+
+    /*********************************************************/
+    /*** new per-tab history code                          ***/
+    /*********************************************************/
+
+
+    private static class PerTabHistory {
+    	LinkedList backwardEntries = new LinkedList();
+    	NavigationHistoryEntry currentEntry = null;
+    	LinkedList forwardEntries = new LinkedList();
+    }
+
+    private void setNewCurrentEntryForTab(PerTabHistory perTabHistory, NavigationHistoryEntry entry) {
+    	if (perTabHistory.currentEntry != null) {
+    		perTabHistory.backwardEntries.addFirst(perTabHistory.currentEntry);
+    	}
+    	perTabHistory.currentEntry = entry;
+    	removeEntriesForTab(perTabHistory.forwardEntries);
+    }
+
+    private Object getCookieForTab(IEditorPart part) {
+    	if (part != null) {
+	        IWorkbenchPartSite site = part.getSite();
+	        if (site instanceof PartSite) {
+	        	PartSite partSite = (PartSite) site;
+	        	WorkbenchPartReference ref = (WorkbenchPartReference) partSite.getPartReference();
+	        	if (!ref.isDisposed()) {
+					return partSite.getModel().getWidget();
+	        	}
+	        }
+    	}
+    	return null;
+    }
+
+    private void markLocationForTab(IEditorPart part) {
+    	if (part instanceof ErrorEditorPart) {
+    		updateActions();
+    		return;
+    	}
+		Object tabCookie = getCookieForTab(part);
+		if (tabCookie != null) {
+			INavigationLocation location = null;
+			if (part instanceof INavigationLocationProvider) {
+				location = ((INavigationLocationProvider) part)
+						.createNavigationLocation();
+			}
+			PerTabHistory perTabHistory = (PerTabHistory) perTabHistoryMap
+					.get(tabCookie);
+			if (perTabHistory == null) {
+				perTabHistory = new PerTabHistory();
+				perTabHistoryMap.put(tabCookie, perTabHistory);
+			}
+			NavigationHistoryEntry current = perTabHistory.currentEntry;
+			if (current != null && current.editorInfo.memento != null) {
+				current.editorInfo.restoreEditor();
+				checkDuplicates(current.editorInfo);
+			}
+			NavigationHistoryEntry entry = createEntry(page, part, location);
+			if (current != null && entry.mergeInto(current)) {
+				disposeEntry(entry);
+				removeEntriesForTab(perTabHistory.forwardEntries);
+			} else {
+				setNewCurrentEntryForTab(perTabHistory, entry);
+			}
+		}
+		updateActions();
+	}
+
+    public void updateCookieForTab(Object oldCookie, Object newCookie) {
+    	if (newCookie.equals(oldCookie)) {
+    		return;
+    	}
+    	PerTabHistory perTabHistory = (PerTabHistory) perTabHistoryMap.remove(oldCookie);
+    	if (perTabHistory != null) {
+    		perTabHistoryMap.put(newCookie, perTabHistory);
+    	}
+    }
+
+    private void gotoEntryForTab(NavigationHistoryEntry target, boolean forward) {
+    	Object editorTabCookie = getCookieForTab(page.getActiveEditor());
+    	if (editorTabCookie!=null) {
+	    	PerTabHistory perTabHistory = (PerTabHistory) perTabHistoryMap.get(editorTabCookie);
+	    	if (perTabHistory != null) {
+	    		LinkedList source = forward ? perTabHistory.forwardEntries : perTabHistory.backwardEntries;
+	    		LinkedList destination = forward ? perTabHistory.backwardEntries : perTabHistory.forwardEntries;
+				if (perTabHistory.currentEntry != null) {
+					if (perTabHistory.currentEntry.location != null) {
+						perTabHistory.currentEntry.location.update();
+					}
+					destination.addFirst(perTabHistory.currentEntry);
+				}
+				NavigationHistoryEntry newCurrent = null;
+	    		while (!source.isEmpty() && newCurrent==null) {
+		    		NavigationHistoryEntry entry = (NavigationHistoryEntry) source
+							.removeFirst();
+		    		if (entry.equals(target)) {
+		    			newCurrent = entry;
+		    		} else {
+		    			destination.addFirst(entry);
+		    		}
+	    		}
+	    		Assert.isTrue(newCurrent != null);
+	    		perTabHistory.currentEntry = newCurrent;
+	            try {
+	                ignoreEntries++;
+	                if (newCurrent.editorInfo.memento != null) {
+	                	newCurrent.editorInfo.restoreEditor();
+	                	checkDuplicates(newCurrent.editorInfo);
+	                }
+	                newCurrent.restoreLocation();
+	                updateActions();
+	            } finally {
+	            	ignoreEntries--;
+	            }
+	    	}
+    	}
+    }
+
+	private void forwardForTab() {
+    	Object editorTabCookie = getCookieForTab(page.getActiveEditor());
+    	if (editorTabCookie!=null) {
+	    	PerTabHistory perTabHistory = (PerTabHistory) perTabHistoryMap.get(editorTabCookie);
+	    	if (perTabHistory != null && !perTabHistory.forwardEntries.isEmpty()) {
+	    		NavigationHistoryEntry newCurrent = (NavigationHistoryEntry) perTabHistory.forwardEntries
+						.removeFirst();
+	    		if (perTabHistory.currentEntry != null) {
+	    			final INavigationLocation location = perTabHistory.currentEntry.location;
+	    			if (location!=null) {
+	    				location.update();
+	    			}
+	    			perTabHistory.backwardEntries.addFirst(perTabHistory.currentEntry);
+	    		}
+	    		perTabHistory.currentEntry = newCurrent;
+	            try {
+	                ignoreEntries++;
+	                if (newCurrent.editorInfo.memento != null) {
+	                	newCurrent.editorInfo.restoreEditor();
+	                	checkDuplicates(newCurrent.editorInfo);
+	                }
+	                newCurrent.restoreLocation();
+	                updateActions();
+	            } finally {
+	            	ignoreEntries--;
+	            }
+	    	}
+    	}
+    }
+
+    private void backwardForTab() {
+    	Object editorTabCookie = getCookieForTab(page.getActiveEditor());
+    	if (editorTabCookie!=null) {
+	    	PerTabHistory perTabHistory = (PerTabHistory) perTabHistoryMap.get(editorTabCookie);
+	    	if (perTabHistory != null && !perTabHistory.backwardEntries.isEmpty()) {
+	    		NavigationHistoryEntry newCurrent = (NavigationHistoryEntry) perTabHistory.backwardEntries
+	    				.removeFirst();
+	    		if (perTabHistory.currentEntry != null) {
+	    			perTabHistory.currentEntry.location.update();
+	    			perTabHistory.forwardEntries.addFirst(perTabHistory.currentEntry);
+	    		}
+	    		perTabHistory.currentEntry = newCurrent;
+	            try {
+	                ignoreEntries++;
+	                if (newCurrent.editorInfo.memento != null) {
+	                	newCurrent.editorInfo.restoreEditor();
+	                	checkDuplicates(newCurrent.editorInfo);
+	                }
+	                newCurrent.restoreLocation();
+	                updateActions();
+	            } finally {
+	            	ignoreEntries--;
+	            }
+	    	}
+    	}
+    }
+
+    private boolean hasEntriesForTab(boolean forward) {
+    	Object editorTabCookie = getCookieForTab(page.getActiveEditor());
+    	if (editorTabCookie!=null) {
+	    	PerTabHistory perTabHistory = (PerTabHistory) perTabHistoryMap.get(editorTabCookie);
+	    	if (perTabHistory != null) {
+		    	LinkedList entries = forward ? perTabHistory.forwardEntries : perTabHistory.backwardEntries;
+		    	return !entries.isEmpty();
+	    	}
+    	}
+    	return false;
+    }
+
+	/**
+	 * Returns entries in restore order.
+	 *
+	 * @param forward <code>true</code> for forward and <code>false</code> for backward history
+	 * @return the navigation history entries
+	 */
+    private NavigationHistoryEntry[] getEntriesForTab(boolean forward) {
+		Object editorTabCookie = getCookieForTab(page.getActiveEditor());
+		if (editorTabCookie != null) {
+			PerTabHistory perTabHistory = (PerTabHistory) perTabHistoryMap
+					.get(editorTabCookie);
+			if (perTabHistory != null) {
+				LinkedList entries = forward ? perTabHistory.forwardEntries
+						: perTabHistory.backwardEntries;
+				return (NavigationHistoryEntry[]) entries
+				.toArray(new NavigationHistoryEntry[entries.size()]);
+			}
+		}
+		return new NavigationHistoryEntry[0];
+	}
+
+    private void disposeHistoryForTabs() {
+    	Object[] keys = perTabHistoryMap.keySet().toArray();
+    	for (Object key : keys) {
+			disposeHistoryForTab(key);
+		}
+    }
+
+    void disposeHistoryForTab(Object editorTabCookie) {
+    	PerTabHistory perTabHistory = (PerTabHistory) perTabHistoryMap.remove(editorTabCookie);
+    	if (perTabHistory != null) {
+    		if (perTabHistory.currentEntry != null) {
+    			disposeEntry(perTabHistory.currentEntry);
+    			perTabHistory.currentEntry = null;
+    		}
+    		removeEntriesForTab(perTabHistory.backwardEntries);
+    		removeEntriesForTab(perTabHistory.forwardEntries);
+    	}
+    }
+
+	private void removeEntriesForTab(LinkedList entries) {
+		for (Iterator it = entries.iterator(); it.hasNext();) {
+			NavigationHistoryEntry entry = (NavigationHistoryEntry) it.next();
+			disposeEntry(entry);
+			it.remove();
+		}
+	}
+
+	public boolean updateActive(IEditorPart editor) {
+        NavigationHistoryEntry e = getEntry(activeEntry);
+        if (e == null)
+        	return false;
+        // 1) check if editor ID matches
+        IWorkbenchPartSite site = editor.getSite();
+        if (site == null) // might happen if site has not being initialized yet
+        	return false;
+        String editorID = site.getId();
+        if (editorID == null) // should not happen for an editor
+        	return false;
+        if (!editorID.equals(e.editorInfo.editorID))
+            return false;
+        // 2) check that input matches
+		IEditorInput input = editor.getEditorInput();
+		if (input == null)
+			return false;
+		if (!input.equals(e.editorInfo.editorInput))
+			return false;
+		updateEntry(e);
+		return true;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/NavigationHistoryAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/NavigationHistoryAction.java
new file mode 100644
index 0000000..5c2978f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/NavigationHistoryAction.java
@@ -0,0 +1,279 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+
+import org.eclipse.jface.action.IMenuCreator;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MenuAdapter;
+import org.eclipse.swt.events.MenuEvent;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+
+/**
+ * The <code>NavigationHistoryAction</code> moves navigation history
+ * back and forward.
+ */
+public class NavigationHistoryAction extends PageEventAction {
+
+	private boolean recreateMenu;
+
+	private boolean forward;
+
+    private Menu historyMenu;
+
+    private int MAX_HISTORY_LENGTH = 9;
+
+    private class MenuCreator implements IMenuCreator {
+        @Override
+		public void dispose() {
+        }
+
+        @Override
+		public Menu getMenu(Menu parent) {
+        	setMenu(new Menu(parent));
+        	fillMenu(historyMenu);
+            initMenu();
+            return historyMenu;
+        }
+
+        @Override
+		public Menu getMenu(Control parent) {
+        	setMenu(new Menu(parent));
+        	fillMenu(historyMenu);
+            initMenu();
+            return historyMenu;
+        }
+
+    }
+
+    private void setMenu(Menu menu) {
+    	historyMenu = menu;
+    }
+
+    private void initMenu() {
+    	historyMenu.addMenuListener(new MenuAdapter() {
+    		@Override
+			public void menuShown(MenuEvent e) {
+    			if (recreateMenu) {
+					Menu m = (Menu) e.widget;
+					MenuItem[] items = m.getItems();
+					for (MenuItem item : items) {
+						item.dispose();
+					}
+					fillMenu(m);
+				}
+			}
+    	});
+    }
+
+    private void fillMenu(Menu menu) {
+    	IWorkbenchPage page = getWorkbenchWindow().getActivePage();
+    	if (page == null) {
+    		return;
+    	}
+
+    	final NavigationHistory history = (NavigationHistory) getWorkbenchWindow()
+    	.getActivePage().getNavigationHistory();
+    	NavigationHistoryEntry[] entries;
+    	if (forward) {
+    		entries = history.getForwardEntries();
+    	} else {
+    		entries = history.getBackwardEntries();
+    	}
+    	int entriesCount[] = new int[entries.length];
+    	for (int i = 0; i < entriesCount.length; i++) {
+    		entriesCount[i] = 1;
+    	}
+    	entries = collapseEntries(entries, entriesCount);
+    	for (int i = 0; i < entries.length; i++) {
+    		if (i > MAX_HISTORY_LENGTH) {
+    			break;
+    		}
+    		String text = entries[i].getHistoryText();
+    		if (text != null) {
+    			MenuItem item = new MenuItem(menu, SWT.NONE);
+    			item.setData(entries[i]);
+    			if (entriesCount[i] > 1) {
+					text = NLS.bind(WorkbenchMessages.get().NavigationHistoryAction_locations, text,
+							Integer.valueOf(entriesCount[i]));
+    			}
+    			item.setText(text);
+				item.addSelectionListener(new SelectionAdapter()
+                {
+				    public void widgetSelected(SelectionEvent e) {
+				        history.shiftCurrentEntry((NavigationHistoryEntry) e.widget.getData(), forward);
+				    }
+                });
+    		}
+    	}
+    	recreateMenu = false;
+    }
+
+    @Override
+	public void dispose() {
+    	super.dispose();
+    	if (historyMenu != null) {
+    		for (int i = 0; i < historyMenu.getItemCount(); i++) {
+    			MenuItem menuItem = historyMenu.getItem(i);
+    			menuItem.dispose();
+    		}
+    		historyMenu.dispose();
+    		historyMenu = null;
+    	}
+    }
+
+    /**
+	 * Create a new instance of <code>NavigationHistoryAction</code>
+	 *
+	 * @param window
+	 *            the workbench window this action applies to
+	 * @param forward
+	 *            if this action should move history forward of backward
+	 */
+    public NavigationHistoryAction(IWorkbenchWindow window, boolean forward) {
+        super("", window); //$NON-NLS-1$
+        ISharedImages sharedImages = window.getWorkbench().getSharedImages();
+        if (forward) {
+            setText(WorkbenchMessages.get().NavigationHistoryAction_forward_text);
+            setToolTipText(WorkbenchMessages.get().NavigationHistoryAction_forward_toolTip);
+            // @issue missing action id
+            window.getWorkbench().getHelpSystem().setHelp(this,
+					IWorkbenchHelpContextIds.NAVIGATION_HISTORY_FORWARD);
+            setImageDescriptor(sharedImages
+                    .getImageDescriptor(ISharedImages.IMG_TOOL_FORWARD));
+            setDisabledImageDescriptor(sharedImages
+                    .getImageDescriptor(ISharedImages.IMG_TOOL_FORWARD_DISABLED));
+            setActionDefinitionId(IWorkbenchCommandConstants.NAVIGATE_FORWARD_HISTORY);
+        } else {
+            setText(WorkbenchMessages.get().NavigationHistoryAction_backward_text);
+            setToolTipText(WorkbenchMessages.get().NavigationHistoryAction_backward_toolTip);
+            // @issue missing action id
+            window.getWorkbench().getHelpSystem().setHelp(this,
+					IWorkbenchHelpContextIds.NAVIGATION_HISTORY_BACKWARD);
+            setImageDescriptor(sharedImages
+                    .getImageDescriptor(ISharedImages.IMG_TOOL_BACK));
+            setDisabledImageDescriptor(sharedImages
+                    .getImageDescriptor(ISharedImages.IMG_TOOL_BACK_DISABLED));
+            setActionDefinitionId(IWorkbenchCommandConstants.NAVIGATE_BACKWARD_HISTORY);
+        }
+        // PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IHelpContextIds.CLOSE_ALL_PAGES_ACTION);
+        setEnabled(false);
+        this.forward = forward;
+        setMenuCreator(new MenuCreator());
+    }
+
+    @Override
+	public void pageClosed(IWorkbenchPage page) {
+        super.pageClosed(page);
+        setEnabled(false);
+    }
+
+    private NavigationHistoryEntry[] collapseEntries(
+            NavigationHistoryEntry[] entries, int entriesCount[]) {
+        ArrayList allEntries = new ArrayList(Arrays.asList(entries));
+        NavigationHistoryEntry previousEntry = null;
+        int i = -1;
+        for (Iterator iter = allEntries.iterator(); iter.hasNext();) {
+            NavigationHistoryEntry entry = (NavigationHistoryEntry) iter.next();
+            if (previousEntry != null) {
+                String text = previousEntry.getHistoryText();
+                if (text != null) {
+                    if (text.equals(entry.getHistoryText())
+                            && previousEntry.editorInfo == entry.editorInfo) {
+                        iter.remove();
+                        entriesCount[i]++;
+                        continue;
+                    }
+                }
+            }
+            previousEntry = entry;
+            i++;
+        }
+        entries = new NavigationHistoryEntry[allEntries.size()];
+        return (NavigationHistoryEntry[]) allEntries.toArray(entries);
+    }
+
+    @Override
+	public void pageActivated(IWorkbenchPage page) {
+        super.pageActivated(page);
+        NavigationHistory nh = (NavigationHistory) page.getNavigationHistory();
+        if (forward) {
+            nh.setForwardAction(this);
+        } else {
+            nh.setBackwardAction(this);
+        }
+    }
+
+    @Override
+	public void run() {
+        if (getWorkbenchWindow() == null) {
+            // action has been disposed
+            return;
+        }
+        IWorkbenchPage page = getActivePage();
+        if (page != null) {
+            NavigationHistory nh = (NavigationHistory) page
+                    .getNavigationHistory();
+            if (forward) {
+                nh.forward();
+            } else {
+                nh.backward();
+            }
+            recreateMenu = true;
+        }
+    }
+
+    public void update() {
+        // Set the enabled state of the action and set the tool tip text.  The tool tip
+        // text is set to reflect the item that one will move back/forward to.
+        WorkbenchPage page = (WorkbenchPage) getActivePage();
+        if (page == null) {
+			return;
+		}
+        NavigationHistory history = (NavigationHistory) page
+                .getNavigationHistory();
+        NavigationHistoryEntry[] entries;
+        if (forward) {
+            setEnabled(history.canForward());
+            entries = history.getForwardEntries();
+            if (entries.length > 0) {
+                NavigationHistoryEntry entry = entries[0];
+                String text = NLS.bind(WorkbenchMessages.get().NavigationHistoryAction_forward_toolTipName, entry.getHistoryText() );
+                setToolTipText(text);
+            } else {
+                setToolTipText(WorkbenchMessages.get().NavigationHistoryAction_forward_toolTip);
+            }
+        } else {
+            setEnabled(history.canBackward());
+            entries = history.getBackwardEntries();
+            if (entries.length > 0) {
+                NavigationHistoryEntry entry = entries[0];
+                String text = NLS.bind(WorkbenchMessages.get().NavigationHistoryAction_backward_toolTipName, entry.getHistoryText() );
+                setToolTipText(text);
+            } else {
+                setToolTipText(WorkbenchMessages.get().NavigationHistoryAction_backward_toolTip);
+            }
+        }
+        recreateMenu = true;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/NavigationHistoryEditorInfo.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/NavigationHistoryEditorInfo.java
new file mode 100644
index 0000000..e8976fc
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/NavigationHistoryEditorInfo.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IElementFactory;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IPersistableElement;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.XMLMemento;
+
+/**
+ * Keeps the info to save, restore or identify and editor.
+ * Instances of this class are shared between history entries and there should be
+ * only one instance making reference to the same editor.
+ */
+public class NavigationHistoryEditorInfo {
+    String editorID;
+
+    IEditorInput editorInput;
+
+    int refCount = 0;
+
+    IMemento memento;
+
+    NavigationHistoryEditorInfo(IEditorPart part) {
+        editorID = part.getSite().getId();
+        editorInput = part.getEditorInput();
+    }
+
+    NavigationHistoryEditorInfo(IMemento memento) {
+        this.memento = memento;
+    }
+
+    boolean isPersistable() {
+        if (editorInput != null) {
+            IPersistableElement persistable = editorInput.getPersistable();
+            return persistable != null;
+        }
+        return memento != null;
+    }
+
+    void handlePartClosed() {
+        if (!isPersistable()) {
+			return;
+		}
+        if (memento == null) {
+            IPersistableElement persistable = editorInput.getPersistable();
+            memento = XMLMemento
+                    .createWriteRoot(IWorkbenchConstants.TAG_EDITOR);
+            memento.putString(IWorkbenchConstants.TAG_ID, editorID);
+            memento.putString(IWorkbenchConstants.TAG_FACTORY_ID, persistable
+                    .getFactoryId());
+            persistable.saveState(memento);
+        }
+        editorID = null;
+        editorInput = null;
+    }
+
+    void restoreEditor() {
+        if (memento == null) {
+			return;
+		}
+        String factoryID = memento
+                .getString(IWorkbenchConstants.TAG_FACTORY_ID);
+        IElementFactory factory = PlatformUI.getWorkbench().getElementFactory(
+                factoryID);
+        if (factory != null) {
+            IAdaptable element = factory.createElement(memento);
+            if (element instanceof IEditorInput) {
+                editorInput = (IEditorInput) element;
+                editorID = memento.getString(IWorkbenchConstants.TAG_ID);
+            }
+        }
+        memento = null;
+    }
+
+    void saveState(IMemento mem) {
+        if (editorInput != null) {
+            IPersistableElement persistable = editorInput.getPersistable();
+            mem.putString(IWorkbenchConstants.TAG_ID, editorID);
+            mem.putString(IWorkbenchConstants.TAG_FACTORY_ID, persistable
+                    .getFactoryId());
+            persistable.saveState(mem);
+        } else if (memento != null) {
+            mem.putMemento(memento);
+        }
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/NavigationHistoryEntry.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/NavigationHistoryEntry.java
new file mode 100644
index 0000000..ce60184
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/NavigationHistoryEntry.java
@@ -0,0 +1,189 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import java.util.ArrayList;
+
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.INavigationLocation;
+import org.eclipse.ui.INavigationLocationProvider;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.XMLMemento;
+
+/*
+ * Wraps the INavigationLocation and keeps editor info.
+ */
+public class NavigationHistoryEntry {
+
+    private IWorkbenchPage page;
+
+    NavigationHistoryEditorInfo editorInfo;
+
+    String historyText;
+
+    /* Both may be set at the same time. */
+    INavigationLocation location;
+
+    private IMemento locationMemento;
+
+    /**
+     * Constructs a new HistoryEntry and intializes its editor input and editor id.
+     */
+    public NavigationHistoryEntry(NavigationHistoryEditorInfo editorInfo,
+            IWorkbenchPage page, IEditorPart part, INavigationLocation location) {
+        this.editorInfo = editorInfo;
+        this.page = page;
+        this.location = location;
+        if (location != null) {
+            historyText = location.getText();
+        }
+        // ensure that the historyText is initialized to something
+        if (historyText == null || historyText.length() == 0) {
+            if (part != null) {
+				historyText = part.getTitle();
+			}
+        }
+    }
+
+    /**
+     * Restores the state of the entry and the location if needed and then
+     * restores the location.
+     */
+    void restoreLocation() {
+        if (editorInfo.editorInput != null && editorInfo.editorID != null) {
+            try {
+                IEditorPart editor = page.openEditor(editorInfo.editorInput,
+                        editorInfo.editorID, true);
+                if (location == null) {
+                    if (editor instanceof INavigationLocationProvider) {
+						location = ((INavigationLocationProvider) editor)
+                                .createEmptyNavigationLocation();
+					}
+                }
+
+                if (location != null) {
+                    if (locationMemento != null) {
+                        location.setInput(editorInfo.editorInput);
+                        location.restoreState(locationMemento);
+                        locationMemento = null;
+                    }
+                    location.restoreLocation();
+                }
+            } catch (PartInitException e) {
+                // ignore for now
+            }
+        }
+    }
+
+    /**
+     * Return the label to display in the history drop down list.  Use the
+     * history entry text if the location has not been restored yet.
+     */
+    String getHistoryText() {
+        if (location != null) {
+            // location exists or has been restored, use its text.
+            // Also update the historyText so that this value will
+            // be saved.  Doing so handles cases where getText() value
+            // may be dynamic.
+            String text = location.getText();
+            if ((text == null) || text.equals("")) { //$NON-NLS-1$
+                text = historyText;
+            } else {
+                historyText = text;
+            }
+            return text;
+        } else {
+            return historyText;
+        }
+    }
+
+    /**
+     * Saves the state of this entry and its location.
+     * Returns true if possible otherwise returns false.
+     */
+    boolean handlePartClosed() {
+        if (!editorInfo.isPersistable()) {
+			return false;
+		}
+        if (location != null) {
+            locationMemento = XMLMemento
+                    .createWriteRoot(IWorkbenchConstants.TAG_POSITION);
+            location.saveState(locationMemento);
+            location.releaseState();
+        }
+        return true;
+    }
+
+    /**
+     * Saves the state of this entry and its location.
+     */
+    void saveState(IMemento mem, ArrayList entries) {
+        mem.putString(IWorkbenchConstants.TAG_HISTORY_LABEL, getHistoryText());
+        if (locationMemento != null) {
+            IMemento childMem = mem
+                    .createChild(IWorkbenchConstants.TAG_POSITION);
+            childMem.putMemento(locationMemento);
+        } else if (location != null) {
+            IMemento childMem = mem
+                    .createChild(IWorkbenchConstants.TAG_POSITION);
+            location.saveState(childMem);
+        }
+    }
+
+    /**
+     * Restore the state of this entry.
+     */
+    void restoreState(IMemento mem) {
+        historyText = mem.getString(IWorkbenchConstants.TAG_HISTORY_LABEL);
+        locationMemento = mem.getChild(IWorkbenchConstants.TAG_POSITION);
+    }
+
+    @Override
+	public String toString() {
+        return "Input<" + editorInfo.editorInput + "> Details<" + location + ">"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+    }
+
+    /**
+     * Disposes this entry and its location.
+     */
+    void dispose() {
+        if (location != null) {
+			location.dispose();
+		}
+        editorInfo = null;
+    }
+
+    /**
+     * Merges this entry into the current entry. Returns true
+     * if the merge was possible otherwise returns false.
+     */
+    boolean mergeInto(NavigationHistoryEntry currentEntry) {
+        if (editorInfo.editorInput != null
+                && editorInfo.editorInput
+                        .equals(currentEntry.editorInfo.editorInput)) {
+            if (location != null) {
+                if (currentEntry.location == null) {
+                    currentEntry.location = location;
+                    location = null;
+                    return true;
+                } else {
+                    return location.mergeInto(currentEntry.location);
+                }
+            } else if (currentEntry.location == null) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ObjectActionContributor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ObjectActionContributor.java
new file mode 100644
index 0000000..bf5ec37
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ObjectActionContributor.java
@@ -0,0 +1,407 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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.ui.internal;
+
+import java.util.List;
+import org.eclipse.core.expressions.EvaluationContext;
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.ExpressionConverter;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.SelectionEnabler;
+import org.eclipse.ui.internal.misc.Policy;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.model.IWorkbenchAdapter;
+
+/**
+ * This class describes the object contribution element within the popup menu
+ * action registry.
+ */
+public class ObjectActionContributor extends PluginActionBuilder implements
+        IObjectActionContributor, IAdaptable {
+
+    private static final String P_TRUE = "true"; //$NON-NLS-1$
+
+    private IConfigurationElement config;
+
+    private boolean configRead = false;
+
+    private boolean adaptable = false;
+
+    private String objectClass;
+
+    /**
+     * The constructor.
+     *
+     * @param config the element
+     */
+    public ObjectActionContributor(IConfigurationElement config) {
+        this.config = config;
+        this.adaptable = P_TRUE.equalsIgnoreCase(config
+                .getAttribute(IWorkbenchRegistryConstants.ATT_ADAPTABLE));
+        this.objectClass = config.getAttribute(IWorkbenchRegistryConstants.ATT_OBJECTCLASS);
+    }
+
+    @Override
+	public boolean canAdapt() {
+        return adaptable;
+    }
+
+    /**
+     * Return the object class for this contributor.
+     *
+     * @return the object class
+     */
+	public String getObjectClass() {
+		return objectClass;
+	}
+
+    @Override
+	public void contributeObjectActionIdOverrides(List actionIdOverrides) {
+        if (!configRead) {
+			readConfigElement();
+		}
+
+        // Easy case out if no actions
+        if (currentContribution.actions != null) {
+            for (int i = 0; i < currentContribution.actions.size(); i++) {
+                ActionDescriptor ad = (ActionDescriptor) currentContribution.actions
+                        .get(i);
+                String id = ad.getAction().getOverrideActionId();
+                if (id != null) {
+					actionIdOverrides.add(id);
+				}
+            }
+        }
+    }
+
+    /**
+     * Contributes actions applicable for the current selection.
+     */
+    @Override
+	public boolean contributeObjectActions(final IWorkbenchPart part,
+            IMenuManager menu, ISelectionProvider selProv,
+            List actionIdOverrides) {
+        if (!configRead) {
+			readConfigElement();
+		}
+
+        // Easy case out if no actions
+        if (currentContribution.actions == null) {
+			return false;
+		}
+
+        // Get a structured selection.
+        ISelection sel = selProv.getSelection();
+        if ((sel == null) || !(sel instanceof IStructuredSelection)) {
+			return false;
+		}
+        IStructuredSelection ssel = (IStructuredSelection) sel;
+
+        if(canAdapt()) {
+           IStructuredSelection newSelection = LegacyResourceSupport.adaptSelection(ssel, getObjectClass());
+           if(newSelection.size() != ssel.size()) {
+        	   if (Policy.DEBUG_CONTRIBUTIONS) {
+				WorkbenchPlugin.log("Error adapting selection to " + getObjectClass() +  //$NON-NLS-1$
+            			". Contribution " + getID(config) + " is being ignored"); //$NON-NLS-1$ //$NON-NLS-2$
+			}
+            	return false;
+           }
+           ssel = newSelection;
+        }
+
+        final IStructuredSelection selection = ssel;
+
+        // Generate menu.
+        for (int i = 0; i < currentContribution.actions.size(); i++) {
+            ActionDescriptor ad = (ActionDescriptor) currentContribution.actions
+                    .get(i);
+            if (!actionIdOverrides.contains(ad.getId())) {
+                currentContribution.contributeMenuAction(ad, menu, true);
+                // Update action for the current selection and part.
+                if (ad.getAction() instanceof ObjectPluginAction) {
+                    final ObjectPluginAction action = (ObjectPluginAction) ad
+                            .getAction();
+                    ISafeRunnable runnable = new ISafeRunnable() {
+						@Override
+						public void handleException(Throwable exception) {
+							WorkbenchPlugin.log("Failed to update action "  //$NON-NLS-1$
+									+ action.getId(), exception);
+						}
+
+						@Override
+						public void run() throws Exception {
+		                    action.setActivePart(part);
+		                    action.selectionChanged(selection);
+						}
+                    };
+                    SafeRunner.run(runnable);
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
+	 * Contributes menus applicable for the current selection.
+	 */
+    @Override
+	public boolean contributeObjectMenus(IMenuManager menu,
+            ISelectionProvider selProv) {
+        if (!configRead) {
+			readConfigElement();
+		}
+
+        // Easy case out if no menus
+        if (currentContribution.menus == null) {
+			return false;
+		}
+
+        // Get a structured selection.
+        ISelection sel = selProv.getSelection();
+        if ((sel == null) || !(sel instanceof IStructuredSelection)) {
+			return false;
+		}
+
+        // Generate menu.
+        for (int i = 0; i < currentContribution.menus.size(); i++) {
+            IConfigurationElement menuElement = (IConfigurationElement) currentContribution.menus
+                    .get(i);
+            currentContribution.contributeMenu(menuElement, menu, true);
+        }
+        return true;
+    }
+
+    @Override
+	protected ActionDescriptor createActionDescriptor(
+            IConfigurationElement element) {
+        return new ActionDescriptor(element, ActionDescriptor.T_POPUP);
+    }
+
+    @Override
+	protected BasicContribution createContribution() {
+        return new ObjectContribution();
+    }
+
+    /**
+     * Returns true if name filter is not specified for the contribution
+     * or the current selection matches the filter.
+     */
+    @Override
+	public boolean isApplicableTo(Object object) {
+        if (!configRead) {
+			readConfigElement();
+		}
+
+        // Perform all tests with an instance of the objectClass and not
+        // the actual selected object.
+        if (canAdapt()) {
+			Object adapted = LegacyResourceSupport.getAdapter(object, getObjectClass());
+			if (adapted == null) {
+				if (Policy.DEBUG_CONTRIBUTIONS) {
+					WorkbenchPlugin
+							.log("Error adapting " + object.getClass().getName() + //$NON-NLS-1$
+									" to " //$NON-NLS-1$
+									+ getObjectClass()
+									+ ". Contribution " + getID(config) + " is being ignored"); //$NON-NLS-1$ //$NON-NLS-2$
+				}
+			} else {
+				object = adapted;
+			}
+		}
+
+        if (!testName(object)) {
+			return false;
+		}
+
+        return ((ObjectContribution) currentContribution)
+                .isApplicableTo(object);
+    }
+
+    /**
+     * Reads the configuration element and all the children.
+     * This creates an action descriptor for every action in the extension.
+     */
+    private void readConfigElement() {
+        currentContribution = createContribution();
+        readElementChildren(config);
+        configRead = true;
+    }
+
+    @Override
+	protected boolean readElement(IConfigurationElement element) {
+        String tag = element.getName();
+
+        // Found visibility sub-element
+        if (tag.equals(IWorkbenchRegistryConstants.TAG_VISIBILITY)) {
+            ((ObjectContribution) currentContribution)
+                    .setVisibilityTest(element);
+            return true;
+        }
+
+        // Found filter sub-element
+        if (tag.equals(IWorkbenchRegistryConstants.TAG_FILTER)) {
+            ((ObjectContribution) currentContribution).addFilterTest(element);
+            return true;
+        }
+
+        if (tag.equals(IWorkbenchRegistryConstants.TAG_ENABLEMENT)) {
+            ((ObjectContribution) currentContribution)
+                    .setEnablementTest(element);
+            return true;
+        }
+
+        return super.readElement(element);
+    }
+
+    /**
+     * Returns whether the current selection matches the contribution name filter.
+     */
+    private boolean testName(Object object) {
+        String nameFilter = config.getAttribute(IWorkbenchRegistryConstants.ATT_NAME_FILTER);
+        if (nameFilter == null) {
+			return true;
+		}
+        String objectName = null;
+        IWorkbenchAdapter de = Adapters.adapt(object, IWorkbenchAdapter.class);
+        if (de != null) {
+			objectName = de.getLabel(object);
+		}
+        if (objectName == null) {
+            objectName = object.toString();
+        }
+        return SelectionEnabler.verifyNameMatch(objectName, nameFilter);
+    }
+
+    /**
+     * Helper class to collect the menus and actions defined within a
+     * contribution element.
+     */
+    private static class ObjectContribution extends BasicContribution {
+        private ObjectFilterTest filterTest;
+
+        private ActionExpression visibilityTest;
+
+        private Expression enablement;
+
+        /**
+         * Add a filter test.
+         *
+         * @param element the element
+         */
+        public void addFilterTest(IConfigurationElement element) {
+            if (filterTest == null) {
+				filterTest = new ObjectFilterTest();
+			}
+            filterTest.addFilterElement(element);
+        }
+
+        /**
+         * Set the visibility test.
+         *
+         * @param element the element
+         */
+        public void setVisibilityTest(IConfigurationElement element) {
+            visibilityTest = new ActionExpression(element);
+        }
+
+        /**
+         * Set the enablement test.
+         *
+         * @param element the element
+         */
+        public void setEnablementTest(IConfigurationElement element) {
+            try {
+                enablement = ExpressionConverter.getDefault().perform(element);
+            } catch (CoreException e) {
+                WorkbenchPlugin.log(e);
+            }
+        }
+
+        /**
+         * Returns true if name filter is not specified for the contribution
+         * or the current selection matches the filter.
+         *
+         * @param object the object to test
+         * @return whether we're applicable
+         */
+        public boolean isApplicableTo(Object object) {
+            boolean result = true;
+            if (visibilityTest != null) {
+                result = result && visibilityTest.isEnabledFor(object);
+                if (!result) {
+					return result;
+				}
+            } else if (filterTest != null) {
+                result = result && filterTest.matches(object, true);
+                if (!result) {
+					return result;
+				}
+            }
+            if (enablement != null) {
+                try {
+                    IEvaluationContext context = new EvaluationContext(null,
+                            object);
+                    context.setAllowPluginActivation(true);
+                    context.addVariable("selection", object); //$NON-NLS-1$
+                    context.addVariable("org.eclipse.core.runtime.Platform", Platform.class); //$NON-NLS-1$
+                    EvaluationResult evalResult = enablement.evaluate(context);
+                    if (evalResult == EvaluationResult.FALSE) {
+						return false;
+					}
+                } catch (CoreException e) {
+                    enablement = null;
+                    WorkbenchPlugin.log(e);
+                    result = false;
+                }
+            }
+            return result;
+        }
+    }
+
+    /**
+     * Debugging helper that will print out the contribution names for this
+     * contributor.
+     */
+    @Override
+	public String toString() {
+    	StringBuffer buffer = new StringBuffer();
+    	IConfigurationElement[] children = config.getChildren();
+    	for (IConfigurationElement element : children) {
+			String label = element.getAttribute(IWorkbenchRegistryConstants.ATT_LABEL);
+			if(label != null) {
+				buffer.append(label);
+				buffer.append('\n');
+			}
+		}
+    	return buffer.toString();
+    }
+
+	@Override
+	public <T> T getAdapter(Class<T> adapter) {
+		if (adapter.equals(IConfigurationElement.class)) {
+			return adapter.cast(config);
+		}
+		return null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ObjectActionContributorManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ObjectActionContributorManager.java
new file mode 100644
index 0000000..b9b3b8e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ObjectActionContributorManager.java
@@ -0,0 +1,145 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+
+/**
+ * This manager is used to populate a popup menu manager with actions
+ * for a given type.
+ */
+public class ObjectActionContributorManager extends ObjectContributorManager {
+    private static ObjectActionContributorManager sharedInstance;
+
+    /**
+     * PopupMenuManager constructor.
+     */
+    public ObjectActionContributorManager() {
+    	super();
+        loadContributors();
+    }
+
+    /**
+	 * Contributes submenus and/or actions applicable to the selection in the
+	 * provided viewer into the provided popup menu.
+	 *
+	 * @param part
+	 *            the part being contributed to
+	 * @param popupMenu
+	 *            the menu being contributed to
+	 * @param selProv
+	 *            the selection provider
+	 * @param alreadyContributed
+	 *            the set of contributors that already contributed to the menu
+	 * @return whether anything was contributed
+	 */
+	public boolean contributeObjectActions(IWorkbenchPart part, IMenuManager popupMenu,
+			ISelectionProvider selProv, Set<IObjectActionContributor> alreadyContributed) {
+        // Get a selection.
+        ISelection selection = selProv.getSelection();
+        if (selection == null) {
+			return false;
+		}
+
+        // Convert the selection into an element vector.
+        // According to the dictionary, a selection is "one that
+        // is selected", or "a collection of selected things".
+        // In reflection of this, we deal with one or a collection.
+        List elements = null;
+        if (selection instanceof IStructuredSelection) {
+            elements = ((IStructuredSelection) selection).toList();
+        } else {
+            elements = new ArrayList(1);
+            elements.add(selection);
+        }
+
+		List<IObjectActionContributor> contributors = getContributors(elements);
+		contributors.removeAll(alreadyContributed);
+
+        if (contributors.isEmpty()) {
+			return false;
+		}
+
+        // First pass, add the menus and collect the overrides. Prune from the
+        // list any non-applicable contributions.
+        boolean actualContributions = false;
+        ArrayList overrides = new ArrayList(4);
+		for (Iterator<IObjectActionContributor> it = contributors.iterator(); it.hasNext();) {
+			IObjectActionContributor contributor = it.next();
+            if (!isApplicableTo(elements, contributor)) {
+            	it.remove();
+                continue;
+            }
+            if (contributor.contributeObjectMenus(popupMenu, selProv)) {
+				actualContributions = true;
+				alreadyContributed.add(contributor);
+			}
+            contributor.contributeObjectActionIdOverrides(overrides);
+        }
+
+        // Second pass, add the contributions that are applicable to
+        // the selection.
+		for (IObjectActionContributor contributor : contributors) {
+			if (contributor.contributeObjectActions(part, popupMenu, selProv,
+                    overrides)) {
+				actualContributions = true;
+				alreadyContributed.add(contributor);
+			}
+        }
+        return actualContributions;
+    }
+
+    /**
+     * Returns the shared instance of this manager.
+     * @return the shared instance of this manager
+     */
+    public static ObjectActionContributorManager getManager() {
+        if (sharedInstance == null) {
+            sharedInstance = new ObjectActionContributorManager();
+        }
+        return sharedInstance;
+    }
+
+    /**
+     * Loads the contributors from the workbench's registry.
+     */
+    private void loadContributors() {
+        ObjectActionContributorReader reader = new ObjectActionContributorReader();
+        reader.readPopupContributors(this);
+    }
+
+	@Override
+	public void addExtension(IExtensionTracker tracker, IExtension addedExtension) {
+        IConfigurationElement[] addedElements = addedExtension.getConfigurationElements();
+        for (IConfigurationElement addedElement : addedElements) {
+            ObjectActionContributorReader reader = new ObjectActionContributorReader();
+            reader.setManager(this);
+            reader.readElement(addedElement);
+        }
+    }
+
+	@Override
+	protected String getExtensionPointFilter() {
+		return IWorkbenchRegistryConstants.PL_POPUP_MENU;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ObjectActionContributorReader.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ObjectActionContributorReader.java
new file mode 100644
index 0000000..81504b1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ObjectActionContributorReader.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.registry.RegistryReader;
+
+/**
+ * This reader loads the popup menu manager with all the
+ * popup menu contributors found in the workbench registry.
+ */
+public class ObjectActionContributorReader extends RegistryReader {
+
+    private ObjectActionContributorManager manager;
+
+    /**
+     * Creates popup menu contributor from this element.
+     */
+    protected void processObjectContribution(IConfigurationElement element) {
+        String objectClassName = element.getAttribute(IWorkbenchRegistryConstants.ATT_OBJECTCLASS);
+        if (objectClassName == null) {
+            logMissingAttribute(element, IWorkbenchRegistryConstants.ATT_OBJECTCLASS);
+            return;
+        }
+
+        IObjectContributor contributor = new ObjectActionContributor(element);
+        manager.registerContributor(contributor, objectClassName);
+    }
+
+    /**
+     * Implements abstract method to handle configuration elements.
+     */
+    @Override
+	protected boolean readElement(IConfigurationElement element) {
+        String tagName = element.getName();
+        if (tagName.equals(IWorkbenchRegistryConstants.TAG_OBJECT_CONTRIBUTION)) {
+            processObjectContribution(element);
+            return true;
+        }
+        if (tagName.equals(IWorkbenchRegistryConstants.TAG_VIEWER_CONTRIBUTION)) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Reads the registry and registers popup menu contributors
+     * found there.
+     *
+     * @param mng the manager to read into
+     */
+    public void readPopupContributors(ObjectActionContributorManager mng) {
+        setManager(mng);
+        IExtensionRegistry registry = Platform.getExtensionRegistry();
+        // RAP [bm]: 
+//        readRegistry(registry, PlatformUI.PLUGIN_ID,
+//                IWorkbenchRegistryConstants.PL_POPUP_MENU);
+        readRegistry(registry, PlatformUI.PLUGIN_EXTENSION_NAME_SPACE,
+              IWorkbenchRegistryConstants.PL_POPUP_MENU);
+        // RAPEND: [bm] 
+    }
+
+    /**
+     * Set the manager to read into.
+     *
+     * @param mng the manager
+     */
+    public void setManager(ObjectActionContributorManager mng) {
+        manager = mng;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ObjectContributorManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ObjectContributorManager.java
new file mode 100644
index 0000000..db495fa
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ObjectContributorManager.java
@@ -0,0 +1,1001 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IAdapterManager;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.dynamichelpers.ExtensionTracker;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * This class is a default implementation of <code>IObjectContributorManager</code>.
+ * It provides fast merging of contributions with the following semantics:
+ * <ul>
+ * <li> All of the matching contributors will be invoked per property lookup
+ * <li> The search order from a class with the definition<br>
+ *			<code>class X extends Y implements A, B</code><br>
+ *		is as follows:
+ * 		<il>
+ *			<li>the target's class: X
+ *			<li>X's superclasses in order to <code>Object</code>
+ *			<li>a depth-first traversal of the target class's interaces in the order
+ *				returned by <code>getInterfaces()</code> (in the example, A and
+ *				its superinterfaces then B and its superinterfaces)
+ *		</il>
+ * </ul>
+ *
+ * @see IObjectContributor
+ */
+public abstract class ObjectContributorManager implements IExtensionChangeHandler {
+
+	/**
+	 * @since 3.1
+	 */
+	private class ContributorRecord {
+		/**
+		 * @param contributor
+		 * @param targetType
+		 */
+		public ContributorRecord(IObjectContributor contributor, String targetType) {
+			this.contributor = contributor;
+			this.objectClassName = targetType;
+		}
+
+		String objectClassName;
+		IObjectContributor contributor;
+	}
+
+    /** Table of contributors. */
+    protected Map contributors;
+
+    /** Cache of object class contributor search paths; <code>null</code> if none. */
+    protected Map objectLookup;
+
+    /** Cache of resource adapter class contributor search paths; <code>null</code> if none. */
+    protected Map resourceAdapterLookup;
+
+    /** Cache of adaptable class contributor search paths; <code>null</code> if none. */
+    protected Map adaptableLookup;
+
+    protected Set contributorRecordSet;
+
+    /**
+     * Constructs a new contributor manager.
+     */
+    public ObjectContributorManager() {
+    	contributors = new Hashtable(5);
+        contributorRecordSet = new HashSet(5);
+        objectLookup = null;
+        resourceAdapterLookup = null;
+        adaptableLookup = null;
+        String extensionPointId = getExtensionPointFilter();
+        if (extensionPointId != null) {
+            // RAP [bm] namespace
+            IExtensionPoint extensionPoint = Platform.getExtensionRegistry().getExtensionPoint(
+                    PlatformUI.PLUGIN_EXTENSION_NAME_SPACE, extensionPointId);
+			IExtensionTracker tracker = PlatformUI.getWorkbench()
+					.getExtensionTracker();
+			tracker.registerHandler(this, ExtensionTracker
+					.createExtensionPointFilter(extensionPoint));
+		}
+    }
+
+    /**
+	 * Return the extension point id (local to org.eclipse.ui) that this manager
+	 * is associated with. Default implementation returns null, which implies no
+	 * relationship with a particular extension.
+	 *
+	 * @return the extension point id
+	 * @since 3.4
+	 */
+	protected String getExtensionPointFilter() {
+		return null;
+	}
+
+	/**
+     * Adds contributors for the given types to the result list.
+     */
+    private void addContributorsFor(List types, List result) {
+        for (Iterator classes = types.iterator(); classes.hasNext();) {
+            Class clazz = (Class) classes.next();
+            List contributorList = (List) contributors.get(clazz.getName());
+            if (contributorList != null) {
+				result.addAll(contributorList);
+			}
+        }
+    }
+
+    /**
+     * Returns the class search order starting with <code>extensibleClass</code>.
+     * The search order is defined in this class' comment.
+     */
+    protected final List computeClassOrder(Class extensibleClass) {
+        ArrayList result = new ArrayList(4);
+        Class clazz = extensibleClass;
+        while (clazz != null) {
+            result.add(clazz);
+            clazz = clazz.getSuperclass();
+        }
+        return result;
+    }
+
+    /**
+     * Returns the interface search order for the class hierarchy described
+     * by <code>classList</code>.
+     * The search order is defined in this class' comment.
+     */
+    protected final List computeInterfaceOrder(List classList) {
+        ArrayList result = new ArrayList(4);
+        Map seen = new HashMap(4);
+        for (Iterator list = classList.iterator(); list.hasNext();) {
+            Class[] interfaces = ((Class) list.next()).getInterfaces();
+            internalComputeInterfaceOrder(interfaces, result, seen);
+        }
+        return result;
+    }
+
+    /**
+     * Flushes the cache of contributor search paths.  This is generally required
+     * whenever a contributor is added or removed.
+     * <p>
+     * It is likely easier to just toss the whole cache rather than trying to be
+     * smart and remove only those entries affected.
+     */
+    public void flushLookup() {
+        objectLookup = null;
+        resourceAdapterLookup = null;
+        adaptableLookup = null;
+    }
+
+    /**
+     * Cache the real adapter class contributor search path.
+     */
+    private void cacheResourceAdapterLookup(Class adapterClass, List results) {
+        if (resourceAdapterLookup == null) {
+			resourceAdapterLookup = new HashMap();
+		}
+        resourceAdapterLookup.put(adapterClass, results);
+    }
+
+    /**
+     * Cache the real adapter class contributor search path.
+     */
+    private void cacheAdaptableLookup(String adapterClass, List results) {
+        if (adaptableLookup == null) {
+			adaptableLookup = new HashMap();
+		}
+        adaptableLookup.put(adapterClass, results);
+    }
+
+    /**
+     * Cache the object class contributor search path.
+     */
+    private void cacheObjectLookup(Class objectClass, List results) {
+        if (objectLookup == null) {
+			objectLookup = new HashMap();
+		}
+        objectLookup.put(objectClass, results);
+    }
+
+    /**
+     * Get the contributions registered to this manager.
+     *
+     * @return an unmodifiable <code>Collection</code> containing all registered
+     * contributions.  The objects in this <code>Collection</code> will be
+     * <code>List</code>s containing the actual contributions.
+     * @since 3.0
+     */
+    public Collection getContributors() {
+        return Collections.unmodifiableCollection(contributors.values());
+    }
+
+    /**
+     * Return the list of contributors for the supplied class.
+     */
+    protected List addContributorsFor(Class objectClass) {
+
+        List classList = computeClassOrder(objectClass);
+        List result = new ArrayList();
+        addContributorsFor(classList, result);
+        classList = computeInterfaceOrder(classList); // interfaces
+        addContributorsFor(classList, result);
+        return result;
+    }
+
+    /**
+     * Returns true if contributors exist in the manager for
+     * this object and any of it's super classes, interfaces, or
+     * adapters.
+     *
+     * @param object the object to test
+     * @return whether the object has contributors
+     */
+    public boolean hasContributorsFor(Object object) {
+
+        List contributors = getContributors(object);
+        return contributors.size() > 0;
+    }
+
+    /**
+     * Add interface Class objects to the result list based
+     * on the class hierarchy. Interfaces will be searched
+     * based on their position in the result list.
+     */
+    private void internalComputeInterfaceOrder(Class[] interfaces, List result,
+            Map seen) {
+        List newInterfaces = new ArrayList(seen.size());
+        for (Class currentInterface : interfaces) {
+            if (seen.get(currentInterface) == null) {
+                result.add(currentInterface);
+                seen.put(currentInterface, currentInterface);
+                newInterfaces.add(currentInterface);
+            }
+        }
+        for (Iterator newList = newInterfaces.iterator(); newList.hasNext();) {
+			internalComputeInterfaceOrder(((Class) newList.next())
+                    .getInterfaces(), result, seen);
+		}
+    }
+
+    /**
+	 * Return whether the given contributor is applicable to all elements in the
+	 * selection.
+	 *
+	 * @param selection
+	 *            the selection
+	 * @param contributor
+	 *            the contributor
+	 * @return whether it is applicable
+	 */
+    public boolean isApplicableTo(IStructuredSelection selection,
+            IObjectContributor contributor) {
+        Iterator elements = selection.iterator();
+        while (elements.hasNext()) {
+            if (contributor.isApplicableTo(elements.next()) == false) {
+				return false;
+			}
+        }
+        return true;
+    }
+
+    /**
+	 * Return whether the given contributor is applicable to all elements in the
+	 * list.
+	 *
+	 * @param list
+	 *            the selection
+	 * @param contributor
+	 *            the contributor
+	 * @return whether it is applicable
+	 */
+
+    public boolean isApplicableTo(List list, IObjectContributor contributor) {
+        Iterator elements = list.iterator();
+        while (elements.hasNext()) {
+            if (contributor.isApplicableTo(elements.next()) == false) {
+				return false;
+			}
+        }
+        return true;
+    }
+
+    /**
+     * Register a contributor.
+     *
+     * @param contributor the contributor
+     * @param targetType the target type
+     */
+    public void registerContributor(IObjectContributor contributor,
+            String targetType) {
+        List contributorList = (List) contributors.get(targetType);
+        if (contributorList == null) {
+            contributorList = new ArrayList(5);
+            contributors.put(targetType, contributorList);
+        }
+        contributorList.add(contributor);
+        flushLookup();
+
+        IConfigurationElement element = Adapters.adapt(contributor, IConfigurationElement.class);
+
+        //hook the object listener
+        if (element != null) {
+			ContributorRecord contributorRecord = new ContributorRecord(
+					contributor, targetType);
+			contributorRecordSet.add(contributorRecord);
+			PlatformUI.getWorkbench().getExtensionTracker().registerObject(
+					element.getDeclaringExtension(), contributorRecord,
+					IExtensionTracker.REF_WEAK);
+        }
+    }
+
+    /**
+     * Unregister all contributors.
+     */
+    public void unregisterAllContributors() {
+        contributors = new Hashtable(5);
+        flushLookup();
+    }
+
+    /**
+     * Unregister a contributor from the target type.
+     *
+     * @param contributor the contributor
+     * @param targetType the target type
+     */
+    public void unregisterContributor(IObjectContributor contributor,
+            String targetType) {
+        List contributorList = (List) contributors.get(targetType);
+        if (contributorList == null) {
+			return;
+		}
+        contributorList.remove(contributor);
+        if (contributorList.isEmpty()) {
+			contributors.remove(targetType);
+		}
+        flushLookup();
+    }
+
+
+    /**
+     * Unregister all contributors for the target type.
+     *
+     * @param targetType the target type
+     */
+    public void unregisterContributors(String targetType) {
+        contributors.remove(targetType);
+        flushLookup();
+    }
+
+    protected List getContributors(Object object) {
+    	// Determine is the object is a resource
+    	Object resource  = LegacyResourceSupport.getAdaptedContributorResource(object);
+
+    	// Fetch the unique adapters
+    	List adapters = new ArrayList(Arrays.asList(Platform.getAdapterManager().computeAdapterTypes(object.getClass())));
+    	removeCommonAdapters(adapters, Arrays.asList(new Class[] {object.getClass()}));
+
+    	List contributors = new ArrayList();
+
+        // Calculate the contributors for this object class
+        addAll(contributors, getObjectContributors(object.getClass()));
+        // Calculate the contributors for resource classes
+        if(resource != null) {
+			addAll(contributors, getResourceContributors(resource.getClass()));
+		}
+        // Calculate the contributors for each adapter type
+    	if(adapters != null) {
+    		for (Iterator it = adapters.iterator(); it.hasNext();) {
+				String adapter = (String) it.next();
+				addAll(contributors, getAdaptableContributors(adapter));
+			}
+    	}
+
+        // Remove duplicates.  Note: this -must- maintain the element order to preserve menu order.
+        contributors = removeDups(contributors);
+
+    	return contributors.isEmpty() ? Collections.EMPTY_LIST : new ArrayList(contributors);
+    }
+
+    /**
+     * Returns the contributions for the given class. This considers
+     * contributors on any super classes and interfaces.
+     *
+     * @param objectClass the class to search for contributions.
+     * @return the contributions for the given class. This considers
+     * contributors on any super classes and interfaces.
+     *
+     * @since 3.1
+     */
+    protected List getObjectContributors(Class objectClass) {
+		List objectList = null;
+		// Lookup the results in the cache first.
+		if (objectLookup != null) {
+			objectList = (List) objectLookup.get(objectClass);
+		}
+		if (objectList == null) {
+			objectList = addContributorsFor(objectClass);
+			if (objectList.size() == 0) {
+				objectList = Collections.EMPTY_LIST;
+			}
+			else {
+				objectList = Collections.unmodifiableList(objectList);
+			}
+			cacheObjectLookup(objectClass, objectList);
+		}
+		return objectList;
+	}
+
+    /**
+     * Returns the contributions for the given <code>IResource</code>class.
+     * This considers contributors on any super classes and interfaces. This
+     * will only return contributions that are adaptable.
+     *
+     * @param resourceClass the class to search for contributions.
+     * @return the contributions for the given class. This considers
+     * adaptable contributors on any super classes and interfaces.
+     *
+     * @since 3.1
+     */
+	protected List getResourceContributors(Class resourceClass) {
+		List resourceList = null;
+		if (resourceAdapterLookup != null) {
+			resourceList = (List) resourceAdapterLookup.get(resourceClass);
+		}
+		if (resourceList == null) {
+			resourceList = addContributorsFor(resourceClass);
+			if (resourceList.size() == 0) {
+				resourceList = Collections.EMPTY_LIST;
+			} else {
+				resourceList = Collections.unmodifiableList(filterOnlyAdaptableContributors(resourceList));
+			}
+			cacheResourceAdapterLookup(resourceClass, resourceList);
+		}
+		return resourceList;
+	}
+
+    /**
+     * Returns the contributions for the given type name.
+     *
+     * @param adapterType the class to search for contributions.
+     * @return the contributions for the given class. This considers
+     * contributors to this specific type.
+     *
+     * @since 3.1
+     */
+	protected List getAdaptableContributors(String adapterType) {
+		List adaptableList = null;
+		// Lookup the results in the cache first, there are two caches
+		// one that stores non-adapter contributions and the other
+		// contains adapter contributions.
+		if (adaptableLookup != null) {
+			adaptableList = (List) adaptableLookup.get(adapterType);
+		}
+		if (adaptableList == null) {
+			// ignore resource adapters because these must be adapted via the
+			// IContributorResourceAdapter.
+			if (LegacyResourceSupport.isResourceType(adapterType) || LegacyResourceSupport.isResourceMappingType(adapterType)) {
+				adaptableList = Collections.EMPTY_LIST;
+			}
+			else {
+				adaptableList = (List) contributors.get(adapterType);
+				if (adaptableList == null || adaptableList.size() == 0) {
+					adaptableList = Collections.EMPTY_LIST;
+				} else {
+					adaptableList = Collections.unmodifiableList(filterOnlyAdaptableContributors(adaptableList));
+				}
+			}
+			cacheAdaptableLookup(adapterType, adaptableList);
+		}
+		return adaptableList;
+	}
+
+	/**
+	 * Prunes from the list of adapters type names that are in the class
+	 * search order of every class in <code>results</code>.
+	 * @param adapters
+	 * @param results
+	 * @since 3.1
+	 */
+	protected void removeCommonAdapters(List adapters, List results) {
+    	for (Iterator it = results.iterator(); it.hasNext();) {
+			Class clazz = ((Class) it.next());
+			List commonTypes = computeCombinedOrder(clazz);
+			for (Iterator it2 = commonTypes.iterator(); it2.hasNext();) {
+				Class type = (Class) it2.next();
+				adapters.remove(type.getName());
+			}
+		}
+    }
+
+	/**
+     * Returns the class search order starting with <code>extensibleClass</code>.
+     * The search order is defined in this class' comment.
+     */
+    protected List computeCombinedOrder(Class inputClass) {
+        List result = new ArrayList(4);
+        Class clazz = inputClass;
+        while (clazz != null) {
+            // add the class
+            result.add(clazz);
+            // add all the interfaces it implements
+            Class[] interfaces = clazz.getInterfaces();
+            for (Class currentInterface : interfaces) {
+                result.add(currentInterface);
+            }
+            // get the superclass
+            clazz = clazz.getSuperclass();
+        }
+        return result;
+    }
+
+	private List filterOnlyAdaptableContributors(List contributors) {
+		List adaptableContributors = null;
+		for (Iterator it = contributors.iterator(); it.hasNext();) {
+			IObjectContributor c = (IObjectContributor) it.next();
+			if(c.canAdapt()) {
+				if(adaptableContributors == null) {
+					adaptableContributors = new ArrayList();
+				}
+				adaptableContributors.add(c);
+			}
+		}
+		return adaptableContributors == null ? Collections.EMPTY_LIST : adaptableContributors;
+	}
+
+    @Override
+	public void removeExtension(IExtension source, Object[] objects) {
+        for (Object object : objects) {
+            if (object instanceof ContributorRecord) {
+                ContributorRecord contributorRecord = (ContributorRecord) object;
+                unregisterContributor((contributorRecord).contributor, (contributorRecord).objectClassName);
+                contributorRecordSet.remove(contributorRecord);
+            }
+        }
+    }
+
+    /**
+     * Remove listeners and dispose of this manager.
+     *
+     * @since 3.1
+     */
+    public void dispose() {
+    	if(getExtensionPointFilter() != null) {
+			PlatformUI.getWorkbench().getExtensionTracker().unregisterHandler(this);
+		}
+    }
+
+    /**
+     * Returns the list of contributors that are interested in the
+     * given list of model elements.
+     * @param elements a list of model elements (<code>Object</code>)
+     * @return the list of interested contributors (<code>IObjectContributor</code>)
+     */
+    protected List getContributors(List elements) {
+        // Calculate the common class, interfaces, and adapters registered
+        // via the IAdapterManager.
+        List commonAdapters = new ArrayList();
+        List commonClasses = getCommonClasses(elements, commonAdapters);
+
+        // Get the resource class. It will be null if any of the
+        // elements are resources themselves or do not adapt to
+        // IResource.
+        Class resourceClass = getCommonResourceClass(elements);
+        Class resourceMappingClass = getResourceMappingClass(elements);
+
+        // Get the contributors.
+
+        List contributors = new ArrayList();
+
+        // Add the resource contributions to avoid duplication
+        if (resourceClass != null) {
+            addAll(contributors, getResourceContributors(resourceClass));
+        }
+        if (commonClasses != null && !commonClasses.isEmpty()) {
+            for (int i = 0; i < commonClasses.size(); i++) {
+                List results = getObjectContributors((Class) commonClasses
+                        .get(i));
+                addAll(contributors, results);
+            }
+        }
+        // Add the resource mappings explicitly to avoid possible duplication
+        if (resourceMappingClass == null) {
+            // Still show the menus if the object is not adaptable but the adapter manager
+            // has an entry for it
+            resourceMappingClass = LegacyResourceSupport
+                    .getResourceMappingClass();
+            if (resourceMappingClass != null
+                    && commonAdapters.contains(resourceMappingClass.getName())) {
+            	addAll(contributors, getResourceContributors(resourceMappingClass));
+            }
+        } else {
+            contributors.addAll(getResourceContributors(resourceMappingClass));
+        }
+        if (!commonAdapters.isEmpty()) {
+            for (Iterator it = commonAdapters.iterator(); it.hasNext();) {
+                String adapter = (String) it.next();
+                addAll(contributors, getAdaptableContributors(adapter));
+            }
+        }
+
+        // Remove duplicates.  Note: this -must- maintain the element order to preserve menu order.
+        contributors = removeDups(contributors);
+
+        return contributors.isEmpty() ? Collections.EMPTY_LIST : new ArrayList(contributors);
+    }
+
+    /**
+	 * Adds all items in toAdd to the given collection.  Optimized to avoid creating an iterator.
+	 * This assumes that toAdd is efficient to index (i.e. it's an ArrayList or some other RandomAccessList),
+	 * which is the case for all uses in this class.
+	 */
+	private static void addAll(Collection collection, List toAdd) {
+		for (int i = 0, size = toAdd.size(); i < size; ++i) {
+			collection.add(toAdd.get(i));
+		}
+	}
+
+    /**
+     * Removes duplicates from the given list, preserving order.
+     */
+    private static List removeDups(List list) {
+    	if (list.size() <= 1) {
+    		return list;
+    	}
+    	HashSet set = new HashSet(list);
+    	if (set.size() == list.size()) {
+    		return list;
+    	}
+    	ArrayList result = new ArrayList(set.size());
+    	for (Iterator i = list.iterator(); i.hasNext();) {
+    		Object o = i.next();
+    		if (set.remove(o)) {
+    			result.add(o);
+    		}
+		}
+    	return result;
+    }
+
+	/**
+     * Returns the common denominator class, interfaces, and adapters
+     * for the given collection of objects.
+     */
+    private List getCommonClasses(List objects, List commonAdapters) {
+        if (objects == null || objects.size() == 0) {
+			return null;
+		}
+
+        // Optimization: if n==1 (or if all objects are of the same class), then the common class is the object's class,
+        // and the common adapters are the adapters cached for that class in the adapter manager
+        // See bug 177592 for more details.
+        if (allSameClass(objects)) {
+
+        	Class clazz = objects.get(0).getClass();
+        	commonAdapters.addAll(Arrays.asList(Platform.getAdapterManager().computeAdapterTypes(clazz)));
+        	List result = new ArrayList(1);
+        	result.add(clazz);
+        	return result;
+        }
+
+        // Compute all the super classes, interfaces, and adapters
+        // for the first element.
+        List classes = computeClassOrder(objects.get(0).getClass());
+        List adapters = computeAdapterOrder(classes);
+        List interfaces = computeInterfaceOrder(classes);
+
+        // Cache of all types found in the selection - this is needed
+        // to compute common adapters.
+        List lastCommonTypes = new ArrayList();
+
+        boolean classesEmpty = classes.isEmpty();
+        boolean interfacesEmpty = interfaces.isEmpty();
+
+        // Traverse the selection if there is more than one element selected.
+        for (int i = 1; i < objects.size(); i++) {
+            // Compute all the super classes for the current element
+            List otherClasses = computeClassOrder(objects.get(i).getClass());
+            if (!classesEmpty) {
+                classesEmpty = extractCommonClasses(classes, otherClasses);
+            }
+
+            // Compute all the interfaces for the current element
+            // and all of its super classes.
+            List otherInterfaces = computeInterfaceOrder(otherClasses);
+            if (!interfacesEmpty) {
+                interfacesEmpty = extractCommonClasses(interfaces,
+                        otherInterfaces);
+            }
+
+            // Compute all the adapters provided for the calculated
+            // classes and interfaces for this element.
+            List classesAndInterfaces = new ArrayList(otherClasses);
+            if (otherInterfaces != null) {
+				classesAndInterfaces.addAll(otherInterfaces);
+			}
+            List otherAdapters = computeAdapterOrder(classesAndInterfaces);
+
+            // Compute common adapters
+            // Note here that an adapter can match a class or interface, that is
+            // that an element in the selection may not adapt to a type but instead
+            // be of that type.
+            // If the selected classes doesn't have adapters, keep
+            // adapters that match the given classes types (classes and interfaces).
+            if (otherAdapters.isEmpty() && !adapters.isEmpty()) {
+                removeNonCommonAdapters(adapters, classesAndInterfaces);
+            } else {
+                if (adapters.isEmpty()) {
+                    removeNonCommonAdapters(otherAdapters, lastCommonTypes);
+                    if (!otherAdapters.isEmpty()) {
+						adapters.addAll(otherAdapters);
+					}
+                } else {
+                    // Remove any adapters of the first element that
+                    // are not in the current element's adapter list.
+                    for (Iterator it = adapters.iterator(); it.hasNext();) {
+                        String adapter = (String) it.next();
+                        if (!otherAdapters.contains(adapter)) {
+                            it.remove();
+                        }
+                    }
+                }
+            }
+
+            // Remember the common search order up to now, this is
+            // used to match adapters against common classes or interfaces.
+            lastCommonTypes.clear();
+            lastCommonTypes.addAll(classes);
+            lastCommonTypes.addAll(interfaces);
+
+            if (interfacesEmpty && classesEmpty && adapters.isEmpty()) {
+                // As soon as we detect nothing in common, just exit.
+                return null;
+            }
+        }
+
+        // Once the common classes, interfaces, and adapters are
+        // calculated, let's prune the lists to remove duplicates.
+        ArrayList results = new ArrayList(4);
+        ArrayList superClasses = new ArrayList(4);
+        if (!classesEmpty) {
+            for (int j = 0; j < classes.size(); j++) {
+                if (classes.get(j) != null) {
+                    superClasses.add(classes.get(j));
+                }
+            }
+            // Just keep the first super class
+            if (!superClasses.isEmpty()) {
+                results.add(superClasses.get(0));
+            }
+        }
+
+        if (!interfacesEmpty) {
+            removeCommonInterfaces(superClasses, interfaces, results);
+        }
+
+        // Remove adapters already included as common classes
+        if (!adapters.isEmpty()) {
+            removeCommonAdapters(adapters, results);
+            commonAdapters.addAll(adapters);
+        }
+        return results;
+    }
+
+    /**
+     * Returns <code>true</code> if all objects in the given list are of the same class,
+     * <code>false</code> otherwise.
+	 */
+	private boolean allSameClass(List objects) {
+		int size = objects.size();
+		if (size <= 1) return true;
+		Class clazz = objects.get(0).getClass();
+		for (int i = 1; i < size; ++i) {
+			if (!objects.get(i).getClass().equals(clazz)) {
+				return false;
+			}
+		}
+		return true;
+	}
+
+	private boolean extractCommonClasses(List classes, List otherClasses) {
+        boolean classesEmpty = true;
+        if (otherClasses.isEmpty()) {
+            // When no super classes, then it is obvious there
+            // are no common super classes with the first element
+            // so clear its list.
+            classes.clear();
+        } else {
+            // Remove any super classes of the first element that
+            // are not in the current element's super classes list.
+            for (int j = 0; j < classes.size(); j++) {
+                if (classes.get(j) != null) {
+                    classesEmpty = false; // TODO: should this only be set if item not nulled out?
+                    if (!otherClasses.contains(classes.get(j))) {
+                        classes.set(j, null);
+                    }
+                }
+            }
+        }
+        return classesEmpty;
+    }
+
+    private void removeNonCommonAdapters(List adapters, List classes) {
+        for (int i = 0; i < classes.size(); i++) {
+            Object o = classes.get(i);
+            if (o != null) {
+                Class clazz = (Class) o;
+                String name = clazz.getName();
+                if (adapters.contains(name)) {
+					return;
+				}
+            }
+        }
+        adapters.clear();
+    }
+
+    private void removeCommonInterfaces(List superClasses, List types,
+            List results) {
+        List dropInterfaces = null;
+        if (!superClasses.isEmpty()) {
+            dropInterfaces = computeInterfaceOrder(superClasses);
+        }
+        for (int j = 0; j < types.size(); j++) {
+            if (types.get(j) != null) {
+                if (dropInterfaces != null
+                        && !dropInterfaces.contains(types.get(j))) {
+                    results.add(types.get(j));
+                }
+            }
+        }
+    }
+
+    private List computeAdapterOrder(List classList) {
+        Set result = new HashSet(4);
+        IAdapterManager adapterMgr = Platform.getAdapterManager();
+        for (Iterator list = classList.iterator(); list.hasNext();) {
+            Class clazz = ((Class) list.next());
+			for (String adapter : adapterMgr.computeAdapterTypes(clazz)) {
+                if (!result.contains(adapter)) {
+                    result.add(adapter);
+                }
+            }
+        }
+        return new ArrayList(result);
+    }
+
+    /**
+     * Returns the common denominator resource class for the given
+     * collection of objects.
+     * Do not return a resource class if the objects are resources
+     * themselves so as to prevent double registration of actions.
+     */
+    private Class getCommonResourceClass(List objects) {
+        if (objects == null || objects.size() == 0) {
+            return null;
+        }
+        Class resourceClass = LegacyResourceSupport.getResourceClass();
+        if (resourceClass == null) {
+            // resources plug-in not loaded - no resources. period.
+            return null;
+        }
+
+        List testList = new ArrayList(objects.size());
+
+        for (int i = 0; i < objects.size(); i++) {
+            Object object = objects.get(i);
+
+            if (object instanceof IAdaptable) {
+                if (resourceClass.isInstance(object)) {
+                    continue;
+                }
+
+                Object resource = LegacyResourceSupport
+                        .getAdaptedContributorResource(object);
+
+                if (resource == null) {
+                    //Not a resource and does not adapt. No common resource class
+                    return null;
+                }
+                testList.add(resource);
+            } else {
+                return null;
+            }
+        }
+
+        return getCommonClass(testList);
+    }
+
+    /**
+     * Return the ResourceMapping class if the elements all adapt to it.
+     */
+    private Class getResourceMappingClass(List objects) {
+        if (objects == null || objects.size() == 0) {
+            return null;
+        }
+        Class resourceMappingClass = LegacyResourceSupport
+                .getResourceMappingClass();
+        if (resourceMappingClass == null) {
+            // resources plug-in not loaded - no resources. period.
+            return null;
+        }
+
+        for (int i = 0; i < objects.size(); i++) {
+            Object object = objects.get(i);
+
+            if (object instanceof IAdaptable) {
+                if (resourceMappingClass.isInstance(object)) {
+                    continue;
+                }
+
+                Object resourceMapping = LegacyResourceSupport
+                        .getAdaptedContributorResourceMapping(object);
+
+                if (resourceMapping == null) {
+                    //Not a resource and does not adapt. No common resource class
+                    return null;
+                }
+            } else {
+                return null;
+            }
+        }
+        // If we get here then all objects adapt to ResourceMapping
+        return resourceMappingClass;
+    }
+
+    /**
+     * Returns the common denominator class for the given
+     * collection of objects.
+     */
+    private Class getCommonClass(List objects) {
+        if (objects == null || objects.size() == 0) {
+			return null;
+		}
+        Class commonClass = objects.get(0).getClass();
+        // try easy
+        if (objects.size() == 1) {
+			return commonClass;
+        // try harder
+		}
+
+        for (int i = 1; i < objects.size(); i++) {
+            Object object = objects.get(i);
+            Class newClass = object.getClass();
+            // try the short cut
+            if (newClass.equals(commonClass)) {
+				continue;
+			}
+            // compute common class
+            commonClass = getCommonClass(commonClass, newClass);
+            // give up
+            if (commonClass == null) {
+				return null;
+			}
+        }
+        return commonClass;
+    }
+
+    /**
+     * Returns the common denominator class for
+     * two input classes.
+     */
+    private Class getCommonClass(Class class1, Class class2) {
+        List list1 = computeCombinedOrder(class1);
+        List list2 = computeCombinedOrder(class2);
+        for (int i = 0; i < list1.size(); i++) {
+            for (int j = 0; j < list2.size(); j++) {
+                Class candidate1 = (Class) list1.get(i);
+                Class candidate2 = (Class) list2.get(j);
+                if (candidate1.equals(candidate2)) {
+					return candidate1;
+				}
+            }
+        }
+        // no common class
+        return null;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ObjectFilterTest.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ObjectFilterTest.java
new file mode 100644
index 0000000..2b9c305
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ObjectFilterTest.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import java.util.HashMap;
+import java.util.Map.Entry;
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.ui.IActionFilter;
+
+/**
+ * An ObjectFilterTest is used to read an object filter from XML,
+ * and evaluate the results for a given object.
+ */
+public class ObjectFilterTest {
+	private HashMap<String, String> filterElements;
+
+    /**
+     * Create a new object filter.
+     */
+    public ObjectFilterTest() {
+        // do nothing
+    }
+
+    /**
+     * Add a filter element to the test.  This element must contain
+     * a name value filter pair, as defined by the
+     * <code>org.eclipse.ui.actionFilters</code> extension point.
+     */
+    public boolean addFilterElement(IConfigurationElement element) {
+        String name = element.getAttribute("name");//$NON-NLS-1$
+        if (name == null) {
+			return false;
+		}
+
+        // Get positive property.
+        String value = element.getAttribute("value");//$NON-NLS-1$
+        if (value == null) {
+			return false;
+		}
+        if (filterElements == null) {
+			filterElements = new HashMap();
+		}
+        filterElements.put(name, value);
+        return true;
+    }
+
+	/**
+	 * Returns whether the object filter correctly matches a given object. The
+	 * results will be <code>true</code> if there is a filter match.
+	 * <p>
+	 * If <code>adaptable is true</code>, the result will also be
+	 * <code>true</code> if the object is a wrapper for a resource, and the
+	 * resource produces a filter match.
+	 * </p>
+	 *
+	 * @param object
+	 *            the object to examine
+	 * @returns <code>true</code> if there is a filter match.
+	 */
+    public boolean matches(Object object, boolean adaptable) {
+        // Optimize it.
+        if (filterElements == null) {
+			return true;
+		}
+
+        // Try out the object.
+        if (this.preciselyMatches(object)) {
+			return true;
+		}
+        return false;
+    }
+
+    /**
+     * Returns whether the object filter correctly matches a given object.
+     */
+    private boolean preciselyMatches(Object object) {
+        // Get the action filter.
+        IActionFilter filter = Adapters.adapt(object, IActionFilter.class);
+        if (filter == null) {
+			return false;
+		}
+
+        // Run the action filter.
+		for (Entry<String, String> entry : filterElements.entrySet()) {
+			String name = entry.getKey();
+			String value = entry.getValue();
+            if (!filter.testAttribute(object, name, value)) {
+				return false;
+			}
+        }
+        return true;
+    }
+}
+
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ObjectPluginAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ObjectPluginAction.java
new file mode 100644
index 0000000..1f3d4cb
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ObjectPluginAction.java
@@ -0,0 +1,175 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.ui.IActionDelegate;
+import org.eclipse.ui.IObjectActionDelegate;
+import org.eclipse.ui.IPartListener2;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartReference;
+
+/**
+ * An object action extension in a popup menu.
+ * <p>
+ * For backward compatibility, the delegate object can implement either
+ * <code>IActionDelegate</code> or <code>IObjectActionDelegate</code>.
+ * </p>
+ */
+public class ObjectPluginAction extends PluginAction implements IPartListener2 {
+	/**
+	 * The configuration element attribute for the identifier of the action
+	 * which this action is intended to override (i.e., replace).
+	 */
+	public static final String ATT_OVERRIDE_ACTION_ID = "overrideActionId";//$NON-NLS-1$
+
+    private String overrideActionId;
+
+    private IWorkbenchPart activePart;
+
+	@Override
+	public void partActivated(IWorkbenchPartReference partRef) {
+	}
+
+	@Override
+	public void partBroughtToTop(IWorkbenchPartReference partRef) {
+	}
+
+	@Override
+	public void partClosed(IWorkbenchPartReference partRef) {
+		if (activePart != null && partRef.getPart(false) == activePart) {
+			selectionChanged(StructuredSelection.EMPTY);
+			disposeDelegate();
+			activePart = null;
+		}
+	}
+
+	@Override
+	public void partDeactivated(IWorkbenchPartReference partRef) {
+	}
+
+	@Override
+	public void partHidden(IWorkbenchPartReference partRef) {
+	}
+
+	@Override
+	public void partInputChanged(IWorkbenchPartReference partRef) {
+	}
+
+	@Override
+	public void partOpened(IWorkbenchPartReference partRef) {
+	}
+
+	@Override
+	public void partVisible(IWorkbenchPartReference partRef) {
+	}
+
+    /**
+	 * Constructs a new ObjectPluginAction.
+	 *
+	 * @param actionElement
+	 *            The configuration element used to construct this action; must
+	 *            not be <code>null</code>.
+	 * @param id
+	 *            The identifier for this action; must not be <code>null</code>.
+	 * @param style
+	 *            The style bits
+	 */
+    public ObjectPluginAction(IConfigurationElement actionElement, String id,
+            int style) {
+        super(actionElement, id, style);
+        overrideActionId = actionElement.getAttribute(ATT_OVERRIDE_ACTION_ID);
+    }
+
+    @Override
+	protected void initDelegate() {
+        super.initDelegate();
+		final IActionDelegate actionDelegate = getDelegate();
+		if (actionDelegate instanceof IObjectActionDelegate
+				&& activePart != null) {
+			final IObjectActionDelegate objectActionDelegate = (IObjectActionDelegate) actionDelegate;
+			final ISafeRunnable runnable = new ISafeRunnable() {
+				@Override
+				public void run() throws Exception {
+					objectActionDelegate.setActivePart(ObjectPluginAction.this,
+							activePart);
+				}
+
+				@Override
+				public void handleException(Throwable exception) {
+					// Do nothing.
+				}
+			};
+			SafeRunner.run(runnable);
+		}
+	}
+
+    /**
+	 * Sets the active part for the delegate.
+	 * <p>
+	 * This method will be called every time the action appears in a popup menu.
+	 * The targetPart may change with each invocation.
+	 * </p>
+	 *
+	 * @param targetPart
+	 *            the new part target
+	 */
+    public void setActivePart(IWorkbenchPart targetPart) {
+    	if (activePart != targetPart) {
+			if (activePart != null) {
+				activePart.getSite().getPage().removePartListener(this);
+			}
+			if (targetPart != null) {
+				targetPart.getSite().getPage().addPartListener(this);
+			}
+		}
+        activePart = targetPart;
+        IActionDelegate delegate = getDelegate();
+        if (delegate instanceof IObjectActionDelegate && activePart != null) {
+			final IObjectActionDelegate objectActionDelegate = (IObjectActionDelegate) delegate;
+			final ISafeRunnable runnable = new ISafeRunnable() {
+				@Override
+				public void run() throws Exception {
+					objectActionDelegate.setActivePart(ObjectPluginAction.this,
+							activePart);
+				}
+
+				@Override
+				public void handleException(Throwable exception) {
+					// Do nothing.
+				}
+			};
+			SafeRunner.run(runnable);
+		}
+	}
+
+    /**
+     * Returns the action identifier this action overrides.
+     *
+     * @return the action identifier to override or <code>null</code>
+     */
+    @Override
+	public String getOverrideActionId() {
+        return overrideActionId;
+    }
+
+    @Override
+	public void dispose() {
+    	if (activePart!=null) {
+    		activePart.getSite().getPage().removePartListener(this);
+    		activePart = null;
+    	}
+    	super.dispose();
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/OpenPerspectivePropertyTester.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/OpenPerspectivePropertyTester.java
new file mode 100644
index 0000000..33d5c77
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/OpenPerspectivePropertyTester.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal;
+
+import org.eclipse.core.expressions.PropertyTester;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.IWorkbenchPage;
+
+/**
+ * Tests if any Perspective is open or not.
+ *
+ * @since 3.3
+ *
+ */
+public class OpenPerspectivePropertyTester extends PropertyTester {
+	private static final String PROPERTY_IS_PERSPECTIVE_OPEN = "isPerspectiveOpen"; //$NON-NLS-1$
+
+	@Override
+	public boolean test(Object receiver, String property, Object[] args,
+			Object expectedValue) {
+		if (args.length == 0 && receiver instanceof WorkbenchWindow) {
+			final WorkbenchWindow window = (WorkbenchWindow) receiver;
+			if (PROPERTY_IS_PERSPECTIVE_OPEN.equals(property)) {
+				IWorkbenchPage page = window.getActivePage();
+				if (page != null) {
+					IPerspectiveDescriptor persp = page.getPerspective();
+					if (persp != null) {
+						return true;
+					}
+				}
+			}
+		}
+		return false;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/OpenPreferencesAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/OpenPreferencesAction.java
new file mode 100644
index 0000000..78e7311
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/OpenPreferencesAction.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.preference.PreferenceDialog;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.ActionFactory;
+import org.eclipse.ui.dialogs.PreferencesUtil;
+
+/**
+ * Open the preferences dialog
+ */
+public class OpenPreferencesAction extends Action implements ActionFactory.IWorkbenchAction {
+
+	/**
+	 * The workbench window; or <code>null</code> if this
+	 * action has been <code>dispose</code>d.
+	 */
+	private IWorkbenchWindow workbenchWindow;
+
+	/**
+	 * Create a new <code>OpenPreferenceAction</code>
+	 * This default constructor allows the the action to be called from the welcome page.
+	 */
+	public OpenPreferencesAction() {
+		this(PlatformUI.getWorkbench().getActiveWorkbenchWindow());
+	}
+
+	/**
+	 * Create a new <code>OpenPreferenceAction</code> and initialize it
+	 * from the given resource bundle.
+	 * @param window
+	 */
+	public OpenPreferencesAction(IWorkbenchWindow window) {
+		super(WorkbenchMessages.get().OpenPreferences_text);
+		if (window == null) {
+			throw new IllegalArgumentException();
+		}
+		this.workbenchWindow = window;
+		// @issue action id not set
+		setToolTipText(WorkbenchMessages.get().OpenPreferences_toolTip);
+		window.getWorkbench().getHelpSystem().setHelp(this,
+				IWorkbenchHelpContextIds.OPEN_PREFERENCES_ACTION);
+	}
+
+	@Override
+	public void run() {
+		if (workbenchWindow == null) {
+			// action has been dispose
+			return;
+		}
+		PreferenceDialog dialog = PreferencesUtil.createPreferenceDialogOn(null, null, null, null);
+		dialog.open();
+	}
+
+	@Override
+	public void dispose() {
+		workbenchWindow = null;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/OverlayIcon.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/OverlayIcon.java
new file mode 100644
index 0000000..2d334e6
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/OverlayIcon.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2014 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.ui.internal;
+
+import org.eclipse.jface.resource.CompositeImageDescriptor;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.ui.internal.util.Util;
+
+/**
+ * An OverlayIcon consists of a main icon and an overlay icon
+ */
+public class OverlayIcon extends CompositeImageDescriptor {
+
+    // the size of the OverlayIcon
+    private Point fSize = null;
+
+    // the main image
+    private ImageDescriptor fBase = null;
+
+    // the additional image (a pin for example)
+    private ImageDescriptor fOverlay = null;
+
+    /**
+     * @param base the main image
+     * @param overlay the additional image (a pin for example)
+     * @param size the size of the OverlayIcon
+     */
+    public OverlayIcon(ImageDescriptor base, ImageDescriptor overlay, Point size) {
+        fBase = base;
+        fOverlay = overlay;
+        fSize = size;
+    }
+
+    @Override
+	protected void drawCompositeImage(int width, int height) {
+        ImageData bg;
+        if (fBase == null || (bg = fBase.getImageData()) == null) {
+			bg = DEFAULT_IMAGE_DATA;
+		}
+        drawImage(bg, 0, 0);
+
+        if (fOverlay != null) {
+			drawTopRight(fOverlay);
+		}
+    }
+
+    /**
+     * @param overlay the additional image (a pin for example)
+     * to be drawn on top of the main image
+     */
+    protected void drawTopRight(ImageDescriptor overlay) {
+        if (overlay == null) {
+			return;
+		}
+        int x = getSize().x;
+        ImageData id = overlay.getImageData();
+        x -= id.width;
+        drawImage(id, x, 0);
+    }
+
+    @Override
+	protected Point getSize() {
+        return fSize;
+    }
+
+    @Override
+	public int hashCode() {
+        return Util.hashCode(fBase) * 17 + Util.hashCode(fOverlay);
+    }
+
+    @Override
+	public boolean equals(Object obj) {
+        if (!(obj instanceof OverlayIcon)) {
+			return false;
+		}
+        OverlayIcon overlayIcon = (OverlayIcon) obj;
+        return Util.equals(this.fBase, overlayIcon.fBase)
+                && Util.equals(this.fOverlay, overlayIcon.fOverlay)
+                && Util.equals(this.fSize, overlayIcon.fSize);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PageEventAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PageEventAction.java
new file mode 100644
index 0000000..95f9f76
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PageEventAction.java
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.ui.IPageListener;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.actions.ActionFactory;
+import org.eclipse.ui.actions.PartEventAction;
+import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction;
+
+/**
+ * The abstract superclass for actions that listen to page activation and
+ * open/close events. This implementation tracks the active page (see
+ * <code>getActivePage</code>) and provides a convenient place to monitor
+ * page lifecycle events that could affect the availability of the action.
+ * <p>
+ * Subclasses must implement the following <code>IAction</code> method:
+ * <ul>
+ *   <li><code>run</code> - to do the action's work</li>
+ * </ul>
+ * </p>
+ * <p>
+ * Subclasses may extend any of the <code>IPartListener</code> methods if the
+ * action availablity needs to be recalculated:
+ * <ul>
+ *   <li><code>partActivated</code></li>
+ *   <li><code>partDeactivated</code></li>
+ *   <li><code>partOpened</code></li>
+ *   <li><code>partClosed</code></li>
+ *   <li><code>partBroughtToTop</code></li>
+ * </ul>
+ * </p>
+ * <p>
+ * Subclasses may extend any of the <code>IPageListener</code> methods if the
+ * action availablity needs to be recalculated:
+ * <ul>
+ *   <li><code>pageActivated</code></li>
+ *   <li><code>pageClosed</code></li>
+ *   <li><code>pageOpened</code></li>
+ * </ul>
+ * </p>
+ * <p>
+ * This method implements the <code>IPartListener</code> and
+ * <code>IPageListener</code>interfaces, and automatically registers listeners
+ * so that it can keep its enablement state up to date. Ordinarily, the
+ * window's references to these listeners will be dropped automatically when
+ * the window closes. However, if the client needs to get rid of an action
+ * while the window is still open, the client must call
+ * {@link IWorkbenchAction#dispose dispose} to give the action an
+ * opportunity to deregister its listeners and to perform any other cleanup.
+ * </p>
+ */
+public abstract class PageEventAction extends PartEventAction implements
+        IPageListener, ActionFactory.IWorkbenchAction {
+    /**
+     * The active page, or <code>null</code> if none.
+     */
+    private IWorkbenchPage activePage;
+
+    /**
+     * The workbench window this action is registered with.
+     */
+    private IWorkbenchWindow workbenchWindow;
+
+    /**
+     * Creates a new action with the given text. Register this
+     * action with the workbench window for page lifecycle
+     * events.
+     *
+     * @param text the string used as the text for the action,
+     *   or <code>null</code> if there is no text
+     * @param window the workbench window this action is
+     *   registered with
+     */
+    protected PageEventAction(String text, IWorkbenchWindow window) {
+        super(text);
+        if (window == null) {
+            throw new IllegalArgumentException();
+        }
+        this.workbenchWindow = window;
+        this.activePage = window.getActivePage();
+        this.workbenchWindow.addPageListener(this);
+        this.workbenchWindow.getPartService().addPartListener(this);
+    }
+
+    /**
+     * Returns the currently active page in the workbench window.
+     *
+     * @return currently active page in the workbench window,
+     * or <code>null</code> in none
+     */
+    public final IWorkbenchPage getActivePage() {
+        return activePage;
+    }
+
+    /**
+     * Returns the workbench window this action applies to.
+     *
+     * @return the workbench window, or <code>null</code> if this action has been
+     * disposed
+     */
+    public final IWorkbenchWindow getWorkbenchWindow() {
+        return workbenchWindow;
+    }
+
+    /**
+     * The <code>PageEventAction</code> implementation of this
+     * <code>IPageListener</code> method records that the given page is active.
+     * Subclasses may extend this method if action availability has to be
+     * recalculated.
+     */
+    @Override
+	public void pageActivated(IWorkbenchPage page) {
+        this.activePage = page;
+    }
+
+    /**
+     * The <code>PageEventAction</code> implementation of this
+     * <code>IPageListener</code> method clears the active page if it just closed.
+     * Subclasses may extend this method if action availability has to be
+     * recalculated.
+     */
+    @Override
+	public void pageClosed(IWorkbenchPage page) {
+        if (page == activePage) {
+            activePage = null;
+        }
+    }
+
+    /**
+     * The <code>PageEventAction</code> implementation of this
+     * <code>IPageListener</code> method does nothing. Subclasses should extend
+     * this method if action availability has to be recalculated.
+     */
+    @Override
+	public void pageOpened(IWorkbenchPage page) {
+        // do nothing
+    }
+
+    /**
+     * The <code>PageEventAction</code> implementation of this
+     * <code>ActionFactory.IWorkbenchAction</code> method
+     * deregisters the part and page listener adding by the constructor.
+     * Subclasses should extend this method to do additional
+     * cleanup.
+     *
+     * @since 3.0
+     */
+    @Override
+	public void dispose() {
+        if (workbenchWindow == null) {
+            // action has already been disposed
+            return;
+        }
+        workbenchWindow.removePageListener(this);
+        workbenchWindow.getPartService().removePartListener(this);
+        workbenchWindow = null;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PageListenerList.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PageListenerList.java
new file mode 100644
index 0000000..36f3af8
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PageListenerList.java
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.core.commands.common.EventManager;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.jface.util.SafeRunnable;
+import org.eclipse.ui.IPageListener;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.internal.misc.UIStats;
+
+/**
+ * Part listener list.
+ */
+public class PageListenerList extends EventManager {
+
+    /**
+     * PartNotifier constructor comment.
+     */
+    public PageListenerList() {
+        super();
+    }
+
+    /**
+     * Adds an IPartListener to the part service.
+     */
+    public void addPageListener(IPageListener l) {
+    	addListenerObject(l);
+    }
+
+    /**
+     * Calls a page listener with associated performance event instrumentation
+     *
+     * @param runnable
+     * @param listener
+     * @param page
+     * @param description
+     */
+    private void fireEvent(SafeRunnable runnable, IPageListener listener, IWorkbenchPage page, String description) {
+    	String label = null;//for debugging
+    	if (UIStats.isDebugging(UIStats.NOTIFY_PAGE_LISTENERS)) {
+    		label = description + page.getLabel();
+    		UIStats.start(UIStats.NOTIFY_PAGE_LISTENERS, label);
+    	}
+    	SafeRunner.run(runnable);
+    	if (UIStats.isDebugging(UIStats.NOTIFY_PAGE_LISTENERS)) {
+			UIStats.end(UIStats.NOTIFY_PAGE_LISTENERS, listener, label);
+		}
+	}
+
+    /**
+     * Notifies the listener that a part has been activated.
+     */
+    public void firePageActivated(final IWorkbenchPage page) {
+		for (Object listener : getListeners()) {
+			final IPageListener pageListener = (IPageListener) listener;
+            fireEvent(new SafeRunnable() {
+                @Override
+				public void run() {
+					pageListener.pageActivated(page);
+                }
+			}, pageListener, page, "activated::"); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Notifies the listener that a part has been closed
+     */
+    public void firePageClosed(final IWorkbenchPage page) {
+		for (Object listener : getListeners()) {
+			final IPageListener pageListener = (IPageListener) listener;
+            fireEvent(new SafeRunnable() {
+                @Override
+				public void run() {
+					pageListener.pageClosed(page);
+                }
+			}, pageListener, page, "closed::"); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Notifies the listener that a part has been opened.
+     */
+    public void firePageOpened(final IWorkbenchPage page) {
+		for (Object listener : getListeners()) {
+			final IPageListener pageListener = (IPageListener) listener;
+            fireEvent(new SafeRunnable() {
+                @Override
+				public void run() {
+					pageListener.pageOpened(page);
+                }
+			}, pageListener, page, "opened::"); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Removes an IPartListener from the part service.
+     */
+    public void removePageListener(IPageListener l) {
+        removeListenerObject(l);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PagePartSelectionTracker.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PagePartSelectionTracker.java
new file mode 100644
index 0000000..d791539
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PagePartSelectionTracker.java
@@ -0,0 +1,275 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.jface.viewers.IPostSelectionProvider;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.ui.IPartListener;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.IPerspectiveListener2;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IViewReference;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartReference;
+
+/**
+ * Provides debug view selection management/notification for
+ * a debug view in a specific workbench page. This selection
+ * provider shields clients from a debug view opening and closing,
+ * and still provides selection notification/information even
+ * when the debug view is not the active part.
+ */
+public class PagePartSelectionTracker extends AbstractPartSelectionTracker
+        implements IPartListener, IPerspectiveListener2, ISelectionChangedListener {
+
+    /**
+     * The workbench page for which this is tracking selection.
+     */
+    private IWorkbenchPage fPage;
+
+    /**
+     * The part in this tracker's page, or <code>null</code> if one is not open.
+     */
+    private IWorkbenchPart fPart;
+
+    private ISelectionChangedListener selectionListener = event -> fireSelection(getPart(), event.getSelection());
+
+    private ISelectionChangedListener postSelectionListener = event -> firePostSelection(getPart(), event.getSelection());
+
+    public PagePartSelectionTracker(IWorkbenchPage page, String partId) {
+        super(partId);
+        setPage(page);
+        page.addPartListener(this);
+        page.getWorkbenchWindow().addPerspectiveListener(this);
+        String secondaryId = null;
+        int indexOfColon;
+        if ((indexOfColon = partId.indexOf(':')) != -1) {
+        	secondaryId = partId.substring(indexOfColon + 1);
+        	partId = partId.substring(0, indexOfColon);
+        }
+		IViewReference part = page.findViewReference(partId, secondaryId);
+        if (part != null && part.getView(false) != null) {
+            setPart(part.getView(false), false);
+        }
+    }
+
+    /**
+     * Disposes this selection provider - removes all listeners
+     * currently registered.
+     */
+    @Override
+	public void dispose() {
+    	IWorkbenchPage page = getPage();
+    	page.getWorkbenchWindow().removePerspectiveListener(this);
+    	page.removePartListener(this);
+        setPart(null, false);
+        setPage(null);
+        super.dispose();
+    }
+
+    /*
+     * @see IPartListener#partActivated(IWorkbenchPart)
+     */
+    @Override
+	public void partActivated(IWorkbenchPart part) {
+    }
+
+    /*
+     * @see IPartListener#partBroughtToTop(IWorkbenchPart)
+     */
+    @Override
+	public void partBroughtToTop(IWorkbenchPart part) {
+    }
+
+    /**
+     * @see IPartListener#partClosed(IWorkbenchPart)
+     */
+    @Override
+	public void partClosed(IWorkbenchPart part) {
+        if (getPartId(part).equals(getPartId())) {
+            setPart(null, true);
+        }
+    }
+
+    /*
+     * @see IPartListener#partDeactivated(IWorkbenchPart)
+     */
+    @Override
+	public void partDeactivated(IWorkbenchPart part) {
+    }
+
+    /**
+     * @see IPartListener#partOpened(IWorkbenchPart)
+     */
+    @Override
+	public void partOpened(IWorkbenchPart part) {
+        if (getPartId(part).equals(getPartId())) {
+            setPart(part, true);
+        }
+    }
+
+    /**
+     * Returns the id for the given part, taking into account
+     * multi-view instances which may have a secondary id.
+     *
+     * @since 3.0
+     */
+    private Object getPartId(IWorkbenchPart part) {
+        String id = part.getSite().getId();
+        if (part instanceof IViewPart) {
+            String secondaryId = ((IViewPart) part).getViewSite()
+                    .getSecondaryId();
+            if (secondaryId != null) {
+                id = id + ':' + secondaryId;
+            }
+        }
+        return id;
+    }
+
+    /**
+     * The selection has changed in the part being tracked.
+     * Forward it to the listeners.
+     *
+     * @see ISelectionChangedListener#selectionChanged
+     */
+    @Override
+	public void selectionChanged(SelectionChangedEvent event) {
+        fireSelection(getPart(), event.getSelection());
+    }
+
+    /**
+     * Sets the page this selection provider works for
+     *
+     * @param page workbench page
+     */
+    private void setPage(IWorkbenchPage page) {
+        fPage = page;
+    }
+
+    /**
+     * Returns the page this selection provider works for
+     *
+     * @return workbench page
+     */
+    protected IWorkbenchPage getPage() {
+        return fPage;
+    }
+
+    /**
+     * Returns the part this is tracking,
+     * or <code>null</code> if it is not open
+     *
+     * @return part., or <code>null</code>
+     */
+    protected IWorkbenchPart getPart() {
+        return fPart;
+    }
+
+    /*
+     * @see AbstractPartSelectionTracker#getSelection()
+     */
+    @Override
+	public ISelection getSelection() {
+        IWorkbenchPart part = getPart();
+        if (part != null) {
+            ISelectionProvider sp = part.getSite().getSelectionProvider();
+            if (sp != null) {
+                return sp.getSelection();
+            }
+        }
+        return null;
+    }
+
+    /**
+     * @see AbstractDebugSelectionProvider#getSelectionProvider()
+     */
+    protected ISelectionProvider getSelectionProvider() {
+        IWorkbenchPart part = getPart();
+        if (part != null) {
+            return part.getSite().getSelectionProvider();
+        }
+        return null;
+    }
+
+    /**
+     * Sets the part for this selection tracker.
+     *
+     * @param part the part
+     * @param notify whether to send notification that the selection has changed.
+     */
+    private void setPart(IWorkbenchPart part, boolean notify) {
+        if (fPart != null) {
+            // remove myself as a listener from the existing part
+            ISelectionProvider sp = fPart.getSite().getSelectionProvider();
+            if (sp != null) {
+                sp.removeSelectionChangedListener(selectionListener);
+                if (sp instanceof IPostSelectionProvider) {
+					((IPostSelectionProvider) sp)
+                            .removePostSelectionChangedListener(postSelectionListener);
+				} else {
+					sp.removeSelectionChangedListener(postSelectionListener);
+				}
+            }
+        }
+        fPart = part;
+        ISelection sel = null;
+        if (part != null) {
+            ISelectionProvider sp = part.getSite().getSelectionProvider();
+            if (sp != null) {
+                sp.addSelectionChangedListener(selectionListener);
+                if (sp instanceof IPostSelectionProvider) {
+					((IPostSelectionProvider) sp)
+                            .addPostSelectionChangedListener(postSelectionListener);
+				} else {
+					sp.addSelectionChangedListener(postSelectionListener);
+				}
+                if (notify) {
+                    // get the selection to send below
+                    sel = sp.getSelection();
+                }
+            }
+        }
+        if (notify) {
+            fireSelection(part, sel);
+            firePostSelection(part, sel);
+        }
+    }
+
+	@Override
+	public void perspectiveActivated(IWorkbenchPage page, IPerspectiveDescriptor perspective) {
+		// nothing to do
+	}
+
+	@Override
+	public void perspectiveChanged(IWorkbenchPage page, IPerspectiveDescriptor perspective, String changeId) {
+		// nothing to do
+	}
+
+	@Override
+	public void perspectiveChanged(IWorkbenchPage page, IPerspectiveDescriptor perspective,
+			IWorkbenchPartReference partRef, String changeId) {
+		if (partRef == null)
+			return;
+		IWorkbenchPart part = partRef.getPart(false);
+		if (part == null)
+			return;
+		if (IWorkbenchPage.CHANGE_VIEW_SHOW.equals(changeId)) {
+			if (getPart() != null) // quick check first, plus avoids double setting
+				return;
+	        if (getPartId(part).equals(getPartId()))
+	            setPart(part, true);
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PageSelectionService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PageSelectionService.java
new file mode 100644
index 0000000..e365adb
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PageSelectionService.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2014 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.ui.internal;
+
+import org.eclipse.ui.IWorkbenchPage;
+
+/**
+ * The selection service for a page.
+ */
+/* package */
+class PageSelectionService extends AbstractSelectionService {
+
+    private IWorkbenchPage page;
+
+    /**
+     * Creates a new selection service for a specific workbench page.
+     */
+    public PageSelectionService(IWorkbenchPage page) {
+        setPage(page);
+    }
+
+    /**
+     * Sets the page.
+     */
+    private void setPage(IWorkbenchPage page) {
+        this.page = page;
+    }
+
+    /**
+     * Returns the page.
+     */
+    protected IWorkbenchPage getPage() {
+        return page;
+    }
+
+    /*
+     * @see AbstractSelectionService#createPartTracker(String)
+     */
+    @Override
+	protected AbstractPartSelectionTracker createPartTracker(String partId) {
+        return new PagePartSelectionTracker(getPage(), partId);
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PartListenerList.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PartListenerList.java
new file mode 100644
index 0000000..a160501
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PartListenerList.java
@@ -0,0 +1,144 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.core.commands.common.EventManager;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.jface.util.SafeRunnable;
+import org.eclipse.ui.IPartListener;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.internal.misc.UIStats;
+
+/**
+ * Part listener list.
+ */
+/*
+ * This class should be deleted when IPartListener and IPartListener2
+ * renamed to IPartListener.
+ */
+public class PartListenerList extends EventManager {
+
+    /**
+     * PartNotifier constructor comment.
+     */
+    public PartListenerList() {
+        super();
+    }
+
+    /**
+     * Adds an IPartListener to the part service.
+     */
+    public void addPartListener(IPartListener l) {
+        addListenerObject(l);
+    }
+
+    /**
+     * Calls a part listener with associated performance event instrumentation
+     *
+     * @param runnable
+     * @param listener
+     * @param part
+     * @param description
+     */
+    private void fireEvent(SafeRunnable runnable, IPartListener listener, IWorkbenchPart part, String description) {
+    	String label = null;//for debugging
+    	if (UIStats.isDebugging(UIStats.NOTIFY_PART_LISTENERS)) {
+    		label = description + part.getTitle();
+    		UIStats.start(UIStats.NOTIFY_PART_LISTENERS, label);
+    	}
+    	SafeRunner.run(runnable);
+    	if (UIStats.isDebugging(UIStats.NOTIFY_PART_LISTENERS)) {
+			UIStats.end(UIStats.NOTIFY_PART_LISTENERS, listener, label);
+		}
+	}
+
+    /**
+     * Notifies the listener that a part has been activated.
+     */
+    public void firePartActivated(final IWorkbenchPart part) {
+		for (Object listener : getListeners()) {
+			final IPartListener partListener = (IPartListener) listener;
+            fireEvent(new SafeRunnable() {
+                @Override
+				public void run() {
+					partListener.partActivated(part);
+                }
+			}, partListener, part, "activated::"); //$NON-NLS-1$
+        }
+    }
+
+	/**
+     * Notifies the listener that a part has been brought to top.
+     */
+    public void firePartBroughtToTop(final IWorkbenchPart part) {
+		for (Object listener : getListeners()) {
+			final IPartListener partListener = (IPartListener) listener;
+            fireEvent(new SafeRunnable() {
+                @Override
+				public void run() {
+					partListener.partBroughtToTop(part);
+                }
+			}, partListener, part, "broughtToTop::"); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Notifies the listener that a part has been closed
+     */
+    public void firePartClosed(final IWorkbenchPart part) {
+		for (Object element : getListeners()) {
+			final IPartListener partListener = (IPartListener) element;
+            fireEvent(new SafeRunnable() {
+                @Override
+				public void run() {
+					partListener.partClosed(part);
+                }
+			}, partListener, part, "closed::"); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Notifies the listener that a part has been deactivated.
+     */
+    public void firePartDeactivated(final IWorkbenchPart part) {
+		for (Object listener : getListeners()) {
+			final IPartListener partListener = (IPartListener) listener;
+            fireEvent(new SafeRunnable() {
+                @Override
+				public void run() {
+					partListener.partDeactivated(part);
+                }
+			}, partListener, part, "deactivated::"); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Notifies the listener that a part has been opened.
+     */
+    public void firePartOpened(final IWorkbenchPart part) {
+		for (Object listener : getListeners()) {
+			final IPartListener partListener = (IPartListener) listener;
+            fireEvent(new SafeRunnable() {
+                @Override
+				public void run() {
+					partListener.partOpened(part);
+                }
+			}, partListener, part, "opened::"); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Removes an IPartListener from the part service.
+     */
+    public void removePartListener(IPartListener l) {
+        removeListenerObject(l);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PartListenerList2.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PartListenerList2.java
new file mode 100644
index 0000000..61daec7
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PartListenerList2.java
@@ -0,0 +1,223 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.core.commands.common.EventManager;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.jface.dialogs.IPageChangedListener;
+import org.eclipse.jface.dialogs.PageChangedEvent;
+import org.eclipse.jface.util.SafeRunnable;
+import org.eclipse.ui.IPartListener2;
+import org.eclipse.ui.IWorkbenchPartReference;
+import org.eclipse.ui.internal.misc.UIStats;
+
+/**
+ * Part listener list.
+ */
+public class PartListenerList2 extends EventManager {
+
+    /**
+     * PartListenerList2 constructor comment.
+     */
+    public PartListenerList2() {
+        super();
+    }
+
+    /**
+     * Adds an PartListener to the part service.
+     */
+    public void addPartListener(IPartListener2 l) {
+        addListenerObject(l);
+    }
+
+    /**
+     * Calls a part listener with associated performance event instrumentation
+     *
+     * @param runnable
+     * @param listener
+     * @param ref
+     * @param string
+     */
+    private void fireEvent(SafeRunnable runnable, IPartListener2 listener, IWorkbenchPartReference ref, String string) {
+    	String label = null;//for debugging
+    	if (UIStats.isDebugging(UIStats.NOTIFY_PART_LISTENERS)) {
+    		label = string + ref.getTitle();
+    		UIStats.start(UIStats.NOTIFY_PART_LISTENERS, label);
+    	}
+    	SafeRunner.run(runnable);
+    	if (UIStats.isDebugging(UIStats.NOTIFY_PART_LISTENERS)) {
+			UIStats.end(UIStats.NOTIFY_PART_LISTENERS, listener, label);
+		}
+	}
+
+    /**
+     * Notifies the listener that a part has been activated.
+     */
+    public void firePartActivated(final IWorkbenchPartReference ref) {
+		for (Object listener : getListeners()) {
+			final IPartListener2 partListener = (IPartListener2) listener;
+            fireEvent(new SafeRunnable() {
+                @Override
+				public void run() {
+					partListener.partActivated(ref);
+                }
+			}, partListener, ref, "activated::"); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Notifies the listener that a part has been brought to top.
+     */
+    public void firePartBroughtToTop(final IWorkbenchPartReference ref) {
+		for (Object listener : getListeners()) {
+			final IPartListener2 partListener = (IPartListener2) listener;
+            fireEvent(new SafeRunnable() {
+                @Override
+				public void run() {
+					partListener.partBroughtToTop(ref);
+                }
+			}, partListener, ref, "broughtToTop::"); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Notifies the listener that a part has been closed
+     */
+    public void firePartClosed(final IWorkbenchPartReference ref) {
+		for (Object listener : getListeners()) {
+			final IPartListener2 partListener = (IPartListener2) listener;
+            fireEvent(new SafeRunnable() {
+                @Override
+				public void run() {
+					partListener.partClosed(ref);
+                }
+			}, partListener, ref, "closed::"); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Notifies the listener that a part has been deactivated.
+     */
+    public void firePartDeactivated(final IWorkbenchPartReference ref) {
+		for (Object listener : getListeners()) {
+			final IPartListener2 partListener = (IPartListener2) listener;
+            fireEvent(new SafeRunnable() {
+                @Override
+				public void run() {
+					partListener.partDeactivated(ref);
+                }
+			}, partListener, ref, "deactivated::"); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Notifies the listener that a part has been opened.
+     */
+    public void firePartOpened(final IWorkbenchPartReference ref) {
+		for (Object listener : getListeners()) {
+			final IPartListener2 partListener = (IPartListener2) listener;
+            fireEvent(new SafeRunnable() {
+                @Override
+				public void run() {
+					partListener.partOpened(ref);
+                }
+			}, partListener, ref, "opened::"); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Notifies the listener that a part has been opened.
+     */
+    public void firePartHidden(final IWorkbenchPartReference ref) {
+		for (Object element : getListeners()) {
+			final IPartListener2 partListener;
+            if (element instanceof IPartListener2) {
+				partListener = (IPartListener2) element;
+			} else {
+				continue;
+			}
+
+            fireEvent(new SafeRunnable() {
+                @Override
+				public void run() {
+					partListener.partHidden(ref);
+                }
+			}, partListener, ref, "hidden::"); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Notifies the listener that a part has been opened.
+     */
+    public void firePartVisible(final IWorkbenchPartReference ref) {
+		for (Object listener : getListeners()) {
+			final IPartListener2 partListener;
+			if (listener instanceof IPartListener2) {
+				partListener = (IPartListener2) listener;
+			} else {
+				continue;
+			}
+
+            fireEvent(new SafeRunnable() {
+                @Override
+				public void run() {
+					partListener.partVisible(ref);
+                }
+			}, partListener, ref, "visible::"); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Notifies the listener that a part has been opened.
+     */
+    public void firePartInputChanged(final IWorkbenchPartReference ref) {
+		for (Object listener : getListeners()) {
+			final IPartListener2 partListener;
+			if (listener instanceof IPartListener2) {
+				partListener = (IPartListener2) listener;
+			} else {
+				continue;
+			}
+
+            fireEvent(new SafeRunnable() {
+                @Override
+				public void run() {
+					partListener.partInputChanged(ref);
+                }
+			}, partListener, ref, "inputChanged::"); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Removes an IPartListener from the part service.
+     */
+    public void removePartListener(IPartListener2 l) {
+        removeListenerObject(l);
+    }
+
+	public void firePageChanged(final PageChangedEvent event) {
+		for (Object listener : getListeners()) {
+			final IPageChangedListener partListener;
+			if (listener instanceof IPageChangedListener) {
+				partListener = (IPageChangedListener) listener;
+			} else {
+				continue;
+			}
+
+            SafeRunnable.run(new SafeRunnable() {
+                @Override
+				public void run() {
+					partListener.pageChanged(event);
+                }
+            });
+        }
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PartPane.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PartPane.java
new file mode 100644
index 0000000..a785576
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PartPane.java
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ * Copyright (c) 2011 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.ui.internal;
+
+import org.eclipse.swt.widgets.Control;
+
+public abstract class PartPane {
+
+	public abstract Control getControl();
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PartPluginAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PartPluginAction.java
new file mode 100644
index 0000000..b863627
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PartPluginAction.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 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.ui.internal;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.ui.IWorkbenchPart;
+
+/**
+ * This class adds to the PluginAction support by
+ * setting itself up for work within a WorkbenchPart.
+ * The main difference is that it is capable of
+ * processing local selection changes within a part.
+ */
+public class PartPluginAction extends PluginAction {
+    /**
+     * PartPluginAction constructor.
+     */
+    public PartPluginAction(IConfigurationElement actionElement, String id,
+            int style) {
+        super(actionElement, id, style);
+    }
+
+    /**
+     * Registers this action as a listener of the workbench part.
+     */
+    protected void registerSelectionListener(IWorkbenchPart aPart) {
+        ISelectionProvider selectionProvider = aPart.getSite()
+                .getSelectionProvider();
+        if (selectionProvider != null) {
+            selectionProvider.addSelectionChangedListener(this);
+            selectionChanged(selectionProvider.getSelection());
+        }
+    }
+
+    /**
+     * Unregisters this action as a listener of the workbench part.
+     */
+    protected void unregisterSelectionListener(IWorkbenchPart aPart) {
+        ISelectionProvider selectionProvider = aPart.getSite()
+                .getSelectionProvider();
+        if (selectionProvider != null) {
+            selectionProvider.removeSelectionChangedListener(this);
+        }
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PartService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PartService.java
new file mode 100644
index 0000000..570fcd1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PartService.java
@@ -0,0 +1,247 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2016 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.ui.internal;
+
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.jface.dialogs.IPageChangedListener;
+import org.eclipse.jface.dialogs.PageChangedEvent;
+import org.eclipse.jface.util.SafeRunnable;
+import org.eclipse.ui.IPartListener;
+import org.eclipse.ui.IPartListener2;
+import org.eclipse.ui.IPartService;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartReference;
+
+public class PartService implements IPageChangedListener, IPartListener, IPartListener2,
+		IPartService {
+
+	private ListenerList<IPartListener> partListeners = new ListenerList<>();
+	private ListenerList<IPartListener2> partListeners2 = new ListenerList<>();
+
+	private WorkbenchPage page;
+
+	void setPage(WorkbenchPage page) {
+		if (page == null) {
+			if (this.page != null) {
+				this.page.removePartListener((IPartListener) this);
+				this.page.removePartListener((IPartListener2) this);
+			}
+		} else {
+			page.addPartListener((IPartListener) this);
+			page.addPartListener((IPartListener2) this);
+		}
+
+		this.page = page;
+	}
+
+	@Override
+	public void addPartListener(IPartListener listener) {
+		partListeners.add(listener);
+	}
+
+	@Override
+	public void addPartListener(IPartListener2 listener) {
+		partListeners2.add(listener);
+	}
+
+	@Override
+	public IWorkbenchPart getActivePart() {
+		return page == null ? null : page.getActivePart();
+	}
+
+	@Override
+	public IWorkbenchPartReference getActivePartReference() {
+		return page == null ? null : page.getActivePartReference();
+	}
+
+	@Override
+	public void removePartListener(IPartListener listener) {
+		partListeners.remove(listener);
+	}
+
+	@Override
+	public void removePartListener(IPartListener2 listener) {
+		partListeners2.remove(listener);
+	}
+
+	@Override
+	public void partActivated(final IWorkbenchPart part) {
+		for (final IPartListener listener : partListeners) {
+			SafeRunner.run(new SafeRunnable() {
+				@Override
+				public void run() throws Exception {
+					listener.partActivated(part);
+				}
+			});
+		}
+	}
+
+	@Override
+	public void partBroughtToTop(final IWorkbenchPart part) {
+		for (final IPartListener listener : partListeners) {
+			SafeRunner.run(new SafeRunnable() {
+				@Override
+				public void run() throws Exception {
+					listener.partBroughtToTop(part);
+				}
+			});
+		}
+	}
+
+	@Override
+	public void partClosed(final IWorkbenchPart part) {
+		for (final IPartListener listener : partListeners) {
+			SafeRunner.run(new SafeRunnable() {
+				@Override
+				public void run() throws Exception {
+					listener.partClosed(part);
+				}
+			});
+		}
+	}
+
+	@Override
+	public void partDeactivated(final IWorkbenchPart part) {
+		for (final IPartListener listener : partListeners) {
+			SafeRunner.run(new SafeRunnable() {
+				@Override
+				public void run() throws Exception {
+					listener.partDeactivated(part);
+				}
+			});
+		}
+	}
+
+	@Override
+	public void partOpened(final IWorkbenchPart part) {
+		for (final IPartListener listener : partListeners) {
+			SafeRunner.run(new SafeRunnable() {
+				@Override
+				public void run() throws Exception {
+					listener.partOpened(part);
+				}
+			});
+		}
+	}
+
+	@Override
+	public void partActivated(final IWorkbenchPartReference partRef) {
+		for (final IPartListener2 listener : partListeners2) {
+			SafeRunner.run(new SafeRunnable() {
+				@Override
+				public void run() throws Exception {
+					listener.partActivated(partRef);
+				}
+			});
+		}
+	}
+
+	@Override
+	public void partBroughtToTop(final IWorkbenchPartReference partRef) {
+		for (final IPartListener2 listener : partListeners2) {
+			SafeRunner.run(new SafeRunnable() {
+				@Override
+				public void run() throws Exception {
+					listener.partBroughtToTop(partRef);
+				}
+			});
+		}
+	}
+
+	@Override
+	public void partClosed(final IWorkbenchPartReference partRef) {
+		for (final IPartListener2 listener : partListeners2) {
+			SafeRunner.run(new SafeRunnable() {
+				@Override
+				public void run() throws Exception {
+					listener.partClosed(partRef);
+				}
+			});
+		}
+	}
+
+	@Override
+	public void partDeactivated(final IWorkbenchPartReference partRef) {
+		for (final IPartListener2 listener : partListeners2) {
+			SafeRunner.run(new SafeRunnable() {
+				@Override
+				public void run() throws Exception {
+					listener.partDeactivated(partRef);
+				}
+			});
+		}
+	}
+
+	@Override
+	public void partOpened(final IWorkbenchPartReference partRef) {
+		for (final IPartListener2 listener : partListeners2) {
+			SafeRunner.run(new SafeRunnable() {
+				@Override
+				public void run() throws Exception {
+					listener.partOpened(partRef);
+				}
+			});
+		}
+	}
+
+	@Override
+	public void partHidden(final IWorkbenchPartReference partRef) {
+		for (final IPartListener2 listener : partListeners2) {
+			SafeRunner.run(new SafeRunnable() {
+				@Override
+				public void run() throws Exception {
+					listener.partHidden(partRef);
+				}
+			});
+		}
+	}
+
+	@Override
+	public void partVisible(final IWorkbenchPartReference partRef) {
+		for (final IPartListener2 listener : partListeners2) {
+			SafeRunner.run(new SafeRunnable() {
+				@Override
+				public void run() throws Exception {
+					listener.partVisible(partRef);
+				}
+			});
+		}
+	}
+
+	@Override
+	public void partInputChanged(final IWorkbenchPartReference partRef) {
+		for (final IPartListener2 listener : partListeners2) {
+			SafeRunner.run(new SafeRunnable() {
+				@Override
+				public void run() throws Exception {
+					listener.partInputChanged(partRef);
+				}
+			});
+		}
+	}
+
+	@Override
+	public void pageChanged(final PageChangedEvent event) {
+		for (final IPartListener2 listener : partListeners2) {
+			if (listener instanceof IPageChangedListener) {
+				SafeRunner.run(new SafeRunnable() {
+					@Override
+					public void run() throws Exception {
+						((IPageChangedListener) listener).pageChanged(event);
+					}
+				});
+			}
+		}
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PartSite.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PartSite.java
new file mode 100644
index 0000000..357251c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PartSite.java
@@ -0,0 +1,650 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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
+ *     Dan Rubel (dan_rubel@instantiations.com) - accessor to get context menu ids
+ *******************************************************************************/
+package org.eclipse.ui.internal;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.e4.core.contexts.ContextFunction;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.ui.MElementContainer;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IKeyBindingService;
+import org.eclipse.ui.IPageService;
+import org.eclipse.ui.IPartService;
+import org.eclipse.ui.ISelectionService;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartReference;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.SubActionBars;
+import org.eclipse.ui.contexts.IContextService;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.internal.contexts.SlaveContextService;
+import org.eclipse.ui.internal.expressions.ActivePartExpression;
+import org.eclipse.ui.internal.handlers.LegacyHandlerService;
+import org.eclipse.ui.internal.menus.SlaveMenuService;
+import org.eclipse.ui.internal.progress.WorkbenchSiteProgressService;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.services.IServiceLocatorCreator;
+import org.eclipse.ui.internal.services.IWorkbenchLocationService;
+import org.eclipse.ui.internal.services.ServiceLocator;
+import org.eclipse.ui.internal.services.WorkbenchLocationService;
+import org.eclipse.ui.internal.testing.WorkbenchPartTestable;
+import org.eclipse.ui.menus.IMenuService;
+import org.eclipse.ui.progress.IProgressService;
+import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
+import org.eclipse.ui.services.IServiceScopes;
+import org.eclipse.ui.testing.IWorkbenchPartTestable;
+
+/**
+ * <code>PartSite</code> is the general implementation for an
+ * <code>IWorkbenchPartSite</code>. A site maintains the context for a part,
+ * including the part, its pane, active contributions, selection provider, etc.
+ * Together, these components make up the complete behavior for a part as if it
+ * was implemented by one person.
+ *
+ * The <code>PartSite</code> lifecycle is as follows ..
+ *
+ * <ol>
+ * <li>a site is constructed </li>
+ * <li>a part is constructed and stored in the part </li>
+ * <li>the site calls part.init() </li>
+ * <li>a pane is constructed and stored in the site </li>
+ * <li>the action bars for a part are constructed and stored in the site </li>
+ * <li>the pane is added to a presentation </li>
+ * <li>the SWT widgets for the pane and part are created </li>
+ * <li>the site is activated, causing the actions to become visible </li>
+ * </ol>
+ */
+public abstract class PartSite implements IWorkbenchPartSite {
+
+	/**
+	 * This is a helper method for the register context menu functionality. It
+	 * is provided so that different implementations of the
+	 * <code>IWorkbenchPartSite</code> interface don't have to worry about how
+	 * context menus should work.
+	 *
+	 * @param menuId
+	 *            the menu id
+	 * @param menuManager
+	 *            the menu manager
+	 * @param selectionProvider
+	 *            the selection provider
+	 * @param includeEditorInput
+	 *            whether editor inputs should be included in the structured
+	 *            selection when calculating contributions
+	 * @param part
+	 *            the part for this site
+	 * @param menuExtenders
+	 *            the collection of menu extenders for this site
+	 * @see IWorkbenchPartSite#registerContextMenu(MenuManager,
+	 *      ISelectionProvider)
+	 */
+	public static final void registerContextMenu(final String menuId,
+			final MenuManager menuManager, final ISelectionProvider selectionProvider,
+			final boolean includeEditorInput, final IWorkbenchPart part, IEclipseContext context,
+			final Collection menuExtenders) {
+		/*
+		 * Check to see if the same menu manager and selection provider have
+		 * already been used. If they have, then we can just add another menu
+		 * identifier to the existing PopupMenuExtender.
+		 */
+		final Iterator extenderItr = menuExtenders.iterator();
+		boolean foundMatch = false;
+		while (extenderItr.hasNext()) {
+			final PopupMenuExtender existingExtender = (PopupMenuExtender) extenderItr
+					.next();
+			if (existingExtender.matches(menuManager, selectionProvider, part)) {
+				existingExtender.addMenuId(menuId);
+				foundMatch = true;
+				break;
+			}
+		}
+
+		if (!foundMatch) {
+			menuExtenders.add(new PopupMenuExtender(menuId, menuManager, selectionProvider, part,
+					context, includeEditorInput));
+		}
+	}
+
+	private IWorkbenchPartReference partReference;
+
+	private IWorkbenchPart part;
+
+	private ISelectionProvider selectionProvider;
+
+	private SubActionBars actionBars;
+
+	private KeyBindingService keyBindingService;
+
+	private SlavePageService pageService;
+
+	private SlavePartService partService;
+
+	private SlaveSelectionService selectionService;
+
+	private SlaveContextService contextService;
+
+	private SlaveMenuService menuService;
+
+	protected ArrayList menuExtenders;
+
+	private WorkbenchSiteProgressService progressService;
+
+	protected final ServiceLocator serviceLocator;
+
+	protected MPart model;
+
+	private IConfigurationElement element;
+
+	private IEclipseContext e4Context;
+
+	private IWorkbenchWindow workbenchWindow;
+
+	private String extensionId;
+
+	/**
+	 * Build the part site.
+	 *
+	 * @param ref
+	 *            the part reference
+	 * @param part
+	 *            the part
+	 * @param page
+	 *            the page it belongs to
+	 */
+	public PartSite(MPart model, IWorkbenchPart part, IWorkbenchPartReference ref,
+			IConfigurationElement element) {
+		this.model = model;
+		this.part = part;
+		this.partReference = ref;
+		this.element = element;
+
+		MElementContainer<?> parent = (MElementContainer<?>) ((EObject) model).eContainer();
+		while (!(parent instanceof MWindow)) {
+			parent = (MElementContainer<?>) ((EObject) parent).eContainer(); // parent.getParent();
+		}
+
+		setWindow((MWindow) parent);
+
+		e4Context = model.getContext();
+		IServiceLocatorCreator slc = e4Context
+				.get(IServiceLocatorCreator.class);
+		IWorkbenchWindow workbenchWindow = getWorkbenchWindow();
+		this.serviceLocator = (ServiceLocator) slc.createServiceLocator(workbenchWindow, null,
+				() -> {
+					// not sure what to do here
+				}, e4Context);
+		initializeDefaultServices();
+	}
+
+	void setExtensionId(String extensionId) {
+		this.extensionId = extensionId;
+	}
+
+	private void setWindow(MWindow window) {
+		MWindow topWindow = getTopLevelModelWindow(window);
+		MApplication application = topWindow.getContext().get(MApplication.class);
+		Workbench workbench = (Workbench) application.getContext().get(IWorkbench.class);
+
+		workbenchWindow = workbench.createWorkbenchWindow(
+				workbench.getDefaultPageInput(),
+				workbench.getPerspectiveRegistry().findPerspectiveWithId(
+						workbench.getPerspectiveRegistry().getDefaultPerspective()), topWindow,
+				false);
+	}
+
+	/**
+	 * Initialize the local services.
+	 */
+	private void initializeDefaultServices() {
+		IHandlerService handlerService = new LegacyHandlerService(e4Context,
+				new ActivePartExpression(part));
+		e4Context.set(IHandlerService.class, handlerService);
+
+		serviceLocator.registerService(IWorkbenchLocationService.class,
+				new WorkbenchLocationService(IServiceScopes.PARTSITE_SCOPE,
+						getWorkbenchWindow().getWorkbench(),
+						getWorkbenchWindow(), this, null, null, 2));
+		// added back for legacy reasons
+		serviceLocator.registerService(IWorkbenchPartSite.class, this);
+		serviceLocator.registerService(IWorkbenchPart.class, getPart());
+
+		e4Context.set(IWorkbenchSiteProgressService.class.getName(), new ContextFunction() {
+			@Override
+			public Object compute(IEclipseContext context, String contextKey) {
+				if (progressService == null) {
+					progressService = new WorkbenchSiteProgressService(PartSite.this);
+				}
+				return progressService;
+			}
+		});
+		e4Context.set(IProgressService.class.getName(), new ContextFunction() {
+			@Override
+			public Object compute(IEclipseContext context, String contextKey) {
+				if (progressService == null) {
+					progressService = new WorkbenchSiteProgressService(PartSite.this);
+				}
+				return progressService;
+			}
+		});
+		e4Context.set(IKeyBindingService.class.getName(), new ContextFunction() {
+			@Override
+			public Object compute(IEclipseContext context, String contextKey) {
+				if (keyBindingService == null) {
+					keyBindingService = new KeyBindingService(PartSite.this);
+				}
+
+				return keyBindingService;
+			}
+		});
+		e4Context.set(IPageService.class.getName(), new ContextFunction() {
+			@Override
+			public Object compute(IEclipseContext context, String contextKey) {
+				if (pageService == null) {
+					pageService = new SlavePageService(context.getParent().get(IPageService.class));
+				}
+
+				return pageService;
+			}
+		});
+		e4Context.set(IPartService.class.getName(), new ContextFunction() {
+			@Override
+			public Object compute(IEclipseContext context, String contextKey) {
+				if (partService == null) {
+					partService = new SlavePartService(context.getParent().get(IPartService.class));
+				}
+				return partService;
+			}
+		});
+		e4Context.set(ISelectionService.class.getName(), new ContextFunction() {
+			@Override
+			public Object compute(IEclipseContext context, String contextKey) {
+				if (selectionService == null) {
+					selectionService = new SlaveSelectionService(context.getParent().get(
+							ISelectionService.class));
+				}
+				return selectionService;
+			}
+		});
+		e4Context.set(IContextService.class.getName(), new ContextFunction() {
+			@Override
+			public Object compute(IEclipseContext context, String contextKey) {
+				if (contextService == null) {
+					contextService = new SlaveContextService(context.getParent().get(
+							IContextService.class), new ActivePartExpression(part));
+				}
+				return contextService;
+			}
+		});
+		e4Context.set(IMenuService.class.getName(), new ContextFunction() {
+			@Override
+			public Object compute(IEclipseContext context, String contextKey) {
+				if (menuService == null) {
+					menuService = new SlaveMenuService(context.getParent().get(IMenuService.class),
+							model);
+				}
+				return menuService;
+			}
+		});
+	}
+
+	/**
+	 * Dispose the contributions.
+	 */
+	public void dispose() {
+		if (menuExtenders != null) {
+			HashSet managers = new HashSet(menuExtenders.size());
+			for (int i = 0; i < menuExtenders.size(); i++) {
+				PopupMenuExtender ext = (PopupMenuExtender) menuExtenders.get(i);
+				managers.add(ext.getManager());
+				ext.dispose();
+			}
+			if (managers.size()>0) {
+				for (Iterator iterator = managers.iterator(); iterator
+						.hasNext();) {
+					MenuManager mgr = (MenuManager) iterator.next();
+					mgr.dispose();
+				}
+			}
+			menuExtenders = null;
+		}
+
+		 if (keyBindingService != null) {
+			keyBindingService.dispose();
+			keyBindingService = null;
+		 }
+
+		if (progressService != null) {
+			progressService.dispose();
+			progressService = null;
+		}
+
+		if (pageService != null) {
+			pageService.dispose();
+		}
+
+		if (partService != null) {
+			partService.dispose();
+		}
+
+		if (selectionService != null) {
+			selectionService.dispose();
+		}
+
+		if (contextService != null) {
+			contextService.dispose();
+		}
+
+		if (serviceLocator != null) {
+			serviceLocator.dispose();
+		}
+		menuService = null;
+		part = null;
+	}
+
+	/**
+	 * Returns the action bars for the part. If this part is a view then it has
+	 * exclusive use of the action bars. If this part is an editor then the
+	 * action bars are shared among this editor and other editors of the same
+	 * type.
+	 */
+	public IActionBars getActionBars() {
+		return actionBars;
+	}
+
+	@Override
+	public String getId() {
+		return extensionId == null ? element == null ? model.getElementId() : element
+				.getAttribute(IWorkbenchRegistryConstants.ATT_ID)
+				: extensionId;
+	}
+
+	@Override
+	public String getPluginId() {
+		return element == null ? model.getElementId() : element.getNamespaceIdentifier();
+	}
+
+	@Override
+	public String getRegisteredName() {
+		return element == null ? model.getLocalizedLabel() : element
+				.getAttribute(IWorkbenchRegistryConstants.ATT_NAME);
+	}
+
+	/**
+	 * Returns the page containing this workbench site's part.
+	 *
+	 * @return the page containing this part
+	 */
+	@Override
+	public IWorkbenchPage getPage() {
+		return getWorkbenchWindow().getActivePage();
+	}
+
+
+	/**
+	 * Returns the part.
+	 */
+	@Override
+	public IWorkbenchPart getPart() {
+		return part;
+	}
+
+	/**
+	 * Returns the part reference.
+	 */
+	public IWorkbenchPartReference getPartReference() {
+		return partReference;
+	}
+
+	/**
+	 * Returns the selection provider for a part.
+	 */
+	@Override
+	public ISelectionProvider getSelectionProvider() {
+		return selectionProvider;
+	}
+
+	/**
+	 * Returns the shell containing this part.
+	 *
+	 * @return the shell containing this part
+	 */
+	@Override
+	public Shell getShell() {
+
+		// Compatibility: This method should not be used outside the UI
+		// thread... but since this condition
+		// was not always in the JavaDoc, we still try to return our best guess
+		// about the shell if it is
+		// called from the wrong thread.
+		Display currentDisplay = Display.getCurrent();
+		if (currentDisplay == null) {
+			// Uncomment this to locate places that try to access the shell from
+			// a background thread
+			// WorkbenchPlugin.log(new Exception("Error:
+			// IWorkbenchSite.getShell() was called outside the UI thread. Fix
+			// this code.")); //$NON-NLS-1$
+
+			return getWorkbenchWindow().getShell();
+		}
+
+		Control control = (Control) model.getWidget();
+		if (control != null && !control.isDisposed()) {
+			return control.getShell();
+		}
+		// likely means the part has been destroyed, return the parent window's
+		// shell, we don't just arbitrarily return the workbench window's shell
+		// because we may be in a detached window
+		MWindow window = e4Context.get(MWindow.class);
+		return window == null ? getWorkbenchWindow().getShell() : (Shell) window.getWidget();
+	}
+
+	private MWindow getTopLevelModelWindow(MWindow window) {
+		EObject previousParent = (EObject) window;
+		EObject parent = previousParent.eContainer();
+		// we can't simply stop at an MWindow because the part may be in a detached window
+		while (!(parent instanceof MApplication)) {
+			previousParent = parent;
+			parent = parent.eContainer();
+		}
+
+		return (MWindow) previousParent;
+	}
+
+	/**
+	 * Returns the workbench window containing this part.
+	 *
+	 * @return the workbench window containing this part
+	 */
+	@Override
+	public IWorkbenchWindow getWorkbenchWindow() {
+		return workbenchWindow;
+	}
+
+	/**
+	 * Register a popup menu for extension.
+	 */
+	@Override
+	public void registerContextMenu(String menuID, MenuManager menuMgr,
+			ISelectionProvider selProvider) {
+		if (menuExtenders == null) {
+			menuExtenders = new ArrayList(1);
+		}
+
+		registerContextMenu(menuID, menuMgr, selProvider, true, getPart(), e4Context, menuExtenders);
+	}
+
+	/**
+	 * Register a popup menu with the default id for extension.
+	 */
+	@Override
+	public void registerContextMenu(MenuManager menuMgr,
+			ISelectionProvider selProvider) {
+		registerContextMenu(getId(), menuMgr, selProvider);
+	}
+
+	// getContextMenuIds() added by Dan Rubel (dan_rubel@instantiations.com)
+	/**
+	 * Get the registered popup menu identifiers
+	 */
+	public String[] getContextMenuIds() {
+		if (menuExtenders == null) {
+			return new String[0];
+		}
+		ArrayList menuIds = new ArrayList(menuExtenders.size());
+		for (Iterator iter = menuExtenders.iterator(); iter.hasNext();) {
+			final PopupMenuExtender extender = (PopupMenuExtender) iter.next();
+			menuIds.addAll(extender.getMenuIds());
+		}
+		return (String[]) menuIds.toArray(new String[menuIds.size()]);
+	}
+
+	/**
+	 * Sets the action bars for the part.
+	 */
+	public void setActionBars(SubActionBars bars) {
+		actionBars = bars;
+	}
+
+
+	/**
+	 * Sets the part.
+	 */
+	public void setPart(IWorkbenchPart newPart) {
+		part = newPart;
+	}
+
+
+	/**
+	 * Set the selection provider for a part.
+	 */
+	@Override
+	public void setSelectionProvider(ISelectionProvider provider) {
+		selectionProvider = provider;
+	}
+
+	/*
+	 * @see IWorkbenchPartSite#getKeyBindingService()
+	 */
+	@Override
+	public IKeyBindingService getKeyBindingService() {
+		return e4Context.get(IKeyBindingService.class);
+	}
+
+	protected String getInitialScopeId() {
+		return null;
+	}
+
+	/**
+	 * Get an adapter for this type.
+	 *
+	 * @param adapter
+	 * @return
+	 */
+	@Override
+	public final <T> T getAdapter(Class<T> adapter) {
+
+		if (IWorkbenchSiteProgressService.class == adapter) {
+			return adapter.cast(getService(adapter));
+		}
+
+		if (IWorkbenchPartTestable.class == adapter) {
+			return adapter.cast(new WorkbenchPartTestable(this));
+		}
+
+		return Platform.getAdapterManager().getAdapter(this, adapter);
+	}
+
+	public void activateActionBars(boolean forceVisibility) {
+		if (serviceLocator != null) {
+			serviceLocator.activate();
+		}
+
+		if (actionBars != null) {
+			actionBars.activate(forceVisibility);
+		}
+	}
+
+	public void deactivateActionBars(boolean forceHide) {
+		if (actionBars != null) {
+			actionBars.deactivate(forceHide);
+		}
+		if (serviceLocator != null) {
+			serviceLocator.deactivate();
+		}
+	}
+
+	/**
+	 * Get a progress service for the receiver.
+	 *
+	 * @return WorkbenchSiteProgressService
+	 */
+	WorkbenchSiteProgressService getSiteProgressService() {
+		return (WorkbenchSiteProgressService) e4Context.get(IWorkbenchSiteProgressService.class
+				.getName());
+	}
+
+	@Override
+	public final <T> T getService(final Class<T> key) {
+		return serviceLocator.getService(key);
+	}
+
+	@Override
+	public final boolean hasService(final Class<?> key) {
+		return serviceLocator.hasService(key);
+	}
+
+	/**
+	 * Prints out the identifier, the plug-in identifier and the registered
+	 * name. This is for debugging purposes only.
+	 *
+	 * @since 3.2
+	 */
+	@Override
+	public String toString() {
+		final StringBuffer buffer = new StringBuffer();
+		buffer.append("PartSite(id="); //$NON-NLS-1$
+		buffer.append(getId());
+		buffer.append(",pluginId="); //$NON-NLS-1$
+		buffer.append(getPluginId());
+		buffer.append(",registeredName="); //$NON-NLS-1$
+		buffer.append(getRegisteredName());
+		buffer.append(",hashCode="); //$NON-NLS-1$
+		buffer.append(hashCode());
+		buffer.append(')');
+		return buffer.toString();
+	}
+
+	public MPart getModel() {
+		return model;
+	}
+
+	public IEclipseContext getContext() {
+		return e4Context;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PartTester.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PartTester.java
new file mode 100644
index 0000000..3fe2f99
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PartTester.java
@@ -0,0 +1,145 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IPersistableElement;
+import org.eclipse.ui.IPropertyListener;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPart2;
+
+public class PartTester {
+    private PartTester() {
+    }
+
+    /**
+     * Sanity-check the public interface of the editor. This is called on every editor after it
+     * is fully initiallized, but before it is actually connected to the editor reference or the
+     * layout. Calls as much of the editor's public interface as possible to test for exceptions,
+     * and tests the return values for glaring faults. This does not need to be an exhaustive conformance
+     * test, as it is called every time an editor is opened and it needs to be efficient.
+     * The part should be unmodified when the method exits.
+     *
+     * @param part
+     */
+    public static void testEditor(IEditorPart part) throws Exception {
+        testWorkbenchPart(part);
+
+        Assert.isTrue(part.getEditorSite() == part.getSite(),
+				"The part's editor site must be the same as the part's site"); //$NON-NLS-1$
+		IEditorInput input = part.getEditorInput();
+		Assert.isNotNull(input, "The editor input must be non-null"); //$NON-NLS-1$
+		testEditorInput(input);
+
+        part.isDirty();
+        part.isSaveAsAllowed();
+        part.isSaveOnCloseNeeded();
+    }
+
+    public static void testEditorInput(IEditorInput input) throws Exception {
+        input.getAdapter(Object.class);
+
+        // Don't test input.getImageDescriptor() -- the workbench never uses that
+        // method and most editor inputs would fail the test. It should really be
+        // deprecated.
+
+        Assert.isNotNull(input.getName(),
+				"The editor input must have a non-null name"); //$NON-NLS-1$
+		Assert.isNotNull(input.getToolTipText(),
+				"The editor input must have a non-null tool tip"); //$NON-NLS-1$
+
+		// Persistable element may be null
+		IPersistableElement persistableElement = input.getPersistable();
+		if (persistableElement != null) {
+			Assert
+					.isNotNull(persistableElement.getFactoryId(),
+							"The persistable element for the editor input must have a non-null factory id"); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Sanity-checks a workbench part. Excercises the public interface and tests for any
+     * obviously bogus return values. The part should be unmodified when the method exits.
+     *
+     * @param part
+     * @throws Exception
+     */
+    private static void testWorkbenchPart(IWorkbenchPart part) throws Exception {
+        IPropertyListener testListener = (source, propId) -> {
+
+		};
+
+        // Test addPropertyListener
+        part.addPropertyListener(testListener);
+
+        // Test removePropertyListener
+        part.removePropertyListener(testListener);
+
+        // Test equals
+		Assert.isTrue(part.equals(part), "A part must be equal to itself"); //$NON-NLS-1$
+		Assert.isTrue(!part.equals(Integer.valueOf(32)),
+				"A part must have a meaningful equals method"); //$NON-NLS-1$
+
+        // Test getAdapter
+        Object partAdapter = part.getAdapter(part.getClass());
+        Assert.isTrue(partAdapter == null || partAdapter == part,
+				"A part must adapter to itself or return null"); //$NON-NLS-1$
+
+        // Test getTitle
+		Assert.isNotNull(part.getTitle(), "A part's title must be non-null"); //$NON-NLS-1$
+
+		// Test getTitleImage
+		Assert.isNotNull(part.getTitleImage(),
+				"A part's title image must be non-null"); //$NON-NLS-1$
+
+		// Test getTitleToolTip
+		Assert.isNotNull(part.getTitleToolTip(),
+				"A part's title tool tip must be non-null"); //$NON-NLS-1$
+
+		// Test toString
+		Assert.isNotNull(part.toString(),
+				"A part's toString method must return a non-null value"); //$NON-NLS-1$
+
+        // Compute hashCode
+        part.hashCode();
+
+        if (part instanceof IWorkbenchPart2) {
+            testWorkbenchPart2((IWorkbenchPart2)part);
+        }
+    }
+
+    private static void testWorkbenchPart2(IWorkbenchPart2 part)
+			throws Exception {
+		Assert.isNotNull(part.getContentDescription(),
+				"A part must return a non-null content description"); //$NON-NLS-1$
+		Assert.isNotNull(part.getPartName(),
+				"A part must return a non-null part name"); //$NON-NLS-1$
+    }
+
+    /**
+     * Sanity-check the public interface of a view. This is called on every view after it
+     * is fully initiallized, but before it is actually connected to the part reference or the
+     * layout. Calls as much of the part's public interface as possible without modifying the part
+     * to test for exceptions and check the return values for glaring faults. This does not need
+     * to be an exhaustive conformance test, as it is called every time an editor is opened and
+     * it needs to be efficient.
+     *
+     * @param part
+     */
+    public static void testView(IViewPart part) throws Exception {
+       Assert.isTrue(part.getSite() == part.getViewSite(),
+				"A part's site must be the same as a part's view site"); //$NON-NLS-1$
+       testWorkbenchPart(part);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PendingSyncExec.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PendingSyncExec.java
new file mode 100644
index 0000000..30e5b78
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PendingSyncExec.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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.ui.internal;
+
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+public final class PendingSyncExec {
+	private final Semaphore semaphore = new Semaphore(0);
+
+	private Thread operation;
+
+	private final Runnable runnable;
+
+	// Accessed by multiple threads. Synchronize on "this" before accessing.
+	private boolean hasFinishedRunning;
+
+    public PendingSyncExec(Runnable runnable) {
+        this.runnable = runnable;
+    }
+
+    /**
+     * Attempts to acquire this semaphore.  Returns true if it was successfully acquired,
+     * and false otherwise.
+     */
+	private boolean acquire(long delay) throws InterruptedException {
+		return semaphore.tryAcquire(delay, TimeUnit.MILLISECONDS);
+    }
+
+    @Override
+	public boolean equals(Object obj) {
+        return (runnable == ((PendingSyncExec) obj).runnable);
+    }
+
+    public Thread getOperationThread() {
+        return operation;
+    }
+
+	public void run() {
+		// Clear the interrupted flag. The blocked thread may have been
+		// periodically interrupting the UI thread in
+		// order to interrupt other tasks in the queue and cause this job to
+		// start execution. (Note that it will
+		// continue to try to interrupt this runnable if it takes too long to
+		// run, until we set the hasFinishedRunning
+		// flag).
+		Thread.interrupted();
+		try {
+			if (runnable != null) {
+				runnable.run();
+			}
+		} finally {
+			// Record the fact that this pending syncExec has finished
+			// execution, to prevent the calling thread from
+			// interrupting this thread.
+			synchronized (this) {
+				hasFinishedRunning = true;
+			}
+			// The calling thread may have still interrupted this operation up
+			// until the point where we flipped the
+			// hasFinishedRunning flag.
+			Thread.interrupted();
+			semaphore.release();
+		}
+	}
+
+	public void waitUntilExecuted(UILockListener lockListener) throws InterruptedException {
+		// even if the UI was not blocked earlier, it might become blocked
+		// before it can serve the asyncExec to do the pending work
+		while (!acquire(1000)) {
+			if (lockListener.isUIWaiting()) {
+				synchronized (this) {
+					if (!hasFinishedRunning) {
+						lockListener.interruptUI(runnable);
+					}
+				}
+			}
+		}
+	}
+
+    @Override
+	public int hashCode() {
+        return runnable == null ? 0 : runnable.hashCode();
+    }
+
+    public void setOperationThread(Thread operation) {
+        this.operation = operation;
+    }
+
+    // for debug only
+    @Override
+	public String toString() {
+		return "PendingSyncExec(" + runnable + ")"; //$NON-NLS-1$ //$NON-NLS-2$
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/Perspective.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/Perspective.java
new file mode 100644
index 0000000..5c82886
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/Perspective.java
@@ -0,0 +1,258 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Markus Alexander Kuppe, Versant GmbH - bug 215797
+ *     Sascha Zak - bug 282874
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 440810, 440136, 472654
+ *     Andrey Loskutov <loskutov@gmx.de> - Bug 404348, 421178, 456727
+ *******************************************************************************/
+
+package org.eclipse.ui.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.contexts.IContextService;
+import org.eclipse.ui.internal.e4.compatibility.ModeledPageLayout;
+import org.eclipse.ui.internal.registry.ActionSetRegistry;
+import org.eclipse.ui.internal.registry.IActionSetDescriptor;
+import org.eclipse.ui.internal.registry.PerspectiveDescriptor;
+
+/**
+ *
+ */
+public class Perspective {
+
+	private final PerspectiveDescriptor descriptor;
+	private final WorkbenchPage page;
+	private final List<IActionSetDescriptor> alwaysOnActionSets;
+	private final List<IActionSetDescriptor> alwaysOffActionSets;
+	private final MPerspective layout;
+
+	public Perspective(PerspectiveDescriptor desc, MPerspective layout, WorkbenchPage page) {
+		Assert.isNotNull(page);
+		this.page = page;
+		this.layout = layout;
+		descriptor = desc;
+		alwaysOnActionSets = new ArrayList<>(2);
+		alwaysOffActionSets = new ArrayList<>(2);
+	}
+
+	public void initActionSets() {
+		if (descriptor != null) {
+			List<String> alwaysOn = ModeledPageLayout.getIds(layout, ModeledPageLayout.ACTION_SET_TAG);
+
+			// read explicitly disabled sets.
+			String hiddenIDs = page.getHiddenItems();
+			List<String> alwaysOff = new ArrayList<>();
+
+			String[] hiddenIds = hiddenIDs.split(","); //$NON-NLS-1$
+			for (String id : hiddenIds) {
+				if (!id.startsWith(ModeledPageLayout.HIDDEN_ACTIONSET_PREFIX)) {
+					continue;
+				}
+				id = id.substring(ModeledPageLayout.HIDDEN_ACTIONSET_PREFIX.length());
+				if (!alwaysOff.contains(id)) {
+					alwaysOff.add(id);
+				}
+			}
+
+			alwaysOn.removeAll(alwaysOff);
+
+			for (IActionSetDescriptor descriptor : createInitialActionSets(alwaysOn)) {
+				if (!alwaysOnActionSets.contains(descriptor)) {
+					alwaysOnActionSets.add(descriptor);
+				}
+			}
+
+			for (IActionSetDescriptor descriptor : createInitialActionSets(alwaysOff)) {
+				if (!alwaysOffActionSets.contains(descriptor)) {
+					alwaysOffActionSets.add(descriptor);
+				}
+			}
+		}
+
+	}
+
+	/**
+	 * Create the initial list of action sets.
+	 *
+	 * @return action set descriptors created from given descriptor id's, can be
+	 *         empty but never null.
+	 */
+	private List<IActionSetDescriptor> createInitialActionSets(List<String> ids) {
+		List<IActionSetDescriptor> result = new ArrayList<>();
+		ActionSetRegistry reg = WorkbenchPlugin.getDefault().getActionSetRegistry();
+		for (String id : ids) {
+			IActionSetDescriptor desc = reg.findActionSet(id);
+			if (desc != null) {
+				result.add(desc);
+			} else {
+				// plugin with actionSet was removed
+				// we remember then so it's available when added back
+			}
+		}
+		return result;
+	}
+
+	/**
+	 * Returns the perspective.
+	 *
+	 * @return can return null!
+	 */
+	public IPerspectiveDescriptor getDesc() {
+		return descriptor;
+	}
+
+	/**
+	 * Returns the new wizard shortcuts associated with this perspective.
+	 *
+	 * @return an array of new wizard identifiers
+	 */
+	public String[] getNewWizardShortcuts() {
+		return page.getNewWizardShortcuts();
+	}
+
+	/**
+	 * Returns the perspective shortcuts associated with this perspective.
+	 *
+	 * @return an array of perspective identifiers
+	 */
+	public String[] getPerspectiveShortcuts() {
+		return page.getPerspectiveShortcuts();
+	}
+
+	/**
+	 * Returns the show view shortcuts associated with this perspective.
+	 *
+	 * @return an array of view identifiers
+	 */
+	public String[] getShowViewShortcuts() {
+		return page.getShowViewShortcuts();
+	}
+
+	private void removeAlwaysOn(IActionSetDescriptor descriptor) {
+		if (alwaysOnActionSets.contains(descriptor)) {
+			alwaysOnActionSets.remove(descriptor);
+			page.perspectiveActionSetChanged(this, descriptor, ActionSetManager.CHANGE_HIDE);
+		}
+	}
+
+	private void addAlwaysOff(IActionSetDescriptor descriptor) {
+		if (!alwaysOffActionSets.contains(descriptor)) {
+			alwaysOffActionSets.add(descriptor);
+			page.perspectiveActionSetChanged(this, descriptor, ActionSetManager.CHANGE_MASK);
+			removeAlwaysOn(descriptor);
+		}
+	}
+
+	private void addAlwaysOn(IActionSetDescriptor descriptor) {
+		if (!alwaysOnActionSets.contains(descriptor)) {
+			alwaysOnActionSets.add(descriptor);
+			page.perspectiveActionSetChanged(this, descriptor, ActionSetManager.CHANGE_SHOW);
+			removeAlwaysOff(descriptor);
+		}
+	}
+
+	private void removeAlwaysOff(IActionSetDescriptor descriptor) {
+		if (alwaysOffActionSets.contains(descriptor)) {
+			alwaysOffActionSets.remove(descriptor);
+			page.perspectiveActionSetChanged(this, descriptor, ActionSetManager.CHANGE_UNMASK);
+		}
+	}
+
+	public void turnOnActionSets(IActionSetDescriptor[] newArray) {
+		for (IActionSetDescriptor descriptor : newArray) {
+			addActionSet(descriptor);
+		}
+	}
+
+	public void turnOffActionSets(IActionSetDescriptor[] toDisable) {
+		for (IActionSetDescriptor descriptor : toDisable) {
+			turnOffActionSet(descriptor);
+		}
+	}
+
+	public void turnOffActionSet(IActionSetDescriptor toDisable) {
+		removeActionSet(toDisable);
+	}
+
+	// for dynamic UI
+	protected void addActionSet(IActionSetDescriptor newDesc) {
+		IContextService service = page.getWorkbenchWindow().getService(IContextService.class);
+		try {
+			service.deferUpdates(true);
+			for (IActionSetDescriptor desc : alwaysOnActionSets) {
+				if (desc.getId().equals(newDesc.getId())) {
+					removeAlwaysOn(desc);
+					removeAlwaysOff(desc);
+					break;
+				}
+			}
+			addAlwaysOn(newDesc);
+			final String actionSetID = newDesc.getId();
+
+			// Add Tags
+			String tag = ModeledPageLayout.ACTION_SET_TAG + actionSetID;
+			if (!layout.getTags().contains(tag)) {
+				layout.getTags().add(tag);
+			}
+		} finally {
+			service.deferUpdates(false);
+		}
+	}
+
+	// for dynamic UI
+	protected void removeActionSet(IActionSetDescriptor toRemove) {
+		String id = toRemove.getId();
+		IContextService service = page.getWorkbenchWindow().getService(IContextService.class);
+		try {
+			service.deferUpdates(true);
+
+			// this advance for loop only works because it breaks out of it
+			// right after the removal
+			for (IActionSetDescriptor desc : alwaysOnActionSets) {
+				if (desc.getId().equals(id)) {
+					removeAlwaysOn(desc);
+					break;
+				}
+			}
+
+			// this advance for loop only works because it breaks out of it
+			// right after the removal
+			for (IActionSetDescriptor desc : alwaysOffActionSets) {
+				if (desc.getId().equals(id)) {
+					removeAlwaysOff(desc);
+					break;
+				}
+			}
+			addAlwaysOff(toRemove);
+			// not necessary to remove the ModeledPageLayout.ACTION_SET_TAG + id
+			// tag as the entry is only disabled.
+		} finally {
+			service.deferUpdates(false);
+		}
+	}
+
+	public List<IActionSetDescriptor> getAlwaysOnActionSets() {
+		return alwaysOnActionSets;
+	}
+
+	public List<IActionSetDescriptor> getAlwaysOffActionSets() {
+		return alwaysOffActionSets;
+	}
+
+	public void updateActionBars() {
+		page.getActionBars().getMenuManager().updateAll(true);
+		page.resetToolBarLayout();
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PerspectiveAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PerspectiveAction.java
new file mode 100644
index 0000000..613e682
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PerspectiveAction.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.action.Action;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.actions.ActionFactory;
+
+/**
+ * Abstract superclass of actions which are enabled iff there is an active perspective
+ * in the window.
+ *
+ * @since 3.1
+ */
+public abstract class PerspectiveAction extends Action implements ActionFactory.IWorkbenchAction {
+
+    /**
+     * The workbench window containing this action.
+     */
+    private IWorkbenchWindow workbenchWindow;
+
+    /**
+     * Tracks perspective activation, to update this action's
+     * enabled state.
+     */
+    private PerspectiveTracker tracker;
+
+    /**
+     * Constructs a new perspective action for the given window.
+     *
+     * @param window the window
+     */
+    protected PerspectiveAction(IWorkbenchWindow window) {
+        Assert.isNotNull(window);
+        this.workbenchWindow = window;
+        tracker = new PerspectiveTracker(window, this);
+    }
+
+    /**
+     * Returns the window, or <code>null</code> if the action has been disposed.
+     *
+     * @return the window or <code>null</code>
+     */
+    protected IWorkbenchWindow getWindow() {
+        return workbenchWindow;
+    }
+
+    @Override
+	public void run() {
+        if (workbenchWindow == null) {
+            // action has been disposed
+            return;
+        }
+        IWorkbenchPage page = workbenchWindow.getActivePage();
+        if (page != null && page.getPerspective() != null) {
+            run(page, page.getPerspective());
+        }
+    }
+
+    /**
+     * Runs the action, passing the active page and perspective.
+     *
+     * @param page the active page
+     * @param persp the active perspective
+     */
+    protected abstract void run(IWorkbenchPage page, IPerspectiveDescriptor persp);
+
+    @Override
+	public void dispose() {
+        if (workbenchWindow == null) {
+            // already disposed
+            return;
+        }
+        tracker.dispose();
+        workbenchWindow = null;
+    }
+
+}
+
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PerspectiveBarContributionItem.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PerspectiveBarContributionItem.java
new file mode 100644
index 0000000..f028873
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PerspectiveBarContributionItem.java
@@ -0,0 +1,240 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.jface.action.ContributionItem;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPreferenceConstants;
+import org.eclipse.ui.internal.util.PrefUtil;
+
+/**
+ * A  {@link ContributionItem} specifically for contributions to the perspective switcher.
+ *
+ */
+public class PerspectiveBarContributionItem extends ContributionItem {
+
+    private IPerspectiveDescriptor perspective;
+
+    private IPreferenceStore apiPreferenceStore = PrefUtil
+            .getAPIPreferenceStore();
+
+    private ToolItem toolItem = null;
+
+    private Image image;
+
+    private IWorkbenchPage workbenchPage;
+
+    /**
+     * Create a new perspective contribution item
+     *
+     * @param perspective the descriptor for the perspective
+     * @param workbenchPage the page that this perspective is in
+     */
+    public PerspectiveBarContributionItem(IPerspectiveDescriptor perspective,
+            IWorkbenchPage workbenchPage) {
+        super(perspective.getId());
+        this.perspective = perspective;
+        this.workbenchPage = workbenchPage;
+    }
+
+    @Override
+	public void dispose() {
+        super.dispose();
+        if (image != null && !image.isDisposed()) {
+            image.dispose();
+            image = null;
+        }
+        apiPreferenceStore = null;
+        workbenchPage = null;
+        perspective = null;
+
+    }
+
+    @Override
+	public void fill(ToolBar parent, int index) {
+        if (toolItem == null && parent != null && !parent.isDisposed()) {
+
+            if (index >= 0) {
+				toolItem = new ToolItem(parent, SWT.CHECK, index);
+			} else {
+				toolItem = new ToolItem(parent, SWT.CHECK);
+			}
+
+            if (image == null || image.isDisposed()) {
+                createImage();
+            }
+            toolItem.setImage(image);
+
+            toolItem.setToolTipText(NLS.bind(WorkbenchMessages.get().PerspectiveBarContributionItem_toolTip, perspective.getLabel()));
+            toolItem.addSelectionListener(new SelectionAdapter()
+            {
+                /** {@inheritDoc} */
+                @Override
+                public void widgetSelected(SelectionEvent e)
+                {
+                    select();
+                }
+            });
+            toolItem.setData(this); //TODO review need for this
+            update();
+        }
+    }
+
+    private void createImage() {
+        ImageDescriptor imageDescriptor = perspective.getImageDescriptor();
+        if (imageDescriptor != null) {
+            image = imageDescriptor.createImage();
+        } else {
+            image = WorkbenchImages.getImageDescriptor(
+                    ISharedImages.IMG_ETOOL_DEF_PERSPECTIVE)
+                    .createImage();
+        }
+    }
+
+    Image getImage() {
+        if (image == null) {
+            createImage();
+        }
+        return image;
+    }
+
+    /**
+     * Select this perspective
+     */
+    public void select() {
+        if (workbenchPage.getPerspective() != perspective) {
+            workbenchPage.setPerspective(perspective);
+        } else {
+			toolItem.setSelection(true);
+		}
+    }
+
+    @Override
+	public void update() {
+        if (toolItem != null && !toolItem.isDisposed()) {
+            toolItem
+                    .setSelection(workbenchPage.getPerspective() == perspective);
+            if (apiPreferenceStore
+                    .getBoolean(IWorkbenchPreferenceConstants.SHOW_TEXT_ON_PERSPECTIVE_BAR)) {
+                if (apiPreferenceStore.getString(
+                        IWorkbenchPreferenceConstants.DOCK_PERSPECTIVE_BAR)
+                        .equals(IWorkbenchPreferenceConstants.TOP_LEFT)) {
+					toolItem.setText(perspective.getLabel());
+				} else {
+					toolItem.setText(shortenText(perspective.getLabel(),
+                            toolItem));
+				}
+            } else {
+                toolItem.setText(""); //$NON-NLS-1$
+            }
+        }
+    }
+
+    /**
+     * Update this item with a new perspective descriptor
+     * @param newDesc
+     */
+    public void update(IPerspectiveDescriptor newDesc) {
+        perspective = newDesc;
+        if (toolItem != null && !toolItem.isDisposed()) {
+            ImageDescriptor imageDescriptor = perspective.getImageDescriptor();
+            if (imageDescriptor != null) {
+                toolItem.setImage(imageDescriptor.createImage());
+            } else {
+                toolItem.setImage(WorkbenchImages.getImageDescriptor(
+                        ISharedImages.IMG_ETOOL_DEF_PERSPECTIVE)
+                        .createImage());
+            }
+            toolItem.setToolTipText(NLS.bind(WorkbenchMessages.get().PerspectiveBarContributionItem_toolTip, perspective.getLabel() ));
+        }
+        update();
+    }
+
+    IWorkbenchPage getPage() {
+        return workbenchPage;
+    }
+
+    IPerspectiveDescriptor getPerspective() {
+        return perspective;
+    }
+
+    ToolItem getToolItem() {
+        return toolItem;
+    }
+
+    /**
+     * Answer whether the receiver is a match for the provided
+     * perspective descriptor
+     *
+     * @param perspective the perspective descriptor
+     * @param workbenchPage the page
+     * @return <code>true</code> if it is a match
+     */
+    public boolean handles(IPerspectiveDescriptor perspective,
+            IWorkbenchPage workbenchPage) {
+        return this.perspective == perspective
+                && this.workbenchPage == workbenchPage;
+    }
+
+    /**
+     * Set the current perspective
+     * @param newPerspective
+     */
+    public void setPerspective(IPerspectiveDescriptor newPerspective) {
+        this.perspective = newPerspective;
+    }
+
+    // TODO review need for this method
+    void setSelection(boolean b) {
+        if (toolItem != null && !toolItem.isDisposed()) {
+			toolItem.setSelection(b);
+		}
+    }
+
+    static int getMaxWidth(Image image) {
+        return image.getBounds().width * 5;
+    }
+
+    private static final String ellipsis = "..."; //$NON-NLS-1$
+
+    protected String shortenText(String textValue, ToolItem item) {
+        if (textValue == null || toolItem == null || toolItem.isDisposed()) {
+			return null;
+		}
+        String returnText = textValue;
+        GC gc = new GC(item.getParent());
+        int maxWidth = getMaxWidth(item.getImage());
+        if (gc.textExtent(textValue).x >= maxWidth) {
+            for (int i = textValue.length(); i > 0; i--) {
+                String test = textValue.substring(0, i);
+                test = test + ellipsis;
+                if (gc.textExtent(test).x < maxWidth) {
+                    returnText = test;
+                    break;
+                }
+            }
+        }
+        gc.dispose();
+        return returnText;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PerspectiveBarNewContributionItem.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PerspectiveBarNewContributionItem.java
new file mode 100644
index 0000000..e537b4b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PerspectiveBarNewContributionItem.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+
+import org.eclipse.jface.action.ContributionItem;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.actions.ContributionItemFactory;
+
+public class PerspectiveBarNewContributionItem extends ContributionItem {
+
+    private MenuManager menuManager = null;
+
+    private Image image;
+
+    private ToolItem toolItem = null;
+
+    public PerspectiveBarNewContributionItem(IWorkbenchWindow workbenchWindow) {
+        super(PerspectiveBarNewContributionItem.class.getName());
+        menuManager = new MenuManager();
+        menuManager.add(ContributionItemFactory.PERSPECTIVES_SHORTLIST
+                .create(workbenchWindow));
+    }
+
+    @Override
+	public void dispose() {
+        super.dispose();
+        if (image != null && !image.isDisposed()) {
+            image.dispose();
+            image = null;
+        }
+    }
+
+    @Override
+	public void fill(final ToolBar parent, int index) {
+        if (toolItem == null && parent != null) {
+            parent.addDisposeListener(e -> {
+			    //toolItem.getImage().dispose();
+			    toolItem.dispose();
+			    toolItem = null;
+			});
+
+            toolItem = new ToolItem(parent, SWT.PUSH);
+            if (image == null || image.isDisposed()) {
+                image = WorkbenchImages.getImageDescriptor(
+                        IWorkbenchGraphicConstants.IMG_ETOOL_NEW_PAGE)
+                        .createImage();
+            }
+            toolItem.setImage(image);
+
+            toolItem.setText(""); //$NON-NLS-1$
+            toolItem.setToolTipText(WorkbenchMessages.get().PerspectiveBarNewContributionItem_toolTip);
+            toolItem.addSelectionListener(new SelectionAdapter()
+            {
+                public void widgetSelected(SelectionEvent event) {
+                    
+                    menuManager.update(true);
+                    Point point = new Point(event.x, event.y);
+                    if (event.widget instanceof ToolItem) {
+                        ToolItem toolItem = (ToolItem) event.widget;
+                        Rectangle rectangle = toolItem.getBounds();
+                        point = new Point(rectangle.x, rectangle.y + rectangle.height);
+                    }
+                    Menu menu = menuManager.createContextMenu(parent);
+                    point = parent.toDisplay(point);
+                    menu.setLocation(point.x, point.y);
+                    menu.setVisible(true);
+                }
+			});
+        }
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PerspectiveExtensionReader.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PerspectiveExtensionReader.java
new file mode 100644
index 0000000..f073ed9
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PerspectiveExtensionReader.java
@@ -0,0 +1,367 @@
+/*******************************************************************************
+ * Copyright (c) 2013, 2016 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.ui.internal;
+
+import java.util.HashSet;
+import java.util.Set;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
+import org.eclipse.ui.IPageLayout;
+import org.eclipse.ui.IViewLayout;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.e4.compatibility.ModeledPageLayout;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.registry.RegistryReader;
+
+/**
+ * A strategy to read perspective extension from the registry.
+ * A pespective extension is one of a view, viewAction, perspAction,
+ * newWizardAction, or actionSet.
+ */
+public class PerspectiveExtensionReader extends RegistryReader {
+    private String targetID;
+
+	private ModeledPageLayout pageLayout;
+
+    private Set includeOnlyTags = null;
+
+    private static final String VAL_LEFT = "left";//$NON-NLS-1$
+
+    private static final String VAL_RIGHT = "right";//$NON-NLS-1$
+
+    private static final String VAL_TOP = "top";//$NON-NLS-1$
+
+    private static final String VAL_BOTTOM = "bottom";//$NON-NLS-1$
+
+    private static final String VAL_STACK = "stack";//$NON-NLS-1$
+
+	private static final String VAL_FAST = "fast";//$NON-NLS-1$
+
+	private static final String VAL_TRUE = "true";//$NON-NLS-1$
+
+    // VAL_FALSE added by dan_rubel@instantiations.com
+    // TODO: this logic is backwards... we should be checking for true, but
+    // technically this is API now...
+    private static final String VAL_FALSE = "false";//$NON-NLS-1$
+
+	private IExtensionTracker tracker;
+
+    /**
+     * PerspectiveExtensionReader constructor..
+     */
+    public PerspectiveExtensionReader() {
+        // do nothing
+    }
+
+    /**
+     * Read the view extensions within a registry.
+     *
+     * @param extensionTracker the tracker
+     * @param id the id
+     * @param out the layout
+     */
+	public void extendLayout(IExtensionTracker extensionTracker, String id, ModeledPageLayout out) {
+    	tracker = extensionTracker;
+    	targetID = id;
+        pageLayout = out;
+        // RAP [bm] namespace
+        readRegistry(Platform.getExtensionRegistry(), PlatformUI.PLUGIN_EXTENSION_NAME_SPACE,
+                IWorkbenchRegistryConstants.PL_PERSPECTIVE_EXTENSIONS);
+    }
+
+    /**
+     * Returns whether the given tag should be included.
+     */
+    private boolean includeTag(String tag) {
+        return includeOnlyTags == null || includeOnlyTags.contains(tag);
+    }
+
+    /**
+     * Process an action set.
+     */
+    private boolean processActionSet(IConfigurationElement element) {
+        String id = element.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+        if (id != null) {
+			pageLayout.addActionSet(id);
+		}
+        return true;
+    }
+
+    /**
+     * Process an extension.
+     * Assumption: Extension is for current perspective.
+     */
+    private boolean processExtension(IConfigurationElement element) {
+        IConfigurationElement[] children = element.getChildren();
+        for (IConfigurationElement child : children) {
+            String type = child.getName();
+            if (includeTag(type)) {
+                boolean result = false;
+                if (type.equals(IWorkbenchRegistryConstants.TAG_ACTION_SET)) {
+					result = processActionSet(child);
+				} else if (type.equals(IWorkbenchRegistryConstants.TAG_VIEW)) {
+					result = processView(child);
+				} else if (type.equals(IWorkbenchRegistryConstants.TAG_VIEW_SHORTCUT)) {
+					result = processViewShortcut(child);
+				} else if (type.equals(IWorkbenchRegistryConstants.TAG_NEW_WIZARD_SHORTCUT)) {
+					result = processWizardShortcut(child);
+				} else if (type.equals(IWorkbenchRegistryConstants.TAG_PERSP_SHORTCUT)) {
+					result = processPerspectiveShortcut(child);
+				} else if (type.equals(IWorkbenchRegistryConstants.TAG_SHOW_IN_PART)) {
+					result = processShowInPart(child);
+				} else if (type.equals(IWorkbenchRegistryConstants.TAG_HIDDEN_MENU_ITEM)) {
+					result = processHiddenMenuItem(child);
+				} else if (type.equals(IWorkbenchRegistryConstants.TAG_HIDDEN_TOOLBAR_ITEM)) {
+					result = processHiddenToolBarItem(child);
+				}
+                if (!result) {
+                    WorkbenchPlugin.log("Unable to process element: " + //$NON-NLS-1$
+                            type
+                            + " in perspective extension: " + //$NON-NLS-1$
+                            element.getDeclaringExtension()
+                                    .getUniqueIdentifier());
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Process a perspective shortcut
+     */
+    private boolean processPerspectiveShortcut(IConfigurationElement element) {
+        String id = element.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+        if (id != null) {
+			pageLayout.addPerspectiveShortcut(id);
+		}
+        return true;
+    }
+
+    /**
+     * Process a show in element.
+     */
+    private boolean processShowInPart(IConfigurationElement element) {
+        String id = element.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+        if (id != null) {
+			pageLayout.addShowInPart(id);
+		}
+        return true;
+    }
+
+    /**
+     * Process a hidden menu item
+     */
+    private boolean processHiddenMenuItem(IConfigurationElement element) {
+        String id = element.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+        if (id != null) {
+			pageLayout.addHiddenMenuItemId(id);
+		}
+        return true;
+    }
+
+    /**
+     * Process a hidden toolbar item
+     */
+    private boolean processHiddenToolBarItem(IConfigurationElement element) {
+        String id = element.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+        if (id != null) {
+			pageLayout.addHiddenToolBarItemId(id);
+		}
+        return true;
+    }
+
+    // processView(IConfigurationElement) modified by dan_rubel@instantiations.com
+    /**
+     * Process a view
+     */
+    private boolean processView(IConfigurationElement element) {
+        // Get id, relative, and relationship.
+        String id = element.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+        String relative = element.getAttribute(IWorkbenchRegistryConstants.ATT_RELATIVE);
+        String relationship = element.getAttribute(IWorkbenchRegistryConstants.ATT_RELATIONSHIP);
+        String ratioString = element.getAttribute(IWorkbenchRegistryConstants.ATT_RATIO);
+        boolean visible = !VAL_FALSE.equals(element.getAttribute(IWorkbenchRegistryConstants.ATT_VISIBLE));
+        String closeable = element.getAttribute(IWorkbenchRegistryConstants.ATT_CLOSEABLE);
+        String moveable = element.getAttribute(IWorkbenchRegistryConstants.ATT_MOVEABLE);
+        String standalone = element.getAttribute(IWorkbenchRegistryConstants.ATT_STANDALONE);
+        String showTitle = element.getAttribute(IWorkbenchRegistryConstants.ATT_SHOW_TITLE);
+
+        // Default to 'false'
+        String minVal = element.getAttribute(IWorkbenchRegistryConstants.ATT_MINIMIZED);
+        boolean minimized = minVal != null && VAL_TRUE.equals(minVal);
+
+        float ratio;
+
+        if (id == null) {
+            logMissingAttribute(element, IWorkbenchRegistryConstants.ATT_ID);
+            return false;
+        }
+        if (relationship == null) {
+            logMissingAttribute(element, IWorkbenchRegistryConstants.ATT_RELATIONSHIP);
+            return false;
+        }
+		if (!VAL_FAST.equals(relationship) && relative == null) {
+			logError(element,
+					"Attribute '" + IWorkbenchRegistryConstants.ATT_RELATIVE //$NON-NLS-1$
+							+ "' not defined.  This attribute is required when " //$NON-NLS-1$
+							+ IWorkbenchRegistryConstants.ATT_RELATIONSHIP + "=\"" + relationship + "\"."); //$NON-NLS-1$ //$NON-NLS-2$
+			return false;
+		}
+        // Get the ratio.
+        if (ratioString == null) {
+            // The ratio has not been specified.
+            ratio = IPageLayout.NULL_RATIO;
+        } else {
+            try {
+                ratio = new Float(ratioString).floatValue();
+            } catch (NumberFormatException e) {
+                return false;
+            }
+            // If the ratio is outside the allowable range, mark it as invalid.
+            if (ratio < IPageLayout.RATIO_MIN || ratio > IPageLayout.RATIO_MAX) {
+				ratio = IPageLayout.INVALID_RATIO;
+			}
+        }
+
+        // Get relationship details.
+        boolean stack = false;
+        int intRelation = 0;
+		boolean fast = false;
+        if (relationship.equals(VAL_LEFT)) {
+			intRelation = IPageLayout.LEFT;
+		} else if (relationship.equals(VAL_RIGHT)) {
+			intRelation = IPageLayout.RIGHT;
+		} else if (relationship.equals(VAL_TOP)) {
+			intRelation = IPageLayout.TOP;
+		} else if (relationship.equals(VAL_BOTTOM)) {
+			intRelation = IPageLayout.BOTTOM;
+		} else if (relationship.equals(VAL_STACK)) {
+			stack = true;
+		} else if (relationship.equals(VAL_FAST)) {
+			fast = true;
+		} else {
+			return false;
+		}
+
+        if (visible) {
+        	// If adding a view (not just a placeholder), remove any existing placeholder.
+        	// See bug 85948 [Perspectives] Adding register & expressions view by default to debug perspective fails
+        	pageLayout.removePlaceholder(id);
+        }
+
+        // If stack ..
+        if (stack) {
+            if (visible) {
+				pageLayout.stackView(id, relative, true);
+			} else {
+				pageLayout.stackView(id, relative, false);
+			}
+		}
+		// If the view is a fast view...
+		else if (fast) {
+			if (ratio == IPageLayout.NULL_RATIO) {
+				// The ratio has not been specified.
+				pageLayout.addFastView(id);
+			} else {
+				pageLayout.addFastView(id, ratio);
+			}
+		} else {
+
+            // The view is a regular view.
+            // If the ratio is not specified or is invalid, use the default ratio.
+            if (ratio == IPageLayout.NULL_RATIO
+                    || ratio == IPageLayout.INVALID_RATIO) {
+				ratio = IPageLayout.DEFAULT_VIEW_RATIO;
+			}
+
+            if (visible) {
+                if (VAL_TRUE.equals(standalone)) {
+                    pageLayout.addStandaloneView(id, !VAL_FALSE
+                            .equals(showTitle), intRelation, ratio, relative);
+                } else {
+                    pageLayout.addView(id, intRelation, ratio, relative, minimized);
+                }
+            } else {
+				// Fix for 99155, CGross (schtoo@schtoo.com)
+				// Adding standalone placeholder for standalone views
+				if (VAL_TRUE.equals(standalone)) {
+					pageLayout.addStandaloneViewPlaceholder(id, intRelation,
+							ratio, relative, !VAL_FALSE.equals(showTitle));
+				} else {
+					pageLayout.addPlaceholder(id, intRelation, ratio, relative);
+				}
+			}
+        }
+        IViewLayout viewLayout = pageLayout.getViewLayout(id);
+        // may be null if it's been filtered by activity
+        if (viewLayout != null) {
+			if (closeable != null) {
+				viewLayout.setCloseable(!VAL_FALSE.equals(closeable));
+			}
+			if (moveable != null) {
+				viewLayout.setMoveable(!VAL_FALSE.equals(moveable));
+			}
+		}
+
+        return true;
+    }
+
+    /**
+	 * Process a view shortcut
+	 */
+    private boolean processViewShortcut(IConfigurationElement element) {
+        String id = element.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+        if (id != null) {
+			pageLayout.addShowViewShortcut(id);
+		}
+        return true;
+    }
+
+    /**
+     * Process a wizard shortcut
+     */
+    private boolean processWizardShortcut(IConfigurationElement element) {
+        String id = element.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+        if (id != null) {
+			pageLayout.addNewWizardShortcut(id);
+		}
+        return true;
+    }
+
+    @Override
+	protected boolean readElement(IConfigurationElement element) {
+        String type = element.getName();
+        if (type.equals(IWorkbenchRegistryConstants.TAG_PERSPECTIVE_EXTENSION)) {
+            String id = element.getAttribute(IWorkbenchRegistryConstants.ATT_TARGET_ID);
+            if (targetID.equals(id) || "*".equals(id)) { //$NON-NLS-1$
+            	if (tracker != null) {
+					tracker.registerObject(element.getDeclaringExtension(), new DirtyPerspectiveMarker(id), IExtensionTracker.REF_STRONG);
+				}
+                return processExtension(element);
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Sets the tags to include.  All others are ignored.
+     *
+     * @param tags the tags to include
+     */
+    public void setIncludeOnlyTags(String[] tags) {
+        includeOnlyTags = new HashSet();
+        for (String tag : tags) {
+            includeOnlyTags.add(tag);
+        }
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PerspectiveListenerList.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PerspectiveListenerList.java
new file mode 100644
index 0000000..892bb08
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PerspectiveListenerList.java
@@ -0,0 +1,226 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.core.commands.common.EventManager;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.jface.util.SafeRunnable;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.IPerspectiveListener;
+import org.eclipse.ui.IPerspectiveListener2;
+import org.eclipse.ui.IPerspectiveListener3;
+import org.eclipse.ui.IPerspectiveListener4;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPartReference;
+import org.eclipse.ui.internal.misc.UIStats;
+
+/**
+ * Perspective listener list.
+ */
+public class PerspectiveListenerList extends EventManager {
+
+    /**
+     * PerspectiveListenerList constructor comment.
+     */
+    public PerspectiveListenerList() {
+        super();
+    }
+
+    /**
+     * Adds an IPerspectiveListener to the perspective service.
+     */
+    public void addPerspectiveListener(IPerspectiveListener l) {
+        addListenerObject(l);
+    }
+
+    /**
+     * Calls a perspective listener with associated performance event instrumentation
+     *
+     * @param runnable
+     * @param listener
+     * @param perspective
+     * @param description
+     */
+    private void fireEvent(SafeRunnable runnable, IPerspectiveListener listener, IPerspectiveDescriptor perspective, String description) {
+    	String label = null;//for debugging
+    	if (UIStats.isDebugging(UIStats.NOTIFY_PERSPECTIVE_LISTENERS)) {
+    		label = description + perspective.getId();
+    		UIStats.start(UIStats.NOTIFY_PERSPECTIVE_LISTENERS, label);
+    	}
+    	SafeRunner.run(runnable);
+    	if (UIStats.isDebugging(UIStats.NOTIFY_PERSPECTIVE_LISTENERS)) {
+			UIStats.end(UIStats.NOTIFY_PERSPECTIVE_LISTENERS, listener, label);
+		}
+	}
+
+    /**
+     * Notifies the listener that a perspective has been activated.
+     */
+    public void firePerspectiveActivated(final IWorkbenchPage page,
+            final IPerspectiveDescriptor perspective) {
+		for (Object listener : getListeners()) {
+			final IPerspectiveListener perspectiveListener = (IPerspectiveListener) listener;
+            fireEvent(new SafeRunnable() {
+                @Override
+				public void run() {
+					perspectiveListener.perspectiveActivated(page, perspective);
+                }
+			}, perspectiveListener, perspective, "activated::"); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Notifies the listener that a perspective has been deactivated.
+     *
+     * @since 3.2
+     */
+    public void firePerspectivePreDeactivate(final IWorkbenchPage page,
+            final IPerspectiveDescriptor perspective) {
+		for (Object listener : getListeners()) {
+			if (listener instanceof IPerspectiveListener4) {
+				final IPerspectiveListener4 perspectiveListener = (IPerspectiveListener4) listener;
+                fireEvent(new SafeRunnable() {
+                    @Override
+					public void run() {
+						perspectiveListener.perspectivePreDeactivate(page, perspective);
+                    }
+				}, perspectiveListener, perspective, "pre-deactivate::"); //$NON-NLS-1$
+            }
+        }
+    }
+
+    /**
+     * Notifies the listener that a perspective has been deactivated.
+     *
+     * @since 3.1
+     */
+    public void firePerspectiveDeactivated(final IWorkbenchPage page,
+            final IPerspectiveDescriptor perspective) {
+		for (Object listener : getListeners()) {
+			if (listener instanceof IPerspectiveListener3) {
+				final IPerspectiveListener3 perspectiveListener = (IPerspectiveListener3) listener;
+                fireEvent(new SafeRunnable() {
+                    @Override
+					public void run() {
+						perspectiveListener.perspectiveDeactivated(page, perspective);
+                    }
+				}, perspectiveListener, perspective, "deactivated::"); //$NON-NLS-1$
+            }
+        }
+    }
+
+    /**
+     * Notifies the listener that a perspective has been changed.
+     */
+    public void firePerspectiveChanged(final IWorkbenchPage page,
+            final IPerspectiveDescriptor perspective, final String changeId) {
+		for (Object listener : getListeners()) {
+			final IPerspectiveListener perspectiveListener = (IPerspectiveListener) listener;
+            fireEvent(new SafeRunnable() {
+                @Override
+				public void run() {
+					perspectiveListener.perspectiveChanged(page, perspective, changeId);
+                }
+			}, perspectiveListener, perspective, "changed::"); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Notifies the listener that a part has been affected
+     * in the given perspective.
+     *
+     * @since 3.0
+     */
+    public void firePerspectiveChanged(final IWorkbenchPage page,
+            final IPerspectiveDescriptor perspective,
+            final IWorkbenchPartReference partRef, final String changeId) {
+		for (Object listener : getListeners()) {
+			if (listener instanceof IPerspectiveListener2) {
+				final IPerspectiveListener2 perspectiveListener = (IPerspectiveListener2) listener;
+                fireEvent(new SafeRunnable() {
+                    @Override
+					public void run() {
+						perspectiveListener.perspectiveChanged(page, perspective, partRef,
+                                changeId);
+                    }
+				}, perspectiveListener, perspective, "changed::"); //$NON-NLS-1$
+            }
+        }
+    }
+
+    /**
+     * Notifies the listener that a perspective has been closed.
+     *
+     * @since 3.1
+     */
+    public void firePerspectiveClosed(final IWorkbenchPage page,
+            final IPerspectiveDescriptor perspective) {
+		for (Object listener : getListeners()) {
+			if (listener instanceof IPerspectiveListener3) {
+				final IPerspectiveListener3 perspectiveListener = (IPerspectiveListener3) listener;
+                fireEvent(new SafeRunnable() {
+                    @Override
+					public void run() {
+						perspectiveListener.perspectiveClosed(page, perspective);
+                    }
+				}, perspectiveListener, perspective, "closed::"); //$NON-NLS-1$
+            }
+        }
+    }
+
+    /**
+     * Notifies the listener that a perspective has been opened.
+     *
+     * @since 3.1
+     */
+    public void firePerspectiveOpened(final IWorkbenchPage page,
+            final IPerspectiveDescriptor perspective) {
+		for (Object listener : getListeners()) {
+			if (listener instanceof IPerspectiveListener3) {
+				final IPerspectiveListener3 perspectiveListener = (IPerspectiveListener3) listener;
+                fireEvent(new SafeRunnable() {
+                    @Override
+					public void run() {
+						perspectiveListener.perspectiveOpened(page, perspective);
+                    }
+				}, perspectiveListener, perspective, "opened::"); //$NON-NLS-1$
+            }
+        }
+    }
+
+    /**
+     * Notifies the listener that a perspective has been deactivated.
+     *
+     * @since 3.1
+     */
+    public void firePerspectiveSavedAs(final IWorkbenchPage page,
+            final IPerspectiveDescriptor oldPerspective,
+            final IPerspectiveDescriptor newPerspective) {
+		for (Object listener : getListeners()) {
+			if (listener instanceof IPerspectiveListener3) {
+				final IPerspectiveListener3 perspectiveListener = (IPerspectiveListener3) listener;
+                fireEvent(new SafeRunnable() {
+                    @Override
+					public void run() {
+						perspectiveListener.perspectiveSavedAs(page, oldPerspective, newPerspective);
+                    }
+				}, perspectiveListener, newPerspective, "saveAs::"); //$NON-NLS-1$
+            }
+        }
+    }
+
+    /**
+     * Removes an IPerspectiveListener from the perspective service.
+     */
+    public void removePerspectiveListener(IPerspectiveListener l) {
+        removeListenerObject(l);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PerspectiveTagger.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PerspectiveTagger.java
new file mode 100644
index 0000000..792eca4
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PerspectiveTagger.java
@@ -0,0 +1,130 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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.ui.internal;
+
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+
+import org.eclipse.e4.ui.model.application.ui.MUIElement;
+import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective;
+
+public class PerspectiveTagger {
+	/**
+	 * Alters known 3.x perspective part folders into their e4 counterparts.
+	 */
+	public static void tagPerspective(MPerspective perspective, EModelService modelService) {
+		String id = perspective.getElementId();
+		if (id == null) {
+			return;
+		}
+
+		// see bug 305557
+		if (id.equals("org.eclipse.jdt.ui.JavaPerspective")) { //$NON-NLS-1$
+			tagJavaPerspective(perspective, modelService);
+		} else if (id.equals("org.eclipse.team.cvs.ui.cvsPerspective")) { //$NON-NLS-1$
+			tagCVSPerspective(perspective, modelService);
+		} else if (id.equals("org.eclipse.team.ui.TeamSynchronizingPerspective")) { //$NON-NLS-1$
+			tagTeamPerspective(perspective, modelService);
+		} else if (id.equals("org.eclipse.debug.ui.DebugPerspective")) { //$NON-NLS-1$
+			tagDebugPerspective(perspective, modelService);
+		} else if (id.equals("org.eclipse.ui.resourcePerspective")) { //$NON-NLS-1$
+			tagResourcePerspective(perspective, modelService);
+		} else if (id.equals("org.eclipse.pde.ui.PDEPerspective")) { //$NON-NLS-1$
+			tagPluginDevelopmentPerspective(perspective, modelService);
+		}
+	}
+
+	static void tagJavaPerspective(MPerspective perspective, EModelService modelService) {
+		MUIElement element = modelService.find("left", perspective); //$NON-NLS-1$
+		if (element != null) {
+			element.getTags().add("org.eclipse.e4.primaryNavigationStack"); //$NON-NLS-1$
+		}
+
+		element = modelService.find("bottom", perspective); //$NON-NLS-1$
+		if (element != null) {
+			element.getTags().add("org.eclipse.e4.secondaryDataStack"); //$NON-NLS-1$
+		}
+
+		element = modelService.find("right", perspective); //$NON-NLS-1$
+		if (element != null) {
+			element.getTags().add("org.eclipse.e4.secondaryNavigationStack"); //$NON-NLS-1$
+		}
+	}
+
+	static void tagCVSPerspective(MPerspective perspective, EModelService modelService) {
+		MUIElement element = modelService.find("top", perspective); //$NON-NLS-1$
+		if (element != null) {
+			element.getTags().add("org.eclipse.e4.primaryNavigationStack"); //$NON-NLS-1$
+		}
+	}
+
+	static void tagTeamPerspective(MPerspective perspective, EModelService modelService) {
+		MUIElement element = modelService.find("top", perspective); //$NON-NLS-1$
+		if (element != null) {
+			element.getTags().add("org.eclipse.e4.primaryNavigationStack"); //$NON-NLS-1$
+		}
+
+		element = modelService.find("top2", perspective); //$NON-NLS-1$
+		if (element != null) {
+			element.getTags().add("org.eclipse.e4.secondaryDataStack"); //$NON-NLS-1$
+		}
+	}
+
+	static void tagDebugPerspective(MPerspective perspective, EModelService modelService) {
+		MUIElement element = modelService.find(
+				"org.eclipse.debug.internal.ui.NavigatorFolderView", perspective); //$NON-NLS-1$
+		if (element != null) {
+			element.getTags().add("org.eclipse.e4.primaryNavigationStack"); //$NON-NLS-1$
+		}
+
+		element = modelService.find(
+				"org.eclipse.debug.internal.ui.ConsoleFolderView", perspective); //$NON-NLS-1$
+		if (element != null) {
+			element.getTags().add("org.eclipse.e4.secondaryDataStack"); //$NON-NLS-1$
+		}
+
+		element = modelService.find(
+				"org.eclipse.debug.internal.ui.OutlineFolderView", perspective); //$NON-NLS-1$
+		if (element != null) {
+			element.getTags().add("org.eclipse.e4.secondaryNavigationStack"); //$NON-NLS-1$
+		}
+	}
+
+	static void tagResourcePerspective(MPerspective perspective, EModelService modelService) {
+		MUIElement element = modelService.find("topLeft", perspective); //$NON-NLS-1$
+		if (element != null) {
+			element.getTags().add("org.eclipse.e4.primaryNavigationStack"); //$NON-NLS-1$
+		}
+
+		element = modelService.find("bottomRight", perspective); //$NON-NLS-1$
+		if (element != null) {
+			element.getTags().add("org.eclipse.e4.secondaryDataStack"); //$NON-NLS-1$
+		}
+
+		element = modelService.find("bottomLeft", perspective); //$NON-NLS-1$
+		if (element != null) {
+			element.getTags().add("org.eclipse.e4.secondaryNavigationStack"); //$NON-NLS-1$
+		}
+	}
+
+	static void tagPluginDevelopmentPerspective(MPerspective perspective,
+			EModelService modelService) {
+		MUIElement element = modelService.find("topLeft", perspective); //$NON-NLS-1$
+		if (element != null) {
+			element.getTags().add("org.eclipse.e4.primaryNavigationStack"); //$NON-NLS-1$
+		}
+
+		element = modelService.find("bottomRight", perspective); //$NON-NLS-1$
+		if (element != null) {
+			element.getTags().add("org.eclipse.e4.secondaryDataStack"); //$NON-NLS-1$
+		}
+	}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PerspectiveTracker.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PerspectiveTracker.java
new file mode 100644
index 0000000..ae35acb
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PerspectiveTracker.java
@@ -0,0 +1,125 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.ui.IPageListener;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PerspectiveAdapter;
+
+/**
+ * Utility class for tracking the active perspective in a window.
+ *
+ * @since 3.1
+ */
+public class PerspectiveTracker extends PerspectiveAdapter implements
+        IPageListener {
+
+    private IWorkbenchWindow window;
+
+    private IAction action;
+
+    /**
+     * Creates a perspective tracker for the given window.
+     * Subclasses should override <code>update(IPerspectiveDescriptor)</code>
+     * to get notified of perspective changes.
+     *
+     * @param window the window to track
+     */
+    protected PerspectiveTracker(IWorkbenchWindow window) {
+        Assert.isNotNull(window);
+        this.window = window;
+        window.addPageListener(this);
+        window.addPerspectiveListener(this);
+    }
+
+    /**
+     * Creates a perspective tracker for the given window which will
+     * enable the given action only when there is an active perspective.
+     *
+     * @param window the window to track
+     * @param action the action to enable or disable
+     */
+    public PerspectiveTracker(IWorkbenchWindow window, IAction action) {
+        this(window);
+        this.action = action;
+        update();
+    }
+
+    /**
+     * Disposes the tracker.
+     */
+    public void dispose() {
+        if (window != null) {
+            window.removePageListener(this);
+            window.removePerspectiveListener(this);
+        }
+    }
+
+    @Override
+	public void pageActivated(IWorkbenchPage page) {
+        update();
+    }
+
+    @Override
+	public void pageClosed(IWorkbenchPage page) {
+        update();
+    }
+
+    @Override
+	public void pageOpened(IWorkbenchPage page) {
+        // ignore
+    }
+
+    @Override
+	public void perspectiveActivated(IWorkbenchPage page,
+            IPerspectiveDescriptor perspective) {
+        update();
+    }
+
+    /**
+     * Determines the active perspective in the window
+     * and calls <code>update(IPerspectiveDescriptor)</code>.
+     */
+    private void update() {
+        if (window != null) {
+            IPerspectiveDescriptor persp = null;
+            IWorkbenchPage page = window.getActivePage();
+            if (page != null) {
+                persp = page.getPerspective();
+            }
+            update(persp);
+        }
+    }
+
+    /**
+     * Performs some function based on the active perspective in the window.
+     * <p>
+     * The default implementation enables the action (if given) if there
+     * is an active perspective, otherwise it disables it.
+     * </p>
+     * <p>
+     * Subclasses may override or extend.
+     * </p>
+     *
+     * @param persp the active perspective in the window, or <code>null</code> if none
+     */
+    protected void update(IPerspectiveDescriptor persp) {
+        if (action != null) {
+            action.setEnabled(persp != null);
+        }
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PlaceholderContributionItem.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PlaceholderContributionItem.java
new file mode 100644
index 0000000..5d443a0
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PlaceholderContributionItem.java
@@ -0,0 +1,217 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.IContributionManager;
+import org.eclipse.jface.internal.provisional.action.IToolBarContributionItem;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.CoolBar;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.ToolBar;
+
+/**
+ * A contribution item that is intended to hold the place of a tool bar
+ * contribution item that has been disposed. This is to ensure that tool bar
+ * contribution items are disposed (freeing their resources), but that layout
+ * information about the item is not lost.
+ *
+ * @since 3.0
+ */
+final class PlaceholderContributionItem implements IContributionItem {
+
+    /**
+     * The identifier for the replaced contribution item.
+     */
+    private final String id;
+
+    /**
+     * The height of the SWT widget corresponding to the replaced contribution
+     * item.
+     */
+    private final int storedHeight;
+
+    /**
+     * The minimum number of items to display on the replaced contribution
+     * item.
+     */
+    private final int storedMinimumItems;
+
+    /**
+     * Whether the replaced contribution item would display chevrons.
+     */
+    private final boolean storedUseChevron;
+
+    /**
+     * The width of the SWT widget corresponding to the replaced contribution
+     * item.
+     */
+    private final int storedWidth;
+
+    /**
+     * Constructs a new instance of <code>PlaceholderContributionItem</code>
+     * from the item it is intended to replace.
+     *
+     * @param item
+     *            The item to be replaced; must not be <code>null</code>.
+     */
+    PlaceholderContributionItem(final IToolBarContributionItem item) {
+        item.saveWidgetState();
+        id = item.getId();
+        storedHeight = item.getCurrentHeight();
+        storedWidth = item.getCurrentWidth();
+        storedMinimumItems = item.getMinimumItemsToShow();
+        storedUseChevron = item.getUseChevron();
+    }
+
+    @Override
+	public void dispose() {
+        // Do nothing
+    }
+
+    @Override
+	public void fill(Composite parent) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+	public void fill(CoolBar parent, int index) {
+        throw new UnsupportedOperationException();
+
+    }
+
+    @Override
+	public void fill(Menu parent, int index) {
+        throw new UnsupportedOperationException();
+
+    }
+
+    @Override
+	public void fill(ToolBar parent, int index) {
+        throw new UnsupportedOperationException();
+
+    }
+
+    /**
+     * The height of the replaced contribution item.
+     *
+     * @return The height.
+     */
+    int getHeight() {
+        return storedHeight;
+    }
+
+    @Override
+	public String getId() {
+        return id;
+    }
+
+    /**
+     * The width of the replaced contribution item.
+     *
+     * @return The width.
+     */
+    int getWidth() {
+        return storedWidth;
+    }
+
+    /**
+     * Returns the minimum number of tool items to show in the cool item.
+     *
+     * @return the minimum number of tool items to show, or <code>SHOW_ALL_ITEMS</code>
+     *         if a value was not set
+     * @see #setMinimumItemsToShow(int)
+	 * @since 3.2
+     */
+    int getMinimumItemsToShow() {
+    	return storedMinimumItems;
+    }
+
+    /**
+     * Returns whether chevron support is enabled.
+     *
+     * @return <code>true</code> if chevron support is enabled, <code>false</code>
+     *         otherwise
+	 * @since 3.2
+     */
+    boolean getUseChevron() {
+        return storedUseChevron;
+    }
+
+    @Override
+	public boolean isDirty() {
+        return false;
+    }
+
+    @Override
+	public boolean isDynamic() {
+        return false;
+    }
+
+    @Override
+	public boolean isEnabled() {
+        // XXX Auto-generated method stub
+        return false;
+    }
+
+    @Override
+	public boolean isGroupMarker() {
+        return false;
+    }
+
+    @Override
+	public boolean isSeparator() {
+        return false;
+    }
+
+    @Override
+	public boolean isVisible() {
+        return false;
+    }
+
+    @Override
+	public void saveWidgetState() {
+        // Do nothing.
+
+    }
+
+    @Override
+	public void setParent(IContributionManager parent) {
+        // Do nothing
+
+    }
+
+    @Override
+	public void setVisible(boolean visible) {
+        // Do nothing.
+    }
+
+    /**
+     * Displays a string representation of this contribution item, which is
+     * really just a function of its identifier.
+     */
+    @Override
+	public String toString() {
+        return "PlaceholderContributionItem(" + id + ")"; //$NON-NLS-1$//$NON-NLS-2$
+    }
+
+    @Override
+	public void update() {
+        update(null);
+
+    }
+
+    @Override
+	public void update(String identifier) {
+        // Do nothing
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PlatformUIPreferenceListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PlatformUIPreferenceListener.java
new file mode 100644
index 0000000..ed2d4bd
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PlatformUIPreferenceListener.java
@@ -0,0 +1,197 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *      Wojciech Galanciak <wojciech.galanciak@pl.ibm.com> - Bug 236104 [EditorMgmt] File association default needs to be set twice to take effect
+ *      Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ *******************************************************************************/
+package org.eclipse.ui.internal;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.HashMap;
+
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.util.OpenStrategy;
+import org.eclipse.ui.IEditorDescriptor;
+import org.eclipse.ui.IEditorRegistry;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferenceConstants;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.WorkbenchException;
+import org.eclipse.ui.internal.decorators.DecoratorManager;
+import org.eclipse.ui.internal.progress.ProgressManager;
+import org.eclipse.ui.internal.registry.EditorRegistry;
+import org.eclipse.ui.internal.util.PrefUtil;
+
+/**
+ * The PlatformUIPreferenceListener is a class that listens to changes in the
+ * preference store and propogates the change for any special cases that require
+ * updating of other values within the workbench.
+ */
+public class PlatformUIPreferenceListener implements
+		IEclipsePreferences.IPreferenceChangeListener {
+
+	private static PlatformUIPreferenceListener singleton;
+
+	public static IEclipsePreferences.IPreferenceChangeListener getSingleton(){
+		if(singleton == null) {
+			singleton = new PlatformUIPreferenceListener();
+		}
+	    return singleton;
+	}
+
+	@Override
+	public void preferenceChange(PreferenceChangeEvent event) {
+
+		String propertyName = event.getKey();
+		if (IPreferenceConstants.ENABLED_DECORATORS.equals(propertyName)) {
+			DecoratorManager manager = WorkbenchPlugin.getDefault()
+					.getDecoratorManager();
+			manager.applyDecoratorsPreference();
+			manager.clearCaches();
+			manager.updateForEnablementChange();
+			return;
+		}
+
+		if (IWorkbenchPreferenceConstants.SHOW_SYSTEM_JOBS.equals(propertyName)) {
+			boolean setting = PrefUtil.getAPIPreferenceStore().getBoolean(
+					IWorkbenchPreferenceConstants.SHOW_SYSTEM_JOBS);
+
+			ProgressManager.getInstance().setShowSystemJobs(setting);
+		}
+
+		if (IWorkbenchPreferenceConstants.DEFAULT_PERSPECTIVE_ID.equals(propertyName)) {
+			IWorkbench workbench = PlatformUI.getWorkbench();
+
+			workbench.getPerspectiveRegistry().setDefaultPerspective(
+					PrefUtil.getAPIPreferenceStore().getString(
+							IWorkbenchPreferenceConstants.DEFAULT_PERSPECTIVE_ID));
+			return;
+		}
+
+		if (IWorkbenchPreferenceConstants.DOCK_PERSPECTIVE_BAR
+				.equals(propertyName)) {
+			// IPreferenceStore apiStore = PrefUtil.getAPIPreferenceStore();
+			IWorkbench workbench = PlatformUI.getWorkbench();
+			for (IWorkbenchWindow window : workbench.getWorkbenchWindows()) {
+				if (window instanceof WorkbenchWindow) {
+					// ((WorkbenchWindow) window)
+					// .setPerspectiveBarLocation(apiStore
+					// .getString(IWorkbenchPreferenceConstants.DOCK_PERSPECTIVE_BAR));
+				}
+			}
+			return;
+		}
+
+		// TODO the banner apperance should have its own preference
+		// RAP [bm]: no styled tabs
+//		if (IWorkbenchPreferenceConstants.SHOW_TRADITIONAL_STYLE_TABS
+//				.equals(propertyName)) {
+//			// boolean newValue = PrefUtil.getAPIPreferenceStore().getBoolean(
+//			// IWorkbenchPreferenceConstants.SHOW_TRADITIONAL_STYLE_TABS);
+//
+//			IWorkbench workbench = PlatformUI.getWorkbench();
+//			for (IWorkbenchWindow window : workbench.getWorkbenchWindows()) {
+//				if (window instanceof WorkbenchWindow) {
+//					// ((WorkbenchWindow) window).setBannerCurve(newValue);
+//				}
+//			}
+//			return;
+//		}
+		// RAPEND: [bm]
+
+		// Update the file associations if they have changed due to an import
+		if (IPreferenceConstants.RESOURCES.equals(propertyName)) {
+			IEditorRegistry registry = WorkbenchPlugin.getDefault()
+					.getEditorRegistry();
+			if (registry instanceof EditorRegistry) {
+				EditorRegistry editorRegistry = (EditorRegistry) registry;
+				IPreferenceStore store = WorkbenchPlugin.getDefault()
+						.getPreferenceStore();
+				Reader reader = null;
+				try {
+					String xmlString = store
+							.getString(IPreferenceConstants.RESOURCES);
+					if (xmlString != null && xmlString.length() > 0) {
+						reader = new StringReader(xmlString);
+						// Build the editor map.
+						HashMap<String, IEditorDescriptor> editorMap = new HashMap<>();
+						int i = 0;
+						IEditorDescriptor[] descriptors = editorRegistry
+								.getSortedEditorsFromPlugins();
+						// Get the internal editors
+						for (i = 0; i < descriptors.length; i++) {
+							IEditorDescriptor descriptor = descriptors[i];
+							editorMap.put(descriptor.getId(), descriptor);
+						}
+						// RAP [rh] external editors not supported
+//						// Get the external (OS) editors
+//						descriptors = editorRegistry.getSortedEditorsFromOS();
+//						for (i = 0; i < descriptors.length; i++) {
+//							IEditorDescriptor descriptor = descriptors[i];
+//							editorMap.put(descriptor.getId(), descriptor);
+//						}
+//						// Get default editors which are not OS or internal
+//						// editors
+//						for (IFileEditorMapping fileEditorMapping : editorRegistry.getFileEditorMappings()) {
+//							IEditorDescriptor descriptor = fileEditorMapping.getDefaultEditor();
+//							if (descriptor != null && !editorMap.containsKey(descriptor.getId())) {
+//								editorMap.put(descriptor.getId(), descriptor);
+//							}
+//						}
+						// Update the file to editor(s) mappings
+						editorRegistry.readResources(editorMap, reader);
+					}
+				} catch (WorkbenchException e) {
+					WorkbenchPlugin.log(e);
+				} finally {
+					if (reader != null) {
+						try {
+							reader.close();
+						} catch (IOException e) {
+							WorkbenchPlugin.log(e);
+						}
+					}
+				}
+			}
+		}
+
+		// Set Open mode
+		if (IPreferenceConstants.OPEN_ON_SINGLE_CLICK.equals(propertyName)
+				|| IPreferenceConstants.SELECT_ON_HOVER.equals(propertyName)
+				|| IPreferenceConstants.OPEN_AFTER_DELAY.equals(propertyName)
+				|| IPreferenceConstants.SELECT_ON_HOVER.equals(propertyName)) {
+			initializeSingleClickOption();
+		}
+
+	}
+
+	private static void initializeSingleClickOption() {
+		IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore();
+		boolean openOnSingleClick = store.getBoolean(IPreferenceConstants.OPEN_ON_SINGLE_CLICK);
+		boolean selectOnHover = store.getBoolean(IPreferenceConstants.SELECT_ON_HOVER);
+		boolean openAfterDelay = store.getBoolean(IPreferenceConstants.OPEN_AFTER_DELAY);
+		int singleClickMethod = openOnSingleClick ? OpenStrategy.SINGLE_CLICK
+				: OpenStrategy.DOUBLE_CLICK;
+		if (openOnSingleClick) {
+			if (selectOnHover) {
+				singleClickMethod |= OpenStrategy.SELECT_ON_HOVER;
+			}
+			if (openAfterDelay) {
+				singleClickMethod |= OpenStrategy.ARROW_KEYS_OPEN;
+			}
+		}
+		OpenStrategy.setOpenMethod(singleClickMethod);
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PluginAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PluginAction.java
new file mode 100644
index 0000000..41c590b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PluginAction.java
@@ -0,0 +1,376 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IMenuCreator;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.ui.IActionDelegate;
+import org.eclipse.ui.IActionDelegate2;
+import org.eclipse.ui.IActionDelegateWithEvent;
+import org.eclipse.ui.INullSelectionListener;
+import org.eclipse.ui.IPluginContribution;
+import org.eclipse.ui.ISelectionListener;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindowActionDelegate;
+import org.eclipse.ui.SelectionEnabler;
+import org.eclipse.ui.WorkbenchException;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.util.BundleUtility;
+import org.eclipse.ui.internal.util.Util;
+
+/**
+ * A PluginAction is a proxy for an action extension.
+ *
+ * At startup we read the registry and create a PluginAction for each action extension.
+ * This plugin action looks like the real action ( label, icon, etc ) and acts as
+ * a proxy for the action until invoked.  At that point the proxy will instantiate
+ * the real action and delegate the run method to the real action.
+ * This makes it possible to load the action extension lazily.
+ *
+ * Occasionally the class will ask if it is OK to
+ * load the delegate (on selection changes).  If the plugin containing
+ * the action extension has been loaded then the action extension itself
+ * will be instantiated.
+ */
+
+public abstract class PluginAction extends Action implements
+        ISelectionListener, ISelectionChangedListener, INullSelectionListener,
+        IPluginContribution {
+    private IActionDelegate delegate;
+
+    private SelectionEnabler enabler;
+
+    private ISelection selection;
+
+    private IConfigurationElement configElement;
+
+    private String pluginId;
+
+    private String runAttribute = IWorkbenchRegistryConstants.ATT_CLASS;
+
+    private static int actionCount = 0;
+
+    /**
+     * PluginAction constructor.
+     *
+     * @param actionElement the element
+     * @param id the identifier
+     * @param style the style bits
+     */
+    public PluginAction(IConfigurationElement actionElement, String id,
+            int style) {
+        super(null, style);
+
+        this.configElement = actionElement;
+
+        if (id != null) {
+            setId(id);
+        } else {
+            // Create unique action id.
+            setId("PluginAction." + Integer.toString(actionCount)); //$NON-NLS-1$
+            ++actionCount;
+        }
+
+        String defId = actionElement
+                .getAttribute(IWorkbenchRegistryConstants.ATT_DEFINITION_ID);
+        setActionDefinitionId(defId);
+
+        pluginId = configElement.getNamespace();
+
+        // Read enablement declaration.
+        if (configElement.getAttribute(IWorkbenchRegistryConstants.ATT_ENABLES_FOR) != null) {
+            enabler = new SelectionEnabler(configElement);
+        } else {
+			IConfigurationElement[] kids = configElement
+					.getChildren(IWorkbenchRegistryConstants.TAG_ENABLEMENT);
+			IConfigurationElement[] kids2 = configElement
+					.getChildren(IWorkbenchRegistryConstants.TAG_SELECTION);
+			if (kids.length > 0 || kids2.length>0) {
+				enabler = new SelectionEnabler(configElement);
+			}
+		}
+
+        // Give enabler or delegate a chance to adjust enable state
+        selectionChanged(StructuredSelection.EMPTY);
+    }
+
+    /**
+     * Creates the delegate and refreshes its enablement.
+     */
+    protected final void createDelegate() {
+        // The runAttribute is null if delegate creation failed previously...
+        if (delegate == null && runAttribute != null) {
+            try {
+                Object obj = WorkbenchPlugin.createExtension(configElement,
+                        runAttribute);
+                delegate = validateDelegate(obj);
+                initDelegate();
+                refreshEnablement();
+            } catch (Throwable e) {
+                runAttribute = null;
+                IStatus status = null;
+                if (e instanceof CoreException) {
+                    status = ((CoreException) e).getStatus();
+                } else {
+                    status = StatusUtil
+                            .newStatus(
+                                    IStatus.ERROR,
+                                    "Internal plug-in action delegate error on creation.", e); //$NON-NLS-1$
+                }
+                String id = configElement.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+                WorkbenchPlugin
+                        .log(
+                                "Could not create action delegate for id: " + id, status); //$NON-NLS-1$
+                return;
+            }
+        }
+    }
+
+    /**
+     * Validates the object is a delegate of the expected type. Subclasses can
+     * override to check for specific delegate types.
+     * <p>
+     * <b>Note:</b> Calls to the object are not allowed during this method.
+     * </p>
+     *
+     * @param obj a possible action delegate implementation
+     * @return the <code>IActionDelegate</code> implementation for the object
+     * @throws WorkbenchException if not of the expected delegate type
+     */
+    protected IActionDelegate validateDelegate(Object obj)
+            throws WorkbenchException {
+        if (obj instanceof IActionDelegate) {
+			return (IActionDelegate) obj;
+		}
+
+        throw new WorkbenchException(
+                "Action must implement IActionDelegate"); //$NON-NLS-1$
+    }
+
+    /**
+     * Initialize the action delegate by calling its lifecycle method.
+     * Subclasses may override but must call this implementation first.
+     */
+    protected void initDelegate() {
+        if (delegate instanceof IActionDelegate2) {
+			((IActionDelegate2) delegate).init(this);
+		}
+    }
+
+    /**
+     * Returns the action delegate if created. Can be <code>null</code>
+     * if the delegate is not created yet or if previous delegate
+     * creation failed.
+     */
+    protected IActionDelegate getDelegate() {
+        return delegate;
+    }
+
+    /**
+     * Returns true if the declaring plugin has been loaded
+     * and there is no need to delay creating the delegate
+     * any more.
+     */
+    protected boolean isOkToCreateDelegate() {
+        // test if the plugin has loaded
+        String bundleId = configElement.getContributor().getName();
+        return BundleUtility.isActive(bundleId);
+    }
+
+    /**
+     * Refresh the action enablement.
+     */
+    protected void refreshEnablement() {
+        if (enabler != null) {
+            setEnabled(enabler.isEnabledForSelection(selection));
+        }
+        if (delegate != null) {
+            delegate.selectionChanged(this, selection);
+        }
+    }
+
+    @Override
+	public void run() {
+        runWithEvent(null);
+    }
+
+    @Override
+	public void runWithEvent(Event event) {
+        // this message dialog is problematic.
+        if (delegate == null) {
+            createDelegate();
+            if (delegate == null) {
+                MessageDialog
+                        .openInformation(
+                                Util.getShellToParentOn(),
+                                WorkbenchMessages.get().Information,
+                                WorkbenchMessages.get().PluginAction_operationNotAvailableMessage);
+                return;
+            }
+            if (!isEnabled()) {
+                MessageDialog.openInformation(Util.getShellToParentOn(), WorkbenchMessages.get().Information,
+                        WorkbenchMessages.get().PluginAction_disabledMessage);
+                return;
+            }
+        }
+
+        if (event != null) {
+            if (delegate instanceof IActionDelegate2) {
+                ((IActionDelegate2) delegate).runWithEvent(this, event);
+                return;
+            }
+            // Keep for backward compatibility with R2.0
+            if (delegate instanceof IActionDelegateWithEvent) {
+                ((IActionDelegateWithEvent) delegate).runWithEvent(this, event);
+                return;
+            }
+        }
+
+        delegate.run(this);
+    }
+
+    /**
+     * Handles selection change. If rule-based enabled is
+     * defined, it will be first to call it. If the delegate
+     * is loaded, it will also be given a chance.
+     *
+     * @param newSelection the new selection
+     */
+    public void selectionChanged(ISelection newSelection) {
+        // Update selection.
+        selection = newSelection;
+        if (selection == null) {
+			selection = StructuredSelection.EMPTY;
+		}
+
+        // The selection is passed to the delegate as-is without
+        // modification. If the selection needs to be modified
+        // the action contributors should do so.
+
+        // If the delegate can be loaded, do so.
+        // Otherwise, just update the enablement.
+        if (delegate == null && isOkToCreateDelegate()) {
+			createDelegate();
+		} else {
+			refreshEnablement();
+		}
+    }
+
+    /**
+     * The <code>SelectionChangedEventAction</code> implementation of this
+     * <code>ISelectionChangedListener</code> method calls
+     * <code>selectionChanged(IStructuredSelection)</code> when the selection is
+     * a structured one.
+     */
+    @Override
+	public void selectionChanged(SelectionChangedEvent event) {
+        ISelection sel = event.getSelection();
+        selectionChanged(sel);
+    }
+
+    /**
+     * The <code>SelectionChangedEventAction</code> implementation of this
+     * <code>ISelectionListener</code> method calls
+     * <code>selectionChanged(IStructuredSelection)</code> when the selection is
+     * a structured one. Subclasses may extend this method to react to the change.
+     */
+    @Override
+	public void selectionChanged(IWorkbenchPart part, ISelection sel) {
+        selectionChanged(sel);
+    }
+
+    /**
+     * For testing purposes only.
+     *
+     * @return the selection
+     * @since 3.1
+     */
+    public ISelection getSelection() {
+    	return selection;
+    }
+
+    /**
+     * Returns the action identifier this action overrides.
+     * Default implementation returns <code>null</code>.
+     *
+     * @return the action identifier to override or <code>null</code>
+     */
+    public String getOverrideActionId() {
+        return null;
+    }
+
+    /**
+     * @return the IConfigurationElement used to create this PluginAction.
+     *
+     * @since 3.0
+     */
+    protected IConfigurationElement getConfigElement() {
+        return configElement;
+    }
+
+    @Override
+	public String getLocalId() {
+        return getId();
+    }
+
+    @Override
+	public String getPluginId() {
+        return pluginId;
+    }
+
+    /**
+     * Disposes the delegate, if created.
+     *
+     * @since 3.1
+     */
+    public void disposeDelegate() {
+        // avoid calling dispose() twice if the delegate implements
+        // both IActionDelegate2 and IWorkbenchWindowActionDelegate
+        if (getDelegate() instanceof IActionDelegate2) {
+            ((IActionDelegate2) getDelegate()).dispose();
+        }
+        else if (getDelegate() instanceof IWorkbenchWindowActionDelegate) {
+            ((IWorkbenchWindowActionDelegate) getDelegate()).dispose();
+        }
+        delegate = null;
+    }
+
+    /**
+     * Disposes this plugin action.
+     *
+     * @since 3.1
+     */
+    public void dispose() {
+        disposeDelegate();
+        selection = null;
+    }
+
+    @Override
+	public IMenuCreator getMenuCreator() {
+    	// now that action contribution item defers asking for the menu
+    	// creator until its ready o show the menu, asking for the menu
+    	// creator is time to instantiate the delegate
+    	if (getDelegate()==null) {
+    		createDelegate();
+    	}
+    	return super.getMenuCreator();
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PluginActionBuilder.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PluginActionBuilder.java
new file mode 100644
index 0000000..483bcad
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PluginActionBuilder.java
@@ -0,0 +1,556 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Remy Chi Jian Suen <remy.suen@gmail.com> - Bug 43573 [Contributions] Support icon in <menu>
+ *******************************************************************************/
+package org.eclipse.ui.internal;
+
+import java.util.ArrayList;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.action.AbstractGroupMarker;
+import org.eclipse.jface.action.GroupMarker;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.IContributionManager;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.IWorkbenchActionConstants;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.registry.RegistryReader;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+/**
+ * This class contains shared functionality for reading action contributions
+ * from plugins into workbench parts (both editors and views).
+ */
+public abstract class PluginActionBuilder extends RegistryReader {
+    protected String targetID;
+
+    protected String targetContributionTag;
+
+    protected BasicContribution currentContribution;
+
+	protected ArrayList cache;
+
+    /**
+     * The default constructor.
+     */
+    public PluginActionBuilder() {
+    }
+
+    /**
+     * Contributes submenus and/or actions into the provided menu and tool bar
+     * managers.
+     *
+     * @param menu the menu to contribute to
+     * @param toolbar the toolbar to contribute to
+     * @param appendIfMissing append containers if missing
+     */
+    public final void contribute(IMenuManager menu, IToolBarManager toolbar,
+            boolean appendIfMissing) {
+        if (cache == null) {
+			return;
+		}
+
+        for (int i = 0; i < cache.size(); i++) {
+			BasicContribution contribution = (BasicContribution) cache.get(i);
+            contribution.contribute(menu, appendIfMissing, toolbar,
+                    appendIfMissing);
+        }
+    }
+
+    /**
+     * This factory method returns a new ActionDescriptor for the
+     * configuration element.  It should be implemented by subclasses.
+     */
+    protected abstract ActionDescriptor createActionDescriptor(
+            IConfigurationElement element);
+
+    /**
+     * Factory method to create the helper contribution class that will hold
+     * onto the menus and actions contributed.
+     */
+    protected BasicContribution createContribution() {
+        return new BasicContribution();
+    }
+
+    /**
+     * Returns the name of the part ID attribute that is expected
+     * in the target extension.
+     */
+    protected String getTargetID(IConfigurationElement element) {
+        String value = element.getAttribute(IWorkbenchRegistryConstants.ATT_TARGET_ID);
+        return value != null ? value : "???"; //$NON-NLS-1$
+    }
+
+    /**
+     * Returns the id of this contributions.
+     */
+    protected String getID(IConfigurationElement element) {
+        String value = element.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+        return value != null ? value : "???"; //$NON-NLS-1$
+    }
+
+    /**
+     * Reads the contributions from the registry for the provided workbench
+     * part and the provided extension point ID.
+     */
+    protected void readContributions(String id, String tag,
+            String extensionPoint) {
+        cache = null;
+        currentContribution = null;
+        targetID = id;
+        targetContributionTag = tag;
+        // RAP [bm]: 
+//      readRegistry(Platform.getExtensionRegistry(), PlatformUI.PLUGIN_ID,
+//              extensionPoint);
+      readRegistry(Platform.getExtensionRegistry(), PlatformUI.PLUGIN_EXTENSION_NAME_SPACE,
+              extensionPoint);
+      // RAPEND: [bm] 
+    }
+
+    /**
+     * Implements abstract method to handle the provided XML element
+     * in the registry.
+     */
+    @Override
+	protected boolean readElement(IConfigurationElement element) {
+        String tag = element.getName();
+
+        // Ignore all object contributions element as these
+        // are handled by the ObjectActionContributorReader.
+        if (tag.equals(IWorkbenchRegistryConstants.TAG_OBJECT_CONTRIBUTION)) {
+            return true;
+        }
+
+        // Found top level contribution element
+        if (tag.equals(targetContributionTag)) {
+            if (targetID != null) {
+                // Ignore contributions not matching target id
+                String id = getTargetID(element);
+                if (id == null || !id.equals(targetID)) {
+					return true;
+				}
+            }
+
+            // Read its sub-elements
+            currentContribution = createContribution();
+            readElementChildren(element);
+            if (cache == null) {
+				cache = new ArrayList(4);
+			}
+            cache.add(currentContribution);
+            currentContribution = null;
+            return true;
+        }
+
+        // Found menu contribution sub-element
+        if (tag.equals(IWorkbenchRegistryConstants.TAG_MENU)) {
+            currentContribution.addMenu(element);
+            return true;
+        }
+
+        // Found action contribution sub-element
+        if (tag.equals(IWorkbenchRegistryConstants.TAG_ACTION)) {
+            currentContribution.addAction(createActionDescriptor(element));
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Helper class to collect the menus and actions defined within a
+     * contribution element.
+     */
+    protected static class BasicContribution {
+		protected ArrayList menus;
+
+		protected ArrayList actions;
+
+        /**
+         * Add a menu.
+         *
+         * @param element the element to base the menu on
+         */
+        public void addMenu(IConfigurationElement element) {
+            if (menus == null) {
+				menus = new ArrayList(1);
+			}
+            menus.add(element);
+        }
+
+        /**
+         * Add an action.
+         *
+         * @param desc the descriptor
+         */
+        public void addAction(ActionDescriptor desc) {
+            if (actions == null) {
+				actions = new ArrayList(3);
+			}
+            actions.add(desc);
+        }
+
+        /**
+         * Contributes submenus and/or actions into the provided menu and tool bar
+         * managers.
+         *
+         * The elements added are filtered based on activity enablement.
+         * @param menu the menu to contribute to
+         * @param menuAppendIfMissing whether to append missing groups to menus
+         * @param toolbar the toolbar to contribute to
+         * @param toolAppendIfMissing whether to append missing groups to toolbars
+         */
+        public void contribute(IMenuManager menu, boolean menuAppendIfMissing,
+                IToolBarManager toolbar, boolean toolAppendIfMissing) {
+            if (menus != null && menu != null) {
+                for (int i = 0; i < menus.size(); i++) {
+					IConfigurationElement menuElement = (IConfigurationElement) menus
+                            .get(i);
+                    contributeMenu(menuElement, menu, menuAppendIfMissing);
+                }
+            }
+
+            if (actions != null) {
+                for (int i = 0; i < actions.size(); i++) {
+					ActionDescriptor ad = (ActionDescriptor) actions.get(i);
+                    if (menu != null) {
+						contributeMenuAction(ad, menu, menuAppendIfMissing);
+					}
+                    if (toolbar != null) {
+						contributeToolbarAction(ad, toolbar,
+                                toolAppendIfMissing);
+					}
+                }
+            }
+        }
+
+        /**
+         * Creates a menu from the information in the menu configuration element and
+         * adds it into the provided menu manager. If 'appendIfMissing' is true, and
+         * menu path slot is not found, it will be created and menu will be added
+         * into it. Otherwise, add operation will fail.
+         */
+        protected void contributeMenu(IConfigurationElement menuElement,
+                IMenuManager mng, boolean appendIfMissing) {
+            // Get config data.
+            String id = menuElement.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+            String label = menuElement.getAttribute(IWorkbenchRegistryConstants.ATT_LABEL);
+            String path = menuElement.getAttribute(IWorkbenchRegistryConstants.ATT_PATH);
+            String icon = menuElement.getAttribute(IWorkbenchRegistryConstants.ATT_ICON);
+            ImageDescriptor image = null;
+            if (icon != null) {
+            	String extendingPluginId = menuElement.getDeclaringExtension()
+						.getContributor().getName();
+				image = AbstractUIPlugin.imageDescriptorFromPlugin(
+						extendingPluginId, icon);
+			}
+            if (label == null) {
+				WorkbenchPlugin.log("Plugin \'" //$NON-NLS-1$
+						+ menuElement.getContributor().getName()
+						+ "\' invalid Menu Extension (label == null): " + id); //$NON-NLS-1$
+				return;
+			}
+
+            // Calculate menu path and group.
+            String group = null;
+            if (path != null) {
+                int loc = path.lastIndexOf('/');
+                if (loc != -1) {
+                    group = path.substring(loc + 1);
+                    path = path.substring(0, loc);
+                } else {
+                    // assume that path represents a slot
+                    // so actual path portion should be null
+                    group = path;
+                    path = null;
+                }
+            }
+
+            // Find parent menu.
+            IMenuManager parent = mng;
+            if (path != null) {
+                parent = mng.findMenuUsingPath(path);
+                if (parent == null) {
+					ideLog("Plugin \'" //$NON-NLS-1$
+									+ menuElement.getContributor().getName()
+									+ "\' invalid Menu Extension (Path \'"  //$NON-NLS-1$
+									+ path + "\' is invalid): " + id); //$NON-NLS-1$
+					return;
+				}
+            }
+
+            // Find reference group.
+            if (group == null) {
+				group = IWorkbenchActionConstants.MB_ADDITIONS;
+			}
+            IContributionItem sep = parent.find(group);
+            if (sep == null) {
+                if (appendIfMissing) {
+					addGroup(parent, group);
+				} else {
+                    WorkbenchPlugin
+                            .log("Plugin \'" //$NON-NLS-1$
+									+ menuElement.getContributor().getName()
+									+ "\' invalid Menu Extension (Group \'"  //$NON-NLS-1$
+									+ group + "\' is invalid): " + id); //$NON-NLS-1$
+                    return;
+                }
+            }
+
+            // If the menu does not exist create it.
+            IMenuManager newMenu = parent.findMenuUsingPath(id);
+            if (newMenu == null) {
+				newMenu = new MenuManager(label, image, id);
+			}
+
+            // Add the menu
+			try {
+                insertAfter(parent, group, newMenu);
+            } catch (IllegalArgumentException e) {
+                WorkbenchPlugin
+                        .log("Plugin \'" //$NON-NLS-1$
+								+ menuElement.getContributor().getName()
+								+ "\' invalid Menu Extension (Group \'"  //$NON-NLS-1$
+								+ group + "\' is missing): " + id); //$NON-NLS-1$
+            }
+
+            // Get the menu again as it may be wrapped, otherwise adding
+            // the separators and group markers below will not be wrapped
+            // properly if the menu was just created.
+            newMenu = parent.findMenuUsingPath(id);
+            if (newMenu == null) {
+				WorkbenchPlugin.log("Could not find new menu: " + id); //$NON-NLS-1$
+			}
+
+            // Create separators.
+            IConfigurationElement[] children = menuElement.getChildren();
+            for (IConfigurationElement element : children) {
+                String childName = element.getName();
+                if (childName.equals(IWorkbenchRegistryConstants.TAG_SEPARATOR)) {
+                    contributeSeparator(newMenu, element);
+                } else if (childName.equals(IWorkbenchRegistryConstants.TAG_GROUP_MARKER)) {
+                    contributeGroupMarker(newMenu, element);
+                }
+            }
+        }
+
+        /**
+         * Contributes action from action descriptor into the provided menu manager.
+         */
+        protected void contributeMenuAction(ActionDescriptor ad,
+                IMenuManager menu, boolean appendIfMissing) {
+            // Get config data.
+            String mpath = ad.getMenuPath();
+            String mgroup = ad.getMenuGroup();
+            if (mpath == null && mgroup == null) {
+				return;
+			}
+            // Find parent menu.
+            IMenuManager parent = menu;
+            if (mpath != null) {
+                parent = parent.findMenuUsingPath(mpath);
+                if (parent == null) {
+                    ideLog("Plug-in '" + ad.getPluginId() + "' contributed an invalid Menu Extension (Path: '" + mpath + "' is invalid): " + ad.getId()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+                    return;
+                }
+            }
+
+            // Find reference group.
+            if (mgroup == null) {
+				mgroup = IWorkbenchActionConstants.MB_ADDITIONS;
+			}
+            IContributionItem sep = parent.find(mgroup);
+            if (sep == null) {
+                if (appendIfMissing) {
+					addGroup(parent, mgroup);
+				} else {
+                    WorkbenchPlugin
+                            .log("Plug-in '" + ad.getPluginId() + "' contributed an invalid Menu Extension (Group: '" + mgroup + "' is invalid): " + ad.getId()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+                    return;
+                }
+            }
+
+            // Add action.
+            try {
+                insertAfter(parent, mgroup, ad);
+            } catch (IllegalArgumentException e) {
+                WorkbenchPlugin
+                        .log("Plug-in '" + ad.getPluginId() + "' contributed an invalid Menu Extension (Group: '" + mgroup + "' is missing): " + ad.getId()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+            }
+        }
+
+        /**
+         * Creates a named menu separator from the information in the configuration element.
+         * If the separator already exists do not create a second.
+         */
+        protected void contributeSeparator(IMenuManager menu,
+                IConfigurationElement element) {
+            String id = element.getAttribute(IWorkbenchRegistryConstants.ATT_NAME);
+            if (id == null || id.length() <= 0) {
+				return;
+			}
+            IContributionItem sep = menu.find(id);
+            if (sep != null) {
+				return;
+			}
+            insertMenuGroup(menu, new Separator(id));
+        }
+
+        /**
+         * Creates a named menu group marker from the information in the configuration element.
+         * If the marker already exists do not create a second.
+         */
+        protected void contributeGroupMarker(IMenuManager menu,
+                IConfigurationElement element) {
+            String id = element.getAttribute(IWorkbenchRegistryConstants.ATT_NAME);
+            if (id == null || id.length() <= 0) {
+				return;
+			}
+            IContributionItem marker = menu.find(id);
+            if (marker != null) {
+				return;
+			}
+            insertMenuGroup(menu, new GroupMarker(id));
+        }
+
+        /**
+         * Contributes action from the action descriptor into the provided tool bar manager.
+         */
+        protected void contributeToolbarAction(ActionDescriptor ad,
+                IToolBarManager toolbar, boolean appendIfMissing) {
+            // Get config data.
+            String tId = ad.getToolbarId();
+            String tgroup = ad.getToolbarGroupId();
+            if (tId == null && tgroup == null) {
+				return;
+			}
+
+            // Find reference group.
+            if (tgroup == null) {
+				tgroup = IWorkbenchActionConstants.MB_ADDITIONS;
+			}
+            IContributionItem sep = null;
+            sep = toolbar.find(tgroup);
+            if (sep == null) {
+                if (appendIfMissing) {
+                    addGroup(toolbar, tgroup);
+                } else {
+                    WorkbenchPlugin
+                            .log("Plug-in '" + ad.getPluginId()  //$NON-NLS-1$
+                            		+ "' invalid Toolbar Extension (Group \'" //$NON-NLS-1$
+                            		+ tgroup + "\' is invalid): " + ad.getId()); //$NON-NLS-1$
+                    return;
+                }
+            }
+            // Add action to tool bar.
+            try {
+                insertAfter(toolbar, tgroup, ad);
+            } catch (IllegalArgumentException e) {
+                WorkbenchPlugin
+                        .log("Plug-in '" + ad.getPluginId()  //$NON-NLS-1$
+                        		+ "' invalid Toolbar Extension (Group \'" //$NON-NLS-1$
+                        		+ tgroup + "\' is missing): " + ad.getId()); //$NON-NLS-1$
+            }
+        }
+
+        /**
+         * Inserts the separator or group marker into the menu. Subclasses may override.
+         */
+        protected void insertMenuGroup(IMenuManager menu,
+                AbstractGroupMarker marker) {
+            menu.add(marker);
+        }
+
+        /**
+         * Inserts an action after another named contribution item.
+         * Subclasses may override.
+         */
+        protected void insertAfter(IContributionManager mgr, String refId,
+                ActionDescriptor desc) {
+            final PluginActionContributionItem item = new PluginActionContributionItem(desc.getAction());
+            item.setMode(desc.getMode());
+			insertAfter(mgr, refId, item);
+        }
+
+        /**
+         * Inserts a contribution item after another named contribution item.
+         * Subclasses may override.
+         */
+        protected void insertAfter(IContributionManager mgr, String refId,
+                IContributionItem item) {
+            mgr.insertAfter(refId, item);
+        }
+
+        /**
+         * Adds a group to a contribution manager.
+         * Subclasses may override.
+         */
+        protected void addGroup(IContributionManager mgr, String name) {
+            mgr.add(new Separator(name));
+        }
+
+		/**
+		 * Disposes this contribution.
+		 *
+		 * @since 3.1
+		 */
+		public void dispose() {
+			// do nothing
+		}
+
+		/**
+		 * Disposes the actions.
+		 *
+		 * @since 3.1
+		 */
+		protected void disposeActions() {
+            if (actions != null) {
+                for (int i = 0; i < actions.size(); i++) {
+					PluginAction proxy = ((ActionDescriptor) actions.get(i))
+                            .getAction();
+					proxy.dispose();
+                }
+				actions = null;
+            }
+		}
+    }
+
+    private static boolean allowIdeLogging = false;
+
+    /**
+	 * If set to <code>false</code>, some of the logs that can be caused by
+	 * use IDE plugins from an RCP app will be ignored.
+	 *
+	 * @param b
+	 *            Log the errors or not.
+	 * @since 3.3
+	 */
+    public static void setAllowIdeLogging(boolean b) {
+    	allowIdeLogging = b;
+    }
+
+    /**
+	 * These are log messages that should be ignored by RCP apps when using the
+	 * IDE plugins.
+	 *
+	 * @param msg
+	 * @since 3.3
+	 */
+    private static void ideLog(String msg) {
+    	if (allowIdeLogging) {
+    		WorkbenchPlugin.log(msg);
+    	}
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PluginActionContributionItem.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PluginActionContributionItem.java
new file mode 100644
index 0000000..79fed5a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PluginActionContributionItem.java
@@ -0,0 +1,182 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.jface.action.ActionContributionItem;
+import org.eclipse.jface.action.IContributionManager;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.ui.IPluginContribution;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.activities.ActivityManagerEvent;
+import org.eclipse.ui.activities.IActivityManagerListener;
+import org.eclipse.ui.activities.IIdentifier;
+import org.eclipse.ui.activities.IIdentifierListener;
+import org.eclipse.ui.activities.IWorkbenchActivitySupport;
+import org.eclipse.ui.activities.IdentifierEvent;
+import org.eclipse.ui.activities.WorkbenchActivityHelper;
+
+/**
+ * Contribution item for actions provided by plugins via workbench action
+ * extension points.
+ */
+public class PluginActionContributionItem extends ActionContributionItem
+        implements IIdentifierListener, IActivityManagerListener {
+
+    private IIdentifier identifier = null;
+
+    /**
+     * Creates a new contribution item from the given action. The id of the
+     * action is used as the id of the item.
+     *
+     * @param action
+     *            the action
+     */
+    public PluginActionContributionItem(PluginAction action) {
+        // dynamic UI (DDW) - this constructor has changed since 1113
+        super(action);
+    }
+
+    /**
+     * Hook the activity and identifier listener (if necessary);
+     *
+     * @since 3.1
+     */
+    private void hookListeners() {
+        PlatformUI.getWorkbench().getActivitySupport().getActivityManager()
+                .addActivityManagerListener(this);
+        // set up the identifier if necessary
+        IIdentifier id = getIdentifier();
+        if (id != null) {
+			id.addIdentifierListener(this);
+		}
+    }
+
+    /**
+     * Unhook the activity and identifier listener (if necessary);
+     *
+     * @since 3.1
+     */
+    private void unhookListeners() {
+        PlatformUI.getWorkbench().getActivitySupport().getActivityManager()
+                .removeActivityManagerListener(this);
+
+        IIdentifier id = getIdentifier();
+        if (id != null) {
+			id.removeIdentifierListener(this);
+		}
+    }
+
+    @Override
+	public void setParent(IContributionManager parent) {
+        IContributionManager oldParent = getParent();
+        super.setParent(parent);
+        if (oldParent == parent) {
+			return;
+		}
+
+        if (parent == null) {
+			unhookListeners();
+		} else {
+			hookListeners();
+		}
+    }
+
+    /**
+     * Create the IIdentifier reference for this item.
+     *
+     * @since 3.0
+     */
+    private IIdentifier getIdentifier() {
+        if (!WorkbenchActivityHelper.isFiltering()) {
+			return null;
+		}
+
+        if (identifier == null) {
+            IWorkbenchActivitySupport workbenchActivitySupport = PlatformUI
+                    .getWorkbench().getActivitySupport();
+            IPluginContribution contribution = (IPluginContribution) getAction();
+            // no need to check if contribution.getPluginId() == null - plugin
+            // actions are always from plugins.
+            identifier = workbenchActivitySupport.getActivityManager()
+                    .getIdentifier(
+                            WorkbenchActivityHelper
+                                    .createUnifiedId(contribution));
+        }
+        return identifier;
+    }
+
+    /**
+     * Dispose of the IIdentifier if necessary.
+     *
+     * @since 3.0
+     */
+    private void disposeIdentifier() {
+        identifier = null;
+    }
+
+    /**
+     * The default implementation of this <code>IContributionItem</code>
+     * method notifies the delegate if loaded and implements the <code>IActionDelegate2</code>
+     * interface.
+     */
+    @Override
+	public void dispose() {
+        unhookListeners();
+        disposeIdentifier();
+    }
+
+    @Override
+	public boolean isVisible() {
+        if (identifier != null && !identifier.isEnabled()) {
+			return false;
+		}
+        return super.isVisible();
+    }
+
+    @Override
+	public void identifierChanged(IdentifierEvent identifierEvent) {
+        invalidateParent();
+    }
+
+    /**
+     * Mark the parent dirty if we have a parent.
+     *
+     * @since 3.1
+     */
+	protected void invalidateParent() {
+        IContributionManager parent = getParent();
+        if (parent != null) {
+			parent.markDirty();
+		}
+    }
+
+    @Override
+	public void activityManagerChanged(ActivityManagerEvent activityManagerEvent) {
+        // ensure that if we're going from a non-filtering state that we get an identifier
+        // and vice versa.
+        if (WorkbenchActivityHelper.isFiltering() && identifier == null) {
+            hookListeners();
+            invalidateParent();
+        } else if (!WorkbenchActivityHelper.isFiltering() && identifier != null) {
+            unhookListeners();
+            disposeIdentifier();
+            invalidateParent();
+        }
+    }
+
+    /*
+     * For testing purposes only
+     */
+    public ISelection getSelection() {
+    	return ((PluginAction)getAction()).getSelection();
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PluginActionCoolBarContributionItem.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PluginActionCoolBarContributionItem.java
new file mode 100644
index 0000000..5e3e85e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PluginActionCoolBarContributionItem.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ *******************************************************************************/
+
+package org.eclipse.ui.internal;
+
+import java.util.HashSet;
+import org.eclipse.jface.action.IContributionManager;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * Contribution item for actions provided by plugins via workbench
+ * action extension points.
+ */
+public class PluginActionCoolBarContributionItem extends
+        PluginActionContributionItem implements IActionSetContributionItem {
+    private String actionSetId;
+
+    /**
+     * Creates a new contribution item from the given action.
+     * The id of the action is used as the id of the item.
+     *
+     * @param action the action
+     */
+    public PluginActionCoolBarContributionItem(PluginAction action) {
+        super(action);
+        setActionSetId(((WWinPluginAction) action).getActionSetId());
+    }
+
+    @Override
+	public String getActionSetId() {
+        return actionSetId;
+    }
+
+    @Override
+	public void setActionSetId(String id) {
+        this.actionSetId = id;
+    }
+
+	@Override
+	protected void invalidateParent() {
+		super.invalidateParent();
+		IContributionManager parent = getParent();
+		if (parent != null && managersToUpdate.add(parent)) {
+			if (!queued) {
+				queued = true;
+				PlatformUI.getWorkbench().getDisplay().asyncExec(updater);
+			}
+		}
+	}
+
+	private static Runnable updater = new Runnable() {
+		@Override
+		public void run() {
+			IContributionManager[] managers = managersToUpdate
+					.toArray(new IContributionManager[managersToUpdate.size()]);
+			managersToUpdate.clear();
+			queued = false;
+			for (IContributionManager manager : managers) {
+				manager.update(false);
+			}
+		}
+	};
+	private static HashSet<IContributionManager> managersToUpdate = new HashSet<>();
+	private static boolean queued = false;
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PluginActionSet.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PluginActionSet.java
new file mode 100644
index 0000000..4cfbefa
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PluginActionSet.java
@@ -0,0 +1,135 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.internal.registry.ActionSetDescriptor;
+import org.eclipse.ui.internal.registry.IActionSet;
+import org.eclipse.ui.services.IDisposable;
+
+/**
+ * A PluginActionSet is a proxy for an action set defined in XML.
+ * It creates a PluginAction for each action and does the required
+ * cleanup on dispose.
+ */
+public class PluginActionSet implements IActionSet {
+    private ActionSetDescriptor desc;
+
+    private ArrayList pluginActions = new ArrayList(4);
+
+    private ActionSetActionBars bars;
+
+	private IDisposable disposableBuilder;
+
+    /**
+     * PluginActionSet constructor comment.
+     *
+     * @param desc the descriptor
+     */
+    public PluginActionSet(ActionSetDescriptor desc) {
+        super();
+        this.desc = desc;
+    }
+
+    /**
+     * Adds one plugin action ref to the list.
+     *
+     * @param action the action
+     */
+    public void addPluginAction(WWinPluginAction action) {
+        pluginActions.add(action);
+    }
+
+    /**
+     * Returns the list of plugin actions for the set.
+     *
+     * @return the actions for the set
+     */
+    public IAction[] getPluginActions() {
+        IAction result[] = new IAction[pluginActions.size()];
+        pluginActions.toArray(result);
+        return result;
+    }
+
+    /**
+     * Disposes of this action set.
+     */
+    @Override
+	public void dispose() {
+        Iterator iter = pluginActions.iterator();
+        while (iter.hasNext()) {
+            WWinPluginAction action = (WWinPluginAction) iter.next();
+            action.dispose();
+        }
+        pluginActions.clear();
+        bars = null;
+		if (disposableBuilder != null) {
+			disposableBuilder.dispose();
+			disposableBuilder = null;
+		}
+    }
+
+    /**
+     */
+    /* package */ActionSetActionBars getBars() {
+        return bars;
+    }
+
+    /**
+     * Returns the configuration element.
+     *
+     * @return the configuration element
+     */
+    public IConfigurationElement getConfigElement() {
+        return desc.getConfigurationElement();
+    }
+
+    /**
+     * Returns the underlying descriptor.
+     *
+     * @return the descriptor
+     */
+    public ActionSetDescriptor getDesc() {
+        return desc;
+    }
+
+    /**
+     * Initializes this action set, which is expected to add it actions as required
+     * to the given workbench window and action bars.
+     *
+     * @param window the workbench window
+     * @param bars the action bars
+     */
+    @Override
+	public void init(IWorkbenchWindow window, IActionBars bars) {
+        this.bars = (ActionSetActionBars) bars;
+    }
+
+	public void setBuilder(IDisposable builder) {
+		if (disposableBuilder != null) {
+			disposableBuilder.dispose();
+		}
+		disposableBuilder = builder;
+	}
+
+	@Override
+	public String toString() {
+		return "PluginActionSet [desc=" + desc + ", " //$NON-NLS-1$ //$NON-NLS-2$
+				+ (pluginActions != null ? "actions=" + pluginActions : "") + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PluginActionSetBuilder.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PluginActionSetBuilder.java
new file mode 100644
index 0000000..85cff9d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PluginActionSetBuilder.java
@@ -0,0 +1,766 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
+import org.eclipse.jface.action.AbstractGroupMarker;
+import org.eclipse.jface.action.ActionContributionItem;
+import org.eclipse.jface.action.GroupMarker;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.IContributionManager;
+import org.eclipse.jface.action.ICoolBarManager;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.internal.provisional.action.IToolBarContributionItem;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IWorkbenchActionConstants;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.internal.registry.ActionSetRegistry;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.services.IDisposable;
+
+/**
+ * This builder reads the actions for an action set from the registry.
+ */
+public class PluginActionSetBuilder extends PluginActionBuilder {
+
+    private PluginActionSet actionSet;
+
+    private IWorkbenchWindow window;
+
+    private ArrayList adjunctContributions = new ArrayList(0);
+
+    /**
+     * Used by the workbench window extension handler to unhook action sets from
+     * their associated window.
+     *
+     * @since 3.1
+     */
+	public static class Binding implements IDisposable {
+        PluginActionSetBuilder builder;
+        PluginActionSet set;
+        IWorkbenchWindow window;
+		IExtensionTracker tracker;
+
+		@Override
+		public void dispose() {
+			if (tracker != null) {
+				tracker.unregisterObject(set.getConfigElement()
+						.getDeclaringExtension(), this);
+				tracker = null;
+			}
+		}
+    }
+
+    /**
+     * Constructs a new builder.
+     */
+    public PluginActionSetBuilder() {
+    }
+
+    /**
+     * Read the actions within a config element. Called by customize perspective
+     *
+     * @param set the action set
+     * @param window the window to contribute to
+     */
+    public void buildMenuAndToolBarStructure(PluginActionSet set,
+            IWorkbenchWindow window) {
+        this.actionSet = set;
+        this.window = window;
+        cache = null;
+        currentContribution = null;
+        targetID = null;
+        targetContributionTag = IWorkbenchRegistryConstants.TAG_ACTION_SET;
+
+        readElements(new IConfigurationElement[] { set.getConfigElement() });
+
+        if (cache != null) {
+            for (int i = 0; i < cache.size(); i++) {
+                ActionSetContribution contribution = (ActionSetContribution) cache
+                        .get(i);
+                contribution.contribute(actionSet.getBars(), true, true);
+                if (contribution.isAdjunctContributor()) {
+                    adjunctContributions.add(contribution);
+                }
+            }
+        }
+        for (int i = 0; i < adjunctContributions.size(); i++) {
+            ActionSetContribution contribution = (ActionSetContribution) adjunctContributions
+                    .get(i);
+            ActionSetActionBars bars = actionSet.getBars();
+            for (int j = 0; j < contribution.adjunctActions.size(); j++) {
+                ActionDescriptor adjunctAction = (ActionDescriptor) contribution.adjunctActions
+                        .get(j);
+                contribution
+                        .contributeAdjunctCoolbarAction(adjunctAction, bars);
+            }
+        }
+
+        registerBinding(set);
+    }
+
+    @Override
+	protected ActionDescriptor createActionDescriptor(
+            IConfigurationElement element) {
+        // As of 2.1, the "pulldown" attribute was deprecated and replaced by
+        // the attribute "style". See doc for more details.
+        boolean pullDownStyle = false;
+        String style = element.getAttribute(IWorkbenchRegistryConstants.ATT_STYLE);
+        if (style != null) {
+            pullDownStyle = style.equals(ActionDescriptor.STYLE_PULLDOWN);
+        } else {
+            String pulldown = element.getAttribute(ActionDescriptor.STYLE_PULLDOWN);
+            pullDownStyle = pulldown != null && pulldown.equals("true"); //$NON-NLS-1$
+        }
+
+        ActionDescriptor desc = null;
+        if (pullDownStyle) {
+			desc = new ActionDescriptor(element,
+                    ActionDescriptor.T_WORKBENCH_PULLDOWN, window);
+		} else {
+			desc = new ActionDescriptor(element, ActionDescriptor.T_WORKBENCH,
+                    window);
+		}
+        WWinPluginAction action = (WWinPluginAction) desc.getAction();
+        action.setActionSetId(actionSet.getDesc().getId());
+        actionSet.addPluginAction(action);
+        return desc;
+    }
+
+    @Override
+	protected BasicContribution createContribution() {
+        return new ActionSetContribution(actionSet.getDesc().getId(), window);
+    }
+
+    /**
+     * Returns the insertion point for a new contribution item.  Clients should
+     * use this item as a reference point for insertAfter.
+     *
+     * @param startId the reference id for insertion
+     * @param sortId the sorting id for the insertion.  If null then the item
+     *		will be inserted at the end of all action sets.
+     * @param mgr the target menu manager.
+     * @param startVsEnd if <code>true</code> the items are added at the start of
+     *		action with the same id; else they are added to the end
+     * @return the insertion point, or null if not found.
+     */
+    public static IContributionItem findInsertionPoint(String startId,
+            String sortId, IContributionManager mgr, boolean startVsEnd) {
+        // Get items.
+        IContributionItem[] items = mgr.getItems();
+
+        // Find the reference item.
+        int insertIndex = 0;
+        while (insertIndex < items.length) {
+            if (startId.equals(items[insertIndex].getId())) {
+				break;
+			}
+            ++insertIndex;
+        }
+        if (insertIndex >= items.length) {
+			return null;
+		}
+
+        // Calculate startVsEnd comparison value.
+        int compareMetric = 0;
+        if (startVsEnd) {
+			compareMetric = 1;
+		}
+
+        // Find the insertion point for the new item.
+        // We do this by iterating through all of the previous
+        // action set contributions define within the current group.
+        for (int nX = insertIndex + 1; nX < items.length; nX++) {
+            IContributionItem item = items[nX];
+            if (item.isSeparator() || item.isGroupMarker()) {
+                // Fix for bug report 18357
+                break;
+            }
+            if (item instanceof IActionSetContributionItem) {
+                if (sortId != null) {
+                    String testId = ((IActionSetContributionItem) item)
+                            .getActionSetId();
+                    if (sortId.compareTo(testId) < compareMetric) {
+						break;
+					}
+                }
+                insertIndex = nX;
+            } else {
+                break;
+            }
+        }
+        // Return item.
+        return items[insertIndex];
+    }
+
+    /**
+     */
+    /* package */static void processActionSets(ArrayList pluginActionSets,
+            WorkbenchWindow window) {
+        // Process the action sets in two passes.  On the first pass the pluginActionSetBuilder
+        // will process base contributions and cache adjunct contributions.  On the second
+        // pass the adjunct contributions will be processed.
+        PluginActionSetBuilder[] builders = new PluginActionSetBuilder[pluginActionSets
+                .size()];
+        for (int i = 0; i < pluginActionSets.size(); i++) {
+            PluginActionSet set = (PluginActionSet) pluginActionSets.get(i);
+            PluginActionSetBuilder builder = new PluginActionSetBuilder();
+            builder.readActionExtensions(set, window);
+            builders[i] = builder;
+        }
+        for (PluginActionSetBuilder builder : builders) {
+            builder.processAdjunctContributions();
+        }
+    }
+
+    /**
+     */
+    protected void processAdjunctContributions() {
+        // Contribute the adjunct contributions.
+        for (int i = 0; i < adjunctContributions.size(); i++) {
+            ActionSetContribution contribution = (ActionSetContribution) adjunctContributions
+                    .get(i);
+            ActionSetActionBars bars = actionSet.getBars();
+            for (int j = 0; j < contribution.adjunctActions.size(); j++) {
+                ActionDescriptor adjunctAction = (ActionDescriptor) contribution.adjunctActions
+                        .get(j);
+                contribution
+                        .contributeAdjunctCoolbarAction(adjunctAction, bars);
+            }
+        }
+    }
+
+    /**
+     * Read the actions within a config element.
+     */
+    protected void readActionExtensions(PluginActionSet set,
+            IWorkbenchWindow window) {
+        this.actionSet = set;
+        this.window = window;
+        cache = null;
+        currentContribution = null;
+        targetID = null;
+        targetContributionTag = IWorkbenchRegistryConstants.TAG_ACTION_SET;
+
+        readElements(new IConfigurationElement[] { set.getConfigElement() });
+
+        if (cache != null) {
+            // for dynamic UI - save cache for future removal lf actionset extensions
+            //        Don't call addCache -- it's broken, and is only used for dynamic plugin removal,
+            //        which the workbench doesn't currently support.
+            //        See bug 66374 for more details.
+            //			WorkbenchPlugin.getDefault().getActionSetRegistry().addCache(set.getDesc().getId(), cache);
+            for (int i = 0; i < cache.size(); i++) {
+                ActionSetContribution contribution = (ActionSetContribution) cache
+                        .get(i);
+                contribution.contribute(actionSet.getBars(), true, true);
+                if (contribution.isAdjunctContributor()) {
+                    adjunctContributions.add(contribution);
+                }
+            }
+
+            registerBinding(set);
+
+        } else {
+            WorkbenchPlugin
+                    .log("Action Set is empty: " + set.getDesc().getId()); //$NON-NLS-1$
+        }
+    }
+
+    private void registerBinding(final PluginActionSet set) {
+    	final IExtensionTracker tracker = window.getExtensionTracker();
+
+    	// register the new binding
+    	final Binding binding = new Binding();
+        binding.builder = this;
+        binding.set = set;
+        binding.window = window;
+		binding.tracker = tracker;
+        tracker.registerObject(
+                set.getConfigElement().getDeclaringExtension(), binding,
+                IExtensionTracker.REF_STRONG);
+		set.setBuilder(binding);
+    }
+
+    /**
+     * Helper class to collect the menus and actions defined within a
+     * contribution element.
+     */
+    private static class ActionSetContribution extends BasicContribution {
+        private String actionSetId;
+
+        private WorkbenchWindow window;
+
+        protected ArrayList adjunctActions = new ArrayList(0);
+
+        /**
+         * Create a new instance of <code>ActionSetContribution</code>.
+         *
+         * @param id the id
+         * @param window the window to contribute to
+         */
+        public ActionSetContribution(String id, IWorkbenchWindow window) {
+            super();
+            actionSetId = id;
+            this.window = (WorkbenchWindow) window;
+        }
+
+        /**
+         * This implementation inserts the group into the action set additions group.
+         */
+        @Override
+		protected void addGroup(IContributionManager mgr, String name) {
+            IContributionItem refItem = findInsertionPoint(
+                    IWorkbenchActionConstants.MB_ADDITIONS, actionSetId, mgr,
+                    true);
+            // Insert the new group marker.
+            ActionSetSeparator group = new ActionSetSeparator(name, actionSetId);
+            if (refItem == null) {
+                mgr.add(group);
+            } else {
+                mgr.insertAfter(refItem.getId(), group);
+            }
+        }
+
+        /**
+         * Contributes submenus and/or actions into the provided menu and tool bar
+         * managers.
+         *
+         * @param bars the action bars to contribute to
+         * @param menuAppendIfMissing append to the menubar if missing
+         * @param toolAppendIfMissing append to the toolbar if missing
+         */
+        public void contribute(IActionBars bars, boolean menuAppendIfMissing,
+                boolean toolAppendIfMissing) {
+
+            IMenuManager menuMgr = bars.getMenuManager();
+            IToolBarManager toolBarMgr = bars.getToolBarManager();
+            if (menus != null && menuMgr != null) {
+                for (int i = 0; i < menus.size(); i++) {
+                    IConfigurationElement menuElement = (IConfigurationElement) menus
+                            .get(i);
+                    contributeMenu(menuElement, menuMgr, menuAppendIfMissing);
+                }
+            }
+
+            if (actions != null) {
+                for (int i = 0; i < actions.size(); i++) {
+                    ActionDescriptor ad = (ActionDescriptor) actions.get(i);
+                    if (menuMgr != null) {
+						contributeMenuAction(ad, menuMgr, menuAppendIfMissing);
+					}
+                    if (toolBarMgr != null) {
+                        if (bars instanceof ActionSetActionBars) {
+                            contributeCoolbarAction(ad,
+                                    (ActionSetActionBars) bars);
+                        } else {
+                            contributeToolbarAction(ad, toolBarMgr,
+                                    toolAppendIfMissing);
+                        }
+                    }
+                }
+            }
+        }
+
+        /**
+         * Contributes action from the action descriptor into the cool bar manager.
+         */
+        protected void contributeAdjunctCoolbarAction(ActionDescriptor ad,
+                ActionSetActionBars bars) {
+            String toolBarId = ad.getToolbarId();
+            String toolGroupId = ad.getToolbarGroupId();
+
+            String contributingId = bars.getActionSetId();
+            ICoolBarManager coolBarMgr = bars.getCoolBarManager();
+            if (coolBarMgr == null) {
+                return;
+            }
+
+            PluginAction action = ad.getAction();
+            ActionContributionItem actionContribution = new PluginActionCoolBarContributionItem(
+                    action);
+            actionContribution.setMode(ad.getMode());
+
+            bars.addAdjunctContribution(actionContribution);
+
+            // create a coolitem for the toolbar id if it does not yet exist
+            IToolBarManager toolBarManager = bars.getToolBarManager(toolBarId);
+
+            // Check to see if the group already exists
+            IContributionItem groupMarker = toolBarManager.find(toolGroupId);
+            // Add a group marker if one does not exist
+            if (groupMarker == null) {
+                toolBarManager.add(new Separator(toolGroupId));
+            }
+            IContributionItem refItem = findAlphabeticalOrder(toolGroupId,
+                    contributingId, toolBarManager);
+            if (refItem != null && refItem.getId() != null) {
+                toolBarManager.insertAfter(refItem.getId(), actionContribution);
+            } else {
+                toolBarManager.add(actionContribution);
+            }
+            toolBarManager.update(false);
+
+        }
+
+        /**
+         * Contributes action from the action descriptor into the cool bar manager.
+         */
+        protected void contributeCoolbarAction(ActionDescriptor ad,
+                ActionSetActionBars bars) {
+            String toolBarId = ad.getToolbarId();
+            String toolGroupId = ad.getToolbarGroupId();
+            if (toolBarId == null && toolGroupId == null) {
+				return;
+			}
+
+            String contributingId = bars.getActionSetId();
+
+            if (toolBarId == null || toolBarId.equals("")) { //$NON-NLS-1$
+                // the item is being added to the coolitem for its action set
+                toolBarId = contributingId;
+            }
+
+            if (!toolBarId.equals(contributingId)) {
+                // adding to another action set, validate the id
+                if (!isValidCoolItemId(toolBarId, window)) {
+                    // toolbarid not valid, add the item to the coolitem for its action set
+                    toolBarId = contributingId;
+                } else {
+                    adjunctActions.add(ad);
+                    return;
+                }
+            }
+
+            // Create the action
+            PluginAction action = ad.getAction();
+            ActionContributionItem actionContribution = new PluginActionCoolBarContributionItem(
+                    action);
+            actionContribution.setMode(ad.getMode());
+
+            // retreive the toolbar from the action bars.
+            IToolBarManager toolBar = bars.getToolBarManager(toolBarId);
+
+            // Check to see if the group already exists
+            IContributionItem groupMarker = toolBar.find(toolGroupId);
+            // Add a group marker if one does not exist
+            if (groupMarker == null) {
+                // @issue should this be a GroupMarker?
+                toolBar.add(new Separator(toolGroupId));
+            }
+            toolBar.prependToGroup(toolGroupId, actionContribution);
+            toolBar.update(false);
+
+        }
+
+        /**
+         * Checks to see if the cool item id is in the given window.
+         */
+        private boolean isValidCoolItemId(String id, WorkbenchWindow window) {
+            ActionSetRegistry registry = WorkbenchPlugin.getDefault()
+                    .getActionSetRegistry();
+            if (registry.findActionSet(id) != null) {
+				return true;
+			}
+            if (window != null) {
+                return window.isWorkbenchCoolItemId(id);
+            }
+            return false;
+        }
+
+        @Override
+		protected void insertMenuGroup(IMenuManager menu,
+                AbstractGroupMarker marker) {
+            if (actionSetId != null) {
+                IContributionItem[] items = menu.getItems();
+                // Loop thru all the current groups looking for the first
+                // group whose id > than the current action set id. Insert
+                // current marker just before this item then.
+                for (IContributionItem item : items) {
+                    if (item.isSeparator() || item.isGroupMarker()) {
+                        if (item instanceof IActionSetContributionItem) {
+                            String testId = ((IActionSetContributionItem) item)
+                                    .getActionSetId();
+                            if (actionSetId.compareTo(testId) < 0) {
+                                menu.insertBefore(item.getId(), marker);
+                                return;
+                            }
+                        }
+                    }
+                }
+            }
+
+            menu.add(marker);
+        }
+
+        private IContributionItem findAlphabeticalOrder(String startId,
+                String itemId, IContributionManager mgr) {
+            IContributionItem[] items = mgr.getItems();
+            int insertIndex = 0;
+
+            // look for starting point
+            while (insertIndex < items.length) {
+                IContributionItem item = items[insertIndex];
+                if (startId != null && startId.equals(item.getId())) {
+					break;
+				}
+                ++insertIndex;
+            }
+
+            // Find the index that this item should be inserted in
+            for (int i = insertIndex + 1; i < items.length; i++) {
+                IContributionItem item = items[i];
+                if (item.isGroupMarker()) {
+					break;
+				}
+
+                String testId = null;
+                if (item instanceof PluginActionCoolBarContributionItem) {
+                    testId = ((PluginActionCoolBarContributionItem) item)
+                            .getActionSetId();
+                }
+                if (testId == null) {
+                    break;
+                }
+
+                if (itemId != null && testId != null) {
+                    if (itemId.compareTo(testId) < 1) {
+						break;
+					}
+                }
+                insertIndex = i;
+            }
+            if (insertIndex >= items.length) {
+                return null;
+            }
+            return items[insertIndex];
+        }
+
+        /**
+         * Returns whether the contributor is an adjunct contributor.
+         *
+         * @return whether the contributor is an adjunct contributor
+         */
+        public boolean isAdjunctContributor() {
+            return adjunctActions.size() > 0;
+        }
+
+        @Override
+		protected void insertAfter(IContributionManager mgr, String refId,
+                IContributionItem item) {
+            IContributionItem refItem = findInsertionPoint(refId, actionSetId,
+                    mgr, true);
+            if (refItem != null) {
+                mgr.insertAfter(refItem.getId(), item);
+            } else {
+                WorkbenchPlugin
+                        .log("Reference item " + refId + " not found for action " + item.getId()); //$NON-NLS-1$ //$NON-NLS-2$
+            }
+        }
+
+        //for dynamic UI
+        protected void revokeContribution(WorkbenchWindow window,
+                IActionBars bars, String id) {
+            revokeActionSetFromMenu(window.getMenuManager(), id);
+            //			IMenuManager menuMgr = bars.getMenuManager();
+            //			if (menuMgr != null)
+            //				revokeActionSetFromMenu(menuMgr, id);
+
+            revokeActionSetFromCoolbar(window.getCoolBarManager2(), id);
+            //			IToolBarManager toolBarMgr = bars.getToolBarManager();
+            //			if (toolBarMgr != null && toolBarMgr instanceof CoolItemToolBarManager)
+            //				revokeActionSetFromToolbar(toolBarMgr, id);
+        }
+
+        //for dynamic UI
+        protected void revokeAdjunctCoolbarAction(ActionDescriptor ad,
+                ActionSetActionBars bars) {
+            String toolBarId = ad.getToolbarId();
+//            String toolGroupId = ad.getToolbarGroupId();
+//
+//            String contributingId = bars.getActionSetId();
+            ICoolBarManager coolBarMgr = bars.getCoolBarManager();
+            //				((CoolItemToolBarManager)bars.getToolBarManager()).getParentManager();
+            PluginAction action = ad.getAction();
+            PluginActionCoolBarContributionItem actionContribution = new PluginActionCoolBarContributionItem(
+                    action);
+            actionContribution.setMode(ad.getMode());
+
+            bars.removeAdjunctContribution(actionContribution);
+
+            // remove a coolitem for the toolbar id if it exists
+            IContributionItem cbItem = coolBarMgr.find(toolBarId);
+            if (cbItem != null) {
+				coolBarMgr.remove(cbItem);
+			}
+
+            //			activeManager = cbItem.getToolBarManager();
+            //			activeManager.remove(contributingId);
+            //			IContributionItem groupMarker = activeManager.find(toolGroupId);
+            //			if (groupMarker != null) {
+            //				int idx = activeManager.indexOf(toolGroupId);
+            //				IContributionItem[] items = activeManager.getItems();
+            //				if (items.length == idx+1 ||
+            //						((items.length > idx && items[idx+1] instanceof Separator)))
+            //					if (activeManager.find(toolGroupId) != null)
+            //						activeManager.remove(toolGroupId);
+            //			}
+            //			activeManager.addAdjunctItemToGroup(toolGroupId, contributingId, actionContribution);
+        }
+
+        //for dynamic UI
+        private void revokeActionSetFromMenu(IMenuManager menuMgr,
+                String actionsetId) {
+            IContributionItem[] items = menuMgr.getItems();
+            ArrayList itemsToRemove = new ArrayList();
+            String id;
+            for (IContributionItem item : items) {
+				if (item instanceof IMenuManager) {
+                    revokeActionSetFromMenu((IMenuManager) item,
+                            actionsetId);
+                } else if (item instanceof ActionSetContributionItem) {
+                    id = ((ActionSetContributionItem) item)
+                            .getActionSetId();
+                    if (actionsetId.equals(id)) {
+						itemsToRemove.add(item);
+					}
+                } else if (item instanceof Separator) {
+                    id = ((Separator) item).getId();
+                    if (actionsetId.equals(id)) {
+						itemsToRemove.add(item);
+					}
+                } else if (item instanceof GroupMarker) {
+                    id = ((GroupMarker) item).getId();
+                    if (actionsetId.equals(id)) {
+						itemsToRemove.add(item);
+					}
+                }
+			}
+            Iterator iter = itemsToRemove.iterator();
+            while (iter.hasNext()) {
+                IContributionItem item = (IContributionItem) iter.next();
+                menuMgr.remove(item);
+            }
+            menuMgr.update(true);
+        }
+
+        // for dynamic UI
+        private void revokeActionSetFromCoolbar(ICoolBarManager coolbarMgr,
+                String actionsetId) {
+            IContributionItem[] items = coolbarMgr.getItems();
+            ArrayList itemsToRemove = new ArrayList();
+            String id;
+            for (IContributionItem item : items) {
+                id = item.getId();
+                if (actionsetId.equals(id)) {
+                    itemsToRemove.add(item);
+                    continue;
+                }
+                if (item instanceof IToolBarManager) {
+                    revokeActionSetFromToolbar((IToolBarManager) item,
+                            actionsetId);
+                } else if (item instanceof IToolBarContributionItem) {
+                    id = ((IToolBarContributionItem) item).getId();
+                    if (actionsetId.equals(id)) {
+						itemsToRemove.add(item);
+					}
+                } else if (item instanceof GroupMarker) {
+                    id = ((GroupMarker) item).getId();
+                    if (actionsetId.equals(id)) {
+						itemsToRemove.add(item);
+					}
+                }
+            }
+            Iterator iter = itemsToRemove.iterator();
+            while (iter.hasNext()) {
+				coolbarMgr.remove((IContributionItem) iter.next());
+			}
+            coolbarMgr.update(true);
+        }
+
+        // for dynamic UI
+        private void revokeActionSetFromToolbar(IToolBarManager toolbarMgr,
+                String actionsetId) {
+            IContributionItem[] items = toolbarMgr.getItems();
+            ArrayList itemsToRemove = new ArrayList();
+            String id;
+            for (IContributionItem item : items) {
+                id = item.getId();
+                if (id.equals(actionsetId)) {
+                    itemsToRemove.add(item);
+                    continue;
+                }
+                if (item instanceof PluginActionCoolBarContributionItem) {
+                    id = ((PluginActionCoolBarContributionItem) item)
+                            .getActionSetId();
+                    if (actionsetId.equals(id)) {
+						itemsToRemove.add(item);
+					}
+                } else if (item instanceof ActionContributionItem) {
+                    id = ((ActionContributionItem) item).getId();
+                    if (actionsetId.equals(id)) {
+						itemsToRemove.add(item);
+					}
+                } else if (item instanceof GroupMarker) {
+                    id = ((GroupMarker) item).getId();
+                    if (actionsetId.equals(id)) {
+						itemsToRemove.add(item);
+					}
+                }
+            }
+            Iterator iter = itemsToRemove.iterator();
+            while (iter.hasNext()) {
+				toolbarMgr.remove((IContributionItem) iter.next());
+			}
+            toolbarMgr.update(true);
+        }
+    }
+
+
+    /**
+     * Remove the given action set from the window.
+     *
+     * @param set the set to remove
+     * @param window the window to remove from
+     */
+    protected void removeActionExtensions(PluginActionSet set,
+            IWorkbenchWindow window) {
+        this.actionSet = set;
+        this.window = window;
+        currentContribution = null;
+        targetID = null;
+        targetContributionTag = IWorkbenchRegistryConstants.TAG_ACTION_SET;
+        String id = set.getDesc().getId();
+
+        if (cache != null) {
+            for (int i = 0; i < cache.size(); i++) {
+                ActionSetContribution contribution = (ActionSetContribution) cache
+                        .get(i);
+                contribution.revokeContribution((WorkbenchWindow) window,
+                        actionSet.getBars(), id);
+                if (contribution.isAdjunctContributor()) {
+                    for (int j = 0; j < contribution.adjunctActions.size(); j++) {
+                        ActionDescriptor adjunctAction = (ActionDescriptor) contribution.adjunctActions
+                                .get(j);
+                        contribution.revokeAdjunctCoolbarAction(adjunctAction,
+                                actionSet.getBars());
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PopupMenuExtender.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PopupMenuExtender.java
new file mode 100644
index 0000000..90f8c1c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/PopupMenuExtender.java
@@ -0,0 +1,624 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Dan Rubel (dan_rubel@instantiations.com) - accessor to get menu id
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ *******************************************************************************/
+package org.eclipse.ui.internal;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionDelta;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IRegistryChangeEvent;
+import org.eclipse.core.runtime.IRegistryChangeListener;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.ui.internal.workbench.ContributionsAnalyzer;
+import org.eclipse.e4.ui.internal.workbench.OpaqueElementUtil;
+import org.eclipse.e4.ui.internal.workbench.swt.AbstractPartRenderer;
+import org.eclipse.e4.ui.internal.workbench.swt.MenuService;
+import org.eclipse.e4.ui.model.application.ui.MElementContainer;
+import org.eclipse.e4.ui.model.application.ui.MUIElement;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.model.application.ui.menu.MMenu;
+import org.eclipse.e4.ui.model.application.ui.menu.MMenuElement;
+import org.eclipse.e4.ui.model.application.ui.menu.MPopupMenu;
+import org.eclipse.e4.ui.model.application.ui.menu.impl.MenuFactoryImpl;
+import org.eclipse.e4.ui.workbench.renderers.swt.MenuManagerRenderer;
+import org.eclipse.e4.ui.workbench.swt.factories.IRendererFactory;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.IMenuListener2;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.action.SubMenuManager;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+
+/**
+ * This class extends a single popup menu
+ */
+public class PopupMenuExtender implements IMenuListener2,
+		IRegistryChangeListener {
+
+    /**
+     * The bit in <code>bitSet</code> that stores whether the static actions
+     * have been read from the registry.
+     */
+    private static final int STATIC_ACTION_READ = 1;
+
+    /**
+     * The bit in <code>bitSet</code> that stores whether the editor input
+     * should be included for the sake of object contributions.
+     */
+    private static final int INCLUDE_EDITOR_INPUT = 1 << 1;
+
+    private final MenuManager menu;
+
+    private SubMenuManager menuWrapper;
+
+    private final ISelectionProvider selProvider;
+
+    private final IWorkbenchPart part;
+
+	private Map<String, ViewerActionBuilder> staticActionBuilders = null;
+
+    /**
+     * The boolean properties maintained by this extender. A bit set is used to
+     * save memory.
+     */
+	private int bitSet = 0;
+
+	private ArrayList<PluginActionContributionItem> actionContributionCache = new ArrayList<>();
+	private boolean cleanupNeeded = false;
+
+	private MPart modelPart;
+
+	/**
+	 * The context that will be used to create the popup menu's context under.
+	 */
+	private IEclipseContext context;
+
+    /**
+     * Construct a new menu extender.
+     *
+     * @param id
+     *            the menu id
+     * @param menu
+     *            the menu to extend
+     * @param prov
+     *            the selection provider
+     * @param part
+     *            the part to extend
+	 * @param context
+	 *            the context to create the child popup menu context under
+     */
+	public PopupMenuExtender(String id, MenuManager menu, ISelectionProvider prov,
+			IWorkbenchPart part, IEclipseContext context) {
+		this(id, menu, prov, part, context, true);
+	}
+
+    /**
+     * Construct a new menu extender.
+     *
+     * @param id
+     *            the menu id
+     * @param menu
+     *            the menu to extend
+     * @param prov
+     *            the selection provider
+     * @param part
+     *            the part to extend
+	 * @param context
+	 *            the context to create the child popup menu context under
+     * @param includeEditorInput
+     *            Whether the editor input should be included when adding object
+     *            contributions to this context menu.
+     */
+	public PopupMenuExtender(final String id, final MenuManager menu,
+			final ISelectionProvider prov, final IWorkbenchPart part, IEclipseContext context,
+			final boolean includeEditorInput) {
+		super();
+		this.menu = menu;
+		this.selProvider = prov;
+		this.part = part;
+		this.context = context;
+		this.modelPart = part.getSite().getService(MPart.class);
+		if (includeEditorInput) {
+			bitSet |= INCLUDE_EDITOR_INPUT;
+		}
+		menu.addMenuListener(this);
+		if (!menu.getRemoveAllWhenShown()) {
+			menuWrapper = new SubMenuManager(menu);
+			menuWrapper.setVisible(true);
+		}
+		createModelFor(id);
+		addMenuId(id);
+
+		Platform.getExtensionRegistry().addRegistryChangeListener(this);
+	}
+
+	private void createModelFor(String id) {
+		if (id == null) {
+			id = getClass().getName() + '.' + System.identityHashCode(this);
+		}
+		menuModel = null;
+		for (MMenu item : modelPart.getMenus()) {
+			if (id.equals(item.getElementId()) && item instanceof MPopupMenu
+					&& item.getTags().contains("popup")) { //$NON-NLS-1$
+				menuModel = (MPopupMenu) item;
+				break;
+			}
+		}
+		if (menuModel == null) {
+			menuModel = MenuFactoryImpl.eINSTANCE.createPopupMenu();
+			menuModel.setElementId(id);
+			menuModel.getTags().add(ContributionsAnalyzer.MC_POPUP);
+			modelPart.getMenus().add(menuModel);
+		}
+		IRendererFactory factory = modelPart.getContext().get(IRendererFactory.class);
+		AbstractPartRenderer obj = factory.getRenderer(menuModel, null);
+		if (obj instanceof MenuManagerRenderer) {
+			((MenuManagerRenderer) obj).linkModelToManager(menuModel, menu);
+		}
+		registerE4Support();
+		cleanUpContributionCache();
+	}
+
+	private void registerE4Support() {
+		if (menuModel.getWidget() == null && menu.getMenu() != null) {
+			MenuService.registerMenu(menu.getMenu().getParent(), menuModel, context);
+		}
+	}
+	// getMenuId() added by Dan Rubel (dan_rubel@instantiations.com)
+    /**
+     * Return the menu identifiers for this extender.
+     *
+     * @return The set of all identifiers that represent this extender.
+     */
+	public Set<String> getMenuIds() {
+    	if (staticActionBuilders == null) {
+			return Collections.emptySet();
+    	}
+
+        return staticActionBuilders.keySet();
+    }
+
+    /**
+     * <p>
+     * Adds another menu identifier to this extender. An extender can represent
+     * many menu identifiers. These identifiers should represent the same menu
+     * manager, selection provider and part. Duplicate identifiers are
+     * automatically ignored.
+     * </p>
+     * <p>
+     * For example, it is necessary to filter out duplicate identifiers for
+     * <code>CompilationUnitEditor</code> instances, as these define both
+     * <code>"#CompilationUnitEditorContext"</code> and
+     * <code>"org.eclipse.jdt.ui.CompilationUnitEditor.EditorContext"</code>
+     * as menu identifier for the same pop-up menu. We don't want to contribute
+     * duplicate items in this case.
+     * </p>
+     *
+     * @param menuId
+     *            The menu identifier to add to this extender; should not be
+     *            <code>null</code>.
+     */
+    public final void addMenuId(final String menuId) {
+		bitSet &= ~STATIC_ACTION_READ;
+		if (menuModel != null) {
+			List<String> tags = menuModel.getTags();
+			String tag = "popup:" + menuId; //$NON-NLS-1$
+			if (!tags.contains(tag)) {
+				tags.add(tag);
+			}
+		}
+		readStaticActionsFor(menuId);
+	}
+
+    /**
+     * Determines whether this extender would be the same as another extender
+     * created with the given values. Two extenders are equivalent if they have
+     * the same menu manager, selection provider and part (i.e., if the menu
+     * they represent is about to show, they would populate it with duplicate
+     * values).
+     *
+     * @param menuManager
+     *            The menu manager with which to compare; may be
+     *            <code>null</code>.
+     * @param selectionProvider
+     *            The selection provider with which to compare; may be
+     *            <code>null</code>.
+     * @param part
+     *            The part with which to compare; may be <code>null</code>.
+     * @return <code>true</code> if the menu manager, selection provider and
+     *         part are all the same.
+     */
+    public final boolean matches(final MenuManager menuManager,
+            final ISelectionProvider selectionProvider,
+            final IWorkbenchPart part) {
+        return (this.menu == menuManager)
+                && (this.selProvider == selectionProvider)
+                && (this.part == part);
+    }
+
+    /**
+     * Contributes items registered for the currently active editor.
+     */
+	private void addEditorActions(IMenuManager mgr, Set<IObjectActionContributor> alreadyContributed) {
+        ISelectionProvider activeEditor = new ISelectionProvider() {
+
+            @Override
+			public void addSelectionChangedListener(
+                    ISelectionChangedListener listener) {
+                throw new UnsupportedOperationException(
+                "This ISelectionProvider is static, and cannot be modified."); //$NON-NLS-1$
+            }
+
+            @Override
+			public ISelection getSelection() {
+                if (part instanceof IEditorPart) {
+                    final IEditorPart editorPart = (IEditorPart) part;
+                    return new StructuredSelection(new Object[] { editorPart
+                            .getEditorInput() });
+                }
+
+                return new StructuredSelection(new Object[0]);
+            }
+
+            @Override
+			public void removeSelectionChangedListener(
+                    ISelectionChangedListener listener) {
+                throw new UnsupportedOperationException(
+                "This ISelectionProvider is static, and cannot be modified."); //$NON-NLS-1$
+            }
+
+            @Override
+			public void setSelection(ISelection selection) {
+                throw new UnsupportedOperationException(
+                        "This ISelectionProvider is static, and cannot be modified."); //$NON-NLS-1$
+            }
+        };
+
+		if (ObjectActionContributorManager.getManager().contributeObjectActions(part, mgr,
+				activeEditor, alreadyContributed)) {
+			mgr.add(new Separator());
+		}
+    }
+
+    /**
+     * Contributes items registered for the object type(s) in
+     * the current selection.
+     */
+	private void addObjectActions(IMenuManager mgr, Set<IObjectActionContributor> alreadyContributed) {
+        if (selProvider != null) {
+			if (ObjectActionContributorManager.getManager().contributeObjectActions(part, mgr,
+					selProvider, alreadyContributed)) {
+				mgr.add(new Separator());
+            }
+        }
+    }
+
+    /**
+     * Disposes all of the static actions.
+     */
+    private final void clearStaticActions() {
+		bitSet &= ~STATIC_ACTION_READ;
+		if (staticActionBuilders != null) {
+			final Iterator<ViewerActionBuilder> staticActionBuilderItr = staticActionBuilders
+					.values().iterator();
+			while (staticActionBuilderItr.hasNext()) {
+				final ViewerActionBuilder staticActionBuilder = staticActionBuilderItr.next();
+				staticActionBuilder.dispose();
+			}
+		}
+	}
+
+    /**
+     * Adds static items to the context menu.
+     */
+    private void addStaticActions(IMenuManager mgr) {
+		if (staticActionBuilders != null) {
+			final Iterator<ViewerActionBuilder> staticActionBuilderItr = staticActionBuilders
+					.values().iterator();
+			while (staticActionBuilderItr.hasNext()) {
+				final ViewerActionBuilder staticActionBuilder = staticActionBuilderItr.next();
+				staticActionBuilder.contribute(mgr, null, true);
+			}
+		}
+	}
+
+    /**
+     * Notifies the listener that the menu is about to be shown.
+     */
+    @Override
+	public void menuAboutToShow(IMenuManager mgr) {
+		registerE4Support();
+
+    	// Add this menu as a visible menu.
+    	final IWorkbenchPartSite site = part.getSite();
+    	if (site != null) {
+			final IWorkbench workbench = site.getWorkbenchWindow()
+					.getWorkbench();
+			if (workbench instanceof Workbench) {
+				final Workbench realWorkbench = (Workbench) workbench;
+				runCleanUp(realWorkbench);
+				ISelection input = null;
+				if ((bitSet & INCLUDE_EDITOR_INPUT) != 0) {
+					if (part instanceof IEditorPart) {
+						final IEditorPart editorPart = (IEditorPart) part;
+						input = new StructuredSelection(
+								new Object[] { editorPart.getEditorInput() });
+					}
+				}
+				ISelection s = (selProvider == null ? null : selProvider
+						.getSelection());
+				realWorkbench.addShowingMenus(getMenuIds(), s, input);
+			}
+		}
+
+		addMenuContributions(mgr);
+
+    	readStaticActions();
+        // test for additions removed to comply with menu contributions
+        if (menuWrapper != null) {
+            mgr = menuWrapper;
+            menuWrapper.removeAll();
+        }
+		Set<IObjectActionContributor> contributedItems = new HashSet<>();
+        if ((bitSet & INCLUDE_EDITOR_INPUT) != 0) {
+			addEditorActions(mgr, contributedItems);
+        }
+		addObjectActions(mgr, contributedItems);
+        addStaticActions(mgr);
+    }
+
+
+	/**
+	 * well, this goes to the renderer.
+	 *
+	 * @param mgr
+	 */
+	private void addMenuContributions(IMenuManager mgr) {
+		IRendererFactory factory = modelPart.getContext().get(IRendererFactory.class);
+		AbstractPartRenderer obj = factory.getRenderer(menuModel, null);
+		if (obj instanceof MenuManagerRenderer) {
+			MenuManagerRenderer renderer = (MenuManagerRenderer) obj;
+			renderer.reconcileManagerToModel(menu, menuModel);
+			renderer.processContributions(menuModel, menuModel.getElementId(), false, true);
+			// double cast because we're bad people
+			renderer.processContents((MElementContainer<MUIElement>) ((Object) menuModel));
+		}
+	}
+
+	private MPopupMenu menuModel;
+
+    /**
+	 * Notifies the listener that the menu is about to be hidden.
+	 */
+    @Override
+	public final void menuAboutToHide(final IMenuManager mgr) {
+    	gatherContributions(mgr);
+		cleanupNeeded = true;
+    	// Remove this menu as a visible menu.
+    	final IWorkbenchPartSite site = part.getSite();
+    	if (site != null) {
+    		final IWorkbench workbench = site.getWorkbenchWindow().getWorkbench();
+    		if (workbench instanceof Workbench) {
+    			// try delaying this until after the selection event
+    			// has been fired.
+    			// This is less threatening if the popup: menu
+    			// contributions aren't tied to the evaluation service
+				workbench.getDisplay().asyncExec(() -> {
+					final Workbench realWorkbench = (Workbench) workbench;
+					runCleanUp(realWorkbench);
+				});
+			}
+    	}
+    }
+
+	private void runCleanUp(Workbench realWorkbench) {
+		if (!cleanupNeeded) {
+			return;
+		}
+		cleanupNeeded = false;
+		realWorkbench.removeShowingMenus(getMenuIds(), null, null);
+		cleanUpContributionCache();
+	}
+
+	private void gatherContributions(final IMenuManager mgr) {
+		final IContributionItem[] items = mgr.getItems();
+		for (IContributionItem item : items) {
+			if (item instanceof PluginActionContributionItem) {
+				actionContributionCache.add((PluginActionContributionItem) item);
+			} else if (item instanceof IMenuManager) {
+				gatherContributions(((IMenuManager) item));
+			}
+		}
+	}
+
+	private void cleanUpContributionCache() {
+		if (!actionContributionCache.isEmpty()) {
+			PluginActionContributionItem[] items = actionContributionCache
+					.toArray(new PluginActionContributionItem[actionContributionCache.size()]);
+			actionContributionCache.clear();
+			for (PluginActionContributionItem item : items) {
+				item.dispose();
+			}
+		}
+
+		if (modelPart == null || menuModel == null) {
+			return;
+		}
+		IEclipseContext modelContext = modelPart.getContext();
+		if (modelContext != null) {
+			IRendererFactory factory = modelContext.get(IRendererFactory.class);
+			if (factory != null) {
+				AbstractPartRenderer obj = factory.getRenderer(menuModel, null);
+				if (obj instanceof MenuManagerRenderer) {
+					MenuManagerRenderer renderer = (MenuManagerRenderer) obj;
+					renderer.cleanUp(menuModel);
+				}
+			}
+		}
+	}
+
+	/**
+     * Read all of the static items for the content menu.
+     */
+    private final void readStaticActions() {
+    	if (staticActionBuilders != null) {
+			final Iterator<String> menuIdItr = staticActionBuilders.keySet().iterator();
+			while (menuIdItr.hasNext()) {
+				final String menuId = menuIdItr.next();
+				readStaticActionsFor(menuId);
+			}
+		}
+    }
+
+    /**
+	 * Read static items for a particular menu id, into the context menu.
+	 */
+    private void readStaticActionsFor(final String menuId) {
+		if ((bitSet & STATIC_ACTION_READ) != 0) {
+			return;
+		}
+
+		bitSet |= STATIC_ACTION_READ;
+
+		// If no menu id provided, then there is no contributions
+		// to add. Fix for bug #33140.
+		if ((menuId == null) || (menuId.length() < 1)) {
+			return;
+		}
+
+		if (staticActionBuilders == null) {
+			staticActionBuilders = new HashMap<>();
+		}
+
+		Object object = staticActionBuilders.get(menuId);
+		if (!(object instanceof ViewerActionBuilder)) {
+			object = new ViewerActionBuilder();
+			staticActionBuilders.put(menuId, (ViewerActionBuilder) object);
+		}
+		final ViewerActionBuilder staticActionBuilder = (ViewerActionBuilder) object;
+		staticActionBuilder.readViewerContributions(menuId, selProvider, part);
+	}
+
+    /**
+     * Dispose of the menu extender. Should only be called when the part
+     * is disposed.
+     */
+    public void dispose() {
+		clearStaticActions();
+		Platform.getExtensionRegistry().removeRegistryChangeListener(this);
+		menu.removeMenuListener(this);
+
+		if (menuModel != null) {
+			// unlink ourselves from the renderer
+			IRendererFactory factory = modelPart.getContext().get(IRendererFactory.class);
+			AbstractPartRenderer obj = factory.getRenderer(menuModel, null);
+			if (obj instanceof MenuManagerRenderer) {
+				MenuManagerRenderer renderer = (MenuManagerRenderer) obj;
+				unlink(renderer, menuModel);
+				renderer.clearModelToManager(menuModel, menu);
+			}
+
+			modelPart.getMenus().remove(menuModel);
+		}
+	}
+
+	/**
+	 * Unlink all contribution items from the given model menu.
+	 *
+	 * @param renderer
+	 *            the renderer that is holding the links
+	 * @param menu
+	 *            the model menu whose children should have its items unlinked
+	 *            from their corresponding contribution items
+	 */
+	private void unlink(MenuManagerRenderer renderer, MMenu menu) {
+		for (MMenuElement menuElement : menu.getChildren()) {
+			if (OpaqueElementUtil.isOpaqueMenuItem(menuElement)
+					|| OpaqueElementUtil.isOpaqueMenuSeparator(menuElement)) {
+				Object item = OpaqueElementUtil.getOpaqueItem(menuElement);
+				if (item instanceof IContributionItem) {
+					renderer.clearModelToContribution(menuElement, (IContributionItem) item);
+					OpaqueElementUtil.clearOpaqueItem(menuElement);
+				}
+			} else if (menuElement instanceof MMenu) {
+				MMenu subMenu = (MMenu) menuElement;
+				unlink(renderer, subMenu);
+				MenuManager manager = renderer.getManager(subMenu);
+				if (manager != null) {
+					renderer.clearModelToManager(subMenu, manager);
+				}
+			} else {
+				IContributionItem contribution = renderer.getContribution(menuElement);
+				if (contribution != null) {
+					renderer.clearModelToContribution(menuElement, contribution);
+				}
+			}
+		}
+	}
+
+	@Override
+	public void registryChanged(final IRegistryChangeEvent event) {
+		Display display = Display.getDefault();
+		if (part != null) {
+			display = part.getSite().getPage().getWorkbenchWindow().getWorkbench().getDisplay();
+		}
+		//check the delta to see if there are any viewer contribution changes.  if so, null our builder to cause reparsing on the next menu show
+		IExtensionDelta [] deltas = event.getExtensionDeltas();
+		for (IExtensionDelta delta : deltas) {
+			IExtensionPoint extensionPoint = delta.getExtensionPoint();
+			// RAP [bm]: namespace
+			if (extensionPoint.getNamespace().equals(
+			        PlatformUI.PLUGIN_EXTENSION_NAME_SPACE)
+			        && extensionPoint.getSimpleIdentifier().equals(
+			                IWorkbenchRegistryConstants.PL_POPUP_MENU)) {
+
+				boolean clearPopups = false;
+				IConfigurationElement [] elements = delta.getExtension().getConfigurationElements();
+				for (IConfigurationElement element : elements) {
+					if (element.getName().equals(IWorkbenchRegistryConstants.TAG_VIEWER_CONTRIBUTION)) {
+						clearPopups = true;
+						break;
+					}
+				}
+
+				if (clearPopups) {
+					display.syncExec(() -> clearStaticActions());
+				}
+			}
+		}
+	}
+
+	public MenuManager getManager() {
+		return menu;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ProductInfo.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ProductInfo.java
new file mode 100644
index 0000000..38b68e3
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ProductInfo.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal;
+
+import org.eclipse.core.runtime.IProduct;
+import org.eclipse.jface.resource.ImageDescriptor;
+
+/**
+ * Stores information about the product.  This class replaces the old AboutInfo.
+ * The product information is available as strings, but is needed as URLs, etc.
+ * This class manages that translation.
+ * @since 3.0
+ */
+public class ProductInfo {
+    private IProduct product;
+
+    private String productName;
+
+    private String appName;
+
+    private ImageDescriptor[] windowImages;
+
+    private ImageDescriptor aboutImage;
+
+    private String aboutText;
+
+    public ProductInfo(IProduct product) {
+        this.product = product;
+    }
+
+    /**
+     * Returns the product name or <code>null</code>.
+     * This is shown in the window title and the About action.
+     *
+     * @return the product name, or <code>null</code>
+     */
+    public String getProductName() {
+        if (productName == null && product != null) {
+			productName = product.getName();
+		}
+        return productName;
+    }
+
+    /**
+     * Returns the application name or <code>null</code>. Note this is never
+     * shown to the user.  It is used to initialize the SWT Display.
+     * <p>
+     * On Motif, for example, this can be used to set the name used
+     * for resource lookup.
+     * </p>
+     *
+     * @return the application name, or <code>null</code>
+     *
+     * @see org.eclipse.swt.widgets.Display#setAppName
+     */
+    public String getAppName() {
+        if (appName == null && product != null) {
+			appName = ProductProperties.getAppName(product);
+		}
+        return appName;
+    }
+
+    /**
+     * Returns the descriptor for an image which can be shown in an "about" dialog
+     * for this product. Products designed to run "headless" typically would not
+     * have such an image.
+     *
+     * @return the descriptor for an about image, or <code>null</code> if none
+     */
+    public ImageDescriptor getAboutImage() {
+        if (aboutImage == null && product != null) {
+			aboutImage = ProductProperties.getAboutImage(product);
+		}
+        return aboutImage;
+    }
+
+    /**
+     * Return an array of image descriptors for the window images to use for
+     * this product. The expectations is that the elements will be the same
+     * image rendered at different sizes. Products designed to run "headless"
+     * typically would not have such images.
+     *
+     * @return an array of the image descriptors for the window images, or
+     *         <code>null</code> if none
+     */
+    public ImageDescriptor[] getWindowImages() {
+        if (windowImages == null && product != null) {
+			windowImages = ProductProperties.getWindowImages(product);
+		}
+        return windowImages;
+    }
+
+    /**
+     * Returns the text to show in an "about" dialog for this product.
+     * Products designed to run "headless" typically would not have such text.
+     *
+     * @return the about text, or <code>null</code> if none
+     */
+    public String getAboutText() {
+        if (aboutText == null && product != null) {
+			aboutText = ProductProperties.getAboutText(product);
+		}
+        return aboutText;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ProductProperties.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ProductProperties.java
new file mode 100644
index 0000000..2570faa
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ProductProperties.java
@@ -0,0 +1,348 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.MissingResourceException;
+import java.util.PropertyResourceBundle;
+
+import org.eclipse.core.runtime.IProduct;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.branding.IProductConstants;
+import org.osgi.framework.Bundle;
+
+import com.ibm.icu.text.MessageFormat;
+
+/**
+ * A class that converts the strings returned by
+ * <code>org.eclipse.core.runtime.IProduct.getProperty</code> to the
+ * appropriate class. This implementation is tightly bound to the properties
+ * provided in IProductConstants. Clients adding their own properties could
+ * choose to subclass this.
+ *
+ * @see org.eclipse.ui.branding.IProductConstants
+ * @since 3.0
+ */
+public class ProductProperties extends BrandingProperties implements
+        IProductConstants {
+
+    private final IProduct product;
+
+    private String appName;
+
+    private String aboutText;
+
+    private ImageDescriptor aboutImageDescriptor;
+
+    private ImageDescriptor[] windowImageDescriptors;
+
+    private URL welcomePageUrl;
+
+    private String productName;
+
+    private String productId;
+
+    private static final String ABOUT_MAPPINGS = "$nl$/about.mappings"; //$NON-NLS-1$
+
+    private static HashMap mappingsMap = new HashMap(4);
+
+    private static String[] loadMappings(Bundle definingBundle) {
+        URL location = Platform.find(definingBundle, new Path(
+                ABOUT_MAPPINGS));
+        PropertyResourceBundle bundle = null;
+        InputStream is;
+        if (location != null) {
+            is = null;
+            try {
+                is = location.openStream();
+                bundle = new PropertyResourceBundle(is);
+            } catch (IOException e) {
+                bundle = null;
+            } finally {
+                try {
+                    if (is != null) {
+						is.close();
+					}
+                } catch (IOException e) {
+                    // do nothing if we fail to close
+                }
+            }
+        }
+
+        ArrayList mappingsList = new ArrayList();
+        if (bundle != null) {
+            boolean found = true;
+            int i = 0;
+            while (found) {
+                try {
+                    mappingsList.add(bundle.getString(Integer.toString(i)));
+                } catch (MissingResourceException e) {
+                    found = false;
+                }
+                i++;
+            }
+        }
+        String[] mappings = (String[]) mappingsList.toArray(new String[mappingsList.size()]);
+        mappingsMap.put(definingBundle, mappings);
+        return mappings;
+    }
+
+    private static String[] getMappings(Bundle definingBundle) {
+    	String[] mappings = (String[]) mappingsMap.get(definingBundle);
+    	if (mappings == null) {
+    		mappings = loadMappings(definingBundle);
+    	}
+    	if (mappings == null) {
+    		mappings = new String[0];
+    	}
+    	return mappings;
+    }
+
+    /**
+     * This instance will return properties from the given product.  The properties are
+     * retrieved in a lazy fashion and cached for later retrieval.
+     * @param product must not be null
+     */
+    public ProductProperties(IProduct product) {
+        if (product == null) {
+			throw new IllegalArgumentException();
+		}
+        this.product = product;
+    }
+
+    /**
+     * The application name, used to initialize the SWT Display.  This
+     * value is distinct from the string displayed in the application
+     * title bar.
+     * <p>
+     * E.g., On motif, this can be used to set the name used for
+     * resource lookup.
+     * </p>
+     * @see org.eclipse.swt.widgets.Display#setAppName
+     */
+    public String getAppName() {
+        if (appName == null) {
+			appName = getAppName(product);
+		}
+        return appName;
+    }
+
+    /**
+     * The text to show in an "about" dialog for this product.
+     * Products designed to run "headless" typically would not
+     * have such text.
+     */
+    public String getAboutText() {
+        if (aboutText == null) {
+			aboutText = getAboutText(product);
+		}
+        return aboutText;
+    }
+
+    /**
+     * An image which can be shown in an "about" dialog for this
+     * product. Products designed to run "headless" typically would not
+     * have such an image.
+     * <p>
+     * A full-sized product image (no larger than 500x330 pixels) is
+     * shown without the "aboutText" blurb.  A half-sized product image
+     * (no larger than 250x330 pixels) is shown with the "aboutText"
+     * blurb beside it.
+     */
+    public ImageDescriptor getAboutImage() {
+        if (aboutImageDescriptor == null) {
+			aboutImageDescriptor = getAboutImage(product);
+		}
+        return aboutImageDescriptor;
+    }
+
+    /**
+     * An array of one or more images to be used for this product.  The
+     * expectation is that the array will contain the same image rendered
+     * at different sizes (16x16 and 32x32).
+     * Products designed to run "headless" typically would not have such images.
+     * <p>
+     * If this property is given, then it supercedes <code>WINDOW_IMAGE</code>.
+     * </p>
+     */
+    public ImageDescriptor[] getWindowImages() {
+        if (windowImageDescriptors == null) {
+			windowImageDescriptors = getWindowImages(product);
+		}
+        return windowImageDescriptors;
+    }
+
+    /**
+     * Location of the product's welcome page (special XML-based format), either
+     * a fully qualified valid URL or a path relative to the product's defining
+     * bundle. Products designed to run "headless" typically would not have such
+     * a page. Use of this property is discouraged in 3.0, the new
+     * org.eclipse.ui.intro extension point should be used instead.
+     */
+    public URL getWelcomePageUrl() {
+        if (welcomePageUrl == null) {
+			welcomePageUrl = getWelcomePageUrl(product);
+		}
+        return welcomePageUrl;
+    }
+
+    /**
+     * Returns the product name or <code>null</code>.
+     * This is shown in the window title and the About action.
+     */
+    public String getProductName() {
+        if (productName == null) {
+			productName = getProductName(product);
+		}
+        return productName;
+    }
+
+    /**
+     * Returns the id for the product or <code>null</code> if none.
+     */
+    public String getProductId() {
+        if (productId == null) {
+			productId = getProductId(product);
+		}
+        return productId;
+    }
+
+    /**
+     * The application name, used to initialize the SWT Display.  This
+     * value is distinct from the string displayed in the application
+     * title bar.
+     * <p>
+     * E.g., On motif, this can be used to set the name used for
+     * resource lookup.
+     * </p>
+     * <p>
+     * The returned value will have {n} values substituted based on the
+     * current product's mappings regardless of the given product argument.
+     * </p>
+     * @see org.eclipse.swt.widgets.Display#setAppName
+     */
+    public static String getAppName(IProduct product) {
+        String property = product.getProperty(APP_NAME);
+        if (property == null) {
+			return ""; //$NON-NLS-1$
+		}
+        if (property.indexOf('{') == -1) {
+			return property;
+		}
+        String[] mappings = getMappings(product.getDefiningBundle());
+		return MessageFormat.format(property, (Object[]) mappings);
+    }
+
+    /**
+     * The text to show in an "about" dialog for this product.
+     * Products designed to run "headless" typically would not
+     * have such text.
+     * <p>
+     * The returned value will have {n} values substituted based on the
+     * current product's mappings regardless of the given product argument.
+     * </p>
+     */
+    public static String getAboutText(IProduct product) {
+        String property = product.getProperty(ABOUT_TEXT);
+        if (property == null) {
+			return ""; //$NON-NLS-1$
+		}
+        if (property.indexOf('{') == -1) {
+			return property;
+		}
+        String[] tempMappings = getMappings(product.getDefiningBundle());
+                /*
+    	 * Check if the mapping value is a system property, specified
+    	 * by '$' at the beginning and end of the string.  If so, update
+    	 * the mappings array with the system property value.
+    	 */
+        for (int i=0; i<tempMappings.length; i++) {
+        	String nextString = tempMappings[i];
+        	int length = nextString.length();
+
+        	if (length > 2 && nextString.charAt(0) == '$' && nextString.charAt(length-1) == '$') {
+        		String systemPropertyKey = nextString.substring(1, length-1);
+        		// If system property is not set, insert an empty String
+        		tempMappings[i] = System.getProperty(systemPropertyKey, ""); //$NON-NLS-1$;
+        	}
+        }
+
+		return MessageFormat.format(property, (Object[]) tempMappings);
+    }
+
+    /**
+     * An image which can be shown in an "about" dialog for this
+     * product. Products designed to run "headless" typically would not
+     * have such an image.
+     * <p>
+     * A full-sized product image (no larger than 500x330 pixels) is
+     * shown without the "aboutText" blurb.  A half-sized product image
+     * (no larger than 250x330 pixels) is shown with the "aboutText"
+     * blurb beside it.
+     */
+    public static ImageDescriptor getAboutImage(IProduct product) {
+        return getImage(product.getProperty(ABOUT_IMAGE), product
+                .getDefiningBundle());
+    }
+
+    /**
+     * An array of one or more images to be used for this product.  The
+     * expectation is that the array will contain the same image rendered
+     * at different sizes (16x16 and 32x32).
+     * Products designed to run "headless" typically would not have such images.
+     * <p>
+     * If this property is given, then it supercedes <code>WINDOW_IMAGE</code>.
+     * </p>
+     */
+    public static ImageDescriptor[] getWindowImages(IProduct product) {
+        String property = product.getProperty(WINDOW_IMAGES);
+
+        // for compatibility with pre-3.0 plugins that may still use WINDOW_IMAGE
+        if (property == null) {
+			property = product.getProperty(WINDOW_IMAGE);
+		}
+
+        return getImages(property, product.getDefiningBundle());
+    }
+
+    /**
+     * Location of the product's welcome page (special XML-based format), either
+     * a fully qualified valid URL or a path relative to the product's defining
+     * bundle. Products designed to run "headless" typically would not have such
+     * a page. Use of this property is discouraged in 3.0, the new
+     * org.eclipse.ui.intro extension point should be used instead.
+     */
+    public static URL getWelcomePageUrl(IProduct product) {
+        return getUrl(product.getProperty(WELCOME_PAGE), product
+                .getDefiningBundle());
+    }
+
+    /**
+     * Returns the product name or <code>null</code>.
+     * This is shown in the window title and the About action.
+     */
+    public static String getProductName(IProduct product) {
+        return product.getName();
+    }
+
+    /**
+     * Returns the id for the product.
+     */
+    public static String getProductId(IProduct product) {
+        return product.getId();
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/RadioMenu.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/RadioMenu.java
new file mode 100644
index 0000000..c75f99c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/RadioMenu.java
@@ -0,0 +1,133 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+
+/**
+ * Represents a group of radio buttons in a menu. Each menu item
+ * is mapped onto a particular value. The RadioMenu reports its state
+ * using the attached Model object. That is, Model.getState() will
+ * return the value of the currently selected radio button and Model.setState(value)
+ * will select the radio button associated with the given value.
+ */
+public class RadioMenu implements IChangeListener {
+
+    private Model data;
+
+    private Menu parent;
+
+    private List items = new ArrayList();
+
+	SelectionListener selectionAdapter = new SelectionAdapter()
+    {
+	    public void widgetSelected(SelectionEvent e) {
+	        Object newState = e.widget.getData();
+	        
+	        data.setState(newState, RadioMenu.this);
+	    }
+	};
+
+    /**
+     * Creates a set of radio menu items on the given menu.
+     *
+     * @param parent menu that will contain the menu items
+     * @param newData the model that will store the value of the currently selected item
+     */
+    public RadioMenu(Menu parent, Model newData) {
+        this.parent = parent;
+        this.data = newData;
+
+        newData.addChangeListener(this);
+    }
+
+    /**
+     * Returns true iff the given values are considered equal.
+     *
+     * @param value1
+     * @param value2
+     * @return
+     */
+    private static boolean isEqual(Object value1, Object value2) {
+        if (value1 == null) {
+            return value2 == null;
+        } else if (value2 == null) {
+            return false;
+        }
+
+        return value1.equals(value2);
+    }
+
+    /**
+     * Creates a new menu item with the given text and value. When
+     * the item is selected, the state of the model will change to
+     * match the given value.
+     *
+     * @param text
+     * @param value
+     */
+    public void addMenuItem(String text, Object value) {
+        MenuItem newItem = new MenuItem(parent, SWT.RADIO);
+
+        newItem.setSelection(isEqual(data.getState(), value));
+        newItem.setText(text);
+        newItem.setData(value);
+        items.add(newItem);
+
+        newItem.addSelectionListener(selectionAdapter);
+    }
+
+    /**
+     * Disposes all menu items
+     */
+    public void dispose() {
+        Iterator iter = items.iterator();
+        while (iter.hasNext()) {
+            MenuItem next = (MenuItem) iter.next();
+
+            if (!next.isDisposed()) {
+                next.removeSelectionListener(selectionAdapter);
+                next.dispose();
+            }
+        }
+
+        items.clear();
+    }
+
+    /**
+     * Refreshes the selected menu items to match the current state of the model.
+     */
+    private void refreshSelection() {
+        Iterator iter = items.iterator();
+        while (iter.hasNext()) {
+            MenuItem next = (MenuItem) iter.next();
+
+            if (!next.isDisposed()) {
+                next.setSelection(isEqual(data.getState(), next.getData()));
+            }
+        }
+    }
+
+    @Override
+	public void update(boolean changed) {
+        refreshSelection();
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/RectangleAnimationFeedbackBase.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/RectangleAnimationFeedbackBase.java
new file mode 100644
index 0000000..4c1d7a3
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/RectangleAnimationFeedbackBase.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.jface.util.Geometry;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.internal.AnimationEngine;
+import org.eclipse.ui.internal.AnimationFeedbackBase;
+
+/**
+ * RectangleAnimationFeedbackBase is an abstract base class for all the
+ * rectangle animations.
+ * @since 3.3
+ *
+ */
+public abstract class RectangleAnimationFeedbackBase extends AnimationFeedbackBase {
+
+	private List startRects = new ArrayList();
+	private List endRects = new ArrayList();
+
+	/**
+	 * Creates a Rectangle Animation Feedback
+	 *
+	 * @param parentShell specifies the composite where the animation will be drawn
+	 * @param start initial rectangle (display coordinates)
+	 * @param end final rectangle (display coordinates)
+	 */
+	public RectangleAnimationFeedbackBase(Shell parentShell, Rectangle start,
+			Rectangle end) {
+		super(parentShell);
+		addStartRect(start);
+		addEndRect(end);
+	}
+
+	@Override
+	public boolean jobInit(AnimationEngine engine) {
+		if (!super.jobInit(engine))
+			return false;
+
+		return startRects.size() > 0 && startRects.size() == endRects.size();
+	}
+
+	public void addStartRect(Rectangle rect) {
+		if (rect != null) {
+			startRects.add(rect);
+		}
+	}
+
+	public void addEndRect(Rectangle rect) {
+		if (rect != null) {
+			endRects.add(rect);
+		}
+	}
+
+    public void addStartRect(Control ctrl) {
+    	Rectangle ctrlBounds = ctrl.getBounds();
+    	Rectangle startRect = Geometry.toDisplay(ctrl.getParent(), ctrlBounds);
+    	addStartRect(startRect);
+    }
+
+    public void addEndRect(Control ctrl) {
+    	Rectangle ctrlBounds = ctrl.getBounds();
+    	Rectangle endRect = Geometry.toDisplay(ctrl.getParent(), ctrlBounds);
+    	addEndRect(endRect);
+    }
+
+	public static Rectangle interpolate(Rectangle start, Rectangle end,
+			double amount) {
+		double initialWeight = 1.0 - amount;
+
+		Rectangle result = new Rectangle((int) (start.x * initialWeight + end.x
+				* amount), (int) (start.y * initialWeight + end.y * amount),
+				(int) (start.width * initialWeight + end.width * amount),
+				(int) (start.height * initialWeight + end.height * amount));
+
+		return result;
+	}
+
+	public List getStartRects() {
+		return startRects;
+	}
+
+	public List getEndRects() {
+		return endRects;
+	}
+
+	public List getCurrentRects(double amount) {
+		List currentRects = new ArrayList();
+		Iterator startIter = getStartRects().iterator();
+		Iterator endIter = getEndRects().iterator();
+		while (startIter.hasNext()) {
+			Rectangle start = (Rectangle) startIter.next();
+			Rectangle end = (Rectangle) endIter.next();
+
+			// Get the bounds of the interpolated rect
+			Rectangle curRect = interpolate(start, end, amount);
+			currentRects.add(curRect);
+		}
+		return currentRects;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ReferenceCounter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ReferenceCounter.java
new file mode 100644
index 0000000..08c3772
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ReferenceCounter.java
@@ -0,0 +1,176 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A ReferenceCounter is used to reference counting objects.
+ * Each object is identified by a unique ID.  Together they form
+ * an ID - value pair. An object is added to the counter by calling
+ * #put(id, object).  From this point on additional refs can be made
+ * by calling #addRef(id) or #removeRef(id).
+ */
+public class ReferenceCounter {
+    private Map mapIdToRec = new HashMap(11);
+
+    /**
+     * Capture the information about an object.
+     */
+    public class RefRec {
+        public RefRec(Object id, Object value) {
+            this.id = id;
+            this.value = value;
+            addRef();
+        }
+
+        public Object getId() {
+            return id;
+        }
+
+        public Object getValue() {
+            return value;
+        }
+
+        public int addRef() {
+            ++refCount;
+            return refCount;
+        }
+
+        public int removeRef() {
+            --refCount;
+            return refCount;
+        }
+
+        public int getRef() {
+            return refCount;
+        }
+
+        public boolean isNotReferenced() {
+            return (refCount <= 0);
+        }
+
+        public Object id;
+
+        public Object value;
+
+        private int refCount;
+    }
+
+    /**
+     * Creates a new counter.
+     */
+    public ReferenceCounter() {
+        super();
+    }
+
+    /**
+     * Adds one reference to an object in the counter.
+     *
+     * @param id is a unique ID for the object.
+     * @return the new ref count
+     */
+    public int addRef(Object id) {
+        RefRec rec = (RefRec) mapIdToRec.get(id);
+        if (rec == null) {
+			return 0;
+		}
+        return rec.addRef();
+    }
+
+    /**
+     * Returns the object defined by an ID.  If the ID is not
+     * found <code>null</code> is returned.
+     *
+     * @return the object or <code>null</code>
+     */
+    public Object get(Object id) {
+        RefRec rec = (RefRec) mapIdToRec.get(id);
+        if (rec == null) {
+			return null;
+		}
+        return rec.getValue();
+    }
+
+    /**
+     * Returns a complete list of the keys in the counter.
+     *
+     * @return a Set containing the ID for each.
+     */
+    public Set keySet() {
+        return mapIdToRec.keySet();
+    }
+
+    /**
+     * Adds an object to the counter for counting and gives
+     * it an initial ref count of 1.
+     *
+     * @param id is a unique ID for the object.
+     * @param value is the object itself.
+     */
+    public void put(Object id, Object value) {
+        RefRec rec = new RefRec(id, value);
+        mapIdToRec.put(id, rec);
+    }
+
+    /**
+     * @param id is a unique ID for the object.
+     * @return the current ref count
+     */
+    public int getRef(Object id) {
+        RefRec rec = (RefRec) mapIdToRec.get(id);
+        if (rec == null) {
+			return 0;
+		}
+        return rec.refCount;
+    }
+
+    /**
+     * Removes one reference from an object in the counter.
+     * If the ref count drops to 0 the object is removed from
+     * the counter completely.
+     *
+     * @param id is a unique ID for the object.
+     * @return the new ref count
+     */
+    public int removeRef(Object id) {
+    	RefRec rec = (RefRec) mapIdToRec.get(id);
+    	if (rec == null) {
+    		return 0;
+    	}
+    	int newCount = rec.removeRef();
+    	if (newCount <= 0) {
+    		mapIdToRec.remove(id);
+    	}
+    	return newCount;
+    }
+
+    /**
+     * Returns a complete list of the values in the counter.
+     *
+     * @return a Collection containing the values.
+     */
+    public List values() {
+        int size = mapIdToRec.size();
+        ArrayList list = new ArrayList(size);
+        Iterator iter = mapIdToRec.values().iterator();
+        while (iter.hasNext()) {
+            RefRec rec = (RefRec) iter.next();
+            list.add(rec.getValue());
+        }
+        return list;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ReopenEditorMenu.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ReopenEditorMenu.java
new file mode 100644
index 0000000..cc27f2a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ReopenEditorMenu.java
@@ -0,0 +1,290 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.jface.action.ContributionItem;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.util.SafeRunnable;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.osgi.util.TextProcessor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.ui.IEditorDescriptor;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PartInitException;
+
+/**
+ * A dynamic menu item which supports to switch to other Windows.
+ */
+public class ReopenEditorMenu extends ContributionItem {
+    private IWorkbenchWindow window;
+
+    private EditorHistory history;
+
+    private boolean showSeparator;
+
+    // the maximum length for a file name; must be >= 4
+    private static final int MAX_TEXT_LENGTH = 40;
+
+    // only assign mnemonic to the first nine items
+    private static final int MAX_MNEMONIC_SIZE = 9;
+
+    /**
+     * Create a new instance.
+     * @param window the window on which the menu is to be created
+     * @param id menu's id
+     * @param showSeparator whether or not to show a separator
+     */
+    public ReopenEditorMenu(IWorkbenchWindow window, String id,
+            boolean showSeparator) {
+        super(id);
+        this.window = window;
+        this.showSeparator = showSeparator;
+        IWorkbench workbench = window.getWorkbench();
+		if (workbench instanceof Workbench) {
+			history = ((Workbench) workbench).getEditorHistory();
+		}
+    }
+
+    /**
+     * Returns the text for a history item.  This may be truncated to fit
+     * within the MAX_TEXT_LENGTH.
+     */
+    private String calcText(int index, EditorHistoryItem item) {
+		// IMPORTANT: avoid accessing the item's input since
+		// this can require activating plugins.
+		// Instead, ask the item for the info, which can
+		// consult its memento if it is not restored yet.
+    	// RAP [bm] SWT.RIGHT_TO_LEFT
+//		return calcText(index, item.getName(), item.getToolTipText(), Window
+//				.getDefaultOrientation() == SWT.RIGHT_TO_LEFT);
+    	return calcText(index, item.getName(), item.getToolTipText(), false);
+	}
+
+    /**
+     * Return a string suitable for a file MRU list.  This should not be called
+     * outside the framework.
+     *
+     * @param index the index in the MRU list
+     * @param name the file name
+     * @param toolTip potentially the path
+     * @param rtl should it be right-to-left
+     * @return a string suitable for an MRU file menu
+     */
+    public static String calcText(int index, String name, String toolTip, boolean rtl) {
+        StringBuffer sb = new StringBuffer();
+
+        int mnemonic = index + 1;
+        StringBuffer nm = new StringBuffer();
+        nm.append(mnemonic);
+        if (mnemonic <= MAX_MNEMONIC_SIZE) {
+        	nm.insert(nm.length() - (mnemonic + "").length(), '&'); //$NON-NLS-1$
+        }
+//        sb.append(" "); //$NON-NLS-1$
+
+        String fileName = name;
+        String pathName = toolTip;
+        if (pathName.equals(fileName)) {
+            // tool tip text isn't necessarily a path;
+            // sometimes it's the same as name, so it shouldn't be treated as a path then
+            pathName = ""; //$NON-NLS-1$
+        }
+        IPath path = new Path(pathName);
+        // if last segment in path is the fileName, remove it
+        if (path.segmentCount() > 1
+                && path.segment(path.segmentCount() - 1).equals(fileName)) {
+            path = path.removeLastSegments(1);
+            pathName = path.toString();
+        }
+
+        if ((fileName.length() + pathName.length()) <= (MAX_TEXT_LENGTH - 4)) {
+            // entire item name fits within maximum length
+            sb.append(fileName);
+            if (pathName.length() > 0) {
+                sb.append("  ["); //$NON-NLS-1$
+                sb.append(pathName);
+                sb.append("]"); //$NON-NLS-1$
+            }
+        } else {
+            // need to shorten the item name
+            int length = fileName.length();
+            if (length > MAX_TEXT_LENGTH) {
+                // file name does not fit within length, truncate it
+                sb.append(fileName.substring(0, MAX_TEXT_LENGTH - 3));
+                sb.append("..."); //$NON-NLS-1$
+            } else if (length > MAX_TEXT_LENGTH - 7) {
+                sb.append(fileName);
+            } else {
+                sb.append(fileName);
+                int segmentCount = path.segmentCount();
+                if (segmentCount > 0) {
+                    length += 7; // 7 chars are taken for "  [...]"
+
+                    sb.append("  ["); //$NON-NLS-1$
+
+                    // Add first n segments that fit
+                    int i = 0;
+                    while (i < segmentCount && length < MAX_TEXT_LENGTH) {
+                        String segment = path.segment(i);
+                        if (length + segment.length() < MAX_TEXT_LENGTH) {
+                            sb.append(segment);
+                            sb.append(IPath.SEPARATOR);
+                            length += segment.length() + 1;
+                            i++;
+                        } else if (i == 0) {
+                            // append at least part of the first segment
+                            sb.append(segment.substring(0, MAX_TEXT_LENGTH
+                                    - length));
+                            length = MAX_TEXT_LENGTH;
+                            break;
+                        } else {
+                            break;
+                        }
+                    }
+
+                    sb.append("..."); //$NON-NLS-1$
+
+                    i = segmentCount - 1;
+                    // Add last n segments that fit
+                    while (i > 0 && length < MAX_TEXT_LENGTH) {
+                        String segment = path.segment(i);
+                        if (length + segment.length() < MAX_TEXT_LENGTH) {
+                            sb.append(IPath.SEPARATOR);
+                            sb.append(segment);
+                            length += segment.length() + 1;
+                            i--;
+                        } else {
+                            break;
+                        }
+                    }
+
+                    sb.append("]"); //$NON-NLS-1$
+                }
+            }
+        }
+        final String process;
+        if (rtl) {
+        	process = sb + " " + nm; //$NON-NLS-1$
+        } else {
+        	process = nm + " " + sb; //$NON-NLS-1$
+        }
+        return TextProcessor.process(process, TextProcessor.getDefaultDelimiters() + "[]");//$NON-NLS-1$
+    }
+
+    /**
+     * Fills the given menu with
+     * menu items for all windows.
+     */
+    @Override
+	public void fill(final Menu menu, int index) {
+        if (window.getActivePage() == null
+                || window.getActivePage().getPerspective() == null) {
+            return;
+        }
+
+        int itemsToShow = WorkbenchPlugin.getDefault().getPreferenceStore()
+                .getInt(IPreferenceConstants.RECENT_FILES);
+		if (itemsToShow == 0 || history == null) {
+            return;
+        }
+
+        // Get items.
+        EditorHistoryItem[] historyItems = history.getItems();
+
+        int n = Math.min(itemsToShow, historyItems.length);
+        if (n <= 0) {
+            return;
+        }
+
+        if (showSeparator) {
+            new MenuItem(menu, SWT.SEPARATOR, index);
+            ++index;
+        }
+
+        final int menuIndex[] = new int[] { index };
+
+        for (int i = 0; i < n; i++) {
+            final EditorHistoryItem item = historyItems[i];
+            final int historyIndex = i;
+            SafeRunner.run(new SafeRunnable() {
+                @Override
+				public void run() throws Exception {
+                    String text = calcText(historyIndex, item);
+                    MenuItem mi = new MenuItem(menu, SWT.PUSH, menuIndex[0]);
+                    ++menuIndex[0];
+                    mi.setText(text);
+                    mi.addSelectionListener(new SelectionAdapter()
+                    {
+                        public void widgetSelected(SelectionEvent e) 
+                        {
+                            open(item);
+                        }
+                    });
+                }
+
+                @Override
+				public void handleException(Throwable e) {
+                    // just skip the item if there's an error,
+                    // e.g. in the calculation of the shortened name
+                    WorkbenchPlugin.log(getClass(), "fill", e); //$NON-NLS-1$
+                }
+            });
+        }
+    }
+
+    /**
+     * Overridden to always return true and force dynamic menu building.
+     */
+    @Override
+	public boolean isDynamic() {
+        return true;
+    }
+
+    /**
+     * Reopens the editor for the given history item.
+     */
+    private void open(EditorHistoryItem item) {
+        IWorkbenchPage page = window.getActivePage();
+        if (page != null) {
+            try {
+                String itemName = item.getName();
+                if (!item.isRestored()) {
+                    item.restoreState();
+                }
+                IEditorInput input = item.getInput();
+                IEditorDescriptor desc = item.getDescriptor();
+				if (input == null || !input.exists() || desc == null) {
+                    String title = WorkbenchMessages.get().OpenRecent_errorTitle;
+                    String msg = NLS.bind(WorkbenchMessages.get().OpenRecent_unableToOpen,  itemName );
+                    MessageDialog.openWarning(window.getShell(), title, msg);
+                    history.remove(item);
+                } else {
+                    page.openEditor(input, desc.getId());
+                }
+            } catch (PartInitException e2) {
+                String title = WorkbenchMessages.get().OpenRecent_errorTitle;
+                MessageDialog.openWarning(window.getShell(), title, e2
+                        .getMessage());
+                history.remove(item);
+            }
+        }
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ResetPerspectiveAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ResetPerspectiveAction.java
new file mode 100644
index 0000000..c76463f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ResetPerspectiveAction.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * Reset the layout within the active perspective.
+ */
+public class ResetPerspectiveAction extends PerspectiveAction {
+
+    /**
+     * This default constructor allows the the action to be called from the welcome page.
+     */
+    public ResetPerspectiveAction() {
+        this(PlatformUI.getWorkbench().getActiveWorkbenchWindow());
+    }
+
+    /**
+     * Create an instance of this class
+     * @param window the window
+     */
+    public ResetPerspectiveAction(IWorkbenchWindow window) {
+        super(window);
+        setText(WorkbenchMessages.get().ResetPerspective_text);
+        setActionDefinitionId(IWorkbenchCommandConstants.WINDOW_RESET_PERSPECTIVE);
+        // @issue missing action id
+        setToolTipText(WorkbenchMessages.get().ResetPerspective_toolTip);
+        window.getWorkbench().getHelpSystem().setHelp(this,
+				IWorkbenchHelpContextIds.RESET_PERSPECTIVE_ACTION);
+    }
+
+    @Override
+	protected void run(IWorkbenchPage page, IPerspectiveDescriptor persp) {
+        String message = NLS.bind(WorkbenchMessages.get().ResetPerspective_message, persp.getLabel() );
+        MessageDialog d = new MessageDialog(getWindow().getShell(),
+                WorkbenchMessages.get().ResetPerspective_title,
+				null, message, MessageDialog.QUESTION, new String[] { IDialogConstants.get().OK_LABEL, IDialogConstants.get().CANCEL_LABEL }, 0);
+        if (d.open() == 0) {
+			page.resetPerspective();
+		}
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/SavePerspectiveAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/SavePerspectiveAction.java
new file mode 100644
index 0000000..0e9d041
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/SavePerspectiveAction.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.internal.registry.PerspectiveDescriptor;
+
+/**
+ * Action to save the layout of the active perspective.
+ */
+public class SavePerspectiveAction extends PerspectiveAction {
+
+    /**
+     * Creates an instance of this class.
+     *
+     * @param window the workbench window in which this action appears
+     */
+    public SavePerspectiveAction(IWorkbenchWindow window) {
+        super(window);
+        setText(WorkbenchMessages.get().SavePerspective_text);
+        setActionDefinitionId(IWorkbenchCommandConstants.WINDOW_SAVE_PERSPECTIVE_AS);
+        // @issue missing action id
+        setToolTipText(WorkbenchMessages.get().SavePerspective_toolTip);
+        window.getWorkbench().getHelpSystem().setHelp(this,
+				IWorkbenchHelpContextIds.SAVE_PERSPECTIVE_ACTION);
+    }
+
+    @Override
+	protected void run(IWorkbenchPage page, IPerspectiveDescriptor persp) {
+        PerspectiveDescriptor desc = (PerspectiveDescriptor) persp;
+        if (desc != null) {
+			// saveNonSingleton(page, desc);
+        }
+    }
+
+
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/SaveableHelper.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/SaveableHelper.java
new file mode 100644
index 0000000..7d302a4
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/SaveableHelper.java
@@ -0,0 +1,500 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *     Andrey Loskutov <loskutov@gmx.de> - Bug 372799
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ *     Patrik Suzzi <psuzzi@gmail.com> - Bug 511198
+ *******************************************************************************/
+package org.eclipse.ui.internal;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.core.runtime.CoreException;
+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.SubMonitor;
+import org.eclipse.core.runtime.jobs.IJobChangeEvent;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.core.runtime.jobs.JobChangeAdapter;
+import org.eclipse.jface.action.LegacyActionTools;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.operation.IRunnableContext;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.window.IShellProvider;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.ui.ISaveablePart;
+import org.eclipse.ui.ISaveablePart2;
+import org.eclipse.ui.ISaveablesLifecycleListener;
+import org.eclipse.ui.ISaveablesSource;
+import org.eclipse.ui.ISecondarySaveableSource;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.Saveable;
+import org.eclipse.ui.internal.dialogs.EventLoopProgressMonitor;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.progress.IJobRunnable;
+import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+/**
+ * Helper class for prompting to save dirty views or editors.
+ *
+ * @since 3.0.1
+ */
+public class SaveableHelper {
+
+	/**
+	 * The helper must prompt.
+	 */
+	public static final int USER_RESPONSE = -1;
+
+	private static int AutomatedResponse = USER_RESPONSE;
+
+	/**
+	 * FOR USE BY THE AUTOMATED TEST HARNESS ONLY.
+	 *
+	 * Sets the response to use when <code>savePart</code> is called with <code>confirm=true</code>.
+	 *
+	 * @param response 0 for yes, 1 for no, 2 for cancel, -1 for default (prompt)
+	 */
+	public static void testSetAutomatedResponse(int response) {
+		AutomatedResponse = response;
+	}
+
+	/**
+	 * FOR USE BY THE AUTOMATED TEST HARNESS ONLY.
+	 *
+	 * Sets the response to use when <code>savePart</code> is called with <code>confirm=true</code>.
+	 *
+	 * @return 0 for yes, 1 for no, 2 for cancel, -1 for default (prompt)
+	 */
+	public static int testGetAutomatedResponse() {
+		return AutomatedResponse;
+	}
+
+	/**
+	 * Saves the workbench part.
+	 *
+	 * @param saveable the part
+	 * @param part the same part
+	 * @param window the workbench window
+	 * @param confirm request confirmation
+	 * @return <code>true</code> for continue, <code>false</code> if the operation
+	 * was canceled.
+	 */
+	public static boolean savePart(final ISaveablePart saveable, IWorkbenchPart part,
+			IWorkbenchWindow window, boolean confirm) {
+		// Short circuit.
+		if (!saveable.isDirty()) {
+			return true;
+		}
+
+		// If confirmation is required ..
+		if (confirm) {
+			int choice = AutomatedResponse;
+			if (choice == USER_RESPONSE) {
+				if (saveable instanceof ISaveablePart2) {
+					choice = ((ISaveablePart2)saveable).promptToSaveOnClose();
+				}
+				if (choice == USER_RESPONSE || choice == ISaveablePart2.DEFAULT) {
+					String message = NLS.bind(WorkbenchMessages.get().EditorManager_saveChangesQuestion,
+							LegacyActionTools.escapeMnemonics(part.getTitle()));
+					// Show a dialog.
+					MessageDialog d = new MessageDialog(window.getShell(),
+							WorkbenchMessages.get().Save_Resource, null, message,
+							MessageDialog.QUESTION,
+							new String[] {
+							WorkbenchMessages.get().SaveableHelper_Save, WorkbenchMessages.get().SaveableHelper_Dont_Save,
+							WorkbenchMessages.get().SaveableHelper_Cancel}, 0) {
+						@Override
+						protected int getShellStyle() {
+							return super.getShellStyle() | SWT.SHEET;
+						}
+					};
+					choice = d.open();
+				}
+			}
+
+			// Branch on the user choice.
+			// The choice id is based on the order of button labels above.
+			switch (choice) {
+				case ISaveablePart2.YES : //yes
+					break;
+				case ISaveablePart2.NO : //no
+					return true;
+				default :
+				case ISaveablePart2.CANCEL : //cancel
+					return false;
+			}
+		}
+
+		if (saveable instanceof ISaveablesSource) {
+			return saveModels((ISaveablesSource) saveable, window, confirm);
+		}
+
+		// Create save block.
+		IRunnableWithProgress progressOp = monitor -> {
+			IProgressMonitor monitorWrap = new EventLoopProgressMonitor(monitor);
+			saveable.doSave(monitorWrap);
+		};
+
+		// Do the save.
+		return runProgressMonitorOperation(WorkbenchMessages.get().Save, progressOp, window);
+	}
+
+	/**
+	 * Saves the selected dirty models from the given model source.
+	 *
+	 * @param modelSource the model source
+	 * @param window the workbench window
+	 * @param confirm
+	 * @return <code>true</code> for continue, <code>false</code> if the operation
+	 *   was canceled or an error occurred while saving.
+	 */
+	private static boolean saveModels(ISaveablesSource modelSource, final IWorkbenchWindow window, final boolean confirm) {
+		final ArrayList<Saveable> dirtyModels = new ArrayList<>();
+		for (Saveable model : modelSource.getActiveSaveables()) {
+			if (model.isDirty()) {
+				dirtyModels.add(model);
+			}
+		}
+		if (dirtyModels.isEmpty()) {
+			return true;
+		}
+
+		// Create save block.
+		IRunnableWithProgress progressOp = monitor -> {
+			IProgressMonitor monitorWrap = new EventLoopProgressMonitor(monitor);
+			SubMonitor subMonitor = SubMonitor.convert(monitorWrap, WorkbenchMessages.get().Save, dirtyModels.size());
+			try {
+				for (Saveable model : dirtyModels) {
+					// handle case where this model got saved as a result of
+					// saving another
+					if (!model.isDirty()) {
+						subMonitor.worked(1);
+						continue;
+					}
+					doSaveModel(model, subMonitor.split(1), window, confirm);
+					if (subMonitor.isCanceled()) {
+						break;
+					}
+				}
+			} finally {
+				monitorWrap.done();
+			}
+		};
+
+		// Do the save.
+		return runProgressMonitorOperation(WorkbenchMessages.get().Save, progressOp, window);
+	}
+
+	/**
+	 * Saves the workbench part ... this is similar to
+	 * {@link SaveableHelper#savePart(ISaveablePart, IWorkbenchPart, IWorkbenchWindow, boolean) }
+	 * except that the {@link ISaveablePart2#DEFAULT } case must cause the
+	 * calling function to allow this part to participate in the default saving
+	 * mechanism.
+	 *
+	 * @param saveable the part
+	 * @param window the workbench window
+	 * @param confirm request confirmation
+	 * @return the ISaveablePart2 constant
+	 */
+	static int savePart(final ISaveablePart2 saveable,
+			IWorkbenchWindow window, boolean confirm) {
+		// Short circuit.
+		if (!saveable.isDirty()) {
+			return ISaveablePart2.YES;
+		}
+
+		// If confirmation is required ..
+		if (confirm) {
+			int choice = AutomatedResponse;
+			if (choice == USER_RESPONSE) {
+				choice = saveable.promptToSaveOnClose();
+			}
+
+			// Branch on the user choice.
+			// The choice id is based on the order of button labels above.
+			if (choice!=ISaveablePart2.YES) {
+				return (choice==USER_RESPONSE?ISaveablePart2.DEFAULT:choice);
+			}
+		}
+
+		// Create save block.
+		IRunnableWithProgress progressOp = monitor -> {
+			IProgressMonitor monitorWrap = new EventLoopProgressMonitor(monitor);
+			saveable.doSave(monitorWrap);
+		};
+
+		// Do the save.
+		if (!runProgressMonitorOperation(WorkbenchMessages.get().Save, progressOp,window)) {
+			return ISaveablePart2.CANCEL;
+		}
+		return ISaveablePart2.YES;
+	}
+
+	/**
+	 * Runs a progress monitor operation. Returns true if success, false if
+	 * canceled.
+	 */
+	static boolean runProgressMonitorOperation(String opName,
+			IRunnableWithProgress progressOp, IWorkbenchWindow window) {
+		return runProgressMonitorOperation(opName, progressOp, window, window);
+	}
+
+	/**
+	 * Runs a progress monitor operation.
+	 * Returns true if success, false if canceled or an error occurred.
+	 */
+	static boolean runProgressMonitorOperation(String opName,
+			final IRunnableWithProgress progressOp,
+			final IRunnableContext runnableContext, final IShellProvider shellProvider) {
+		final boolean[] success = new boolean[] { false };
+		IRunnableWithProgress runnable = monitor -> {
+			progressOp.run(monitor);
+			// Only indicate success if the monitor wasn't canceled
+			if (!monitor.isCanceled())
+				success[0] = true;
+		};
+
+		try {
+			runnableContext.run(false, true, runnable);
+		} catch (InvocationTargetException e) {
+			String title = NLS.bind(WorkbenchMessages.get().EditorManager_operationFailed, opName );
+			Throwable targetExc = e.getTargetException();
+			WorkbenchPlugin.log(title, new Status(IStatus.WARNING,
+					PlatformUI.PLUGIN_ID, 0, title, targetExc));
+			StatusUtil.handleStatus(title, targetExc, StatusManager.SHOW,
+					shellProvider.getShell());
+			// Fall through to return failure
+		} catch (InterruptedException e) {
+			// The user pressed cancel. Fall through to return failure
+		} catch (OperationCanceledException e) {
+			// The user pressed cancel. Fall through to return failure
+		}
+		return success[0];
+	}
+
+	/**
+	 * Returns whether the model source needs saving. This is true if any of
+	 * the active models are dirty. This logic must correspond with
+	 * {@link #saveModels} above.
+	 *
+	 * @param modelSource
+	 *            the model source
+	 * @return <code>true</code> if save is required, <code>false</code>
+	 *         otherwise
+	 * @since 3.2
+	 */
+	public static boolean needsSave(ISaveablesSource modelSource) {
+		for (Saveable model : modelSource.getActiveSaveables()) {
+			if (model.isDirty() && !((InternalSaveable)model).isSavingInBackground()) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * @param model
+	 * @param progressMonitor
+	 * @param shellProvider
+	 * @param blockUntilSaved
+	 */
+	public static void doSaveModel(final Saveable model,
+			IProgressMonitor progressMonitor,
+			final IShellProvider shellProvider, boolean blockUntilSaved) {
+		try {
+			Job backgroundSaveJob = ((InternalSaveable)model).getBackgroundSaveJob();
+			if (backgroundSaveJob != null) {
+				boolean canceled = waitForBackgroundSaveJob(model);
+				if (canceled) {
+					progressMonitor.setCanceled(true);
+					return;
+				}
+				// return early if the saveable is no longer dirty
+				if (!model.isDirty()) {
+					return;
+				}
+			}
+			final IJobRunnable[] backgroundSaveRunnable = new IJobRunnable[1];
+			try {
+				SubMonitor subMonitor = SubMonitor.convert(progressMonitor, 3);
+				backgroundSaveRunnable[0] = model.doSave(subMonitor.split(2), shellProvider);
+				if (backgroundSaveRunnable[0] == null) {
+					// no further work needs to be done
+					return;
+				}
+				if (blockUntilSaved) {
+					// for now, block on close by running the runnable in the UI
+					// thread
+					IStatus result = backgroundSaveRunnable[0].run(subMonitor.split(1));
+					if (!result.isOK()) {
+						StatusUtil.handleStatus(result, StatusManager.SHOW, shellProvider.getShell());
+						progressMonitor.setCanceled(true);
+					}
+					return;
+				}
+				// for the job family, we use the model object because based on
+				// the family we can display the busy state with an animated tab
+				// (see the calls to showBusyForFamily() below).
+				Job saveJob = new Job(
+						NLS.bind(WorkbenchMessages.get().EditorManager_backgroundSaveJobName, model.getName())) {
+					@Override
+					public boolean belongsTo(Object family) {
+						if (family instanceof DynamicFamily) {
+							return ((DynamicFamily)family).contains(model);
+						}
+						return family.equals(model);
+					}
+
+					@Override
+					protected IStatus run(IProgressMonitor monitor) {
+						return backgroundSaveRunnable[0].run(monitor);
+					}
+				};
+				// we will need the associated parts (for disabling their UI)
+				((InternalSaveable) model).setBackgroundSaveJob(saveJob);
+				SaveablesList saveablesList = (SaveablesList) PlatformUI.getWorkbench()
+						.getService(ISaveablesLifecycleListener.class);
+				final IWorkbenchPart[] parts = saveablesList.getPartsForSaveable(model);
+
+				// this will cause the parts tabs to show the ongoing background operation
+				for (IWorkbenchPart workbenchPart : parts) {
+					IWorkbenchSiteProgressService progressService = Adapters.adapt(workbenchPart.getSite(),
+							IWorkbenchSiteProgressService.class);
+					progressService.showBusyForFamily(model);
+				}
+				model.disableUI(parts, blockUntilSaved);
+				// Add a listener for enabling the UI after the save job has
+				// finished, and for displaying an error dialog if
+				// necessary.
+				saveJob.addJobChangeListener(new JobChangeAdapter() {
+					@Override
+					public void done(final IJobChangeEvent event) {
+						((InternalSaveable) model).setBackgroundSaveJob(null);
+						shellProvider.getShell().getDisplay().asyncExec(
+								() -> {
+									notifySaveAction(parts);
+									model.enableUI(parts);
+								});
+					}
+				});
+				// Finally, we are ready to schedule the job.
+				saveJob.schedule();
+				// the job was started - notify the save actions,
+				// this is done through the workbench windows, which
+				// we can get from the parts...
+				notifySaveAction(parts);
+			} catch (CoreException e) {
+				StatusUtil.handleStatus(e.getStatus(), StatusManager.SHOW, shellProvider.getShell());
+				progressMonitor.setCanceled(true);
+			}
+		} finally {
+			progressMonitor.done();
+		}
+	}
+
+	private static void notifySaveAction(final IWorkbenchPart[] parts) {
+		Set<IWorkbenchWindow> wwindows = new HashSet<>();
+		for (IWorkbenchPart part : parts) {
+			wwindows.add(part.getSite().getWorkbenchWindow());
+		}
+		for (IWorkbenchWindow iWorkbenchWindow : wwindows) {
+			WorkbenchWindow wwin = (WorkbenchWindow) iWorkbenchWindow;
+			wwin.fireBackgroundSaveStarted();
+		}
+	}
+
+	/**
+	 * Waits for the background save job (if any) of the given saveable to complete.
+	 * This may open a progress dialog with the option to cancel.
+	 *
+	 * @param modelToSave
+	 * @return true if the user canceled.
+	 */
+	private static boolean waitForBackgroundSaveJob(final Saveable model) {
+		List<Saveable> models = new ArrayList<>();
+		models.add(model);
+		return waitForBackgroundSaveJobs(models);
+	}
+
+	/**
+	 * Waits for the background save jobs (if any) of the given saveables to complete.
+	 * This may open a progress dialog with the option to cancel.
+	 *
+	 * @param modelsToSave
+	 * @return true if the user canceled.
+	 */
+	public static boolean waitForBackgroundSaveJobs(final List modelsToSave) {
+		// block if any of the saveables is still saving in the background
+		try {
+			PlatformUI.getWorkbench().getProgressService().busyCursorWhile(monitor -> Job.getJobManager().join(new DynamicFamily(modelsToSave), monitor));
+		} catch (InvocationTargetException e) {
+			StatusUtil.handleStatus(e, StatusManager.SHOW | StatusManager.LOG);
+		} catch (InterruptedException e) {
+			return true;
+		}
+		// remove saveables that are no longer dirty from the list
+		for (Iterator<?> it = modelsToSave.iterator(); it.hasNext();) {
+			Saveable model = (Saveable) it.next();
+			if (!model.isDirty()) {
+				it.remove();
+			}
+		}
+		return false;
+	}
+
+	private static class DynamicFamily extends HashSet<Object> {
+		private static final long serialVersionUID = 1L;
+
+		public DynamicFamily(Collection<?> collection) {
+			super(collection);
+		}
+	}
+
+	public static ISaveablePart getSaveable(Object o) {
+		return Adapters.adapt(o, ISaveablePart.class);
+	}
+
+	public static boolean isSaveable(Object o) {
+		return getSaveable(o) != null;
+	}
+
+	public static ISaveablePart2 getSaveable2(Object o) {
+		ISaveablePart saveable = getSaveable(o);
+		if (saveable instanceof ISaveablePart2) {
+			return (ISaveablePart2) saveable;
+		}
+		return Adapters.adapt(o, ISaveablePart2.class);
+	}
+
+	public static boolean isSaveable2(Object o) {
+		return getSaveable2(o) != null;
+	}
+
+	public static boolean isDirtyStateSupported(IWorkbenchPart part) {
+		if (part instanceof ISecondarySaveableSource) {
+			return ((ISecondarySaveableSource) part).isDirtyStateSupported();
+		}
+		return isSaveable(part);
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/SaveablesList.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/SaveablesList.java
new file mode 100644
index 0000000..90f5f47
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/SaveablesList.java
@@ -0,0 +1,853 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *     Andrey Loskutov <loskutov@gmx.de> - Bug 372799
+ *     Patrik Suzzi <psuzzi@gmail.com> - Bug 490700, 511198
+ *******************************************************************************/
+
+package org.eclipse.ui.internal;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.AssertionFailedException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.dialogs.MessageDialogWithToggle;
+import org.eclipse.jface.operation.IRunnableContext;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.window.IShellProvider;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.ISaveablePart;
+import org.eclipse.ui.ISaveablePart2;
+import org.eclipse.ui.ISaveablesLifecycleListener;
+import org.eclipse.ui.ISaveablesSource;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPreferenceConstants;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.Saveable;
+import org.eclipse.ui.SaveablesLifecycleEvent;
+import org.eclipse.ui.dialogs.ListSelectionDialog;
+import org.eclipse.ui.internal.dialogs.EventLoopProgressMonitor;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.internal.util.PrefUtil;
+import org.eclipse.ui.model.WorkbenchPartLabelProvider;
+
+/**
+ * The model manager maintains a list of open saveable models.
+ *
+ * @see Saveable
+ * @see ISaveablesSource
+ *
+ * @since 3.2
+ */
+public class SaveablesList implements ISaveablesLifecycleListener {
+
+	private ListenerList<ISaveablesLifecycleListener> listeners = new ListenerList<>();
+
+	// event source (mostly ISaveablesSource) -> Set of Saveable
+	private Map<Object, Set<Saveable>> modelMap = new HashMap<>();
+
+	// reference counting map
+	private Map<Saveable, Integer> modelRefCounts = new HashMap<>();
+
+	private Set<ISaveablesSource> nonPartSources = new HashSet<>();
+
+	/**
+	 * Returns the list of open models managed by this model manager.
+	 *
+	 * @return a list of models
+	 */
+	public Saveable[] getOpenModels() {
+		Set<Saveable> allDistinctModels = new HashSet<>();
+		Iterator<Set<Saveable>> saveables = modelMap.values().iterator();
+		while (saveables.hasNext()) {
+			allDistinctModels.addAll(saveables.next());
+		}
+
+		return allDistinctModels.toArray(
+				new Saveable[allDistinctModels.size()]);
+	}
+
+	// returns true if this model has not yet been in getModels()
+	private boolean addModel(Object source, Saveable model) {
+		if (model == null) {
+			logWarning(
+					"Ignored attempt to add invalid saveable", source, model); //$NON-NLS-1$
+			return false;
+		}
+		boolean result = false;
+		Set<Saveable> modelsForSource = modelMap.get(source);
+		if (modelsForSource == null) {
+			modelsForSource = new HashSet<>();
+			modelMap.put(source, modelsForSource);
+		}
+		if (modelsForSource.add(model)) {
+			result = incrementRefCount(modelRefCounts, model);
+		} else {
+			logWarning(
+					"Ignored attempt to add saveable that was already registered", source, model); //$NON-NLS-1$
+		}
+		return result;
+	}
+
+	/**
+	 * returns true if the given key was added for the first time
+	 *
+	 * @param referenceMap
+	 * @param key
+	 * @return true if the ref count of the given key is now 1
+	 */
+	private boolean incrementRefCount(Map<Saveable, Integer> referenceMap, Saveable key) {
+		boolean result = false;
+		Integer refCount = referenceMap.get(key);
+		if (refCount == null) {
+			result = true;
+			refCount = Integer.valueOf(0);
+		}
+		referenceMap.put(key, Integer.valueOf(refCount.intValue() + 1));
+		return result;
+	}
+
+	/**
+	 * returns true if the given key has been removed
+	 *
+	 * @param referenceMap
+	 * @param key
+	 * @return true if the ref count of the given key was 1
+	 */
+	private boolean decrementRefCount(Map<Saveable, Integer> referenceMap, Saveable key) {
+		boolean result = false;
+		Integer refCount = referenceMap.get(key);
+		if (refCount == null)
+			Assert.isTrue(false, key + ": " + key.getName()); //$NON-NLS-1$
+		if (refCount.intValue() == 1) {
+			referenceMap.remove(key);
+			result = true;
+		} else {
+			referenceMap.put(key, Integer.valueOf(refCount.intValue() - 1));
+		}
+		return result;
+	}
+
+	// returns true if this model was removed from getModels();
+	private boolean removeModel(Object source, Saveable model) {
+		boolean result = false;
+		Set<Saveable> modelsForSource = modelMap.get(source);
+		if (modelsForSource == null) {
+			logWarning(
+					"Ignored attempt to remove a saveable when no saveables were known", source, model); //$NON-NLS-1$
+		} else {
+			if (modelsForSource.remove(model)) {
+				result = decrementRefCount(modelRefCounts, model);
+				if (modelsForSource.isEmpty()) {
+					modelMap.remove(source);
+				}
+			} else {
+				logWarning(
+						"Ignored attempt to remove a saveable that was not registered", source, model); //$NON-NLS-1$
+			}
+		}
+		return result;
+	}
+
+	private void logWarning(String message, Object source, Saveable model) {
+		// create a new exception
+		AssertionFailedException assertionFailedException = new AssertionFailedException("unknown saveable: " + model //$NON-NLS-1$
+				+ " from part: " + source); //$NON-NLS-1$
+		// record the current stack trace to help with debugging
+		assertionFailedException.fillInStackTrace();
+		WorkbenchPlugin.log(StatusUtil.newStatus(IStatus.WARNING, message,
+				assertionFailedException));
+	}
+
+	/**
+	 * This implementation of handleModelLifecycleEvent must be called by
+	 * implementers of ISaveablesSource whenever the list of models of the model
+	 * source changes, or when the dirty state of models changes. The
+	 * ISaveablesSource instance must be passed as the source of the event
+	 * object.
+	 * <p>
+	 * This method may also be called by objects that hold on to models but are
+	 * not workbench parts. In this case, the event source must be set to an
+	 * object that is not an instanceof IWorkbenchPart.
+	 * </p>
+	 * <p>
+	 * Corresponding open and close events must originate from the same
+	 * (identical) event source.
+	 * </p>
+	 * <p>
+	 * This method must be called on the UI thread.
+	 * </p>
+	 */
+	@Override
+	public void handleLifecycleEvent(SaveablesLifecycleEvent event) {
+		if (!(event.getSource() instanceof IWorkbenchPart)) {
+			// just update the set of non-part sources. No prompting necessary.
+			// See bug 139004.
+			updateNonPartSource((ISaveablesSource) event.getSource());
+			return;
+		}
+		Saveable[] modelArray = event.getSaveables();
+		switch (event.getEventType()) {
+		case SaveablesLifecycleEvent.POST_OPEN:
+			addModels(event.getSource(), modelArray);
+			break;
+		case SaveablesLifecycleEvent.PRE_CLOSE:
+			Saveable[] models = event.getSaveables();
+			Map<Saveable, Integer> modelsDecrementing = new HashMap<>();
+			Set<Saveable> modelsClosing = new HashSet<>();
+			for (Saveable model : models) {
+				incrementRefCount(modelsDecrementing, model);
+			}
+
+			fillModelsClosing(modelsClosing, modelsDecrementing);
+			boolean canceled = promptForSavingIfNecessary(PlatformUI
+					.getWorkbench().getActiveWorkbenchWindow(), modelsClosing, modelsDecrementing,
+					!event.isForce());
+			if (canceled) {
+				event.setVeto(true);
+			}
+			break;
+		case SaveablesLifecycleEvent.POST_CLOSE:
+			removeModels(event.getSource(), modelArray);
+			break;
+		case SaveablesLifecycleEvent.DIRTY_CHANGED:
+			fireModelLifecycleEvent(new SaveablesLifecycleEvent(this, event
+					.getEventType(), event.getSaveables(), false));
+			break;
+		}
+	}
+
+	/**
+	 * Updates the set of non-part saveables sources.
+	 * @param source
+	 */
+	private void updateNonPartSource(ISaveablesSource source) {
+		Saveable[] saveables = source.getSaveables();
+		if (saveables.length == 0) {
+			nonPartSources.remove(source);
+		} else {
+			nonPartSources.add(source);
+		}
+	}
+
+	/**
+	 * @param source
+	 * @param modelArray
+	 */
+	private void removeModels(Object source, Saveable[] modelArray) {
+		List<Saveable> removed = new ArrayList<>();
+		for (Saveable model : modelArray) {
+			if (removeModel(source, model)) {
+				removed.add(model);
+			}
+		}
+		if (removed.size() > 0) {
+			fireModelLifecycleEvent(new SaveablesLifecycleEvent(this,
+					SaveablesLifecycleEvent.POST_OPEN, removed
+							.toArray(new Saveable[removed.size()]), false));
+		}
+	}
+
+	/**
+	 * @param source
+	 * @param modelArray
+	 */
+	private void addModels(Object source, Saveable[] modelArray) {
+		List<Saveable> added = new ArrayList<>();
+		for (Saveable model : modelArray) {
+			if (addModel(source, model)) {
+				added.add(model);
+			}
+		}
+		if (added.size() > 0) {
+			fireModelLifecycleEvent(new SaveablesLifecycleEvent(this,
+					SaveablesLifecycleEvent.POST_OPEN, added
+							.toArray(new Saveable[added.size()]), false));
+		}
+	}
+
+	/**
+	 * @param event
+	 */
+	private void fireModelLifecycleEvent(SaveablesLifecycleEvent event) {
+		for (ISaveablesLifecycleListener listener : listeners) {
+			listener.handleLifecycleEvent(event);
+		}
+	}
+
+	/**
+	 * Adds the given listener to the list of listeners. Has no effect if the
+	 * same (identical) listener has already been added. The listener will be
+	 * notified about changes to the models managed by this model manager. Event
+	 * types include: <br>
+	 * POST_OPEN when models were added to the list of models <br>
+	 * POST_CLOSE when models were removed from the list of models <br>
+	 * DIRTY_CHANGED when the dirty state of models changed
+	 * <p>
+	 * Listeners should ignore all other event types, including PRE_CLOSE. There
+	 * is no guarantee that listeners are notified before models are closed.
+	 *
+	 * @param listener
+	 */
+	public void addModelLifecycleListener(ISaveablesLifecycleListener listener) {
+		listeners.add(listener);
+	}
+
+	/**
+	 * Removes the given listener from the list of listeners. Has no effect if
+	 * the given listener is not contained in the list.
+	 *
+	 * @param listener
+	 */
+	public void removeModelLifecycleListener(ISaveablesLifecycleListener listener) {
+		listeners.remove(listener);
+	}
+
+	/**
+	 * @param partsToClose
+	 * @param save
+	 * @param window
+	 * @return the post close info to be passed to postClose
+	 */
+	public Object preCloseParts(List<IWorkbenchPart> partsToClose, boolean save,
+			final IWorkbenchWindow window) {
+		return preCloseParts(partsToClose, save, window, window);
+	}
+
+	public Object preCloseParts(List<IWorkbenchPart> partsToClose, boolean save, IShellProvider shellProvider,
+			final IWorkbenchWindow window) {
+		return preCloseParts(partsToClose, false, save, shellProvider, window);
+	}
+
+	public Object preCloseParts(List<IWorkbenchPart> partsToClose, boolean addNonPartSources, boolean save,
+			IShellProvider shellProvider, final IWorkbenchWindow window) {
+		// reference count (how many occurrences of a model will go away?)
+		PostCloseInfo postCloseInfo = new PostCloseInfo();
+		for (IWorkbenchPart part : partsToClose) {
+			postCloseInfo.partsClosing.add(part);
+			ISaveablePart saveable = SaveableHelper.getSaveable(part);
+			if (saveable != null) {
+				if (save && !saveable.isSaveOnCloseNeeded()) {
+					// pretend for now that this part is not closing
+					continue;
+				}
+			}
+			if (save && saveable instanceof ISaveablePart2) {
+				ISaveablePart2 saveablePart2 = (ISaveablePart2) saveable;
+				// TODO show saveablePart2 before prompting, see
+				// EditorManager.saveAll
+				int response = SaveableHelper.savePart(saveablePart2, window,
+						true);
+				if (response == ISaveablePart2.CANCEL) {
+					// user canceled
+					return null;
+				} else if (response != ISaveablePart2.DEFAULT) {
+					// only include this part in the following logic if it returned
+					// DEFAULT
+					continue;
+				}
+			}
+			for (Saveable saveableModel : getSaveables(part)) {
+				incrementRefCount(postCloseInfo.modelsDecrementing, saveableModel);
+			}
+		}
+		fillModelsClosing(postCloseInfo.modelsClosing,
+				postCloseInfo.modelsDecrementing);
+		if (addNonPartSources) {
+			for (ISaveablesSource nonPartSource : getNonPartSources()) {
+				Saveable[] saveables = nonPartSource.getSaveables();
+				for (Saveable saveable : saveables) {
+					if (saveable.isDirty()) {
+						postCloseInfo.modelsClosing.add(saveable);
+					}
+				}
+			}
+		}
+		if (save) {
+			boolean canceled = promptForSavingIfNecessary(shellProvider, window,
+					postCloseInfo.modelsClosing, postCloseInfo.modelsDecrementing, true);
+			if (canceled) {
+				return null;
+			}
+		}
+		return postCloseInfo;
+	}
+
+	/**
+	 * @param window
+	 * @param modelsClosing
+	 * @param canCancel
+	 * @return true if the user canceled
+	 */
+	private boolean promptForSavingIfNecessary(final IWorkbenchWindow window,
+			Set<Saveable> modelsClosing, Map<Saveable, Integer> modelsDecrementing, boolean canCancel) {
+		return promptForSavingIfNecessary(window, window, modelsClosing, modelsDecrementing,
+				canCancel);
+	}
+
+	private boolean promptForSavingIfNecessary(IShellProvider shellProvider,
+ IWorkbenchWindow window,
+			Set<Saveable> modelsClosing, Map<Saveable, Integer> modelsDecrementing, boolean canCancel) {
+		List<Saveable> modelsToOptionallySave = new ArrayList<>();
+		for (Saveable modelDecrementing : modelsDecrementing.keySet()) {
+			if (modelDecrementing.isDirty() && !modelsClosing.contains(modelDecrementing)) {
+				modelsToOptionallySave.add(modelDecrementing);
+			}
+		}
+
+		boolean shouldCancel = modelsToOptionallySave.isEmpty() ? false : promptForSaving(
+				modelsToOptionallySave, shellProvider, window, canCancel, true);
+
+		if (shouldCancel) {
+			return true;
+		}
+
+		List<Saveable> modelsToSave = new ArrayList<>();
+		for (Saveable modelClosing : modelsClosing) {
+			if (modelClosing.isDirty()) {
+				modelsToSave.add(modelClosing);
+			}
+		}
+		return modelsToSave.isEmpty() ? false : promptForSaving(modelsToSave, shellProvider,
+				window, canCancel, false);
+	}
+
+	/**
+	 * @param modelsClosing
+	 * @param modelsDecrementing
+	 */
+	private void fillModelsClosing(Set<Saveable> modelsClosing, Map<Saveable, Integer> modelsDecrementing) {
+		for (Entry<Saveable, Integer> entry : modelsDecrementing.entrySet()) {
+			Saveable model = entry.getKey();
+			if (entry.getValue().equals(modelRefCounts.get(model))) {
+				modelsClosing.add(model);
+			}
+		}
+	}
+
+	/**
+	 * Prompt the user to save the given saveables.
+	 * @param modelsToSave the saveables to be saved
+	 * @param shellProvider the provider used to obtain a shell in prompting is
+	 *            required. Clients can use a workbench window for this.
+	 * @param runnableContext a runnable context that will be used to provide a
+	 *            progress monitor while the save is taking place. Clients can
+	 *            use a workbench window for this.
+	 * @param canCancel whether the operation can be canceled
+	 * @param stillOpenElsewhere whether the models are referenced by open parts
+	 * @return true if the user canceled
+	 */
+	public boolean promptForSaving(List<Saveable> modelsToSave,
+			final IShellProvider shellProvider, IRunnableContext runnableContext, final boolean canCancel, boolean stillOpenElsewhere) {
+		// Save parts, exit the method if cancel is pressed.
+		if (modelsToSave.size() > 0) {
+			boolean canceled = SaveableHelper.waitForBackgroundSaveJobs(modelsToSave);
+			if (canceled) {
+				return true;
+			}
+
+			IPreferenceStore apiPreferenceStore = PrefUtil.getAPIPreferenceStore();
+			boolean dontPrompt = stillOpenElsewhere && !apiPreferenceStore.getBoolean(IWorkbenchPreferenceConstants.PROMPT_WHEN_SAVEABLE_STILL_OPEN);
+
+			if (dontPrompt) {
+				modelsToSave.clear();
+				return false;
+			} else if (modelsToSave.size() == 1) {
+				Saveable model = modelsToSave.get(0);
+				// Show a dialog.
+
+				// don't save if we don't prompt
+				int choice = ISaveablePart2.NO;
+
+				MessageDialog dialog;
+				if (stillOpenElsewhere) {
+					LinkedHashMap<String, Integer> buttonLabelToIdMap = new LinkedHashMap<>();
+					buttonLabelToIdMap.put(WorkbenchMessages.get().SaveableHelper_Save, IDialogConstants.OK_ID);
+					buttonLabelToIdMap.put(WorkbenchMessages.get().SaveableHelper_Dont_Save, IDialogConstants.NO_ID);
+					if (canCancel) {
+						buttonLabelToIdMap.put(WorkbenchMessages.get().SaveableHelper_Cancel, IDialogConstants.CANCEL_ID);
+					}
+					String message = NLS
+							.bind(
+									WorkbenchMessages.get().EditorManager_saveChangesOptionallyQuestion,
+									model.getName());
+					MessageDialogWithToggle dialogWithToggle = new MessageDialogWithToggle(shellProvider.getShell(),
+							WorkbenchMessages.get().Save_Resource, null, message,
+							MessageDialog.QUESTION, buttonLabelToIdMap.keySet().toArray(null), 0,
+							WorkbenchMessages.get().EditorManager_closeWithoutPromptingOption, false) {
+						@Override
+						protected int getShellStyle() {
+							return (canCancel ? SWT.CLOSE : SWT.NONE)
+									| SWT.TITLE | SWT.BORDER
+									| SWT.APPLICATION_MODAL | SWT.SHEET
+									| getDefaultOrientation();
+						}
+					};
+					dialog = dialogWithToggle;
+				} else {
+					String[] buttons;
+					if (canCancel) {
+						buttons = new String[] { WorkbenchMessages.get().SaveableHelper_Save,
+								WorkbenchMessages.get().SaveableHelper_Dont_Save, WorkbenchMessages.get().SaveableHelper_Cancel };
+					} else {
+						buttons = new String[] { WorkbenchMessages.get().SaveableHelper_Save,
+								WorkbenchMessages.get().SaveableHelper_Dont_Save };
+					}
+
+					String message = NLS
+							.bind(
+									WorkbenchMessages.get().EditorManager_saveChangesQuestion,
+									model.getName());
+					dialog = new MessageDialog(shellProvider.getShell(),
+							WorkbenchMessages.get().Save_Resource, null, message,
+							MessageDialog.QUESTION, buttons, 0) {
+						@Override
+						protected int getShellStyle() {
+							return (canCancel ? SWT.CLOSE : SWT.NONE)
+									| SWT.TITLE | SWT.BORDER
+									| SWT.APPLICATION_MODAL | SWT.SHEET
+									| getDefaultOrientation();
+						}
+					};
+				}
+
+				choice = SaveableHelper.testGetAutomatedResponse();
+				if (SaveableHelper.testGetAutomatedResponse() == SaveableHelper.USER_RESPONSE) {
+					choice = dialog.open();
+
+					if(stillOpenElsewhere) {
+						// map value of choice back to ISaveablePart2 values
+						switch (choice) {
+						case IDialogConstants.YES_ID:
+							choice = ISaveablePart2.YES;
+							break;
+						case IDialogConstants.NO_ID:
+							choice = ISaveablePart2.NO;
+							break;
+						case IDialogConstants.CANCEL_ID:
+							choice = ISaveablePart2.CANCEL;
+							break;
+						default:
+							break;
+						}
+						MessageDialogWithToggle dialogWithToggle = (MessageDialogWithToggle) dialog;
+						if (choice != ISaveablePart2.CANCEL && dialogWithToggle.getToggleState()) {
+							apiPreferenceStore.setValue(IWorkbenchPreferenceConstants.PROMPT_WHEN_SAVEABLE_STILL_OPEN, false);
+						}
+					}
+				}
+
+				// Branch on the user choice.
+				// The choice id is based on the order of button labels
+				// above.
+				switch (choice) {
+				case ISaveablePart2.YES: // yes
+					break;
+				case ISaveablePart2.NO: // no
+					modelsToSave.clear();
+					break;
+				default:
+				case ISaveablePart2.CANCEL: // cancel
+					return true;
+				}
+			} else {
+				MyListSelectionDialog dlg = new MyListSelectionDialog(
+						shellProvider.getShell(),
+						modelsToSave,
+						new ArrayContentProvider(),
+						new WorkbenchPartLabelProvider(),
+						stillOpenElsewhere ? WorkbenchMessages.get().EditorManager_saveResourcesOptionallyMessage
+								: WorkbenchMessages.get().EditorManager_saveResourcesMessage,
+						canCancel, stillOpenElsewhere);
+				dlg.setInitialSelections(modelsToSave.toArray());
+				dlg.setTitle(WorkbenchMessages.get().EditorManager_saveResourcesTitle);
+
+				// this "if" statement aids in testing.
+				if (SaveableHelper.testGetAutomatedResponse() == SaveableHelper.USER_RESPONSE) {
+					int result = dlg.open();
+					// Just return null to prevent the operation continuing
+					if (result == IDialogConstants.CANCEL_ID)
+						return true;
+
+					if (dlg.getDontPromptSelection()) {
+						apiPreferenceStore.setValue(IWorkbenchPreferenceConstants.PROMPT_WHEN_SAVEABLE_STILL_OPEN, false);
+					}
+
+					modelsToSave = new ArrayList<>();
+					Object[] objects = dlg.getResult();
+					for (Object object : objects) {
+						if (object instanceof Saveable) {
+							modelsToSave.add((Saveable) object);
+						}
+					}
+				}
+			}
+		}
+		// Create save block.
+		return saveModels(modelsToSave, shellProvider, runnableContext);
+	}
+
+	/**
+	 * Save the given models.
+	 * @param finalModels the list of models to be saved
+	 * @param shellProvider the provider used to obtain a shell in prompting is
+	 *            required. Clients can use a workbench window for this.
+	 * @param runnableContext a runnable context that will be used to provide a
+	 *            progress monitor while the save is taking place. Clients can
+	 *            use a workbench window for this.
+	 * @return <code>true</code> if the operation was canceled
+	 */
+	public boolean saveModels(final List<Saveable> finalModels, final IShellProvider shellProvider,
+			IRunnableContext runnableContext) {
+		return saveModels(finalModels, shellProvider, runnableContext, true);
+	}
+
+	/**
+	 * Save the given models.
+	 *
+	 * @param finalModels
+	 *            the list of models to be saved
+	 * @param shellProvider
+	 *            the provider used to obtain a shell in prompting is required.
+	 *            Clients can use a workbench window for this.
+	 * @param runnableContext
+	 *            a runnable context that will be used to provide a progress
+	 *            monitor while the save is taking place. Clients can use a
+	 *            workbench window for this.
+	 * @param blockUntilSaved
+	 * @return <code>true</code> if the operation was canceled
+	 */
+	public boolean saveModels(final List<Saveable> finalModels, final IShellProvider shellProvider,
+			IRunnableContext runnableContext, final boolean blockUntilSaved) {
+		IRunnableWithProgress progressOp = monitor -> {
+			IProgressMonitor monitorWrap = new EventLoopProgressMonitor(monitor);
+			SubMonitor subMonitor = SubMonitor.convert(monitorWrap, WorkbenchMessages.get().Saving_Modifications,
+					finalModels.size());
+			for (Saveable model : finalModels) {
+				// handle case where this model got saved as a result of
+				// saving another
+				if (!model.isDirty()) {
+					subMonitor.worked(1);
+					continue;
+				}
+				SaveableHelper.doSaveModel(model, subMonitor.split(1),
+						shellProvider, blockUntilSaved);
+				if (subMonitor.isCanceled())
+					break;
+			}
+			monitorWrap.done();
+		};
+
+		// Do the save.
+		return !SaveableHelper.runProgressMonitorOperation(
+				WorkbenchMessages.get().Save_All, progressOp, runnableContext,
+				shellProvider);
+	}
+
+	private static class PostCloseInfo {
+		private List<IWorkbenchPart> partsClosing = new ArrayList<>();
+
+		private Map<Saveable, Integer> modelsDecrementing = new HashMap<>();
+
+		private Set<Saveable> modelsClosing = new HashSet<>();
+	}
+
+	/**
+	 * @param postCloseInfoObject
+	 */
+	public void postClose(Object postCloseInfoObject) {
+		PostCloseInfo postCloseInfo = (PostCloseInfo) postCloseInfoObject;
+		List<Saveable> removed = new ArrayList<>();
+		for (IWorkbenchPart part : postCloseInfo.partsClosing) {
+			Set<Saveable> saveables = modelMap.get(part);
+			if (saveables != null) {
+				// make a copy to avoid a ConcurrentModificationException - we
+				// will remove from the original set as we iterate
+				saveables = new HashSet<>(saveables);
+				for (Saveable saveable : saveables) {
+					if (removeModel(part, saveable)) {
+						removed.add(saveable);
+					}
+				}
+			}
+		}
+		if (removed.size() > 0) {
+			fireModelLifecycleEvent(new SaveablesLifecycleEvent(this,
+					SaveablesLifecycleEvent.POST_CLOSE, removed
+							.toArray(new Saveable[removed.size()]), false));
+		}
+	}
+
+	/**
+	 * Returns the saveable models provided by the given part. If the part does
+	 * not provide any models, a default model is returned representing the
+	 * part.
+	 *
+	 * @param part
+	 *            the workbench part
+	 * @return the saveable models
+	 */
+	private Saveable[] getSaveables(IWorkbenchPart part) {
+		if (part instanceof ISaveablesSource) {
+			ISaveablesSource source = (ISaveablesSource) part;
+			return source.getSaveables();
+		} else if (SaveableHelper.isSaveable(part)) {
+			return new Saveable[] { new DefaultSaveable(part) };
+		} else {
+			return new Saveable[0];
+		}
+	}
+
+	/**
+	 * @param part
+	 */
+	public void postOpen(IWorkbenchPart part) {
+		addModels(part, getSaveables(part));
+	}
+
+	/**
+	 * @param part
+	 */
+	public void dirtyChanged(IWorkbenchPart part) {
+		Saveable[] saveables = getSaveables(part);
+		if (saveables.length > 0) {
+			fireModelLifecycleEvent(new SaveablesLifecycleEvent(this,
+					SaveablesLifecycleEvent.DIRTY_CHANGED, saveables, false));
+		}
+	}
+
+	/**
+	 * For testing purposes. Not to be called by clients.
+	 *
+	 * @param model
+	 * @return never null
+	 */
+	public Object[] testGetSourcesForModel(Saveable model) {
+		List<Object> result = new ArrayList<>();
+		for (Entry<Object, Set<Saveable>> entry : modelMap.entrySet()) {
+			Set<Saveable> values = entry.getValue();
+			if (values.contains(model)) {
+				result.add(entry.getKey());
+			}
+		}
+		return result.toArray();
+	}
+
+	private static final class MyListSelectionDialog extends
+			ListSelectionDialog {
+		private final boolean canCancel;
+		private Button checkbox;
+		private boolean dontPromptSelection;
+		private boolean stillOpenElsewhere;
+
+		private MyListSelectionDialog(Shell shell, Object input,
+				IStructuredContentProvider contentprovider,
+				ILabelProvider labelProvider, String message, boolean canCancel, boolean stillOpenElsewhere) {
+			super(shell, input, contentprovider, labelProvider, message);
+			this.canCancel = canCancel;
+			this.stillOpenElsewhere = stillOpenElsewhere;
+			int shellStyle = getShellStyle();
+			if (!canCancel) {
+				shellStyle &= ~SWT.CLOSE;
+			}
+			setShellStyle(shellStyle | SWT.SHEET);
+		}
+
+		public boolean getDontPromptSelection() {
+			return dontPromptSelection;
+		}
+
+		@Override
+		protected void createButtonsForButtonBar(Composite parent) {
+			createButton(parent, IDialogConstants.OK_ID, IDialogConstants.get().OK_LABEL, true);
+			if (canCancel) {
+				createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.get().CANCEL_LABEL, false);
+			}
+		}
+
+		@Override
+		protected Control createDialogArea(Composite parent) {
+			 Composite dialogAreaComposite = (Composite) super.createDialogArea(parent);
+
+			 if (stillOpenElsewhere) {
+				 Composite checkboxComposite = new Composite(dialogAreaComposite, SWT.NONE);
+				 checkboxComposite.setLayout(new GridLayout(2, false));
+
+				 checkbox = new Button(checkboxComposite, SWT.CHECK);
+				 checkbox.addSelectionListener(new SelectionAdapter() {
+	                    @Override
+	                    public void widgetSelected(SelectionEvent e) {
+	                        dontPromptSelection = checkbox.getSelection();
+	                    }
+	                 });
+				 GridData gd = new GridData();
+				 gd.horizontalAlignment = SWT.BEGINNING;
+				 checkbox.setLayoutData(gd);
+
+				 Label label = new Label(checkboxComposite, SWT.NONE);
+				 label.setText(WorkbenchMessages.get().EditorManager_closeWithoutPromptingOption);
+				 gd = new GridData();
+				 gd.grabExcessHorizontalSpace = true;
+				 gd.horizontalAlignment = SWT.BEGINNING;
+			 }
+
+			 return dialogAreaComposite;
+		}
+	}
+
+	/**
+	 * @return a list of ISaveablesSource objects registered with this saveables
+	 *         list which are not workbench parts.
+	 */
+	public ISaveablesSource[] getNonPartSources() {
+		return nonPartSources
+				.toArray(new ISaveablesSource[nonPartSources.size()]);
+	}
+
+	public IWorkbenchPart[] getPartsForSaveable(Saveable model) {
+		List<IWorkbenchPart> result = new ArrayList<>();
+		for (Entry<Object, Set<Saveable>> entry : modelMap.entrySet()) {
+			Set<Saveable> values = entry.getValue();
+			if (values.contains(model) && entry.getKey() instanceof IWorkbenchPart) {
+				result.add((IWorkbenchPart) entry.getKey());
+			}
+		}
+		return result.toArray(new IWorkbenchPart[result.size()]);
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/SelectionAdapterFactory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/SelectionAdapterFactory.java
new file mode 100644
index 0000000..a69502e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/SelectionAdapterFactory.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2016 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.ui.internal;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import org.eclipse.core.expressions.ICountable;
+import org.eclipse.core.expressions.IIterable;
+import org.eclipse.core.runtime.IAdapterFactory;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+
+/**
+ * Adapts ISelection instances to either IIterable or ICountable. For use with
+ * core expressions.
+ *
+ * @since 3.3
+ */
+public class SelectionAdapterFactory implements IAdapterFactory {
+	private static final ICountable ICOUNT_0 = () -> 0;
+	private static final ICountable ICOUNT_1 = () -> 1;
+	private static final IIterable ITERATE_EMPTY = () -> Collections.EMPTY_LIST.iterator();
+
+	/**
+	 * The classes we can adapt to.
+	 */
+	private static final Class[] CLASSES = new Class[] { IIterable.class,
+			ICountable.class };
+
+	@Override
+	public <T> T getAdapter(Object adaptableObject, Class<T> adapterType) {
+		if (adaptableObject instanceof ISelection) {
+			if (adapterType == IIterable.class) {
+				return adapterType.cast(iterable((ISelection) adaptableObject));
+			} else if (adapterType == ICountable.class) {
+				return adapterType.cast(countable((ISelection) adaptableObject));
+			}
+		}
+		return null;
+	}
+
+	private Object iterable(final ISelection sel) {
+		if (sel.isEmpty()) {
+			return ITERATE_EMPTY;
+		}
+		if (sel instanceof IStructuredSelection) {
+			return (IIterable) () -> ((IStructuredSelection) sel).iterator();
+		}
+		final List list = Arrays.asList(new Object[] { sel });
+		return (IIterable) () -> list.iterator();
+	}
+
+	private Object countable(final ISelection sel) {
+		if (sel.isEmpty()) {
+			return ICOUNT_0;
+		}
+		if (sel instanceof IStructuredSelection) {
+			final IStructuredSelection ss = (IStructuredSelection) sel;
+			return (ICountable) () -> ss.size();
+		}
+		return ICOUNT_1;
+	}
+
+	@Override
+	public Class[] getAdapterList() {
+		return CLASSES;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/SelectionConversionService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/SelectionConversionService.java
new file mode 100644
index 0000000..6ad815a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/SelectionConversionService.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+
+/**
+ * <p>
+ * The SelectionConversionService is the service that converts the selection to
+ * IResources.
+ * </p>
+ * <p>
+ * This interface is only intended for use within the
+ * <code>org.eclipse.ui.workbench</code> and <code>org.eclipse.ui.ide</code>
+ * plug-ins.
+ * </p>
+ *
+ * @since 3.2
+ */
+public class SelectionConversionService implements ISelectionConversionService {
+
+	/**
+	 * Attempt to convert the elements in the passed selection into resources by
+	 * asking each for its IResource property (iff it isn't already a resource).
+	 * If all elements in the initial selection can be converted to resources
+	 * then answer a new selection containing these resources; otherwise answer
+	 * an empty selection.
+	 *
+	 * @param originalSelection
+	 *            the original selection
+	 * @return the converted selection or an empty selection.
+	 */
+	@Override
+	public IStructuredSelection convertToResources(
+			IStructuredSelection originalSelection) {
+		// @issue resource-specific code should be pushed into IDE
+		Class resourceClass = LegacyResourceSupport.getResourceClass();
+		if (resourceClass == null) {
+			return originalSelection;
+		}
+
+		List result = new ArrayList();
+		Iterator elements = originalSelection.iterator();
+
+		while (elements.hasNext()) {
+			Object currentElement = elements.next();
+			Object resource = Adapters.adapt(currentElement, resourceClass);
+            if (resource != null) {
+            	result.add(resource);
+            }
+		}
+
+		// all that can be converted are done, answer new selection
+		if (result.isEmpty()) {
+			return StructuredSelection.EMPTY;
+		}
+		return new StructuredSelection(result.toArray());
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/SharedImages.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/SharedImages.java
new file mode 100644
index 0000000..f8353f2
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/SharedImages.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2014 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.ui.internal;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.ISharedImages;
+
+/**
+ * Common images used by the workbench which may be useful to other plug-ins.
+ */
+public class SharedImages implements ISharedImages {
+    /**
+     * Retrieves the specified image from the workbench plugin's image registry.
+     *
+     * @see ISharedImages
+     */
+    @Override
+	public Image getImage(String symbolicName) {
+        Image image = WorkbenchImages.getImage(symbolicName);
+        if (image != null) {
+			return image;
+		}
+
+        //if there is a descriptor for it, add the image to the registry.
+        ImageDescriptor desc = WorkbenchImages.getImageDescriptor(symbolicName);
+        if (desc != null) {
+            WorkbenchImages.getImageRegistry().put(symbolicName, desc);
+            return WorkbenchImages.getImageRegistry().get(symbolicName);
+        }
+        return null;
+    }
+
+    /**
+     * Retrieves the specified image descriptor from the workbench plugin's image registry.
+     *
+     * @see ISharedImages
+     */
+    @Override
+	public ImageDescriptor getImageDescriptor(String symbolicName) {
+        return WorkbenchImages.getImageDescriptor(symbolicName);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ShellPool.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ShellPool.java
new file mode 100644
index 0000000..730b485
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ShellPool.java
@@ -0,0 +1,138 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.ShellAdapter;
+import org.eclipse.swt.events.ShellEvent;
+import org.eclipse.swt.events.ShellListener;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * Manages a pool of shells. This can be used instead of creating and destroying
+ * shells. By reusing shells, they will never be disposed until the pool goes away.
+ * This is useful in situations where client code may have cached pointers to the
+ * shells to use as a parent for dialogs. It also works around bug 86226 (SWT menus
+ * cannot be reparented).
+ *
+ * @since 3.1
+ */
+public class ShellPool {
+
+    private int flags;
+
+    /**
+     * Parent shell (or null if none)
+     */
+    private Shell parentShell;
+
+    private LinkedList availableShells = new LinkedList();
+
+    private final static String CLOSE_LISTENER = "close listener"; //$NON-NLS-1$
+
+    private boolean isDisposed = false;
+
+    private DisposeListener disposeListener = new DisposeListener() {
+        @Override
+		public void widgetDisposed(DisposeEvent e) {
+            WorkbenchPlugin.log(new RuntimeException("Widget disposed too early!")); //$NON-NLS-1$
+        }
+    };
+
+    private ShellListener closeListener = new ShellAdapter() {
+
+        @Override
+		public void shellClosed(ShellEvent e) {
+                if (isDisposed) {
+                    return;
+                }
+
+                if (e.doit) {
+                    Shell s = (Shell)e.widget;
+                    ShellListener l = (ShellListener)s.getData(CLOSE_LISTENER);
+
+                    if (l != null) {
+                        s.setData(CLOSE_LISTENER, null);
+                        l.shellClosed(e);
+
+                        // The shell can 'cancel' the close by setting
+                        // the 'doit' to false...if so, do nothing
+                        if (e.doit) {
+						for (Control control : s.getChildren()) {
+	                            control.dispose();
+	                        }
+	                        availableShells.add(s);
+	                        s.setVisible(false);
+                        }
+                        else {
+                        	// Restore the listener
+                            s.setData(CLOSE_LISTENER, l);
+                        }
+                    }
+                }
+                e.doit = false;
+         }
+    };
+
+    /**
+     * Creates a shell pool that allocates shells that are children of the
+     * given parent and are created with the given flags.
+     *
+     * @param parentShell parent shell (may be null, indicating that this pool creates
+     * top-level shells)
+     * @param childFlags flags for all child shells
+     */
+    public ShellPool(Shell parentShell, int childFlags) {
+        this.parentShell = parentShell;
+        this.flags = childFlags;
+    }
+
+    /**
+     * Returns a new shell. The shell must not be disposed directly, but it may be closed.
+     * Once the shell is closed, it will be returned to the shell pool. Note: callers must
+     * remove all listeners from the shell before closing it.
+     */
+    public Shell allocateShell(ShellListener closeListener) {
+        Shell result;
+        if (!availableShells.isEmpty()) {
+            result = (Shell)availableShells.removeFirst();
+        } else {
+            result = new Shell(parentShell, flags);
+            result.addShellListener(this.closeListener);
+            result.addDisposeListener(disposeListener);
+        }
+
+        result.setData(CLOSE_LISTENER, closeListener);
+        return result;
+    }
+
+    /**
+     * Disposes this pool. Any unused shells in the pool are disposed immediately,
+     * and any shells in use will be disposed once they are closed.
+     *
+     * @since 3.1
+     */
+    public void dispose() {
+        for (Iterator iter = availableShells.iterator(); iter.hasNext();) {
+            Shell next = (Shell) iter.next();
+            next.removeDisposeListener(disposeListener);
+
+            next.dispose();
+        }
+
+        availableShells.clear();
+        isDisposed = true;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ShowInHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ShowInHandler.java
new file mode 100644
index 0000000..5d52d4b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ShowInHandler.java
@@ -0,0 +1,136 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ ******************************************************************************/
+
+package org.eclipse.ui.internal;
+
+import java.util.Map;
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.ui.ISourceProvider;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.commands.IElementUpdater;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.eclipse.ui.internal.services.WorkbenchSourceProvider;
+import org.eclipse.ui.menus.UIElement;
+import org.eclipse.ui.part.IShowInTarget;
+import org.eclipse.ui.part.ShowInContext;
+import org.eclipse.ui.services.ISourceProviderService;
+import org.eclipse.ui.views.IViewDescriptor;
+import org.eclipse.ui.views.IViewRegistry;
+
+/**
+ * The show in command, which only needs a target id.
+ *
+ * @since 3.4
+ */
+public class ShowInHandler extends AbstractHandler implements IElementUpdater {
+
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		IWorkbenchPage p = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+		WorkbenchPartReference r = (WorkbenchPartReference) p.getActivePartReference();
+		if (p != null && r != null && r.getModel() != null) {
+			((WorkbenchPage) p).updateShowInSources(r.getModel());
+		}
+
+		String targetId = event
+				.getParameter(IWorkbenchCommandConstants.NAVIGATE_SHOW_IN_PARM_TARGET);
+		if (targetId == null) {
+			throw new ExecutionException("No targetId specified"); //$NON-NLS-1$
+		}
+
+		final IWorkbenchWindow activeWorkbenchWindow = HandlerUtil.getActiveWorkbenchWindowChecked(event);
+		ISourceProviderService sps = activeWorkbenchWindow.getService(ISourceProviderService.class);
+		if (sps != null) {
+			ISourceProvider sp = sps.getSourceProvider(ISources.SHOW_IN_SELECTION);
+			if (sp instanceof WorkbenchSourceProvider) {
+				((WorkbenchSourceProvider)sp).checkActivePart(true);
+			}
+		}
+
+		ShowInContext context = getContext(HandlerUtil
+				.getShowInSelection(event), HandlerUtil.getShowInInput(event));
+		if (context == null) {
+			return null;
+		}
+
+		IWorkbenchPage page= activeWorkbenchWindow.getActivePage();
+
+		try {
+			IViewPart view = page.showView(targetId);
+			IShowInTarget target = getShowInTarget(view);
+			if (!(target != null && target.show(context))) {
+				page.getWorkbenchWindow().getShell().getDisplay().beep();
+			}
+			((WorkbenchPage) page).performedShowIn(targetId); // TODO: move
+			// back up
+		} catch (PartInitException e) {
+			throw new ExecutionException("Failed to show in", e); //$NON-NLS-1$
+		}
+
+		return null;
+	}
+
+	/**
+	 * Returns the <code>ShowInContext</code> to show in the selected target,
+	 * or <code>null</code> if there is no valid context to show.
+	 * <p>
+	 * This implementation obtains the context from global variables provide.
+	 * showInSelection and showInInput should be available.
+	 * <p>
+	 *
+	 * @return the <code>ShowInContext</code> to show or <code>null</code>
+	 */
+	private ShowInContext getContext(ISelection showInSelection, Object input) {
+		if (input == null && showInSelection == null) {
+			return null;
+		}
+		return new ShowInContext(input, showInSelection);
+	}
+
+	/**
+	 * Returns the <code>IShowInTarget</code> for the given part, or
+	 * <code>null</code> if it does not provide one.
+	 *
+	 * @param targetPart
+	 *            the target part
+	 * @return the <code>IShowInTarget</code> or <code>null</code>
+	 */
+	private IShowInTarget getShowInTarget(IWorkbenchPart targetPart) {
+		return Adapters.adapt(targetPart, IShowInTarget.class);
+	}
+
+	@Override
+	public void updateElement(UIElement element, Map parameters) {
+		String targetId = (String) parameters
+				.get(IWorkbenchCommandConstants.NAVIGATE_SHOW_IN_PARM_TARGET);
+		if (targetId == null || targetId.length() == 0) {
+			return;
+		}
+		IViewRegistry reg = WorkbenchPlugin.getDefault().getViewRegistry();
+		IViewDescriptor desc = reg.find(targetId);
+		if (desc != null) {
+			element.setIcon(desc.getImageDescriptor());
+			element.setText(desc.getLabel());
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ShowInMenu.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ShowInMenu.java
new file mode 100644
index 0000000..02a8ded
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ShowInMenu.java
@@ -0,0 +1,417 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 440810, 444070, 472654
+ *     Simon Scholz <simon.scholz@vogella.com> - Bug 451214
+ *******************************************************************************/
+
+package org.eclipse.ui.internal;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.e4.core.commands.ExpressionContext;
+import org.eclipse.e4.ui.internal.workbench.ContributionsAnalyzer;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.commands.MCommand;
+import org.eclipse.e4.ui.model.application.ui.menu.MHandledMenuItem;
+import org.eclipse.e4.ui.model.application.ui.menu.MMenu;
+import org.eclipse.e4.ui.model.application.ui.menu.MMenuContribution;
+import org.eclipse.e4.ui.model.application.ui.menu.MMenuElement;
+import org.eclipse.e4.ui.model.application.ui.menu.impl.MenuFactoryImpl;
+import org.eclipse.jface.action.ContributionItem;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.IMenuListener;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.ISourceProvider;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.commands.ICommandImageService;
+import org.eclipse.ui.internal.services.IWorkbenchLocationService;
+import org.eclipse.ui.internal.services.WorkbenchSourceProvider;
+import org.eclipse.ui.menus.CommandContributionItem;
+import org.eclipse.ui.menus.CommandContributionItemParameter;
+import org.eclipse.ui.menus.IWorkbenchContribution;
+import org.eclipse.ui.menus.MenuUtil;
+import org.eclipse.ui.part.IShowInSource;
+import org.eclipse.ui.part.IShowInTargetList;
+import org.eclipse.ui.part.ShowInContext;
+import org.eclipse.ui.services.IServiceLocator;
+import org.eclipse.ui.services.ISourceProviderService;
+import org.eclipse.ui.views.IViewDescriptor;
+import org.eclipse.ui.views.IViewRegistry;
+
+/**
+ * A <code>ShowInMenu</code> is used to populate a menu manager with Show In
+ * actions. The items to show are determined from the active perspective and
+ * active part.
+ */
+public class ShowInMenu extends ContributionItem implements
+		IWorkbenchContribution {
+
+	private static final String NO_TARGETS_MSG = WorkbenchMessages.get().Workbench_showInNoTargets;
+
+	private IWorkbenchWindow window;
+
+	private boolean dirty = true;
+
+	private IMenuListener menuListener = manager -> {
+		manager.markDirty();
+		dirty = true;
+	};
+
+	private IServiceLocator locator;
+
+	private MenuManager currentManager;
+
+	public ShowInMenu() {
+
+	}
+
+	/**
+	 * Creates a Show In menu.
+	 *
+	 * @param window
+	 *            the window containing the menu
+	 * @param id
+	 *            The ID for this contribution
+	 */
+	public ShowInMenu(IWorkbenchWindow window, String id) {
+		super(id);
+		this.window = window;
+	}
+
+	@Override
+	public boolean isDirty() {
+		return dirty;
+	}
+
+	/**
+	 * Overridden to always return true and force dynamic menu building.
+	 */
+	@Override
+	public boolean isDynamic() {
+		return true;
+	}
+
+	@Override
+	public void fill(Menu menu, int index) {
+		if (getParent() instanceof MenuManager) {
+			((MenuManager) getParent()).addMenuListener(menuListener);
+		}
+
+		if (!dirty) {
+			return;
+		}
+
+		if (currentManager!=null && currentManager.getSize() > 0) {
+			// IMenuService service = (IMenuService) locator
+			// .getService(IMenuService.class);
+			// service.releaseContributions(currentManager);
+			currentManager.removeAll();
+		}
+
+		currentManager = new MenuManager();
+		fillMenu(currentManager);
+		int itemCount = menu.getItemCount();
+		IContributionItem[] items = currentManager.getItems();
+		if (items.length == 0) {
+			MenuItem item = new MenuItem(menu, SWT.NONE, index == -1 ? itemCount : index);
+			item.setText(NO_TARGETS_MSG);
+			item.setEnabled(false);
+		} else {
+			for (IContributionItem item : items) {
+				if (item.isVisible()) {
+					if (index == -1) {
+						item.fill(menu, -1);
+					} else {
+						item.fill(menu, index);
+						int newItemCount = menu.getItemCount();
+						index += newItemCount - itemCount;
+						itemCount = newItemCount;
+					}
+				}
+			}
+		}
+		dirty = false;
+	}
+
+	/**
+	 * Fills the menu with Show In actions.
+	 */
+	private void fillMenu(IMenuManager innerMgr) {
+		IWorkbenchPage page = locator.getService(IWorkbenchPage.class);
+		if (page == null) {
+			return;
+		}
+		WorkbenchPartReference r = (WorkbenchPartReference) page.getActivePartReference();
+		if (page != null && r != null && r.getModel() != null) {
+			((WorkbenchPage) page).updateShowInSources(r.getModel());
+		}
+
+		// Remove all.
+		innerMgr.removeAll();
+
+		IWorkbenchPart sourcePart = getSourcePart();
+		ShowInContext context = getContext(sourcePart);
+		if (context == null) {
+			return;
+		}
+		if (context.getInput() == null
+				&& (context.getSelection() == null || context.getSelection()
+						.isEmpty())) {
+			return;
+		}
+
+		IViewDescriptor[] viewDescs = getViewDescriptors(sourcePart);
+		for (IViewDescriptor viewDesc : viewDescs) {
+			IContributionItem cci = getContributionItem(viewDesc);
+			if (cci != null) {
+				innerMgr.add(cci);
+			}
+		}
+		if (sourcePart != null && innerMgr instanceof MenuManager) {
+			ISourceProviderService sps = locator
+					.getService(ISourceProviderService.class);
+			ISourceProvider sp = sps
+					.getSourceProvider(ISources.SHOW_IN_SELECTION);
+			if (sp instanceof WorkbenchSourceProvider) {
+				((WorkbenchSourceProvider) sp).checkActivePart(true);
+			}
+
+			// add contributions targeting popup:org.eclipse.ui.menus.showInMenu
+			String location = MenuUtil.SHOW_IN_MENU_ID;
+			location = location.substring(location.indexOf(':') + 1);
+			WorkbenchWindow workbenchWindow = (WorkbenchWindow) getWindow();
+			MApplication application = workbenchWindow.getModel().getContext()
+					.get(MApplication.class);
+
+			MMenu menuModel = MenuFactoryImpl.eINSTANCE.createMenu();
+			final ArrayList<MMenuContribution> toContribute = new ArrayList<>();
+			final ArrayList<MMenuElement> menuContributionsToRemove = new ArrayList<>();
+			ExpressionContext eContext = new ExpressionContext(workbenchWindow.getModel()
+					.getContext());
+			ContributionsAnalyzer.gatherMenuContributions(menuModel,
+					application.getMenuContributions(), location, toContribute, eContext, true);
+			ContributionsAnalyzer.addMenuContributions(menuModel, toContribute,
+					menuContributionsToRemove);
+
+			ICommandImageService imgService = workbenchWindow.getService(ICommandImageService.class);
+
+			for (MMenuElement menuElement : menuModel.getChildren()) {
+				if (menuElement instanceof MHandledMenuItem) {
+					MCommand command = ((MHandledMenuItem) menuElement).getCommand();
+					String commandId = command.getElementId();
+					CommandContributionItemParameter ccip = new CommandContributionItemParameter(
+							workbenchWindow, commandId, commandId,
+							CommandContributionItem.STYLE_PUSH);
+					String label = menuElement.getLabel();
+					if (label != null && label.length() > 0) {
+						ccip.label = label;
+						String mnemonics = menuElement.getMnemonics();
+						if (mnemonics != null && mnemonics.length() == 1) {
+							ccip.mnemonic = mnemonics;
+						} else {
+							ccip.mnemonic = label.substring(0, 1);
+						}
+					}
+					String iconURI = menuElement.getIconURI();
+					try {
+						if (iconURI != null && !iconURI.isEmpty()) {
+							ccip.icon = ImageDescriptor.createFromURL(new URL(iconURI));
+						} else {
+							ccip.icon = imgService.getImageDescriptor(commandId);
+						}
+					} catch (MalformedURLException e) {
+						ccip.icon = imgService.getImageDescriptor(commandId);
+					}
+					innerMgr.add(new CommandContributionItem(ccip));
+				}
+			}
+		}
+	}
+
+	/**
+	 * Return the appropriate command contribution item for the parameter.
+	 * @param viewDescriptor
+	 * @return the show in command contribution item
+	 */
+	protected IContributionItem getContributionItem(IViewDescriptor viewDescriptor) {
+		CommandContributionItemParameter parm = new CommandContributionItemParameter(
+				locator, viewDescriptor.getId(), IWorkbenchCommandConstants.NAVIGATE_SHOW_IN,
+				CommandContributionItem.STYLE_PUSH);
+		HashMap<String, String> targetId = new HashMap<>();
+		targetId.put(IWorkbenchCommandConstants.NAVIGATE_SHOW_IN_PARM_TARGET,
+				viewDescriptor.getId());
+		parm.parameters = targetId;
+		parm.label = viewDescriptor.getLabel();
+		if (parm.label.length() > 0) {
+			parm.mnemonic = parm.label.substring(0, 1);
+		}
+		parm.icon = viewDescriptor.getImageDescriptor();
+		return new CommandContributionItem(parm);
+	}
+
+	/**
+	 * Returns the Show In... target part ids for the given source part. Merges
+	 * the contributions from the current perspective and the source part.
+	 */
+	private ArrayList<Object> getShowInPartIds(IWorkbenchPart sourcePart) {
+		ArrayList<Object> targetIds = new ArrayList<>();
+		WorkbenchPage page = (WorkbenchPage) getWindow().getActivePage();
+		if (page != null) {
+			String srcId = sourcePart == null ? null : sourcePart.getSite().getId();
+			ArrayList<?> pagePartIds = page.getShowInPartIds();
+			for (Object pagePartId : pagePartIds) {
+				// Don't add own view, except when explicitly requested with
+				// IShowInTargetList below
+				if (!pagePartId.equals(srcId)) {
+					targetIds.add(pagePartId);
+				}
+			}
+		}
+		IShowInTargetList targetList = Adapters.adapt(sourcePart, IShowInTargetList.class);
+		if (targetList != null) {
+			String[] partIds = targetList.getShowInTargetIds();
+			if (partIds != null) {
+				for (int i = 0; i < partIds.length; ++i) {
+					if (!targetIds.contains(partIds[i])) {
+						targetIds.add(partIds[i]);
+					}
+				}
+			}
+		}
+		page.sortShowInPartIds(targetIds);
+		return targetIds;
+	}
+
+	/**
+	 * Returns the source part, or <code>null</code> if there is no applicable
+	 * source part
+	 * <p>
+	 * This implementation returns the current part in the window. Subclasses
+	 * may extend or reimplement.
+	 *
+	 * @return the source part or <code>null</code>
+	 */
+	protected IWorkbenchPart getSourcePart() {
+		IWorkbenchWindow window = getWindow();
+
+		if (window == null)
+			return null;
+
+		IWorkbenchPage page = window.getActivePage();
+		return page != null ? page.getActivePart() : null;
+	}
+
+	/**
+	 * Returns the <code>ShowInContext</code> to show in the selected target,
+	 * or <code>null</code> if there is no valid context to show.
+	 * <p>
+	 * This implementation obtains the context from the
+	 * <code>IShowInSource</code> of the source part (if provided), or, if the
+	 * source part is an editor, it creates the context from the editor's input
+	 * and selection.
+	 * <p>
+	 * Subclasses may extend or reimplement.
+	 *
+	 * @return the <code>ShowInContext</code> to show or <code>null</code>
+	 */
+	protected ShowInContext getContext(IWorkbenchPart sourcePart) {
+		if (sourcePart != null) {
+			IShowInSource source = Adapters.adapt(sourcePart, IShowInSource.class);
+			if (source != null) {
+				ShowInContext context = source.getShowInContext();
+				if (context != null) {
+					return context;
+				}
+			} else if (sourcePart instanceof IEditorPart) {
+				Object input = ((IEditorPart) sourcePart).getEditorInput();
+				ISelectionProvider sp = sourcePart.getSite().getSelectionProvider();
+				ISelection sel = sp == null ? null : sp.getSelection();
+				return new ShowInContext(input, sel);
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Returns the view descriptors to show in the dialog.
+	 */
+	private IViewDescriptor[] getViewDescriptors(IWorkbenchPart sourcePart) {
+		ArrayList<Object> ids = getShowInPartIds(sourcePart);
+		ArrayList<IViewDescriptor> descs = new ArrayList<>();
+		IViewRegistry reg = WorkbenchPlugin.getDefault().getViewRegistry();
+		for (Object object : ids) {
+			String id = (String) object;
+			IViewDescriptor desc = reg.find(id);
+			if (desc != null) {
+				descs.add(desc);
+			}
+		}
+		return descs.toArray(new IViewDescriptor[descs
+				.size()]);
+	}
+
+	@Override
+	public void initialize(IServiceLocator serviceLocator) {
+		locator = serviceLocator;
+	}
+
+	protected IWorkbenchWindow getWindow() {
+		if (locator == null)
+			return null;
+
+		IWorkbenchLocationService wls = locator
+				.getService(IWorkbenchLocationService.class);
+
+		if (window == null) {
+			window = wls.getWorkbenchWindow();
+		}
+		if (window == null) {
+			IWorkbench wb = wls.getWorkbench();
+			if (wb != null) {
+				window = wb.getActiveWorkbenchWindow();
+			}
+		}
+		return window;
+	}
+
+	@Override
+	public void dispose() {
+		if (currentManager != null && currentManager.getSize() > 0) {
+			// IMenuService service = (IMenuService) locator
+			// .getService(IMenuService.class);
+			// if (service != null) {
+			// service.releaseContributions(currentManager);
+			// }
+			currentManager.removeAll();
+			currentManager = null;
+		}
+		if (getParent() instanceof MenuManager) {
+			((MenuManager) getParent()).removeMenuListener(menuListener);
+		}
+		window=null;
+		locator=null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ShowPartPaneMenuHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ShowPartPaneMenuHandler.java
new file mode 100644
index 0000000..6c7ef14
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ShowPartPaneMenuHandler.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.ExpressionInfo;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CTabFolder;
+import org.eclipse.swt.custom.CTabItem;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * Show the menu on top of the icon in the view or editor label.
+ * <p>
+ * Replacement for ShowPartPaneMenuAction
+ * </p>
+ *
+ * @since 3.3
+ */
+public class ShowPartPaneMenuHandler extends AbstractEvaluationHandler {
+
+	private Expression enabledWhen;
+
+	public ShowPartPaneMenuHandler() {
+		registerEnablement();
+	}
+
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		IWorkbenchPart part = HandlerUtil.getActivePart(event);
+		if (part != null) {
+			IWorkbenchPartSite site = part.getSite();
+			if (site instanceof PartSite) {
+				final MPart model = ((PartSite) site).getModel();
+				Composite partContainer = (Composite) model.getWidget();
+				if (partContainer != null) {
+					Composite parent = partContainer.getParent();
+					while (parent != null) {
+						if (parent instanceof CTabFolder) {
+							CTabFolder ctf = (CTabFolder) parent;
+							final CTabItem item = ctf.getSelection();
+							if (item != null) {
+								final Display disp = item.getDisplay();
+								final Rectangle bounds = item.getBounds();
+								final Rectangle info = disp.map(ctf, null, bounds);
+								Event sevent = new Event();
+								sevent.type = SWT.MenuDetect;
+								sevent.widget = ctf;
+								sevent.x = info.x;
+								sevent.y = info.y + info.height - 1;
+								sevent.doit = true;
+								ctf.notifyListeners(SWT.MenuDetect, sevent);
+							}
+							return null;
+						}
+						parent = parent.getParent();
+					}
+				}
+			}
+		}
+		return null;
+	}
+
+	@Override
+	protected Expression getEnabledWhenExpression() {
+		if (enabledWhen == null) {
+			enabledWhen = new Expression() {
+				@Override
+				public EvaluationResult evaluate(IEvaluationContext context) throws CoreException {
+					IWorkbenchPart part = InternalHandlerUtil.getActivePart(context);
+
+					if (part != null) {
+						return EvaluationResult.TRUE;
+					}
+					return EvaluationResult.FALSE;
+				}
+
+				@Override
+				public void collectExpressionInfo(ExpressionInfo info) {
+					info.addVariableNameAccess(ISources.ACTIVE_PART_NAME);
+				}
+			};
+		}
+		return enabledWhen;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ShowViewMenu.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ShowViewMenu.java
new file mode 100644
index 0000000..ab0a1ac
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ShowViewMenu.java
@@ -0,0 +1,358 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *******************************************************************************/
+
+package org.eclipse.ui.internal;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IParameter;
+import org.eclipse.core.commands.NotEnabledException;
+import org.eclipse.core.commands.NotHandledException;
+import org.eclipse.core.commands.Parameterization;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.ContributionItem;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.IMenuListener;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.ui.IPluginContribution;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.activities.WorkbenchActivityHelper;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.internal.intro.IIntroConstants;
+import org.eclipse.ui.internal.registry.ViewDescriptor;
+import org.eclipse.ui.menus.CommandContributionItem;
+import org.eclipse.ui.menus.CommandContributionItemParameter;
+import org.eclipse.ui.services.IServiceLocator;
+import org.eclipse.ui.views.IViewDescriptor;
+import org.eclipse.ui.views.IViewRegistry;
+
+import com.ibm.icu.text.Collator;
+
+/**
+ * A <code>ShowViewMenu</code> is used to populate a menu manager with Show
+ * View actions. The visible views are determined by user preference from the
+ * Perspective Customize dialog.
+ */
+public class ShowViewMenu extends ContributionItem {
+	/**
+	 * @deprecated As of 3.5, replaced by {@link IWorkbenchCommandConstants#VIEWS_SHOW_VIEW}
+	 */
+	@Deprecated
+	public static final String SHOW_VIEW_ID= IWorkbenchCommandConstants.VIEWS_SHOW_VIEW;
+	/**
+	 * @deprecated As of 3.6, replaced by
+	 *             {@link IWorkbenchCommandConstants#VIEWS_SHOW_VIEW_PARM_ID}
+	 */
+	@Deprecated
+	public static final String VIEW_ID_PARM = IWorkbenchCommandConstants.VIEWS_SHOW_VIEW_PARM_ID;
+
+	private IWorkbenchWindow window;
+
+	private static final String NO_TARGETS_MSG = WorkbenchMessages.get().Workbench_showInNoTargets;
+
+	private Comparator actionComparator = (o1, o2) -> {
+		if (collator == null) {
+			collator = Collator.getInstance();
+		}
+		CommandContributionItemParameter a1 = (CommandContributionItemParameter) o1;
+		CommandContributionItemParameter a2 = (CommandContributionItemParameter) o2;
+		return collator.compare(a1.label, a2.label);
+	};
+
+	private Action showDlgAction;
+
+	private Map actions = new HashMap(21);
+
+	// Maps pages to a list of opened views
+	private Map openedViews = new HashMap();
+
+	private MenuManager menuManager;
+
+	private IMenuListener menuListener = manager -> manager.markDirty();
+	private boolean makeFast;
+
+	private static Collator collator;
+
+
+	/**
+	 * Creates a Show View menu.
+	 *
+	 * @param window
+	 *            the window containing the menu
+	 * @param id
+	 *            the id
+	 */
+	public ShowViewMenu(IWorkbenchWindow window, String id) {
+		this(window, id, false);
+	}
+
+	/**
+	 * Creates a Show View menu.
+	 *
+	 * @param window
+	 *            the window containing the menu
+	 * @param id
+	 *            the id
+	 * @param makeFast use the fact view variant of the command
+	 */
+	public ShowViewMenu(IWorkbenchWindow window, String id,
+			final boolean makeFast) {
+		super(id);
+		this.window = window;
+		this.makeFast = makeFast;
+		final IHandlerService handlerService = window
+				.getService(IHandlerService.class);
+		final ICommandService commandService = window
+				.getService(ICommandService.class);
+		final ParameterizedCommand cmd = getCommand(commandService, makeFast);
+
+		showDlgAction = new Action(WorkbenchMessages.get().ShowView_title) {
+			@Override
+			public void run() {
+				try {
+					handlerService.executeCommand(cmd, null);
+				} catch (final ExecutionException e) {
+					// Do nothing.
+				} catch (NotDefinedException e) {
+					// Do nothing.
+				} catch (NotEnabledException e) {
+					// Do nothing.
+				} catch (NotHandledException e) {
+					// Do nothing.
+				}
+			}
+		};
+
+		window.getWorkbench().getHelpSystem().setHelp(showDlgAction,
+				IWorkbenchHelpContextIds.SHOW_VIEW_OTHER_ACTION);
+		// indicate that a show views submenu has been created
+		if (window instanceof WorkbenchWindow) {
+			((WorkbenchWindow) window)
+					.addSubmenu(WorkbenchWindow.SHOW_VIEW_SUBMENU);
+		}
+
+		showDlgAction.setActionDefinitionId(IWorkbenchCommandConstants.VIEWS_SHOW_VIEW);
+
+	}
+
+	/**
+	 * Overridden to always return true and force dynamic menu building.
+	 */
+	@Override
+	public boolean isDynamic() {
+		return true;
+	}
+
+	/**
+	 * Fills the menu with Show View actions.
+	 */
+	private void fillMenu(IMenuManager innerMgr) {
+		// Remove all.
+		innerMgr.removeAll();
+
+		// If no page disable all.
+		IWorkbenchPage page = window.getActivePage();
+		if (page == null) {
+			return;
+		}
+
+		// If no active perspective disable all
+		if (page.getPerspective() == null) {
+			return;
+		}
+
+		// Get visible actions.
+		List viewIds = Arrays.asList(page.getShowViewShortcuts());
+
+		// add all open views
+		viewIds = addOpenedViews(page, viewIds);
+
+		List actions = new ArrayList(viewIds.size());
+		for (Iterator i = viewIds.iterator(); i.hasNext();) {
+			String id = (String) i.next();
+			if (id.equals(IIntroConstants.INTRO_VIEW_ID)) {
+				continue;
+			}
+			CommandContributionItemParameter item = getItem(id);
+			if (item != null) {
+				actions.add(item);
+			}
+		}
+		Collections.sort(actions, actionComparator);
+		for (Iterator i = actions.iterator(); i.hasNext();) {
+			CommandContributionItemParameter ccip = (CommandContributionItemParameter) i.next();
+			if (WorkbenchActivityHelper.filterItem(ccip)) {
+				continue;
+			}
+			CommandContributionItem item = new CommandContributionItem(ccip);
+			innerMgr.add(item);
+		}
+
+		// We only want to add the separator if there are show view shortcuts,
+		// otherwise, there will be a separator and then the 'Other...' entry
+		// and that looks weird as the separator is separating nothing
+		if (!innerMgr.isEmpty()) {
+			innerMgr.add(new Separator());
+		}
+
+		// Add Other...
+		innerMgr.add(showDlgAction);
+	}
+
+	static class PluginCCIP extends CommandContributionItemParameter implements
+			IPluginContribution {
+
+		private String localId;
+		private String pluginId;
+
+		public PluginCCIP(IViewDescriptor v, IServiceLocator serviceLocator,
+				String id, String commandId, int style) {
+			super(serviceLocator, id, commandId, style);
+			localId = ((ViewDescriptor) v).getLocalId();
+			pluginId = ((ViewDescriptor) v).getPluginId();
+		}
+
+		@Override
+		public String getLocalId() {
+			return localId;
+		}
+
+		@Override
+		public String getPluginId() {
+			return pluginId;
+		}
+
+	}
+
+	private CommandContributionItemParameter getItem(String viewId) {
+		IViewRegistry reg = WorkbenchPlugin.getDefault().getViewRegistry();
+		IViewDescriptor desc = reg.find(viewId);
+		if (desc==null) {
+			return null;
+		}
+		String label = desc.getLabel();
+
+		CommandContributionItemParameter parms = new PluginCCIP(desc,
+				window, viewId, IWorkbenchCommandConstants.VIEWS_SHOW_VIEW,
+				CommandContributionItem.STYLE_PUSH);
+		parms.label = label;
+		parms.icon = desc.getImageDescriptor();
+		parms.parameters = new HashMap();
+
+		parms.parameters.put(VIEW_ID_PARM, viewId);
+		if (makeFast) {
+			parms.parameters.put(
+					IWorkbenchCommandConstants.VIEWS_SHOW_VIEW_PARM_FASTVIEW,
+					"true"); //$NON-NLS-1$
+		}
+		return parms;
+	}
+
+	private List addOpenedViews(IWorkbenchPage page, List actions) {
+		ArrayList views = getParts(page);
+		ArrayList result = new ArrayList(views.size() + actions.size());
+
+		for (int i = 0; i < actions.size(); i++) {
+			Object element = actions.get(i);
+			if (result.indexOf(element) < 0) {
+				result.add(element);
+			}
+		}
+		for (int i = 0; i < views.size(); i++) {
+			Object element = views.get(i);
+			if (result.indexOf(element) < 0) {
+				result.add(element);
+			}
+		}
+		return result;
+	}
+
+	private ArrayList getParts(IWorkbenchPage page) {
+		ArrayList parts = (ArrayList) openedViews.get(page);
+		if (parts == null) {
+			parts = new ArrayList();
+			openedViews.put(page, parts);
+		}
+		return parts;
+	}
+
+	@Override
+	public void fill(Menu menu, int index) {
+		if (getParent() instanceof MenuManager) {
+			((MenuManager) getParent()).addMenuListener(menuListener);
+		}
+
+		if (menuManager != null) {
+			menuManager.dispose();
+			menuManager = null;
+		}
+
+		menuManager = new MenuManager();
+		fillMenu(menuManager);
+		IContributionItem items[] = menuManager.getItems();
+		if (items.length == 0) {
+			MenuItem item = new MenuItem(menu, SWT.NONE, index++);
+			item.setText(NO_TARGETS_MSG);
+			item.setEnabled(false);
+		} else {
+			for (IContributionItem item : items) {
+				item.fill(menu, index++);
+			}
+		}
+	}
+
+	// for dynamic UI
+	protected void removeAction(String viewId) {
+		actions.remove(viewId);
+	}
+
+	/**
+	 * @param commandService
+	 * @param makeFast
+	 */
+	private ParameterizedCommand getCommand(ICommandService commandService,
+			final boolean makeFast) {
+		Command c = commandService.getCommand(IWorkbenchCommandConstants.VIEWS_SHOW_VIEW);
+		Parameterization[] parms = null;
+		if (makeFast) {
+			try {
+				IParameter parmDef = c
+						.getParameter(IWorkbenchCommandConstants.VIEWS_SHOW_VIEW_PARM_FASTVIEW);
+				parms = new Parameterization[] { new Parameterization(parmDef,
+						"true") //$NON-NLS-1$
+				};
+			} catch (NotDefinedException e) {
+				// this should never happen
+			}
+		}
+		return new ParameterizedCommand(c, parms);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ShowViewMenuHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ShowViewMenuHandler.java
new file mode 100644
index 0000000..066529f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ShowViewMenuHandler.java
@@ -0,0 +1,159 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2016 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
+ *     Friederike Schertel <friederike@schertel.org> - Bug 478336
+ ******************************************************************************/
+
+package org.eclipse.ui.internal;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.ExpressionInfo;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.model.application.ui.menu.MMenu;
+import org.eclipse.e4.ui.workbench.IPresentationEngine;
+import org.eclipse.e4.ui.workbench.renderers.swt.StackRenderer;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CTabFolder;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * Shows the View Menu
+ * <p>
+ * Replacement for: ShowViewMenuAction
+ * </p>
+ *
+ * @since 3.3
+ *
+ */
+public class ShowViewMenuHandler extends AbstractEvaluationHandler {
+
+	private Expression enabledWhen;
+
+	public ShowViewMenuHandler() {
+		registerEnablement();
+	}
+
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		IWorkbenchPart part = HandlerUtil.getActivePart(event);
+		if (part != null) {
+			IWorkbenchPartSite site = part.getSite();
+			if (site instanceof PartSite) {
+				final MPart model = ((PartSite) site).getModel();
+				Composite partContainer = (Composite) model.getWidget();
+				if (partContainer != null) {
+					Composite parent = partContainer.getParent();
+					while (parent != null) {
+						if (parent instanceof CTabFolder) {
+							CTabFolder ctf = (CTabFolder) parent;
+							final Control topRight = ctf.getTopRight();
+							if (topRight instanceof Composite) {
+								for (Control child : ((Composite) topRight).getChildren()) {
+									if (child instanceof ToolBar
+											&& "ViewMenu".equals(child.getData())) { //$NON-NLS-1$
+										ToolBar tb = (ToolBar) child;
+										ToolItem ti = tb.getItem(0);
+										Event sevent = new Event();
+										sevent.type = SWT.Selection;
+										sevent.widget = ti;
+										ti.notifyListeners(SWT.Selection, sevent);
+									}
+								}
+							}
+							return null;
+						}
+						parent = parent.getParent();
+					}
+
+					MMenu menuModel = StackRenderer.getViewMenu(model);
+					if (menuModel != null) {
+						showStandaloneViewMenu(event, model, menuModel, partContainer);
+					}
+				}
+			}
+		}
+		return null;
+	}
+
+	private void showStandaloneViewMenu(ExecutionEvent event, MPart model, MMenu menuModel,
+			Composite partContainer) {
+		Shell shell = partContainer.getShell();
+		Menu menu = (Menu) menuModel.getWidget();
+		if (menu == null) {
+			IPresentationEngine engine = (IPresentationEngine) HandlerUtil.getVariable(event,
+					IPresentationEngine.class.getName());
+			menu = (Menu) engine.createGui(menuModel, shell, model.getContext());
+			if (menu != null) {
+				final Menu tmpMenu = menu;
+				partContainer.addDisposeListener(e -> tmpMenu.dispose());
+			}
+		}
+
+		Display display = menu.getDisplay();
+		Point location = display.map(partContainer, null, partContainer.getLocation());
+		Point size = partContainer.getSize();
+		menu.setLocation(location.x + size.x, location.y);
+		menu.setVisible(true);
+
+		while (!menu.isDisposed() && menu.isVisible()) {
+			if (!display.readAndDispatch())
+				display.sleep();
+		}
+
+		if (!(menu.getData() instanceof MenuManager)) {
+			menu.dispose();
+		}
+	}
+
+	@Override
+	protected Expression getEnabledWhenExpression() {
+		if (enabledWhen == null) {
+			enabledWhen = new Expression() {
+				@Override
+				public EvaluationResult evaluate(IEvaluationContext context) throws CoreException {
+					// IWorkbenchPart part = InternalHandlerUtil
+					// .getActivePart(context);
+					// if (part != null) {
+					// PartPane pane = ((PartSite) part.getSite()).getPane();
+					// if ((pane instanceof ViewPane)
+					// && ((ViewPane) pane).hasViewMenu()) {
+					return EvaluationResult.TRUE;
+					// }
+					// }
+					// return EvaluationResult.FALSE;
+				}
+
+				@Override
+				public void collectExpressionInfo(ExpressionInfo info) {
+					info.addVariableNameAccess(ISources.ACTIVE_PART_NAME);
+				}
+			};
+		}
+		return enabledWhen;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/SlavePageService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/SlavePageService.java
new file mode 100644
index 0000000..f41002e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/SlavePageService.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2016 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.ui.internal;
+
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.ui.IPageListener;
+import org.eclipse.ui.IPageService;
+import org.eclipse.ui.IPerspectiveListener;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.services.IDisposable;
+
+/**
+ * @since 3.4
+ *
+ */
+public class SlavePageService implements IPageService, IDisposable {
+
+	private IPageService parent;
+	private ListenerList<IPageListener> pageListeners = new ListenerList<>(ListenerList.IDENTITY);
+	private ListenerList<IPerspectiveListener> perspectiveListeners = new ListenerList<>(
+			ListenerList.IDENTITY);
+
+	public SlavePageService(IPageService parent) {
+		if (parent == null) {
+			throw new IllegalArgumentException(
+					"Parent IPageService cannot be null"); //$NON-NLS-1$
+		}
+		this.parent = parent;
+	}
+
+	@Override
+	public void addPageListener(IPageListener listener) {
+		pageListeners.add(listener);
+		parent.addPageListener(listener);
+	}
+
+	@Override
+	public void addPerspectiveListener(IPerspectiveListener listener) {
+		perspectiveListeners.add(listener);
+		parent.addPerspectiveListener(listener);
+	}
+
+	@Override
+	public IWorkbenchPage getActivePage() {
+		return parent.getActivePage();
+	}
+
+	@Override
+	public void removePageListener(IPageListener listener) {
+		pageListeners.remove(listener);
+		parent.removePageListener(listener);
+	}
+
+	@Override
+	public void removePerspectiveListener(IPerspectiveListener listener) {
+		perspectiveListeners.remove(listener);
+		parent.removePerspectiveListener(listener);
+	}
+
+	@Override
+	public void dispose() {
+
+		for (IPageListener listener : pageListeners) {
+			parent.removePageListener(listener);
+		}
+		pageListeners.clear();
+
+		for (IPerspectiveListener listener : perspectiveListeners) {
+			parent.removePerspectiveListener(listener);
+		}
+		perspectiveListeners.clear();
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/SlavePartService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/SlavePartService.java
new file mode 100644
index 0000000..44e41f0
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/SlavePartService.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal;
+
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.ui.IPartListener;
+import org.eclipse.ui.IPartListener2;
+import org.eclipse.ui.IPartService;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartReference;
+import org.eclipse.ui.services.IDisposable;
+
+/**
+ * A part service which delegates all responsibility to the parent service. The
+ * slave service is only responsible for disposing any locally activated
+ * listeners when it is disposed.
+ * <p>
+ * This class is not intended for use outside of the
+ * <code>org.eclipse.ui.workbench</code> plug-in.
+ * </p>
+ *
+ * @since 3.4
+ *
+ */
+public class SlavePartService implements IPartService, IDisposable {
+
+	/**
+	 * The parent part service to which all listeners are routed. This value is
+	 * never <code>null</code>.
+	 */
+	private IPartService parent;
+
+	private ListenerList listeners = new ListenerList(ListenerList.IDENTITY);
+
+	/**
+	 * Constructs a new instance.
+	 *
+	 * @param parentPartService
+	 *            The parent part service for this slave. Never
+	 *            <code>null</code>.
+	 */
+	public SlavePartService(IPartService parentPartService) {
+		if (parentPartService == null) {
+			throw new IllegalArgumentException(
+					"The parent part service cannot be null"); //$NON-NLS-1$
+		}
+		this.parent = parentPartService;
+	}
+
+	@Override
+	public void addPartListener(IPartListener listener) {
+		listeners.add(listener);
+		parent.addPartListener(listener);
+	}
+
+	@Override
+	public void addPartListener(IPartListener2 listener) {
+		listeners.add(listener);
+		parent.addPartListener(listener);
+	}
+
+	@Override
+	public IWorkbenchPart getActivePart() {
+		return parent.getActivePart();
+	}
+
+	@Override
+	public IWorkbenchPartReference getActivePartReference() {
+		return parent.getActivePartReference();
+	}
+
+	@Override
+	public void removePartListener(IPartListener listener) {
+		listeners.remove(listener);
+		parent.removePartListener(listener);
+	}
+
+	@Override
+	public void removePartListener(IPartListener2 listener) {
+		listeners.remove(listener);
+		parent.removePartListener(listener);
+	}
+
+	@Override
+	public void dispose() {
+		for (Object listener : listeners.getListeners()) {
+			if (listener instanceof IPartListener) {
+				parent.removePartListener((IPartListener) listener);
+			}
+			if (listener instanceof IPartListener2) {
+				parent.removePartListener((IPartListener2) listener);
+			}
+		}
+		listeners.clear();
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/SlaveSelectionService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/SlaveSelectionService.java
new file mode 100644
index 0000000..13c812a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/SlaveSelectionService.java
@@ -0,0 +1,130 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.ui.ISelectionListener;
+import org.eclipse.ui.ISelectionService;
+import org.eclipse.ui.services.IDisposable;
+
+/**
+ * @since 3.4
+ *
+ */
+public class SlaveSelectionService implements ISelectionService, IDisposable {
+
+	private ListenerList<ISelectionListener> postListeners = new ListenerList<>(ListenerList.IDENTITY);
+	private ListenerList<ISelectionListener> listeners = new ListenerList<>(ListenerList.IDENTITY);
+	private Map<ISelectionListener, String> listenersToPartId = new HashMap<>();
+	private Map<ISelectionListener, String> postListenersToPartId = new HashMap<>();
+
+	private ISelectionService parentSelectionService;
+
+	/**
+	 * @param parentSelectionService
+	 */
+	public SlaveSelectionService(ISelectionService parentSelectionService) {
+		if (parentSelectionService == null) {
+			throw new IllegalArgumentException(
+					"The parent selection service cannot be null"); //$NON-NLS-1$
+		}
+		this.parentSelectionService = parentSelectionService;
+	}
+
+	@Override
+	public void addPostSelectionListener(ISelectionListener listener) {
+		postListeners.add(listener);
+		parentSelectionService.addPostSelectionListener(listener);
+	}
+
+	@Override
+	public void addPostSelectionListener(String partId,
+			ISelectionListener listener) {
+		listenersToPartId.put(listener, partId);
+		parentSelectionService.addPostSelectionListener(partId, listener);
+	}
+
+	@Override
+	public void addSelectionListener(ISelectionListener listener) {
+		listeners.add(listener);
+		parentSelectionService.addSelectionListener(listener);
+	}
+
+	@Override
+	public void addSelectionListener(String partId, ISelectionListener listener) {
+		postListenersToPartId.put(listener, partId);
+		parentSelectionService.addPostSelectionListener(partId, listener);
+	}
+
+	@Override
+	public ISelection getSelection() {
+		return parentSelectionService.getSelection();
+	}
+
+	@Override
+	public ISelection getSelection(String partId) {
+		return parentSelectionService.getSelection(partId);
+	}
+
+	@Override
+	public void removePostSelectionListener(ISelectionListener listener) {
+		postListeners.remove(listener);
+		parentSelectionService.removePostSelectionListener(listener);
+	}
+
+	@Override
+	public void removePostSelectionListener(String partId,
+			ISelectionListener listener) {
+		postListenersToPartId.remove(listener);
+		parentSelectionService.removePostSelectionListener(partId, listener);
+	}
+
+	@Override
+	public void removeSelectionListener(ISelectionListener listener) {
+		listeners.remove(listener);
+		parentSelectionService.removeSelectionListener(listener);
+	}
+
+	@Override
+	public void removeSelectionListener(String partId,
+			ISelectionListener listener) {
+		listenersToPartId.remove(listener);
+		parentSelectionService.removeSelectionListener(partId, listener);
+	}
+
+	@Override
+	public void dispose() {
+		for (Object listener : listeners.getListeners()) {
+			parentSelectionService.removeSelectionListener((ISelectionListener) listener);
+		}
+		listeners.clear();
+
+		for (Object listener : postListeners.getListeners()) {
+			parentSelectionService.removePostSelectionListener((ISelectionListener) listener);
+		}
+		postListeners.clear();
+
+		for (Entry<ISelectionListener, String> entry : listenersToPartId.entrySet()) {
+			parentSelectionService.removeSelectionListener(entry.getValue(), entry.getKey());
+		}
+		listenersToPartId.clear();
+
+		for (Entry<ISelectionListener, String> entry : postListenersToPartId.entrySet()) {
+			parentSelectionService.removePostSelectionListener(entry.getValue(), entry.getKey());
+		}
+		postListenersToPartId.clear();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/SplitHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/SplitHandler.java
new file mode 100644
index 0000000..4e4659d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/SplitHandler.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 2013, 2016 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
+ *     Patrik Suzzi <psuzzi@gmail.com> - Bug 494680
+ ******************************************************************************/
+package org.eclipse.ui.internal;
+
+import java.util.List;
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.e4.ui.model.application.ui.MUIElement;
+import org.eclipse.e4.ui.model.application.ui.basic.MCompositePart;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.model.application.ui.basic.MPartStack;
+import org.eclipse.e4.ui.model.application.ui.basic.MStackElement;
+import org.eclipse.e4.ui.workbench.IPresentationEngine;
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * Our sample handler extends AbstractHandler, an IHandler base class.
+ * @see org.eclipse.core.commands.IHandler
+ * @see org.eclipse.core.commands.AbstractHandler
+ */
+public class SplitHandler extends AbstractHandler {
+	private EModelService modelService;
+	private IWorkbenchWindow window;
+
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		// Only works for the active editor
+		IEditorPart activeEditor = HandlerUtil.getActiveEditor(event);
+		if (activeEditor == null)
+			return null;
+
+		MPart editorPart = activeEditor.getSite().getService(MPart.class);
+		if (editorPart == null)
+			return null;
+
+		window = HandlerUtil.getActiveWorkbenchWindowChecked(event);
+
+		// Get services
+		modelService =  editorPart.getContext().get(EModelService.class);
+
+		MPartStack stack = getStackFor(editorPart);
+		if (stack == null)
+			return null;
+
+		window.getShell().setRedraw(false);
+		try {
+			// Determine which part has the tags
+			MStackElement stackSelElement = stack.getSelectedElement();
+			MPart taggedEditor = editorPart;
+			if (stackSelElement instanceof MCompositePart) {
+				List<MPart> innerElements = modelService.findElements(stackSelElement, null, MPart.class, null);
+				taggedEditor = innerElements.get(1); // '0' is the composite part
+			}
+
+			if ("false".equals(event.getParameter("Splitter.isHorizontal"))) { //$NON-NLS-1$ //$NON-NLS-2$
+				if (taggedEditor.getTags().contains(IPresentationEngine.SPLIT_VERTICAL)) {
+					taggedEditor.getTags().remove(IPresentationEngine.SPLIT_VERTICAL);
+				} else {
+					editorPart.getTags().remove(IPresentationEngine.SPLIT_HORIZONTAL);
+					editorPart.getTags().add(IPresentationEngine.SPLIT_VERTICAL);
+				}
+			} else {
+				if (taggedEditor.getTags().contains(IPresentationEngine.SPLIT_HORIZONTAL)) {
+					taggedEditor.getTags().remove(IPresentationEngine.SPLIT_HORIZONTAL);
+				} else {
+					editorPart.getTags().remove(IPresentationEngine.SPLIT_VERTICAL);
+					editorPart.getTags().add(IPresentationEngine.SPLIT_HORIZONTAL);
+				}
+			}
+		} finally {
+			window.getShell().setRedraw(true);
+		}
+
+		return null;
+	}
+
+	private MPartStack getStackFor(MPart part) {
+		MUIElement presentationElement = part.getCurSharedRef() == null ? part : part.getCurSharedRef();
+		MUIElement parent = presentationElement.getParent();
+		while (parent != null && !(parent instanceof MPartStack))
+			parent = parent.getParent();
+
+		return (MPartStack) parent;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/SplitValues.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/SplitValues.java
new file mode 100644
index 0000000..cadfc4e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/SplitValues.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2013, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ ******************************************************************************/
+package org.eclipse.ui.internal;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.eclipse.core.commands.IParameterValues;
+
+/**
+ * Display the values that can be used in the keybindings page and quick access.
+ *
+ * @since 3.106
+ */
+public class SplitValues implements IParameterValues {
+
+	private HashMap<String, String> values = new HashMap<>();
+
+	public SplitValues() {
+		values.put(WorkbenchMessages.get().SplitValues_Horizontal, "true"); //$NON-NLS-1$
+		values.put(WorkbenchMessages.get().SplitValues_Vertical, "false"); //$NON-NLS-1$
+	}
+
+	@Override
+	public Map getParameterValues() {
+		return values;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/StandardTrim.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/StandardTrim.java
new file mode 100644
index 0000000..6d3890d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/StandardTrim.java
@@ -0,0 +1,130 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2016 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
+ *     Daniel Kruegler <daniel.kruegler@gmail.com> - Bug 471310
+ ******************************************************************************/
+
+package org.eclipse.ui.internal;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+import org.eclipse.e4.core.contexts.ContextInjectionFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolControl;
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+import org.eclipse.jface.action.StatusLineManager;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.TaskBar;
+import org.eclipse.swt.widgets.TaskItem;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.progress.ProgressRegion;
+import org.eclipse.ui.internal.progress.TaskBarProgressManager;
+import org.eclipse.ui.internal.util.PrefUtil;
+
+/**
+ * @since 3.5
+ *
+ */
+public class StandardTrim {
+	@Inject
+	EModelService modelService;
+
+	private StatusLineManager manager;
+
+	@PostConstruct
+	void createWidget(Composite parent, MToolControl toolControl) {
+		if (toolControl.getElementId().equals("org.eclipse.ui.StatusLine")) { //$NON-NLS-1$
+			createStatusLine(parent, toolControl);
+		} else if (toolControl.getElementId().equals("org.eclipse.ui.HeapStatus")) { //$NON-NLS-1$
+			createHeapStatus(parent, toolControl);
+		} else if (toolControl.getElementId().equals("org.eclipse.ui.ProgressBar")) { //$NON-NLS-1$
+			createProgressBar(parent, toolControl);
+		}
+	}
+
+	@PreDestroy
+	void destroy() {
+		if (manager != null) {
+			manager.dispose();
+			manager = null;
+		}
+	}
+
+	/**
+	 * @param parent
+	 * @param toolControl
+	 */
+	private void createProgressBar(Composite parent, MToolControl toolControl) {
+		IEclipseContext context = modelService.getContainingContext(toolControl);
+		IEclipseContext child = context.createChild(ProgressRegion.class.getName());
+		child.set(MToolControl.class, toolControl);
+		child.set(Composite.class, parent);
+		ContextInjectionFactory.make(ProgressRegion.class, child);
+
+		if (parent.getDisplay() != null && parent.getDisplay().getSystemTaskBar() != null) {
+			// only create the TaskBarProgressManager if there is a TaskBar that
+			// the progress can be displayed on
+			TaskItem taskItem = null;
+			TaskBar systemTaskBar = parent.getDisplay().getSystemTaskBar();
+			taskItem = systemTaskBar.getItem(parent.getShell());
+			if (taskItem == null) {
+				// try to get the application TaskItem
+				taskItem = systemTaskBar.getItem(null);
+			}
+
+			if (taskItem != null) {
+				// If there is a TaskItem, see if there is
+				// TaskBarProgressManager already associated with it to make
+				// sure that we don't duplicate the progress information
+				String taskBarProgressManagerKey = TaskBarProgressManager.class.getName() + ".instance"; //$NON-NLS-1$
+				Object data = taskItem.getData(taskBarProgressManagerKey);
+				if (data == null || !(data instanceof TaskBarProgressManager)) {
+					taskItem.setData(taskBarProgressManagerKey, new TaskBarProgressManager(taskItem));
+				}
+			}
+		}
+	}
+
+	/**
+	 * @param parent
+	 * @param toolControl
+	 */
+	private void createHeapStatus(Composite parent, MToolControl toolControl) {
+		new HeapStatus(parent, PrefUtil.getInternalPreferenceStore());
+	}
+
+	/**
+	 * @param parent
+	 * @param toolControl
+	 */
+	private void createStatusLine(Composite parent, MToolControl toolControl) {
+		IEclipseContext context = modelService.getContainingContext(toolControl);
+		WorkbenchWindow wbw = (WorkbenchWindow) context.get(IWorkbenchWindow.class);
+		// wbw may be null if workspace is started with no open perspectives.
+		if (wbw == null) {
+			// Create one assuming there's no defined perspective
+			Workbench wb = (Workbench) PlatformUI.getWorkbench();
+			wb.createWorkbenchWindow(wb.getDefaultPageInput(), null,
+					modelService.getTopLevelWindowFor(toolControl), false);
+			wbw = (WorkbenchWindow) context.get(IWorkbenchWindow.class);
+		}
+
+		if (wbw != null) {
+			Workbench wb = (Workbench) PlatformUI.getWorkbench();
+			wb.createWorkbenchWindow(wb.getDefaultPageInput(), null,
+					modelService.getTopLevelWindowFor(toolControl), false);
+			wbw = (WorkbenchWindow) context.get(IWorkbenchWindow.class);
+
+			manager = wbw.getStatusLineManager();
+			manager.createControl(parent);
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/StartupThreading.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/StartupThreading.java
new file mode 100644
index 0000000..8aae657
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/StartupThreading.java
@@ -0,0 +1,125 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal;
+
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.WorkbenchException;
+import org.eclipse.ui.internal.misc.StatusUtil;
+
+/**
+ * 
+ */
+public final class StartupThreading {
+
+	// RAP [bm]: 
+//	static Workbench workbench;
+	// RAPEND: [bm] 
+
+	public static abstract class StartupRunnable implements Runnable {
+		private Throwable throwable;
+
+		public final void run() {
+			try {
+				runWithException();
+			} catch (Throwable t) {
+				this.throwable = t;
+			}
+		}
+
+		public abstract void runWithException() throws Throwable;
+
+		public Throwable getThrowable() {
+			return throwable;
+		}
+	}
+
+	// RAP [bm]: 
+//	static void setWorkbench(Workbench wb) {
+//		workbench = wb;
+//	}
+	// RAPEND: [bm] 
+
+	public static void runWithWorkbenchExceptions(StartupRunnable r)
+			throws WorkbenchException {
+		// RAP [bm]: 
+//		workbench.getDisplay().syncExec(r);
+		Workbench.getInstance().getDisplay().syncExec(r);
+		// RAPEND: [bm] 
+
+		Throwable throwable = r.getThrowable();
+		if (throwable != null) {
+			if (throwable instanceof Error) {
+				throw (Error) throwable;
+			} else if (throwable instanceof RuntimeException) {
+				throw (RuntimeException) throwable;
+			} else if (throwable instanceof WorkbenchException) {
+				throw (WorkbenchException) throwable;
+			} else {
+				throw new WorkbenchException(StatusUtil.newStatus(
+						WorkbenchPlugin.PI_WORKBENCH, throwable));
+			}
+		}
+	}
+
+	public static void runWithPartInitExceptions(StartupRunnable r)
+			throws PartInitException {
+		// RAP [bm]: 
+//		workbench.getDisplay().syncExec(r);
+		Workbench.getInstance().getDisplay().syncExec(r);
+		// RAPEND: [bm] 
+		Throwable throwable = r.getThrowable();
+		if (throwable != null) {
+			if (throwable instanceof Error) {
+				throw (Error) throwable;
+			} else if (throwable instanceof RuntimeException) {
+				throw (RuntimeException) throwable;
+			} else if (throwable instanceof WorkbenchException) {
+				throw (PartInitException) throwable;
+			} else {
+				throw new PartInitException(StatusUtil.newStatus(
+						WorkbenchPlugin.PI_WORKBENCH, throwable));
+			}
+		}
+	}
+
+	public static void runWithThrowable(StartupRunnable r) throws Throwable {
+		// RAP [bm]: 
+//		workbench.getDisplay().syncExec(r);
+		Workbench.getInstance().getDisplay().syncExec(r);
+		// RAPEND: [bm] 
+
+		Throwable throwable = r.getThrowable();
+		if (throwable != null) {
+			throw throwable;
+		}
+	}
+
+	public static void runWithoutExceptions(StartupRunnable r)
+			throws RuntimeException {
+		// RAP [bm]: 
+//		workbench.getDisplay().syncExec(r);
+		Workbench.getInstance().getDisplay().syncExec(r);
+		// RAPEND: [bm] 
+
+		Throwable throwable = r.getThrowable();
+		if (throwable != null) {
+			if (throwable instanceof Error) {
+				throw (Error) throwable;
+			} else if (throwable instanceof RuntimeException) {
+				throw (RuntimeException) throwable;
+			} else {
+				throw new RuntimeException(throwable);
+			}
+		}
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/SwitchToWindowMenu.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/SwitchToWindowMenu.java
new file mode 100644
index 0000000..c72a82e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/SwitchToWindowMenu.java
@@ -0,0 +1,136 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.jface.action.ContributionItem;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchWindow;
+
+/**
+ * A dynamic menu item to switch to other opened workbench windows.
+ */
+public class SwitchToWindowMenu extends ContributionItem {
+    private static final int MAX_TEXT_LENGTH = 40;
+
+    private IWorkbenchWindow workbenchWindow;
+
+    private boolean showSeparator;
+
+    /**
+     * Creates a new instance of this class.
+     *
+     * @param window the workbench window this action applies to
+     * @param showSeparator whether to add a separator in the menu
+     */
+    public SwitchToWindowMenu(IWorkbenchWindow window, String id,
+            boolean showSeparator) {
+        super(id);
+        this.workbenchWindow = window;
+        this.showSeparator = showSeparator;
+    }
+
+    /**
+     * Returns the text for a window. This may be truncated to fit
+     * within the MAX_TEXT_LENGTH.
+     */
+    private String calcText(int number, IWorkbenchWindow window) {
+        String suffix = window.getShell().getText();
+        if (suffix == null) {
+			return null;
+		}
+
+        StringBuffer sb = new StringBuffer();
+        if (number < 10) {
+			sb.append('&');
+		}
+        sb.append(number);
+        sb.append(' ');
+        if (suffix.length() <= MAX_TEXT_LENGTH) {
+            sb.append(suffix);
+        } else {
+            sb.append(suffix.substring(0, MAX_TEXT_LENGTH));
+            sb.append("..."); //$NON-NLS-1$
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Fills the given menu with menu items for all
+     * opened workbench windows.
+     */
+    @Override
+	public void fill(Menu menu, int index) {
+
+        // Get workbench windows.
+        IWorkbench workbench = workbenchWindow.getWorkbench();
+        IWorkbenchWindow[] array = workbench.getWorkbenchWindows();
+        // avoid showing the separator and list for 0 or 1 items
+        if (array.length < 2) {
+			return;
+		}
+
+        // Add separator.
+        if (showSeparator) {
+            new MenuItem(menu, SWT.SEPARATOR, index);
+            ++index;
+        }
+
+        // Add one item for each window.
+        int count = 1;
+		for (IWorkbenchWindow window : array) {
+            // can encounter disposed shells if this update is in response to a shell closing
+            if (!window.getShell().isDisposed()) {
+                String name = calcText(count, window);
+                if (name != null) {
+                    MenuItem mi = new MenuItem(menu, SWT.RADIO, index);
+                    index++;
+                    count++;
+                    mi.setText(name);
+                    mi.addSelectionListener(new SelectionAdapter()
+                    {
+                        public void widgetSelected(SelectionEvent e) 
+                        {
+    					    Shell windowShell = window.getShell();
+    					    if (windowShell.getMinimized()) {
+    							windowShell.setMinimized(false);
+    						}
+    					    windowShell.setActive();
+    					    windowShell.moveAbove(null);
+                        }
+					});
+                    mi.setSelection(window == workbenchWindow);
+                }
+            }
+        }
+    }
+
+    /**
+     * Overridden to always return true and force dynamic menu building.
+     */
+    @Override
+	public boolean isDirty() {
+		return true;
+    }
+
+    /**
+     * Overridden to always return true and force dynamic menu building.
+     */
+    @Override
+	public boolean isDynamic() {
+        return true;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ToggleEditorsVisibilityAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ToggleEditorsVisibilityAction.java
new file mode 100644
index 0000000..440b48d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ToggleEditorsVisibilityAction.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.IPerspectiveListener;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+
+/**
+ * Hides or shows the editor area within the current
+ * perspective of the workbench page.
+ */
+public class ToggleEditorsVisibilityAction extends PerspectiveAction implements
+        IPerspectiveListener {
+
+    @Override
+	public void perspectiveActivated(IWorkbenchPage page,
+            IPerspectiveDescriptor perspective) {
+        if (page.isEditorAreaVisible()) {
+            setText(WorkbenchMessages.get().ToggleEditor_hideEditors);
+        } else {
+            setText(WorkbenchMessages.get().ToggleEditor_showEditors);
+        }
+    }
+
+    @Override
+	public void perspectiveChanged(IWorkbenchPage page,
+            IPerspectiveDescriptor perspective, String changeId) {
+        if (changeId == IWorkbenchPage.CHANGE_RESET
+                || changeId == IWorkbenchPage.CHANGE_EDITOR_AREA_HIDE
+                || changeId == IWorkbenchPage.CHANGE_EDITOR_AREA_SHOW) {
+            if (page.isEditorAreaVisible()) {
+                setText(WorkbenchMessages.get().ToggleEditor_hideEditors);
+            } else {
+                setText(WorkbenchMessages.get().ToggleEditor_showEditors);
+            }
+        }
+    }
+
+    /**
+     * Creates a new <code>ToggleEditorsVisibilityAction</code>
+     *
+     * @param window the window
+     */
+    public ToggleEditorsVisibilityAction(IWorkbenchWindow window) {
+        super(window);
+        setText(WorkbenchMessages.get().ToggleEditor_hideEditors);
+        setActionDefinitionId("org.eclipse.ui.window.hideShowEditors"); //$NON-NLS-1$
+        // @issue missing action id
+        setToolTipText(WorkbenchMessages.get().ToggleEditor_toolTip);
+        window.getWorkbench().getHelpSystem().setHelp(this,
+                IWorkbenchHelpContextIds.TOGGLE_EDITORS_VISIBILITY_ACTION);
+        window.addPerspectiveListener(this);
+    }
+
+    @Override
+	protected void run(IWorkbenchPage page, IPerspectiveDescriptor persp) {
+        boolean visible = page.isEditorAreaVisible();
+        if (visible) {
+            page.setEditorAreaVisible(false);
+            setText(WorkbenchMessages.get().ToggleEditor_showEditors);
+        } else {
+            page.setEditorAreaVisible(true);
+            setText(WorkbenchMessages.get().ToggleEditor_hideEditors);
+        }
+    }
+
+    @Override
+	public void dispose() {
+        if (getWindow() != null) {
+            getWindow().removePerspectiveListener(this);
+        }
+        super.dispose();
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/TrimFrame.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/TrimFrame.java
new file mode 100644
index 0000000..8782d82
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/TrimFrame.java
@@ -0,0 +1,189 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.CoolBar;
+import org.eclipse.swt.widgets.Layout;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.ui.themes.ColorUtil;
+
+/**
+ * Draws a styled frame around its contained controls.
+ * This class is intended to be used to wrap various
+ * trim elements that appear in the workbench.
+ *
+ *  Currently this class expects a <b>single</b> child
+ *  control.
+ *
+ * @since 3.3
+ *
+ */
+public class TrimFrame {
+	private static int blend = 40;
+
+    Canvas canvas = null;
+
+    public TrimFrame(Composite parent) {
+        createControl(parent);
+    }
+
+    private void createControl(Composite parent) {
+        dispose();
+        canvas = new Canvas(parent, SWT.NONE);
+        canvas.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
+
+        // paint the border
+        canvas.addPaintListener(new PaintListener() {
+            private void drawLine (GC gc, int x1, int y1, int x2, int y2, boolean flipXY) {
+                if (flipXY) {
+                    int tmp = x1;
+                    x1 = y1;
+                    y1 = tmp;
+                    tmp = x2;
+                    x2 = y2;
+                    y2 = tmp;
+                }
+
+                 gc.drawLine(x1, y1, x2, y2);
+            }
+
+            @Override
+			public void paintControl(PaintEvent e) {
+                Canvas canvas = (Canvas)e.widget;
+                Control child = canvas.getChildren ()[0];
+
+                // Are we horizontally or vertically aligned
+                boolean flipXY = false;
+                if (child instanceof ToolBar && (((ToolBar)child).getStyle() & SWT.VERTICAL) != 0)
+                    flipXY = true;
+                else if (child instanceof CoolBar && (((CoolBar)child).getStyle() & SWT.VERTICAL) != 0)
+                    flipXY = true;
+
+                Rectangle bb = canvas.getBounds();
+                int maxX = bb.width-1;
+                int maxY = bb.height-1;
+
+                if (flipXY) {
+                    int tmp = maxX;
+                    maxX = maxY;
+                    maxY = tmp;
+                }
+
+                Color white = e.gc.getDevice ().getSystemColor(SWT.COLOR_WHITE);
+                Color shadow = e.gc.getDevice().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW);
+                RGB outerRGB = ColorUtil.blend(white.getRGB(), shadow.getRGB(), blend);
+                Color outerColor = new Color(e.gc.getDevice(), outerRGB);
+
+                // Draw the 'outer' bits
+                e.gc.setForeground(outerColor);
+
+                // Top Line and curve
+                drawLine(e.gc, 1, 0, maxX-5, 0, flipXY);
+                drawLine(e.gc, maxX-4, 1, maxX-3, 1, flipXY);
+                drawLine(e.gc, maxX-2, 2, maxX-2, 2, flipXY);
+                drawLine(e.gc, maxX-1, 3, maxX-1, 4, flipXY);
+
+                // Bottom line and curve
+                drawLine(e.gc, 1, maxY, maxX-5, maxY, flipXY);
+                drawLine( e.gc, maxX-4, maxY-1, maxX-3, maxY-1, flipXY);
+                drawLine(e.gc, maxX-2, maxY-2, maxX-2, maxY-2, flipXY);
+                drawLine(e.gc, maxX-1, maxY-3, maxX-1, maxY-4, flipXY);
+
+                // Left & Right edges
+                drawLine(e.gc, 0, 1, 0, maxY-1, flipXY);
+                drawLine(e.gc, maxX, 5, maxX, maxY-5, flipXY);
+
+                // Dispose the color since we created it...
+                outerColor.dispose();
+
+                // Draw the 'inner' curve
+                e.gc.setForeground (white);
+
+                drawLine(e.gc, 1, 1, maxX-5, 1, flipXY);
+                drawLine(e.gc, maxX-4, 2, maxX-3, 2, flipXY);
+                drawLine(e.gc, maxX-3, 3, maxX-2, 3, flipXY);
+                drawLine( e.gc, maxX-2, 4, maxX-2, 4, flipXY);
+
+                drawLine(e.gc, 1, maxY-1, maxX-5, maxY-1, flipXY);
+                drawLine(e.gc, maxX-4, maxY-2, maxX-3, maxY-2, flipXY);
+                drawLine( e.gc, maxX-3, maxY-3, maxX-2, maxY-3, flipXY);
+                drawLine(e.gc, maxX-2, maxY-4, maxX-2, maxY-4, flipXY);
+
+                // Left and Right sides
+                drawLine(e.gc, 1, 1, 1, maxY-1, flipXY);
+                drawLine(e.gc, maxX-1, 5, maxX-1, maxY-5, flipXY);
+            }
+        });
+
+        // provide a layout that provides enough extra space to
+        // draw the border and to place the child conrol in the
+        // correct location
+        canvas.setLayout(new Layout() {
+
+			@Override
+			protected Point computeSize(Composite composite, int wHint,
+                    int hHint, boolean changed) {
+                Control[] children = composite.getChildren();
+
+                if (children.length == 0)
+                    return new Point(0,0);
+
+                Point innerSize = children[0].computeSize(hHint, wHint, changed);
+                innerSize.x += 4;
+                innerSize.y += 4;
+
+                Control child = children[0];
+                if (child instanceof CoolBar && (((CoolBar)child).getStyle() & SWT.VERTICAL) != 0)
+                    innerSize.y += 3;
+                else
+                    innerSize.x += 3;
+
+                return innerSize;
+            }
+
+            @Override
+			protected void layout(Composite composite, boolean flushCache) {
+                Control[] children = composite.getChildren();
+                if (children.length == 0)
+                    return;
+
+                children[0].setLocation(2, 2);
+            }
+        });
+    }
+
+    /**
+     * Dispose the frame
+     */
+    private void dispose() {
+        if (canvas != null && !canvas.isDisposed())
+            canvas.dispose();
+    }
+
+    /**
+     * @return The border canvas
+     */
+    public Composite getComposite() {
+    	return canvas;
+    }
+}
+
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/TrimUtil.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/TrimUtil.java
new file mode 100644
index 0000000..cda839a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/TrimUtil.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+
+/**
+ * Simple class to provide some common internal Trim support.
+ *
+ * @since 3.2
+ *
+ */
+public class TrimUtil {
+
+    /**
+     * Default height for workbench trim.
+     */
+    public static final int TRIM_DEFAULT_HEIGHT;
+    static {
+    	Shell s = new Shell(Display.getCurrent(), SWT.NONE);
+    	s.setLayout(new GridLayout());
+    	ToolBar t = new ToolBar(s, SWT.NONE);
+    	t.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+    	ToolItem ti = new ToolItem(t, SWT.PUSH);
+    	ti.setImage(JFaceResources.getImageRegistry().get(Dialog.DLG_IMG_MESSAGE_INFO));
+    	s.layout();
+    	int toolItemHeight = t.computeSize(SWT.DEFAULT, SWT.DEFAULT).y;
+    	GC gc = new GC(s);
+    	Point fontSize = gc.textExtent("Wg"); //$NON-NLS-1$
+    	gc.dispose();
+    	TRIM_DEFAULT_HEIGHT = Math.max(toolItemHeight, fontSize.y);
+    	s.dispose();
+
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/UILockListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/UILockListener.java
new file mode 100644
index 0000000..57d4223
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/UILockListener.java
@@ -0,0 +1,224 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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 - Initial API and implementation
+ *     Jeremiah Lott (jeremiah.lott@timesys.com) - fix for deadlock bug 76378
+ *
+ *******************************************************************************/
+package org.eclipse.ui.internal;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadInfo;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.LockListener;
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * The UI lock listener is used to prevent the UI thread from deadlocking on
+ * a lock when the thread owning the lock is attempting to syncExec.
+ */
+public class UILockListener extends LockListener {
+
+    /**
+     * The Queue is the construct that keeps track of Semaphores.
+     */
+    public class Queue {
+        private static final int BASE_SIZE = 8;
+
+        protected PendingSyncExec[] elements = new PendingSyncExec[BASE_SIZE];
+
+        protected int head = 0;
+
+        protected int tail = 0;
+
+        /**
+         * Add the semaphore to the queue.
+         * @param element
+         */
+        public synchronized void add(PendingSyncExec element) {
+            int newTail = increment(tail);
+            if (newTail == head) {
+                grow();
+                newTail = tail + 1;
+            }
+            elements[tail] = element;
+            tail = newTail;
+        }
+
+        private void grow() {
+            int newSize = elements.length * 2;
+            PendingSyncExec[] newElements = new PendingSyncExec[newSize];
+            if (tail >= head) {
+				System.arraycopy(elements, head, newElements, head, size());
+			} else {
+                int newHead = newSize - (elements.length - head);
+                System.arraycopy(elements, 0, newElements, 0, tail + 1);
+                System.arraycopy(elements, head, newElements, newHead,
+                        (newSize - newHead));
+                head = newHead;
+            }
+            elements = newElements;
+        }
+
+        private int increment(int index) {
+            return (index == (elements.length - 1)) ? 0 : index + 1;
+        }
+
+        /**
+         * Remove the next semaphore to be woken up.
+         * @return
+         */
+        public synchronized PendingSyncExec remove() {
+            if (tail == head) {
+				return null;
+			}
+            PendingSyncExec result = elements[head];
+            elements[head] = null;
+            head = increment(head);
+            //reset the queue if it is empty and it has grown
+            if (tail == head && elements.length > BASE_SIZE) {
+                elements = new PendingSyncExec[BASE_SIZE];
+                tail = head = 0;
+            }
+            return result;
+        }
+
+        private int size() {
+            return tail > head ? (tail - head)
+                    : ((elements.length - head) + tail);
+        }
+    }
+
+    protected Display display;
+
+    protected final Queue pendingWork = new Queue();
+
+    protected PendingSyncExec currentWork = null;
+
+	/**
+	 * Points to the UI thread if it is currently waiting on a lock or null
+	 */
+	protected volatile Thread ui;
+
+    /**
+     * Create a new instance of the receiver.
+     * @param display
+     */
+    public UILockListener(Display display) {
+        this.display = display;
+    }
+
+    @Override
+	public void aboutToRelease() {
+        if (isUI()) {
+			ui = null;
+		}
+    }
+
+    @Override
+	public boolean aboutToWait(Thread lockOwner) {
+        if (isUI()) {
+            // If a syncExec was executed from the current operation, it
+            // has already acquired the lock. So, just return true.
+            if (currentWork != null
+                    && currentWork.getOperationThread() == lockOwner) {
+				return true;
+			}
+            ui = Thread.currentThread();
+            try {
+                doPendingWork();
+            } finally {
+                //UI field may be nulled if there is a nested wait during execution
+                //of pending work, so make sure it is assigned before we start waiting
+                ui = Thread.currentThread();
+            }
+        }
+        return false;
+    }
+
+    void addPendingWork(PendingSyncExec work) {
+        pendingWork.add(work);
+    }
+
+	@Override
+	public boolean canBlock() {
+		return !isUI();
+	}
+
+	/**
+	 * Should always be called from the UI thread.
+	 */
+	void doPendingWork() {
+		// Clear the interrupt flag that we may have set in interruptUI()
+		Thread.interrupted();
+		PendingSyncExec work;
+		while ((work = pendingWork.remove()) != null) {
+			// Remember the old current work before replacing, to handle
+			// the nested waiting case (bug 76378)
+			PendingSyncExec oldWork = currentWork;
+			try {
+				currentWork = work;
+				work.run();
+			} finally {
+				currentWork = oldWork;
+			}
+		}
+	}
+
+	void interruptUI(Runnable runnable) {
+		reportInterruption(runnable);
+        display.getThread().interrupt();
+    }
+
+    boolean isLockOwner() {
+        return isLockOwnerThread();
+    }
+
+    boolean isUI() {
+        return (!display.isDisposed())
+                && (display.getThread() == Thread.currentThread());
+    }
+
+	boolean isUIWaiting() {
+		Thread localUi = ui;
+		return (localUi != null) && (Thread.currentThread() != localUi);
+	}
+
+	/**
+	 * Adds a 'UI thread interrupted' message to the log with extra lock state
+	 * and thread stack information.
+	 */
+	private void reportInterruption(Runnable runnable) {
+		Thread nonUiThread = Thread.currentThread();
+
+		String msg = "To avoid deadlock while executing Display.syncExec() with argument: " //$NON-NLS-1$
+				+ runnable + ", thread " + nonUiThread.getName() //$NON-NLS-1$
+				+ " will interrupt UI thread."; //$NON-NLS-1$
+		MultiStatus main = new MultiStatus(WorkbenchPlugin.PI_WORKBENCH, IStatus.ERROR, msg, null);
+
+		ThreadInfo[] threads = ManagementFactory.getThreadMXBean().getThreadInfo(new long[] { nonUiThread.getId(), display.getThread().getId() }, true, true);
+
+		for (ThreadInfo info : threads) {
+			String childMsg;
+			if (info.getThreadId() == nonUiThread.getId()) {
+				// see org.eclipse.core.internal.jobs.LockManager.isLockOwner()
+				childMsg = nonUiThread.getName() + " thread is an instance of Worker or owns an ILock"; //$NON-NLS-1$
+			} else {
+				childMsg = "UI thread waiting on a job or lock."; //$NON-NLS-1$
+			}
+			Exception childEx = new IllegalStateException("Call stack for thread " + info.getThreadName()); //$NON-NLS-1$
+			childEx.setStackTrace(info.getStackTrace());
+			Status child = new Status(IStatus.ERROR, WorkbenchPlugin.PI_WORKBENCH, IStatus.ERROR, childMsg, childEx);
+			main.add(child);
+		}
+
+		WorkbenchPlugin.log(main);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/UISynchronizer.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/UISynchronizer.java
new file mode 100644
index 0000000..9ace9ed
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/UISynchronizer.java
@@ -0,0 +1,157 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Synchronizer;
+import org.eclipse.ui.internal.StartupThreading.StartupRunnable;
+
+public class UISynchronizer extends Synchronizer {
+    protected UILockListener lockListener;
+
+    /**
+	 * Indicates that the UI is in startup mode and that no non-workbench
+	 * runnables should be invoked.
+	 */
+	protected boolean isStarting = true;
+
+	/**
+	 * List of non-workbench Runnables that need executing at some point in the future
+	 */
+	protected List pendingStartup = new ArrayList();
+
+	/**
+	 * If this boolean is set to true the synchronizer will fall back to the
+	 * behaviour it had prior to 3.3/3.4. Ie: there will be no restriction on
+	 * what runnables may be run via a/syncExec calls.
+	 *
+	 * @see IPreferenceConstants#USE_32_THREADING
+	 */
+	private boolean use32Threading = false;
+
+	/**
+	 * Setting this variable to the value {@link Boolean#TRUE} will allow a
+	 * thread to execute code during the startup sequence.
+	 */
+	public static final ThreadLocal startupThread = new ThreadLocal() {
+
+		@Override
+		protected Object initialValue() {
+			return Boolean.FALSE;
+		}
+
+		@Override
+		public void set(Object value) {
+			if (value != Boolean.TRUE && value != Boolean.FALSE)
+				throw new IllegalArgumentException();
+			super.set(value);
+		}
+	};
+
+	public static final ThreadLocal overrideThread = new ThreadLocal() {
+		@Override
+		protected Object initialValue() {
+			return Boolean.FALSE;
+		}
+		@Override
+		public void set(Object value) {
+			if (value != Boolean.TRUE && value != Boolean.FALSE)
+				throw new IllegalArgumentException();
+			if (value == Boolean.TRUE
+                    && ((Boolean)startupThread.get()).booleanValue()) {
+				throw new IllegalStateException();
+			}
+			super.set(value);
+		}
+	};
+
+    public UISynchronizer(Display display, UILockListener lock) {
+        super(display);
+        this.lockListener = lock;
+        use32Threading = WorkbenchPlugin.getDefault()
+				.getPreferenceStore().getBoolean(
+						IPreferenceConstants.USE_32_THREADING);
+    }
+
+    public void started() {
+    	synchronized (this) {
+			if (!isStarting)
+				throw new IllegalStateException();
+			isStarting = false;
+			for (Iterator i = pendingStartup.iterator(); i.hasNext();) {
+				Runnable runnable = (Runnable) i.next();
+				try {
+					//queue up all pending asyncs
+					super.asyncExec(runnable);
+				} catch (RuntimeException e) {
+					// do nothing
+				}
+			}
+			pendingStartup = null;
+			// wake up all pending syncExecs
+			this.notifyAll();
+    	}
+    }
+
+    @Override
+	protected void asyncExec(Runnable runnable) {
+    	// the following block should not be invoked if we're using 3.2 threading.
+    	if (runnable != null && !use32Threading) {
+			synchronized (this) {
+				if (isStarting && !(runnable instanceof StartupRunnable)
+						&& overrideThread.get() == Boolean.FALSE) {
+
+					// don't run it now, add it to the list of deferred runnables
+					pendingStartup.add(runnable);
+
+					return;
+				}
+			}
+		}
+    	super.asyncExec(runnable);
+    }
+
+	@Override
+	public void syncExec(Runnable runnable) {
+
+		synchronized (this) {
+			// the following block should not be invoked if we're using 3.2 threading.
+			if (isStarting && !use32Threading && startupThread.get() == Boolean.FALSE
+					&& overrideThread.get() == Boolean.FALSE) {
+				do {
+					try {
+						this.wait();
+					} catch (InterruptedException e) {
+					}
+				} while (isStarting);
+			}
+		}
+
+        //if this thread is the UI or this thread does not own any locks, just do the syncExec
+        if ((runnable == null) || lockListener.isUI()
+                || !lockListener.isLockOwner()) {
+            super.syncExec(runnable);
+            return;
+        }
+        PendingSyncExec work = new PendingSyncExec(runnable);
+        work.setOperationThread(Thread.currentThread());
+        lockListener.addPendingWork(work);
+        asyncExec(() -> lockListener.doPendingWork());
+
+		try {
+			work.waitUntilExecuted(lockListener);
+		} catch (InterruptedException e) {
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ViewActionBuilder.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ViewActionBuilder.java
new file mode 100644
index 0000000..e0a13b0
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ViewActionBuilder.java
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import java.util.ArrayList;
+
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+
+/**
+ * This class reads the registry for extensions that plug into
+ * 'viewActions' extension point.
+ */
+public class ViewActionBuilder extends PluginActionBuilder {
+    public static final String TAG_CONTRIBUTION_TYPE = "viewContribution"; //$NON-NLS-1$
+
+    private IViewPart targetPart;
+
+    /**
+     * Basic constructor
+     */
+    public ViewActionBuilder() {
+    }
+
+    /**
+     * Contribute the external menus and actions applicable for this view part.
+     */
+    private void contributeToPart(IViewPart part) {
+        IActionBars bars = part.getViewSite().getActionBars();
+        contribute(bars.getMenuManager(), bars.getToolBarManager(), true);
+    }
+
+    @Override
+	protected ActionDescriptor createActionDescriptor(
+            org.eclipse.core.runtime.IConfigurationElement element) {
+        return new ActionDescriptor(element, ActionDescriptor.T_VIEW,
+                targetPart);
+    }
+
+    /**
+     * Return all extended actions.
+     */
+    public ActionDescriptor[] getExtendedActions() {
+        if (cache == null) {
+			return new ActionDescriptor[0];
+		}
+
+        ArrayList results = new ArrayList();
+        for (int i = 0; i < cache.size(); i++) {
+            BasicContribution bc = (BasicContribution) cache.get(i);
+            if (bc.actions != null) {
+				results.addAll(bc.actions);
+			}
+        }
+        return (ActionDescriptor[]) results
+                .toArray(new ActionDescriptor[results.size()]);
+    }
+
+    /**
+     * Reads and apply all external contributions for this view's ID registered
+     * in 'viewActions' extension point.
+     */
+    public void readActionExtensions(IViewPart viewPart) {
+        targetPart = viewPart;
+        readContributions(viewPart.getSite().getId(), TAG_CONTRIBUTION_TYPE,
+                IWorkbenchRegistryConstants.PL_VIEW_ACTIONS);
+        contributeToPart(targetPart);
+    }
+
+    public void dispose() {
+		if (cache != null) {
+			for (int i = 0; i < cache.size(); i++) {
+				((BasicContribution) cache.get(i)).disposeActions();
+			}
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ViewIntroAdapterPart.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ViewIntroAdapterPart.java
new file mode 100644
index 0000000..0b44e25
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ViewIntroAdapterPart.java
@@ -0,0 +1,242 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2012, 2015 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
+ *     Dirk Fauth <dirk.fauth@googlemail.com> - Bug 463043
+ *******************************************************************************/
+package org.eclipse.ui.internal;
+
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.e4.core.services.events.IEventBroker;
+import org.eclipse.e4.ui.model.application.ui.MUIElement;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.model.application.ui.basic.MPartStack;
+import org.eclipse.e4.ui.workbench.IPresentationEngine;
+import org.eclipse.e4.ui.workbench.UIEvents;
+import org.eclipse.e4.ui.workbench.UIEvents.EventTags;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IViewSite;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.internal.intro.IntroMessages;
+import org.eclipse.ui.internal.util.PrefUtil;
+import org.eclipse.ui.intro.IIntroPart;
+import org.eclipse.ui.intro.IIntroSite;
+import org.eclipse.ui.part.ViewPart;
+import org.osgi.service.event.EventHandler;
+
+/**
+ * Simple view that will wrap an <code>IIntroPart</code>.
+ *
+ * @since 3.0
+ */
+public final class ViewIntroAdapterPart extends ViewPart {
+
+    private IIntroPart introPart;
+
+    private IIntroSite introSite;
+
+    private boolean handleZoomEvents = true;
+
+	private IEventBroker eventBroker;
+
+	private EventHandler zoomChangeListener = event -> {
+		if (!handleZoomEvents)
+			return;
+
+		Object changedObj = event.getProperty(EventTags.ELEMENT);
+		if (!(changedObj instanceof MPartStack))
+			return;
+
+		if (changedObj != getIntroStack())
+			return;
+
+		if (UIEvents.isADD(event)
+				&& UIEvents.contains(event, UIEvents.EventTags.NEW_VALUE,
+						IPresentationEngine.MAXIMIZED)) {
+			setStandby(false);
+		} else if (UIEvents.isREMOVE(event)
+				&& UIEvents.contains(event, UIEvents.EventTags.OLD_VALUE,
+						IPresentationEngine.MAXIMIZED)) {
+			setStandby(true);
+		}
+	};
+
+
+    /**
+     * Adds a listener that toggles standby state if the view pane is zoomed.
+     */
+    private void addZoomListener() {
+		ViewSite site = (ViewSite) getViewSite();
+		MPart introModelPart = site.getModel();
+		if (introModelPart == null || introModelPart.getContext() == null)
+			return;
+
+		eventBroker = introModelPart.getContext().get(IEventBroker.class);
+		eventBroker.subscribe(UIEvents.ApplicationElement.TOPIC_TAGS, zoomChangeListener);
+    }
+
+	private MPartStack getIntroStack() {
+		ViewSite site = (ViewSite) getViewSite();
+
+		MPart introModelPart = site.getModel();
+		if (introModelPart.getCurSharedRef() != null) {
+			MUIElement introPartParent = introModelPart.getCurSharedRef().getParent();
+			if (introPartParent instanceof MPartStack) {
+				return (MPartStack) introPartParent;
+			}
+		}
+
+		return null;
+	}
+
+    /**
+     * Forces the standby state of the intro part.
+     *
+     * @param standby update the standby state
+     */
+    public void setStandby(final boolean standby) {
+		final Control control = (Control) ((PartSite) getSite()).getModel().getWidget();
+        BusyIndicator.showWhile(control.getDisplay(), () -> {
+		    try {
+		        control.setRedraw(false);
+		        introPart.standbyStateChanged(standby);
+		    } finally {
+		        control.setRedraw(true);
+		    }
+
+		    setBarVisibility(standby);
+		});
+    }
+
+    /**
+     * Toggles handling of zoom events.
+     *
+     * @param handle whether to handle zoom events
+     */
+    public void setHandleZoomEvents(boolean handle) {
+        handleZoomEvents = handle;
+    }
+
+    @Override
+	public void createPartControl(Composite parent) {
+        addZoomListener();
+        introPart.createPartControl(parent);
+
+		ViewSite site = (ViewSite) getViewSite();
+		MPart introModelPart = site.getModel();
+		if (introModelPart.getCurSharedRef() != null) {
+			MUIElement parentElement = introModelPart.getCurSharedRef().getParent();
+			if (parentElement instanceof MPartStack) {
+				setStandby(!parentElement.getTags().contains(IPresentationEngine.MAXIMIZED));
+			}
+		}
+    }
+
+    @Override
+	public void dispose() {
+		eventBroker.unsubscribe(zoomChangeListener);
+
+    	setBarVisibility(true);
+        super.dispose();
+        getSite().getWorkbenchWindow().getWorkbench().getIntroManager()
+                .closeIntro(introPart);
+        introPart.dispose();
+    }
+
+    @Override
+	public <T> T getAdapter(Class<T> adapter) {
+		return Adapters.adapt(introPart, adapter);
+    }
+
+    @Override
+	public Image getTitleImage() {
+        return introPart.getTitleImage();
+    }
+
+    @Override
+	public String getTitle() {
+    	// this method is called eagerly before our init method is called (and
+    	// therefore before our intropart is created).  By default return
+    	// the view title from the view declaration.  We will fire a property
+    	// change to set the title to the proper value in the init method.
+    	return introPart == null ? super.getTitle() : introPart.getTitle();
+    }
+
+    @Override
+	public void init(IViewSite site, IMemento memento) throws PartInitException {
+        super.init(site);
+        Workbench workbench = (Workbench) site.getWorkbenchWindow()
+                .getWorkbench();
+        try {
+            introPart = workbench.getWorkbenchIntroManager()
+                    .createNewIntroPart();
+            // reset the part name of this view to be that of the intro title
+            setPartName(introPart.getTitle());
+            introPart.addPropertyListener((source, propId) -> firePropertyChange(propId));
+            introSite = new ViewIntroAdapterSite(site, workbench
+                    .getIntroDescriptor());
+            introPart.init(introSite, memento);
+
+        } catch (CoreException e) {
+            WorkbenchPlugin
+                    .log(
+                            IntroMessages.Intro_could_not_create_proxy, new Status(IStatus.ERROR, WorkbenchPlugin.PI_WORKBENCH, IStatus.ERROR, IntroMessages.Intro_could_not_create_proxy, e));
+        }
+    }
+
+    @Override
+	public void setFocus() {
+        introPart.setFocus();
+    }
+
+    @Override
+	public void saveState(IMemento memento) {
+        introPart.saveState(memento);
+    }
+
+	/**
+	 * Sets whether the CoolBar/PerspectiveBar should be visible.
+	 *
+	 * @param visible whether the CoolBar/PerspectiveBar should be visible
+	 * @since 3.1
+	 */
+	private void setBarVisibility(final boolean visible) {
+		WorkbenchWindow window = (WorkbenchWindow) getSite()
+				.getWorkbenchWindow();
+
+		boolean layout = false; // don't layout unless things have actually changed
+		if (visible) {
+			// Restore the last 'saved' state
+			boolean coolbarVisible = PrefUtil
+					.getInternalPreferenceStore().getBoolean(
+							IPreferenceConstants.COOLBAR_VISIBLE);
+			boolean persBarVisible = PrefUtil
+					.getInternalPreferenceStore().getBoolean(
+							IPreferenceConstants.PERSPECTIVEBAR_VISIBLE);
+			layout = (coolbarVisible != window.getCoolBarVisible())
+				|| (persBarVisible != window.getPerspectiveBarVisible());
+			window.setCoolBarVisible(coolbarVisible);
+			window.setPerspectiveBarVisible(persBarVisible);
+		} else {
+			layout = !window.getCoolBarVisible() || !window.getPerspectiveBarVisible();
+			window.setCoolBarVisible(false);
+			window.setPerspectiveBarVisible(false);
+		}
+
+		if (layout) {
+			window.getShell().layout();
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ViewIntroAdapterSite.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ViewIntroAdapterSite.java
new file mode 100644
index 0000000..c8a3d6b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ViewIntroAdapterSite.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2016 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.ui.internal;
+
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IKeyBindingService;
+import org.eclipse.ui.IViewSite;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.internal.intro.IntroDescriptor;
+import org.eclipse.ui.intro.IIntroSite;
+
+/**
+ * Simple <code>IIntroSite</code> that wraps a <code>IViewSite</code>.  For use in conjunction with
+ * <code>ViewIntroAdapterPart</code>.
+ *
+ * @since 3.0
+ */
+final class ViewIntroAdapterSite implements IIntroSite {
+    private IntroDescriptor descriptor;
+
+    private IViewSite viewSite;
+
+    public ViewIntroAdapterSite(IViewSite viewSite, IntroDescriptor descriptor) {
+        this.viewSite = viewSite;
+        this.descriptor = descriptor;
+    }
+
+    @Override
+	public IActionBars getActionBars() {
+        return viewSite.getActionBars();
+    }
+
+    @Override
+	public <T> T getAdapter(Class<T> adapter) {
+		return Adapters.adapt(viewSite, adapter);
+    }
+
+    @Override
+	public String getId() {
+        return descriptor.getId();
+    }
+
+    @Override
+	public IKeyBindingService getKeyBindingService() {
+        return viewSite.getKeyBindingService();
+    }
+
+    @Override
+	public IWorkbenchPage getPage() {
+        return viewSite.getPage();
+    }
+
+    @Override
+	public String getPluginId() {
+        return descriptor.getPluginId();
+    }
+
+    @Override
+	public ISelectionProvider getSelectionProvider() {
+        return viewSite.getSelectionProvider();
+    }
+
+    @Override
+	public final <T> T getService(final Class<T> key) {
+    		return viewSite.getService(key);
+    }
+
+    @Override
+	public Shell getShell() {
+        return viewSite.getShell();
+    }
+
+    @Override
+	public IWorkbenchWindow getWorkbenchWindow() {
+        return viewSite.getWorkbenchWindow();
+    }
+
+	@Override
+	public final boolean hasService(final Class<?> key) {
+		return viewSite.hasService(key);
+	}
+
+    @Override
+	public void setSelectionProvider(ISelectionProvider provider) {
+        viewSite.setSelectionProvider(provider);
+    }
+
+    @Override
+	public String toString() {
+        return viewSite.toString();
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ViewPluginAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ViewPluginAction.java
new file mode 100644
index 0000000..15ab13f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ViewPluginAction.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.ui.IActionDelegate;
+import org.eclipse.ui.IViewActionDelegate;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.WorkbenchException;
+
+/**
+ * This class extends regular plugin action with the
+ * additional requirement that the delegate has
+ * to implement interface IViewActionDeelgate.
+ * This interface has one additional method (init)
+ * whose purpose is to initialize the delegate with
+ * the view part in which the action is intended to run.
+ */
+public final class ViewPluginAction extends PartPluginAction {
+    private IViewPart viewPart;
+
+    /**
+     * This class adds the requirement that action delegates
+     * loaded on demand implement IViewActionDelegate
+     */
+    public ViewPluginAction(IConfigurationElement actionElement,
+            IViewPart viewPart, String id, int style) {
+        super(actionElement, id, style);
+        this.viewPart = viewPart;
+        registerSelectionListener(viewPart);
+    }
+
+    @Override
+	protected IActionDelegate validateDelegate(Object obj)
+            throws WorkbenchException {
+        if (obj instanceof IViewActionDelegate) {
+			return (IViewActionDelegate) obj;
+		} else {
+			throw new WorkbenchException(
+                    "Action must implement IViewActionDelegate"); //$NON-NLS-1$
+		}
+    }
+
+    @Override
+	protected void initDelegate() {
+        super.initDelegate();
+        ((IViewActionDelegate) getDelegate()).init(viewPart);
+    }
+
+    /**
+     * Returns true if the view has been set
+     * The view may be null after the constructor is called and
+     * before the view is stored.  We cannot create the delegate
+     * at that time.
+     */
+    @Override
+	public boolean isOkToCreateDelegate() {
+        return super.isOkToCreateDelegate() && viewPart != null;
+    }
+
+	@Override
+	public void dispose() {
+		unregisterSelectionListener(viewPart);
+		super.dispose();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ViewReference.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ViewReference.java
new file mode 100644
index 0000000..5bc46a1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ViewReference.java
@@ -0,0 +1,148 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2016 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
+ *     Friederike Schertel <friederike@schertel.org> - Bug 478336
+ *******************************************************************************/
+package org.eclipse.ui.internal;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IViewReference;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.WorkbenchException;
+import org.eclipse.ui.XMLMemento;
+import org.eclipse.ui.internal.registry.ViewDescriptor;
+
+public class ViewReference extends WorkbenchPartReference implements IViewReference {
+
+	private ViewDescriptor descriptor;
+	private IMemento memento;
+
+	public ViewReference(IEclipseContext windowContext, IWorkbenchPage page, MPart part,
+			ViewDescriptor descriptor) {
+		super(windowContext, page, part);
+		this.descriptor = descriptor;
+
+		String mementoString = getModel().getPersistedState().get(MEMENTO_KEY);
+		if (mementoString != null) {
+			try {
+				memento = XMLMemento.createReadRoot(new StringReader(mementoString));
+			} catch (WorkbenchException e) {
+				WorkbenchPlugin.log(e);
+			}
+		}
+	}
+
+	void persist() {
+		IViewPart view = getView(false);
+		if (view != null) {
+			XMLMemento root = XMLMemento.createWriteRoot("view"); //$NON-NLS-1$
+			view.saveState(root);
+			StringWriter writer = new StringWriter();
+			try {
+				root.save(writer);
+				getModel().getPersistedState().put(MEMENTO_KEY, writer.toString());
+			} catch (IOException e) {
+				WorkbenchPlugin.log(e);
+			}
+		}
+	}
+
+	@Override
+	public String getPartName() {
+		return descriptor.getLabel();
+	}
+
+	@Override
+	public String getSecondaryId() {
+		MPart part = getModel();
+
+		int colonIndex = part.getElementId().indexOf(':');
+		if (colonIndex == -1 || colonIndex == (part.getElementId().length() - 1))
+			return null;
+
+		return part.getElementId().substring(colonIndex + 1);
+	}
+
+	@Override
+	public IViewPart getView(boolean restore) {
+		return (IViewPart) getPart(restore);
+	}
+
+	@Override
+	public boolean isFastView() {
+		return false;
+	}
+
+	@Override
+	public IWorkbenchPart createPart() throws PartInitException {
+		try {
+			if (descriptor == null) {
+				return createErrorPart();
+			}
+
+			return descriptor.createView();
+		} catch (CoreException e) {
+			IStatus status = e.getStatus();
+			throw new PartInitException(new Status(IStatus.ERROR, WorkbenchPlugin.PI_WORKBENCH,
+					status.getCode(), status.getMessage(), e));
+		}
+	}
+
+	@Override
+	IWorkbenchPart createErrorPart() {
+		IStatus status = new Status(IStatus.ERROR, WorkbenchPlugin.PI_WORKBENCH, NLS.bind(
+				WorkbenchMessages.get().ViewFactory_initException, getModel().getElementId()), new Exception());
+		return createErrorPart(status);
+	}
+
+	@Override
+	public IWorkbenchPart createErrorPart(IStatus status) {
+		return new ErrorViewPart(status);
+	}
+
+	@Override
+	public void initialize(IWorkbenchPart part) throws PartInitException {
+		ViewSite viewSite = new ViewSite(getModel(), part, this, descriptor == null ? null
+				: descriptor.getConfigurationElement());
+		IViewPart view = (IViewPart) part;
+		view.init(viewSite, memento);
+
+		if (view.getSite() != viewSite || view.getViewSite() != viewSite) {
+			String id = descriptor == null ? getModel().getElementId() : descriptor.getId();
+			throw new PartInitException(NLS.bind(WorkbenchMessages.get().ViewFactory_siteException, id));
+		}
+
+		legacyPart = part;
+		addPropertyListeners();
+	}
+
+	@Override
+	public PartSite getSite() {
+		if (legacyPart != null) {
+			return (PartSite) legacyPart.getSite();
+		}
+		return null;
+	}
+
+	public ViewDescriptor getDescriptor() {
+		return descriptor;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ViewSite.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ViewSite.java
new file mode 100644
index 0000000..ecfc2ec
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ViewSite.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IViewSite;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartReference;
+import org.eclipse.ui.SubActionBars;
+import org.eclipse.ui.internal.e4.compatibility.ActionBars;
+
+/**
+ * A view container manages the services for a view.
+ */
+public class ViewSite extends PartSite implements IViewSite {
+
+	public ViewSite(MPart model, IWorkbenchPart part, IWorkbenchPartReference ref,
+			IConfigurationElement element) {
+		super(model, part, ref, element);
+		initializeDefaultServices();
+	}
+
+	private void initializeDefaultServices() {
+		setActionBars(new ActionBars(((WorkbenchPage) getPage()).getActionBars(), serviceLocator,
+				model));
+		serviceLocator.registerService(IViewPart.class, getPart());
+	}
+
+	@Override
+	public String getSecondaryId() {
+		MPart part = getModel();
+
+		int colonIndex = part.getElementId().indexOf(':');
+		if (colonIndex == -1 || colonIndex == (part.getElementId().length() - 1))
+			return null;
+
+		return part.getElementId().substring(colonIndex + 1);
+	}
+
+	@Override
+	public void dispose() {
+		final IActionBars actionBars = getActionBars();
+		if (actionBars instanceof SubActionBars) {
+			((SubActionBars) actionBars).dispose();
+		}
+		super.dispose();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ViewerActionBuilder.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ViewerActionBuilder.java
new file mode 100644
index 0000000..966c61d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/ViewerActionBuilder.java
@@ -0,0 +1,189 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+
+/**
+ * This class reads the registry for extensions that plug into
+ * 'popupMenus' extension point and deals only with the 'viewerContribution'
+ * elements.
+ */
+public class ViewerActionBuilder extends PluginActionBuilder {
+
+
+    private ISelectionProvider provider;
+
+    private IWorkbenchPart part;
+
+    /**
+     * Basic contstructor
+     */
+    public ViewerActionBuilder() {
+    }
+
+    @Override
+	protected ActionDescriptor createActionDescriptor(
+            IConfigurationElement element) {
+        if (part instanceof IViewPart) {
+			return new ActionDescriptor(element, ActionDescriptor.T_VIEW, part);
+		}
+		return new ActionDescriptor(element, ActionDescriptor.T_EDITOR, part);
+    }
+
+    @Override
+	protected BasicContribution createContribution() {
+        return new ViewerContribution(provider);
+    }
+
+    /**
+     * Dispose of the action builder
+     */
+    public void dispose() {
+        if (cache != null) {
+            for (int i = 0; i < cache.size(); i++) {
+                ((BasicContribution) cache.get(i)).dispose();
+            }
+            cache = null;
+        }
+    }
+
+    @Override
+	protected boolean readElement(IConfigurationElement element) {
+        String tag = element.getName();
+
+        // Found visibility sub-element
+        if (currentContribution != null && tag.equals(IWorkbenchRegistryConstants.TAG_VISIBILITY)) {
+            ((ViewerContribution) currentContribution)
+                    .setVisibilityTest(element);
+            return true;
+        }
+
+        return super.readElement(element);
+    }
+
+    /**
+     * Reads the contributions for a viewer menu.
+     * This method is typically used in conjunction with <code>contribute</code> to read
+     * and then insert actions for a particular viewer menu.
+     *
+     * @param id the menu id
+     * @param prov the selection provider for the control containing the menu
+     * @param part the part containing the menu.
+     * @return <code>true</code> if 1 or more items were read.
+     */
+    public boolean readViewerContributions(String id, ISelectionProvider prov,
+            IWorkbenchPart part) {
+		Assert.isTrue(part instanceof IViewPart || part instanceof IEditorPart);
+        provider = prov;
+        this.part = part;
+        readContributions(id, IWorkbenchRegistryConstants.TAG_VIEWER_CONTRIBUTION,
+                IWorkbenchRegistryConstants.PL_POPUP_MENU);
+        return (cache != null);
+    }
+
+    /**
+     * Helper class to collect the menus and actions defined within a
+     * contribution element.
+     */
+    private static class ViewerContribution extends BasicContribution implements ISelectionChangedListener {
+        private ISelectionProvider selProvider;
+
+        private ActionExpression visibilityTest;
+
+        /**
+         * Create a new ViewerContribution.
+         *
+         * @param selProvider the selection provider
+         */
+        public ViewerContribution(ISelectionProvider selProvider) {
+            super();
+            this.selProvider = selProvider;
+			if (selProvider != null) {
+				selProvider.addSelectionChangedListener(this);
+			}
+        }
+
+        /**
+         * Set the visibility test.
+         *
+         * @param element the element
+         */
+        public void setVisibilityTest(IConfigurationElement element) {
+            visibilityTest = new ActionExpression(element);
+        }
+
+        @Override
+		public void contribute(IMenuManager menu, boolean menuAppendIfMissing,
+                IToolBarManager toolbar, boolean toolAppendIfMissing) {
+            boolean visible = true;
+
+            if (visibilityTest != null) {
+                ISelection selection = selProvider.getSelection();
+                if (selection instanceof IStructuredSelection) {
+                    visible = visibilityTest
+                            .isEnabledFor((IStructuredSelection) selection);
+                } else {
+                    visible = visibilityTest.isEnabledFor(selection);
+                }
+            }
+
+            if (visible) {
+				super.contribute(menu, menuAppendIfMissing, toolbar,
+                        toolAppendIfMissing);
+			}
+        }
+
+		@Override
+		public void dispose() {
+			if (selProvider != null) {
+				selProvider.removeSelectionChangedListener(this);
+			}
+			disposeActions();
+			super.dispose();
+		}
+
+		/**
+		 * Rather than hooking up each action as a selection listener,
+		 * the contribution itself is added, and propagates
+		 * the selection changed notification to all actions.
+		 * This simplifies cleanup, in addition to potentially reducing the number of listeners.
+		 *
+		 * @see ISelectionChangedListener
+		 * @since 3.1
+		 */
+		@Override
+		public void selectionChanged(SelectionChangedEvent event) {
+			if (actions != null) {
+				if (actions != null) {
+					for (int i = 0; i < actions.size(); i++) {
+						PluginAction proxy = ((ActionDescriptor) actions.get(i))
+								.getAction();
+						proxy.selectionChanged(event);
+					}
+				}
+			}
+		}
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WWinActionBars.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WWinActionBars.java
new file mode 100644
index 0000000..4c11d67
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WWinActionBars.java
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.ICoolBarManager;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.IStatusLineManager;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.ui.IActionBars2;
+import org.eclipse.ui.services.IServiceLocator;
+
+public class WWinActionBars implements IActionBars2 {
+    private WorkbenchWindow window;
+
+    /**
+     * PerspActionBars constructor comment.
+     */
+    public WWinActionBars(WorkbenchWindow window) {
+        super();
+        this.window = window;
+    }
+
+    /**
+     * Clears the global action handler list.
+     */
+    @Override
+	public void clearGlobalActionHandlers() {
+    }
+
+    /**
+     * Returns the cool bar manager.
+     *
+     */
+    @Override
+	public ICoolBarManager getCoolBarManager() {
+        return window.getCoolBarManager2();
+    }
+
+    /**
+     * Get the handler for a window action.
+     *
+     * @param actionID an action ID declared in the registry
+     * @return an action handler which implements the action ID, or
+     *		<code>null</code> if none is registered.
+     */
+    @Override
+	public IAction getGlobalActionHandler(String actionID) {
+        return null;
+    }
+
+    /**
+     * Returns the menu manager.  If items are added or
+     * removed from the manager be sure to call <code>updateActionBars</code>.
+     *
+     * @return the menu manager
+     */
+    @Override
+	public IMenuManager getMenuManager() {
+        return window.getMenuManager();
+    }
+
+	@Override
+	public final IServiceLocator getServiceLocator() {
+		return window;
+	}
+
+    /**
+     * Returns the status line manager.  If items are added or
+     * removed from the manager be sure to call <code>updateActionBars</code>.
+     *
+     * @return the status line manager
+     */
+    @Override
+	public IStatusLineManager getStatusLineManager() {
+        return window.getStatusLineManager();
+    }
+
+    /**
+     * Returns the tool bar manager.
+     *
+     */
+    @Override
+	public IToolBarManager getToolBarManager() {
+        // This should never be called
+        Assert.isTrue(false);
+        return null;
+    }
+
+    /**
+     * Add a handler for a window action.
+     *
+     * The standard action ID's for the workbench are defined in
+     * <code>IWorkbenchActions</code>.
+     *
+     * @see IWorkbenchActions
+     *
+     * @param actionID an action ID declared in the registry
+     * @param handler an action which implements the action ID.
+     *		<code>null</code> may be passed to deregister a handler.
+     */
+    @Override
+	public void setGlobalActionHandler(String actionID, IAction handler) {
+    }
+
+	/**
+     * Commits all UI changes.  This should be called
+     * after additions or subtractions have been made to a
+     * menu, status line, or toolbar.
+     */
+    @Override
+	public void updateActionBars() {
+        window.updateActionBars();
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WWinPluginAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WWinPluginAction.java
new file mode 100644
index 0000000..ba3db95
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WWinPluginAction.java
@@ -0,0 +1,276 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.swt.events.HelpListener;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.ui.IActionDelegate;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.IWorkbenchWindowActionDelegate;
+import org.eclipse.ui.WorkbenchException;
+import org.eclipse.ui.actions.LabelRetargetAction;
+import org.eclipse.ui.actions.RetargetAction;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+
+/**
+ * This class extends regular plugin action with the additional requirement that
+ * the delegate has to implement interface
+ * {@link org.eclipse.ui.IWorkbenchWindowActionDelegate}. This interface has
+ * one additional method (init) whose purpose is to initialize the delegate with
+ * the window in which the action is intended to run.
+ */
+public class WWinPluginAction extends PluginAction implements
+        IActionSetContributionItem {
+    /**
+     * The help listener assigned to this action, or <code>null</code> if none.
+     */
+    private HelpListener localHelpListener;
+
+    private IWorkbenchWindow window;
+
+    private String actionSetId;
+
+    private RetargetAction retargetAction;
+
+    private static ArrayList staticActionList = new ArrayList(50);
+
+    /**
+     * Constructs a new <code>WWinPluginAction</code> object.
+     *
+     * @param actionElement the configuration element
+     * @param window the window to contribute to
+     * @param id the identifier
+     * @param style the style
+     */
+    public WWinPluginAction(IConfigurationElement actionElement,
+            IWorkbenchWindow window, String id, int style) {
+        super(actionElement, id, style);
+        this.window = window;
+
+        // If config specifies a retarget action, create it now
+        String retarget = actionElement
+                .getAttribute(IWorkbenchRegistryConstants.ATT_RETARGET);
+        if (retarget != null && Boolean.valueOf(retarget).booleanValue()) {
+            // create a retarget action
+            String allowLabelUpdate = actionElement
+                    .getAttribute(IWorkbenchRegistryConstants.ATT_ALLOW_LABEL_UPDATE);
+            String label = actionElement
+                    .getAttribute(IWorkbenchRegistryConstants.ATT_LABEL);
+
+            if (allowLabelUpdate != null && Boolean.valueOf(allowLabelUpdate).booleanValue()) {
+				retargetAction = new LabelRetargetAction(id, label, style);
+			} else {
+				retargetAction = new RetargetAction(id, label, style);
+			}
+            retargetAction
+                    .addPropertyChangeListener(event -> {
+					    if (event.getProperty().equals(IAction.ENABLED)) {
+					        Object val1 = event.getNewValue();
+					        if (val1 instanceof Boolean) {
+					            setEnabled(((Boolean) val1).booleanValue());
+					        }
+					    } else if (event.getProperty().equals(
+					            IAction.CHECKED)) {
+					        Object val2 = event.getNewValue();
+					        if (val2 instanceof Boolean) {
+					            setChecked(((Boolean) val2).booleanValue());
+					        }
+					    } else if (event.getProperty().equals(IAction.TEXT)) {
+					        Object val3 = event.getNewValue();
+					        if (val3 instanceof String) {
+					            setText((String) val3);
+					        }
+					    } else if (event.getProperty().equals(
+					            IAction.TOOL_TIP_TEXT)) {
+					        Object val4 = event.getNewValue();
+					        if (val4 instanceof String) {
+					            setToolTipText((String) val4);
+					        }
+					    }
+					});
+            retargetAction.setEnabled(false);
+            setEnabled(false);
+            window.getPartService().addPartListener(retargetAction);
+            IWorkbenchPart activePart = window.getPartService().getActivePart();
+            if (activePart != null) {
+				retargetAction.partActivated(activePart);
+			}
+        } else {
+            // if we retarget the handler will look after selection changes
+            window.getSelectionService().addSelectionListener(this);
+            refreshSelection();
+        }
+        addToActionList(this);
+
+        super.setHelpListener(e -> {
+		    HelpListener listener = null;
+		    if (retargetAction != null) {
+				listener = retargetAction.getHelpListener();
+			}
+		    if (listener == null) {
+				// use our own help listener
+		        listener = localHelpListener;
+			}
+		    if (listener != null) {
+				// pass on the event
+		        listener.helpRequested(e);
+			}
+		});
+    }
+
+    /**
+     * Adds an item to the action list.
+     */
+    private static void addToActionList(WWinPluginAction action) {
+        staticActionList.add(action);
+    }
+
+    /**
+     * Removes an item from the action list.
+     */
+    private static void removeFromActionList(WWinPluginAction action) {
+        staticActionList.remove(action);
+    }
+
+    /**
+     * Creates any actions which belong to an activated plugin.
+     */
+    public static void refreshActionList() {
+        Iterator iter = staticActionList.iterator();
+        while (iter.hasNext()) {
+            WWinPluginAction action = (WWinPluginAction) iter.next();
+            if ((action.getDelegate() == null) && action.isOkToCreateDelegate()) {
+                action.createDelegate();
+                // creating the delegate also refreshes its enablement
+            }
+        }
+    }
+
+    @Override
+	protected IActionDelegate validateDelegate(Object obj)
+            throws WorkbenchException {
+        if (obj instanceof IWorkbenchWindowActionDelegate) {
+			return (IWorkbenchWindowActionDelegate) obj;
+		}
+
+        throw new WorkbenchException(
+                "Action must implement IWorkbenchWindowActionDelegate"); //$NON-NLS-1$
+    }
+
+    @Override
+	protected void initDelegate() {
+        super.initDelegate();
+        ((IWorkbenchWindowActionDelegate) getDelegate()).init(window);
+    }
+
+    /**
+     * Disposes of the action and any resources held.
+     */
+    @Override
+	public void dispose() {
+        removeFromActionList(this);
+        if (retargetAction != null) {
+            window.getPartService().removePartListener(retargetAction);
+            retargetAction.dispose();
+            retargetAction = null;
+        }
+        window.getSelectionService().removeSelectionListener(this);
+        super.dispose();
+    }
+
+    /**
+     * Returns the action set id.
+     */
+    @Override
+	public String getActionSetId() {
+        return actionSetId;
+    }
+
+    /**
+     * Returns true if the window has been set.
+     * The window may be null after the constructor is called and
+     * before the window is stored.  We cannot create the delegate
+     * at that time.
+     */
+    @Override
+	public boolean isOkToCreateDelegate() {
+        return super.isOkToCreateDelegate() && window != null
+                && retargetAction == null;
+    }
+
+    @Override
+	public void runWithEvent(Event event) {
+        if (retargetAction == null) {
+            super.runWithEvent(event);
+            return;
+        }
+
+        if (event != null) {
+			retargetAction.runWithEvent(event);
+		} else {
+			retargetAction.run();
+		}
+    }
+
+    /**
+     * Sets the action set id.
+     */
+    @Override
+	public void setActionSetId(String newActionSetId) {
+        actionSetId = newActionSetId;
+    }
+
+    /**
+     * The <code>WWinPluginAction</code> implementation of this method
+     * declared on <code>IAction</code> stores the help listener in
+     * a local field. The supplied listener is only used if there is
+     * no retarget action.
+     */
+    @Override
+	public void setHelpListener(HelpListener listener) {
+        localHelpListener = listener;
+    }
+
+    @Override
+	public void setChecked(boolean checked) {
+        super.setChecked(checked);
+        // This call may come from the SWT control event handler
+        // itself, so notify the retarget action to keep things
+        // in sync.
+        if (retargetAction != null) {
+			retargetAction.setChecked(checked);
+		}
+    }
+
+    /**
+     * Refresh the selection for the action.
+     */
+    protected void refreshSelection() {
+        ISelection selection = window.getSelectionService().getSelection();
+        selectionChanged(selection);
+    }
+
+	@Override
+	public String toString() {
+		return "WWinPluginAction [" //$NON-NLS-1$
+				+ "id=" + getId() //$NON-NLS-1$
+				+ ", enabled=" + isEnabled() + //$NON-NLS-1$
+				(actionSetId != null ? ", actionSet=" + actionSetId : "") //$NON-NLS-1$ //$NON-NLS-2$
+				+ "]"; //$NON-NLS-1$
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WWinPluginPulldown.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WWinPluginPulldown.java
new file mode 100644
index 0000000..089c2c0
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WWinPluginPulldown.java
@@ -0,0 +1,221 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.jface.action.IMenuCreator;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.ui.IActionDelegate;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.IWorkbenchWindowPulldownDelegate;
+import org.eclipse.ui.IWorkbenchWindowPulldownDelegate2;
+import org.eclipse.ui.WorkbenchException;
+
+/**
+ * A workbench window pulldown action.
+ */
+public class WWinPluginPulldown extends WWinPluginAction {
+
+	/**
+	 * The proxy for creating the menu. There is always a menu proxy. This value
+	 * can't be <code>null</code>.
+	 */
+	private final IMenuCreator menuProxy;
+
+	private class MenuProxy implements IMenuCreator {
+
+		/**
+		 * A wrapper for loading the menu that defends against possible
+		 * exceptions triggered outside of the workbench.
+		 *
+		 * @since 3.0
+		 */
+		private class MenuLoader implements ISafeRunnable {
+
+			/**
+			 * The parent for the menu to be created. This value is
+			 * <code>null</code> if the parent is a menu.
+			 */
+			private final Control control;
+
+			/**
+			 * The delegate from which to load the menu.
+			 */
+			private final IWorkbenchWindowPulldownDelegate delegate;
+
+			/**
+			 * The loaded menu. This value is <code>null</code> if the load
+			 * failed, or if it hasn't been loaded yet.
+			 */
+			private Menu menu = null;
+
+			/**
+			 * The parent for the menu to be created. This value is
+			 * <code>null</code> if the parent is a control.
+			 */
+			private final Menu parent;
+
+			/**
+			 * Constructs a new instance of <code>MenuLoader</code>
+			 *
+			 * @param delegate
+			 *            The delegate from which the menu will be loaded; this
+			 *            value must not be <code>null</code>.
+			 * @param parent
+			 *            The parent of the menu to be loaded; this value must
+			 *            not be <code>null</code>.
+			 */
+			private MenuLoader(
+					final IWorkbenchWindowPulldownDelegate2 delegate,
+					final Menu parent) {
+				this.delegate = delegate;
+				this.parent = parent;
+				this.control = null;
+			}
+
+			/**
+			 * Constructs a new instance of <code>MenuLoader</code>
+			 *
+			 * @param delegate
+			 *            The delegate from which the menu will be loaded; this
+			 *            value must not be <code>null</code>.
+			 * @param parent
+			 *            The parent of the menu to be loaded; this value must
+			 *            not be <code>null</code>.
+			 */
+			private MenuLoader(final IWorkbenchWindowPulldownDelegate delegate,
+					final Control parent) {
+				this.delegate = delegate;
+				this.parent = null;
+				this.control = parent;
+			}
+
+			/**
+			 * Returns the menu loaded, if any.
+			 *
+			 * @return the loaded menu, or <code>null</code> if none.
+			 */
+			private Menu getMenu() {
+				return menu;
+			}
+
+			/**
+			 * @see ISafeRunnable#handleException(java.lang.Throwable)
+			 */
+			@Override
+			public void handleException(Throwable exception) {
+				// Do nothing
+			}
+
+			/**
+			 * @see ISafeRunnable#run()
+			 */
+			@Override
+			public void run() throws Exception {
+				if (parent == null) {
+					menu = delegate.getMenu(control);
+				} else {
+					menu = ((IWorkbenchWindowPulldownDelegate2) delegate)
+							.getMenu(parent);
+				}
+			}
+		}
+
+		/**
+		 * @see IMenuCreator#getMenu(Control)
+		 */
+		@Override
+		public Menu getMenu(Control parent) {
+			IWorkbenchWindowPulldownDelegate delegate = getPulldownDelegate();
+			if (delegate != null) {
+				final MenuLoader menuLoader = new MenuLoader(delegate, parent);
+				SafeRunner.run(menuLoader);
+				return menuLoader.getMenu();
+			}
+
+			return null;
+		}
+
+		/**
+		 * @see IMenuCreator#getMenu(Menu)
+		 */
+		@Override
+		public Menu getMenu(Menu parent) {
+			IWorkbenchWindowPulldownDelegate delegate = getPulldownDelegate();
+
+			if (delegate instanceof IWorkbenchWindowPulldownDelegate2) {
+				IWorkbenchWindowPulldownDelegate2 delegate2 = (IWorkbenchWindowPulldownDelegate2) delegate;
+				final MenuLoader menuLoader = new MenuLoader(delegate2, parent);
+				SafeRunner.run(menuLoader);
+				return menuLoader.getMenu();
+			}
+
+			return null;
+		}
+
+		/**
+		 * @see IMenuCreator#dispose()
+		 */
+		@Override
+		public void dispose() {
+			// do nothing
+		}
+	}
+
+	/**
+	 * Constructs a new instance of <code>WWinPluginPulldown</code>.
+	 *
+	 * @param actionElement
+	 *            The registry element from which the pulldown delegate should
+	 *            be created; must not be <code>null</code>.
+	 * @param id
+	 *            The identifier of this action delegate; may be
+	 *            <code>null</code>.
+	 * @param window
+	 *            The workbench window on which this pulldown should act; must
+	 *            not be <code>null</code>.
+	 * @param style
+	 *            The style.
+	 */
+	public WWinPluginPulldown(IConfigurationElement actionElement,
+			IWorkbenchWindow window, String id, int style) {
+		super(actionElement, window, id, style);
+		menuProxy = new MenuProxy();
+		setMenuCreator(menuProxy);
+	}
+
+	@Override
+	protected IActionDelegate validateDelegate(Object obj)
+			throws WorkbenchException {
+		if (obj instanceof IWorkbenchWindowPulldownDelegate) {
+			return (IWorkbenchWindowPulldownDelegate) obj;
+		}
+
+		throw new WorkbenchException(
+				"Action must implement IWorkbenchWindowPulldownDelegate"); //$NON-NLS-1$
+	}
+
+	/**
+	 * Returns the pulldown delegate. If it does not exist it is created. Can
+	 * return <code>null</code> if delegate creation failed.
+	 */
+	protected IWorkbenchWindowPulldownDelegate getPulldownDelegate() {
+		IActionDelegate delegate = getDelegate();
+		if (delegate == null) {
+			createDelegate();
+			delegate = getDelegate();
+		}
+		return (IWorkbenchWindowPulldownDelegate) delegate;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WindowPartSelectionTracker.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WindowPartSelectionTracker.java
new file mode 100644
index 0000000..a893ff2
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WindowPartSelectionTracker.java
@@ -0,0 +1,120 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.ui.INullSelectionListener;
+import org.eclipse.ui.IPageListener;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+
+/**
+ * Provides part selection tracking for a part with a specific id
+ * in all pages of a specific workbench window. This tracker shields
+ * clients from a part opening and closing, and still provides selection
+ * notification/information even when the part is not active.
+ */
+public class WindowPartSelectionTracker extends AbstractPartSelectionTracker
+        implements IPageListener {
+    /**
+     * The window this selection tracker is working in
+     */
+    private IWorkbenchWindow fWindow;
+
+    /**
+     * Part selection listener.
+     */
+    private final INullSelectionListener selListener = (part, selection) -> fireSelection(part, selection);
+
+    /**
+     * Part post selection listener
+     */
+    private final INullSelectionListener postSelListener = (part, selection) -> firePostSelection(part, selection);
+
+    /**
+     * Constructs a new selection tracker for the given window and part id.
+     *
+     * @param window workbench window
+     * @param partId part identifier
+     */
+    public WindowPartSelectionTracker(IWorkbenchWindow window, String partId) {
+        super(partId);
+        setWindow(window);
+        window.addPageListener(this);
+		for (IWorkbenchPage page : window.getPages()) {
+            pageOpened(page);
+        }
+    }
+
+    /*
+     * @see IPageListener#pageActivated(IWorkbenchPage)
+     */
+    @Override
+	public void pageActivated(IWorkbenchPage page) {
+    }
+
+    /*
+     * @see IPageListener#pageClosed(IWorkbenchPage)
+     */
+    @Override
+	public void pageClosed(IWorkbenchPage page) {
+        page.removeSelectionListener(getPartId(), selListener);
+        page.removePostSelectionListener(getPartId(), postSelListener);
+    }
+
+    /*
+     * @see IPageListener#pageOpened(IWorkbenchPage)
+     */
+    @Override
+	public void pageOpened(IWorkbenchPage page) {
+        page.addSelectionListener(getPartId(), selListener);
+        page.addPostSelectionListener(getPartId(), postSelListener);
+    }
+
+    /**
+     * Sets the window this tracker is working in.
+     *
+     * @param window workbench window
+     */
+    private void setWindow(IWorkbenchWindow window) {
+        fWindow = window;
+    }
+
+    /**
+     * Returns the window this tracker is working in.
+     *
+     * @return workbench window
+     */
+    protected IWorkbenchWindow getWindow() {
+        return fWindow;
+    }
+
+    /**
+     * @see AbstractPartSelectionTracker#dispose()
+     */
+    @Override
+	public void dispose() {
+        super.dispose();
+        fWindow = null;
+    }
+
+    /*
+     * @see AbstractPartSelectionTracker#getSelection()
+     */
+    @Override
+	public ISelection getSelection() {
+        IWorkbenchPage page = getWindow().getActivePage();
+        if (page != null) {
+            return page.getSelection(getPartId());
+        }
+        return null;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WindowSelectionService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WindowSelectionService.java
new file mode 100644
index 0000000..9ede2db
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WindowSelectionService.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2014 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.ui.internal;
+
+import org.eclipse.ui.IWorkbenchWindow;
+
+/**
+ * The selection service for a window.
+ */
+/* package */
+class WindowSelectionService extends AbstractSelectionService {
+
+    /**
+     * The window.
+     */
+    private IWorkbenchWindow window;
+
+    /**
+     * Creates a new selection service for the given window.
+     */
+    public WindowSelectionService(IWorkbenchWindow window) {
+        setWindow(window);
+    }
+
+    /**
+     * Sets the window.
+     */
+    private void setWindow(IWorkbenchWindow window) {
+        this.window = window;
+    }
+
+    /**
+     * Returns the window.
+     */
+    protected IWorkbenchWindow getWindow() {
+        return window;
+    }
+
+    /*
+     * @see AbstractSelectionService#createPartTracker(String)
+     */
+    @Override
+	protected AbstractPartSelectionTracker createPartTracker(String partId) {
+        return new WindowPartSelectionTracker(getWindow(), partId);
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/Workbench.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/Workbench.java
new file mode 100644
index 0000000..22f7fbf
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/Workbench.java
@@ -0,0 +1,3866 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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
+ *     Francis Upton - <francisu@ieee.org> - Bug 217777
+ *     Tristan Hume - <trishume@gmail.com> - Bug 2369
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 422533, 440136, 445724, 366708, 418661, 456897, 472654, 481516, 486543
+ *     Terry Parker <tparker@google.com> - Bug 416673
+ *     Sergey Prigogin <eclipse.sprigogin@gmail.com> - Bug 438324
+ *     Snjezana Peco <snjeza.peco@gmail.com> - Bug 405542
+ *     Andrey Loskutov <loskutov@gmx.de> - Bug 372799
+ *     Mickael Istria (Red Hat Inc.) - Bug 469918
+ *     Patrik Suzzi <psuzzi@gmail.com> - Bug 487297
+ *******************************************************************************/
+
+package org.eclipse.ui.internal;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+
+import javax.inject.Inject;
+
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.CommandManager;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.NotEnabledException;
+import org.eclipse.core.commands.NotHandledException;
+import org.eclipse.core.commands.common.EventManager;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.core.commands.contexts.ContextManager;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionDelta;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.IPlatformRunnable;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IRegistryChangeListener;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.e4.core.contexts.ContextFunction;
+import org.eclipse.e4.core.contexts.ContextInjectionFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.di.InjectionException;
+import org.eclipse.e4.core.di.annotations.Optional;
+import org.eclipse.e4.core.services.events.IEventBroker;
+import org.eclipse.e4.ui.internal.workbench.E4Workbench;
+import org.eclipse.e4.ui.internal.workbench.renderers.swt.IUpdateService;
+import org.eclipse.e4.ui.internal.workbench.swt.E4Application;
+import org.eclipse.e4.ui.internal.workbench.swt.IEventLoopAdvisor;
+import org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.commands.MBindingContext;
+import org.eclipse.e4.ui.model.application.commands.MBindingTable;
+import org.eclipse.e4.ui.model.application.commands.MCategory;
+import org.eclipse.e4.ui.model.application.commands.MCommand;
+import org.eclipse.e4.ui.model.application.commands.MCommandsFactory;
+import org.eclipse.e4.ui.model.application.commands.impl.CommandsFactoryImpl;
+import org.eclipse.e4.ui.model.application.descriptor.basic.MPartDescriptor;
+import org.eclipse.e4.ui.model.application.ui.MElementContainer;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.model.application.ui.basic.MTrimBar;
+import org.eclipse.e4.ui.model.application.ui.basic.MTrimElement;
+import org.eclipse.e4.ui.model.application.ui.basic.MTrimmedWindow;
+import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
+import org.eclipse.e4.ui.model.application.ui.basic.impl.BasicFactoryImpl;
+import org.eclipse.e4.ui.model.application.ui.menu.MMenu;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolBar;
+import org.eclipse.e4.ui.model.application.ui.menu.MTrimContribution;
+import org.eclipse.e4.ui.services.EContextService;
+import org.eclipse.e4.ui.workbench.IModelResourceHandler;
+import org.eclipse.e4.ui.workbench.IPresentationEngine;
+import org.eclipse.e4.ui.workbench.UIEvents;
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.equinox.app.IApplication;
+import org.eclipse.equinox.app.IApplicationContext;
+import org.eclipse.jface.action.ActionContributionItem;
+import org.eclipse.jface.action.ExternalActionManager;
+import org.eclipse.jface.action.ExternalActionManager.CommandCallback;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.bindings.BindingManager;
+import org.eclipse.jface.bindings.IBindingManagerListener;
+import org.eclipse.jface.databinding.swt.DisplayRealm;
+import org.eclipse.jface.dialogs.ErrorDialog;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.operation.IRunnableContext;
+import org.eclipse.jface.operation.ModalContext;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.PreferenceConverter;
+import org.eclipse.jface.preference.PreferenceManager;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.OpenStrategy;
+import org.eclipse.jface.util.SafeRunnable;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.window.IShellProvider;
+import org.eclipse.jface.window.Window;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.rap.e4.E4ApplicationConfig;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.rap.rwt.SingletonUtil;
+import org.eclipse.rap.ui.internal.branding.BrandingUtil;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.ui.IDecoratorManager;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorRegistry;
+import org.eclipse.ui.IElementFactory;
+import org.eclipse.ui.ILocalWorkingSetManager;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.IPerspectiveRegistry;
+import org.eclipse.ui.ISaveableFilter;
+import org.eclipse.ui.ISaveablesLifecycleListener;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.ISourceProvider;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.IViewReference;
+import org.eclipse.ui.IWindowListener;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.IWorkbenchListener;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPreferenceConstants;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.IWorkingSetManager;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.Saveable;
+import org.eclipse.ui.WorkbenchException;
+import org.eclipse.ui.XMLMemento;
+import org.eclipse.ui.activities.IWorkbenchActivitySupport;
+import org.eclipse.ui.application.WorkbenchAdvisor;
+import org.eclipse.ui.browser.IWorkbenchBrowserSupport;
+import org.eclipse.ui.commands.ICommandImageService;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.commands.IWorkbenchCommandSupport;
+import org.eclipse.ui.contexts.IContextService;
+import org.eclipse.ui.contexts.IWorkbenchContextSupport;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.help.IWorkbenchHelpSystem;
+import org.eclipse.ui.internal.StartupThreading.StartupRunnable;
+import org.eclipse.ui.internal.actions.CommandAction;
+import org.eclipse.ui.internal.activities.ws.WorkbenchActivitySupport;
+import org.eclipse.ui.internal.browser.WorkbenchBrowserSupport;
+import org.eclipse.ui.internal.commands.CommandImageManager;
+import org.eclipse.ui.internal.commands.CommandImageService;
+import org.eclipse.ui.internal.commands.CommandService;
+import org.eclipse.ui.internal.commands.WorkbenchCommandSupport;
+import org.eclipse.ui.internal.contexts.ActiveContextSourceProvider;
+import org.eclipse.ui.internal.contexts.ContextService;
+import org.eclipse.ui.internal.contexts.WorkbenchContextSupport;
+import org.eclipse.ui.internal.dialogs.PropertyPageContributorManager;
+import org.eclipse.ui.internal.e4.compatibility.CompatibilityEditor;
+import org.eclipse.ui.internal.e4.compatibility.CompatibilityPart;
+import org.eclipse.ui.internal.e4.compatibility.E4Util;
+import org.eclipse.ui.internal.e4.migration.WorkbenchMigrationProcessor;
+import org.eclipse.ui.internal.handlers.LegacyHandlerService;
+import org.eclipse.ui.internal.help.WorkbenchHelpSystem;
+import org.eclipse.ui.internal.intro.IIntroRegistry;
+import org.eclipse.ui.internal.intro.IntroDescriptor;
+import org.eclipse.ui.internal.keys.BindingService;
+import org.eclipse.ui.internal.menus.FocusControlSourceProvider;
+import org.eclipse.ui.internal.menus.WorkbenchMenuService;
+import org.eclipse.ui.internal.misc.Policy;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.internal.misc.UIStats;
+import org.eclipse.ui.internal.model.ContributionService;
+import org.eclipse.ui.internal.progress.ProgressManager;
+import org.eclipse.ui.internal.progress.ProgressManagerUtil;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.registry.UIExtensionTracker;
+import org.eclipse.ui.internal.registry.ViewDescriptor;
+import org.eclipse.ui.internal.services.EvaluationService;
+import org.eclipse.ui.internal.services.IServiceLocatorCreator;
+import org.eclipse.ui.internal.services.IWorkbenchLocationService;
+import org.eclipse.ui.internal.services.MenuSourceProvider;
+import org.eclipse.ui.internal.services.ServiceLocator;
+import org.eclipse.ui.internal.services.ServiceLocatorCreator;
+import org.eclipse.ui.internal.services.SourceProviderService;
+import org.eclipse.ui.internal.services.WorkbenchLocationService;
+import org.eclipse.ui.internal.testing.ContributionInfoMessages;
+import org.eclipse.ui.internal.testing.WorkbenchTestable;
+import org.eclipse.ui.internal.themes.ColorDefinition;
+import org.eclipse.ui.internal.themes.FontDefinition;
+import org.eclipse.ui.internal.themes.ThemeElementHelper;
+import org.eclipse.ui.internal.themes.WorkbenchThemeManager;
+import org.eclipse.ui.internal.tweaklets.GrabFocus;
+import org.eclipse.ui.internal.tweaklets.Tweaklets;
+import org.eclipse.ui.internal.util.PrefUtil;
+import org.eclipse.ui.intro.IIntroManager;
+import org.eclipse.ui.keys.IBindingService;
+import org.eclipse.ui.menus.IMenuService;
+import org.eclipse.ui.model.IContributionService;
+import org.eclipse.ui.operations.IWorkbenchOperationSupport;
+import org.eclipse.ui.progress.IProgressService;
+import org.eclipse.ui.progress.WorkbenchJob;
+import org.eclipse.ui.services.IDisposable;
+import org.eclipse.ui.services.IEvaluationService;
+import org.eclipse.ui.services.IServiceScopes;
+import org.eclipse.ui.services.ISourceProviderService;
+import org.eclipse.ui.statushandlers.StatusManager;
+import org.eclipse.ui.swt.IFocusService;
+import org.eclipse.ui.testing.ContributionInfo;
+import org.eclipse.ui.themes.ITheme;
+import org.eclipse.ui.themes.IThemeManager;
+import org.eclipse.ui.views.IViewDescriptor;
+import org.eclipse.ui.views.IViewRegistry;
+import org.eclipse.ui.wizards.IWizardRegistry;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.util.tracker.ServiceTracker;
+
+import com.ibm.icu.util.ULocale;
+import com.ibm.icu.util.ULocale.Category;
+
+/**
+ * The workbench class represents the top of the Eclipse user interface. Its
+ * primary responsibility is the management of workbench windows, dialogs,
+ * wizards, and other workbench-related windows.
+ * <p>
+ * Note that any code that is run during the creation of a workbench instance
+ * should not required access to the display.
+ * </p>
+ */
+public final class Workbench extends EventManager implements IWorkbench,
+		org.eclipse.e4.ui.workbench.IWorkbench {
+
+	public static String WORKBENCH_AUTO_SAVE_JOB = "Workbench Auto-Save Job"; //$NON-NLS-1$
+
+	private static final String WORKBENCH_AUTO_SAVE_BACKGROUND_JOB = "Workbench Auto-Save Background Job"; //$NON-NLS-1$
+
+	public static String MEMENTO_KEY = "memento"; //$NON-NLS-1$
+
+	public static final String EDITOR_TAG = "Editor"; //$NON-NLS-1$
+
+	private static final String PROP_VM = "eclipse.vm"; //$NON-NLS-1$
+	private static final String PROP_VMARGS = "eclipse.vmargs"; //$NON-NLS-1$
+	private static final String PROP_COMMANDS = "eclipse.commands"; //$NON-NLS-1$
+	private static final String PROP_EXIT_CODE = "eclipse.exitcode"; //$NON-NLS-1$
+	private static final String CMD_DATA = "-data"; //$NON-NLS-1$
+	private static final String CMD_VMARGS = "-vmargs"; //$NON-NLS-1$
+
+	// RAP [fappel]: key for storing workbench state into setting store
+    private static final String KEY_WORKBENCH_STATE
+      = Workbench.class.getName() + "#XMLMemento";
+
+      // RAP [fappel]: ensure that workbench is properly shutdown in case of session timeout
+
+    /**
+     *
+     */
+      private boolean started;
+        private boolean sessionInvalidated;
+
+        private static final class ShutdownHandler implements Listener {
+          public void handleEvent( Event event ){
+            if( Workbench.getInstance().started && Platform.isRunning() ) {
+              Workbench.getInstance().sessionInvalidated = true;
+              Workbench.getInstance().close();
+            }
+          }
+        }
+        // RAPEND: [bm]
+
+	
+//	private final class StartupProgressBundleListener implements SynchronousBundleListener {
+//
+//		private final IProgressMonitor progressMonitor;
+//
+//		private final int maximumProgressCount;
+//
+//		// stack of names of bundles currently starting
+//		private final List<String> starting;
+//
+//		StartupProgressBundleListener(IProgressMonitor progressMonitor, int maximumProgressCount) {
+//			super();
+//			this.progressMonitor = progressMonitor;
+//			this.maximumProgressCount = maximumProgressCount;
+//			this.starting = new ArrayList<>();
+//		}
+//
+//		@Override
+//		public void bundleChanged(BundleEvent event) {
+//			int eventType = event.getType();
+//			String bundleName;
+//			boolean worked = false;
+//			// Note: no calls to any non-trivial Eclipse code outside this class
+//			// should be made inside the synchronized block below. Such calls
+//			// can cause deadlocks on startup, see bug 502095.
+//			// Progress monitor calls *are* non-trivial.
+//			synchronized (this) {
+//				if (eventType == BundleEvent.STARTING) {
+//					starting.add(bundleName = event.getBundle().getSymbolicName());
+//				} else if (eventType == BundleEvent.STARTED) {
+//					progressCount++;
+//					if (progressCount <= maximumProgressCount) {
+//						worked = true;
+//					}
+//					int index = starting.lastIndexOf(event.getBundle().getSymbolicName());
+//					if (index >= 0) {
+//						starting.remove(index);
+//					}
+//					if (index != starting.size()) {
+//						return; // not currently displayed
+//					}
+//					bundleName = index == 0 ? null : (String) starting.get(index - 1);
+//				} else {
+//					return; // uninteresting event
+//				}
+//			}
+//			if (worked) {
+//				progressMonitor.worked(1);
+//			}
+//			if (bundleName != null) {
+//				String taskName = NLS.bind(WorkbenchMessages.get().Startup_Loading, bundleName);
+//				progressMonitor.subTask(taskName);
+//			}
+//		}
+//	}
+
+	/**
+	 * Family for the early startup job.
+	 */
+	public static final String EARLY_STARTUP_FAMILY = "earlyStartup"; //$NON-NLS-1$
+
+	public static final String DEFAULT_WORKBENCH_STATE_FILENAME = "workbench.xml"; //$NON-NLS-1$
+
+
+    // RAP [bm]: instance per session, see getInstance()
+//  /**
+//   * Holds onto the only instance of Workbench.
+//   */
+//  private static Workbench instance;
+    // RAPEND: [bm]
+
+    /**
+     * The testable object facade.
+     */
+    // RAP [bm]:
+//  private static WorkbenchTestable testableObject;
+    private WorkbenchTestable testableObject;
+    // RAPEND: [bm]
+
+    // RAP [bm]: no splash today
+//  /**
+//   * Signals that the workbench should create a splash implementation when
+//   * instantiated. Intial value is <code>true</code>.
+//   */
+//  private static boolean createSplash = true;
+//
+//  /**
+//   * The splash handler.
+//   */
+//  private static AbstractSplashHandler splash;
+    // RAPEND: [bm]
+
+	/**
+	 * The display used for all UI interactions with this workbench.
+	 *
+	 * @since 3.0
+	 */
+	private Display display;
+
+	private boolean workbenchAutoSave = true;
+
+
+	private EditorHistory editorHistory;
+
+	private boolean runEventLoop = true;
+
+	private boolean isStarting = true;
+
+	private boolean isClosing = false;
+
+	/**
+	 * A boolean field to indicate whether all the workbench windows have been
+	 * closed or not.
+	 */
+	private boolean windowsClosed = false;
+
+	/**
+	 * PlatformUI return code (as opposed to IPlatformRunnable return code).
+	 */
+	private int returnCode = PlatformUI.RETURN_UNSTARTABLE;
+
+	/**
+	 * Advisor providing application-specific configuration and customization of
+	 * the workbench.
+	 *
+	 * @since 3.0
+	 */
+	private WorkbenchAdvisor advisor;
+
+	/**
+	 * Object for configuring the workbench. Lazily initialized to an instance
+	 * unique to the workbench instance.
+	 *
+	 * @since 3.0
+	 */
+	private WorkbenchConfigurer workbenchConfigurer;
+
+	// for dynamic UI
+	/**
+	 * ExtensionEventHandler handles extension life-cycle events.
+	 */
+	private ExtensionEventHandler extensionEventHandler;
+
+	/**
+	 * A count of how many large updates are going on. This tracks nesting of
+	 * requests to disable services during a large update -- similar to the
+	 * <code>setRedraw</code> functionality on <code>Control</code>. When this
+	 * value becomes greater than zero, services are disabled. When this value
+	 * becomes zero, services are enabled. Please see
+	 * <code>largeUpdateStart()</code> and <code>largeUpdateEnd()</code>.
+	 */
+	private int largeUpdates = 0;
+
+	private final IServiceLocatorCreator slc;
+
+	
+	/**
+	 * The service locator maintained by the workbench. These services are
+	 * initialized during workbench during the <code>init</code> method.
+	 */
+	private final ServiceLocator serviceLocator;
+
+	/**
+	 * A count of how many plug-ins were loaded while restoring the workbench
+	 * state. Initially -1 for unknown number.
+	 */
+	private int progressCount = -1;
+
+	/**
+	 * Listener list for registered IWorkbenchListeners .
+	 */
+	private ListenerList<IWorkbenchListener> workbenchListeners = new ListenerList<>(ListenerList.IDENTITY);
+
+	private ServiceRegistration workbenchService;
+
+	private MApplication application;
+
+	private IEclipseContext e4Context;
+
+	private IEventBroker eventBroker;
+
+	private IExtensionRegistry registry;
+
+	boolean initializationDone = false;
+
+	private WorkbenchWindow windowBeingCreated = null;
+
+	private Listener backForwardListener;
+	
+    @Inject
+    @Optional
+    private IEclipseContext eclipseContext;
+
+	private Job autoSaveJob;
+
+	private String id;
+	private ServiceRegistration<?> e4WorkbenchService;
+	
+	protected E4Workbench e4Workbench;
+
+	// flag used to identify if the application model needs to be saved
+	private boolean applicationModelChanged = false;
+
+	// RAP [bm]: see createAndRunWorkbench for initialization
+//	/**
+//	 * Creates a new workbench.
+//	 *
+//	 * @param display
+//	 *            the display to be used for all UI interactions with the
+//	 *            workbench
+//	 * @param advisor
+//	 *            the application-specific advisor that configures and
+//	 *            specializes this workbench instance
+//	 * @since 3.0
+//	 */
+//	private Workbench(Display display, final WorkbenchAdvisor advisor, MApplication app, IEclipseContext appContext) {
+//		super();
+//		this.id = createId();
+//		StartupThreading.setWorkbench(this);
+//		if (instance != null && instance.isRunning()) {
+//			throw new IllegalStateException(WorkbenchMessages.get().Workbench_CreatingWorkbenchTwice);
+//		}
+//		Assert.isNotNull(display);
+//		Assert.isNotNull(advisor);
+//		this.advisor = advisor;
+//		this.display = display;
+//		application = app;
+//		e4Context = appContext;
+//		Workbench.instance = this;
+//		eventBroker = e4Context.get(IEventBroker.class);
+//		registry = e4Context.get(IExtensionRegistry.class);
+//
+//		appContext.set(getClass().getName(), this);
+//		appContext.set(IWorkbench.class, this);
+//		appContext.set(IEventLoopAdvisor.class, new IEventLoopAdvisor() {
+//			@Override
+//			public void eventLoopIdle(Display display) {
+//				advisor.eventLoopIdle(display);
+//			}
+//
+//			@Override
+//			public void eventLoopException(Throwable exception) {
+//				advisor.eventLoopException(exception);
+//			}
+//		});
+//
+//		// for dynamic UI [This seems to be for everything that isn't handled by
+//		// some
+//		// subclass of RegistryManager. I think that when an extension is moved
+//		// to the
+//		// RegistryManager implementation, then it should be removed from the
+//		// list in
+//		// ExtensionEventHandler#appear.
+//		// I've found that the new wizard extension in particular is a poor
+//		// choice to
+//		// use as an example, since the result of reading the registry is not
+//		// cached
+//		// -- so it is re-read each time. The only real contribution of this
+//		// dialog is
+//		// to show the user a nice dialog describing the addition.]
+//		extensionEventHandler = new ExtensionEventHandler(this);
+//		registry.addRegistryChangeListener(extensionEventHandler);
+//		IServiceLocatorCreator slc = new ServiceLocatorCreator();
+//		serviceLocator = (ServiceLocator) slc.createServiceLocator(null, null, () -> {
+//			final Display display1 = getDisplay();
+//			if (display1 != null && !display1.isDisposed()) {
+//				MessageDialog.openInformation(null,
+//						WorkbenchMessages.Workbench_NeedsClose_Title,
+//						WorkbenchMessages.Workbench_NeedsClose_Message);
+//				close(PlatformUI.RETURN_RESTART, true);
+//			}
+//		}, appContext);
+//		serviceLocator.registerService(IServiceLocatorCreator.class, slc);
+//		serviceLocator.registerService(IWorkbenchLocationService.class,
+//				new WorkbenchLocationService(IServiceScopes.WORKBENCH_SCOPE, this, null, null,
+//						null, null, 0));
+//	}
+    private Workbench() {
+        this.id = createId();
+        extensionEventHandler = new ExtensionEventHandler(this);
+        Platform.getExtensionRegistry().addRegistryChangeListener(extensionEventHandler);
+        this.slc = new ServiceLocatorCreator();
+        serviceLocator = (ServiceLocator) slc.createServiceLocator(null, null, new IDisposable() {
+            @Override
+            public void dispose() {
+                final Display display = getDisplay();
+                if (display != null && !display.isDisposed()) {
+                    MessageDialog.openInformation(null,
+                            WorkbenchMessages.get().Workbench_NeedsClose_Title,
+                            WorkbenchMessages.get().Workbench_NeedsClose_Message);
+                    close(PlatformUI.RETURN_RESTART, true);
+                }
+            }
+        });
+//      serviceLocator.registerService(IServiceLocatorCreator.class, slc);
+//      serviceLocator.registerService(IWorkbenchLocationService.class,
+//              new WorkbenchLocationService(IServiceScopes.WORKBENCH_SCOPE, this, null, null,
+//                      null, null, 0));
+    }        
+
+	/**
+	 * Returns the one and only instance of the workbench, if there is one.
+	 *
+	 * @return the workbench, or <code>null</code> if the workbench has not been
+	 *         created, or has been created and already completed
+	 */
+	public static final Workbench getInstance() {
+        // RAP [bm]: use SSB
+//      return instance;
+        return SingletonUtil.getSessionInstance( Workbench.class );
+        // RAPEND: [bm]
+	}
+	
+
+    private static IApplicationContext getApplicationContext(final E4ApplicationConfig config) {
+        return new IApplicationContext() {
+
+            public org.osgi.framework.Bundle getBrandingBundle() {
+                return null;
+            }
+
+            @Override
+            public void setResult(Object result, IApplication application) {
+                // TODO Auto-generated method stub
+
+            }
+
+            @Override
+            public String getBrandingProperty(String key) {
+                if( org.eclipse.e4.ui.workbench.IWorkbench.XMI_URI_ARG.equals(key) ) {
+                    return config.getXmiURI();
+                } else if( org.eclipse.e4.ui.workbench.IWorkbench.LIFE_CYCLE_URI_ARG.equals(key) ) {
+                    return config.getLifecycleURI();
+                } else if( org.eclipse.e4.ui.workbench.IWorkbench.PRESENTATION_URI_ARG .equals(key)) {
+                    return config.getPresentationURI();
+                } else if( org.eclipse.e4.ui.workbench.IWorkbench.CLEAR_PERSISTED_STATE.equals(key) ) {
+                    return config.isClearPersistedState() + "";
+                } else if( org.eclipse.e4.ui.workbench.IWorkbench.PERSIST_STATE.equals(key) ) {
+                    return config.isPersistState() + "";
+                }
+                return null;
+            }
+
+            @Override
+            public String getBrandingName() {
+                // TODO Auto-generated method stub
+                return null;
+            }
+
+            @Override
+            public String getBrandingId() {
+                // TODO Auto-generated method stub
+                return null;
+            }
+
+            @Override
+            public String getBrandingDescription() {
+                // TODO Auto-generated method stub
+                return null;
+            }
+
+            @Override
+            public String getBrandingApplication() {
+                // TODO Auto-generated method stub
+                return null;
+            }
+
+            @Override
+            public Map getArguments() {
+                Map<Object, Object> rv = new HashMap<Object, Object>();
+                rv.put(IApplicationContext.APPLICATION_ARGS, new String[0]);
+                return rv;
+            }
+
+            @Override
+            public void applicationRunning() {
+                // TODO Auto-generated method stub
+
+            }
+        };
+    }
+
+	private static boolean isFirstE4WorkbenchRun(MApplication app) {
+		return app.getContext().containsKey(E4Workbench.NO_SAVED_MODEL_FOUND);
+	}
+
+	/**
+	 * Creates the workbench and associates it with the the given display and
+	 * workbench advisor, and runs the workbench UI. This entails processing and
+	 * dispatching events until the workbench is closed or restarted.
+	 * <p>
+	 * This method is intended to be called by <code>PlatformUI</code>. Fails if
+	 * the workbench UI has already been created.
+	 * </p>
+	 * <p>
+	 * The display passed in must be the default display.
+	 * </p>
+	 *
+	 * @param display
+	 *            the display to be used for all UI interactions with the
+	 *            workbench
+	 * @param advisor
+	 *            the application-specific advisor that configures and
+	 *            specializes the workbench
+	 * @return return code {@link PlatformUI#RETURN_OK RETURN_OK}for normal
+	 *         exit; {@link PlatformUI#RETURN_RESTART RETURN_RESTART}if the
+	 *         workbench was terminated with a call to
+	 *         {@link IWorkbench#restart IWorkbench.restart}; other values
+	 *         reserved for future use
+	 */
+	public static final int createAndRunWorkbench(final Display display, final WorkbenchAdvisor advisor) {
+        final int[] returnCode = new int[1];
+        Realm.runWithDefault(DisplayRealm.getRealm(display), new Runnable() {
+            @Override
+            public void run() {
+                final String nlExtensions = Platform.getNLExtensions();
+                if (nlExtensions.length() > 0) {
+                    ULocale.setDefault(Category.FORMAT,
+                            new ULocale(ULocale.getDefault(Category.FORMAT).getBaseName()
+                                    + nlExtensions));
+                }
+
+                System.setProperty(org.eclipse.e4.ui.workbench.IWorkbench.XMI_URI_ARG,
+                        "org.eclipse.rap.ui.workbench/LegacyIDE.e4xmi"); //$NON-NLS-1$
+                Object obj = getApplication(Platform.getCommandLineArgs());
+
+                IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore();
+                if (!store.isDefault(IPreferenceConstants.LAYOUT_DIRECTION)) {
+                    int orientation = store.getInt(IPreferenceConstants.LAYOUT_DIRECTION);
+                    Window.setDefaultOrientation(orientation);
+                }
+
+                if (obj instanceof E4Application) {
+                    E4Application e4app = (E4Application) obj;
+//                  E4Workbench e4Workbench = e4app.createE4Workbench(getApplicationContext(), display);
+
+                    // create the workbench instance
+                    Workbench workbench = getInstance();
+                    
+                    workbench.display = display;
+                    workbench.advisor = advisor;
+                    
+                    E4Workbench e4Workbench = e4app.createE4Workbench(getApplicationContext(E4ApplicationConfig.create("org.eclipse.rap.ui.workbench/LegacyIDE.e4xmi", true)), display);
+                    workbench.e4Workbench = e4Workbench;
+                    workbench.application = e4Workbench.getApplication();
+                    workbench.e4Context = e4Workbench.getContext();
+                    workbench.registry = workbench.e4Context.get(IExtensionRegistry.class);
+                    workbench.eventBroker = workbench.e4Context.get(IEventBroker.class);
+                    workbench.e4Context.set("org.eclipse.ui.IWorkbench", workbench);
+                    workbench.serviceLocator.setContext(e4Workbench.getContext());
+                    workbench.serviceLocator.registerService(IServiceLocatorCreator.class, workbench.slc);
+                    workbench.serviceLocator.registerService(IWorkbenchLocationService.class,
+                            new WorkbenchLocationService(IServiceScopes.WORKBENCH_SCOPE, workbench, null, null,
+                                    null, null, 0));
+                    
+                    IEclipseContext appContext = workbench.application.getContext();
+                    
+                    appContext.set(workbench.getClass().getName(), workbench);
+                    appContext.set(IWorkbench.class.getName(), workbench);
+                    appContext.set(IEventLoopAdvisor.class, new IEventLoopAdvisor() {
+                        @Override
+                        public void eventLoopIdle(Display display) {
+                            advisor.eventLoopIdle(display);
+                        }
+
+                        @Override
+                        public void eventLoopException(Throwable exception) {
+                            advisor.eventLoopException(exception);
+                        }
+                    });
+                    
+                    IEclipseContext context = e4Workbench.getContext();
+
+                    MApplication appModel = getInstance().getApplication();
+                    
+                    WorkbenchMigrationProcessor migrationProcessor = null;
+                    try {
+                        migrationProcessor = ContextInjectionFactory.make(WorkbenchMigrationProcessor.class, context);
+                    } catch (@SuppressWarnings("restriction") InjectionException e) {
+                        WorkbenchPlugin.log(e);
+                    }
+
+                    if (migrationProcessor != null && isFirstE4WorkbenchRun(appModel)
+                            && migrationProcessor.isLegacyWorkbenchDetected()) {
+                        try {
+                            WorkbenchPlugin
+                                    .log(StatusUtil.newStatus(IStatus.INFO, "Workbench migration started", null)); //$NON-NLS-1$
+                            migrationProcessor.migrate();
+                        } catch (Exception e) {
+                            WorkbenchPlugin.log("Workbench migration failed", e); //$NON-NLS-1$
+                            migrationProcessor.restoreDefaultModel();
+                        }
+                    }                   
+
+                    // RAP no splash
+//                  // prime the splash nice and early
+//                  if (createSplash)
+//                      workbench.createSplashWrapper();
+                    
+                    // run the workbench event loop
+                    // RAP [rh]: cleanup when session terminates
+                    display.addListener( SWT.Dispose, new ShutdownHandler() );
+                    // RAPEND
+
+                    // RAP no splash
+//                  AbstractSplashHandler handler = getSplash();
+//
+//
+//                  boolean showProgress = PrefUtil.getAPIPreferenceStore().getBoolean(
+//                                  IWorkbenchPreferenceConstants.SHOW_PROGRESS_ON_STARTUP);
+//
+//                  IProgressMonitor progressMonitor = null;
+//                  if (handler != null && showProgress) {
+//                      progressMonitor = handler.getBundleProgressMonitor();
+//                      if (progressMonitor != null) {
+//                          double cutoff = 0.95;
+//                          int expectedProgressCount = Math.max(1, WorkbenchPlugin.getDefault()
+//                                  .getBundleCount() / 10);
+//                          progressMonitor.beginTask("", expectedProgressCount); //$NON-NLS-1$
+//                          SynchronousBundleListener bundleListener = workbench.new StartupProgressBundleListener(
+//                                  progressMonitor, (int) (expectedProgressCount * cutoff));
+//                          WorkbenchPlugin.getDefault().addBundleListener(bundleListener);
+//                      }
+//                  }
+
+                    setSearchContribution(appModel, true);
+                    // run the legacy workbench once
+                    returnCode[0] = workbench.runUI();
+                    if (migrationProcessor != null && migrationProcessor.isWorkbenchMigrated()) {
+                        migrationProcessor.updatePartsAfterMigration(
+                                WorkbenchPlugin.getDefault().getPerspectiveRegistry(),
+                                WorkbenchPlugin.getDefault().getViewRegistry());
+                        WorkbenchPlugin.log(StatusUtil.newStatus(IStatus.INFO, "Workbench migration finished", null)); //$NON-NLS-1$
+                    }
+                    if (returnCode[0] == PlatformUI.RETURN_OK) {
+                        // run the e4 event loop and instantiate ... well, stuff
+                        e4Workbench.createAndRunUI(e4Workbench.getApplication());
+                        IMenuService wms = e4Workbench.getContext().get(IMenuService.class);
+                        wms.dispose();
+                    }
+                    if (returnCode[0] != PlatformUI.RETURN_UNSTARTABLE) {
+                        setSearchContribution(appModel, false);
+                        e4app.saveModel();
+                    }
+
+                    // if a restart was triggered via E4Workbench the return
+                    // code needs to be set appropriately
+                    if (e4Workbench.isRestart()) {
+                        returnCode[0] = PlatformUI.RETURN_RESTART;
+                    } else {
+                        e4Workbench.close();
+                        returnCode[0] = workbench.returnCode;
+                    }
+                }
+            }
+        });
+        return returnCode[0];
+    }
+
+	private static void setSearchContribution(MApplication app, boolean enabled) {
+		for (MTrimContribution contribution : app.getTrimContributions()) {
+			if ("org.eclipse.ui.ide.application.trimcontribution.QuickAccess".contains(contribution //$NON-NLS-1$
+					.getElementId())) {
+				// allows us to handle the case where someone opens a workspace
+				// with Luna and then with Kepler
+				contribution.setToBeRendered(enabled);
+			}
+		}
+	}
+
+	private static ServiceTracker instanceAppContext;
+
+	static IApplicationContext getApplicationContext() {
+		if (instanceAppContext == null) {
+			instanceAppContext = new ServiceTracker(
+					WorkbenchPlugin.getDefault().getBundleContext(), IApplicationContext.class
+							.getName(), null);
+			instanceAppContext.open();
+		}
+		return (IApplicationContext) instanceAppContext.getService();
+	}
+
+	static Object getApplication(String[] args) {
+		// Find the name of the application as specified by the PDE JUnit
+		// launcher.
+		// If no application is specified, the 3.0 default workbench application
+		// is returned.
+		IExtension extension = Platform.getExtensionRegistry().getExtension(Platform.PI_RUNTIME,
+				Platform.PT_APPLICATIONS, "org.eclipse.e4.ui.workbench.swt.E4Application"); //$NON-NLS-1$
+
+		Assert.isNotNull(extension);
+
+		// If the extension does not have the correct grammar, return null.
+		// Otherwise, return the application object.
+		try {
+			IConfigurationElement[] elements = extension.getConfigurationElements();
+			if (elements.length > 0) {
+				IConfigurationElement[] runs = elements[0].getChildren("run"); //$NON-NLS-1$
+				if (runs.length > 0) {
+					Object runnable;
+					runnable = runs[0].createExecutableExtension("class");//$NON-NLS-1$
+					if (runnable instanceof IPlatformRunnable || runnable instanceof IApplication)
+						return runnable;
+				}
+			}
+		} catch (CoreException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		return null;
+	}
+
+	/**
+	 * Creates the <code>Display</code> to be used by the workbench.
+	 *
+	 * @return the display
+	 */
+	public static Display createDisplay() {
+		// setup the application name used by SWT to lookup resources on some
+		// platforms
+		String applicationName = WorkbenchPlugin.getDefault().getAppName();
+		if (applicationName != null) {
+			Display.setAppName(applicationName);
+		}
+
+		// create the display
+		Display newDisplay = Display.getCurrent();
+		// RAP [bm]:
+//      if(newDisplay == null) {
+//          if (Policy.DEBUG_SWT_GRAPHICS || Policy.DEBUG_SWT_DEBUG) {
+//              DeviceData data = new DeviceData();
+//              if (Policy.DEBUG_SWT_GRAPHICS) {
+//                  data.tracking = true;
+//              }
+//              if (Policy.DEBUG_SWT_DEBUG) {
+//                  data.debug = true;
+//              }
+//              newDisplay = new Display(data);
+//          } else {
+//              newDisplay = new Display();
+//          }
+//      }
+        if(newDisplay == null) {
+            newDisplay = new Display();
+        }
+        // RAPEND: [bm]
+
+        // workaround for 1GEZ9UR and 1GF07HN
+        // RAP [bm]: Display#setWarnings
+//      newDisplay.setWarnings(false);
+
+		// Set the priority higher than normal so as to be higher
+		// than the JobManager.
+		Thread.currentThread().setPriority(Math.min(Thread.MAX_PRIORITY, Thread.NORM_PRIORITY + 1));
+
+		initializeImages();
+
+		return newDisplay;
+	}
+
+	// RAP [bm]: Avoid splash
+//	/**
+//	 * Create the splash wrapper and set it to work.
+//	 *
+//	 * @since 3.3
+//	 */
+//	private void createSplashWrapper() {
+//		final Display display = getDisplay();
+//		String splashLoc = System.getProperty("org.eclipse.equinox.launcher.splash.location"); //$NON-NLS-1$
+//		final Image background = loadImage(splashLoc);
+//
+//		SafeRunnable run = new SafeRunnable() {
+//
+//			@Override
+//			public void run() throws Exception {
+//				if (!WorkbenchPlugin.isSplashHandleSpecified()) {
+//					createSplash = false;
+//					return;
+//				}
+//
+//				// create the splash
+//				getSplash();
+//				if (splash == null) {
+//					createSplash = false;
+//					return;
+//				}
+//
+//				Shell splashShell = splash.getSplash();
+//				if (splashShell == null) {
+//					splashShell = WorkbenchPlugin.getSplashShell(display);
+//
+//					if (splashShell == null)
+//						return;
+//					if (background != null)
+//						splashShell.setBackgroundImage(background);
+//				}
+//
+//				Dictionary properties = new Hashtable();
+//				properties.put(Constants.SERVICE_RANKING, Integer.valueOf(Integer.MAX_VALUE));
+//				BundleContext context = WorkbenchPlugin.getDefault().getBundleContext();
+//				final ServiceRegistration registration[] = new ServiceRegistration[1];
+//				StartupMonitor startupMonitor = new StartupMonitor() {
+//
+//					@Override
+//					public void applicationRunning() {
+//						if (background != null)
+//							background.dispose();
+//						registration[0].unregister(); // unregister ourself
+//						if (splash != null)
+//							splash.dispose();
+//						WorkbenchPlugin.unsetSplashShell(display);
+//
+//						// fire part visibility events now that we're up
+//						for (IWorkbenchWindow window : getWorkbenchWindows()) {
+//							IWorkbenchPage page = window.getActivePage();
+//							if (page != null) {
+//								((WorkbenchPage) page).fireInitialPartVisibilityEvents();
+//							}
+//						}
+//					}
+//
+//					@Override
+//					public void update() {
+//						// do nothing - we come into the picture far too late
+//						// for this to be relevant
+//					}
+//				};
+//				registration[0] = context.registerService(StartupMonitor.class.getName(), startupMonitor, properties);
+//
+//				splash.init(splashShell);
+//			}
+//
+//			@Override
+//			public void handleException(Throwable e) {
+//				StatusManager.getManager().handle(
+//						StatusUtil.newStatus(WorkbenchPlugin.PI_WORKBENCH,
+//								"Could not instantiate splash", e)); //$NON-NLS-1$
+//				createSplash = false;
+//				splash = null;
+//				if (background != null)
+//					background.dispose();
+//
+//			}
+//		};
+//		SafeRunner.run(run);
+//	}
+	// RAPEND: [bm]
+
+	// RAP [bm]: not used
+//	/**
+//	 * Load an image from a filesystem path.
+//	 *
+//	 * @param splashLoc
+//	 *            the location to load from
+//	 * @return the image or <code>null</code>
+//	 * @since 3.3
+//	 */
+//	private Image loadImage(String splashLoc) {
+//		Image background = null;
+//		if (splashLoc != null) {
+//			try (InputStream input = new BufferedInputStream(new FileInputStream(splashLoc)) ){
+//				background = new Image(display, input);
+//			} catch (SWTException | IOException e) {
+//				StatusManager.getManager().handle(StatusUtil.newStatus(WorkbenchPlugin.PI_WORKBENCH, e));
+//			}
+//		}
+//		return background;
+//	}
+	// RAPEND: [bm]
+
+	// RAP [bm]: no splash
+//	/**
+//	 * Return the splash handler for this application. If none is specifically
+//	 * provided the default Eclipse implementation is returned.
+//	 *
+//	 * @return the splash handler for this application or <code>null</code>
+//	 * @since 3.3
+//	 */
+//	private static AbstractSplashHandler getSplash() {
+//		if (!createSplash)
+//			return null;
+//
+//		if (splash == null) {
+//
+//			IProduct product = Platform.getProduct();
+//			if (product != null)
+//				splash = SplashHandlerFactory.findSplashHandlerFor(product);
+//
+//			if (splash == null)
+//				splash = new EclipseSplashHandler();
+//		}
+//		return splash;
+//	}
+	// RAPEND: [bm]
+
+	/**
+	 * Returns the testable object facade, for use by the test harness.
+	 *
+	 * @return the testable object facade
+	 * @since 3.0
+	 */
+	public static WorkbenchTestable getWorkbenchTestable() {
+	    // RAP [bm]:
+//      if (testableObject == null) {
+//          testableObject = new WorkbenchTestable();
+//      }
+//      return testableObject;
+        Workbench instance = getInstance();
+        if (instance.testableObject == null) {
+            instance.testableObject = new WorkbenchTestable();
+        }
+        return instance.testableObject;
+        // RAPEND: [bm]
+	}
+
+	@Override
+	public void addWorkbenchListener(IWorkbenchListener listener) {
+		workbenchListeners.add(listener);
+	}
+
+	@Override
+	public void removeWorkbenchListener(IWorkbenchListener listener) {
+		workbenchListeners.remove(listener);
+	}
+
+	/**
+	 * Fire workbench preShutdown event, stopping at the first one to veto
+	 *
+	 * @param forced
+	 *            flag indicating whether the shutdown is being forced
+	 * @return <code>true</code> to allow the workbench to proceed with
+	 *         shutdown, <code>false</code> to veto a non-forced shutdown
+	 * @since 3.2
+	 */
+	boolean firePreShutdown(final boolean forced) {
+		for (final IWorkbenchListener l : workbenchListeners) {
+			final boolean[] result = new boolean[] { false };
+			SafeRunnable.run(new SafeRunnable() {
+				@Override
+				public void run() {
+					result[0] = l.preShutdown(Workbench.this, forced);
+				}
+			});
+			if (!result[0]) {
+				return false;
+			}
+		}
+		return true;
+	}
+
+	/**
+	 * Fire workbench postShutdown event.
+	 *
+	 * @since 3.2
+	 */
+	void firePostShutdown() {
+		for (final IWorkbenchListener l : workbenchListeners) {
+			SafeRunnable.run(new SafeRunnable() {
+				@Override
+				public void run() {
+					l.postShutdown(Workbench.this);
+				}
+			});
+		}
+	}
+
+	@Override
+	public void addWindowListener(IWindowListener l) {
+		addListenerObject(l);
+	}
+
+	@Override
+	public void removeWindowListener(IWindowListener l) {
+		removeListenerObject(l);
+	}
+
+	/**
+	 * Fire window opened event.
+	 *
+	 * @param window
+	 *            The window which just opened; should not be <code>null</code>.
+	 */
+	protected void fireWindowOpened(final IWorkbenchWindow window) {
+		Object list[] = getListeners();
+		for (Object element : list) {
+			final IWindowListener l = (IWindowListener) element;
+			SafeRunner.run(new SafeRunnable() {
+				@Override
+				public void run() {
+					l.windowOpened(window);
+				}
+			});
+		}
+	}
+
+	/**
+	 * Fire window closed event.
+	 *
+	 * @param window
+	 *            The window which just closed; should not be <code>null</code>.
+	 */
+	protected void fireWindowClosed(final IWorkbenchWindow window) {
+		Object list[] = getListeners();
+		for (Object element : list) {
+			final IWindowListener l = (IWindowListener) element;
+			SafeRunner.run(new SafeRunnable() {
+				@Override
+				public void run() {
+					l.windowClosed(window);
+				}
+			});
+		}
+	}
+
+	/**
+	 * Fire window activated event.
+	 *
+	 * @param window
+	 *            The window which was just activated; should not be
+	 *            <code>null</code>.
+	 */
+	protected void fireWindowActivated(final IWorkbenchWindow window) {
+		Object list[] = getListeners();
+		for (Object element : list) {
+			final IWindowListener l = (IWindowListener) element;
+			SafeRunner.run(new SafeRunnable() {
+				@Override
+				public void run() {
+					l.windowActivated(window);
+				}
+			});
+		}
+	}
+
+	/**
+	 * Fire window deactivated event.
+	 *
+	 * @param window
+	 *            The window which was just deactivated; should not be
+	 *            <code>null</code>.
+	 */
+	protected void fireWindowDeactivated(final IWorkbenchWindow window) {
+		Object list[] = getListeners();
+		for (Object element : list) {
+			final IWindowListener l = (IWindowListener) element;
+			SafeRunner.run(new SafeRunnable() {
+				@Override
+				public void run() {
+					l.windowDeactivated(window);
+				}
+			});
+		}
+	}
+
+	/**
+	 * Closes the workbench. Assumes that the busy cursor is active.
+	 *
+	 * @param force
+	 *            true if the close is mandatory, and false if the close is
+	 *            allowed to fail
+	 * @return true if the close succeeded, and false otherwise
+	 */
+	private boolean busyClose(final boolean force) {
+		// Fire an E4 lifecycle notification
+		UIEvents.publishEvent(UIEvents.UILifeCycle.APP_SHUTDOWN_STARTED, application);
+
+		// notify the advisor of preShutdown and allow it to veto if not forced
+		isClosing = advisor.preShutdown();
+		if (!force && !isClosing) {
+			return false;
+		}
+
+		// notify regular workbench clients of preShutdown and allow them to
+		// veto if not forced
+		isClosing = firePreShutdown(force);
+		if (!force && !isClosing) {
+			return false;
+		}
+
+		// save any open editors if they are dirty
+		isClosing = saveAllEditors(!force, true);
+		if (!force && !isClosing) {
+			return false;
+		}
+
+		// stop the workbench auto-save job so it can't conflict with shutdown
+		if(autoSaveJob != null) {
+			autoSaveJob.cancel();
+			autoSaveJob = null;
+		}
+
+		boolean closeEditors = !force
+				&& PrefUtil.getAPIPreferenceStore().getBoolean(
+						IWorkbenchPreferenceConstants.CLOSE_EDITORS_ON_EXIT);
+		if (closeEditors) {
+			SafeRunner.run(new SafeRunnable() {
+				@Override
+				public void run() {
+					IWorkbenchWindow windows[] = getWorkbenchWindows();
+					for (IWorkbenchWindow window : windows) {
+						IWorkbenchPage pages[] = window.getPages();
+						for (IWorkbenchPage page : pages) {
+							isClosing = isClosing && page.closeAllEditors(false);
+						}
+					}
+				}
+			});
+			if (!force && !isClosing) {
+				return false;
+			}
+		}
+
+		// persist editor inputs and close editors that can't be persisted
+		// also persists views
+		persist(true);
+
+		if (!force && !isClosing) {
+			return false;
+		}
+
+		SafeRunner.run(new SafeRunnable(WorkbenchMessages.get().ErrorClosing) {
+			@Override
+			public void run() {
+				if (isClosing || force) {
+					// isClosing = windowManager.close();
+					E4Util.unsupported("Need to close since no windowManager"); //$NON-NLS-1$
+					MWindow selectedWindow = application.getSelectedElement();
+					WorkbenchWindow selected = null;
+					for (IWorkbenchWindow window : getWorkbenchWindows()) {
+						WorkbenchWindow ww = (WorkbenchWindow) window;
+						if (ww.getModel() == selectedWindow) {
+							selected = ww;
+						} else {
+							((WorkbenchWindow) window).close(false);
+						}
+					}
+
+					if (selected != null) {
+						selected.close(false);
+					}
+
+					windowsClosed = true;
+				}
+			}
+		});
+
+		if (!force && !isClosing) {
+			return false;
+		}
+
+		shutdown();
+
+		IPresentationEngine engine = application.getContext().get(IPresentationEngine.class);
+		engine.stop();
+		//System.err.println("stop()"); //$NON-NLS-1$
+
+		runEventLoop = false;
+		return true;
+	}
+
+	/**
+	 * Saves the state of the workbench in the same way that closing the it
+	 * would. Can be called while the editor is running so that if it crashes
+	 * the workbench state can be recovered.
+	 *
+	 * @param shutdown
+	 *            If true, will close any editors that cannot be persisted. Will
+	 *            also skip saving the model to the disk since that is done
+	 *            later in shutdown.
+	 */
+	private void persist(final boolean shutdown) {
+		// persist editors that can be and possibly close the others
+		SafeRunner.run(new SafeRunnable() {
+			@Override
+			public void run() {
+				IWorkbenchWindow windows[] = getWorkbenchWindows();
+				for (IWorkbenchWindow window : windows) {
+					IWorkbenchPage pages[] = window.getPages();
+					for (IWorkbenchPage page : pages) {
+						List<EditorReference> editorReferences = ((WorkbenchPage) page)
+								.getInternalEditorReferences();
+						List<EditorReference> referencesToClose = new ArrayList<>();
+						for (EditorReference reference : editorReferences) {
+							IEditorPart editor = reference.getEditor(false);
+							if (editor != null && !reference.persist() && shutdown) {
+								referencesToClose.add(reference);
+							}
+						}
+						if (shutdown) {
+							for (EditorReference reference : referencesToClose) {
+								((WorkbenchPage) page).closeEditor(reference);
+							}
+						}
+					}
+				}
+			}
+		});
+
+		// persist workbench state
+		if (getWorkbenchConfigurer().getSaveAndRestore()) {
+			SafeRunner.run(new SafeRunnable() {
+				@Override
+				public void run() {
+					persistWorkbenchState();
+				}
+
+				@Override
+				public void handleException(Throwable e) {
+					String message;
+					if (e.getMessage() == null) {
+						message = WorkbenchMessages.get().ErrorClosingNoArg;
+					} else {
+						message = NLS.bind(WorkbenchMessages.get().ErrorClosingOneArg, e.getMessage());
+					}
+
+					if (!MessageDialog.openQuestion(null, WorkbenchMessages.get().Error, message)) {
+						isClosing = false;
+					}
+				}
+			});
+		}
+
+		// persist view states
+		SafeRunner.run(new SafeRunnable() {
+			@Override
+			public void run() {
+				IWorkbenchWindow windows[] = getWorkbenchWindows();
+				for (IWorkbenchWindow window : windows) {
+					IWorkbenchPage pages[] = window.getPages();
+					for (IWorkbenchPage page : pages) {
+						IViewReference[] references = page.getViewReferences();
+						for (IViewReference reference : references) {
+							if (reference.getView(false) != null) {
+								((ViewReference) reference).persist();
+							}
+						}
+					}
+				}
+			}
+		});
+
+		// now that we have updated the model, save it to workbench.xmi
+		// skip this during shutdown to be efficient since it is done again
+		// later
+		if (!shutdown) {
+			persistWorkbenchModel();
+		}
+	}
+
+	private boolean detectWorkbenchCorruption(MApplication application) {
+		if (application.getChildren().isEmpty()) {
+			WorkbenchPlugin.log(
+					"When auto-saving the workbench model, there were no top-level windows. " //$NON-NLS-1$
+							+ " Skipped saving the model.", //$NON-NLS-1$
+					new Exception()); // log a stack trace to assist debugging
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Copy the model, clean it up and write it out to workbench.xmi. Called as
+	 * part of persist(false) during auto-save.
+	 */
+	private void persistWorkbenchModel() {
+		if (Job.getJobManager().find(WORKBENCH_AUTO_SAVE_JOB).length > 0) {
+			return;
+		}
+		final MApplication appCopy = (MApplication) EcoreUtil.copy((EObject) application);
+		if (detectWorkbenchCorruption(appCopy)) {
+			return;
+		}
+		final IModelResourceHandler handler = e4Context.get(IModelResourceHandler.class);
+
+		Job cleanAndSaveJob = new Job(WORKBENCH_AUTO_SAVE_BACKGROUND_JOB) {
+			@Override
+			protected IStatus run(IProgressMonitor monitor) {
+				final Resource res = handler.createResourceWithApp(appCopy);
+				cleanUpCopy(appCopy, e4Context);
+				try {
+					if (!detectWorkbenchCorruption((MApplication) res.getContents().get(0))) {
+						res.save(null);
+					}
+				} catch (IOException e) {
+					// Just auto-save, we don't really care
+				} finally {
+					res.unload();
+					res.getResourceSet().getResources().remove(res);
+				}
+				return Status.OK_STATUS;
+			}
+
+			@Override
+			public boolean belongsTo(Object family) {
+				return WORKBENCH_AUTO_SAVE_JOB.equals(family);
+			}
+
+		};
+		cleanAndSaveJob.setPriority(Job.SHORT);
+		cleanAndSaveJob.setSystem(true);
+		cleanAndSaveJob.schedule();
+	}
+
+	private static void cleanUpCopy(MApplication appCopy, IEclipseContext context) {
+		// clean up all trim bars that come from trim bar contributions
+		// the trim elements that need to be removed are stored in the trimBar.
+		setSearchContribution(appCopy, false);
+		EModelService modelService = context.get(EModelService.class);
+		List<MWindow> windows = modelService.findElements(appCopy, null, MWindow.class, null);
+		for (MWindow window : windows) {
+			if (window instanceof MTrimmedWindow) {
+				MTrimmedWindow trimmedWindow = (MTrimmedWindow) window;
+				// clean up the main menu to avoid duplicate menu items
+				window.setMainMenu(null);
+				// clean up trim bars created through contributions
+				// to avoid duplicate toolbars
+				for (MTrimBar trimBar : trimmedWindow.getTrimBars()) {
+					cleanUpTrimBar(trimBar);
+				}
+			}
+		}
+		appCopy.getMenuContributions().clear();
+		appCopy.getToolBarContributions().clear();
+		appCopy.getTrimContributions().clear();
+
+		List<MPart> parts = modelService.findElements(appCopy, null, MPart.class, null);
+		for (MPart part : parts) {
+			for (MMenu menu : part.getMenus()) {
+				menu.getChildren().clear();
+			}
+			MToolBar tb = part.getToolbar();
+			if (tb != null) {
+				tb.getChildren().clear();
+			}
+		}
+	}
+
+	private static void cleanUpTrimBar(MTrimBar element) {
+		for (MTrimElement child : element.getPendingCleanup()) {
+			element.getChildren().remove(child);
+		}
+		element.getPendingCleanup().clear();
+	}
+
+	@Override
+	public boolean saveAllEditors(boolean confirm) {
+		return saveAllEditors(confirm, false);
+	}
+
+	private boolean saveAllEditors(boolean confirm, boolean closing) {
+		IWorkbenchWindow[] windows = getWorkbenchWindows();
+		if (windows.length == 0) {
+			return true;
+		}
+
+		Set<IWorkbenchPart> dirtyParts = new HashSet<>();
+		for (IWorkbenchWindow window : windows) {
+			WorkbenchPage page = (WorkbenchPage) window.getActivePage();
+			if (page != null) {
+				Collections.addAll(dirtyParts, page.getDirtyWorkbenchParts());
+			}
+		}
+
+		IWorkbenchWindow activeWindow = getActiveWorkbenchWindow();
+		if (activeWindow == null) {
+			activeWindow = windows[0];
+		}
+		return WorkbenchPage.saveAll(new ArrayList<>(dirtyParts),
+				confirm, closing, true, activeWindow, activeWindow);
+	}
+
+	@Override
+	public boolean close() {
+		return close(PlatformUI.RETURN_OK, false);
+	}
+
+	/**
+	 * Closes the workbench, returning the given return code from the run
+	 * method. If forced, the workbench is closed no matter what.
+	 *
+	 * @param returnCode
+	 *            {@link PlatformUI#RETURN_OK RETURN_OK}for normal exit;
+	 *            {@link PlatformUI#RETURN_RESTART RETURN_RESTART}if the
+	 *            workbench was terminated with a call to
+	 *            {@link IWorkbench#restart IWorkbench.restart};
+	 *            {@link PlatformUI#RETURN_EMERGENCY_CLOSE} for an emergency
+	 *            shutdown {@link PlatformUI#RETURN_UNSTARTABLE
+	 *            RETURN_UNSTARTABLE}if the workbench could not be started;
+	 *            other values reserved for future use
+	 *
+	 * @param force
+	 *            true to force the workbench close, and false for a "soft"
+	 *            close that can be canceled
+	 * @return true if the close was successful, and false if the close was
+	 *         canceled
+	 */
+	/* package */
+	boolean close(int returnCode, final boolean force) {
+		this.returnCode = returnCode;
+		final boolean[] ret = new boolean[1];
+		BusyIndicator.showWhile(null, () -> ret[0] = busyClose(force));
+		return ret[0];
+	}
+
+	@Override
+	public IWorkbenchWindow getActiveWorkbenchWindow() {
+		// Return null if called from a non-UI thread.
+		// This is not spec'ed behaviour and is misleading, however this is how
+		// it
+		// worked in 2.1 and we cannot change it now.
+		// For more details, see [Bug 57384] [RCP] Main window not active on
+		// startup
+		if (Display.getCurrent() == null || !initializationDone) {
+			return null;
+		}
+
+		// the source providers try to update again during shutdown
+		if (windowsClosed) {
+			return null;
+		}
+
+		// rendering engine not available, can't make workbench windows, see bug
+		// 320932
+		if (e4Context.get(IPresentationEngine.class) == null) {
+			return null;
+		}
+
+		MWindow activeWindow = application.getSelectedElement();
+		if ((activeWindow == null || activeWindow.getWidget() == null) && !application.getChildren().isEmpty()) {
+			activeWindow = application.getChildren().get(0);
+		}
+
+		// We can't return a window with no widget...it's in the process
+		// of closing...see Bug 379717
+		if (activeWindow == null || (activeWindow != null && activeWindow.getWidget() == null)) {
+			return null;
+		}
+
+		// search for existing IWorkbenchWindow
+		IWorkbenchWindow iWorkbenchWindow = activeWindow.getContext().get(IWorkbenchWindow.class);
+		if (iWorkbenchWindow != null) {
+			return iWorkbenchWindow;
+		}
+		// otherwise create new IWorkbenchWindow instance
+		return createWorkbenchWindow(getDefaultPageInput(), getPerspectiveRegistry()
+				.findPerspectiveWithId(getPerspectiveRegistry().getDefaultPerspective()),
+				activeWindow, false);
+	}
+
+	IWorkbenchWindow createWorkbenchWindow(IAdaptable input, IPerspectiveDescriptor descriptor,
+			MWindow window, boolean newWindow) {
+
+		IEclipseContext windowContext = window.getContext();
+		if (windowContext == null) {
+			windowContext = E4Workbench.initializeContext(e4Context, window);
+		}
+		WorkbenchWindow result = (WorkbenchWindow) windowContext.get(IWorkbenchWindow.class);
+		if (result == null) {
+			if (windowBeingCreated != null)
+				return windowBeingCreated;
+			result = new WorkbenchWindow(input, descriptor);
+			windowBeingCreated = result;
+			try {
+				if (newWindow) {
+					Point size = result.getWindowConfigurer().getInitialSize();
+					window.setWidth(size.x);
+					window.setHeight(size.y);
+					application.getChildren().add(window);
+					application.setSelectedElement(window);
+				}
+				ContextInjectionFactory.inject(result, windowContext);
+				windowContext.set(IWorkbenchWindow.class, result);
+			} finally {
+				windowBeingCreated = null;
+			}
+
+			if (application.getSelectedElement() == window) {
+				application.getContext().set(ISources.ACTIVE_WORKBENCH_WINDOW_NAME, result);
+				application.getContext().set(ISources.ACTIVE_WORKBENCH_WINDOW_SHELL_NAME, result.getShell());
+			}
+
+			fireWindowOpened(result);
+			result.fireWindowOpened();
+		}
+		return result;
+	}
+
+	/*
+	 * Returns the editor history.
+	 */
+	public EditorHistory getEditorHistory() {
+		if (editorHistory == null) {
+			editorHistory = new EditorHistory();
+		}
+		return editorHistory;
+	}
+
+	@Override
+	public IEditorRegistry getEditorRegistry() {
+		return WorkbenchPlugin.getDefault().getEditorRegistry();
+	}
+
+	@Override
+	public IWorkbenchOperationSupport getOperationSupport() {
+		return WorkbenchPlugin.getDefault().getOperationSupport();
+	}
+
+	@Override
+	public IPerspectiveRegistry getPerspectiveRegistry() {
+		return WorkbenchPlugin.getDefault().getPerspectiveRegistry();
+	}
+
+	@Override
+	public PreferenceManager getPreferenceManager() {
+		return WorkbenchPlugin.getDefault().getPreferenceManager();
+	}
+
+	@Override
+	public IPreferenceStore getPreferenceStore() {
+		return WorkbenchPlugin.getDefault().getPreferenceStore();
+	}
+
+	@Override
+	public ISharedImages getSharedImages() {
+		return WorkbenchPlugin.getDefault().getSharedImages();
+	}
+
+
+
+	@Override
+	public int getWorkbenchWindowCount() {
+		return getWorkbenchWindows().length;
+	}
+
+	@Override
+	public IWorkbenchWindow[] getWorkbenchWindows() {
+		List<IWorkbenchWindow> windows = new ArrayList<>();
+		for (MWindow window : application.getChildren()) {
+			IEclipseContext context = window.getContext();
+			if (context != null) {
+				IWorkbenchWindow wwindow = (IWorkbenchWindow) context.get(IWorkbenchWindow.class
+						.getName());
+				if (wwindow != null) {
+					windows.add(wwindow);
+				}
+			}
+		}
+		return windows.toArray(new IWorkbenchWindow[windows.size()]);
+	}
+
+	@Override
+	public IWorkingSetManager getWorkingSetManager() {
+		return WorkbenchPlugin.getDefault().getWorkingSetManager();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public ILocalWorkingSetManager createLocalWorkingSetManager() {
+		return new LocalWorkingSetManager(WorkbenchPlugin.getDefault().getBundleContext());
+	}
+
+	/**
+	 * Initializes the workbench now that the display is created.
+	 *
+	 * @return true if init succeeded.
+	 */
+	private boolean init() {
+		// setup debug mode if required.
+		if (WorkbenchPlugin.getDefault().isDebugging()) {
+			WorkbenchPlugin.DEBUG = true;
+			ModalContext.setDebugMode(true);
+		}
+
+		// Set up the JFace preference store
+		JFaceUtil.initializeJFacePreferences();
+
+		// create workbench window manager
+		// windowManager = new WindowManager();
+		// TODO compat: I've removed the window manager, now what
+
+		// TODO Correctly order service initialization
+		// there needs to be some serious consideration given to
+		// the services, and hooking them up in the correct order
+		e4Context.set("org.eclipse.core.runtime.Platform", Platform.class); //$NON-NLS-1$
+		final EvaluationService evaluationService = new EvaluationService(e4Context);
+
+		StartupThreading.runWithoutExceptions(new StartupRunnable() {
+
+			@Override
+			public void runWithException() {
+				serviceLocator.registerService(IEvaluationService.class, evaluationService);
+			}
+		});
+
+		initializeLazyServices();
+
+		// Initialize the activity support.
+
+		activityHelper = ActivityPersistanceHelper.getInstance();
+		StartupThreading.runWithoutExceptions(new StartupRunnable() {
+
+			@Override
+			public void runWithException() {
+				WorkbenchImages.getImageRegistry();
+			}
+		});
+		initializeE4Services();
+		IIntroRegistry introRegistry = WorkbenchPlugin.getDefault().getIntroRegistry();
+        if (introRegistry.getIntroCount() > 0) {
+            // RAP [bm]: no product support - use branding instead
+//          IProduct product = Platform.getProduct();
+//          if (product != null) {
+//              introDescriptor = (IntroDescriptor) introRegistry
+//                      .getIntroForProduct(product.getId());
+//          }
+            String brandingId = BrandingUtil.getCurrentBrandingId();
+            if (brandingId != null) {
+                introDescriptor = (IntroDescriptor) introRegistry
+                        .getIntroForBranding(brandingId);
+            }
+            // ENDRAP
+        }
+		initializeDefaultServices();
+		initializeFonts();
+		initializeColors();
+		initializeApplicationColors();
+
+		// now that the workbench is sufficiently initialized, let the advisor
+		// have a turn.
+		StartupThreading.runWithoutExceptions(new StartupRunnable() {
+
+			@Override
+			public void runWithException() {
+				advisor.internalBasicInitialize(getWorkbenchConfigurer());
+			}
+		});
+
+		// configure use of color icons in toolbars
+		boolean useColorIcons = PrefUtil.getInternalPreferenceStore().getBoolean(
+				IPreferenceConstants.COLOR_ICONS);
+		ActionContributionItem.setUseColorIconsInToolbars(useColorIcons);
+
+		// initialize workbench single-click vs double-click behavior
+		initializeSingleClickOption();
+
+        //RAP
+//      initializeGlobalization();
+		initializeNLExtensions();
+
+		initializeWorkbenchImages();
+
+		StartupThreading.runWithoutExceptions(new StartupRunnable() {
+
+			@Override
+			public void runWithException() {
+				((GrabFocus) Tweaklets.get(GrabFocus.KEY)).init(getDisplay());
+			}
+		});
+
+		// attempt to restore a previous workbench state
+		try {
+			UIStats.start(UIStats.RESTORE_WORKBENCH, "Workbench"); //$NON-NLS-1$
+
+			final boolean bail[] = new boolean[1];
+			StartupThreading.runWithoutExceptions(new StartupRunnable() {
+
+				@Override
+				public void runWithException() throws Throwable {
+					advisor.preStartup();
+					// TODO compat: open the windows here/instantiate the model
+					// TODO compat: instantiate the WW around the model
+					initializationDone = true;
+					if (isClosing() || !advisor.openWindows()) {
+						// if (isClosing()) {
+						bail[0] = true;
+					}
+
+					restoreWorkbenchState();
+				}
+			});
+
+			if (bail[0])
+				return false;
+
+		} finally {
+			UIStats.end(UIStats.RESTORE_WORKBENCH, this, "Workbench"); //$NON-NLS-1$
+		}
+
+		// forceOpenPerspective();
+
+		return true;
+	}
+
+	/**
+	 *
+	 */
+	private void initializeWorkbenchImages() {
+		StartupThreading.runWithoutExceptions(new StartupRunnable() {
+			@Override
+			public void runWithException() {
+				WorkbenchImages.getDescriptors();
+			}
+		});
+	}
+
+	/**
+	 * Establishes the relationship between JFace actions and the command
+	 * manager.
+	 */
+	private void initializeCommandResolver() {
+		ExternalActionManager.getInstance().setCallback(
+				new CommandCallback(bindingManager, commandManager, commandId -> workbenchActivitySupport.getActivityManager().getIdentifier(
+						commandId).isEnabled(), action -> !(action instanceof CommandAction)));
+	}
+
+	/**
+	 * Initialize colors defined by the new colorDefinitions extension point.
+	 * Note this will be rolled into initializeColors() at some point.
+	 *
+	 * @since 3.0
+	 */
+	private void initializeApplicationColors() {
+		StartupThreading.runWithoutExceptions(new StartupRunnable() {
+
+			@Override
+			public void runWithException() {
+				ColorDefinition[] colorDefinitions = WorkbenchPlugin.getDefault()
+						.getThemeRegistry().getColors();
+				// RAP
+              ThemeElementHelper.populateRegistry(getThemeManager().getCurrentTheme(),
+                      colorDefinitions, PrefUtil.getInternalPreferenceStore());
+			}
+		});
+	}
+
+	void initializeSingleClickOption() {
+		IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore();
+		boolean openOnSingleClick = store.getBoolean(IPreferenceConstants.OPEN_ON_SINGLE_CLICK);
+		boolean selectOnHover = store.getBoolean(IPreferenceConstants.SELECT_ON_HOVER);
+		boolean openAfterDelay = store.getBoolean(IPreferenceConstants.OPEN_AFTER_DELAY);
+		int singleClickMethod = openOnSingleClick ? OpenStrategy.SINGLE_CLICK
+				: OpenStrategy.DOUBLE_CLICK;
+		if (openOnSingleClick) {
+			if (selectOnHover) {
+				singleClickMethod |= OpenStrategy.SELECT_ON_HOVER;
+			}
+			if (openAfterDelay) {
+				singleClickMethod |= OpenStrategy.ARROW_KEYS_OPEN;
+			}
+		}
+		OpenStrategy.setOpenMethod(singleClickMethod);
+	}
+
+//	private void initializeGlobalization() {
+//		IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore();
+//
+//		if (!store.isDefault(IPreferenceConstants.BIDI_SUPPORT)) {
+//			BidiUtils.setBidiSupport(store.getBoolean(IPreferenceConstants.BIDI_SUPPORT));
+//		}
+//		if (!store.isDefault(IPreferenceConstants.TEXT_DIRECTION)) {
+//			BidiUtils.setTextDirection(store.getString(IPreferenceConstants.TEXT_DIRECTION));
+//		}
+//	}
+
+	private void initializeNLExtensions() {
+		IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore();
+		if (!store.isDefault(IPreferenceConstants.NL_EXTENSIONS)) {
+			String nlExtensions = store.getString(IPreferenceConstants.NL_EXTENSIONS);
+			ULocale.setDefault(Category.FORMAT, new ULocale(ULocale.getDefault(Category.FORMAT)
+					.getBaseName() + nlExtensions));
+		}
+	}
+
+	/*
+	 * Initializes the workbench fonts with the stored values.
+	 */
+	private void initializeFonts() {
+		StartupThreading.runWithoutExceptions(new StartupRunnable() {
+
+			@Override
+			public void runWithException() {
+				FontDefinition[] fontDefinitions = WorkbenchPlugin.getDefault().getThemeRegistry()
+						.getFonts();
+
+				ThemeElementHelper.populateRegistry(getThemeManager().getCurrentTheme(),
+						fontDefinitions, PrefUtil.getInternalPreferenceStore());
+				final IPropertyChangeListener themeToPreferencesFontSynchronizer = event -> {
+					if (event.getNewValue() instanceof FontData[]) {
+						FontData[] fontData = (FontData[]) event.getNewValue();
+						PrefUtil.getInternalPreferenceStore().setValue(event.getProperty(),
+								PreferenceConverter.getStoredRepresentation(fontData));
+					}
+				};
+				getThemeManager().getCurrentTheme().getFontRegistry().addListener(themeToPreferencesFontSynchronizer);
+				getThemeManager().addPropertyChangeListener(event -> {
+					if (IThemeManager.CHANGE_CURRENT_THEME.equals(event.getProperty())) {
+						Object oldValue = event.getOldValue();
+						if (oldValue != null && oldValue instanceof ITheme) {
+							((ITheme) oldValue).removePropertyChangeListener(themeToPreferencesFontSynchronizer);
+						}
+						Object newValue = event.getNewValue();
+						if (newValue != null && newValue instanceof ITheme) {
+							((ITheme) newValue).addPropertyChangeListener(themeToPreferencesFontSynchronizer);
+						}
+					}
+				});
+			}
+		});
+	}
+
+	/*
+	 * Initialize the workbench images.
+	 *
+	 * @param windowImages An array of the descriptors of the images to be used
+	 * in the corner of each window, or <code>null</code> if none. It is
+	 * expected that the array will contain the same icon, rendered at different
+	 * sizes.
+	 *
+	 * @since 3.0
+	 */
+	private static void initializeImages() {
+		ImageDescriptor[] windowImages = WorkbenchPlugin.getDefault().getWindowImages();
+		if (windowImages == null) {
+			return;
+		}
+
+		Image[] images = new Image[windowImages.length];
+		for (int i = 0; i < windowImages.length; ++i) {
+			images[i] = windowImages[i].createImage();
+		}
+		Window.setDefaultImages(images);
+	}
+
+	/*
+	 * Take the workbenches' images out of the shared registry.
+	 *
+	 * @since 3.0
+	 */
+	private void uninitializeImages() {
+		WorkbenchImages.dispose();
+		Image[] images = Window.getDefaultImages();
+		Window.setDefaultImage(null);
+		for (Image image : images) {
+			image.dispose();
+		}
+	}
+
+	/*
+	 * Initialize the workbench colors.
+	 *
+	 * @since 3.0
+	 */
+	private void initializeColors() {
+		StartupThreading.runWithoutExceptions(new StartupRunnable() {
+			@Override
+			public void runWithException() {
+				WorkbenchColors.startup();
+			}
+		});
+	}
+
+	@Override
+	public boolean isClosing() {
+		return isClosing;
+	}
+
+	private final void initializeE4Services() {
+		// track the workbench preference and update the eclipse context with
+		// the new value
+		IPreferenceStore preferenceStore = PrefUtil.getAPIPreferenceStore();
+		preferenceStore.addPropertyChangeListener(event -> {
+			if (IWorkbenchPreferenceConstants.ENABLE_ANIMATIONS.equals(event.getProperty())) {
+				Object o = event.getNewValue();
+				if (o instanceof Boolean) {
+					// Boolean if notified after the preference page has
+					// been closed
+					e4Context.set(IPresentationEngine.ANIMATIONS_ENABLED, o);
+				} else if (o instanceof String) {
+					// String if notified via an import of the preference
+					e4Context.set(IPresentationEngine.ANIMATIONS_ENABLED,
+							Boolean.parseBoolean((String) event.getNewValue()));
+				}
+			}
+		});
+
+		eventBroker.subscribe(UIEvents.ElementContainer.TOPIC_CHILDREN, event -> {
+			if (application == event.getProperty(UIEvents.EventTags.ELEMENT)) {
+				if (UIEvents.isREMOVE(event)) {
+					for (Object removed : UIEvents.asIterable(event, UIEvents.EventTags.OLD_VALUE)) {
+						MWindow window = (MWindow) removed;
+						IEclipseContext windowContext = window.getContext();
+						if (windowContext != null) {
+							IWorkbenchWindow wwindow = windowContext.get(IWorkbenchWindow.class);
+							if (wwindow != null) {
+								fireWindowClosed(wwindow);
+							}
+						}
+					}
+				}
+			}
+		});
+		eventBroker.subscribe(UIEvents.ElementContainer.TOPIC_SELECTEDELEMENT, event -> {
+			if (application == event.getProperty(UIEvents.EventTags.ELEMENT)) {
+				if (UIEvents.EventTypes.SET.equals(event.getProperty(UIEvents.EventTags.TYPE))) {
+					MWindow window = (MWindow) event.getProperty(UIEvents.EventTags.NEW_VALUE);
+					if (window != null) {
+						IWorkbenchWindow wwindow = window.getContext().get(IWorkbenchWindow.class);
+						if (wwindow != null) {
+							e4Context.set(ISources.ACTIVE_WORKBENCH_WINDOW_NAME, wwindow);
+							e4Context.set(ISources.ACTIVE_WORKBENCH_WINDOW_SHELL_NAME, wwindow.getShell());
+						}
+					}
+				}
+			}
+		});
+
+		// watch for parts' "toBeRendered" attribute being flipped to true, if
+		// they need to be rendered, then they need a corresponding 3.x
+		// reference
+		eventBroker.subscribe(UIEvents.UIElement.TOPIC_TOBERENDERED, event -> {
+			if (Boolean.TRUE.equals(event.getProperty(UIEvents.EventTags.NEW_VALUE))) {
+				Object element = event.getProperty(UIEvents.EventTags.ELEMENT);
+				if (element instanceof MPart) {
+					MPart part = (MPart) element;
+					createReference(part);
+				}
+			}
+});
+
+		// watch for parts' contexts being set, once they've been set, we need
+		// to inject the ViewReference/EditorReference into the context
+		eventBroker.subscribe(UIEvents.Context.TOPIC_CONTEXT, event -> {
+			Object element = event.getProperty(UIEvents.EventTags.ELEMENT);
+			if (element instanceof MPart) {
+				MPart part = (MPart) element;
+				IEclipseContext context = part.getContext();
+				if (context != null) {
+					setReference(part, context);
+				}
+			}
+		});
+
+		eventBroker.subscribe(UIEvents.ElementContainer.TOPIC_CHILDREN, event -> {
+			Object element = event.getProperty(UIEvents.EventTags.ELEMENT);
+			if (!(element instanceof MApplication)) {
+				return;
+			}
+			MApplication app = (MApplication) element;
+			if (UIEvents.isREMOVE(event)) {
+				if (app.getChildren().isEmpty()) {
+					Object oldValue = event.getProperty(UIEvents.EventTags.OLD_VALUE);
+					WorkbenchPlugin.log("The final top level window " + oldValue //$NON-NLS-1$
+							+ " was just removed", new Exception()); //$NON-NLS-1$
+				}
+			}
+		});
+
+		eventBroker.subscribe(UIEvents.UIModelTopicBase + "/*", event -> { // //$NON-NLS-1$
+			applicationModelChanged = true;
+		});
+
+		boolean found = false;
+		List<MPartDescriptor> currentDescriptors = application.getDescriptors();
+		for (MPartDescriptor desc : currentDescriptors) {
+			// do we have a matching descriptor?
+			if (desc.getElementId().equals(CompatibilityEditor.MODEL_ELEMENT_ID)) {
+				found = true;
+				break;
+			}
+		}
+		if (!found) {
+			MPartDescriptor descriptor = org.eclipse.e4.ui.model.application.descriptor.basic.impl.BasicFactoryImpl.eINSTANCE
+					.createPartDescriptor();
+			descriptor.getTags().add("Editor"); //$NON-NLS-1$
+			descriptor.setCloseable(true);
+			descriptor.setAllowMultiple(true);
+			descriptor.setElementId(CompatibilityEditor.MODEL_ELEMENT_ID);
+			descriptor.setContributionURI(CompatibilityPart.COMPATIBILITY_EDITOR_URI);
+			descriptor.setCategory("org.eclipse.e4.primaryDataStack"); //$NON-NLS-1$
+			application.getDescriptors().add(descriptor);
+		}
+
+		WorkbenchPlugin.getDefault().getViewRegistry();
+	}
+
+	/**
+	 * Returns a workbench page that will contain the specified part. If no page
+	 * can be located, one will be instantiated.
+	 *
+	 * @param part
+	 *            the model part to query a parent workbench page for
+	 * @return the workbench page that contains the specified part
+	 */
+	private WorkbenchPage getWorkbenchPage(MPart part) {
+		IEclipseContext context = getWindowContext(part);
+		WorkbenchPage page = (WorkbenchPage) context.get(IWorkbenchPage.class);
+		if (page == null) {
+			MWindow window = context.get(MWindow.class);
+			Workbench workbench = (Workbench) PlatformUI.getWorkbench();
+			workbench.openWorkbenchWindow(getDefaultPageInput(), getPerspectiveRegistry()
+					.findPerspectiveWithId(getDefaultPerspectiveId()),
+					window, false);
+			page = (WorkbenchPage) context.get(IWorkbenchPage.class);
+		}
+		return page;
+	}
+
+	/**
+	 * Sets the 3.x reference of the specified part into its context.
+	 *
+	 * @param part
+	 *            the model part that requires a 3.x part reference
+	 * @param context
+	 *            the part's context
+	 */
+	private void setReference(MPart part, IEclipseContext context) {
+		String uri = part.getContributionURI();
+		if (CompatibilityPart.COMPATIBILITY_EDITOR_URI.equals(uri)) {
+			WorkbenchPage page = getWorkbenchPage(part);
+			EditorReference ref = page.getEditorReference(part);
+			if (ref == null) {
+				// If this editor was cloned from an existing editor (as
+				// part of a split...) then re-create a valid EditorReference
+				// from the existing editor's ref.
+				MPart clonedFrom = (MPart) part.getTransientData().get(EModelService.CLONED_FROM_KEY);
+				if (clonedFrom != null && clonedFrom.getContext() != null) {
+					EditorReference originalRef = page.getEditorReference(clonedFrom);
+					if (originalRef != null) {
+						IEditorInput partInput = null;
+						String editorId = originalRef.getDescriptor().getId();
+						try {
+							partInput = originalRef.getEditorInput();
+						} catch (PartInitException e) {
+							System.out.println("Ooops !!!"); //$NON-NLS-1$
+						}
+						ref = page.createEditorReferenceForPart(part, partInput, editorId, null);
+					}
+				}
+
+				// Fallback code
+				if (ref == null) {
+					ref = createEditorReference(part, page);
+				}
+			}
+			context.set(EditorReference.class, ref);
+		} else {
+			// Create View References for 'e4' parts as well
+			WorkbenchPage page = getWorkbenchPage(part);
+			ViewReference ref = page.getViewReference(part);
+			if (ref == null) {
+				ref = createViewReference(part, page);
+			}
+			context.set(ViewReference.class, ref);
+		}
+	}
+
+	private ViewReference createViewReference(MPart part, WorkbenchPage page) {
+		WorkbenchWindow window = (WorkbenchWindow) page.getWorkbenchWindow();
+
+		// If the partId contains a ':' then only use the substring before it to
+		// fine the descriptor
+		String partId = part.getElementId();
+
+		// If the id contains a ':' use the part before it as the descriptor id
+		int colonIndex = partId.indexOf(':');
+		String descId = colonIndex == -1 ? partId : partId.substring(0, colonIndex);
+
+		IViewDescriptor desc = window.getWorkbench().getViewRegistry().find(descId);
+		ViewReference ref = new ViewReference(window.getModel().getContext(), page, part,
+				(ViewDescriptor) desc);
+		page.addViewReference(ref);
+		return ref;
+	}
+
+	private EditorReference createEditorReference(MPart part, WorkbenchPage page) {
+		WorkbenchWindow window = (WorkbenchWindow) page.getWorkbenchWindow();
+		EditorReference ref = new EditorReference(window.getModel().getContext(), page, part, null,
+				null, null);
+		page.addEditorReference(ref);
+		return ref;
+	}
+
+	/**
+	 * Creates a workbench part reference for the specified part if one does not
+	 * already exist.
+	 *
+	 * @param part
+	 *            the model part to create a 3.x part reference for
+	 */
+	private void createReference(MPart part) {
+		String uri = part.getContributionURI();
+		if (CompatibilityPart.COMPATIBILITY_VIEW_URI.equals(uri)) {
+			WorkbenchPage page = getWorkbenchPage(part);
+			ViewReference ref = page.getViewReference(part);
+			if (ref == null) {
+				createViewReference(part, page);
+			}
+		} else if (CompatibilityPart.COMPATIBILITY_EDITOR_URI.equals(uri)) {
+			WorkbenchPage page = getWorkbenchPage(part);
+			EditorReference ref = page.getEditorReference(part);
+			if (ref == null) {
+				createEditorReference(part, page);
+			}
+		}
+	}
+
+	private IEclipseContext getWindowContext(MPart part) {
+		MElementContainer<?> parent = (MElementContainer<?>) ((EObject) part).eContainer();
+		while (!(parent instanceof MWindow)) {
+			parent = (MElementContainer<?>) ((EObject) parent).eContainer(); // parent.getParent();
+		}
+
+		return ((MWindow) parent).getContext();
+	}
+
+	private final void initializeLazyServices() {
+		e4Context.set(IExtensionTracker.class.getName(), new ContextFunction() {
+
+			@Override
+			public Object compute(IEclipseContext context, String contextKey) {
+				if (tracker == null) {
+					tracker = new UIExtensionTracker(getDisplay());
+				}
+				return tracker;
+			}
+		});
+		e4Context.set(IWorkbenchActivitySupport.class.getName(), new ContextFunction() {
+
+			@Override
+			public Object compute(IEclipseContext context, String contextKey) {
+				if (workbenchActivitySupport == null) {
+					workbenchActivitySupport = new WorkbenchActivitySupport();
+				}
+				return workbenchActivitySupport;
+			}
+		});
+		e4Context.set(IProgressService.class.getName(), new ContextFunction() {
+			@Override
+			public Object compute(IEclipseContext context, String contextKey) {
+				return ProgressManager.getInstance();
+			}
+		});
+		WorkbenchPlugin.getDefault().initializeContext(e4Context);
+	}
+
+	private ArrayList<MCommand> commandsToRemove = new ArrayList<>();
+	private ArrayList<MCategory> categoriesToRemove = new ArrayList<>();
+
+	private CommandService initializeCommandService(IEclipseContext appContext) {
+		CommandService service = new CommandService(commandManager, appContext);
+		appContext.set(ICommandService.class, service);
+		appContext.set(IUpdateService.class, service);
+		service.readRegistry();
+
+		return service;
+	}
+
+	private Map<String, MBindingContext> bindingContexts = new HashMap<>();
+
+	public MBindingContext getBindingContext(String id) {
+		// cache
+		MBindingContext result = bindingContexts.get(id);
+		if (result == null) {
+			// search
+			result = searchContexts(id, application.getRootContext());
+			if (result == null) {
+				// create
+				result = MCommandsFactory.INSTANCE.createBindingContext();
+				result.setElementId(id);
+				result.setName("Auto::" + id); //$NON-NLS-1$
+				application.getRootContext().add(result);
+			}
+			if (result != null) {
+				bindingContexts.put(id, result);
+			}
+		}
+		return result;
+	}
+
+	/**
+	 * @param id
+	 * @param rootContext
+	 * @return
+	 */
+	private MBindingContext searchContexts(String id, List<MBindingContext> rootContext) {
+		for (MBindingContext context : rootContext) {
+			if (context.getElementId().equals(id)) {
+				return context;
+			}
+			MBindingContext result = searchContexts(id, context.getChildren());
+			if (result != null) {
+				return result;
+			}
+		}
+		return null;
+	}
+	private void defineBindingTable(String id) {
+		List<MBindingTable> bindingTables = application.getBindingTables();
+		if (contains(bindingTables, id)) {
+			return;
+		}
+		if (WorkbenchPlugin.getDefault().isDebugging()) {
+			WorkbenchPlugin.log("Defining a binding table: " + id); //$NON-NLS-1$
+		}
+		MBindingTable bt = CommandsFactoryImpl.eINSTANCE.createBindingTable();
+		bt.setBindingContext(getBindingContext(id));
+		bindingTables.add(bt);
+	}
+
+	/**
+	 * @param bindingTables
+	 * @param id
+	 * @return true if this BT already exists
+	 */
+	private boolean contains(List<MBindingTable> bindingTables, String id) {
+		for (MBindingTable bt : bindingTables) {
+			if (id.equals(bt.getBindingContext().getElementId())) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Initializes all of the default services for the workbench. For
+	 * initializing the command-based services, this also parses the registry
+	 * and hooks up all the required listeners.
+	 */
+	private final void initializeDefaultServices() {
+
+		final IContributionService contributionService = new ContributionService(getAdvisor());
+		serviceLocator.registerService(IContributionService.class, contributionService);
+
+		// TODO Correctly order service initialization
+		// there needs to be some serious consideration given to
+		// the services, and hooking them up in the correct order
+		final IEvaluationService evaluationService = serviceLocator.getService(IEvaluationService.class);
+
+		StartupThreading.runWithoutExceptions(new StartupRunnable() {
+
+			@Override
+			public void runWithException() {
+				serviceLocator.registerService(ISaveablesLifecycleListener.class, new SaveablesList());
+			}
+		});
+
+		/*
+		 * Phase 1 of the initialization of commands. When this phase completes,
+		 * all the services and managers will exist, and be accessible via the
+		 * getService(Object) method.
+		 */
+		StartupThreading.runWithoutExceptions(new StartupRunnable() {
+
+			@Override
+			public void runWithException() {
+				Command.DEBUG_COMMAND_EXECUTION = Policy.DEBUG_COMMANDS;
+				commandManager = e4Context.get(CommandManager.class);
+			}
+		});
+
+		final CommandService[] commandService = new CommandService[1];
+		StartupThreading.runWithoutExceptions(new StartupRunnable() {
+
+			@Override
+			public void runWithException() {
+				commandService[0] = initializeCommandService(e4Context);
+
+			}
+		});
+
+		StartupThreading.runWithoutExceptions(new StartupRunnable() {
+
+			@Override
+			public void runWithException() {
+				ContextManager.DEBUG = Policy.DEBUG_CONTEXTS;
+				contextManager = e4Context.get(ContextManager.class);
+			}
+		});
+
+		IContextService cxs = ContextInjectionFactory.make(ContextService.class, e4Context);
+
+		final IContextService contextService = cxs;
+
+		StartupThreading.runWithoutExceptions(new StartupRunnable() {
+
+			@Override
+			public void runWithException() {
+				contextManager.addContextManagerListener(contextManagerEvent -> {
+					if (contextManagerEvent.isContextChanged()) {
+						String id = contextManagerEvent.getContextId();
+						if (id != null) {
+							defineBindingTable(id);
+						}
+					}
+				});
+				EContextService ecs = e4Context.get(EContextService.class);
+				ecs.activateContext(IContextService.CONTEXT_ID_DIALOG_AND_WINDOW);
+			}
+		});
+
+		serviceLocator.registerService(IContextService.class, contextService);
+
+		final IBindingService[] bindingService = new BindingService[1];
+
+		StartupThreading.runWithoutExceptions(new StartupRunnable() {
+
+			@Override
+			public void runWithException() {
+				BindingManager.DEBUG = Policy.DEBUG_KEY_BINDINGS;
+				bindingManager = e4Context.get(BindingManager.class);
+				bindingService[0] = ContextInjectionFactory.make(
+						BindingService.class, e4Context);
+			}
+		});
+
+		// bindingService[0].readRegistryAndPreferences(commandService[0]);
+		serviceLocator.registerService(IBindingService.class, bindingService[0]);
+
+		final CommandImageManager commandImageManager = new CommandImageManager();
+		final CommandImageService commandImageService = new CommandImageService(commandImageManager, commandService[0]);
+		commandImageService.readRegistry();
+		serviceLocator.registerService(ICommandImageService.class, commandImageService);
+
+		final WorkbenchMenuService menuService = new WorkbenchMenuService(serviceLocator, e4Context);
+
+		serviceLocator.registerService(IMenuService.class, menuService);
+		// the service must be registered before it is initialized - its
+		// initialization uses the service locator to address a dependency on
+		// the menu service
+		StartupThreading.runWithoutExceptions(new StartupRunnable() {
+
+			@Override
+			public void runWithException() {
+				menuService.readRegistry();
+			}
+		});
+
+		/*
+		 * Phase 2 of the initialization of commands. The source providers that
+		 * the workbench provides are creating and registered with the above
+		 * services. These source providers notify the services when particular
+		 * pieces of workbench state change.
+		 */
+		final SourceProviderService sourceProviderService = new SourceProviderService(serviceLocator);
+		serviceLocator.registerService(ISourceProviderService.class, sourceProviderService);
+		StartupThreading.runWithoutExceptions(new StartupRunnable() {
+
+			@Override
+			public void runWithException() {
+				// this currently instantiates all players ... sigh
+				sourceProviderService.readRegistry();
+				ISourceProvider[] sp = sourceProviderService.getSourceProviders();
+				for (int i = 0; i < sp.length; i++) {
+					evaluationService.addSourceProvider(sp[i]);
+					if (!(sp[i] instanceof ActiveContextSourceProvider)) {
+						contextService.addSourceProvider(sp[i]);
+					}
+				}
+			}
+		});
+
+		StartupThreading.runWithoutExceptions(new StartupRunnable() {
+
+			@Override
+			public void runWithException() {
+				// these guys are need to provide the variables they say
+				// they source
+
+				FocusControlSourceProvider focusControl = (FocusControlSourceProvider) sourceProviderService
+						.getSourceProvider(ISources.ACTIVE_FOCUS_CONTROL_ID_NAME);
+				serviceLocator.registerService(IFocusService.class, focusControl);
+
+				menuSourceProvider = (MenuSourceProvider) sourceProviderService
+						.getSourceProvider(ISources.ACTIVE_MENU_NAME);
+			}
+		});
+
+		/*
+		 * Phase 3 of the initialization of commands. This handles the creation
+		 * of wrappers for legacy APIs. By the time this phase completes, any
+		 * code trying to access commands through legacy APIs should work.
+		 */
+		final IHandlerService[] handlerService = new IHandlerService[1];
+		StartupThreading.runWithoutExceptions(new StartupRunnable() {
+
+			@Override
+			public void runWithException() {
+				handlerService[0] = new LegacyHandlerService(e4Context);
+				e4Context.set(IHandlerService.class, handlerService[0]);
+				handlerService[0].readRegistry();
+			}
+		});
+		workbenchContextSupport = new WorkbenchContextSupport(this, contextManager);
+		workbenchCommandSupport = new WorkbenchCommandSupport(bindingManager, commandManager, contextManager,
+				handlerService[0]);
+		initializeCommandResolver();
+
+		// addWindowListener(windowListener);
+		bindingManager.addBindingManagerListener(bindingManagerListener);
+
+		serviceLocator.registerService(ISelectionConversionService.class,
+				new SelectionConversionService());
+
+		backForwardListener = createBackForwardListener();
+		StartupThreading.runWithoutExceptions(new StartupRunnable() {
+			@Override
+			public void runWithException() {
+				getDisplay().addFilter(SWT.MouseDown, backForwardListener);
+			}
+		});
+	}
+
+	private Listener createBackForwardListener() {
+		return event -> {
+			String commandId;
+			switch (event.button) {
+			case 4:
+			case 8:
+				commandId = IWorkbenchCommandConstants.NAVIGATE_BACKWARD_HISTORY;
+				break;
+			case 5:
+			case 9:
+				commandId = IWorkbenchCommandConstants.NAVIGATE_FORWARD_HISTORY;
+				break;
+			default:
+				return;
+			}
+
+			final IHandlerService handlerService = getService(IHandlerService.class);
+
+			try {
+				handlerService.executeCommand(commandId, event);
+				event.doit = false;
+			} catch (NotDefinedException e1) {
+				// regular condition; do nothing
+			} catch (NotEnabledException e2) {
+				// regular condition; do nothing
+			} catch (NotHandledException e3) {
+				// regular condition; do nothing
+			} catch (ExecutionException ex) {
+				StatusUtil.handleStatus(ex, StatusManager.SHOW | StatusManager.LOG);
+			}
+		};
+	}
+
+	/**
+	 * Returns true if the Workbench is in the process of starting.
+	 *
+	 * @return <code>true</code> if the Workbench is starting, but not yet
+	 *         running the event loop.
+	 */
+	@Override
+	public boolean isStarting() {
+		return isStarting && isRunning();
+	}
+
+	/**
+	 * Opens the initial workbench window.
+	 */
+	/* package */void openFirstTimeWindow() {
+		final boolean showProgress = PrefUtil.getAPIPreferenceStore().getBoolean(
+				IWorkbenchPreferenceConstants.SHOW_PROGRESS_ON_STARTUP);
+
+		if (!showProgress) {
+			doOpenFirstTimeWindow();
+		} else {
+			// We don't know how many plug-ins will be loaded,
+			// assume we are loading a tenth of the installed plug-ins.
+			// (The Eclipse SDK loads 7 of 86 plug-ins at startup as of
+			// 2005-5-20)
+			final int expectedProgressCount = Math.max(1, WorkbenchPlugin.getDefault()
+					.getBundleCount() / 10);
+
+			runStartupWithProgress(expectedProgressCount, () -> doOpenFirstTimeWindow());
+		}
+	}
+
+	private void doOpenFirstTimeWindow() {
+		try {
+			final IAdaptable input[] = new IAdaptable[1];
+			StartupThreading.runWithoutExceptions(new StartupRunnable() {
+
+				@Override
+				public void runWithException() throws Throwable {
+					input[0] = getDefaultPageInput();
+				}
+			});
+
+			openWorkbenchWindow(getDefaultPerspectiveId(), input[0]);
+		} catch (final WorkbenchException e) {
+			// Don't use the window's shell as the dialog parent,
+			// as the window is not open yet (bug 76724).
+			StartupThreading.runWithoutExceptions(new StartupRunnable() {
+
+				@Override
+				public void runWithException() throws Throwable {
+					ErrorDialog.openError(null, WorkbenchMessages.get().Problems_Opening_Page, e
+							.getMessage(), e.getStatus());
+				}
+			});
+		}
+	}
+
+	private void runStartupWithProgress(final int expectedProgressCount, final Runnable runnable) {
+	    // RAP [bm]: no chance to show progress, just start up
+	    runnable.run();
+	    
+//	    progressCount = 0;
+//		final double cutoff = 0.95;
+//
+//		AbstractSplashHandler handler = getSplash();
+//		IProgressMonitor progressMonitor = null;
+//		if (handler != null)
+//			progressMonitor = handler.getBundleProgressMonitor();
+//
+//		if (progressMonitor == null) {
+//			// cannot report progress (e.g. if the splash screen is not showing)
+//			// fall back to starting without showing progress.
+//			runnable.run();
+//		} else {
+//			progressMonitor.beginTask("", expectedProgressCount); //$NON-NLS-1$
+//			SynchronousBundleListener bundleListener = new StartupProgressBundleListener(
+//					progressMonitor, (int) (expectedProgressCount * cutoff));
+//			WorkbenchPlugin.getDefault().addBundleListener(bundleListener);
+//			try {
+//				runnable.run();
+//				progressMonitor.subTask(WorkbenchMessages.get().Startup_Done);
+//				int remainingWork = expectedProgressCount
+//						- Math.min(progressCount, (int) (expectedProgressCount * cutoff));
+//				progressMonitor.worked(remainingWork);
+//				progressMonitor.done();
+//			} finally {
+//				WorkbenchPlugin.getDefault().removeBundleListener(bundleListener);
+//			}
+//		}
+        // RAPEND: [bm]
+	}
+
+	@Override
+	public IWorkbenchWindow openWorkbenchWindow(IAdaptable input) throws WorkbenchException {
+		return openWorkbenchWindow(getDefaultPerspectiveId(), input);
+	}
+
+	@Override
+	public IWorkbenchWindow openWorkbenchWindow(String perspectiveId, IAdaptable input)
+			throws WorkbenchException {
+		IPerspectiveDescriptor descriptor = getPerspectiveRegistry().findPerspectiveWithId(
+				perspectiveId);
+		try {
+			MWindow window = BasicFactoryImpl.eINSTANCE.createTrimmedWindow();
+			return openWorkbenchWindow(input, descriptor, window, true);
+		} catch (InjectionException e) {
+			throw new WorkbenchException(e.getMessage(), e);
+		}
+	}
+
+	public WorkbenchWindow openWorkbenchWindow(IAdaptable input, IPerspectiveDescriptor descriptor,
+			MWindow window, boolean newWindow) {
+		return (WorkbenchWindow) createWorkbenchWindow(input, descriptor, window, newWindow);
+	}
+
+	@Override
+	public boolean restart() {
+		return close(PlatformUI.RETURN_RESTART, false);
+	}
+
+	@Override
+	public boolean restart(boolean useCurrrentWorkspace) {
+		if (useCurrrentWorkspace) {
+			URL instanceUrl = Platform.getInstanceLocation().getURL();
+			if (instanceUrl != null) {
+				try {
+					URI uri = instanceUrl.toURI();
+					String command_line = buildCommandLine(uri.toString());
+					if (command_line != null) {
+						System.setProperty(PROP_EXIT_CODE, IApplication.EXIT_RELAUNCH.toString());
+						System.setProperty(IApplicationContext.EXIT_DATA_PROPERTY, command_line);
+					}
+				} catch (URISyntaxException e) {
+					// do nothing; workbench will be restarted with the same
+					// command line as used for the previous launch
+				}
+			}
+		}
+		return close(PlatformUI.RETURN_RESTART, false);
+	}
+
+	/**
+	 * Create and return a string with command line options for eclipse.exe that
+	 * will launch a new workbench that is the same as the currently running
+	 * one, but using the argument directory as its workspace.
+	 * <p>
+	 * Note that this method has been copied from
+	 * OpenWorkspaceAction.buildCommandLine(String workspace)
+	 * </p>
+	 *
+	 * @param workspace
+	 *            the directory to use as the new workspace
+	 * @return a string of command line options or <code>null</code> if
+	 *         'eclipse.vm' is not set
+	 */
+	private String buildCommandLine(String workspace) {
+		String property = System.getProperty(PROP_VM);
+		if (property == null) {
+			if (!Platform.inDevelopmentMode()) {
+				// Don't log this when in development mode, since 'eclipse.vm'
+				// is never set in this case
+				WorkbenchPlugin.log(NLS.bind(WorkbenchMessages.get().Workbench_missingPropertyMessage, PROP_VM));
+			}
+			return null;
+		}
+
+		StringBuffer result = new StringBuffer(512);
+		result.append(property);
+		result.append('\n');
+
+		// append the vmargs and commands. Assume that these already end in \n
+		String vmargs = System.getProperty(PROP_VMARGS);
+		if (vmargs != null) {
+			result.append(vmargs);
+		}
+
+		// append the rest of the args, replacing or adding -data as required
+		property = System.getProperty(PROP_COMMANDS);
+		if (property == null) {
+			result.append(CMD_DATA);
+			result.append('\n');
+			result.append(workspace);
+			result.append('\n');
+		} else {
+			// find the index of the arg to add/replace its value
+			int cmd_data_pos = property.lastIndexOf(CMD_DATA);
+			if (cmd_data_pos != -1) {
+				cmd_data_pos += CMD_DATA.length() + 1;
+				result.append(property.substring(0, cmd_data_pos));
+				result.append(workspace);
+				// append from the next arg
+				int nextArg = property.indexOf("\n-", cmd_data_pos - 1); //$NON-NLS-1$
+				if (nextArg != -1) {
+					result.append(property.substring(nextArg));
+				}
+			} else {
+				result.append(CMD_DATA);
+				result.append('\n');
+				result.append(workspace);
+				result.append('\n');
+				result.append(property);
+			}
+		}
+
+		// put the vmargs back at the very end (the eclipse.commands property
+		// already contains the -vm arg)
+		if (vmargs != null) {
+			if (result.charAt(result.length() - 1) != '\n') {
+				result.append('\n');
+			}
+			result.append(CMD_VMARGS);
+			result.append('\n');
+			result.append(vmargs);
+		}
+
+		return result.toString();
+	}
+
+	/**
+	 * Returns the ids of all plug-ins that extend the
+	 * <code>org.eclipse.ui.startup</code> extension point.
+	 *
+	 * @return the ids of all plug-ins containing 1 or more startup extensions
+	 */
+	public ContributionInfo[] getEarlyActivatedPlugins() {
+        // RAP [bm]: namespace
+        IExtensionPoint point = Platform.getExtensionRegistry().getExtensionPoint(
+                PlatformUI.PLUGIN_EXTENSION_NAME_SPACE, IWorkbenchRegistryConstants.PL_STARTUP);
+        IExtension[] extensions = point.getExtensions();
+        ArrayList pluginIds = new ArrayList(extensions.length);
+        for (int i = 0; i < extensions.length; i++) {
+            String id = extensions[i].getNamespace();
+            if (!pluginIds.contains(id)) {
+                pluginIds.add(id);
+            }
+        }
+        ContributionInfo[] result = new ContributionInfo[pluginIds.size()];
+        for (int i = 0; i < result.length; i++) {
+// RAP [if]: need session aware messages
+//          result[i] = new ContributionInfo((String) pluginIds.get(i),
+//                  ContributionInfoMessages.ContributionInfo_EarlyStartupPlugin, null);
+            result[i] = new ContributionInfo((String) pluginIds.get(i),
+                    ContributionInfoMessages.ContributionInfo_EarlyStartupPlugin, null);
+
+        }
+        return result;
+    }
+
+	/**
+	 * Returns the ids of the early activated plug-ins that have been disabled
+	 * by the user.
+	 *
+	 * @return the ids of the early activated plug-ins that have been disabled
+	 *         by the user
+	 */
+	public String[] getDisabledEarlyActivatedPlugins() {
+		String pref = PrefUtil.getInternalPreferenceStore().getString(
+				IPreferenceConstants.PLUGINS_NOT_ACTIVATED_ON_STARTUP);
+		return pref.split(";"); //$NON-NLS-1$
+	}
+
+	/*
+	 * Starts all plugins that extend the <code> org.eclipse.ui.startup </code>
+	 * extension point, and that the user has not disabled via the preference
+	 * page.
+	 */
+	private void startPlugins() {
+		// bug 55901: don't use getConfigElements directly, for pre-3.0
+		// compat, make sure to allow both missing class
+		// attribute and a missing startup element
+		IExtensionPoint point = registry.getExtensionPoint(PlatformUI.PLUGIN_EXTENSION_NAME_SPACE,
+				IWorkbenchRegistryConstants.PL_STARTUP);
+
+		final IExtension[] extensions = point.getExtensions();
+		if (extensions.length == 0) {
+			return;
+		}
+        Job job = new Job("Workbench early startup") { //$NON-NLS-1$
+            @Override
+            protected IStatus run(IProgressMonitor monitor)
+            {
+                final IStatus[] result = { Status.OK_STATUS };
+                // RAP [rh] fake service context
+                RWT.getUISession(display).exec(new Runnable()
+                {
+                    public void run()
+                    {
+                        HashSet disabledPlugins = new HashSet(Arrays.asList(getDisabledEarlyActivatedPlugins()));
+                        monitor.beginTask(WorkbenchMessages.get().Workbench_startingPlugins, extensions.length);
+                        for (IExtension extension : extensions)
+                        {
+                            if (monitor.isCanceled() || !isRunning())
+                            {
+                                result[0] = Status.CANCEL_STATUS;
+                                return;
+                            }
+
+                            // if the plugin is not in the set of disabled
+                            // plugins, then
+                            // execute the code to start it
+                            if (!disabledPlugins.contains(extension.getNamespaceIdentifier()))
+                            {
+                                monitor.subTask(extension.getNamespaceIdentifier());
+                                SafeRunner.run(new EarlyStartupRunnable(extension));
+                            }
+                            monitor.worked(1);
+                        }
+                        monitor.done();
+                    }
+                });
+                return result[0];
+            }
+
+			@Override
+			public boolean belongsTo(Object family) {
+				return EARLY_STARTUP_FAMILY.equals(family);
+			}
+		};
+		job.setSystem(true);
+		job.schedule();
+	}
+
+	/**
+	 * Disable the Workbench Auto-Save job on startup during tests.
+	 *
+	 * @param b
+	 *            <code>false</code> to disable the tests.
+	 */
+	public void setEnableAutoSave(boolean b) {
+		workbenchAutoSave = b;
+	}
+
+	/**
+	 * Internal method for running the workbench UI. This entails processing and
+	 * dispatching events until the workbench is closed or restarted.
+	 *
+	 * @return return code {@link PlatformUI#RETURN_OK RETURN_OK}for normal
+	 *         exit; {@link PlatformUI#RETURN_RESTART RETURN_RESTART}if the
+	 *         workbench was terminated with a call to
+	 *         {@link IWorkbench#restart IWorkbench.restart};
+	 *         {@link PlatformUI#RETURN_UNSTARTABLE RETURN_UNSTARTABLE}if the
+	 *         workbench could not be started; other values reserved for future
+	 *         use
+	 * @since 3.0
+	 */
+	private int runUI() {
+		UIStats.start(UIStats.START_WORKBENCH, "Workbench"); //$NON-NLS-1$
+
+		// deadlock code
+		boolean avoidDeadlock = true;
+
+		String[] commandLineArgs = Platform.getCommandLineArgs();
+		for (String commandLineArg : commandLineArgs) {
+			if (commandLineArg.equalsIgnoreCase("-allowDeadlock")) { //$NON-NLS-1$
+				avoidDeadlock = false;
+			}
+		}
+
+		final UISynchronizer synchronizer;
+
+		if (avoidDeadlock) {
+			UILockListener uiLockListener = new UILockListener(display);
+			Job.getJobManager().setLockListener(uiLockListener);
+			synchronizer = new UISynchronizer(display, uiLockListener);
+			display.setSynchronizer(synchronizer);
+			// declare the main thread to be a startup thread.
+			UISynchronizer.startupThread.set(Boolean.TRUE);
+		} else
+			synchronizer = null;
+
+		// // prime the splash nice and early
+		// if (createSplash)
+		// createSplashWrapper();
+
+        // RAP [rh] workaround for bug #249630
+//      (IRunnableWithProgress in WorkbenchAdvisor does not show dialog)
+//     // ModalContext should not spin the event loop (there is no UI yet to
+//     // block)
+//     ModalContext.setAllowReadAndDispatch(false);
+
+		// if the -debug command line argument is used and the event loop is
+		// being
+		// run while starting the Workbench, log a warning.
+		if (WorkbenchPlugin.getDefault().isDebugging()) {
+			display.asyncExec(() -> {
+				if (isStarting()) {
+					WorkbenchPlugin.log(StatusUtil.newStatus(IStatus.WARNING,
+							"Event loop should not be run while the Workbench is starting.", //$NON-NLS-1$
+							new RuntimeException()));
+				}
+			});
+		}
+
+		// RAP [bm]: not used
+//		Listener closeListener = event -> event.doit = close();
+		// RAPEND: [bm]
+
+		// Initialize an exception handler.
+		Window.IExceptionHandler handler = ExceptionHandler.getInstance();
+
+		try {
+			// react to display close event by closing workbench nicely
+		 // RAP [bm]: Display#addListener
+//			display.addListener(SWT.Close, closeListener);
+
+			// install backstop to catch exceptions thrown out of event loop
+			Window.setExceptionHandler(handler);
+
+			final boolean[] initOK = new boolean[1];
+
+			// initialize workbench and restore or open one window
+			initOK[0] = init();
+
+			if (initOK[0] && runEventLoop) {
+				// Same registration as in E4Workbench
+				Hashtable<String, Object> properties = new Hashtable<>();
+				properties.put("id", getId()); //$NON-NLS-1$
+
+				workbenchService = WorkbenchPlugin.getDefault().getBundleContext()
+						.registerService(IWorkbench.class.getName(), this, properties);
+
+				e4WorkbenchService = WorkbenchPlugin.getDefault().getBundleContext()
+						.registerService(org.eclipse.e4.ui.workbench.IWorkbench.class.getName(),
+								this, properties);
+
+				Runnable earlyStartup = () -> {
+					// Let the advisor run its start-up code.
+					advisor.postStartup(); // May trigger a close/restart.
+					// start eager plug-ins
+					startPlugins();
+					addStartupRegistryListener();
+				};
+				e4Context.set(PartRenderingEngine.EARLY_STARTUP_HOOK, earlyStartup);
+				// start workspace auto-save
+				final int millisecondInterval = getAutoSaveJobTime();
+				if (millisecondInterval > 0 && workbenchAutoSave) {
+					autoSaveJob = new WorkbenchJob(WORKBENCH_AUTO_SAVE_JOB) {
+						@Override
+						public IStatus runInUIThread(IProgressMonitor monitor) {
+							if (monitor.isCanceled()) {
+								return Status.CANCEL_STATUS;
+							}
+							final int nextDelay = getAutoSaveJobTime();
+							try {
+								if (applicationModelChanged) {
+									persist(false);
+									applicationModelChanged = false;
+
+								}
+								monitor.done();
+							} finally {
+								// repeat
+								if (nextDelay > 0 && workbenchAutoSave) {
+									this.schedule(nextDelay);
+								}
+							}
+							return Status.OK_STATUS;
+						}
+
+					};
+					autoSaveJob.setSystem(true);
+					autoSaveJob.schedule(millisecondInterval);
+				}
+
+				display.asyncExec(new Runnable() {
+					@Override
+					public void run() {
+						UIStats.end(UIStats.START_WORKBENCH, this, "Workbench"); //$NON-NLS-1$
+						UIStats.startupComplete();
+					}
+				});
+
+				getWorkbenchTestable().init(display, this);
+
+				// allow ModalContext to spin the event loop
+				ModalContext.setAllowReadAndDispatch(true);
+				isStarting = false;
+
+				if (synchronizer != null)
+					synchronizer.started();
+				// the event loop
+				// runEventLoop(handler, display);
+			}
+			returnCode = PlatformUI.RETURN_OK;
+			if (!initOK[0]) {
+				returnCode = PlatformUI.RETURN_UNSTARTABLE;
+			}
+		} catch (final Exception e) {
+			if (!display.isDisposed()) {
+				handler.handleException(e);
+			} else {
+				String msg = "Exception in Workbench.runUI after display was disposed"; //$NON-NLS-1$
+				WorkbenchPlugin.log(msg, new Status(IStatus.ERROR, WorkbenchPlugin.PI_WORKBENCH, 1,
+						msg, e));
+			}
+		}
+
+		// restart or exit based on returnCode
+		return returnCode;
+	}
+
+	private int getAutoSaveJobTime() {
+		final int minuteSaveInterval = getPreferenceStore().getInt(IPreferenceConstants.WORKBENCH_SAVE_INTERVAL);
+		final int millisecondInterval = minuteSaveInterval * 60 * 1000;
+		return millisecondInterval;
+	}
+
+
+
+	@Override
+	public IWorkbenchPage showPerspective(String perspectiveId, IWorkbenchWindow window)
+			throws WorkbenchException {
+		return showPerspective(perspectiveId, window, advisor.getDefaultPageInput());
+	}
+
+	private boolean activate(String perspectiveId, IWorkbenchPage page, IAdaptable input) {
+		if (page != null) {
+			for (IPerspectiveDescriptor openedPerspective : page.getOpenPerspectives()) {
+				if (openedPerspective.getId().equals(perspectiveId)) {
+					if (page.getInput() == input) {
+						WorkbenchWindow wwindow = (WorkbenchWindow) page.getWorkbenchWindow();
+						MWindow model = wwindow.getModel();
+						application.setSelectedElement(model);
+						page.setPerspective(openedPerspective);
+						return true;
+					}
+				}
+			}
+		}
+		return false;
+	}
+
+	@Override
+	public IWorkbenchPage showPerspective(String perspectiveId, IWorkbenchWindow targetWindow,
+			IAdaptable input) throws WorkbenchException {
+		Assert.isNotNull(perspectiveId);
+		IPerspectiveDescriptor targetPerspective = getPerspectiveRegistry().findPerspectiveWithId(
+				perspectiveId);
+		if (targetPerspective == null) {
+			throw new WorkbenchException(NLS.bind(
+					WorkbenchMessages.get().WorkbenchPage_ErrorCreatingPerspective, perspectiveId));
+		}
+
+		if (targetWindow != null) {
+			IWorkbenchPage page = targetWindow.getActivePage();
+			if (activate(perspectiveId, page, input)) {
+				return page;
+			}
+		}
+
+		for (IWorkbenchWindow window : getWorkbenchWindows()) {
+			IWorkbenchPage page = window.getActivePage();
+			if (activate(perspectiveId, page, input)) {
+				return page;
+			}
+		}
+
+		if (targetWindow != null) {
+			IWorkbenchPage page = targetWindow.getActivePage();
+			IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore();
+			int mode = store.getInt(IPreferenceConstants.OPEN_PERSP_MODE);
+
+			if (IPreferenceConstants.OPM_NEW_WINDOW != mode) {
+				targetWindow.getShell().open();
+				if (page == null) {
+					page = targetWindow.openPage(perspectiveId, input);
+				} else {
+					page.setPerspective(targetPerspective);
+				}
+				return page;
+			}
+		}
+
+		return openWorkbenchWindow(perspectiveId, input).getActivePage();
+	}
+
+	/*
+	 * Shuts down the application.
+	 */
+	private void shutdown() {
+		// shutdown application-specific portions first
+		try {
+			advisor.postShutdown();
+		} catch (Exception ex) {
+			StatusManager.getManager().handle(
+					StatusUtil.newStatus(WorkbenchPlugin.PI_WORKBENCH,
+							"Exceptions during shutdown", ex)); //$NON-NLS-1$
+		}
+
+		// notify regular workbench clients of shutdown, and clear the list when
+		// done
+		firePostShutdown();
+		workbenchListeners.clear();
+
+		cancelEarlyStartup();
+		if (workbenchService != null)
+			workbenchService.unregister();
+		workbenchService = null;
+
+		if (e4WorkbenchService != null)
+			e4WorkbenchService.unregister();
+		e4WorkbenchService = null;
+
+		// for dynamic UI
+		registry.removeRegistryChangeListener(extensionEventHandler);
+		registry.removeRegistryChangeListener(startupRegistryListener);
+
+		((GrabFocus) Tweaklets.get(GrabFocus.KEY)).dispose();
+
+		// Bring down all of the services.
+		serviceLocator.dispose();
+		application.getCommands().removeAll(commandsToRemove);
+		application.getCategories().removeAll(categoriesToRemove);
+		getDisplay().removeFilter(SWT.MouseDown, backForwardListener);
+		backForwardListener = null;
+
+		workbenchActivitySupport.dispose();
+		WorkbenchHelpSystem.disposeIfNecessary();
+
+		// shutdown the rest of the workbench
+		WorkbenchColors.shutdown();
+		activityHelper.shutdown();
+		uninitializeImages();
+		if (WorkbenchPlugin.getDefault() != null) {
+			WorkbenchPlugin.getDefault().reset();
+		}
+		WorkbenchThemeManager.getInstance().dispose();
+		PropertyPageContributorManager.getManager().dispose();
+		ObjectActionContributorManager.getManager().dispose();
+		if (tracker != null) {
+			tracker.close();
+		}
+	}
+
+	/**
+	 * Cancels the early startup job, if it's still running.
+	 */
+	private void cancelEarlyStartup() {
+		Job.getJobManager().cancel(EARLY_STARTUP_FAMILY);
+		// We do not currently wait for any plug-in currently being started to
+		// complete
+		// (e.g. by doing a join on EARLY_STARTUP_FAMILY), since they may do a
+		// syncExec,
+		// which would hang. See bug 94537 for rationale.
+	}
+
+	@Override
+	public IDecoratorManager getDecoratorManager() {
+		return WorkbenchPlugin.getDefault().getDecoratorManager();
+	}
+
+	/**
+	 * Returns the unique object that applications use to configure the
+	 * workbench.
+	 * <p>
+	 * IMPORTANT This method is declared package-private to prevent regular
+	 * plug-ins from downcasting IWorkbench to Workbench and getting hold of the
+	 * workbench configurer that would allow them to tamper with the workbench.
+	 * The workbench configurer is available only to the application.
+	 * </p>
+	 */
+	/* package */
+	WorkbenchConfigurer getWorkbenchConfigurer() {
+		if (workbenchConfigurer == null) {
+			workbenchConfigurer = new WorkbenchConfigurer();
+		}
+		return workbenchConfigurer;
+	}
+
+	/**
+	 * Returns the workbench advisor that created this workbench.
+	 * <p>
+	 * IMPORTANT This method is declared package-private to prevent regular
+	 * plug-ins from downcasting IWorkbench to Workbench and getting hold of the
+	 * workbench advisor that would allow them to tamper with the workbench. The
+	 * workbench advisor is internal to the application.
+	 * </p>
+	 */
+	/* package */
+	WorkbenchAdvisor getAdvisor() {
+		return advisor;
+	}
+
+	@Override
+	public Display getDisplay() {
+		return display;
+	}
+
+	/**
+	 * Returns the default perspective id, which may be <code>null</code>.
+	 *
+	 * @return the default perspective id, or <code>null</code>
+	 */
+	public String getDefaultPerspectiveId() {
+		return getAdvisor().getInitialWindowPerspectiveId();
+	}
+
+	/**
+	 * Returns the default workbench window page input.
+	 *
+	 * @return the default window page input or <code>null</code> if none
+	 */
+	public IAdaptable getDefaultPageInput() {
+		return getAdvisor().getDefaultPageInput();
+	}
+
+	/**
+	 * Returns the id of the preference page that should be presented most
+	 * prominently.
+	 *
+	 * @return the id of the preference page, or <code>null</code> if none
+	 */
+	public String getMainPreferencePageId() {
+		String id = getAdvisor().getMainPreferencePageId();
+		return id;
+	}
+
+	@Override
+	public IElementFactory getElementFactory(String factoryId) {
+		Assert.isNotNull(factoryId);
+		return WorkbenchPlugin.getDefault().getElementFactory(factoryId);
+	}
+
+	@Override
+	public IProgressService getProgressService() {
+		return e4Context.get(IProgressService.class);
+	}
+
+	private WorkbenchActivitySupport workbenchActivitySupport;
+
+	private WorkbenchCommandSupport workbenchCommandSupport;
+
+	private WorkbenchContextSupport workbenchContextSupport;
+
+	/**
+	 * The single instance of the binding manager used by the workbench. This is
+	 * initialized in <code>Workbench.init(Display)</code> and then never
+	 * changed. This value will only be <code>null</code> if the initialization
+	 * call has not yet completed.
+	 *
+	 * @since 3.1
+	 */
+	private BindingManager bindingManager;
+
+	/**
+	 * The single instance of the command manager used by the workbench. This is
+	 * initialized in <code>Workbench.init(Display)</code> and then never
+	 * changed. This value will only be <code>null</code> if the initialization
+	 * call has not yet completed.
+	 *
+	 * @since 3.1
+	 */
+	private CommandManager commandManager;
+
+	/**
+	 * The single instance of the context manager used by the workbench. This is
+	 * initialized in <code>Workbench.init(Display)</code> and then never
+	 * changed. This value will only be <code>null</code> if the initialization
+	 * call has not yet completed.
+	 *
+	 * @since 3.1
+	 */
+	private ContextManager contextManager;
+
+	@Override
+	public IWorkbenchActivitySupport getActivitySupport() {
+		return e4Context.get(IWorkbenchActivitySupport.class);
+	}
+
+	@Override
+	public IWorkbenchCommandSupport getCommandSupport() {
+		return workbenchCommandSupport;
+	}
+
+	@Override
+	public IWorkbenchContextSupport getContextSupport() {
+		return workbenchContextSupport;
+	}
+
+	private final IBindingManagerListener bindingManagerListener = bindingManagerEvent -> {
+		if (bindingManagerEvent.isActiveBindingsChanged()) {
+			updateActiveWorkbenchWindowMenuManager(true);
+		}
+	};
+
+	private void updateActiveWorkbenchWindowMenuManager(boolean textOnly) {
+
+		final IWorkbenchWindow workbenchWindow = getActiveWorkbenchWindow();
+
+		if (workbenchWindow instanceof WorkbenchWindow) {
+			WorkbenchWindow activeWorkbenchWindow = (WorkbenchWindow) workbenchWindow;
+			if (activeWorkbenchWindow.isClosing()) {
+				return;
+			}
+
+			// Update the action sets.
+			final MenuManager menuManager = activeWorkbenchWindow.getMenuManager();
+
+			if (textOnly) {
+				menuManager.update(IAction.TEXT);
+			} else {
+				menuManager.update(true);
+			}
+		}
+	}
+
+	private ActivityPersistanceHelper activityHelper;
+
+	@Override
+	public IIntroManager getIntroManager() {
+		return getWorkbenchIntroManager();
+	}
+
+	/**
+	 * @return the workbench intro manager
+	 * @since 3.0
+	 */
+	/* package */WorkbenchIntroManager getWorkbenchIntroManager() {
+		if (introManager == null) {
+			introManager = new WorkbenchIntroManager(this);
+		}
+		return introManager;
+	}
+
+	private WorkbenchIntroManager introManager;
+
+	/**
+	 * @return the intro extension for this workbench.
+	 *
+	 * @since 3.0
+	 */
+	public IntroDescriptor getIntroDescriptor() {
+		return introDescriptor;
+	}
+
+	/**
+	 * This method exists as a test hook. This method should
+	 * <strong>NEVER</strong> be called by clients.
+	 *
+	 * @param descriptor
+	 *            The intro descriptor to use.
+	 * @since 3.0
+	 */
+	public void setIntroDescriptor(IntroDescriptor descriptor) {
+		if (getIntroManager().getIntro() != null) {
+			getIntroManager().closeIntro(getIntroManager().getIntro());
+		}
+		introDescriptor = descriptor;
+	}
+
+	/**
+	 * The descriptor for the intro extension that is valid for this workspace,
+	 * <code>null</code> if none.
+	 */
+	private IntroDescriptor introDescriptor;
+
+	private IExtensionTracker tracker;
+
+	private IRegistryChangeListener startupRegistryListener = event -> {
+		final IExtensionDelta[] deltas = event.getExtensionDeltas(PlatformUI.PLUGIN_EXTENSION_NAME_SPACE,
+				IWorkbenchRegistryConstants.PL_STARTUP);
+		if (deltas.length == 0) {
+			return;
+		}
+		final String disabledPlugins = PrefUtil.getInternalPreferenceStore().getString(
+				IPreferenceConstants.PLUGINS_NOT_ACTIVATED_ON_STARTUP);
+
+		for (IExtensionDelta delta : deltas) {
+			IExtension extension = delta.getExtension();
+			if (delta.getKind() == IExtensionDelta.REMOVED) {
+				continue;
+			}
+
+			// if the plugin is not in the set of disabled plugins,
+			// then
+			// execute the code to start it
+			if (disabledPlugins.indexOf(extension.getNamespaceIdentifier()) == -1) {
+				SafeRunner.run(new EarlyStartupRunnable(extension));
+			}
+		}
+
+	};
+
+	@Override
+	public IThemeManager getThemeManager() {
+		return WorkbenchThemeManager.getInstance();
+	}
+
+	/**
+	 * Returns <code>true</code> if the workbench is running, <code>false</code>
+	 * if it has been terminated.
+	 *
+	 * @return <code>true</code> if the workbench is running, <code>false</code>
+	 *         if it has been terminated.
+	 */
+	public boolean isRunning() {
+		return runEventLoop;
+	}
+
+	/**
+	 * <p>
+	 * Indicates the start of a large update within the workbench. This is used
+	 * to disable CPU-intensive, change-sensitive services that were temporarily
+	 * disabled in the midst of large changes. This method should always be
+	 * called in tandem with <code>largeUpdateEnd</code>, and the event loop
+	 * should not be allowed to spin before that method is called.
+	 * </p>
+	 * <p>
+	 * Important: always use with <code>largeUpdateEnd</code>!
+	 * </p>
+	 */
+	public final void largeUpdateStart() {
+		if (largeUpdates++ == 0) {
+			final IWorkbenchWindow[] windows = getWorkbenchWindows();
+			for (IWorkbenchWindow window : windows) {
+				if (window instanceof WorkbenchWindow) {
+					((WorkbenchWindow) window).largeUpdateStart();
+				}
+			}
+		}
+	}
+
+	/**
+	 * <p>
+	 * Indicates the end of a large update within the workbench. This is used to
+	 * re-enable services that were temporarily disabled in the midst of large
+	 * changes. This method should always be called in tandem with
+	 * <code>largeUpdateStart</code>, and the event loop should not be allowed
+	 * to spin before this method is called.
+	 * </p>
+	 * <p>
+	 * Important: always protect this call by using <code>finally</code>!
+	 * </p>
+	 */
+	public final void largeUpdateEnd() {
+		if (--largeUpdates == 0) {
+
+			// Perform window-specific blocking.
+			final IWorkbenchWindow[] windows = getWorkbenchWindows();
+			for (IWorkbenchWindow window : windows) {
+				if (window instanceof WorkbenchWindow) {
+					((WorkbenchWindow) window).largeUpdateEnd();
+				}
+			}
+		}
+	}
+
+	@Override
+	public IExtensionTracker getExtensionTracker() {
+		return e4Context.get(IExtensionTracker.class);
+	}
+
+	/**
+	 * Adds the listener that handles startup plugins
+	 *
+	 * @since 3.1
+	 */
+	private void addStartupRegistryListener() {
+		registry.addRegistryChangeListener(startupRegistryListener);
+	}
+
+	@Override
+	public IWorkbenchHelpSystem getHelpSystem() {
+		return WorkbenchHelpSystem.getInstance();
+	}
+
+	@Override
+	public IWorkbenchBrowserSupport getBrowserSupport() {
+		return WorkbenchBrowserSupport.getInstance();
+	}
+
+	@Override
+	public IViewRegistry getViewRegistry() {
+		return WorkbenchPlugin.getDefault().getViewRegistry();
+	}
+
+	@Override
+	public IWizardRegistry getNewWizardRegistry() {
+		return WorkbenchPlugin.getDefault().getNewWizardRegistry();
+	}
+
+	@Override
+	public IWizardRegistry getImportWizardRegistry() {
+		return WorkbenchPlugin.getDefault().getImportWizardRegistry();
+	}
+
+	@Override
+	public IWizardRegistry getExportWizardRegistry() {
+		return WorkbenchPlugin.getDefault().getExportWizardRegistry();
+	}
+
+	@Override
+	public final <T> T getAdapter(final Class<T> key) {
+		return key.cast(serviceLocator.getService(key));
+	}
+
+
+	@Override
+	public final <T> T getService(final Class<T> key) {
+		return serviceLocator.getService(key);
+	}
+
+	@Override
+	public final boolean hasService(final Class<?> key) {
+		return serviceLocator.hasService(key);
+	}
+
+	/**
+	 * Registers a service with this locator. If there is an existing service
+	 * matching the same <code>api</code> and it implements {@link IDisposable},
+	 * it will be disposed.
+	 *
+	 * @param api
+	 *            This is the interface that the service implements. Must not be
+	 *            <code>null</code>.
+	 * @param service
+	 *            The service to register. This must be some implementation of
+	 *            <code>api</code>. This value must not be <code>null</code>.
+	 */
+	public final void registerService(final Class api, final Object service) {
+		serviceLocator.registerService(api, service);
+	}
+
+	/**
+	 * The source provider that tracks which context menus (i.e., menus with
+	 * target identifiers) are now showing. This value is <code>null</code>
+	 * until {@link #initializeDefaultServices()} is called.
+	 */
+	private MenuSourceProvider menuSourceProvider;
+
+	/**
+	 * Adds the ids of a menu that is now showing to the menu source provider.
+	 * This is used for legacy action-based handlers which need to become active
+	 * only for the duration of a menu being visible.
+	 *
+	 * @param menuIds
+	 *            The identifiers of the menu that is now showing; must not be
+	 *            <code>null</code>.
+	 * @param localSelection
+	 * @param localEditorInput
+	 */
+	public final void addShowingMenus(final Set menuIds, final ISelection localSelection,
+			final ISelection localEditorInput) {
+		menuSourceProvider.addShowingMenus(menuIds, localSelection, localEditorInput);
+		Map currentState = menuSourceProvider.getCurrentState();
+		for (String key : menuSourceProvider.getProvidedSourceNames()) {
+			e4Context.set(key, currentState.get(key));
+		}
+	}
+
+	/**
+	 * Removes the ids of a menu that is now hidden from the menu source
+	 * provider. This is used for legacy action-based handlers which need to
+	 * become active only for the duration of a menu being visible.
+	 *
+	 * @param menuIds
+	 *            The identifiers of the menu that is now hidden; must not be
+	 *            <code>null</code>.
+	 * @param localSelection
+	 * @param localEditorInput
+	 */
+	public final void removeShowingMenus(final Set menuIds, final ISelection localSelection,
+			final ISelection localEditorInput) {
+		menuSourceProvider.removeShowingMenus(menuIds, localSelection, localEditorInput);
+		for (String key : menuSourceProvider.getProvidedSourceNames()) {
+			e4Context.remove(key);
+		}
+	}
+
+	@Override
+	public boolean saveAll(final IShellProvider shellProvider,
+			final IRunnableContext runnableContext, final ISaveableFilter filter, boolean confirm) {
+		SaveablesList saveablesList = (SaveablesList) getService(ISaveablesLifecycleListener.class);
+		Saveable[] saveables = saveablesList.getOpenModels();
+		List<Saveable> toSave = getFilteredSaveables(filter, saveables);
+		if (toSave.isEmpty()) {
+			return true;
+		}
+
+		if (!confirm) {
+			return !saveablesList.saveModels(toSave, shellProvider, runnableContext);
+		}
+
+		// We must negate the result since false is cancel saveAll
+		return !saveablesList.promptForSaving(toSave, shellProvider, runnableContext, true, false);
+	}
+
+	/*
+	 * Apply the given filter to the list of saveables
+	 */
+	private List<Saveable> getFilteredSaveables(ISaveableFilter filter, Saveable[] saveables) {
+		List<Saveable> toSave = new ArrayList<>();
+		if (filter == null) {
+			for (Saveable saveable : saveables) {
+				if (saveable.isDirty()) {
+					toSave.add(saveable);
+				}
+			}
+		} else {
+			SaveablesList saveablesList = (SaveablesList) getService(ISaveablesLifecycleListener.class);
+			for (Saveable saveable : saveables) {
+				if (saveable.isDirty()) {
+					IWorkbenchPart[] parts = saveablesList.getPartsForSaveable(saveable);
+					if (matchesFilter(filter, saveable, parts)) {
+						toSave.add(saveable);
+					}
+				}
+			}
+		}
+		return toSave;
+	}
+
+	/*
+	 * Test whether the given filter matches the saveable
+	 */
+	private boolean matchesFilter(ISaveableFilter filter, Saveable saveable, IWorkbenchPart[] parts) {
+		return filter == null || filter.select(saveable, parts);
+	}
+
+	@Override
+	public IShellProvider getModalDialogShellProvider() {
+		return () -> ProgressManagerUtil.getDefaultParent();
+	}
+
+	public IEclipseContext getContext() {
+		return e4Context;
+	}
+
+	@Override
+	public MApplication getApplication() {
+		return application;
+	}
+
+	/*
+	 * Record the workbench UI in a document
+	 */
+	private void persistWorkbenchState() {
+		try {
+			XMLMemento memento = XMLMemento.createWriteRoot(IWorkbenchConstants.TAG_WORKBENCH);
+			IStatus status = saveWorkbenchState(memento);
+
+			if (status.getSeverity() == IStatus.OK) {
+				StringWriter writer = new StringWriter();
+				memento.save(writer);
+				application.getPersistedState().put(MEMENTO_KEY, writer.toString());
+			} else {
+				WorkbenchPlugin.log(new Status(status.getSeverity(), PlatformUI.PLUGIN_ID,
+						WorkbenchMessages.get().Workbench_problemsSavingMsg));
+			}
+		} catch (IOException e) {
+			WorkbenchPlugin.log(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0,
+					WorkbenchMessages.get().Workbench_problemsSavingMsg, e));
+		}
+	}
+
+	/*
+	 * Saves the current state of the workbench so it can be restored later on
+	 */
+	private IStatus saveWorkbenchState(IMemento memento) {
+		MultiStatus result = new MultiStatus(PlatformUI.PLUGIN_ID, IStatus.OK,
+				WorkbenchMessages.get().Workbench_problemsSaving, null);
+
+		// TODO: Currently we store the editors history only. Add more if needed
+
+		result.add(getEditorHistory().saveState(
+				memento.createChild(IWorkbenchConstants.TAG_MRU_LIST)));
+		return result;
+	}
+
+	private void restoreWorkbenchState() {
+		try {
+			String persistedState = application.getPersistedState().get(MEMENTO_KEY);
+			if (persistedState != null) {
+				XMLMemento memento = XMLMemento.createReadRoot(new StringReader(persistedState));
+				IStatus status = readWorkbenchState(memento);
+
+				if (status.getSeverity() != IStatus.OK) {
+					WorkbenchPlugin.log(new Status(status.getSeverity(), PlatformUI.PLUGIN_ID,
+							WorkbenchMessages.get().Workbench_problemsRestoring));
+				}
+			}
+		} catch (Exception e) {
+			WorkbenchPlugin.log(new Status(
+					IStatus.ERROR, PlatformUI.PLUGIN_ID, 0,
+					WorkbenchMessages.get().Workbench_problemsRestoring, e));
+		}
+	}
+
+	private IStatus readWorkbenchState(IMemento memento) {
+		MultiStatus result = new MultiStatus(PlatformUI.PLUGIN_ID, IStatus.OK,
+				WorkbenchMessages.get().Workbench_problemsRestoring, null);
+
+		try {
+			UIStats.start(UIStats.RESTORE_WORKBENCH, "MRUList"); //$NON-NLS-1$
+			IMemento mruMemento = memento.getChild(IWorkbenchConstants.TAG_MRU_LIST);
+			if (mruMemento != null) {
+				result.add(getEditorHistory().restoreState(mruMemento));
+			}
+		} finally {
+			UIStats.end(UIStats.RESTORE_WORKBENCH, this, "MRUList"); //$NON-NLS-1$
+		}
+		return result;
+	}
+
+	@Override
+	public final String getId() {
+		return id;
+	}
+
+	protected String createId() {
+		return UUID.randomUUID().toString();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchColors.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchColors.java
new file mode 100644
index 0000000..bda355d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchColors.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * This class manages the common workbench colors.
+ */
+public class WorkbenchColors {
+//    static private boolean init = false;
+//
+//    static private Color[] workbenchColors;
+//
+//    /**
+//     * Dispose all color pre-allocated by the workbench.
+//     */
+//    private static void disposeWorkbenchColors() {
+//        for (Color workbenchColor : workbenchColors) {
+//            workbenchColor.dispose();
+//        }
+//        workbenchColors = null;
+//    }
+//
+//    /**
+//     * Initialize all colors used in the workbench in case the OS is using
+//     * a 256 color palette making sure the workbench colors are allocated.
+//     *
+//     * This list comes from the designers.
+//     */
+//    private static void initWorkbenchColors(Display d) {
+//        if (workbenchColors != null) {
+//			return;
+//		}
+//
+//        workbenchColors = new Color[] {
+//        //Product pallet
+//                new Color(d, 255, 255, 255), new Color(d, 255, 251, 240),
+//                new Color(d, 223, 223, 191), new Color(d, 223, 191, 191),
+//                new Color(d, 192, 220, 192), new Color(d, 192, 192, 192),
+//                new Color(d, 191, 191, 191), new Color(d, 191, 191, 159),
+//                new Color(d, 191, 159, 191), new Color(d, 160, 160, 164),
+//                new Color(d, 159, 159, 191), new Color(d, 159, 159, 159),
+//                new Color(d, 159, 159, 127), new Color(d, 159, 127, 159),
+//                new Color(d, 159, 127, 127), new Color(d, 128, 128, 128),
+//                new Color(d, 127, 159, 159), new Color(d, 127, 159, 127),
+//                new Color(d, 127, 127, 159), new Color(d, 127, 127, 127),
+//                new Color(d, 127, 127, 95), new Color(d, 127, 95, 127),
+//                new Color(d, 127, 95, 95), new Color(d, 95, 127, 127),
+//                new Color(d, 95, 127, 95), new Color(d, 95, 95, 127),
+//                new Color(d, 95, 95, 95), new Color(d, 95, 95, 63),
+//                new Color(d, 95, 63, 95), new Color(d, 95, 63, 63),
+//                new Color(d, 63, 95, 95), new Color(d, 63, 95, 63),
+//                new Color(d, 63, 63, 95), new Color(d, 0, 0, 0),
+//                //wizban pallet
+//                new Color(d, 195, 204, 224), new Color(d, 214, 221, 235),
+//                new Color(d, 149, 168, 199), new Color(d, 128, 148, 178),
+//                new Color(d, 106, 128, 158), new Color(d, 255, 255, 255),
+//                new Color(d, 0, 0, 0), new Color(d, 0, 0, 0),
+//                //Perspective
+//                new Color(d, 132, 130, 132), new Color(d, 143, 141, 138),
+//                new Color(d, 171, 168, 165),
+//                //PreferenceDialog and TitleAreaDialog
+//                new Color(d, 230, 226, 221) };
+//    }
+
+    /**
+     * Disposes of the colors. Ignore all
+     * system colors as they do not need
+     * to be disposed.
+     */
+    static public void shutdown() {
+//        if (!init) {
+//			return;
+//		}
+//        disposeWorkbenchColors();
+//        init = false;
+    }
+
+    /**
+     * Initializes the colors.
+     */
+    static public void startup() {
+//        if (init) {
+//			return;
+//		}
+//
+//        // Initialize the caches first.
+//        init = true;
+//
+//        Display display = Display.getDefault();
+//        initWorkbenchColors(display);
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchConfigurer.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchConfigurer.java
new file mode 100644
index 0000000..4ec8647
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchConfigurer.java
@@ -0,0 +1,183 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.internal;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.window.WindowManager;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.WorkbenchException;
+import org.eclipse.ui.application.IWorkbenchConfigurer;
+import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
+import org.eclipse.ui.application.WorkbenchAdvisor;
+
+/**
+ * Internal class providing special access for configuring the workbench.
+ * <p>
+ * Note that these objects are only available to the main application
+ * (the plug-in that creates and owns the workbench).
+ * </p>
+ * <p>
+ * This class is not intended to be instantiated or subclassed by clients.
+ * </p>
+ *
+ * @since 3.0
+ */
+public final class WorkbenchConfigurer implements IWorkbenchConfigurer {
+
+    /**
+     * Table to hold arbitrary key-data settings (key type: <code>String</code>,
+     * value type: <code>Object</code>).
+     * @see #setData
+     */
+    private Map extraData = new HashMap();
+
+    /**
+     * Indicates whether workbench state should be saved on close and
+     * restored on subsequent open.
+     */
+    private boolean saveAndRestore = false;
+
+    /**
+     * Indicates whether the workbench is being force to close. During
+     * an emergency close, no interaction with the user should be done.
+     */
+    private boolean isEmergencyClosing = false;
+
+    /**
+     * Indicates the behaviour when the last window is closed.
+     * If <code>true</code>, the workbench will exit (saving the last window's state,
+     * if configured to do so).
+     * If <code>false</code> the window will be closed, leaving the workbench running.
+     *
+     * @since 3.1
+     */
+	private boolean exitOnLastWindowClose = true;
+
+    /**
+     * Creates a new workbench configurer.
+     * <p>
+     * This method is declared package-private. Clients are passed an instance
+     * only via {@link WorkbenchAdvisor#initialize WorkbenchAdvisor.initialize}
+     * </p>
+     */
+    /* package */WorkbenchConfigurer() {
+        super();
+    }
+
+    @Override
+	public IWorkbench getWorkbench() {
+        return PlatformUI.getWorkbench();
+    }
+
+    @Override
+	public WindowManager getWorkbenchWindowManager() {
+        // return the global workbench window manager
+		return null;
+    }
+
+    @Override
+	public void declareImage(String symbolicName, ImageDescriptor descriptor,
+            boolean shared) {
+        if (symbolicName == null || descriptor == null) {
+            throw new IllegalArgumentException();
+        }
+        WorkbenchImages.declareImage(symbolicName, descriptor, shared);
+    }
+
+    @Override
+	public IWorkbenchWindowConfigurer getWindowConfigurer(
+            IWorkbenchWindow window) {
+        if (window == null) {
+            throw new IllegalArgumentException();
+        }
+        return ((WorkbenchWindow) window).getWindowConfigurer();
+    }
+
+    @Override
+	public boolean getSaveAndRestore() {
+        return saveAndRestore;
+    }
+
+    @Override
+	public void setSaveAndRestore(boolean enabled) {
+        saveAndRestore = enabled;
+    }
+
+    @Override
+	public Object getData(String key) {
+        if (key == null) {
+            throw new IllegalArgumentException();
+        }
+        return extraData.get(key);
+    }
+
+    @Override
+	public void setData(String key, Object data) {
+        if (key == null) {
+            throw new IllegalArgumentException();
+        }
+        if (data != null) {
+            extraData.put(key, data);
+        } else {
+            extraData.remove(key);
+        }
+    }
+
+    @Override
+	public void emergencyClose() {
+        if (!isEmergencyClosing) {
+            isEmergencyClosing = true;
+            if (Workbench.getInstance() != null
+                    && !Workbench.getInstance().isClosing()) {
+                Workbench.getInstance().close(
+                        PlatformUI.RETURN_EMERGENCY_CLOSE, true);
+            }
+        }
+
+    }
+
+    @Override
+	public boolean emergencyClosing() {
+        return isEmergencyClosing;
+    }
+
+    @Override
+	public IStatus restoreState() {
+		return Status.OK_STATUS;
+    }
+
+    @Override
+	public void openFirstTimeWindow() {
+        ((Workbench) getWorkbench()).openFirstTimeWindow();
+    }
+
+	@Override
+	public IWorkbenchWindowConfigurer restoreWorkbenchWindow(IMemento memento) throws WorkbenchException {
+		return getWindowConfigurer(null);
+	}
+
+	@Override
+	public boolean getExitOnLastWindowClose() {
+		return exitOnLastWindowClose;
+	}
+
+	@Override
+	public void setExitOnLastWindowClose(boolean enabled) {
+		exitOnLastWindowClose = enabled;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchEditorsHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchEditorsHandler.java
new file mode 100644
index 0000000..3a9da63
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchEditorsHandler.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.eclipse.ui.internal.dialogs.WorkbenchEditorsDialog;
+
+/**
+ * Opens a dialog showing all open editors and the recently closed editors.
+ *
+ * @since 3.4
+ *
+ */
+public class WorkbenchEditorsHandler extends AbstractHandler {
+
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		IWorkbenchWindow workbenchWindow = HandlerUtil
+				.getActiveWorkbenchWindow(event);
+		if (workbenchWindow == null) {
+			// action has been disposed
+			return null;
+		}
+		IWorkbenchPage page = workbenchWindow.getActivePage();
+		if (page != null) {
+			new WorkbenchEditorsDialog(workbenchWindow).open();
+		}
+		return null;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchErrorHandlerProxy.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchErrorHandlerProxy.java
new file mode 100644
index 0000000..7b879c5
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchErrorHandlerProxy.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal;
+
+import org.eclipse.ui.statushandlers.AbstractStatusHandler;
+import org.eclipse.ui.statushandlers.StatusAdapter;
+
+/**
+ * A proxy handler which passes all statuses to handler assigned to current
+ * application workbench advisor.
+ *
+ * <strong>EXPERIMENTAL</strong> This class or interface has been added as part
+ * of a work in progress. This API may change at any given time. Please do not
+ * use this API without consulting with the Platform/UI team.
+ *
+ * @since 3.3
+ */
+public class WorkbenchErrorHandlerProxy extends AbstractStatusHandler {
+
+	@Override
+	public void handle(final StatusAdapter statusAdapter, int style) {
+		Workbench.getInstance().getAdvisor().getWorkbenchErrorHandler().handle(
+				statusAdapter, style);
+	}
+
+	@Override
+	public boolean supportsNotification(int type) {
+		return Workbench.getInstance().getAdvisor().getWorkbenchErrorHandler()
+				.supportsNotification(type);
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchHandlerServiceHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchHandlerServiceHandler.java
new file mode 100644
index 0000000..ca940f9
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchHandlerServiceHandler.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2013, 2014 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.ui.internal;
+
+import java.util.Map;
+import org.eclipse.e4.core.commands.internal.HandlerServiceHandler;
+import org.eclipse.e4.core.commands.internal.HandlerServiceImpl;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.ui.commands.IElementUpdater;
+import org.eclipse.ui.menus.UIElement;
+
+/**
+ * @since 3.5
+ *
+ */
+public class WorkbenchHandlerServiceHandler extends HandlerServiceHandler implements
+		IElementUpdater {
+
+	/**
+	 * @param commandId
+	 */
+	public WorkbenchHandlerServiceHandler(String commandId, IEclipseContext context) {
+		super(commandId, context);
+	}
+
+	@Override
+	public void updateElement(UIElement element, Map parameters) {
+		final IEclipseContext executionContext = getExecutionContext(null);
+		if (executionContext == null) {
+			return;
+		}
+		Object handler = HandlerServiceImpl.lookUpHandler(executionContext, commandId);
+		if (handler instanceof IElementUpdater) {
+			((IElementUpdater) handler).updateElement(element, parameters);
+		}
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchImages.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchImages.java
new file mode 100644
index 0000000..a880972
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchImages.java
@@ -0,0 +1,542 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 422040
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 426365
+ *******************************************************************************/
+package org.eclipse.ui.internal;
+
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.misc.Policy;
+import org.eclipse.ui.internal.misc.ProgramImageDescriptor;
+import org.eclipse.ui.internal.util.BundleUtility;
+
+/**
+ * This class provides convenience access to many of the resources required by
+ * the workbench. The class stores some images as descriptors, and some are
+ * stored as real Images in the registry. This is a pure speed-space tradeoff.
+ * The trick for users of this class is that images obtained from the registry
+ * (using getImage()), don't require disposal since they are shared, while
+ * images obtained using getImageDescriptor() will require disposal. Consult the
+ * declareImages method to see if a given image is declared as a registry image
+ * or just as a descriptor. If you change an image from being stored as a
+ * descriptor to a registry image, or vice-versa, make sure to check all users
+ * of the image to ensure they are calling the correct getImage... method and
+ * handling disposal correctly.
+ *
+ * Images: - use getImage(key) to access cached images from the registry. - Less
+ * common images are found by calling getImageDescriptor(key) where key can be
+ * found in IWorkbenchGraphicConstants
+ *
+ * This class initializes the image registry by declaring all of the required
+ * graphics. This involves creating image descriptors describing how to
+ * create/find the image should it be needed. The image is not actually
+ * allocated until requested.
+ *
+ * Some Images are also made available to other plugins by being placed in the
+ * descriptor table of the SharedImages class.
+ *
+ * Where are the images? The images (typically png file) are found the plugins
+ * install directory
+ *
+ * How to add a new image Place the png file into the appropriate directories.
+ * Add a constant to IWorkbenchGraphicConstants following the conventions Add
+ * the declaration to this file
+ */
+public/*final*/class WorkbenchImages {
+
+    private static Map<String, ImageDescriptor> descriptors;
+
+    private static ImageRegistry imageRegistry;
+
+    /* Declare Common paths */
+
+    public final static String ICONS_PATH = "$nl$/icons/full/";//$NON-NLS-1$
+
+    private final static String PATH_ETOOL = ICONS_PATH + "etool16/"; //Enabled toolbar icons.//$NON-NLS-1$
+
+    private final static String PATH_DTOOL = ICONS_PATH + "dtool16/"; //Disabled toolbar icons.//$NON-NLS-1$
+
+    private final static String PATH_ELOCALTOOL = ICONS_PATH + "elcl16/"; //Enabled local toolbar icons.//$NON-NLS-1$
+
+    private final static String PATH_DLOCALTOOL = ICONS_PATH + "dlcl16/"; //Disabled local toolbar icons.//$NON-NLS-1$
+
+    private final static String PATH_EVIEW = ICONS_PATH + "eview16/"; //View icons//$NON-NLS-1$
+
+	private final static String PATH_OVERLAY = ICONS_PATH + "ovr16/"; //$NON-NLS-1$
+
+    private final static String PATH_OBJECT = ICONS_PATH + "obj16/"; //Model object icons//$NON-NLS-1$
+
+    private final static String PATH_POINTER = ICONS_PATH + "pointer/"; //Pointer icons//$NON-NLS-1$
+
+    private final static String PATH_WIZBAN = ICONS_PATH + "wizban/"; //Wizard icons//$NON-NLS-1$
+
+    /**
+     * Declares a workbench image given the path of the image file (relative to
+     * the workbench plug-in). This is a helper method that creates the image
+     * descriptor and passes it to the main <code>declareImage</code> method.
+     *
+     * @param key the symbolic name of the image
+     * @param path the path of the image file relative to the base of the workbench
+     * plug-ins install directory
+     * @param shared <code>true</code> if this is a shared image, and
+     * <code>false</code> if this is not a shared image
+     */
+    private final static void declareImage(String key, String path,
+            boolean shared) {
+        URL url = BundleUtility.find(PlatformUI.PLUGIN_ID, path);
+        ImageDescriptor desc = ImageDescriptor.createFromURL(url);
+        declareImage(key, desc, shared);
+    }
+
+    private static void drawViewMenu(GC gc, GC maskgc) {
+    	Display display = Display.getCurrent();
+
+    	gc.setForeground(display.getSystemColor(SWT.COLOR_WIDGET_DARK_SHADOW));
+    	gc.setBackground(display.getSystemColor(SWT.COLOR_LIST_BACKGROUND));
+
+	    int[] shapeArray = new int[] {1, 1, 10, 1, 6, 5, 5, 5};
+	    gc.fillPolygon(shapeArray);
+	    gc.drawPolygon(shapeArray);
+
+	    Color black = display.getSystemColor(SWT.COLOR_BLACK);
+	    Color white = display.getSystemColor(SWT.COLOR_WHITE);
+
+	    maskgc.setBackground(black);
+	    maskgc.fillRectangle(0,0,12,16);
+
+	    maskgc.setBackground(white);
+	    maskgc.setForeground(white);
+	    maskgc.fillPolygon(shapeArray);
+	    maskgc.drawPolygon(shapeArray);
+    }
+
+    /**
+     * Declares all the workbench's images, including both "shared" ones and
+     * internal ones.
+     */
+    private final static void declareImages() {
+		// Overlays
+		declareImage(ISharedImages.IMG_DEC_FIELD_ERROR, PATH_OVERLAY + "error_ovr.gif", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_DEC_FIELD_WARNING, PATH_OVERLAY + "warning_ovr.gif", true); //$NON-NLS-1$
+
+		// Pinning
+		declareImage(IWorkbenchGraphicConstants.IMG_ETOOL_PIN_EDITOR, PATH_ETOOL + "pin_editor.gif", false); //$NON-NLS-1$
+		declareImage(IWorkbenchGraphicConstants.IMG_ETOOL_PIN_EDITOR_DISABLED, PATH_DTOOL + "pin_editor.gif", false); //$NON-NLS-1$
+
+		// other toolbar buttons
+
+		declareImage(ISharedImages.IMG_ETOOL_SAVE_EDIT, PATH_ETOOL + "save_edit.gif", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_ETOOL_SAVE_EDIT_DISABLED, PATH_DTOOL + "save_edit.gif", true); //$NON-NLS-1$
+
+		declareImage(ISharedImages.IMG_ETOOL_SAVEAS_EDIT, PATH_ETOOL + "saveas_edit.gif", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_ETOOL_SAVEAS_EDIT_DISABLED, PATH_DTOOL + "saveas_edit.gif", true); //$NON-NLS-1$
+
+		declareImage(ISharedImages.IMG_ETOOL_SAVEALL_EDIT, PATH_ETOOL + "saveall_edit.gif", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_ETOOL_SAVEALL_EDIT_DISABLED, PATH_DTOOL + "saveall_edit.gif", true); //$NON-NLS-1$
+
+		declareImage(ISharedImages.IMG_TOOL_UNDO, PATH_ETOOL + "undo_edit.gif", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_TOOL_UNDO_DISABLED, PATH_DTOOL + "undo_edit.gif", true); //$NON-NLS-1$
+
+		declareImage(ISharedImages.IMG_TOOL_REDO, PATH_ETOOL + "redo_edit.gif", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_TOOL_REDO_DISABLED, PATH_DTOOL + "redo_edit.gif", true); //$NON-NLS-1$
+
+		declareImage(ISharedImages.IMG_TOOL_CUT, PATH_ETOOL + "cut_edit.gif", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_TOOL_CUT_DISABLED, PATH_DTOOL + "cut_edit.gif", true); //$NON-NLS-1$
+
+		declareImage(ISharedImages.IMG_TOOL_COPY, PATH_ETOOL + "copy_edit.gif", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_TOOL_COPY_DISABLED, PATH_DTOOL + "copy_edit.gif", true); //$NON-NLS-1$
+
+		declareImage(ISharedImages.IMG_TOOL_PASTE, PATH_ETOOL + "paste_edit.gif", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_TOOL_PASTE_DISABLED, PATH_DTOOL + "paste_edit.gif", true); //$NON-NLS-1$
+
+		declareImage(ISharedImages.IMG_TOOL_DELETE, PATH_ETOOL + "delete_edit.gif", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_TOOL_DELETE_DISABLED, PATH_DTOOL + "delete_edit.gif", true); //$NON-NLS-1$
+
+		declareImage(ISharedImages.IMG_ETOOL_DELETE, PATH_ETOOL + "delete.gif", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_ETOOL_DELETE_DISABLED, PATH_DTOOL + "delete.gif", true); //$NON-NLS-1$
+
+		declareImage(ISharedImages.IMG_ETOOL_CLEAR, PATH_ETOOL + "clear.gif", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_ETOOL_CLEAR_DISABLED, PATH_DTOOL + "clear.gif", true); //$NON-NLS-1$
+
+		declareImage(ISharedImages.IMG_TOOL_NEW_WIZARD, PATH_ETOOL + "new_wiz.gif", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_TOOL_NEW_WIZARD_DISABLED, PATH_DTOOL + "new_wiz.gif", true); //$NON-NLS-1$
+
+		declareImage(ISharedImages.IMG_ETOOL_PRINT_EDIT, PATH_ETOOL + "print_edit.gif", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_ETOOL_PRINT_EDIT_DISABLED, PATH_DTOOL + "print_edit.gif", true); //$NON-NLS-1$
+
+		declareImage(IWorkbenchGraphicConstants.IMG_ETOOL_HELP_CONTENTS, PATH_ETOOL + "help_contents.gif", true); //$NON-NLS-1$
+		declareImage(IWorkbenchGraphicConstants.IMG_ETOOL_HELP_SEARCH, PATH_ETOOL + "help_search.gif", true); //$NON-NLS-1$
+
+		declareImage(IWorkbenchGraphicConstants.IMG_ETOOL_NEW_FASTVIEW, PATH_ETOOL + "new_fastview.gif", true); //$NON-NLS-1$
+		declareImage(IWorkbenchGraphicConstants.IMG_DTOOL_NEW_FASTVIEW, PATH_DTOOL + "new_fastview.gif", true); //$NON-NLS-1$
+
+		declareImage(IWorkbenchGraphicConstants.IMG_ETOOL_RESTORE_TRIMPART, PATH_ETOOL + "fastview_restore.gif", true); //$NON-NLS-1$
+		declareImage(IWorkbenchGraphicConstants.IMG_ETOOL_EDITOR_TRIMPART, PATH_ETOOL + "editor_area.gif", true); //$NON-NLS-1$
+
+		declareImage(ISharedImages.IMG_TOOL_FORWARD, PATH_ELOCALTOOL + "forward_nav.gif", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_TOOL_FORWARD_DISABLED, PATH_DLOCALTOOL + "forward_nav.gif", true); //$NON-NLS-1$
+
+		declareImage(ISharedImages.IMG_TOOL_BACK, PATH_ELOCALTOOL + "backward_nav.gif", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_TOOL_BACK_DISABLED, PATH_DLOCALTOOL + "backward_nav.gif", true); //$NON-NLS-1$
+
+		declareImage(ISharedImages.IMG_TOOL_UP, PATH_ELOCALTOOL + "up_nav.gif", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_TOOL_UP_DISABLED, PATH_DLOCALTOOL + "up_nav.gif", true); //$NON-NLS-1$
+
+		declareImage(ISharedImages.IMG_ELCL_SYNCED, PATH_ELOCALTOOL + "synced.gif", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_ELCL_SYNCED_DISABLED, PATH_DLOCALTOOL + "synced.gif", true); //$NON-NLS-1$
+
+		declareImage(ISharedImages.IMG_ELCL_COLLAPSEALL, PATH_ELOCALTOOL + "collapseall.gif", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_ELCL_COLLAPSEALL_DISABLED, PATH_DLOCALTOOL + "collapseall.gif", true); //$NON-NLS-1$
+
+		declareImage(ISharedImages.IMG_ELCL_REMOVE, PATH_ELOCALTOOL + "remove.gif", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_ELCL_REMOVE_DISABLED, PATH_DLOCALTOOL + "remove.gif", true); //$NON-NLS-1$
+
+		declareImage(ISharedImages.IMG_ELCL_REMOVEALL, PATH_ELOCALTOOL + "removeall.gif", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_ELCL_REMOVEALL_DISABLED, PATH_DLOCALTOOL + "removeall.gif", true); //$NON-NLS-1$
+
+		declareImage(ISharedImages.IMG_ELCL_COLLAPSEALL, PATH_ELOCALTOOL + "collapseall.gif", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_ELCL_COLLAPSEALL_DISABLED, PATH_DLOCALTOOL + "collapseall.gif", true); //$NON-NLS-1$
+
+		declareImage(ISharedImages.IMG_ELCL_STOP, PATH_ELOCALTOOL + "stop.gif", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_ELCL_STOP_DISABLED, PATH_DLOCALTOOL + "stop.gif", true); //$NON-NLS-1$
+
+		declareImage(IWorkbenchGraphicConstants.IMG_ETOOL_NEW_PAGE, PATH_EVIEW + "new_persp.gif", false); //$NON-NLS-1$
+
+		declareImage(ISharedImages.IMG_ETOOL_HOME_NAV, PATH_ELOCALTOOL + "home_nav.gif", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_ETOOL_HOME_NAV_DISABLED, PATH_DLOCALTOOL + "home_nav.gif", true); //$NON-NLS-1$
+
+		declareImage(ISharedImages.IMG_ETOOL_DEF_PERSPECTIVE, PATH_EVIEW + "default_persp.gif", true); //$NON-NLS-1$
+
+		declareImage(IWorkbenchGraphicConstants.IMG_WIZBAN_NEW_WIZ, PATH_WIZBAN + "new_wiz.png", false); //$NON-NLS-1$
+
+		declareImage(IWorkbenchGraphicConstants.IMG_ETOOL_IMPORT_WIZ, PATH_WIZBAN + "import_wiz.png", false); //$NON-NLS-1$
+		declareImage(IWorkbenchGraphicConstants.IMG_ETOOL_EXPORT_WIZ, PATH_WIZBAN + "export_wiz.png", false); //$NON-NLS-1$
+		declareImage(IWorkbenchGraphicConstants.IMG_WIZBAN_IMPORT_WIZ, PATH_WIZBAN + "import_wiz.png", false); //$NON-NLS-1$
+		declareImage(IWorkbenchGraphicConstants.IMG_WIZBAN_EXPORT_WIZ, PATH_WIZBAN + "export_wiz.png", false); //$NON-NLS-1$
+		declareImage(IWorkbenchGraphicConstants.IMG_WIZBAN_IMPORT_PREF_WIZ, PATH_WIZBAN + "importpref_wiz.png", false); //$NON-NLS-1$
+		declareImage(IWorkbenchGraphicConstants.IMG_WIZBAN_EXPORT_PREF_WIZ, PATH_WIZBAN + "exportpref_wiz.png", false); //$NON-NLS-1$
+
+		declareImage(IWorkbenchGraphicConstants.IMG_WIZBAN_WORKINGSET_WIZ, PATH_WIZBAN + "workset_wiz.png", false); //$NON-NLS-1$
+
+		declareImage(IWorkbenchGraphicConstants.IMG_VIEW_DEFAULTVIEW_MISC, PATH_EVIEW + "defaultview_misc.gif", false); //$NON-NLS-1$
+
+		declareImage(IWorkbenchGraphicConstants.IMG_OBJ_FONT, PATH_OBJECT + "font.gif", true); //$NON-NLS-1$
+		declareImage(IWorkbenchGraphicConstants.IMG_OBJ_THEME_CATEGORY, PATH_OBJECT + "theme_category.gif", true); //$NON-NLS-1$
+		declareImage(IWorkbenchGraphicConstants.IMG_OBJ_ACTIVITY, PATH_OBJECT + "activity.gif", true); //$NON-NLS-1$
+		declareImage(IWorkbenchGraphicConstants.IMG_OBJ_ACTIVITY_CATEGORY, PATH_OBJECT + "activity_category.gif", true); //$NON-NLS-1$
+		declareImage(IWorkbenchGraphicConstants.IMG_OBJ_WORKING_SETS, PATH_OBJECT + "workingsets.gif", true); //$NON-NLS-1$
+
+		declareImage(IWorkbenchGraphicConstants.IMG_OBJ_SEPARATOR, PATH_OBJECT + "separator.gif", true); //$NON-NLS-1$
+
+		declareImage(IWorkbenchGraphicConstants.IMG_OBJ_NODE, PATH_OBJECT + "generic_elements.gif", true); //$NON-NLS-1$
+		declareImage(IWorkbenchGraphicConstants.IMG_OBJ_ELEMENT, PATH_OBJECT + "generic_element.gif", true); //$NON-NLS-1$
+
+		declareImage(ISharedImages.IMG_OBJ_ADD, PATH_OBJECT + "add_obj.gif", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_OBJ_FILE, PATH_OBJECT + "file_obj.gif", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_OBJ_FOLDER, PATH_OBJECT + "fldr_obj.gif", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_OBJ_ELEMENT, PATH_OBJECT + "elements_obj.gif", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_DEF_VIEW, PATH_EVIEW + "defaultview_misc.gif", true); //$NON-NLS-1$
+
+		declareImage(IWorkbenchGraphicConstants.IMG_LCL_CLOSE_VIEW, PATH_ELOCALTOOL + "close_view.gif", true); //$NON-NLS-1$
+		declareImage(IWorkbenchGraphicConstants.IMG_LCL_PIN_VIEW, PATH_ELOCALTOOL + "pin_view.gif", true); //$NON-NLS-1$
+		declareImage(IWorkbenchGraphicConstants.IMG_LCL_MIN_VIEW, PATH_ELOCALTOOL + "min_view.gif", true); //$NON-NLS-1$
+		declareImage(IWorkbenchGraphicConstants.IMG_LCL_VIEW_MENU, PATH_ELOCALTOOL + "view_menu.gif", true); //$NON-NLS-1$
+		declareImage(IWorkbenchGraphicConstants.IMG_LCL_BUTTON_MENU, PATH_ELOCALTOOL + "button_menu.gif", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_LCL_LINKTO_HELP, PATH_ELOCALTOOL + "linkto_help.gif", true); //$NON-NLS-1$
+
+		declareImage(IWorkbenchGraphicConstants.IMG_LCL_CLOSE_VIEW_THIN, PATH_ELOCALTOOL + "thin_close_view.gif", true); //$NON-NLS-1$
+		declareImage(IWorkbenchGraphicConstants.IMG_LCL_HIDE_TOOLBAR_THIN, PATH_ELOCALTOOL + "thin_hide_toolbar.gif", //$NON-NLS-1$
+				true);
+		declareImage(IWorkbenchGraphicConstants.IMG_LCL_MAX_VIEW_THIN, PATH_ELOCALTOOL + "thin_max_view.gif", true); //$NON-NLS-1$
+		declareImage(IWorkbenchGraphicConstants.IMG_LCL_MIN_VIEW_THIN, PATH_ELOCALTOOL + "thin_min_view.gif", true); //$NON-NLS-1$
+		declareImage(IWorkbenchGraphicConstants.IMG_LCL_RESTORE_VIEW_THIN, PATH_ELOCALTOOL + "thin_restore_view.gif", //$NON-NLS-1$
+				true);
+		declareImage(IWorkbenchGraphicConstants.IMG_LCL_SHOW_TOOLBAR_THIN, PATH_ELOCALTOOL + "thin_show_toolbar.gif", //$NON-NLS-1$
+				true);
+		declareImage(IWorkbenchGraphicConstants.IMG_LCL_VIEW_MENU_THIN, PATH_ELOCALTOOL + "thin_view_menu.gif", true); //$NON-NLS-1$
+
+		declareImage(ISharedImages.IMG_OBJS_ERROR_TSK, PATH_OBJECT + "error_tsk.gif", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_OBJS_WARN_TSK, PATH_OBJECT + "warn_tsk.gif", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_OBJS_INFO_TSK, PATH_OBJECT + "info_tsk.gif", true); //$NON-NLS-1$
+
+		declareImage(ISharedImages.IMG_OBJS_DND_LEFT_SOURCE, PATH_POINTER + "left_source.bmp", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_OBJS_DND_LEFT_MASK, PATH_POINTER + "left_mask.bmp", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_OBJS_DND_RIGHT_SOURCE, PATH_POINTER + "right_source.bmp", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_OBJS_DND_RIGHT_MASK, PATH_POINTER + "right_mask.bmp", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_OBJS_DND_TOP_SOURCE, PATH_POINTER + "top_source.bmp", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_OBJS_DND_TOP_MASK, PATH_POINTER + "top_mask.bmp", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_OBJS_DND_BOTTOM_SOURCE, PATH_POINTER + "bottom_source.bmp", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_OBJS_DND_BOTTOM_MASK, PATH_POINTER + "bottom_mask.bmp", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_OBJS_DND_INVALID_SOURCE, PATH_POINTER + "invalid_source.bmp", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_OBJS_DND_INVALID_MASK, PATH_POINTER + "invalid_mask.bmp", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_OBJS_DND_STACK_SOURCE, PATH_POINTER + "stack_source.bmp", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_OBJS_DND_STACK_MASK, PATH_POINTER + "stack_mask.bmp", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_OBJS_DND_OFFSCREEN_SOURCE, PATH_POINTER + "offscreen_source.bmp", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_OBJS_DND_OFFSCREEN_MASK, PATH_POINTER + "offscreen_mask.bmp", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_OBJS_DND_TOFASTVIEW_SOURCE, PATH_POINTER + "tofastview_source.bmp", true); //$NON-NLS-1$
+		declareImage(ISharedImages.IMG_OBJS_DND_TOFASTVIEW_MASK, PATH_POINTER + "tofastview_mask.bmp", true); //$NON-NLS-1$
+
+		// signed jar images
+		declareImage(IWorkbenchGraphicConstants.IMG_OBJ_SIGNED_YES, PATH_OBJECT + "signed_yes_tbl.gif", true); //$NON-NLS-1$
+		declareImage(IWorkbenchGraphicConstants.IMG_OBJ_SIGNED_NO, PATH_OBJECT + "signed_no_tbl.gif", true); //$NON-NLS-1$
+		declareImage(IWorkbenchGraphicConstants.IMG_OBJ_SIGNED_UNKNOWN, PATH_OBJECT + "signed_unkn_tbl.gif", true); //$NON-NLS-1$
+
+		declareHoverImages();
+
+		// Manually create the view menu
+
+//		Display d = Display.getCurrent();
+//
+//		Image viewMenu = new Image(d, 11, 16);
+//		Image viewMenuMask = new Image(d, 11, 16);
+//
+//		GC gc = new GC(viewMenu);
+//		GC maskgc = new GC(viewMenuMask);
+//		drawViewMenu(gc, maskgc);
+//		gc.dispose();
+//		maskgc.dispose();
+//
+//		ImageData data = viewMenu.getImageData();
+//		data.transparentPixel = data.getPixel(0, 0);
+//
+//		Image vm2 = new Image(d, viewMenu.getImageData(), viewMenuMask.getImageData());
+//		viewMenu.dispose();
+//		viewMenuMask.dispose();
+//
+//		getImageRegistry().put(IWorkbenchGraphicConstants.IMG_LCL_RENDERED_VIEW_MENU, vm2);
+		declareImage(IWorkbenchGraphicConstants.IMG_LCL_RENDERED_VIEW_MENU,
+		                PATH_EVIEW + "view_menu.gif", true); //$NON-NLS-1$
+    }
+
+    /**
+     * Declares all the workbench's deprecated hover images, including both "shared" ones and
+     * internal ones.
+     *
+     * @deprecated As of 3.0, since the workbench itself no longer uses the hover image variants
+     */
+    @Deprecated
+	private final static void declareHoverImages() {
+        declareImage(ISharedImages.IMG_TOOL_UNDO_HOVER, PATH_ETOOL
+        		+ "undo_edit.gif", true); //$NON-NLS-1$
+        declareImage(ISharedImages.IMG_TOOL_REDO_HOVER, PATH_ETOOL
+                + "redo_edit.gif", true); //$NON-NLS-1$
+        declareImage(ISharedImages.IMG_TOOL_CUT_HOVER, PATH_ETOOL
+        		+ "cut_edit.gif", true); //$NON-NLS-1$
+        declareImage(ISharedImages.IMG_TOOL_COPY_HOVER, PATH_ETOOL
+                + "copy_edit.gif", true); //$NON-NLS-1$
+        declareImage(ISharedImages.IMG_TOOL_PASTE_HOVER, PATH_ETOOL
+                + "paste_edit.gif", true); //$NON-NLS-1$
+        declareImage(ISharedImages.IMG_TOOL_FORWARD_HOVER, PATH_ELOCALTOOL
+                + "forward_nav.gif", true); //$NON-NLS-1$
+        declareImage(ISharedImages.IMG_TOOL_DELETE_HOVER, PATH_ETOOL
+        		+ "delete_edit.gif", true); //$NON-NLS-1$
+        declareImage(ISharedImages.IMG_TOOL_NEW_WIZARD_HOVER, PATH_ETOOL
+                        + "new_wiz.gif", true); //$NON-NLS-1$
+        declareImage(ISharedImages.IMG_TOOL_BACK_HOVER, PATH_ELOCALTOOL
+        		+ "backward_nav.gif", true); //$NON-NLS-1$
+        declareImage(ISharedImages.IMG_TOOL_UP_HOVER, PATH_ELOCALTOOL
+                + "up_nav.gif", true); //$NON-NLS-1$
+    }
+
+    /**
+     * Declares a workbench image.
+     * <p>
+     * The workbench remembers the given image descriptor under the given name,
+     * and makes the image available to plug-ins via
+     * {@link org.eclipse.ui.ISharedImages IWorkbench.getSharedImages()}.
+     * For "shared" images, the workbench remembers the image descriptor and
+     * will manages the image object create from it; clients retrieve "shared"
+     * images via
+     * {@link org.eclipse.ui.ISharedImages#getImage ISharedImages.getImage()}.
+     * For the other, "non-shared" images, the workbench remembers only the
+     * image descriptor; clients retrieve the image descriptor via
+     * {@link org.eclipse.ui.ISharedImages#getImageDescriptor
+     * ISharedImages.getImageDescriptor()} and are entirely
+     * responsible for managing the image objects they create from it.
+     * (This is made confusing by the historical fact that the API interface
+     *  is called "ISharedImages".)
+     * </p>
+     *
+     * @param symbolicName the symbolic name of the image
+     * @param descriptor the image descriptor
+     * @param shared <code>true</code> if this is a shared image, and
+     * <code>false</code> if this is not a shared image
+     * @see org.eclipse.ui.ISharedImages#getImage
+     * @see org.eclipse.ui.ISharedImages#getImageDescriptor
+     */
+    public static void declareImage(String symbolicName,
+            ImageDescriptor descriptor, boolean shared) {
+        if (Policy.DEBUG_DECLARED_IMAGES) {
+            Image image = descriptor.createImage(false);
+            if (image == null) {
+                WorkbenchPlugin.log("Image not found in WorkbenchImages.declaredImage().  symbolicName=" + symbolicName + " descriptor=" + descriptor, new Exception("stack dump"));   //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
+            }
+            else {
+                image.dispose();
+            }
+        }
+        getDescriptors().put(symbolicName, descriptor);
+        if (shared) {
+            getImageRegistry().put(symbolicName, descriptor);
+        }
+    }
+
+    /**
+     * Returns the map from symbolic name to ImageDescriptor.
+     *
+     * @return the map from symbolic name to ImageDescriptor.
+     */
+    public static Map<String, ImageDescriptor> getDescriptors() {
+        if (descriptors == null) {
+            initializeImageRegistry();
+        }
+        return descriptors;
+    }
+
+    /**
+     * Returns the image stored in the workbench plugin's image registry
+     * under the given symbolic name.  If there isn't any value associated
+     * with the name then <code>null</code> is returned.
+     *
+     * The returned Image is managed by the workbench plugin's image registry.
+     * Callers of this method must not dispose the returned image.
+     *
+     * This method is essentially a convenient short form of
+     * WorkbenchImages.getImageRegistry.get(symbolicName).
+     *
+     * @param symbolicName the symbolic name
+     * @return the image
+     */
+    public static Image getImage(String symbolicName) {
+        return getImageRegistry().get(symbolicName);
+    }
+
+    /**
+     * Returns the image descriptor stored under the given symbolic name.
+     * If there isn't any value associated with the name then <code>null
+     * </code> is returned.
+     *
+     * The class also "caches" commonly used images in the image registry.
+     * If you are looking for one of these common images it is recommended you use
+     * the getImage() method instead.
+     *
+     * @param symbolicName the symbolic name
+     * @return the image descriptor
+     */
+    public static ImageDescriptor getImageDescriptor(String symbolicName) {
+        return getDescriptors().get(symbolicName);
+    }
+
+    /**
+     * Convenience Method.
+     * Returns an ImageDescriptor obtained from an external program.
+     * If there isn't any image then <code>null</code> is returned.
+     *
+     * This method is convenience and only intended for use by the workbench because it
+     * explicitly uses the workbench's registry for caching/retrieving images from other
+     * extensions -- other plugins must user their own registry.
+     * This convenience method is subject to removal.
+     *
+     * Note:
+     * This consults the plugin for extension and obtains its installation location.
+     * all requested images are assumed to be in a directory below and relative to that
+     * plugins installation directory.
+     *
+     * @param filename the file name
+     * @param offset the offset
+     * @return the image descriptor
+     */
+
+    public static ImageDescriptor getImageDescriptorFromProgram(
+            String filename, int offset) {
+        Assert.isNotNull(filename);
+        String key = filename + "*" + offset; //use * as it is not a valid filename character//$NON-NLS-1$
+        ImageDescriptor desc = getImageDescriptor(key);
+        if (desc == null) {
+            desc = new ProgramImageDescriptor(filename, offset);
+            getDescriptors().put(key, desc);
+        }
+        return desc;
+    }
+
+    /**
+     * Returns the ImageRegistry.
+     *
+     * @return the image registry
+     */
+    public static ImageRegistry getImageRegistry() {
+        if (imageRegistry == null) {
+            initializeImageRegistry();
+        }
+        return imageRegistry;
+    }
+
+    /**
+	 * Initialize the image registry by declaring all of the required graphics.
+	 * This involves creating JFace image descriptors describing how to
+	 * create/find the image should it be needed. The image is not actually
+	 * allocated until requested.
+	 *
+	 * Prefix conventions Wizard Banners WIZBAN_ Preference Banners PREF_BAN_
+	 * Property Page Banners PROPBAN_ Enable toolbar ETOOL_ Disable toolbar
+	 * DTOOL_ Local enabled toolbar ELCL_ Local Disable toolbar DLCL_ Object
+	 * large OBJL_ Object small OBJS_ View VIEW_ Product images PROD_ Misc
+	 * images MISC_
+	 *
+	 * Where are the images? The images (typically png files) are found in the
+	 * same location as this plugin class. This may mean the same package
+	 * directory as the package holding this class. The images are declared
+	 * using this.getClass() to ensure they are looked up via this plugin class.
+	 *
+	 * @see ImageRegistry
+	 */
+    private static void initializeImageRegistry() {
+        imageRegistry = new ImageRegistry();
+		descriptors = new HashMap<>();
+        declareImages();
+    }
+
+    /**
+     * Disposes and clears the workbench images.
+     * Called when the workbench is shutting down.
+     *
+     * @since 3.1
+     */
+    public static void dispose() {
+        if (imageRegistry != null) {
+            imageRegistry.dispose();
+            imageRegistry = null;
+            descriptors = null;
+        }
+    }
+
+	/**
+	 * Get the workbench image with the given path relative to
+	 * ICON_PATH.
+	 * @param relativePath
+	 * @return ImageDescriptor
+	 */
+	public static ImageDescriptor getWorkbenchImageDescriptor(String relativePath){
+		return ImageDescriptor.createFromURL(BundleUtility.find(PlatformUI.PLUGIN_ID, ICONS_PATH + relativePath));
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchIntroManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchIntroManager.java
new file mode 100644
index 0000000..71c06b3
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchIntroManager.java
@@ -0,0 +1,309 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2011, 2015 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
+ *     Dirk Fauth <dirk.fauth@googlemail.com> - Bug 463043
+ *******************************************************************************/
+package org.eclipse.ui.internal;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
+import org.eclipse.e4.ui.model.application.ui.MUIElement;
+import org.eclipse.e4.ui.model.application.ui.advanced.MPlaceholder;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.model.application.ui.basic.MPartStack;
+import org.eclipse.e4.ui.workbench.IPresentationEngine;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IViewReference;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.internal.e4.compatibility.CompatibilityView;
+import org.eclipse.ui.internal.intro.IIntroConstants;
+import org.eclipse.ui.internal.intro.IntroDescriptor;
+import org.eclipse.ui.internal.intro.IntroMessages;
+import org.eclipse.ui.intro.IIntroManager;
+import org.eclipse.ui.intro.IIntroPart;
+import org.eclipse.ui.intro.IntroContentDetector;
+
+/**
+ * Workbench implementation of the IIntroManager interface.
+ *
+ * @since 3.0
+ */
+public class WorkbenchIntroManager implements IIntroManager {
+
+    private final Workbench workbench;
+
+    /**
+     * Create a new instance of the receiver.
+     *
+     * @param workbench the workbench instance
+     */
+    WorkbenchIntroManager(Workbench workbench) {
+        this.workbench = workbench;
+        workbench.getExtensionTracker().registerHandler(new IExtensionChangeHandler(){
+
+            @Override
+			public void addExtension(IExtensionTracker tracker,IExtension extension) {
+                //Do nothing
+            }
+
+			@Override
+			public void removeExtension(IExtension source, Object[] objects) {
+                for (Object object : objects) {
+                    if (object instanceof IIntroPart) {
+                        closeIntro((IIntroPart) object);
+                    }
+                }
+
+			}}, null);
+
+    }
+
+    /**
+     * The currently active introPart in this workspace, <code>null</code> if none.
+     */
+    private IIntroPart introPart;
+
+    @Override
+	public boolean closeIntro(IIntroPart part) {
+        if (introPart == null || !introPart.equals(part)) {
+			return false;
+		}
+
+        IViewPart introView = getViewIntroAdapterPart();
+        if (introView != null) {
+            //assumption is that there is only ever one intro per workbench
+            //if we ever support one per window then this will need revisiting
+            IWorkbenchPage page = introView.getSite().getPage();
+			if (page == null) {
+				introPart = null;
+				return true;
+			}
+            IViewReference reference = page
+                    .findViewReference(IIntroConstants.INTRO_VIEW_ID);
+            page.hideView(introView);
+            if (reference == null || reference.getPart(false) == null) {
+                introPart = null;
+                return true;
+            }
+            return false;
+        }
+
+		// if there is no part then null our reference
+		introPart = null;
+
+        return true;
+    }
+
+    @Override
+	public IIntroPart showIntro(IWorkbenchWindow preferredWindow,
+            boolean standby) {
+        if (preferredWindow == null) {
+			preferredWindow = this.workbench.getActiveWorkbenchWindow();
+		}
+
+        if (preferredWindow == null) {
+			return null;
+		}
+
+        ViewIntroAdapterPart viewPart = getViewIntroAdapterPart();
+        if (viewPart == null) {
+            createIntro(preferredWindow);
+        } else {
+            try {
+                IWorkbenchPage page = viewPart.getSite().getPage();
+                IWorkbenchWindow window = page.getWorkbenchWindow();
+                if (!window.equals(preferredWindow)) {
+                    window.getShell().setActive();
+                }
+
+                page.showView(IIntroConstants.INTRO_VIEW_ID);
+            } catch (PartInitException e) {
+                WorkbenchPlugin
+                        .log(
+                                "Could not open intro", new Status(IStatus.ERROR, WorkbenchPlugin.PI_WORKBENCH, IStatus.ERROR, "Could not open intro", e)); //$NON-NLS-1$ //$NON-NLS-2$
+            }
+        }
+        setIntroStandby(introPart, standby);
+        return introPart;
+    }
+
+    /**
+     * @param testWindow the window to test
+     * @return whether the intro exists in the given window
+     */
+    /*package*/boolean isIntroInWindow(IWorkbenchWindow testWindow) {
+        ViewIntroAdapterPart viewPart = getViewIntroAdapterPart();
+        if (viewPart == null) {
+			return false;
+		}
+
+        IWorkbenchWindow window = viewPart.getSite().getWorkbenchWindow();
+        if (window.equals(testWindow)) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Create a new Intro area (a view, currently) in the provided window.  If there is no intro
+     * descriptor for this workbench then no work is done.
+     *
+     * @param preferredWindow the window to create the intro in.
+     */
+    private void createIntro(IWorkbenchWindow preferredWindow) {
+        if (this.workbench.getIntroDescriptor() == null) {
+			return;
+		}
+
+        IWorkbenchPage workbenchPage = preferredWindow.getActivePage();
+        if (workbenchPage == null) {
+			return;
+		}
+        try {
+            workbenchPage.showView(IIntroConstants.INTRO_VIEW_ID);
+        } catch (PartInitException e) {
+            WorkbenchPlugin
+                    .log(
+                            IntroMessages.Intro_could_not_create_part, new Status(IStatus.ERROR, WorkbenchPlugin.PI_WORKBENCH, IStatus.ERROR, IntroMessages.Intro_could_not_create_part, e));
+        }
+    }
+
+    @Override
+	public void setIntroStandby(IIntroPart part, boolean standby) {
+        if (introPart == null || !introPart.equals(part)) {
+			return;
+		}
+
+		ViewIntroAdapterPart viewIntroAdapterPart = getViewIntroAdapterPart();
+		if (viewIntroAdapterPart == null) {
+			return;
+		}
+
+		MPartStack introStack = getIntroStack(viewIntroAdapterPart);
+		if (introStack == null)
+			return;
+
+		boolean isMaximized = isIntroMaximized(viewIntroAdapterPart);
+		if (!isMaximized && !standby)
+			introStack.getTags().add(IPresentationEngine.MAXIMIZED);
+		else if (isMaximized && standby)
+			introStack.getTags().remove(IPresentationEngine.MAXIMIZED);
+	}
+
+	private MPartStack getIntroStack(ViewIntroAdapterPart introAdapter) {
+		ViewSite site = (ViewSite) introAdapter.getViewSite();
+
+		MPart introModelPart = site.getModel();
+		if (introModelPart.getCurSharedRef() != null) {
+			MUIElement introPartParent = introModelPart.getCurSharedRef().getParent();
+			if (introPartParent instanceof MPartStack) {
+				return (MPartStack) introPartParent;
+			}
+		}
+
+		return null;
+	}
+
+	private boolean isIntroMaximized(ViewIntroAdapterPart introAdapter) {
+		MPartStack introStack = getIntroStack(introAdapter);
+		if (introStack == null)
+			return false;
+
+		return introStack.getTags().contains(IPresentationEngine.MAXIMIZED);
+    }
+
+    @Override
+	public boolean isIntroStandby(IIntroPart part) {
+        if (introPart == null || !introPart.equals(part)) {
+			return false;
+		}
+
+        ViewIntroAdapterPart viewIntroAdapterPart = getViewIntroAdapterPart();
+        if (viewIntroAdapterPart == null) {
+			return false;
+		}
+
+		return !isIntroMaximized(viewIntroAdapterPart);
+    }
+
+    @Override
+	public IIntroPart getIntro() {
+        return introPart;
+    }
+
+    /**
+     * @return the <code>ViewIntroAdapterPart</code> for this workbench, <code>null</code> if it
+     * cannot be found.
+     */
+    /*package*/ViewIntroAdapterPart getViewIntroAdapterPart() {
+		for (IWorkbenchWindow iWorkbenchWindow : this.workbench.getWorkbenchWindows()) {
+			WorkbenchWindow window = (WorkbenchWindow) iWorkbenchWindow;
+			MUIElement introPart = window.modelService.find(IIntroConstants.INTRO_VIEW_ID, window.getModel());
+			if (introPart instanceof MPlaceholder) {
+				MPlaceholder introPH = (MPlaceholder) introPart;
+				MPart introModelPart = (MPart) introPH.getRef();
+				CompatibilityView compatView = (CompatibilityView) introModelPart.getObject();
+				if (compatView != null) {
+					Object obj = compatView.getPart();
+					if (obj instanceof ViewIntroAdapterPart)
+						return (ViewIntroAdapterPart) obj;
+				}
+			}
+		}
+        return null;
+    }
+
+    /**
+     * @return a new IIntroPart.  This has the side effect of setting the introPart field to the new
+     * value.
+     */
+    /*package*/IIntroPart createNewIntroPart() throws CoreException {
+        IntroDescriptor introDescriptor = workbench.getIntroDescriptor();
+		introPart = introDescriptor == null ? null
+                : introDescriptor.createIntro();
+        if (introPart != null) {
+        	workbench.getExtensionTracker().registerObject(
+					introDescriptor.getConfigurationElement()
+							.getDeclaringExtension(), introPart,
+					IExtensionTracker.REF_WEAK);
+        }
+    	return introPart;
+    }
+
+    @Override
+	public boolean hasIntro() {
+        return workbench.getIntroDescriptor() != null;
+    }
+
+    @Override
+	public boolean isNewContentAvailable() {
+		IntroDescriptor introDescriptor = workbench.getIntroDescriptor();
+		if (introDescriptor == null) {
+			return false;
+		}
+		try {
+			IntroContentDetector contentDetector = introDescriptor
+					.getIntroContentDetector();
+			if (contentDetector != null) {
+				return contentDetector.isNewContentAvailable();
+			}
+		} catch (CoreException ex) {
+			WorkbenchPlugin.log(new Status(IStatus.WARNING,
+					WorkbenchPlugin.PI_WORKBENCH, IStatus.WARNING,
+					"Could not load intro content detector", ex)); //$NON-NLS-1$
+		}
+		return false;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchLayoutSettingsTransfer.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchLayoutSettingsTransfer.java
new file mode 100644
index 0000000..52df40a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchLayoutSettingsTransfer.java
@@ -0,0 +1,126 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.ui.internal.preferences.WorkbenchSettingsTransfer;
+
+/**
+ * The WorkbenchSettings handles the recording and restoring of workbench
+ * settings.
+ *
+ * @since 3.3
+ *
+ */
+public class WorkbenchLayoutSettingsTransfer extends WorkbenchSettingsTransfer {
+
+	/**
+	 * Create a new instance of the receiver.
+	 */
+	public WorkbenchLayoutSettingsTransfer() {
+		super();
+	}
+
+	@Override
+	public IStatus transferSettings(IPath newWorkspaceRoot) {
+		try {
+			IPath currentLocation = getNewWorkbenchStateLocation(Platform.getLocation());
+			File workspaceFile = createFileAndDirectories(newWorkspaceRoot);
+
+			if (workspaceFile == null)
+				return new Status(
+						IStatus.ERROR,
+						WorkbenchPlugin.PI_WORKBENCH,
+						WorkbenchMessages.get().WorkbenchSettings_CouldNotCreateDirectories);
+
+			File deltas = new File(currentLocation.toOSString(), "deltas.xml"); //$NON-NLS-1$
+			if (deltas.exists()) {
+				byte[] bytes = new byte[8192];
+				FileInputStream inputStream = new FileInputStream(deltas);
+				FileOutputStream outputStream = new FileOutputStream(new File(workspaceFile,
+						"deltas.xml")); //$NON-NLS-1$
+				int read = inputStream.read(bytes, 0, 8192);
+				while (read != -1) {
+					outputStream.write(bytes, 0, read);
+					read = inputStream.read(bytes, 0, 8192);
+				}
+				inputStream.close();
+				outputStream.close();
+			}
+
+			File workbenchModel = new File(currentLocation.toOSString(), "workbench.xmi"); //$NON-NLS-1$
+			if (workbenchModel.exists()) {
+				byte[] bytes = new byte[8192];
+				FileInputStream inputStream = new FileInputStream(workbenchModel);
+				FileOutputStream outputStream = new FileOutputStream(new File(workspaceFile,
+						"workbench.xmi")); //$NON-NLS-1$
+				int read = inputStream.read(bytes, 0, 8192);
+				while (read != -1) {
+					outputStream.write(bytes, 0, read);
+					read = inputStream.read(bytes, 0, 8192);
+				}
+				inputStream.close();
+				outputStream.close();
+			}
+		} catch (IOException e) {
+			return new Status(IStatus.ERROR, WorkbenchPlugin.PI_WORKBENCH,
+					WorkbenchMessages.get().Workbench_problemsSavingMsg, e);
+
+		}
+
+		return Status.OK_STATUS;
+	}
+
+	/**
+	 * Create the parent directories for the workbench layout file and then
+	 * return the File.
+	 *
+	 * @param newWorkspaceRoot
+	 * @return File the new layout file. Return <code>null</code> if the file
+	 *         cannot be created.
+	 */
+	private File createFileAndDirectories(IPath newWorkspaceRoot) {
+		IPath newWorkspaceLocation = getNewWorkbenchStateLocation(newWorkspaceRoot);
+		File workspaceFile = new File(newWorkspaceLocation.toOSString());
+		if (!workspaceFile.exists()) {
+			if (!workspaceFile.mkdirs())
+				return null;
+		}
+
+		return workspaceFile;
+	}
+
+	@Override
+	public String getName() {
+		return WorkbenchMessages.get().WorkbenchLayoutSettings_Name;
+	}
+
+	/**
+	 * Return the workbench settings location for the new root
+	 *
+	 * @param newWorkspaceRoot
+	 * @return IPath or <code>null</code> if it can't be determined.
+	 */
+	@Override
+	protected IPath getNewWorkbenchStateLocation(IPath newWorkspaceRoot) {
+		return newWorkspaceRoot.append(new Path(".metadata/.plugins/org.eclipse.e4.workbench")); //$NON-NLS-1$
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchMessages.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchMessages.java
new file mode 100644
index 0000000..3ba4ffb
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchMessages.java
@@ -0,0 +1,1049 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM - Initial API and implementation
+ * Sebastian Davids - bug 128529
+ * Semion Chichelnitsky (semion@il.ibm.com) - bug 278064
+ * Tristan Hume - <trishume@gmail.com> -
+ *      Fix for Bug 2369 [Workbench] Would like to be able to save workspace without exiting
+ *      Implemented workbench auto-save to correctly restore state in case of crash.
+ * Andrey Loskutov <loskutov@gmx.de> - Bug 388476, 445538, 463262
+ * Alain Bernard <alain.bernard1224@gmail.com> - Bug 281490
+ * Patrik Suzzi <psuzzi@gmail.com> - Bug 491785, 368977, 501811, 511198
+ *******************************************************************************/
+package org.eclipse.ui.internal;
+
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * Message class for workbench messages.  These messages are used
+ * throughout the workbench.
+ *
+ */
+//RAP [fappel]: need session aware NLS
+//public class WorkbenchMessages extends NLS {
+public class WorkbenchMessages {
+    private static final String BUNDLE_NAME = "org.eclipse.ui.internal.messages";//$NON-NLS-1$
+
+
+    public String ThemingEnabled;
+
+    public String ThemeChangeWarningText;
+
+    public String BundleSigningTray_Cant_Find_Service;
+
+
+    public String BundleSigningTray_Determine_Signer_For;
+
+
+    public String BundleSigningTray_Signing_Certificate;
+
+
+    public String BundleSigningTray_Signing_Date;
+
+
+    public String BundleSigningTray_Unget_Signing_Service;
+
+
+    public String BundleSigningTray_Unknown;
+
+
+    public String BundleSigningTray_Unsigned;
+
+
+    public String BundleSigningTray_Working;
+
+
+    public String NewWorkingSet;
+
+
+    public String PlatformUI_NoWorkbench;
+
+    public String Workbench_CreatingWorkbenchTwice;
+
+    public String StatusUtil_errorOccurred;
+
+    // ==============================================================================
+    // Workbench Actions
+    // ==============================================================================
+
+    // --- File Menu ---
+    public String NewWizardAction_text;
+    public String NewWizardAction_toolTip;
+    public String CloseAllAction_text;
+    public String CloseAllAction_toolTip;
+    public String CloseAllSavedAction_text;
+    public String CloseAllSavedAction_toolTip;
+    public String CloseEditorAction_text;
+    public String CloseEditorAction_toolTip;
+    public String CloseOthersAction_text;
+    public String CloseOthersAction_toolTip;
+    public String NewEditorAction_text;
+    public String NewEditorAction_tooltip;
+    public String SaveAction_text;
+    public String SaveAction_toolTip;
+    public String SaveAs_text;
+    public String SaveAs_toolTip;
+    public String SaveAll_text;
+    public String SaveAll_toolTip;
+    public String Workbench_revert;
+    public String Workbench_revertToolTip;
+    public String Workbench_missingPropertyMessage;
+    public String Workbench_move;
+
+    public String Workbench_moveToolTip;
+    public String Workbench_rename;
+    public String Workbench_renameToolTip;
+    public String Workbench_refresh;
+    public String Workbench_refreshToolTip;
+    public String Workbench_properties;
+    public String Workbench_propertiesToolTip;
+
+
+    public String Workbench_print;
+    public String Workbench_printToolTip;
+    public String ExportResourcesAction_text;
+    public String ExportResourcesAction_fileMenuText;
+    public String ExportResourcesAction_toolTip;
+    public String ImportResourcesAction_text;
+    public String ImportResourcesAction_toolTip;
+
+
+    public String OpenRecent_errorTitle;
+    public String OpenRecent_unableToOpen;
+    public String Exit_text;
+    public String Exit_toolTip;
+
+
+    // --- Edit Menu ---
+    public String Workbench_undo;
+    public String Workbench_undoToolTip;
+    public String Workbench_redo;
+    public String Workbench_redoToolTip;
+    public String Workbench_cut;
+    public String Workbench_cutToolTip;
+    public String Workbench_copy;
+    public String Workbench_copyToolTip;
+    public String Workbench_paste;
+    public String Workbench_pasteToolTip;
+    public String Workbench_delete;
+    public String Workbench_deleteToolTip;
+    public String Workbench_selectAll;
+    public String Workbench_selectAllToolTip;
+    public String Workbench_findReplace;
+    public String Workbench_findReplaceToolTip;
+
+    // --- Navigate Menu ---
+    public String Workbench_goInto;
+    public String Workbench_goIntoToolTip;
+    public String Workbench_back;
+    public String Workbench_backToolTip;
+    public String Workbench_forward;
+    public String Workbench_forwardToolTip;
+    public String Workbench_up;
+    public String Workbench_upToolTip;
+    public String Workbench_next;
+    public String Workbench_nextToolTip;
+    public String Workbench_previous;
+    public String Workbench_previousToolTip;
+
+    public String NavigationHistoryAction_forward_text;
+    public String NavigationHistoryAction_forward_toolTip;
+    public String NavigationHistoryAction_backward_text;
+    public String NavigationHistoryAction_backward_toolTip;
+    public String NavigationHistoryAction_forward_toolTipName;
+    public String NavigationHistoryAction_backward_toolTipName;
+    public String NavigationHistoryAction_locations;
+
+    public String Workbench_showInNoTargets;
+    public String Workbench_showInNoPerspectives;
+    public String Workbench_noApplicableItems;
+
+    public String OpenPreferences_text;
+    public String OpenPreferences_toolTip;
+
+    // --- Window Menu ---
+    public String PerspectiveMenu_otherItem;
+    public String SelectPerspective_shellTitle;
+    public String SelectPerspective_selectPerspectiveHelp;
+	public String SelectPerspective_noDesc;
+	public String SelectPerspective_open_button_label;
+    public String Workbench_showPerspectiveError;
+    public String ChangeToPerspectiveMenu_errorTitle;
+    public String OpenPerspectiveDialogAction_text;
+    public String OpenPerspectiveDialogAction_tooltip;
+
+    public String ShowView_title;
+    public String ShowView_shellTitle;
+    public String ShowView_selectViewHelp;
+    public String ShowView_noDesc;
+    public String ShowView_open_button_label;	
+
+    public String ToggleEditor_hideEditors;
+    public String ToggleEditor_showEditors;
+    public String ToggleEditor_toolTip;
+
+    public String LockToolBarAction_toolTip;
+
+    public String EditActionSetsAction_text;
+    public String EditActionSetsAction_toolTip;
+    public String ActionSetSelection_customize;
+    public String ActionSetDialogInput_viewCategory;
+    public String ActionSetDialogInput_perspectiveCategory;
+    public String ActionSetDialogInput_wizardCategory;
+
+    public String Shortcuts_shortcutTab;
+    public String Shortcuts_selectShortcutsLabel;
+    public String Shortcuts_availableMenus;
+    public String Shortcuts_availableCategories;
+    public String Shortcuts_allShortcuts;
+
+    public String ActionSetSelection_actionSetsTab;
+    public String ActionSetSelection_selectActionSetsLabel;
+    public String ActionSetSelection_availableActionSets;
+    public String ActionSetSelection_menubarActions;
+    public String ActionSetSelection_toolbarActions;
+    public String ActionSetSelection_descriptionColumnHeader;
+    public String ActionSetSelection_menuColumnHeader;
+
+    public String HideItems_itemInActionSet;
+    public String HideItems_itemInUnavailableActionSet;
+    public String HideItems_itemInUnavailableCommand;
+    public String HideItems_unavailableChildCommandGroup;
+    public String HideItems_unavailableChildCommandGroups;
+    public String HideItems_keyBindings;
+    public String HideItems_keyBindingsActionSetUnavailable;
+    public String HideItems_noKeyBindings;
+    public String HideItems_noKeyBindingsActionSetUnavailable;
+    public String HideItems_commandGroupTitle;
+    public String HideItems_turnOnActionSets;
+    public String HideItems_dynamicItemName;
+    public String HideItems_dynamicItemDescription;
+    public String HideItems_dynamicItemList;
+    public String HideItems_dynamicItemEmptyList;
+
+    public String HideItemsCannotMakeVisible_dialogTitle;
+    public String HideItemsCannotMakeVisible_unavailableCommandGroupText;
+    public String HideItemsCannotMakeVisible_unavailableCommandItemText;
+    public String HideItemsCannotMakeVisible_switchToCommandGroupTab;
+    public String HideItemsCannotMakeVisible_unavailableChildrenText;
+
+    public String HideMenuItems_menuItemsTab;
+    public String HideMenuItems_chooseMenuItemsLabel;
+    public String HideMenuItems_menuStructure;
+
+    public String HideToolBarItems_toolBarItemsTab;
+    public String HideToolBarItems_chooseToolBarItemsLabel;
+    public String HideToolBarItems_toolBarStructure;
+
+    public String SavePerspective_text;
+    public String SavePerspective_toolTip;
+    public String SavePerspective_shellTitle;
+    public String SavePerspective_saveButtonLabel;
+    public String SavePerspectiveDialog_description;
+    public String SavePerspective_name;
+    public String SavePerspective_existing;
+    public String SavePerspective_overwriteTitle;
+    public String SavePerspective_overwriteQuestion;
+    public String SavePerspective_singletonQuestion;
+    public String SavePerspective_errorTitle;
+    public String SavePerspective_errorMessage;
+
+    public String ResetPerspective_text;
+    public String ResetPerspective_toolTip;
+    public String ResetPerspective_message;
+    public String ResetPerspective_title;
+    public String RevertPerspective_note;
+
+    public String RevertPerspective_title;
+    public String RevertPerspective_message;
+    public String RevertPerspective_option;
+
+    public String ClosePerspectiveAction_text;
+    public String ClosePerspectiveAction_toolTip;
+    public String CloseAllPerspectivesAction_text;
+    public String CloseAllPerspectivesAction_toolTip;
+
+    public String OpenInNewWindowAction_text;
+    public String OpenInNewWindowAction_toolTip;
+    public String OpenInNewWindowAction_errorTitle;
+    public String CycleEditorAction_next_text;
+    public String CycleEditorAction_next_toolTip;
+    public String CycleEditorAction_prev_text;
+    public String CycleEditorAction_prev_toolTip;
+    public String CycleEditorAction_header;
+    public String CyclePartAction_next_text;
+    public String CyclePartAction_next_toolTip;
+    public String CyclePartAction_prev_text;
+    public String CyclePartAction_prev_toolTip;
+    public String CyclePartAction_header;
+    public String CyclePartAction_editor;
+    public String CyclePerspectiveAction_next_text;
+    public String CyclePerspectiveAction_next_toolTip;
+    public String CyclePerspectiveAction_prev_text;
+    public String CyclePerspectiveAction_prev_toolTip;
+    public String CyclePerspectiveAction_header;
+    public String ActivateEditorAction_text;
+    public String ActivateEditorAction_toolTip;
+    public String MaximizePartAction_toolTip;
+    public String MinimizePartAction_toolTip;
+
+	// --- Filtered Table Base ---
+	public static String FilteredTableBase_Filter;
+
+
+
+    // --- Help Menu ---
+    public String AboutAction_text;
+    public String AboutAction_toolTip;
+    public String HelpContentsAction_text;
+    public String HelpContentsAction_toolTip;
+    public String HelpSearchAction_text;
+    public String HelpSearchAction_toolTip;
+    public String DynamicHelpAction_text;
+    public String DynamicHelpAction_toolTip;
+    public String AboutDialog_shellTitle;
+    public String AboutDialog_defaultProductName;
+
+
+    public String AboutDialog_DetailsButton;
+    public String ProductInfoDialog_errorTitle;
+    public String ProductInfoDialog_unableToOpenWebBrowser;
+    public String PreferencesExportDialog_ErrorDialogTitle;
+    public String AboutPluginsDialog_shellTitle;
+    public String AboutPluginsDialog_pluginName;
+    public String AboutPluginsDialog_pluginId;
+    public String AboutPluginsDialog_version;
+    public String AboutPluginsDialog_signed;
+    public String AboutPluginsDialog_provider;
+    public String AboutPluginsDialog_state_installed;
+    public String AboutPluginsDialog_state_resolved;
+    public String AboutPluginsDialog_state_starting;
+    public String AboutPluginsDialog_state_stopping;
+    public String AboutPluginsDialog_state_uninstalled;
+    public String AboutPluginsDialog_state_active;
+    public String AboutPluginsDialog_state_unknown;
+    public String AboutPluginsDialog_moreInfo;
+    public String AboutPluginsDialog_signingInfo_show;
+    public String AboutPluginsDialog_signingInfo_hide;
+    public String AboutPluginsDialog_columns;
+    public String AboutPluginsDialog_errorTitle;
+    public String AboutPluginsDialog_unableToOpenFile;
+    public String AboutPluginsDialog_filterTextMessage;
+    public String AboutPluginsPage_Load_Bundle_Data;
+    public String AboutFeaturesDialog_shellTitle;
+    public String AboutFeaturesDialog_featureName;
+    public String AboutFeaturesDialog_featureId;
+    public String AboutFeaturesDialog_version;
+    public String AboutFeaturesDialog_provider;
+    public String AboutFeaturesDialog_moreInfo;
+    public String AboutFeaturesDialog_pluginsInfo;
+    public String AboutFeaturesDialog_columns;
+    public String AboutFeaturesDialog_noInformation;
+    public String AboutFeaturesDialog_pluginInfoTitle;
+    public String AboutFeaturesDialog_pluginInfoMessage;
+    public String AboutFeaturesDialog_noInfoTitle;
+
+
+    public String AboutFeaturesDialog_SimpleTitle;
+    public String AboutSystemDialog_browseErrorLogName;
+    public String AboutSystemDialog_copyToClipboardName;
+    public String AboutSystemDialog_noLogTitle;
+    public String AboutSystemDialog_noLogMessage;
+
+
+    public String AboutSystemPage_FetchJobTitle;
+
+
+    public String AboutSystemPage_RetrievingSystemInfo;
+
+    // --- Shortcutbar ---
+    public String PerspectiveBarContributionItem_toolTip;
+    public String PerspectiveBarNewContributionItem_toolTip;
+
+    //--- Coolbar ---
+    public String WorkbenchWindow_FileToolbar;
+    public String WorkbenchWindow_NavigateToolbar;
+    public String WorkbenchWindow_HelpToolbar;
+    public String WorkbenchWindow_searchCombo_toolTip;
+    public String WorkbenchWindow_searchCombo_text;
+
+
+    public String WorkbenchWindow_close;
+    public String WorkbenchPage_ErrorCreatingPerspective;
+
+    public String SelectWorkingSetAction_text;
+    public String SelectWorkingSetAction_toolTip;
+    public String EditWorkingSetAction_text;
+    public String EditWorkingSetAction_toolTip;
+    public String EditWorkingSetAction_error_nowizard_title;
+    public String EditWorkingSetAction_error_nowizard_message;
+    public String ClearWorkingSetAction_text;
+    public String ClearWorkingSetAction_toolTip;
+    public String WindowWorkingSets;
+    public String NoWorkingSet;
+    public String SelectedWorkingSets;
+    public String NoApplicableWorkingSets;
+
+    // ==============================================================================
+    // Drill Actions
+    // ==============================================================================
+    public String GoHome_text;
+    public String GoHome_toolTip;
+    public String GoBack_text;
+    public String GoBack_toolTip;
+    public String GoInto_text;
+    public String GoInto_toolTip;
+
+
+    public String ICategory_other;
+    public String ICategory_general;
+
+    // ==============================================================================
+    // Wizards
+    // ==============================================================================
+    public String NewWizard_title;
+    public String NewWizardNewPage_description;
+    public String NewWizardNewPage_wizardsLabel;
+    public String NewWizardNewPage_showAll;
+    public String WizardList_description;
+    public String Select;
+    public String NewWizardSelectionPage_description;
+    public String NewWizardShortcutAction_errorTitle;
+    public String NewWizardShortcutAction_errorMessage;
+
+    public String NewWizardsRegistryReader_otherCategory;
+    public String NewWizardDropDown_text;
+
+    public String WizardHandler_menuLabel;
+    public String WorkbenchWizard_errorMessage;
+    public String WorkbenchWizard_errorTitle;
+    public String WizardTransferPage_selectAll;
+    public String WizardTransferPage_deselectAll;
+    public String TypesFiltering_title;
+    public String TypesFiltering_message;
+    public String TypesFiltering_otherExtensions;
+    public String TypesFiltering_typeDelimiter;
+
+    // --- Import/Export ---
+    public String ImportExportPage_chooseImportWizard;
+    public String ImportExportPage_chooseExportWizard;
+
+    // --- Import ---
+    public String ImportWizard_title;
+    public String ImportWizard_selectWizard;
+
+    // --- Export ---
+    public String ExportWizard_title;
+    public String ExportWizard_selectWizard;
+    // --- New Project ---
+    public String NewProject_title;
+
+    // ==============================================================================
+    // Preference Pages
+    // ==============================================================================
+    public String PreferenceNode_errorMessage;
+    public String PreferenceNode_NotFound;
+    public String Preference_note;
+
+    // --- Workbench ---
+    public String WorkbenchPreference_showMultipleEditorTabsButton;
+    public String WorkbenchPreference_allowInplaceEditingButton;
+    public String WorkbenchPreference_useIPersistableEditorButton;
+    public String WorkbenchPreference_promptWhenStillOpenButton;
+    public String WorkbenchPreference_stickyCycleButton;
+    public String WorkbenchPreference_RunInBackgroundButton;
+    public String WorkbenchPreference_RunInBackgroundToolTip;
+
+    // --- Appearance ---
+    public String ViewsPreferencePage_Theme;
+    public String ViewsPreference_currentTheme;
+    public String ViewsPreference_currentThemeDescription;
+    public String ViewsPreference_currentThemeFormat;
+    public String ViewsPreference_enableAnimations;
+    public String ViewsPreference_visibleTabs_description;
+    public String ViewsPreference_enableMRU;
+    public String ViewsPreference_useColoredLabels;
+    public String ToggleFullScreenMode_ActivationPopup_Description;
+    public String ToggleFullScreenMode_ActivationPopup_Description_NoKeybinding;
+    public String ToggleFullScreenMode_ActivationPopup_DoNotShowAgain;
+
+    // --- File Editors ---
+    public String FileEditorPreference_fileTypes;
+    public String FileEditorPreference_add;
+    public String FileEditorPreference_remove;
+    public String FileEditorPreference_associatedEditors;
+    public String FileEditorPreference_addEditor;
+    public String FileEditorPreference_removeEditor;
+    public String FileEditorPreference_default;
+    public String FileEditorPreference_existsTitle;
+    public String FileEditorPreference_existsMessage;
+    public String FileEditorPreference_defaultLabel;
+    public String FileEditorPreference_contentTypesRelatedLink;
+    public String FileEditorPreference_isLocked;
+
+    public String FileExtension_extensionEmptyMessage;
+    public String FileExtension_fileNameInvalidMessage;
+    public String FilteredPreferenceDialog_Key_Scrolling;
+
+
+    public String FilteredPreferenceDialog_PreferenceSaveFailed;
+    public String FilteredPreferenceDialog_Resize;
+    public String FilteredPreferenceDialog_FilterToolTip;
+
+    public String FileExtension_fileTypeMessage;
+    public String FileExtension_fileTypeLabel;
+    public String FileExtension_shellTitle;
+    public String FileExtension_dialogTitle;
+
+    public String Choose_the_editor_for_file;
+    public String EditorSelection_chooseAnEditor;
+    public String EditorSelection_internal;
+    public String EditorSelection_external;
+    public String EditorSelection_rememberEditor;
+    public String EditorSelection_rememberType;
+    public String EditorSelection_browse;
+    public String EditorSelection_title;
+
+    // --- Perspectives ---
+    public String OpenPerspectiveMode_optionsTitle;
+    public String OpenPerspectiveMode_sameWindow;
+    public String OpenPerspectiveMode_newWindow;
+
+    public String PerspectivesPreference_MakeDefault;
+    public String PerspectivesPreference_MakeDefaultTip;
+    public String PerspectivesPreference_Reset;
+    public String PerspectivesPreference_ResetTip;
+    public String PerspectivesPreference_Delete;
+    public String PerspectivesPreference_DeleteTip;
+    public String PerspectivesPreference_available;
+    public String PerspectivesPreference_defaultLabel;
+    public String PerspectivesPreference_perspectiveopen_title;
+    public String PerspectivesPreference_perspectiveopen_message;
+
+    public String PerspectiveLabelProvider_unknown;
+
+    //---- General Preferences----
+    public String PreferencePage_noDescription;
+    public String PreferencePageParameterValues_pageLabelSeparator;
+
+    // --- Workbench -----
+    public String WorkbenchPreference_openMode;
+    public String WorkbenchPreference_doubleClick;
+    public String WorkbenchPreference_singleClick;
+    public String WorkbenchPreference_singleClick_SelectOnHover;
+    public String WorkbenchPreference_singleClick_OpenAfterDelay;
+    public String WorkbenchPreference_noEffectOnAllViews;
+    public String WorkbenchPreference_HeapStatusButton;
+    public String WorkbenchPreference_HeapStatusButtonToolTip;
+
+    // --- Globalization -----
+    public String GlobalizationPreference_nlExtensions;
+    public String GlobalizationPreference_layoutDirection;
+    public String GlobalizationPreference_bidiSupport;
+    public String GlobalizationPreference_textDirection;
+    public String GlobalizationPreference_defaultDirection;
+    public String GlobalizationPreference_ltrDirection;
+    public String GlobalizationPreference_autoDirection;
+    public String GlobalizationPreference_rtlDirection;
+    public String GlobalizationPreference_restartWidget;
+
+    // --- Fonts ---
+    public String FontsPreference_useSystemFont;
+
+    // --- Decorators ---
+    public String DecoratorsPreferencePage_description;
+    public String DecoratorsPreferencePage_decoratorsLabel;
+    public String DecoratorsPreferencePage_explanation;
+    public String DecoratorError;
+    public String DecoratorWillBeDisabled;
+
+    // --- Startup preferences ---
+    public String StartupPreferencePage_label;
+
+    // ==============================================================================
+    // Property Pages
+    // ==============================================================================
+    public String PropertyDialog_text;
+    public String PropertyDialog_toolTip;
+    public String PropertyDialog_messageTitle;
+    public String PropertyDialog_noPropertyMessage;
+    public String PropertyDialog_propertyMessage;
+    public String PropertyPageNode_errorMessage;
+
+    public String SystemInPlaceDescription_name;
+    public String SystemEditorDescription_name;
+
+    // ==============================================================================
+    // Dialogs
+    // ==============================================================================
+    public String Error;
+    public String Information;
+
+
+    public String InstallationDialog_ShellTitle;
+
+    public String Workbench_NeedsClose_Title;
+    public String Workbench_NeedsClose_Message;
+
+    public String ErrorPreferencePage_errorMessage;
+
+    public String ListSelection_title;
+    public String ListSelection_message;
+
+    public String SelectionDialog_selectLabel;
+    public String SelectionDialog_deselectLabel;
+
+    public String ElementTreeSelectionDialog_nothing_available;
+
+    public String CheckedTreeSelectionDialog_nothing_available;
+    public String CheckedTreeSelectionDialog_select_all;
+    public String CheckedTreeSelectionDialog_deselect_all;
+
+    // ==============================================================================
+    // Editor Framework
+    // ==============================================================================
+    public String EditorManager_saveResourcesMessage;
+    public String EditorManager_saveResourcesOptionallyMessage;
+    public String EditorManager_saveResourcesTitle;
+    public String EditorManager_systemEditorError;
+    public String EditorManager_siteIncorrect;
+    public String EditorManager_unknownEditorIDMessage;
+    public String EditorManager_errorOpeningExternalEditor;
+    public String EditorManager_operationFailed;
+    public String EditorManager_saveChangesQuestion;
+    public String EditorManager_closeWithoutPromptingOption;
+    public String EditorManager_saveChangesOptionallyQuestion;
+    public String EditorManager_missing_editor_descriptor;
+    public String EditorManager_no_in_place_support;
+    public String EditorManager_no_persisted_state;
+    public String EditorManager_no_input_factory_ID;
+    public String EditorManager_bad_element_factory;
+    public String EditorManager_create_element_returned_null;
+    public String EditorManager_wrong_createElement_result;
+    public String EditorManager_backgroundSaveJobName;
+    public String EditorManager_largeDocumentWarning;
+
+
+    public String ExternalEditor_errorMessage;
+    public String Save;
+    public String Save_Resource;
+    public String Saving_Modifications;
+    public String Save_All;
+    public String Dont_Save;
+
+	public String SaveableHelper_Save;
+	public String SaveableHelper_Cancel;
+	public String SaveableHelper_Dont_Save;
+	
+
+    // ==============================================================================
+    // Perspective Framework
+    // ==============================================================================
+    public String OpenNewPageMenu_dialogTitle;
+    public String OpenNewPageMenu_unknownPageInput;
+
+    public String OpenNewWindowMenu_dialogTitle;
+    public String OpenNewWindowMenu_unknownInput;
+
+    public String OpenPerspectiveMenu_pageProblemsTitle;
+    public String OpenPerspectiveMenu_errorUnknownInput;
+
+    public String Perspective_localCopyLabel;
+    public String WorkbenchPage_problemRestoringTitle;
+
+
+
+    // ==============================================================================
+    // Views Framework
+    // ==============================================================================
+    public String ViewLabel_unknown;
+
+    public String ViewFactory_initException;
+    public String ViewFactory_siteException;
+    public String ViewFactory_couldNotCreate;
+    // ==============================================================================
+    // Workbench
+    // ==============================================================================
+    public String Startup_Loading;
+    public String Startup_Loading_Workbench;
+    public String Startup_Done;
+
+    public String WorkbenchPage_UnknownLabel;
+
+
+    // These four keys are marked as unused by the NLS search, but they are indirectly used
+    // and should be removed.
+    public String PartPane_sizeLeft;
+    public String PartPane_sizeRight;
+    public String PartPane_sizeTop;
+    public String PartPane_sizeBottom;
+
+    public String PluginAction_operationNotAvailableMessage;
+    public String PluginAction_disabledMessage;
+    public String ActionDescriptor_invalidLabel;
+
+    public String XMLMemento_parserConfigError;
+    public String XMLMemento_ioError;
+    public String XMLMemento_formatError;
+    public String XMLMemento_noElement;
+
+    // --- Workbench Errors/Problems ---
+    public String WorkbenchWindow_exceptionMessage;
+    public String WorkbenchPage_AbnormalWorkbenchCondition;
+    public String WorkbenchPage_IllegalSecondaryId;
+    public String WorkbenchPage_IllegalViewMode;
+    public String WorkbenchPart_AutoTitleFormat;
+
+
+    public String AbstractWorkingSetManager_updatersActivating;
+    public String DecoratorManager_ErrorActivatingDecorator;
+
+    public String EditorRegistry_errorTitle;
+    public String EditorRegistry_errorMessage;
+
+    public String ErrorClosing;
+    public String ErrorClosingNoArg;
+    public String ErrorClosingOneArg;
+
+    public String SavingProblem;
+
+    public String Problems_Opening_Page;
+
+    public String Workbench_problemsSavingMsg;
+    public String Workbench_problemsRestoring;
+    public String Workbench_problemsSaving;
+
+    public String PageLayout_missingRefPart;
+
+    // ==============================================================================
+    // Keys used in the reuse editor which is released as experimental.
+    // ==============================================================================
+    public String EditorManager_openNewEditorLabel;
+    public String EditorManager_reuseEditorDialogTitle;
+    public String PinEditorAction_toolTip;
+    public String WorkbenchPreference_reuseEditors;
+    public String WorkbenchPreference_reuseEditorsThreshold;
+    public String WorkbenchPreference_reuseEditorsThresholdError;
+    public String WorkbenchPreference_recentFiles;
+    public String WorkbenchPreference_recentFilesError;
+    public String WorkbenchPreference_workbenchSaveInterval;
+    public String WorkbenchPreference_workbenchSaveIntervalError;
+    public String WorkbenchEditorsAction_label;
+    public String WorkbookEditorsAction_label;
+
+    public String WorkbenchEditorsDialog_title;
+    public String WorkbenchEditorsDialog_label;
+    public String WorkbenchEditorsDialog_closeSelected;
+    public String WorkbenchEditorsDialog_saveSelected;
+    public String WorkbenchEditorsDialog_selectClean;
+    public String WorkbenchEditorsDialog_invertSelection;
+    public String WorkbenchEditorsDialog_allSelection;
+    public String WorkbenchEditorsDialog_showAllPersp;
+    public String WorkbenchEditorsDialog_name;
+    public String WorkbenchEditorsDialog_path;
+    public String WorkbenchEditorsDialog_activate;
+    public String WorkbenchEditorsDialog_close;
+
+    public String ShowPartPaneMenuAction_text;
+    public String ShowPartPaneMenuAction_toolTip;
+    public String ShowViewMenuAction_text;
+    public String ShowViewMenuAction_toolTip;
+    public String QuickAccessAction_text;
+    public String QuickAccessAction_toolTip;
+
+    public String ToggleCoolbarVisibilityAction_show_text;
+    public String ToggleCoolbarVisibilityAction_hide_text;
+    public String ToggleCoolbarVisibilityAction_toolTip;
+
+	public String ToggleStatusBarVisibilityAction_show_text;
+	public String ToggleStatusBarVisibilityAction_hide_text;
+
+    // ==============================================================================
+    // Working Set Framework.
+    // ==============================================================================
+    public String ProblemSavingWorkingSetState_message;
+    public String ProblemSavingWorkingSetState_title;
+    public String ProblemRestoringWorkingSetState_message;
+
+    public String ProblemRestoringWorkingSetState_title;
+    public String ProblemCyclicDependency;
+
+    public String WorkingSetEditWizard_title;
+    public String WorkingSetNewWizard_title;
+
+    public String WorkingSetTypePage_description;
+    public String WorkingSetTypePage_typesLabel;
+
+    public String WorkingSetSelectionDialog_title;
+    public String WorkingSetSelectionDialog_title_multiSelect;
+    public String WorkingSetSelectionDialog_message;
+    public String WorkingSetSelectionDialog_message_multiSelect;
+    public String WorkingSetSelectionDialog_detailsButton_label;
+    public String WorkingSetSelectionDialog_newButton_label;
+    public String WorkingSetSelectionDialog_removeButton_label;
+
+    public String WorkbenchPage_workingSet_default_label;
+    public String WorkbenchPage_workingSet_multi_label;
+
+    // =================================================================
+    // System Summary
+    // =================================================================
+    public String SystemSummary_timeStamp;
+    public String SystemSummary_systemProperties;
+    public String SystemSummary_features;
+    public String SystemSummary_pluginRegistry;
+    public String SystemSummary_userPreferences;
+    public String SystemSummary_sectionTitle;
+    public String SystemSummary_sectionError;
+
+    // paramter 0 is the feature name, parameter 1 is the version and parameter 2 is the Id
+    public String SystemSummary_featureVersion;
+
+    public String SystemSummary_descriptorIdVersionState;
+
+    // =================================================================
+    // Editor List
+    // =================================================================
+    public String DecorationScheduler_UpdateJobName;
+    public String DecorationScheduler_CalculationJobName;
+    public String DecorationScheduler_UpdatingTask;
+    public String DecorationScheduler_CalculatingTask;
+    public String DecorationScheduler_ClearResultsJob;
+    public String DecorationScheduler_DecoratingSubtask;
+
+    public String PerspectiveBar_showText;
+    public String PerspectiveBar_customize;
+    public String PerspectiveBar_saveAs;
+    public String PerspectiveBar_reset;
+
+    public String WorkbenchPlugin_extension;
+
+    public String EventLoopProgressMonitor_OpenDialogJobName;
+    public String DecorationReference_EmptyReference;
+    public String RectangleAnimation_Animating_Rectangle;
+    public String FilteredList_UpdateJobName;
+    public String FilteredTree_ClearToolTip;
+    public String FilteredTree_FilterMessage;
+    public String FilteredTree_FilteredDialogTitle;
+    public String FilteredTree_AccessibleListenerClearButton;
+    public String FilteredTree_AccessibleListenerFiltered;
+    public String Workbench_startingPlugins;
+    public String ScopedPreferenceStore_DefaultAddedError;
+
+    public String WorkbenchEncoding_invalidCharset;
+
+    //==============================================================
+    // Undo/Redo Support
+
+    public String Operations_undoCommand;
+    public String Operations_redoCommand;
+    public String Operations_undoTooltipCommand;
+    public String Operations_redoTooltipCommand;
+    public String Operations_undoRedoCommandDisabled;
+    public String Operations_undoProblem;
+    public String Operations_redoProblem;
+    public String Operations_executeProblem;
+    public String Operations_undoInfo;
+    public String Operations_redoInfo;
+    public String Operations_executeInfo;
+    public String Operations_undoWarning;
+    public String Operations_redoWarning;
+    public String Operations_executeWarning;
+    public String Operations_linearUndoViolation;
+    public String Operations_linearRedoViolation;
+    public String Operations_nonLocalUndoWarning;
+    public String Operations_nonLocalRedoWarning;
+    public String Operations_discardUndo;
+    public String Operations_discardRedo;
+    public String Operations_proceedWithNonOKExecuteStatus;
+    public String Operations_proceedWithNonOKUndoStatus;
+    public String Operations_proceedWithNonOKRedoStatus;
+    public String Operations_stoppedOnExecuteErrorStatus;
+    public String Operations_stoppedOnUndoErrorStatus;
+    public String Operations_stoppedOnRedoErrorStatus;
+
+    //==============================================================
+    // Heap Status
+
+    public String HeapStatus_status;
+    public String HeapStatus_widthStr;
+    public String HeapStatus_memoryToolTip;
+    public String HeapStatus_meg;
+    public String HeapStatus_maxUnknown;
+    public String HeapStatus_noMark;
+    public String HeapStatus_buttonToolTip;
+    public String SetMarkAction_text;
+    public String ClearMarkAction_text;
+    public String ShowMaxAction_text;
+
+    public String SplitValues_Horizontal;
+
+
+    public String SplitValues_Vertical;
+
+
+    // ==============================================================================
+    // Content Types preference page
+    // ==============================================================================
+
+    public String ContentTypes_lockedFormat;
+    public String ContentTypes_characterSetLabel;
+    public String ContentTypes_characterSetUpdateLabel;
+    public String ContentTypes_unsupportedEncoding;
+    public String ContentTypes_fileAssociationsLabel;
+    public String ContentTypes_fileAssociationsAddLabel;
+    public String ContentTypes_fileAssociationsEditLabel;
+    public String ContentTypes_fileAssociationsRemoveLabel;
+    public String ContentTypes_contentTypesLabel;
+    public String ContentTypes_errorDialogMessage;
+    public String ContentTypes_FileEditorsRelatedLink;
+    public String ContentTypes_addDialog_title;
+    public String ContentTypes_addDialog_messageHeader;
+    public String ContentTypes_addDialog_message;
+    public String ContentTypes_addDialog_label;
+    public String ContentTypes_editDialog_title;
+    public String ContentTypes_editDialog_messageHeader;
+    public String ContentTypes_editDialog_message;
+    public String ContentTypes_editDialog_label;
+   	public String ContentTypes_addRootContentTypeButton;
+	public String ContentTypes_addChildContentTypeButton;
+	public String ContentTypes_removeContentTypeButton;
+	public String ContentTypes_newContentTypeDialog_title;
+	public String ContentTypes_newContentTypeDialog_descritption;
+	public String ContentTypes_newContentTypeDialog_nameLabel;
+	public String ContentTypes_newContentTypeDialog_defaultNameNoParent;
+	public String ContentTypes_newContentTypeDialog_defaultNameWithParent;
+	public String ContentTypes_newContentTypeDialog_invalidContentTypeName;
+	public String ContentTypes_failedAtEditingContentTypes;
+    public String Edit;
+
+    // =========================================================================
+    // Deprecated actions support
+    // =========================================================================
+    public String CommandService_AutogeneratedCategoryName;
+    public String CommandService_AutogeneratedCategoryDescription;
+    public String LegacyActionPersistence_AutogeneratedCommandName;
+
+    // ==============================================================================
+    // Trim Common UI
+    // ==============================================================================
+
+    // Trim Menu item labels
+    public String TrimCommon_DockOn;
+    public String TrimCommon_Left;
+    public String TrimCommon_Right;
+    public String TrimCommon_Bottom;
+    public String TrimCommon_Top;
+    public String TrimCommon_Close;
+
+    // Trim area Display Names
+    public String TrimCommon_Progress_TrimName;
+
+    // FilteredItemsSelectionDialog
+    public String FilteredItemsSelectionDialog_cacheSearchJob_taskName;
+    public String FilteredItemsSelectionDialog_menu;
+    public String FilteredItemsSelectionDialog_refreshJob;
+    public String FilteredItemsSelectionDialog_progressRefreshJob;
+    public String FilteredItemsSelectionDialog_cacheRefreshJob;
+    public String FilteredItemsSelectionDialog_cacheRefreshJob_checkDuplicates;
+    public String FilteredItemsSelectionDialog_cacheRefreshJob_getFilteredElements;
+    public String FilteredItemsSelectionDialog_patternLabel;
+    public String FilteredItemsSelectionDialog_listLabel;
+    public String FilteredItemsSelectionDialog_toggleStatusAction;
+    public String FilteredItemsSelectionDialog_removeItemsFromHistoryAction;
+    public String FilteredItemsSelectionDialog_searchJob_taskName;
+    public String FilteredItemsSelectionDialog_separatorLabel;
+    public String FilteredItemsSelectionDialog_storeError;
+    public String FilteredItemsSelectionDialog_restoreError;
+    public String FilteredItemsSelectionDialog_nItemsSelected;
+
+    // AbstractSearcher
+    public String FilteredItemsSelectionDialog_jobLabel;
+    public String FilteredItemsSelectionDialog_jobError;
+
+    // GranualProgressMonitor
+    public String FilteredItemsSelectionDialog_taskProgressMessage;
+    public String FilteredItemsSelectionDialog_subtaskProgressMessage;
+
+    static {
+        // load message values from bundle file
+        NLS.initializeMessages(BUNDLE_NAME, WorkbenchMessages.class);
+    }
+
+
+    // Content assist support
+    public String ContentAssist_Cue_Description_Key;
+
+    //Settings transfer
+    public String WorkbenchLayoutSettings_Name;
+    public String WorkbenchSettings_CouldNotCreateDirectories;
+    public String WorkbenchSettings_CouldNotFindLocation;
+    public String WorkingSets_Name;
+    public String WorkingSets_CannotSave;
+    public String WorkbenchPreferences_Name;
+
+    // StatusDialog
+    public String WorkbenchStatusDialog_SupportTooltip;
+    public String WorkbenchStatusDialog_SupportHyperlink;
+    public String WorkbenchStatusDialog_StatusWithChildren;
+    public String WorkbenchStatusDialog_SeeDetails;
+    public String WorkbenchStatusDialog_MultipleProblemsHaveOccured;
+    public String WorkbenchStatusDialog_ProblemOccurred;
+    public String WorkbenchStatusDialog_ProblemOccurredInJob;
+
+    public String StackTraceSupportArea_NoStackTrace;
+    public String StackTraceSupportArea_CausedBy;
+    public String StackTraceSupportArea_Title;
+
+    public String ErrorLogUtil_ShowErrorLogTooltip;
+    public String ErrorLogUtil_ShowErrorLogHyperlink;
+
+    // WorkingSetConfigurationBlock
+    public String WorkingSetConfigurationBlock_SelectWorkingSet_button;
+    public String WorkingSetConfigurationBlock_NewWorkingSet_button;
+    public String WorkingSetConfigurationBlock_WorkingSetText_name;
+
+    public String WorkingSetPropertyPage_ReadOnlyWorkingSet_description;
+    public String WorkingSetPropertyPage_ReadOnlyWorkingSet_title;
+
+    public String WorkingSetGroup_WorkingSets_group;
+    public String WorkingSetGroup_WorkingSetSelection_message;
+    public String WorkingSetGroup_EnableWorkingSet_button;
+
+	public String FilteredTableBaseHandler_Close;
+
+    // Util
+    public String Util_List;
+    public String Util_listNull;
+
+    /**
+     * Load message values from bundle file
+     * @return localized message
+     */
+    /**
+     * Load message values from bundle file
+     * @return localized message
+     */
+    public static WorkbenchMessages get() {
+      return RWT.NLS.getISO8859_1Encoded( BUNDLE_NAME, WorkbenchMessages.class );
+    }
+
+    public static WorkbenchMessages get( Display display ) {
+      final WorkbenchMessages[] result = { null };
+      RWT.getUISession( display ).exec( new Runnable() {
+        public void run() {
+          result[ 0 ] = get();
+        }
+      } );
+      return result[ 0 ];
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchPage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchPage.java
new file mode 100644
index 0000000..b2742ba
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchPage.java
@@ -0,0 +1,5662 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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
+ *     Christian Janz  - <christian.janz@gmail.com> Fix for Bug 385592
+ *     Marc-Andre Laperle (Ericsson) - Fix for Bug 413590
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 431340, 431348, 426535, 433234, 431868, 472654
+ *     Cornel Izbasa <cizbasa@info.uvt.ro> - Bug 442214
+ *     Andrey Loskutov <loskutov@gmx.de> - Bug 411639, 372799, 466230
+ *     Dirk Fauth <dirk.fauth@googlemail.com> - Bug 473063
+ *******************************************************************************/
+
+package org.eclipse.ui.internal;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
+import org.eclipse.e4.core.contexts.ContextInjectionFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.di.annotations.Optional;
+import org.eclipse.e4.core.services.events.IEventBroker;
+import org.eclipse.e4.ui.di.UIEventTopic;
+import org.eclipse.e4.ui.internal.workbench.PartServiceImpl;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.descriptor.basic.MPartDescriptor;
+import org.eclipse.e4.ui.model.application.ui.MElementContainer;
+import org.eclipse.e4.ui.model.application.ui.MGenericStack;
+import org.eclipse.e4.ui.model.application.ui.MUIElement;
+import org.eclipse.e4.ui.model.application.ui.advanced.MArea;
+import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective;
+import org.eclipse.e4.ui.model.application.ui.advanced.MPerspectiveStack;
+import org.eclipse.e4.ui.model.application.ui.advanced.MPlaceholder;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.model.application.ui.basic.MPartSashContainer;
+import org.eclipse.e4.ui.model.application.ui.basic.MPartSashContainerElement;
+import org.eclipse.e4.ui.model.application.ui.basic.MPartStack;
+import org.eclipse.e4.ui.model.application.ui.basic.MStackElement;
+import org.eclipse.e4.ui.model.application.ui.basic.MTrimElement;
+import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
+import org.eclipse.e4.ui.model.application.ui.basic.MWindowElement;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolControl;
+import org.eclipse.e4.ui.workbench.IPresentationEngine;
+import org.eclipse.e4.ui.workbench.UIEvents;
+import org.eclipse.e4.ui.workbench.UIEvents.EventTags;
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+import org.eclipse.e4.ui.workbench.modeling.EPartService;
+import org.eclipse.e4.ui.workbench.modeling.EPartService.PartState;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.jface.dialogs.DialogSettings;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.dialogs.IPageChangeProvider;
+import org.eclipse.jface.dialogs.IPageChangedListener;
+import org.eclipse.jface.dialogs.PageChangedEvent;
+import org.eclipse.jface.internal.provisional.action.ICoolBarManager2;
+import org.eclipse.jface.operation.IRunnableContext;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.jface.util.SafeRunnable;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.window.Window;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.swt.dnd.DND;
+import org.eclipse.swt.dnd.DropTarget;
+import org.eclipse.swt.dnd.DropTargetListener;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IEditorDescriptor;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorLauncher;
+import org.eclipse.ui.IEditorMatchingStrategy;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorReference;
+import org.eclipse.ui.IEditorRegistry;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.INavigationHistory;
+import org.eclipse.ui.IPageLayout;
+import org.eclipse.ui.IPartListener;
+import org.eclipse.ui.IPartListener2;
+import org.eclipse.ui.IPathEditorInput;
+import org.eclipse.ui.IPersistableEditor;
+import org.eclipse.ui.IPersistableElement;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.IPerspectiveFactory;
+import org.eclipse.ui.IPerspectiveRegistry;
+import org.eclipse.ui.IReusableEditor;
+import org.eclipse.ui.ISaveablePart;
+import org.eclipse.ui.ISaveablePart2;
+import org.eclipse.ui.ISaveablesLifecycleListener;
+import org.eclipse.ui.ISaveablesSource;
+import org.eclipse.ui.ISelectionListener;
+import org.eclipse.ui.ISelectionService;
+import org.eclipse.ui.IShowEditorInput;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IViewReference;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartReference;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.IWorkbenchPreferenceConstants;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.IWorkingSet;
+import org.eclipse.ui.IWorkingSetManager;
+import org.eclipse.ui.MultiPartInitException;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.Saveable;
+import org.eclipse.ui.WorkbenchException;
+import org.eclipse.ui.XMLMemento;
+import org.eclipse.ui.contexts.IContextService;
+import org.eclipse.ui.dialogs.EditorSelectionDialog;
+import org.eclipse.ui.internal.dialogs.cpd.CustomizePerspectiveDialog;
+import org.eclipse.ui.internal.e4.compatibility.CompatibilityEditor;
+import org.eclipse.ui.internal.e4.compatibility.CompatibilityPart;
+import org.eclipse.ui.internal.e4.compatibility.CompatibilityView;
+import org.eclipse.ui.internal.e4.compatibility.E4Util;
+import org.eclipse.ui.internal.e4.compatibility.ModeledPageLayout;
+import org.eclipse.ui.internal.e4.compatibility.SelectionService;
+import org.eclipse.ui.internal.menus.MenuHelper;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.internal.misc.UIListenerLogging;
+import org.eclipse.ui.internal.progress.ProgressManagerUtil;
+import org.eclipse.ui.internal.registry.ActionSetRegistry;
+import org.eclipse.ui.internal.registry.EditorDescriptor;
+import org.eclipse.ui.internal.registry.IActionSetDescriptor;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.registry.PerspectiveDescriptor;
+import org.eclipse.ui.internal.registry.PerspectiveRegistry;
+import org.eclipse.ui.internal.registry.UIExtensionTracker;
+import org.eclipse.ui.internal.registry.ViewDescriptor;
+import org.eclipse.ui.internal.tweaklets.TabBehaviour;
+import org.eclipse.ui.internal.tweaklets.Tweaklets;
+import org.eclipse.ui.internal.util.PrefUtil;
+import org.eclipse.ui.internal.util.Util;
+import org.eclipse.ui.model.IWorkbenchAdapter;
+import org.eclipse.ui.part.IShowInSource;
+import org.eclipse.ui.part.ShowInContext;
+import org.eclipse.ui.statushandlers.StatusManager;
+import org.eclipse.ui.views.IStickyViewDescriptor;
+import org.eclipse.ui.views.IViewDescriptor;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventHandler;
+
+/**
+ * A collection of views and editors in a workbench.
+ */
+public class WorkbenchPage implements IWorkbenchPage {
+
+	private static final String ATT_AGGREGATE_WORKING_SET_ID = "aggregateWorkingSetId"; //$NON-NLS-1$
+	
+	private static final int WINDOW_SCOPE = EModelService.OUTSIDE_PERSPECTIVE
+			| EModelService.IN_ANY_PERSPECTIVE | EModelService.IN_SHARED_AREA;
+
+	class E4PartListener implements org.eclipse.e4.ui.workbench.modeling.IPartListener {
+
+		@Override
+		public void partActivated(MPart part) {
+			// update the workbench window's current selection with the active
+			// part's selection
+			IWorkbenchPart workbenchPart = getWorkbenchPart(part);
+			selectionService.updateSelection(workbenchPart);
+
+			updateActivations(part);
+			firePartActivated(part);
+			selectionService.notifyListeners(workbenchPart);
+		}
+
+		@Override
+		public void partBroughtToTop(MPart part) {
+			updateBroughtToTop(part);
+			firePartBroughtToTop(part);
+		}
+
+		@Override
+		public void partDeactivated(MPart part) {
+			firePartDeactivated(part);
+
+			Object client = part.getObject();
+			if (client instanceof CompatibilityPart) {
+				CompatibilityPart compatibilityPart = (CompatibilityPart) client;
+				IWorkbenchPartSite site = compatibilityPart.getPart().getSite();
+				// if it's an editor, we only want to disable the actions
+				((PartSite) site).deactivateActionBars(site instanceof ViewSite);
+			}
+
+			WorkbenchWindow wwindow = (WorkbenchWindow) getWorkbenchWindow();
+			if (!wwindow.isClosing()) {
+				wwindow.getStatusLineManager().update(false);
+			}
+		}
+
+		@Override
+		public void partHidden(MPart part) {
+			firePartHidden(part);
+		}
+
+		@Override
+		public void partVisible(MPart part) {
+			firePartVisible(part);
+		}
+	}
+
+	ArrayList<MPart> activationList = new ArrayList<>();
+
+	/**
+	 * Cached perspective stack for this workbench page.
+	 */
+	private MPerspectiveStack _perspectiveStack;
+
+	/** Ids of parts used as Show In targets, maintained in MRU order */
+	private List<String> mruShowInPartIds = new ArrayList<>();
+
+	/**
+	 * Deactivate the last editor's action bars if another type of editor has //
+	 * * been activated.
+	 *
+	 * @param part
+	 *            the part that is being activated
+	 */
+	private void deactivateLastEditor(MPart part) {
+		Object client = part.getObject();
+		// we only care if the currently activated part is an editor
+		if (client instanceof CompatibilityEditor) {
+			// find another editor that was last activated
+			for (MPart previouslyActive : activationList) {
+				if (previouslyActive != part) {
+					Object object = previouslyActive.getObject();
+					if (object instanceof CompatibilityEditor) {
+						EditorSite site = (EditorSite) ((CompatibilityEditor) object).getPart()
+								.getSite();
+						String lastId = site.getId();
+						String activeId = ((CompatibilityEditor) client).getPart().getSite()
+								.getId();
+						// if not the same, hide the other editor's action bars
+						if (lastId != null && !lastId.equals(activeId)) {
+							site.deactivateActionBars(true);
+						}
+						break;
+					}
+				}
+			}
+		}
+	}
+
+	private void updateActivations(MPart part) {
+		if (activationList.size() > 1) {
+			deactivateLastEditor(part);
+		}
+
+		activationList.remove(part);
+		activationList.add(0, part);
+		updateActivePartSources(part);
+		updateActiveEditorSources(part);
+
+		Object client = part.getObject();
+		if (client instanceof CompatibilityPart) {
+			IWorkbenchPart workbenchPart = ((CompatibilityPart) client).getPart();
+			PartSite site = (PartSite) workbenchPart.getSite();
+			site.activateActionBars(true);
+
+			IActionBars actionBars = site.getActionBars();
+			if (actionBars instanceof EditorActionBars) {
+				((EditorActionBars) actionBars).partChanged(workbenchPart);
+			}
+		}
+
+		((WorkbenchWindow) getWorkbenchWindow()).getStatusLineManager().update(false);
+
+		IWorkbenchPart workbenchPart = getWorkbenchPart(part);
+		actionSwitcher.updateActivePart(workbenchPart);
+	}
+
+	private void updateActivePartSources(MPart part) {
+		IWorkbenchPart workbenchPart = getWorkbenchPart(part);
+		IContextService cs = legacyWindow.getService(IContextService.class);
+		try {
+			cs.deferUpdates(true);
+			if (workbenchPart == null) {
+				window.getContext().set(ISources.ACTIVE_PART_NAME, null);
+				window.getContext().set(ISources.ACTIVE_PART_ID_NAME, null);
+				window.getContext().set(ISources.ACTIVE_SITE_NAME, null);
+			} else {
+				window.getContext().set(ISources.ACTIVE_PART_NAME, workbenchPart);
+				window.getContext().set(ISources.ACTIVE_PART_ID_NAME, workbenchPart.getSite().getId());
+				window.getContext().set(ISources.ACTIVE_SITE_NAME, workbenchPart.getSite());
+			}
+		} finally {
+			cs.deferUpdates(false);
+		}
+	}
+
+	private void updateActionSets(Perspective oldPersp, Perspective newPersp) {
+		// Update action sets
+
+		IContextService service = legacyWindow.getService(IContextService.class);
+		try {
+			service.deferUpdates(true);
+			if (newPersp != null) {
+				List<IActionSetDescriptor> newAlwaysOn = newPersp.getAlwaysOnActionSets();
+				for (int i = 0; i < newAlwaysOn.size(); i++) {
+					IActionSetDescriptor descriptor = newAlwaysOn.get(i);
+
+					actionSets.showAction(descriptor);
+				}
+
+				List<IActionSetDescriptor> newAlwaysOff = newPersp.getAlwaysOffActionSets();
+				for (int i = 0; i < newAlwaysOff.size(); i++) {
+					IActionSetDescriptor descriptor = newAlwaysOff.get(i);
+
+					actionSets.maskAction(descriptor);
+				}
+			}
+
+			if (oldPersp != null) {
+				List<IActionSetDescriptor> oldAlwaysOn = oldPersp.getAlwaysOnActionSets();
+				for (int i = 0; i < oldAlwaysOn.size(); i++) {
+					IActionSetDescriptor descriptor = oldAlwaysOn.get(i);
+
+					actionSets.hideAction(descriptor);
+				}
+
+				List<IActionSetDescriptor> oldAlwaysOff = oldPersp.getAlwaysOffActionSets();
+				for (int i = 0; i < oldAlwaysOff.size(); i++) {
+					IActionSetDescriptor descriptor = oldAlwaysOff.get(i);
+
+					actionSets.unmaskAction(descriptor);
+				}
+			}
+		} finally {
+			service.deferUpdates(false);
+		}
+	}
+
+	private IWorkbenchPart getWorkbenchPart(MPart part) {
+		if (part != null) {
+			Object clientObject = part.getObject();
+			if (clientObject instanceof CompatibilityPart) {
+				return ((CompatibilityPart) clientObject).getPart();
+			} else if (clientObject != null) {
+				if (part.getTransientData().get(E4PartWrapper.E4_WRAPPER_KEY) instanceof E4PartWrapper) {
+					return (IWorkbenchPart) part.getTransientData().get(
+							E4PartWrapper.E4_WRAPPER_KEY);
+				}
+
+				ViewReference viewReference = getViewReference(part);
+				if (viewReference != null) {
+					E4PartWrapper legacyPart = E4PartWrapper.getE4PartWrapper(part);
+					try {
+						viewReference.initialize(legacyPart);
+					} catch (PartInitException e) {
+						WorkbenchPlugin.log(e);
+					}
+					part.getTransientData().put(E4PartWrapper.E4_WRAPPER_KEY, legacyPart);
+					return legacyPart;
+				}
+			}
+		}
+		return null;
+	}
+
+	private void updateActiveEditorSources(MPart part) {
+		IEditorPart editor = getEditor(part);
+		window.getContext().set(ISources.ACTIVE_EDITOR_ID_NAME,
+				editor == null ? null : editor.getSite().getId());
+		window.getContext().set(ISources.ACTIVE_EDITOR_NAME, editor);
+		window.getContext().set(ISources.ACTIVE_EDITOR_INPUT_NAME,
+				editor == null ? null : editor.getEditorInput());
+
+		if (editor != null) {
+			navigationHistory.markEditor(editor);
+		}
+		actionSwitcher.updateTopEditor(editor);
+	}
+
+	public void updateShowInSources(MPart part) {
+
+		IWorkbenchPart workbenchPart = getWorkbenchPart(part);
+		ShowInContext context = getContext(workbenchPart);
+		if (context != null) {
+			window.getContext().set(ISources.SHOW_IN_INPUT, context.getInput());
+			window.getContext().set(ISources.SHOW_IN_SELECTION, context.getSelection());
+		}
+	}
+
+	private IShowInSource getShowInSource(IWorkbenchPart sourcePart) {
+		return Adapters.adapt(sourcePart, IShowInSource.class);
+	}
+
+	private ShowInContext getContext(IWorkbenchPart sourcePart) {
+		IShowInSource source = getShowInSource(sourcePart);
+		if (source != null) {
+			ShowInContext context = source.getShowInContext();
+			if (context != null) {
+				return context;
+			}
+		} else if (sourcePart instanceof IEditorPart) {
+			Object input = ((IEditorPart) sourcePart).getEditorInput();
+			ISelectionProvider sp = sourcePart.getSite().getSelectionProvider();
+			ISelection sel = sp == null ? null : sp.getSelection();
+			return new ShowInContext(input, sel);
+		}
+		return null;
+	}
+
+	private IEditorPart getEditor(MPart part) {
+		if (part != null) {
+			Object clientObject = part.getObject();
+			if (clientObject instanceof CompatibilityEditor) {
+				return ((CompatibilityEditor) clientObject).getEditor();
+			}
+		}
+		return getActiveEditor();
+	}
+
+	private void updateBroughtToTop(MPart part) {
+		updateActiveEditorSources(part);
+		IWorkbenchPart workbenchPart = getWorkbenchPart(part);
+		if (workbenchPart instanceof IEditorPart) {
+			navigationHistory.markEditor((IEditorPart) workbenchPart);
+		}
+
+		MElementContainer<?> parent = part.getParent();
+		if (parent == null) {
+			MPlaceholder placeholder = part.getCurSharedRef();
+			if (placeholder == null) {
+				return;
+			}
+
+			parent = placeholder.getParent();
+		}
+
+		if (parent instanceof MPartStack) {
+			int newIndex = lastIndexOfContainer(parent);
+			// New index can be -1 if there is no last index
+			if (newIndex >= 0 && part == activationList.get(newIndex)) {
+				return;
+			}
+			activationList.remove(part);
+			if (newIndex >= 0 && newIndex < activationList.size() - 1) {
+				activationList.add(newIndex, part);
+			} else {
+				activationList.add(part);
+			}
+		}
+	}
+
+	private int lastIndexOfContainer(MElementContainer<?> parent) {
+		for (int i = 0; i < activationList.size(); i++) {
+			MPart mPart = activationList.get(i);
+			MElementContainer<MUIElement> container = mPart.getParent();
+			if (container == parent) {
+				return i;
+			} else if (container == null) {
+				MPlaceholder placeholder = mPart.getCurSharedRef();
+				if (placeholder != null && placeholder.getParent() == parent) {
+					return i;
+				}
+			}
+		}
+		return -1;
+	}
+
+	private List<ViewReference> viewReferences = new ArrayList<>();
+	private List<EditorReference> editorReferences = new ArrayList<>();
+
+	private List<IPerspectiveDescriptor> sortedPerspectives = new ArrayList<>();
+
+	private ListenerList<IPartListener> partListenerList = new ListenerList<>();
+	private ListenerList<IPartListener2> partListener2List = new ListenerList<>();
+
+	/**
+	 * A listener that forwards page change events to our part listeners.
+	 */
+	private IPageChangedListener pageChangedListener = new IPageChangedListener() {
+		@Override
+		public void pageChanged(final PageChangedEvent event) {
+			for (final IPartListener2 listener : partListener2List) {
+				if (listener instanceof IPageChangedListener) {
+					SafeRunner.run(new SafeRunnable() {
+						@Override
+						public void run() throws Exception {
+							((IPageChangedListener) listener).pageChanged(event);
+						}
+					});
+				}
+			}
+		}
+	};
+
+	private E4PartListener e4PartListener = new E4PartListener();
+
+	protected WorkbenchWindow legacyWindow;
+
+    private IAdaptable input;
+
+    private IWorkingSet workingSet;
+
+    private AggregateWorkingSet aggregateWorkingSet;
+
+    private Composite composite;
+
+	private ListenerList<IPropertyChangeListener> propertyChangeListeners = new ListenerList<>();
+
+    private IActionBars actionBars;
+
+    private ActionSetManager actionSets;
+
+    private NavigationHistory navigationHistory = new NavigationHistory(this);
+
+
+    /**
+     * If we're in the process of activating a part, this points to the new part.
+     * Otherwise, this is null.
+     */
+    private IWorkbenchPartReference partBeingActivated = null;
+
+
+
+    private IPropertyChangeListener workingSetPropertyChangeListener = new IPropertyChangeListener() {
+        /*
+         * Remove the working set from the page if the working set is deleted.
+         */
+        @Override
+		public void propertyChange(PropertyChangeEvent event) {
+            String property = event.getProperty();
+            if (IWorkingSetManager.CHANGE_WORKING_SET_REMOVE.equals(property)) {
+            		if(event.getOldValue().equals(workingSet)) {
+						setWorkingSet(null);
+					}
+
+            		// room for optimization here
+				List<IWorkingSet> newList = new ArrayList<>(Arrays.asList(workingSets));
+				if (newList.remove(event.getOldValue())) {
+					setWorkingSets(newList.toArray(new IWorkingSet[newList.size()]));
+				}
+            }
+        }
+    };
+
+	private ActionSwitcher actionSwitcher = new ActionSwitcher();
+
+	private IExtensionTracker tracker;
+
+    // Deferral count... delays disposing parts and sending certain events if nonzero
+    private int deferCount = 0;
+
+
+	private IWorkingSet[] workingSets = new IWorkingSet[0];
+	private String aggregateWorkingSetId;
+
+	// determines if a prompt is shown when opening large files
+	private long maxFileSize = 0;
+	private boolean checkDocumentSize;
+
+	/**
+	 * Manages editor contributions and action set part associations.
+	 */
+	private class ActionSwitcher {
+		private IWorkbenchPart activePart;
+
+		private IEditorPart topEditor;
+
+		private List<IActionSetDescriptor> oldActionSets = new ArrayList<>();
+
+		/**
+		 * Updates the contributions given the new part as the active part.
+		 *
+		 * @param newPart
+		 *            the new active part, may be <code>null</code>
+		 */
+		public void updateActivePart(IWorkbenchPart newPart) {
+			if (activePart == newPart) {
+				return;
+			}
+
+			boolean isNewPartAnEditor = newPart instanceof IEditorPart;
+			if (isNewPartAnEditor) {
+				String oldId = null;
+				if (topEditor != null) {
+					oldId = topEditor.getSite().getId();
+				}
+				String newId = newPart.getSite().getId();
+
+				// if the active part is an editor and the new editor
+				// is the same kind of editor, then we don't have to do
+				// anything
+				if (activePart == topEditor && newId.equals(oldId)) {
+					activePart = newPart;
+					topEditor = (IEditorPart) newPart;
+					return;
+				}
+
+				// remove the contributions of the old editor
+				// if it is a different kind of editor
+				if (oldId != null && !oldId.equals(newId)) {
+					deactivateContributions(topEditor, true);
+				}
+
+				// if a view was the active part, disable its contributions
+				if (activePart != null && activePart != topEditor) {
+					deactivateContributions(activePart, true);
+				}
+
+				// show (and enable) the contributions of the new editor
+				// if it is a different kind of editor or if the
+				// old active part was a view
+				if (!newId.equals(oldId) || activePart != topEditor) {
+					activateContributions(newPart, true);
+				}
+
+			} else if (newPart == null) {
+				if (activePart != null) {
+					// remove all contributions
+					deactivateContributions(activePart, true);
+				}
+			} else {
+				// new part is a view
+
+				// if old active part is a view, remove all contributions,
+				// but if old part is an editor only disable
+				if (activePart != null) {
+					deactivateContributions(activePart, activePart instanceof IViewPart);
+				}
+
+				activateContributions(newPart, true);
+			}
+
+			List<IActionSetDescriptor> newActionSets = null;
+			if (isNewPartAnEditor || (activePart == topEditor && newPart == null)) {
+				newActionSets = calculateActionSets(newPart, null);
+			} else {
+				newActionSets = calculateActionSets(newPart, topEditor);
+			}
+
+			if (!updateActionSets(newActionSets)) {
+				updateActionBars();
+			}
+
+			if (isNewPartAnEditor) {
+				topEditor = (IEditorPart) newPart;
+			} else if (activePart == topEditor && newPart == null) {
+				// since we removed all the contributions, we clear the top
+				// editor
+				topEditor = null;
+			}
+
+			activePart = newPart;
+		}
+
+		/**
+		 * Updates the contributions given the new part as the topEditor.
+		 *
+		 * @param newEditor
+		 *            the new top editor, may be <code>null</code>
+		 */
+		public void updateTopEditor(IEditorPart newEditor) {
+			if (topEditor == newEditor) {
+				return;
+			}
+
+			if (activePart == topEditor) {
+				updateActivePart(newEditor);
+				return;
+			}
+
+			String oldId = null;
+			if (topEditor != null) {
+				oldId = topEditor.getSite().getId();
+			}
+			String newId = null;
+			if (newEditor != null) {
+				newId = newEditor.getSite().getId();
+			}
+			if (oldId == null ? newId == null : oldId.equals(newId)) {
+				// we don't have to change anything
+				topEditor = newEditor;
+				return;
+			}
+
+			// Remove the contributions of the old editor
+			if (topEditor != null) {
+				deactivateContributions(topEditor, true);
+			}
+
+			// Show (disabled) the contributions of the new editor
+			if (newEditor != null) {
+				activateContributions(newEditor, false);
+			}
+
+			List<IActionSetDescriptor> newActionSets = calculateActionSets(activePart, newEditor);
+			if (!updateActionSets(newActionSets)) {
+				updateActionBars();
+			}
+
+			topEditor = newEditor;
+		}
+
+		/**
+		 * Activates the contributions of the given part. If <code>enable</code>
+		 * is <code>true</code> the contributions are visible and enabled,
+		 * otherwise they are disabled.
+		 *
+		 * @param part
+		 *            the part whose contributions are to be activated
+		 * @param enable
+		 *            <code>true</code> the contributions are to be enabled, not
+		 *            just visible.
+		 */
+		private void activateContributions(IWorkbenchPart part, boolean enable) {
+			PartSite site = (PartSite) part.getSite();
+			site.activateActionBars(enable);
+		}
+
+		/**
+		 * Deactivates the contributions of the given part. If
+		 * <code>remove</code> is <code>true</code> the contributions are
+		 * removed, otherwise they are disabled.
+		 *
+		 * @param part
+		 *            the part whose contributions are to be deactivated
+		 * @param remove
+		 *            <code>true</code> the contributions are to be removed, not
+		 *            just disabled.
+		 */
+		private void deactivateContributions(IWorkbenchPart part, boolean remove) {
+			PartSite site = (PartSite) part.getSite();
+			site.deactivateActionBars(remove);
+		}
+
+		/**
+		 * Calculates the action sets to show for the given part and editor
+		 *
+		 * @param part
+		 *            the active part, may be <code>null</code>
+		 * @param editor
+		 *            the current editor, may be <code>null</code>, may be the
+		 *            active part
+		 * @return the new action sets
+		 */
+		private List<IActionSetDescriptor> calculateActionSets(IWorkbenchPart part,
+				IEditorPart editor) {
+			List<IActionSetDescriptor> newActionSets = new ArrayList<>();
+			if (part != null) {
+				IActionSetDescriptor[] partActionSets = WorkbenchPlugin.getDefault()
+						.getActionSetRegistry().getActionSetsFor(part.getSite().getId());
+				for (IActionSetDescriptor partActionSetDescriptor : partActionSets) {
+					newActionSets.add(partActionSetDescriptor);
+				}
+			}
+			if (editor != null && editor != part) {
+				IActionSetDescriptor[] editorActionSets = WorkbenchPlugin.getDefault()
+						.getActionSetRegistry().getActionSetsFor(editor.getSite().getId());
+				for (IActionSetDescriptor editorActionSetDescriptor : editorActionSets) {
+					newActionSets.add(editorActionSetDescriptor);
+				}
+			}
+			return newActionSets;
+		}
+
+		/**
+		 * Updates the actions we are showing for the active part and current
+		 * editor.
+		 *
+		 * @param newActionSets
+		 *            the action sets to show
+		 * @return <code>true</code> if the action sets changed
+		 */
+		private boolean updateActionSets(List<IActionSetDescriptor> newActionSets) {
+			if (oldActionSets.equals(newActionSets)) {
+				return false;
+			}
+
+			IContextService service = legacyWindow
+					.getService(IContextService.class);
+			try {
+				service.deferUpdates(true);
+
+				// show the new
+				for (int i = 0; i < newActionSets.size(); i++) {
+					actionSets.showAction(newActionSets.get(i));
+				}
+
+				// hide the old
+				for (int i = 0; i < oldActionSets.size(); i++) {
+					actionSets.hideAction(oldActionSets.get(i));
+				}
+
+				oldActionSets = newActionSets;
+
+			} finally {
+				service.deferUpdates(false);
+			}
+			Perspective persp = getActivePerspective();
+			if (persp == null) {
+				return false;
+			}
+
+			legacyWindow.updateActionSets(); // this calls updateActionBars
+			legacyWindow.firePerspectiveChanged(WorkbenchPage.this, getPerspective(),
+					CHANGE_ACTION_SET_SHOW);
+			return true;
+		}
+
+	}
+
+	private EPartService partService;
+
+	private SelectionService selectionService;
+
+	private MApplication application;
+
+	private MWindow window;
+
+	private EModelService modelService;
+
+	private IEventBroker broker;
+
+	/**
+	 * An event handler that listens for an MArea's widget being set so that we
+	 * can install DND support into its control.
+	 */
+	private EventHandler widgetHandler = new EventHandler() {
+		@Override
+		public void handleEvent(Event event) {
+			Object element = event.getProperty(UIEvents.EventTags.ELEMENT);
+			Object newValue = event.getProperty(UIEvents.EventTags.NEW_VALUE);
+
+			if (element instanceof MArea) {
+				// If it's an MArea in this window install the DND handling
+				if (modelService.findElements(window, null, MArea.class, null).contains(element)) {
+					if (newValue instanceof Control) {
+						installAreaDropSupport((Control) newValue);
+					}
+				}
+			} else if (element instanceof MPart && newValue == null) {
+				// If it's a 'e4' part then remove the reference for it
+				MPart changedPart = (MPart) element;
+				Object impl = changedPart.getObject();
+				if (impl != null && !(impl instanceof CompatibilityPart)) {
+					EditorReference eRef = getEditorReference(changedPart);
+					if (eRef != null)
+						editorReferences.remove(eRef);
+					ViewReference vRef = getViewReference(changedPart);
+					if (vRef != null)
+						viewReferences.remove(vRef);
+				}
+			}
+		}
+	};
+
+	@Inject
+	@Optional
+	private void handleMinimizedStacks(
+			@UIEventTopic(UIEvents.ApplicationElement.TOPIC_TAGS) Event event) {
+		Object changedObj = event.getProperty(EventTags.ELEMENT);
+
+		if (!(changedObj instanceof MToolControl))
+			return;
+
+		final MToolControl minimizedStack = (MToolControl) changedObj;
+
+		// Note: The non-API type TrimStack is not imported to avoid
+		// https://bugs.eclipse.org/435521
+		if (!(minimizedStack.getObject() instanceof org.eclipse.e4.ui.workbench.addons.minmax.TrimStack))
+			return;
+
+		org.eclipse.e4.ui.workbench.addons.minmax.TrimStack ts = (org.eclipse.e4.ui.workbench.addons.minmax.TrimStack) minimizedStack
+				.getObject();
+		if (!(ts.getMinimizedElement() instanceof MPartStack))
+			return;
+
+		MPartStack stack = (MPartStack) ts.getMinimizedElement();
+		MUIElement stackSel = stack.getSelectedElement();
+		MPart thePart = null;
+		if (stackSel instanceof MPart) {
+			thePart = (MPart) stackSel;
+		} else if (stackSel instanceof MPlaceholder) {
+			MPlaceholder ph = (MPlaceholder) stackSel;
+			if (ph.getRef() instanceof MPart) {
+				thePart = (MPart) ph.getRef();
+			}
+		}
+
+		if (thePart == null)
+			return;
+
+		if (UIEvents.isADD(event)) {
+			if (UIEvents.contains(event, UIEvents.EventTags.NEW_VALUE,
+					org.eclipse.e4.ui.workbench.addons.minmax.TrimStack.MINIMIZED_AND_SHOWING)) {
+				firePartVisible(thePart);
+			}
+		} else if (UIEvents.isREMOVE(event)) {
+			if (UIEvents.contains(event, UIEvents.EventTags.OLD_VALUE,
+					org.eclipse.e4.ui.workbench.addons.minmax.TrimStack.MINIMIZED_AND_SHOWING)) {
+				firePartHidden(thePart);
+			}
+		}
+	}
+
+	/**
+	 * Boolean field to determine whether DND support has been added to the
+	 * shared area yet.
+	 *
+	 * @see #installAreaDropSupport(Control)
+	 */
+	private boolean dndSupportInstalled = false;
+
+    /**
+     * Constructs a page. <code>restoreState(IMemento)</code> should be
+     * called to restore this page from data stored in a persistance file.
+     *
+     * @param w
+     *            the parent window
+     * @param input
+     *            the page input
+     * @throws WorkbenchException
+     */
+    public WorkbenchPage(WorkbenchWindow w, IAdaptable input)
+            throws WorkbenchException {
+        super();
+        init(w, null, input, false);
+    }
+
+    /**
+     * Allow access to the UI model that this page is managing
+     * @return the MWindow element for this page
+     */
+    public MWindow getWindowModel() {
+    	return window;
+
+    }
+    /**
+     * Activates a part. The part will be brought to the front and given focus.
+     *
+     * @param part
+     *            the part to activate
+     */
+    @Override
+	public void activate(IWorkbenchPart part) {
+		if (part == null || !certifyPart(part) || legacyWindow.isClosing()) {
+			return;
+		}
+		MPart mpart = findPart(part);
+		if (mpart != null) {
+			partService.activate(mpart);
+			actionSwitcher.updateActivePart(part);
+		}
+	}
+
+    /**
+	 * Adds an IPartListener to the part service.
+	 */
+    @Override
+	public void addPartListener(IPartListener l) {
+		partListenerList.add(l);
+    }
+
+	/**
+	 * Adds an IPartListener to the part service.
+	 */
+    @Override
+	public void addPartListener(IPartListener2 l) {
+		partListener2List.add(l);
+    }
+
+    /**
+     * Implements IWorkbenchPage
+     *
+     * @see org.eclipse.ui.IWorkbenchPage#addPropertyChangeListener(IPropertyChangeListener)
+     * @since 2.0
+     * @deprecated individual views should store a working set if needed and
+     *             register a property change listener directly with the
+     *             working set manager to receive notification when the view
+     *             working set is removed.
+     */
+    @Deprecated
+	@Override
+	public void addPropertyChangeListener(IPropertyChangeListener listener) {
+        propertyChangeListeners.add(listener);
+    }
+
+    @Override
+	public void addSelectionListener(ISelectionListener listener) {
+		selectionService.addSelectionListener(listener);
+    }
+
+    @Override
+	public void addSelectionListener(String partId, ISelectionListener listener) {
+		selectionService.addSelectionListener(partId, listener);
+    }
+
+    @Override
+	public void addPostSelectionListener(ISelectionListener listener) {
+		selectionService.addPostSelectionListener(listener);
+    }
+
+    @Override
+	public void addPostSelectionListener(String partId,
+            ISelectionListener listener) {
+		selectionService.addPostSelectionListener(partId, listener);
+    }
+
+    /**
+     * Moves a part forward in the Z order of a perspective so it is visible.
+     * If the part is in the same stack as the active part, the new part is
+     * activated.
+     *
+     * @param part
+     *            the part to bring to move forward
+     */
+    @Override
+	public void bringToTop(IWorkbenchPart part) {
+        // Sanity check.
+		MPart mpart = findPart(part);
+		if (mpart != null) {
+			partService.bringToTop(mpart);
+		}
+    }
+
+	public MPart findPart(IWorkbenchPart part) {
+		if (part == null) {
+			return null;
+		}
+
+		for (IViewReference reference : viewReferences) {
+			if (part == reference.getPart(false)) {
+				return ((WorkbenchPartReference) reference).getModel();
+			}
+		}
+
+		for (IEditorReference reference : editorReferences) {
+			if (part == reference.getPart(false)) {
+				return ((WorkbenchPartReference) reference).getModel();
+			}
+		}
+		return null;
+	}
+
+	public EditorReference createEditorReferenceForPart(final MPart part, IEditorInput input,
+			String editorId,
+			IMemento memento) {
+		IEditorRegistry registry = legacyWindow.getWorkbench().getEditorRegistry();
+		EditorDescriptor descriptor = (EditorDescriptor) registry.findEditor(editorId);
+		final EditorReference ref = new EditorReference(window.getContext(), this, part, input,
+				descriptor, memento);
+		addEditorReference(ref);
+		ref.subscribe();
+		return ref;
+	}
+
+	private List<EditorReference> getOrderedEditorReferences() {
+
+		List<EditorReference> editorRefs = new ArrayList<>();
+		List<MPart> visibleEditors = modelService.findElements(window,
+				CompatibilityEditor.MODEL_ELEMENT_ID, MPart.class, null);
+		for (MPart editor : visibleEditors) {
+			if (editor.isToBeRendered()) {
+				EditorReference ref = getEditorReference(editor);
+				if (ref != null && !editorRefs.contains(ref)) {
+					editorRefs.add(ref);
+				}
+			}
+		}
+
+		return editorRefs;
+	}
+
+	List<EditorReference> getSortedEditorReferences() {
+		return getSortedEditorReferences(false);
+	}
+
+	private List<EditorReference> getSortedEditorReferences(boolean allPerspectives) {
+		List<EditorReference> sortedReferences = new ArrayList<>();
+		for (MPart part : activationList) {
+			for (EditorReference ref : editorReferences) {
+				if (ref.getModel() == part) {
+					sortedReferences.add(ref);
+					break;
+				}
+			}
+		}
+
+		for (EditorReference ref : editorReferences) {
+			if (!sortedReferences.contains(ref)) {
+				sortedReferences.add(ref);
+			}
+		}
+
+		MPerspective currentPerspective = getCurrentPerspective();
+		if (currentPerspective != null) {
+			int scope = allPerspectives ? WINDOW_SCOPE : EModelService.PRESENTATION;
+			List<MPart> placeholders = modelService.findElements(window,
+					CompatibilityEditor.MODEL_ELEMENT_ID, MPart.class, null, scope);
+			List<EditorReference> visibleReferences = new ArrayList<>();
+			for (EditorReference reference : sortedReferences) {
+				for (MPart placeholder : placeholders) {
+					if (reference.getModel() == placeholder && placeholder.isToBeRendered()) {
+						// only rendered placeholders are valid references
+						visibleReferences.add(reference);
+					}
+				}
+			}
+
+			return visibleReferences;
+		}
+
+		return sortedReferences;
+	}
+
+	public List<EditorReference> getInternalEditorReferences() {
+		return editorReferences;
+	}
+
+	public EditorReference getEditorReference(MPart part) {
+		for (EditorReference ref : editorReferences) {
+			if (ref.getModel() == part) {
+				return ref;
+			}
+		}
+		return null;
+	}
+
+	public ViewReference getViewReference(MPart part) {
+		for (ViewReference ref : viewReferences) {
+			if (ref.getModel() == part) {
+				return ref;
+			}
+		}
+		return null;
+	}
+
+	private boolean contains(ViewReference reference) {
+		for (ViewReference viewReference : viewReferences) {
+			if (reference.getModel().getElementId().equals(viewReference.getModel().getElementId())) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	public void addViewReference(ViewReference reference) {
+		if (!contains(reference)) {
+			viewReferences.add(reference);
+		}
+	}
+
+	public void addEditorReference(EditorReference editorReference) {
+		WorkbenchPage curPage = (WorkbenchPage) editorReference.getPage();
+
+		// Ensure that the page is up-to-date
+		if (curPage != this) {
+			curPage.editorReferences.remove(editorReference);
+			editorReference.setPage(this);
+		}
+
+		// Avoid dups
+		if (!editorReferences.contains(editorReference)) {
+			editorReferences.add(editorReference);
+		}
+	}
+
+	MPartDescriptor findDescriptor(String id) {
+		return modelService.getPartDescriptor(id);
+	}
+
+	/**
+	 * Searches the workbench window for a part with the given view id and
+	 * secondary id (if desired) given the specified search rules.
+	 *
+	 * @param viewId
+	 *            the id of the view
+	 * @param secondaryId
+	 *            the secondary id of the view, or <code>null</code> if the view
+	 *            to search for should be one without a secondary id defined
+	 * @param searchFlags
+	 *            the desired search locations
+	 * @return the part with the specified view id and secondary id, or
+	 *         <code>null</code> if it could not be found in this page's parent
+	 *         workbench window
+	 * @see EModelService#findElements(MUIElement, String, Class, List, int)
+	 */
+	private MPart findPart(String viewId, int searchFlags) {
+		List<MPart> parts = modelService.findElements(getWindowModel(), viewId, MPart.class, null,
+				searchFlags);
+		if (parts.size() > 0)
+			return parts.get(0);
+
+		return null;
+	}
+
+	PartState convert(int mode) {
+		switch (mode) {
+		case VIEW_ACTIVATE:
+			return PartState.ACTIVATE;
+		case VIEW_VISIBLE:
+			return PartState.VISIBLE;
+		case VIEW_CREATE:
+			return PartState.CREATE;
+		}
+		throw new IllegalArgumentException(WorkbenchMessages.get().WorkbenchPage_IllegalViewMode);
+	}
+
+	/**
+	 * Shows a view.
+	 *
+	 * Assumes that a busy cursor is active.
+	 */
+	protected IViewPart busyShowView(String viewId, int mode) throws PartInitException {
+		switch (mode) {
+		case VIEW_ACTIVATE:
+		case VIEW_VISIBLE:
+		case VIEW_CREATE:
+			break;
+		default:
+			throw new IllegalArgumentException(WorkbenchMessages.get().WorkbenchPage_IllegalViewMode);
+		}
+
+		MPart part = findPart(viewId, EModelService.ANYWHERE);
+		if (part == null) {
+			MPlaceholder ph = partService.createSharedPart(viewId, false);
+			if (ph == null) {
+				throw new PartInitException(NLS.bind(WorkbenchMessages.get().ViewFactory_couldNotCreate,
+						viewId));
+			}
+
+			part = (MPart) ph.getRef();
+			part.setCurSharedRef(ph);
+		}
+
+		part = showPart(mode, part);
+
+		ViewReference ref = getViewReference(part);
+
+		return (IViewPart) ref.getPart(true);
+	}
+	private MPart showPart(int mode, MPart part) {
+		switch (mode) {
+		case VIEW_ACTIVATE:
+			partService.showPart(part, PartState.ACTIVATE);
+			if (part.getObject() instanceof CompatibilityView) {
+				CompatibilityView compatibilityView = (CompatibilityView) part.getObject();
+				actionSwitcher.updateActivePart(compatibilityView.getPart());
+			}
+			break;
+		case VIEW_VISIBLE:
+			MPart activePart = partService.getActivePart();
+			if (activePart == null) {
+				partService.showPart(part, PartState.ACTIVATE);
+				if (part.getObject() instanceof CompatibilityView) {
+					CompatibilityView compatibilityView = (CompatibilityView) part.getObject();
+					actionSwitcher.updateActivePart(compatibilityView.getPart());
+				}
+			} else {
+				part = ((PartServiceImpl) partService).addPart(part);
+				MPlaceholder activePlaceholder = activePart.getCurSharedRef();
+				MUIElement activePartParent = activePlaceholder == null ? activePart
+						.getParent() : activePlaceholder.getParent();
+				partService.showPart(part, PartState.CREATE);
+				if (part.getCurSharedRef() == null || part.getCurSharedRef().getParent() != activePartParent) {
+					partService.bringToTop(part);
+				}
+			}
+			break;
+		case VIEW_CREATE:
+			partService.showPart(part, PartState.CREATE);
+
+			// Report the visibility of the created part
+			MStackElement sElement = part;
+			if (part.getCurSharedRef() != null)
+				sElement = part.getCurSharedRef();
+			MUIElement parentElement = sElement.getParent();
+			if (parentElement instanceof MPartStack) {
+				MPartStack partStack = (MPartStack) parentElement;
+				if (partStack.getSelectedElement() == sElement
+						&& !partStack.getTags().contains(IPresentationEngine.MINIMIZED)) {
+					firePartVisible(part);
+				} else {
+					firePartHidden(part);
+				}
+			} else {
+				firePartVisible(part); // Stand-alone part
+			}
+			break;
+		}
+		return part;
+	}
+
+    /**
+     * Returns whether a part exists in the current page.
+     */
+    private boolean certifyPart(IWorkbenchPart part) {
+        //Workaround for bug 22325
+        if (part != null && !(part.getSite() instanceof PartSite)) {
+			return false;
+		}
+		return true;
+    }
+
+    /**
+	 * Closes this page.
+     */
+    @Override
+	public boolean close() {
+        final boolean[] ret = new boolean[1];
+        BusyIndicator.showWhile(null, new Runnable() {
+            @Override
+			public void run() {
+				ret[0] = close(true, true);
+            }
+        });
+        return ret[0];
+    }
+
+    public boolean closeAllSavedEditors() {
+        // get the Saved editors
+        IEditorReference editors[] = getEditorReferences();
+        IEditorReference savedEditors[] = new IEditorReference[editors.length];
+        int j = 0;
+		for (IEditorReference editor : editors) {
+            if (!editor.isDirty()) {
+                savedEditors[j++] = editor;
+            }
+        }
+        //there are no unsaved editors
+        if (j == 0) {
+			return true;
+		}
+        IEditorReference[] newSaved = new IEditorReference[j];
+        System.arraycopy(savedEditors, 0, newSaved, 0, j);
+        return closeEditors(newSaved, false);
+    }
+
+    /**
+     * See IWorkbenchPage
+     */
+    @Override
+	public boolean closeAllEditors(boolean save) {
+        return closeEditors(getEditorReferences(), save);
+    }
+
+	/**
+	 * See IWorkbenchPage
+	 */
+	@Override
+	public boolean closeEditors(IEditorReference[] refArray, boolean save) {
+		if (refArray.length == 0) {
+			return true;
+        }
+
+		// Check if we're being asked to close any parts that are already closed
+		// or cannot
+		// be closed at this time
+		ArrayList<IEditorReference> editorRefs = new ArrayList<>();
+		for (IEditorReference reference : refArray) {
+			// If we're in the middle of creating this part, this is a
+			// programming error. Abort the entire
+			// close operation. This usually occurs if someone tries to open a
+			// dialog in a method that
+			// isn't allowed to do so, and a *syncExec tries to close the part.
+			// If this shows up in a log
+			// file with a dialog's event loop on the stack, then the code that
+			// opened the dialog is usually
+			// at fault.
+			if (reference == partBeingActivated) {
+				WorkbenchPlugin.log(new RuntimeException(
+						"WARNING: Blocked recursive attempt to close part " //$NON-NLS-1$
+								+ partBeingActivated.getId()
+								+ " while still in the middle of activating it")); //$NON-NLS-1$
+				return false;
+			}
+
+			if (reference instanceof WorkbenchPartReference) {
+				WorkbenchPartReference ref = (WorkbenchPartReference) reference;
+
+				// If we're being asked to close a part that is disposed (ie:
+				// already closed),
+				// skip it and proceed with closing the remaining parts.
+				if (ref.isDisposed()) {
+					continue;
+                }
+            }
+
+			editorRefs.add(reference);
+        }
+
+		// if active navigation position belongs to an editor being closed,
+		// update it
+		// (The navigation position for an editor N was updated as an editor N +
+		// 1
+		// was activated. As a result, all but the last editor have up-to-date
+		// navigation positions.)
+		for (IEditorReference ref : editorRefs) {
+			IEditorPart oldPart = ref.getEditor(false);
+			if (oldPart == null)
+				continue;
+			if (navigationHistory.updateActive(oldPart))
+				break; // updated - skip the rest
+        }
+
+		// notify the model manager before the close
+		List<IWorkbenchPart> partsToClose = new ArrayList<>();
+		for (IEditorReference ref : editorRefs) {
+			IEditorPart refPart = ref.getEditor(false);
+			if (refPart != null) {
+				partsToClose.add(refPart);
+            }
+        }
+
+		boolean confirm = true;
+		SaveablesList modelManager = null;
+		Object postCloseInfo = null;
+		if (partsToClose.size() > 0) {
+			modelManager = (SaveablesList) getWorkbenchWindow().getService(
+					ISaveablesLifecycleListener.class);
+			// this may prompt for saving and return null if the user canceled:
+			postCloseInfo = modelManager.preCloseParts(partsToClose, save, getWorkbenchWindow());
+			if (postCloseInfo == null) {
+				return false;
+			}
+			confirm = false;
+        }
+
+		// Fire pre-removal changes
+		for (IEditorReference ref : editorRefs) {
+			// Notify interested listeners before the close
+			legacyWindow.firePerspectiveChanged(this, getPerspective(), ref, CHANGE_EDITOR_CLOSE);
+
+		}
+
+        deferUpdates(true);
+		try {
+			if (modelManager != null) {
+				modelManager.postClose(postCloseInfo);
+			}
+
+			// Close all editors.
+			for (Iterator<IEditorReference> it = editorRefs.iterator(); it.hasNext();) {
+				IEditorReference ref = it.next();
+				// hide editors that haven't been instantiated first
+				if (ref.getPart(false) == null) {
+					if (!(hidePart(((EditorReference) ref).getModel(), false, confirm, false, false))) {
+						return false;
+					}
+					// hidden successfully, remove it from the list
+					it.remove();
+				}
+			}
+
+			MPart activePart = findPart(getActiveEditor());
+			boolean closeActivePart = false;
+			// now hide all instantiated editors
+			for (IEditorReference editorRef : editorRefs) {
+				MPart model = ((EditorReference) editorRef).getModel();
+				if (activePart == model) {
+					closeActivePart = true;
+				} else if (!(hidePart(model, false, confirm, false, false))) {
+					// saving should've been handled earlier above
+					return false;
+				}
+			}
+
+			// close the active part last to minimize activation churn
+			if (closeActivePart) {
+				if (!(hidePart(activePart, false, confirm, false))) {
+					return false;
+				}
+			}
+		} finally {
+			deferUpdates(false);
+        }
+
+		// Notify interested listeners after the close
+		legacyWindow.firePerspectiveChanged(this, getPerspective(), CHANGE_EDITOR_CLOSE);
+
+        // Return true on success.
+		return true;
+    }
+
+	public boolean closeEditor(IEditorReference editor) {
+		if (getInternalEditorReferences().contains(editor)) {
+			MPart part = ((EditorReference) editor).getModel();
+			hidePart(part, false, false, false, false);
+
+			MElementContainer<MUIElement> parent = part.getParent();
+			if (parent != null) {
+				parent.getChildren().remove(part);
+			}
+			return true;
+		}
+		return false;
+	}
+
+	private boolean hidePart(MPart part, boolean save, boolean confirm, boolean force) {
+		return hidePart(part, save, confirm, force, true);
+	}
+
+	private boolean hidePart(MPart part, boolean save, boolean confirm, boolean force, boolean local) {
+		if (!partService.getParts().contains(part)) {
+			if (local) {
+				return false;
+			}
+			part.setToBeRendered(false);
+			return true;
+		}
+
+		Object clientObject = part.getObject();
+		if (!(clientObject instanceof CompatibilityPart)) {
+			// either not a 3.x part or it's an e4 part, should still hide it
+			if (save) {
+				// save as necessary
+				if (partService.savePart(part, confirm)) {
+					partService.hidePart(part, force);
+					return true;
+				}
+				return false;
+			}
+			partService.hidePart(part, force);
+			return true;
+		}
+
+		CompatibilityPart compatibilityPart = (CompatibilityPart) clientObject;
+		IWorkbenchPart workbenchPart = compatibilityPart.getPart();
+		if (save) {
+			ISaveablePart saveablePart = SaveableHelper.getSaveable(workbenchPart);
+			if (saveablePart != null) {
+				if (saveablePart.isSaveOnCloseNeeded()) {
+					if (!saveSaveable(saveablePart, workbenchPart, confirm, true)) {
+						return false;
+					}
+				}
+			}
+		}
+
+		for (IViewReference viewRef : viewReferences) {
+			if (workbenchPart == viewRef.getPart(false)) {
+				partService.hidePart(part, force);
+				return true;
+			}
+		}
+
+		for (IEditorReference viewRef : editorReferences) {
+			if (workbenchPart == viewRef.getPart(false)) {
+				partService.hidePart(part, force);
+				return true;
+			}
+		}
+		return false;
+	}
+
+    /**
+     * Enables or disables listener notifications. This is used to delay listener notifications until the
+     * end of a public method.
+     *
+     * @param shouldDefer
+     */
+    private void deferUpdates(boolean shouldDefer) {
+        if (shouldDefer) {
+            if (deferCount == 0) {
+                startDeferring();
+            }
+            deferCount++;
+        } else {
+            deferCount--;
+            if (deferCount == 0) {
+                handleDeferredEvents();
+            }
+        }
+    }
+
+    private void startDeferring() {
+		// TODO compat: do we defer events
+    }
+
+    private void handleDeferredEvents() {
+		// TODO compat: do we handler defered events
+    }
+
+    public boolean closeEditor(IEditorReference editorRef, boolean save) {
+        return closeEditors(new IEditorReference[] {editorRef}, save);
+    }
+
+    /**
+     * See IWorkbenchPage#closeEditor
+     */
+    @Override
+	public boolean closeEditor(IEditorPart editor, boolean save) {
+        IWorkbenchPartReference ref = getReference(editor);
+        if (ref instanceof IEditorReference) {
+        	return closeEditors(new IEditorReference[] {(IEditorReference) ref}, save);
+        }
+        return false;
+    }
+
+	/**
+	 * Closes the specified perspective.
+	 *
+	 * @param desc
+	 *            the perspective to close
+	 * @param perspectiveId
+	 *            the id of the perspective being closed
+	 * @param saveParts
+	 *            <code>true</code> if dirty parts should be prompted for its
+	 *            contents to be saved, <code>false</code> otherwise
+	 */
+	private void closePerspective(IPerspectiveDescriptor desc, String perspectiveId,
+			boolean saveParts) {
+		MPerspective persp = (MPerspective) modelService.find(perspectiveId, window);
+		// check to ensure this perspective actually exists in this window
+		if (persp != null) {
+			if (saveParts) {
+				List<IWorkbenchPart> partsToSave = new ArrayList<>();
+				// retrieve all parts under the specified perspective
+				List<MPart> parts = modelService.findElements(persp, null, MPart.class, null);
+				if (!parts.isEmpty()) {
+					// filter out any parts that are visible in any other
+					// perspectives
+					for (MPerspective perspective : getPerspectiveStack().getChildren()) {
+						if (perspective != persp) {
+							parts.removeAll(modelService.findElements(perspective, null,
+									MPart.class, null));
+						}
+					}
+
+					if (!parts.isEmpty()) {
+						for (Iterator<MPart> it = parts.iterator(); it.hasNext();) {
+							MPart part = it.next();
+							if (part.isDirty()) {
+								Object object = part.getObject();
+								if (object instanceof CompatibilityPart) {
+									IWorkbenchPart workbenchPart = ((CompatibilityPart) object)
+											.getPart();
+									ISaveablePart saveablePart = SaveableHelper.getSaveable(workbenchPart);
+									if (saveablePart != null) {
+										if (!saveablePart.isSaveOnCloseNeeded()) {
+											part.setDirty(false);
+											it.remove();
+										} else {
+											partsToSave.add(workbenchPart);
+										}
+									}
+								}
+							} else {
+								it.remove();
+							}
+						}
+
+						if (!partsToSave.isEmpty()) {
+							if (!saveAll(partsToSave, true, true, false, legacyWindow, legacyWindow)) {
+								// user cancel
+								return;
+							}
+						}
+					}
+				}
+			}
+
+			// Remove from caches
+			sortedPerspectives.remove(desc);
+			// check if we're closing the currently active perspective
+			if (getPerspectiveStack().getSelectedElement() == persp
+					&& !sortedPerspectives.isEmpty()) {
+				// get the perspective that was last active and set it
+				IPerspectiveDescriptor lastActive = sortedPerspectives.get(sortedPerspectives
+						.size() - 1);
+				if (lastActive != null) {
+					setPerspective(lastActive);
+				}
+			}
+			modelService.removePerspectiveModel(persp, window);
+			modelToPerspectiveMapping.remove(persp);
+
+			legacyWindow.firePerspectiveClosed(this, desc);
+		}
+	}
+
+	@Override
+	public void closePerspective(IPerspectiveDescriptor desc, boolean saveParts, boolean closePage) {
+		closePerspective(desc, desc.getId(), saveParts, closePage);
+	}
+
+	public void closePerspective(IPerspectiveDescriptor desc, String perspectiveId,
+			boolean saveParts, boolean closePage) {
+		MPerspective persp = (MPerspective) modelService.find(perspectiveId, window);
+		// check to ensure this perspective actually exists in this window
+		if (persp != null) {
+			persp.getTags().add("PerspClosing"); //$NON-NLS-1$
+			try {
+				MPerspectiveStack perspectiveStack = modelService.findElements(window, null,
+						MPerspectiveStack.class, null).get(0);
+				if (perspectiveStack.getChildren().size() == 1) {
+					closeAllPerspectives(saveParts, closePage);
+				} else {
+					closePerspective(desc, perspectiveId, saveParts);
+				}
+			} finally {
+				persp.getTags().remove("PerspClosing"); //$NON-NLS-1$
+			}
+		}
+	}
+
+	@Override
+	public void closeAllPerspectives(boolean saveEditors, boolean closePage) {
+		boolean okToProceed = closeAllEditors(true);
+		if (okToProceed) {
+			List<MPerspective> kids = new ArrayList<>(_perspectiveStack.getChildren());
+			MPerspective curPersp = _perspectiveStack.getSelectedElement();
+			for (MPerspective persp : kids) {
+				if (persp != curPersp) {
+					closePerspective(getPerspectiveDesc(persp.getElementId()),
+							persp.getElementId(), false);
+				}
+			}
+			if (curPersp != null) {
+				closePerspective(getPerspectiveDesc(curPersp.getElementId()),
+						curPersp.getElementId(),
+						false);
+			}
+			if (closePage) {
+				close();
+			}
+		}
+	}
+
+	private boolean close(boolean save, boolean unsetPage) {
+		if (save && !saveAllEditors(true, true, true)) {
+			return false;
+		}
+
+		Collection<MPart> partsToHide = partService.getParts();
+		// workaround for bug 455281
+		List<MPart> partsOutsidePersp = modelService.findElements(window, null, MPart.class, null,
+				EModelService.OUTSIDE_PERSPECTIVE);
+		partsToHide.removeAll(partsOutsidePersp);
+
+		for (MPart part : partsToHide) {
+			// no save, no confirm, force
+			hidePart(part, false, true, true);
+		}
+
+		MPerspectiveStack perspectiveStack = modelService.findElements(window, null,
+				MPerspectiveStack.class, null).get(0);
+		MPerspective current = perspectiveStack.getSelectedElement();
+		for (Object perspective : perspectiveStack.getChildren().toArray()) {
+			if (perspective != current) {
+				modelService.removePerspectiveModel((MPerspective) perspective, window);
+			}
+		}
+
+		if (current != null) {
+			modelService.removePerspectiveModel(current, window);
+		}
+
+		viewReferences.clear();
+		editorReferences.clear();
+		sortedPerspectives.clear();
+		modelToPerspectiveMapping.clear();
+
+		if (unsetPage) {
+			legacyWindow.setActivePage(null);
+			partService.removePartListener(e4PartListener);
+			broker.unsubscribe(selectionHandler);
+			broker.unsubscribe(widgetHandler);
+			broker.unsubscribe(referenceRemovalEventHandler);
+			broker.unsubscribe(firingHandler);
+			broker.unsubscribe(childrenHandler);
+			partEvents.clear();
+
+			partListenerList.clear();
+			partListener2List.clear();
+			propertyChangeListeners.clear();
+
+			selectionService.dispose();
+
+			ContextInjectionFactory.uninject(this, window.getContext());
+		}
+		return true;
+	}
+
+	/**
+	 * Forces all perspectives on the page to zoom out.
+	 */
+	public void unzoomAllPerspectives() {
+		// TODO compat: we have no min/max behaviour
+    }
+
+
+
+    /**
+	 * Cleanup.
+	 */
+	public void dispose() {
+
+// // Always unzoom
+		// if (isZoomed()) {
+		// zoomOut();
+		// }
+		//
+		// // makeActiveEditor(null);
+		// // makeActive(null);
+		//
+		// // Close and dispose the editors.
+		// closeAllEditors(false);
+		//
+		// // Need to make sure model data is cleaned up when the page is
+		// // disposed. Collect all the views on the page and notify the
+		// // saveable list of a pre/post close. This will free model data.
+		// IWorkbenchPartReference[] partsToClose = getOpenParts();
+		// List dirtyParts = new ArrayList(partsToClose.length);
+		// for (int i = 0; i < partsToClose.length; i++) {
+		// IWorkbenchPart part = partsToClose[i].getPart(false);
+		// if (part != null && part instanceof IViewPart) {
+		// dirtyParts.add(part);
+		// }
+		// }
+		// SaveablesList saveablesList = (SaveablesList)
+		// getWorkbenchWindow().getWorkbench().getService(ISaveablesLifecycleListener.class);
+		// Object postCloseInfo = saveablesList.preCloseParts(dirtyParts,
+		// false,getWorkbenchWindow());
+		// saveablesList.postClose(postCloseInfo);
+		//
+		// // Get rid of perspectives. This will close the views.
+		// Iterator itr = perspList.iterator();
+		// while (itr.hasNext()) {
+		// Perspective perspective = (Perspective) itr.next();
+		// legacyWindow.firePerspectiveClosed(this, perspective.getDesc());
+		// perspective.dispose();
+		// }
+		// perspList = new PerspectiveList();
+		//
+		// // Capture views.
+		// IViewReference refs[] = viewFactory.getViews();
+		//
+		// if (refs.length > 0) {
+		// // Dispose views.
+		// for (int i = 0; i < refs.length; i++) {
+		// final WorkbenchPartReference ref = (WorkbenchPartReference) refs[i];
+		// //partList.removePart(ref);
+		// //firePartClosed(refs[i]);
+		// SafeRunner.run(new SafeRunnable() {
+		// public void run() {
+		// // WorkbenchPlugin.log(new Status(IStatus.WARNING,
+		// WorkbenchPlugin.PI_WORKBENCH,
+		////                                Status.OK, "WorkbenchPage leaked a refcount for view " + ref.getId(), null));  //$NON-NLS-1$//$NON-NLS-2$
+		//
+		// ref.dispose();
+		// }
+		//
+		// public void handleException(Throwable e) {
+		// }
+		// });
+		// }
+		// }
+		//
+		// activationList = new ActivationList();
+		//
+		// // Get rid of editor presentation.
+		// editorPresentation.dispose();
+		//
+		// // Get rid of composite.
+		// composite.dispose();
+		//
+		// navigationHistory.dispose();
+		//
+		// stickyViewMan.clear();
+		//
+		// if (tracker != null) {
+		// tracker.close();
+		// }
+		//
+		// // if we're destroying a window in a non-shutdown situation then we
+		// should
+		// // clean up the working set we made.
+		// if (!legacyWindow.getWorkbench().isClosing()) {
+		// if (aggregateWorkingSet != null) {
+		// PlatformUI.getWorkbench().getWorkingSetManager().removeWorkingSet(aggregateWorkingSet);
+		// }
+		// }
+    }
+
+
+
+    /**
+     * @return NavigationHistory
+     */
+    @Override
+	public INavigationHistory getNavigationHistory() {
+        return navigationHistory;
+    }
+
+    public boolean editActionSets() {
+		Perspective persp = getActivePerspective();
+		if (persp == null) {
+			return false;
+		}
+
+		// Create list dialog.
+		CustomizePerspectiveDialog dlg = legacyWindow.createCustomizePerspectiveDialog(persp,
+				window.getContext());
+		// Open.
+		boolean ret = (dlg.open() == Window.OK);
+		if (ret) {
+			legacyWindow.updateActionSets();
+			legacyWindow.firePerspectiveChanged(this, getPerspective(), CHANGE_RESET);
+			legacyWindow.firePerspectiveChanged(this, getPerspective(), CHANGE_RESET_COMPLETE);
+		}
+		return ret;
+    }
+
+
+    /**
+     * See IWorkbenchPage@findView.
+     */
+    @Override
+	public IViewPart findView(String id) {
+        IViewReference ref = findViewReference(id);
+        if (ref == null) {
+			return null;
+		}
+        return ref.getView(true);
+    }
+
+    @Override
+	public IViewReference findViewReference(String viewId) {
+		for (IViewReference reference : getViewReferences()) {
+			ViewReference ref = (ViewReference) reference;
+			if (viewId.equals(ref.getModel().getElementId())) {
+				return reference;
+			}
+		}
+		return null;
+    }
+
+    @Override
+	public IViewReference findViewReference(String viewId, String secondaryId) {
+		String compoundId = viewId;
+		if (secondaryId != null && secondaryId.length() > 0)
+			compoundId += ":" + secondaryId; //$NON-NLS-1$
+		return findViewReference(compoundId);
+    }
+
+	public void createViewReferenceForPart(final MPart part, String viewId) {
+		// If the id contains a ':' use the part before it as the descriptor id
+		int colonIndex = viewId.indexOf(':');
+		String descId = colonIndex == -1 ? viewId : viewId.substring(0, colonIndex);
+
+		IViewDescriptor desc = getWorkbenchWindow().getWorkbench().getViewRegistry().find(descId);
+		final ViewReference ref = new ViewReference(window.getContext(), this, part,
+				(ViewDescriptor) desc);
+		if (contains(ref)) {
+			return;
+		}
+
+		IEclipseContext partContext = part.getContext();
+		if (partContext == null) {
+			ref.subscribe();
+		} else {
+			partContext.set(ViewReference.class.getName(), ref);
+		}
+		addViewReference(ref);
+	}
+
+    /**
+     * Notify property change listeners about a property change.
+     *
+     * @param changeId
+     *            the change id
+     * @param oldValue
+     *            old property value
+     * @param newValue
+     *            new property value
+     */
+    private void firePropertyChange(String changeId, Object oldValue,
+            Object newValue) {
+
+        UIListenerLogging.logPagePropertyChanged(this, changeId, oldValue, newValue);
+
+        PropertyChangeEvent event = new PropertyChangeEvent(this, changeId,
+                oldValue, newValue);
+
+		for (IPropertyChangeListener listener : propertyChangeListeners) {
+			listener.propertyChange(event);
+        }
+    }
+
+    /*
+     * Returns the action bars.
+     */
+    public IActionBars getActionBars() {
+        if (actionBars == null) {
+			actionBars = new WWinActionBars(legacyWindow);
+		}
+        return actionBars;
+    }
+
+	/**
+	 * Returns an array of the visible action sets.
+	 *
+	 * @return an array of the currently visible action sets
+	 */
+	public IActionSetDescriptor[] getActionSets() {
+		Collection<?> collection = actionSets.getVisibleItems();
+		return collection.toArray(new IActionSetDescriptor[collection.size()]);
+	}
+
+    /**
+     * @see IWorkbenchPage
+     */
+    @Override
+	public IEditorPart getActiveEditor() {
+		IWorkbenchPart activePart = getActivePart();
+		if (activePart instanceof IEditorPart) {
+			// if the currently active part is an editor, return it
+			return (IEditorPart) activePart;
+		}
+
+		if (!activationList.isEmpty()) {
+			IEditorPart editor = findActiveEditor();
+			if (editor != null) {
+				return editor;
+			}
+		}
+
+		MUIElement area = findSharedArea();
+		if (area instanceof MPlaceholder) {
+			area = ((MPlaceholder) area).getRef();
+		}
+		if (area != null && area.isVisible() && area.isToBeRendered()) {
+			// we have a shared area, try iterating over its editors first
+			List<MPart> editors = modelService.findElements(area,
+					CompatibilityEditor.MODEL_ELEMENT_ID, MPart.class, null);
+			for (MPart model : editors) {
+				Object object = model.getObject();
+				if (object instanceof CompatibilityEditor) {
+					CompatibilityEditor editor = (CompatibilityEditor) object;
+					// see bug 308492
+					if (!editor.isBeingDisposed() && isInArea(area, model)) {
+						return ((CompatibilityEditor) object).getEditor();
+					}
+				}
+			}
+		}
+
+		MPerspective perspective = getPerspectiveStack().getSelectedElement();
+		if (perspective == null) {
+			return null;
+		}
+
+		List<MPart> parts = modelService.findElements(perspective,
+				CompatibilityEditor.MODEL_ELEMENT_ID, MPart.class, null);
+		for (MPart part : parts) {
+			Object object = part.getObject();
+			if (object instanceof CompatibilityEditor) {
+				CompatibilityEditor editor = (CompatibilityEditor) object;
+				// see bug 308492
+				if (!editor.isBeingDisposed()) {
+					if (isValid(perspective, part) || isValid(window, part)) {
+						return ((CompatibilityEditor) object).getEditor();
+					}
+				}
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Searches and returns an editor from the activation list that is being
+	 * displayed in the current presentation. If an editor is in the
+	 * presentation but is behind another part it will not be returned.
+	 *
+	 * @return an editor that is being shown in the current presentation and was
+	 *         previously activated, editors that are behind another part in a
+	 *         stack will not be returned
+	 */
+	private IEditorPart findActiveEditor() {
+		List<MPart> candidates = new ArrayList<>(activationList);
+		MUIElement area = findSharedArea();
+		if (area instanceof MPlaceholder) {
+			area = ((MPlaceholder) area).getRef();
+		}
+		if (area != null && area.isVisible() && area.isToBeRendered()) {
+			// we have a shared area, try iterating over its editors first
+			List<MPart> editors = modelService
+					.findElements(area, CompatibilityEditor.MODEL_ELEMENT_ID, MPart.class, null);
+			for (Iterator<MPart> it = candidates.iterator(); it.hasNext();) {
+				MPart model = it.next();
+				if (!editors.contains(model)) {
+					continue;
+				}
+
+				Object object = model.getObject();
+				if (object instanceof CompatibilityEditor) {
+					CompatibilityEditor editor = (CompatibilityEditor) object;
+					// see bug 308492
+					if (!editor.isBeingDisposed() && isInArea(area, model)) {
+						return ((CompatibilityEditor) object).getEditor();
+					}
+				}
+				it.remove();
+			}
+		}
+
+		MPerspective perspective = getPerspectiveStack().getSelectedElement();
+		for (MPart model : activationList) {
+			Object object = model.getObject();
+			if (object instanceof CompatibilityEditor) {
+				CompatibilityEditor editor = (CompatibilityEditor) object;
+				// see bug 308492
+				if (!editor.isBeingDisposed()) {
+					if (isValid(perspective, model) || isValid(window, model)) {
+						return ((CompatibilityEditor) object).getEditor();
+					}
+				}
+			}
+		}
+		return null;
+    }
+
+	private boolean isInArea(MUIElement area, MUIElement element) {
+		if (!element.isToBeRendered() || !element.isVisible()) {
+			return false;
+		}
+
+		if (element == area) {
+			return true;
+		}
+
+		MElementContainer<?> parent = element.getParent();
+		if (parent == null || parent instanceof MPerspective || parent instanceof MWindow) {
+			return false;
+		} else if (parent instanceof MGenericStack) {
+			return parent.getSelectedElement() == element ? isValid(area, parent) : false;
+		}
+
+		return isValid(area, parent);
+	}
+
+	private boolean isValid(MUIElement ancestor, MUIElement element) {
+		if (!element.isToBeRendered() || !element.isVisible()) {
+			return false;
+		}
+
+		if (element == ancestor) {
+			return true;
+		}
+
+		MElementContainer<?> parent = element.getParent();
+		if (parent == null) {
+			// might be a detached window
+			if (element instanceof MWindow) {
+				parent = (MElementContainer<?>) ((EObject) element).eContainer();
+			}
+
+			if (parent == null) {
+				return false;
+			}
+		}
+
+		if (parent instanceof MGenericStack) {
+			return parent.getSelectedElement() == element ? isValid(ancestor, parent) : false;
+		}
+
+		return isValid(ancestor, parent);
+	}
+
+    @Override
+	public IWorkbenchPart getActivePart() {
+		MPart part = partService.getActivePart();
+		return getWorkbenchPart(part);
+	}
+
+	@Override
+	public IWorkbenchPartReference getActivePartReference() {
+		IWorkbenchPart part = getActivePart();
+		return part == null ? null : getReference(part);
+	}
+
+	public Composite getClientComposite() {
+		return composite;
+	}
+
+	@Override
+	public IEditorPart[] getDirtyEditors() {
+		List<IEditorPart> dirtyEditors = new ArrayList<>();
+		for (IEditorReference editorRef : editorReferences) {
+			IEditorPart editor = editorRef.getEditor(false);
+			if (editor != null && editor.isDirty()) {
+				dirtyEditors.add(editor);
+			}
+		}
+		return dirtyEditors.toArray(new IEditorPart[dirtyEditors.size()]);
+	}
+
+	@Override
+	public IEditorPart findEditor(IEditorInput input) {
+		IEditorReference[] references = findEditors(input, null, MATCH_INPUT);
+		return references.length == 0 ? null : references[0].getEditor(true);
+	}
+
+	@Override
+	public IEditorReference[] findEditors(IEditorInput input, String editorId, int matchFlags) {
+		List<EditorReference> filteredReferences = getSortedEditorReferences();
+
+		switch (matchFlags) {
+		case MATCH_INPUT:
+			List<IEditorReference> editorRefs = new ArrayList<>();
+			for (EditorReference editorRef : filteredReferences) {
+				checkEditor(input, editorRefs, editorRef);
+			}
+			return editorRefs.toArray(new IEditorReference[editorRefs.size()]);
+		case MATCH_ID:
+			editorRefs = new ArrayList<>();
+			for (IEditorReference editorRef : filteredReferences) {
+				if (editorId.equals(editorRef.getId())) {
+					editorRefs.add(editorRef);
+				}
+			}
+			return editorRefs.toArray(new IEditorReference[editorRefs.size()]);
+		default:
+			if ((matchFlags & IWorkbenchPage.MATCH_ID) != 0
+					&& (matchFlags & IWorkbenchPage.MATCH_INPUT) != 0) {
+				editorRefs = new ArrayList<>();
+				for (EditorReference editorRef : filteredReferences) {
+					if (editorRef.getId().equals(editorId)) {
+						checkEditor(input, editorRefs, editorRef);
+					}
+				}
+				return editorRefs.toArray(new IEditorReference[editorRefs.size()]);
+			}
+			return new IEditorReference[0];
+		}
+	}
+
+	private void checkEditor(IEditorInput input, List<IEditorReference> editorRefs,
+			EditorReference editorRef) {
+		EditorDescriptor descriptor = editorRef.getDescriptor();
+		if (descriptor != null) {
+			IEditorMatchingStrategy strategy = descriptor.getEditorMatchingStrategy();
+			if (strategy != null && strategy.matches(editorRef, input)) {
+				editorRefs.add(editorRef);
+				return;
+			}
+		}
+
+		IEditorPart editor = editorRef.getEditor(false);
+		if (editor == null) {
+			try {
+				String name = input.getName();
+				IPersistableElement persistable = input.getPersistable();
+				if (name == null || persistable == null) {
+					return;
+				}
+
+				String id = persistable.getFactoryId();
+				if (id != null && id.equals(editorRef.getFactoryId())
+						&& name.equals(editorRef.getName())
+						&& input.equals(editorRef.getEditorInput())) {
+					editorRefs.add(editorRef);
+				}
+			} catch (PartInitException e) {
+				WorkbenchPlugin.log(e);
+			}
+		} else if (editor.getEditorInput().equals(input)) {
+			editorRefs.add(editorRef);
+		}
+	}
+
+	@Override
+	public IEditorPart[] getEditors() {
+		final IEditorReference[] editorReferences = getEditorReferences();
+		int length = editorReferences.length;
+		IEditorPart[] editors = new IEditorPart[length];
+		for (int i = 0; i < length; i++) {
+			editors[i] = editorReferences[i].getEditor(true);
+		}
+		return editors;
+	}
+
+	@Override
+	public IEditorReference[] getEditorReferences() {
+		List<EditorReference> references = getOrderedEditorReferences();
+		return references.toArray(new IEditorReference[references.size()]);
+	}
+
+	public IEditorReference[] getSortedEditors() {
+		IWorkbenchPartReference[] parts = getSortedParts(true, false, false);
+		IEditorReference[] editors = new IEditorReference[parts.length];
+		System.arraycopy(parts, 0, editors, 0, parts.length);
+		return editors;
+	}
+
+	public IWorkbenchPartReference[] getSortedParts() {
+		return getSortedParts(true, true, false);
+	}
+
+	/**
+	 * Returns a sorted array of references to editors and/or views from this
+	 * page.
+	 *
+	 * @param editors
+	 *            include editors
+	 * @param views
+	 *            include views
+	 * @param allPerspectives
+	 *            if {@code false}, does not include parts from inactive
+	 *            perspectives
+	 * @return a sorted array of references to editors and/or views
+	 */
+	private IWorkbenchPartReference[] getSortedParts(boolean editors, boolean views,
+			boolean allPerspectives) {
+		if (!editors && !views) {
+			return new IWorkbenchPartReference[0];
+		}
+
+		List<IWorkbenchPartReference> sortedReferences = new ArrayList<>();
+		IViewReference[] viewReferences = getViewReferences(allPerspectives);
+		List<EditorReference> editorReferences = getSortedEditorReferences(allPerspectives);
+
+		activationLoop: for (MPart part : activationList) {
+			if (views) {
+				for (IViewReference ref : viewReferences) {
+					if (((ViewReference) ref).getModel() == part) {
+						sortedReferences.add(ref);
+						continue activationLoop;
+					}
+				}
+			}
+
+			if (editors) {
+				for (EditorReference ref : editorReferences) {
+					if (ref.getModel() == part) {
+						sortedReferences.add(ref);
+						break;
+					}
+				}
+			}
+		}
+
+		if (views) {
+			for (IViewReference ref : viewReferences) {
+				if (!sortedReferences.contains(ref)) {
+					sortedReferences.add(ref);
+				}
+			}
+		}
+
+		if (editors) {
+			for (EditorReference ref : editorReferences) {
+				if (!sortedReferences.contains(ref)) {
+					sortedReferences.add(ref);
+				}
+			}
+		}
+
+		return sortedReferences.toArray(new IWorkbenchPartReference[sortedReferences.size()]);
+	}
+
+    /**
+     * @see IWorkbenchPage
+     */
+    @Override
+	public IAdaptable getInput() {
+        return input;
+    }
+
+    /**
+     * Returns the page label. This is a combination of the page input and
+     * active perspective.
+     */
+    @Override
+	public String getLabel() {
+        String label = WorkbenchMessages.get().WorkbenchPage_UnknownLabel;
+        IWorkbenchAdapter adapter = Adapters.adapt(input, IWorkbenchAdapter.class);
+        if (adapter != null) {
+			label = adapter.getLabel(input);
+		}
+		// Perspective persp = getActivePerspective();
+		// if (persp != null) {
+		// label = NLS.bind(WorkbenchMessages.WorkbenchPage_PerspectiveFormat,
+		// label, persp.getDesc().getLabel());
+		// } else if (deferredActivePersp != null) {
+		// label =
+		// NLS.bind(WorkbenchMessages.WorkbenchPage_PerspectiveFormat,label,
+		// deferredActivePersp.getLabel());
+		// }
+        return label;
+    }
+
+    /**
+     * Returns the perspective.
+     */
+    @Override
+	public IPerspectiveDescriptor getPerspective() {
+		MPerspectiveStack ps = getPerspectiveStack();
+		MPerspective curPersp = ps.getSelectedElement();
+		if (curPersp == null)
+			return null;
+		return getPerspectiveDesc(curPersp.getElementId());
+	}
+
+	public IPerspectiveDescriptor getPerspectiveDesc(String id) {
+		IPerspectiveRegistry perspectiveRegistry = PlatformUI.getWorkbench().getPerspectiveRegistry();
+		// registry may be null on shutdown
+		if (perspectiveRegistry == null) {
+			return null;
+		}
+		IPerspectiveDescriptor desc = perspectiveRegistry
+				.findPerspectiveWithId(id);
+		return desc;
+	}
+
+    @Override
+	public ISelection getSelection() {
+		return selectionService.getSelection();
+    }
+
+    @Override
+	public ISelection getSelection(String partId) {
+		return selectionService.getSelection(partId);
+    }
+
+	/**
+	 * Returns the ids of the parts to list in the Show In... prompter. This is
+	 * a List of Strings.
+	 *
+	 * @return the ids of the parts that should be available in the 'Show In...'
+	 *         prompt
+	 */
+	public ArrayList<?> getShowInPartIds() {
+		MPerspective perspective = getPerspectiveStack().getSelectedElement();
+		return new ArrayList<>(ModeledPageLayout.getIds(perspective,
+				ModeledPageLayout.SHOW_IN_PART_TAG));
+	}
+
+	/**
+	 * The user successfully performed a Show In... action on the specified
+	 * part. Update the list of Show In items accordingly.
+	 *
+	 * @param partId
+	 *            the id of the part that the action was performed on
+	 */
+	public void performedShowIn(String partId) {
+		mruShowInPartIds.remove(partId);
+		mruShowInPartIds.add(0, partId);
+	}
+
+	/**
+	 * Sorts the given collection of show in target part ids in MRU order.
+	 *
+	 * @param partIds
+	 *            the collection of part ids to rearrange
+	 */
+	public void sortShowInPartIds(ArrayList<?> partIds) {
+		Collections.sort(partIds, new Comparator<Object>() {
+			@Override
+			public int compare(Object ob1, Object ob2) {
+				int index1 = mruShowInPartIds.indexOf(ob1);
+				int index2 = mruShowInPartIds.indexOf(ob2);
+				if (index1 != -1 && index2 == -1)
+					return -1;
+				if (index1 == -1 && index2 != -1)
+					return 1;
+				return index1 - index2;
+			}
+		});
+	}
+
+    /**
+     * See IWorkbenchPage.
+     */
+    @Override
+	public IViewReference[] getViewReferences() {
+		return getViewReferences(false);
+	}
+
+	private IViewReference[] getViewReferences(boolean allPerspectives) {
+		MPerspective perspective = getCurrentPerspective();
+		if (perspective != null) {
+			int scope = allPerspectives ? WINDOW_SCOPE : EModelService.PRESENTATION;
+			Set<MUIElement> parts = new HashSet<>();
+			List<MPlaceholder> placeholders = modelService.findElements(window, null, MPlaceholder.class, null, scope);
+			parts.addAll(placeholders);
+			parts.addAll(modelService.findElements(window, null, MPart.class, null, scope));
+			List<IViewReference> visibleReferences = new ArrayList<>();
+			for (ViewReference reference : viewReferences) {
+				MPart model = reference.getModel();
+				// The part may be linked in either directly or via a
+				// placeholder. In the latter case we can look directly
+				// at the part's curSharedRef since we're only considering
+				// parts visible in the current perspective
+				if (parts.contains(model) && model.isToBeRendered()
+						&& (model.getCurSharedRef() == null || model.getCurSharedRef().isToBeRendered())) {
+					// only rendered placeholders are valid view references
+					visibleReferences.add(reference);
+				}
+			}
+			return visibleReferences.toArray(new IViewReference[visibleReferences.size()]);
+		}
+		return new IViewReference[0];
+	}
+
+	/**
+	 * See IWorkbenchPage.
+	 */
+    @Override
+	public IViewPart[] getViews() {
+		IViewReference[] viewReferences = getViewReferences();
+		int length = viewReferences.length;
+		IViewPart[] views = new IViewPart[length];
+		for (int i = 0; i < length; i++) {
+			views[i] = viewReferences[i].getView(true);
+		}
+		return views;
+	}
+
+
+
+    /**
+	 * See IWorkbenchPage.
+	 */
+    @Override
+	public IWorkbenchWindow getWorkbenchWindow() {
+		return legacyWindow;
+    }
+
+    /**
+     * Implements IWorkbenchPage
+     *
+     * @see org.eclipse.ui.IWorkbenchPage#getWorkingSet()
+     * @since 2.0
+     * @deprecated individual views should store a working set if needed
+     */
+    @Deprecated
+	@Override
+	public IWorkingSet getWorkingSet() {
+        return workingSet;
+    }
+
+    /**
+     * @see IWorkbenchPage
+     */
+    @Override
+	public void hideActionSet(String actionSetID) {
+		MPerspective mpersp = getCurrentPerspective();
+		if (mpersp == null)
+			return;
+
+		Perspective persp = getActivePerspective();
+		if (persp != null) {
+			ActionSetRegistry reg = WorkbenchPlugin.getDefault().getActionSetRegistry();
+
+			IActionSetDescriptor desc = reg.findActionSet(actionSetID);
+			if (desc != null) {
+				persp.removeActionSet(desc);
+			}
+			legacyWindow.updateActionSets();
+			legacyWindow.firePerspectiveChanged(this, getPerspective(), CHANGE_ACTION_SET_HIDE);
+		}
+		String tag = ModeledPageLayout.ACTION_SET_TAG + actionSetID;
+		addHiddenItems(tag);
+    }
+
+	@Override
+	public void hideView(IViewReference view) {
+    	if (view != null) {
+    		for (IViewReference reference : getViewReferences()) {
+    			if (reference == view) {
+					hidePart(((ViewReference) view).getModel(), true, true, false);
+					break;
+    			}
+    		}
+		}
+	}
+
+	@Override
+	public void hideView(IViewPart view) {
+		if (view != null) {
+			MPart part = findPart(view);
+			if (part != null) {
+				hidePart(part, true, true, false);
+			}
+		}
+	}
+
+    /**
+     * Initialize the page.
+     *
+     * @param w
+     *            the parent window
+     * @param layoutID
+     *            may be <code>null</code> if restoring from file
+     * @param input
+     *            the page input
+     * @param openExtras
+     *            whether to process the perspective extras preference
+     */
+	private void init(WorkbenchWindow w, String layoutID, IAdaptable input, boolean openExtras) {
+		// Save args.
+		this.legacyWindow = w;
+        this.input = input;
+        actionSets = new ActionSetManager(w);
+		initActionSetListener();
+		initMaxFileSize();
+	}
+
+	private void initMaxFileSize() {
+		IPreferenceStore preferenceStore = PrefUtil.getInternalPreferenceStore();
+		maxFileSize = preferenceStore.getLong(IPreferenceConstants.LARGE_DOC_SIZE_FOR_EDITORS);
+		checkDocumentSize = maxFileSize != 0;
+	}
+
+	@PostConstruct
+	public void setup(MApplication application, EModelService modelService, IEventBroker broker,
+			MWindow window, EPartService partService) {
+		this.application = application;
+		this.modelService = modelService;
+		this.broker = broker;
+		this.window = window;
+		this.partService = partService;
+		selectionService = ContextInjectionFactory.make(SelectionService.class, window.getContext());
+
+		partService.addPartListener(e4PartListener);
+
+		// create editor references for all editors
+		List<MPart> editors = modelService.findElements(window,
+				CompatibilityEditor.MODEL_ELEMENT_ID, MPart.class, null,
+				EModelService.IN_ANY_PERSPECTIVE | EModelService.OUTSIDE_PERSPECTIVE
+						| EModelService.IN_SHARED_AREA);
+		for (MPart editor : editors) {
+			createEditorReferenceForPart(editor, null, editor.getElementId(), null);
+		}
+
+		// create view references for rendered view placeholders
+		List<MPlaceholder> placeholders = modelService.findElements(window, null,
+				MPlaceholder.class, null, EModelService.IN_ANY_PERSPECTIVE
+						| EModelService.OUTSIDE_PERSPECTIVE);
+		for (MPlaceholder placeholder : placeholders) {
+			if (placeholder.isToBeRendered()) {
+				MUIElement ref = placeholder.getRef();
+				if (ref instanceof MPart) {
+					MPart part = (MPart) ref;
+					String uri = part.getContributionURI();
+					if (uri.equals(CompatibilityPart.COMPATIBILITY_VIEW_URI)) {
+						createViewReferenceForPart(part, part.getElementId());
+					}
+				}
+			}
+		}
+
+		broker.subscribe(UIEvents.ElementContainer.TOPIC_SELECTEDELEMENT, selectionHandler);
+		broker.subscribe(UIEvents.UIElement.TOPIC_WIDGET, widgetHandler);
+		broker.subscribe(UIEvents.UIElement.TOPIC_TOBERENDERED, referenceRemovalEventHandler);
+		broker.subscribe(UIEvents.Contribution.TOPIC_OBJECT, firingHandler);
+		broker.subscribe(UIEvents.ElementContainer.TOPIC_CHILDREN, childrenHandler);
+
+		// Bug 479126 PERSPECTIVE_BAR_EXTRAS setting not taken into account
+		createPerspectiveBarExtras();
+
+		MPerspectiveStack perspectiveStack = getPerspectiveStack();
+		if (perspectiveStack != null) {
+			extendPerspectives(perspectiveStack);
+		}
+
+		IPerspectiveRegistry registry = getWorkbenchWindow().getWorkbench()
+				.getPerspectiveRegistry();
+		for (MPerspective perspective : perspectiveStack.getChildren()) {
+			IPerspectiveDescriptor desc = registry
+					.findPerspectiveWithId(perspective.getElementId());
+			if (desc != null) {
+				sortedPerspectives.add(desc);
+			}
+		}
+
+		MPerspective selectedPerspective = perspectiveStack.getSelectedElement();
+		if (selectedPerspective != null) {
+			IPerspectiveDescriptor desc = registry.findPerspectiveWithId(selectedPerspective
+					.getElementId());
+			if (desc != null) {
+				sortedPerspectives.remove(desc);
+				sortedPerspectives.add(desc);
+			}
+		}
+		restoreWorkingSets();
+		restoreShowInMruPartIdsList();
+		configureExistingWindows();
+    }
+
+	/*
+	 * Perform any configuration required for an existing MWindow. The
+	 * association of an MWindow to the WorkbenchWindow/WorkbenchPage can occur
+	 * at different times (see Bug 454056 for details).
+	 */
+	private void configureExistingWindows() {
+		List<MArea> elements = modelService.findElements(window, null, MArea.class, null);
+		for (MArea area : elements) {
+			Object widget = area.getWidget();
+			if (widget instanceof Control) {
+				installAreaDropSupport((Control) widget);
+			}
+		}
+	}
+
+	public void restoreWorkingSets() {
+		String workingSetName = getWindowModel().getPersistedState().get(
+				IWorkbenchConstants.TAG_WORKING_SET);
+		if (workingSetName != null) {
+			AbstractWorkingSetManager workingSetManager = (AbstractWorkingSetManager) getWorkbenchWindow()
+					.getWorkbench().getWorkingSetManager();
+			setWorkingSet(workingSetManager.getWorkingSet(workingSetName));
+		}
+
+		String workingSetMemString = getWindowModel().getPersistedState().get(
+				IWorkbenchConstants.TAG_WORKING_SETS);
+		if (workingSetMemString != null) {
+			IMemento workingSetMem;
+			try {
+				workingSetMem = XMLMemento.createReadRoot(new StringReader(workingSetMemString));
+				IMemento[] workingSetChildren = workingSetMem
+						.getChildren(IWorkbenchConstants.TAG_WORKING_SET);
+				List<IWorkingSet> workingSetList = new ArrayList<>(workingSetChildren.length);
+				for (IMemento memento : workingSetChildren) {
+					IWorkingSet set = getWorkbenchWindow().getWorkbench().getWorkingSetManager()
+							.getWorkingSet(memento.getID());
+					if (set != null) {
+						workingSetList.add(set);
+					}
+				}
+
+				workingSets = workingSetList.toArray(new IWorkingSet[workingSetList.size()]);
+			} catch (WorkbenchException e) {
+				StatusManager.getManager().handle(
+						new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, IStatus.ERROR,
+								WorkbenchMessages.get().WorkbenchPage_problemRestoringTitle, e));
+			}
+		}
+
+		aggregateWorkingSetId = getWindowModel().getPersistedState().get(
+				ATT_AGGREGATE_WORKING_SET_ID);
+	}
+
+	private void restoreShowInMruPartIdsList() {
+		String mruList = getWindowModel().getPersistedState().get(IWorkbenchConstants.TAG_SHOW_IN_TIME);
+		if (mruList != null) {
+			try {
+				IMemento memento = XMLMemento.createReadRoot(new StringReader(mruList));
+				IMemento[] mementoChildren = memento.getChildren();
+				for (IMemento child : mementoChildren) {
+					mruShowInPartIds.add(child.getID());
+				}
+			} catch (WorkbenchException e) {
+				StatusManager.getManager().handle(
+						new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, IStatus.ERROR,
+								WorkbenchMessages.get().WorkbenchPage_problemRestoringTitle, e));
+			}
+		}
+	}
+
+	@PreDestroy
+	public void saveWorkingSets() {
+		// Save working set if set
+		if (workingSet != null) {
+			getWindowModel().getPersistedState().put(IWorkbenchConstants.TAG_WORKING_SET,
+					workingSet.getName());
+		} else {
+			getWindowModel().getPersistedState().remove(IWorkbenchConstants.TAG_WORKING_SET);
+		}
+
+		List<String> workingSetNames = new ArrayList<>(workingSets.length);
+		for (IWorkingSet workingSet : workingSets) {
+			workingSetNames.add(workingSet.getName());
+		}
+		saveMemento(IWorkbenchConstants.TAG_WORKING_SETS, IWorkbenchConstants.TAG_WORKING_SET, workingSetNames);
+
+		getWindowModel().getPersistedState().put(ATT_AGGREGATE_WORKING_SET_ID,
+				aggregateWorkingSetId);
+	}
+
+	@PreDestroy
+	public void saveShowInMruPartIdsList() {
+		saveMemento(IWorkbenchConstants.TAG_SHOW_IN_TIME, IWorkbenchConstants.TAG_ID, mruShowInPartIds);
+	}
+
+	private void saveMemento(String rootType, String childType, Collection<String> ids) {
+		XMLMemento memento = XMLMemento.createWriteRoot(rootType);
+		for (String id : ids) {
+			memento.createChild(childType, id);
+		}
+		StringWriter writer = new StringWriter();
+		try {
+			memento.save(writer);
+			getWindowModel().getPersistedState().put(rootType, writer.getBuffer().toString());
+		} catch (IOException e) {
+			// Simply don't store the settings
+			StatusManager.getManager().handle(
+					new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, IStatus.ERROR, WorkbenchMessages.get().SavingProblem, e));
+		}
+	}
+
+	/**
+	 * Extends the perspectives within the given stack with action set
+	 * contributions from the <code>perspectiveExtensions</code> extension
+	 * point.
+	 *
+	 * @param perspectiveStack
+	 *            the stack that contain the perspectives to be extended
+	 */
+	private void extendPerspectives(MPerspectiveStack perspectiveStack) {
+		for (MPerspective perspective : perspectiveStack.getChildren()) {
+			String id = perspective.getElementId();
+			IPerspectiveDescriptor desc = getWorkbenchWindow().getWorkbench()
+					.getPerspectiveRegistry().findPerspectiveWithId(id);
+			if (desc != null) {
+				MPerspective temporary = modelService.createModelElement(MPerspective.class);
+				ModeledPageLayout modelLayout = new ModeledPageLayout(window, modelService,
+						partService, temporary, desc, this, true);
+
+				PerspectiveExtensionReader reader = new PerspectiveExtensionReader();
+				reader.setIncludeOnlyTags(new String[] { IWorkbenchRegistryConstants.TAG_ACTION_SET });
+				reader.extendLayout(null, id, modelLayout);
+
+				addActionSet(perspective, temporary);
+			}
+		}
+	}
+
+	ArrayList<String> getPerspectiveExtensionActionSets(String id) {
+		IPerspectiveDescriptor desc = getWorkbenchWindow().getWorkbench().getPerspectiveRegistry()
+				.findPerspectiveWithId(id);
+		if (desc != null) {
+			MPerspective temporary = modelService.createModelElement(MPerspective.class);
+			ModeledPageLayout modelLayout = new ModeledPageLayout(window, modelService,
+					partService, temporary, desc, this, true);
+
+			PerspectiveExtensionReader reader = new PerspectiveExtensionReader();
+			reader.setIncludeOnlyTags(new String[] { IWorkbenchRegistryConstants.TAG_ACTION_SET });
+			reader.extendLayout(null, id, modelLayout);
+			return new ArrayList<>(ModeledPageLayout.getIds(temporary, ModeledPageLayout.ACTION_SET_TAG));
+		}
+		return null;
+	}
+
+	/**
+	 * Copies action set extensions from the temporary perspective to the other
+	 * one.
+	 *
+	 * @param perspective
+	 *            the perspective to copy action set contributions to
+	 * @param temporary
+	 *            the perspective to copy action set contributions from
+	 */
+	private void addActionSet(MPerspective perspective, MPerspective temporary) {
+		List<String> tags = perspective.getTags();
+		List<String> extendedTags = temporary.getTags();
+		for (String extendedTag : extendedTags) {
+			if (!tags.contains(extendedTag)) {
+				tags.add(extendedTag);
+			}
+		}
+	}
+
+	/**
+	 * Installs drop support into the shared area so that editors can be opened
+	 * by dragging and dropping files into it.
+	 *
+	 * @param control
+	 *            the control to attach the drop support to
+	 */
+	private void installAreaDropSupport(Control control) {
+		if (!dndSupportInstalled) {
+			WorkbenchWindowConfigurer configurer = legacyWindow.getWindowConfigurer();
+			DropTargetListener dropTargetListener = configurer.getDropTargetListener();
+			if (dropTargetListener != null) {
+				DropTarget dropTarget = new DropTarget(control, DND.DROP_DEFAULT | DND.DROP_COPY
+						| DND.DROP_LINK);
+				dropTarget.setTransfer(configurer.getTransfers());
+				dropTarget.addDropListener(dropTargetListener);
+			}
+			dndSupportInstalled = true;
+		}
+	}
+
+	private List<MPartStack> getPartStacks(MPerspective perspective) {
+		if (perspective == null) {
+			return Collections.emptyList();
+		}
+		return modelService.findElements(perspective, null, MPartStack.class, null);
+	}
+
+	private EventHandler selectionHandler = new EventHandler() {
+		@Override
+		public void handleEvent(Event event) {
+			Object changedElement = event.getProperty(UIEvents.EventTags.ELEMENT);
+
+			if (!(changedElement instanceof MPerspectiveStack)) {
+				return;
+			}
+
+			List<MPerspectiveStack> theStack = modelService.findElements(window, null,
+					MPerspectiveStack.class, null);
+			if (theStack.isEmpty()) {
+				return;
+			} else if (!theStack.isEmpty() && changedElement != theStack.get(0)) {
+				return;
+			}
+
+			MPerspective oldPersp = (MPerspective) event.getProperty(UIEvents.EventTags.OLD_VALUE);
+			MPerspective newPersp = (MPerspective) event.getProperty(UIEvents.EventTags.NEW_VALUE);
+			// updatePerspectiveActionSets(oldPersp, newPersp);
+
+			// ((CoolBarToTrimManager)
+			// legacyWindow.getCoolBarManager2()).updateAll(true);
+			// legacyWindow.menuManager.updateAll(true);
+
+			List<MPart> hiddenParts = new ArrayList<>();
+			List<MPart> visibleParts = new ArrayList<>();
+
+			List<MPartStack> oldStacks = getPartStacks(oldPersp);
+			List<MPartStack> newStacks = getPartStacks(newPersp);
+
+			for (MPartStack oldStack : oldStacks) {
+				MStackElement element = oldStack.getSelectedElement();
+				if (element instanceof MPlaceholder) {
+					hiddenParts.add((MPart) ((MPlaceholder) element).getRef());
+				} else if (element instanceof MPart) {
+					hiddenParts.add((MPart) element);
+				}
+			}
+
+			for (MPartStack newStack : newStacks) {
+				MStackElement element = newStack.getSelectedElement();
+				if (element instanceof MPlaceholder) {
+					visibleParts.add((MPart) ((MPlaceholder) element).getRef());
+				} else if (element instanceof MPart) {
+					visibleParts.add((MPart) element);
+				}
+			}
+
+			List<MPart> ignoredParts = new ArrayList<>();
+			for (MPart hiddenPart : hiddenParts) {
+				if (visibleParts.contains(hiddenPart)) {
+					ignoredParts.add(hiddenPart);
+				}
+			}
+
+			hiddenParts.removeAll(ignoredParts);
+			visibleParts.removeAll(ignoredParts);
+
+			for (MPart hiddenPart : hiddenParts) {
+				firePartHidden(hiddenPart);
+			}
+
+			for (MPart visiblePart : visibleParts) {
+				firePartVisible(visiblePart);
+			}
+
+			updateActionSets(getPerspective(oldPersp), getPerspective(newPersp));
+
+			// might've been set to null if we were closing the perspective
+			if (newPersp != null) {
+				IPerspectiveDescriptor perspective = getPerspectiveDesc(newPersp
+						.getElementId());
+				legacyWindow.firePerspectiveActivated(WorkbenchPage.this, perspective);
+
+				sortedPerspectives.remove(perspective);
+				sortedPerspectives.add(perspective);
+			}
+			legacyWindow.updateActionSets();
+		}
+	};
+
+	/**
+     * See IWorkbenchPage.
+     */
+    @Override
+	public boolean isPartVisible(IWorkbenchPart part) {
+		MPart mpart = findPart(part);
+		return mpart == null ? false : partService.isPartVisible(mpart);
+    }
+
+	public MUIElement findSharedArea() {
+		MPerspective perspective = getPerspectiveStack().getSelectedElement();
+		return perspective == null ? null : modelService.find(IPageLayout.ID_EDITOR_AREA,
+				perspective);
+	}
+
+    /**
+     * See IWorkbenchPage.
+     */
+    @Override
+	public boolean isEditorAreaVisible() {
+		MUIElement find = findSharedArea();
+		return find == null ? false : find.isVisible() && find.isToBeRendered();
+    }
+
+    @Override
+	public boolean isPageZoomed() {
+		List<String> maxTag = new ArrayList<>();
+		maxTag.add(IPresentationEngine.MAXIMIZED);
+		List<Object> maxElements = modelService.findElements(window, null, null, maxTag);
+		return maxElements.size() > 0;
+    }
+
+
+	// /**
+	// * This method is called when the page is activated.
+	// */
+	// protected void onActivate() {
+	// composite.setVisible(true);
+	// Perspective persp = getActivePerspective();
+	//
+	// if (persp != null) {
+	// persp.onActivate();
+	// updateVisibility(null, persp);
+	// }
+	// }
+	//
+	// /**
+	// * This method is called when the page is deactivated.
+	// */
+	// protected void onDeactivate() {
+	// makeActiveEditor(null);
+	// makeActive(null);
+	// if (getActivePerspective() != null) {
+	// getActivePerspective().onDeactivate();
+	// }
+	// composite.setVisible(false);
+	// }
+
+    /**
+     * See IWorkbenchPage.
+     */
+    @Override
+	public void reuseEditor(IReusableEditor editor, IEditorInput input) {
+
+        // Rather than calling editor.setInput on the editor directly, we do it through the part reference.
+        // This case lets us detect badly behaved editors that are not firing a PROP_INPUT event in response
+        // to the input change... but if all editors obeyed their API contract, the "else" branch would be
+        // sufficient.
+
+		// TODO compat: should we be talking to the editor reference here
+		editor.setInput(input);
+        navigationHistory.markEditor(editor);
+    }
+
+    /**
+     * See IWorkbenchPage.
+     */
+    @Override
+	public IEditorPart openEditor(IEditorInput input, String editorID)
+            throws PartInitException {
+        return openEditor(input, editorID, true, MATCH_INPUT);
+    }
+
+    /**
+     * See IWorkbenchPage.
+     */
+    @Override
+	public IEditorPart openEditor(IEditorInput input, String editorID,
+			boolean activate) throws PartInitException {
+		return openEditor(input, editorID, activate, MATCH_INPUT);
+    }
+
+    /**
+     * See IWorkbenchPage.
+     */
+    @Override
+	public IEditorPart openEditor(final IEditorInput input,
+            final String editorID, final boolean activate, final int matchFlags)
+            throws PartInitException {
+    	return openEditor(input, editorID, activate, matchFlags, null, true);
+    }
+
+	/**
+	 * This is not public API but for use internally. editorState can be
+	 * <code>null</code>.
+	 *
+	 * @param input
+	 *            the input to open the editor with
+	 * @param editorID
+	 *            the id of the editor to open
+	 * @param activate
+	 *            <tt>true</tt> if the editor should be activated,
+	 *            <tt>false</tt> otherwise
+	 * @param matchFlags
+	 *            a bit mask consisting of zero or more of the MATCH_* constants
+	 *            OR-ed together
+	 * @param editorState
+	 *            the previously saved state of the editor as a memento, this
+	 *            may be <tt>null</tt>
+	 * @param notify
+	 *            <tt>true</tt> if the perspective should fire off events about
+	 *            the editors being opened, <tt>false</tt> otherwise
+	 * @return the opened editor
+	 * @exception PartInitException
+	 *                if the editor could not be created or initialized
+	 */
+	public IEditorPart openEditor(final IEditorInput input, final String editorID,
+			final boolean activate, final int matchFlags, final IMemento editorState,
+			final boolean notify) throws PartInitException {
+        if (input == null || editorID == null) {
+            throw new IllegalArgumentException();
+        }
+
+        final IEditorPart result[] = new IEditorPart[1];
+        final PartInitException ex[] = new PartInitException[1];
+		BusyIndicator.showWhile(legacyWindow.getWorkbench().getDisplay(),
+                new Runnable() {
+                    @Override
+					public void run() {
+                        try {
+					result[0] = busyOpenEditor(input, editorID, activate, matchFlags, editorState,
+							notify);
+                        } catch (PartInitException e) {
+                            ex[0] = e;
+                        }
+                    }
+                });
+        if (ex[0] != null) {
+			throw ex[0];
+		}
+        return result[0];
+    }
+
+
+
+    /**
+     * @see #openEditor(IEditorInput, String, boolean, int)
+	 */
+	private IEditorPart busyOpenEditor(IEditorInput input, String editorId, boolean activate,
+			int matchFlags, IMemento editorState, boolean notify) throws PartInitException {
+
+		if (input == null || editorId == null) {
+			throw new IllegalArgumentException();
+		}
+
+		// RAP no external editors
+//		// Special handling for external editors (they have no tabs...)
+//		if ("org.eclipse.ui.systemExternalEditor".equals(editorId)) { //$NON-NLS-1$
+//			IPathEditorInput fileInput = getPathEditorInput(input);
+//			if (fileInput == null) {
+//				throw new PartInitException(WorkbenchMessages.get().EditorManager_systemEditorError);
+//			}
+//
+//			String fullPath = fileInput.getPath().toOSString();
+//			Program.launch(fullPath);
+//			return null;
+//		}
+
+		IEditorDescriptor desc = getWorkbenchWindow().getWorkbench()
+				.getEditorRegistry().findEditor(editorId);
+		if (desc != null && !desc.isOpenExternal() && isLargeDocument(input)) {
+			desc = getAlternateEditor();
+			if (desc == null) {
+				// the user pressed cancel in the editor selection dialog
+				return null;
+			}
+		}
+		if (desc == null) {
+			throw new PartInitException(NLS.bind(
+					WorkbenchMessages.get().EditorManager_unknownEditorIDMessage, editorId));
+		}
+
+		setEditorAreaVisible(true);
+
+		IEditorReference[] editorReferences = findEditors(input, editorId, matchFlags);
+		if (editorReferences.length != 0) {
+			IEditorPart editor = editorReferences[0].getEditor(true);
+			if (editor instanceof IShowEditorInput) {
+				((IShowEditorInput) editor).showEditorInput(input);
+			}
+
+			partService.showPart(((EditorReference) editorReferences[0]).getModel(),
+					PartState.VISIBLE);
+
+			if (activate) {
+				activate(editor);
+			}
+
+			recordEditor(input, desc);
+			return editor;
+		} else if (desc.isInternal()) {
+			// look for an editor to reuse
+			EditorReference reusableEditorRef = (EditorReference) ((TabBehaviour) Tweaklets
+					.get(TabBehaviour.KEY)).findReusableEditor(this);
+			if (reusableEditorRef != null) {
+				IEditorPart reusableEditor = reusableEditorRef.getEditor(false);
+				if (editorId.equals(reusableEditorRef.getId())
+						&& reusableEditor instanceof IReusableEditor) {
+					// reusable editors that share the same id are okay
+					recordEditor(input, desc);
+					reuseEditor((IReusableEditor) reusableEditor, input);
+
+					MPart editor = reusableEditorRef.getModel();
+					partService.showPart(editor, PartState.VISIBLE);
+					if (activate) {
+						partService.activate(editor);
+					} else {
+						updateActiveEditorSources(editor);
+					}
+					return reusableEditor;
+				}
+				// should have saved already if necessary, close this editor, a
+				// new one will be opened
+				closeEditor(reusableEditorRef, false);
+			}
+		} else if (desc.isOpenExternal()) {
+			openExternalEditor((EditorDescriptor) desc, input);
+			// no editor parts for external editors, return null
+			return null;
+		}
+
+		MPart editor = partService.createPart(CompatibilityEditor.MODEL_ELEMENT_ID);
+		editor.getTags().add(editorId);
+		EditorReference ref = createEditorReferenceForPart(editor, input, editorId, editorState);
+		partService.showPart(editor, PartState.VISIBLE);
+
+		CompatibilityEditor compatibilityEditor = (CompatibilityEditor) editor.getObject();
+		if (compatibilityEditor == null) {
+			return null;
+		}
+
+		if (activate) {
+			partService.activate(editor);
+		} else {
+			updateActiveEditorSources(editor);
+		}
+
+		if (notify) {
+			legacyWindow.firePerspectiveChanged(this, getPerspective(), ref, CHANGE_EDITOR_OPEN);
+			legacyWindow.firePerspectiveChanged(this, getPerspective(), CHANGE_EDITOR_OPEN);
+		}
+
+		recordEditor(input, desc);
+		return compatibilityEditor.getEditor();
+    }
+
+	private void recordEditor(IEditorInput input, IEditorDescriptor descriptor) {
+		EditorHistory history = ((Workbench) legacyWindow.getWorkbench()).getEditorHistory();
+		history.add(input, descriptor);
+	}
+
+	private static IEditorDescriptor getAlternateEditor() {
+		Shell shell = ProgressManagerUtil.getDefaultParent();
+		EditorSelectionDialog dialog = new EditorSelectionDialog(shell) {
+			@Override
+			protected IDialogSettings getDialogSettings() {
+				IDialogSettings result = new DialogSettings("EditorSelectionDialog"); //$NON-NLS-1$
+				result.put(EditorSelectionDialog.STORE_ID_INTERNAL_EXTERNAL, true);
+				return result;
+			}
+		};
+		dialog.setMessage(WorkbenchMessages.get().EditorManager_largeDocumentWarning);
+
+		if (dialog.open() == Window.OK)
+			return dialog.getSelectedEditor();
+		return null;
+	}
+
+	boolean isLargeDocument(IEditorInput editorInput) {
+
+		if (!checkDocumentSize)
+			return false;
+
+		if (!(editorInput instanceof IPathEditorInput))
+			return false; // we know nothing about it
+
+		try {
+			IPath path = ((IPathEditorInput) editorInput).getPath();
+			File file = new File(path.toOSString());
+			return file.length() > maxFileSize;
+		} catch (Exception e) {
+			// ignore exceptions
+			return false;
+		}
+	}
+
+    /**
+     * See IWorkbenchPage.
+     */
+    @Override
+	public boolean isEditorPinned(IEditorPart editor) {
+    	WorkbenchPartReference ref = (WorkbenchPartReference)getReference(editor);
+        return ref != null && ref.isPinned();
+    }
+
+
+
+    /**
+     * Removes an IPartListener from the part service.
+     */
+    @Override
+	public void removePartListener(IPartListener l) {
+		partListenerList.remove(l);
+    }
+
+    /**
+     * Removes an IPartListener from the part service.
+     */
+    @Override
+	public void removePartListener(IPartListener2 l) {
+		partListener2List.remove(l);
+    }
+
+    /**
+     * Implements IWorkbenchPage
+     *
+     * @see org.eclipse.ui.IWorkbenchPage#removePropertyChangeListener(IPropertyChangeListener)
+     * @since 2.0
+     * @deprecated individual views should store a working set if needed and
+     *             register a property change listener directly with the
+     *             working set manager to receive notification when the view
+     *             working set is removed.
+     */
+    @Deprecated
+	@Override
+	public void removePropertyChangeListener(IPropertyChangeListener listener) {
+        propertyChangeListeners.remove(listener);
+    }
+
+    @Override
+	public void removeSelectionListener(ISelectionListener listener) {
+		selectionService.removeSelectionListener(listener);
+    }
+
+    @Override
+	public void removeSelectionListener(String partId,
+            ISelectionListener listener) {
+		selectionService.removeSelectionListener(partId, listener);
+    }
+
+    @Override
+	public void removePostSelectionListener(ISelectionListener listener) {
+		selectionService.removePostSelectionListener(listener);
+    }
+
+    @Override
+	public void removePostSelectionListener(String partId,
+            ISelectionListener listener) {
+		selectionService.removePostSelectionListener(partId, listener);
+    }
+
+
+
+    /**
+     * Resets the layout for the perspective. The active part in the old layout
+     * is activated in the new layout for consistent user context.
+     */
+    @Override
+	public void resetPerspective() {
+		MPerspectiveStack perspStack = getPerspectiveStack();
+		MPerspective persp = perspStack.getSelectedElement();
+		if (persp == null)
+			return;
+
+		// HACK!! the 'perspective' field doesn't match reality...
+		IPerspectiveDescriptor desc = PlatformUI.getWorkbench().getPerspectiveRegistry()
+				.findPerspectiveWithId(persp.getElementId());
+		if (desc == null)
+			return;
+
+		// send out reset notification
+		legacyWindow.firePerspectiveChanged(this, desc, CHANGE_RESET);
+
+		// collect all the parts under the current perspective
+		List<MPart> perspectiveParts = modelService.findElements(persp, null, MPart.class, null);
+		// find the shared area
+		MUIElement area = findSharedArea();
+		if (area != null) {
+			// remove all editors in the shared area from the list of parts
+			perspectiveParts.removeAll(modelService.findElements(area,
+					CompatibilityEditor.MODEL_ELEMENT_ID, MPart.class, null));
+		}
+
+		List<MPart> dirtyParts = new ArrayList<>();
+		List<IWorkbenchPart> partsToSave = new ArrayList<>();
+		// iterate over the list of parts to find dirty parts
+		for (MPart currentPart : perspectiveParts) {
+			if (currentPart.isDirty()) {
+				Object object = currentPart.getObject();
+				if (object == null) {
+					continue;
+				} else if (object instanceof CompatibilityPart) {
+					IWorkbenchPart workbenchPart = ((CompatibilityPart) object).getPart();
+					ISaveablePart saveable = SaveableHelper.getSaveable(workbenchPart);
+					if (saveable == null || !saveable.isSaveOnCloseNeeded()) {
+						continue;
+					}
+					partsToSave.add(workbenchPart);
+				}
+
+				dirtyParts.add(currentPart);
+			}
+		}
+
+		SaveablesList saveablesList = null;
+		Object postCloseInfo = null;
+		if (partsToSave.size() > 0) {
+			saveablesList = (SaveablesList) getWorkbenchWindow().getService(
+					ISaveablesLifecycleListener.class);
+			postCloseInfo = saveablesList.preCloseParts(partsToSave, true,
+					this.getWorkbenchWindow());
+			if (postCloseInfo == null) {
+				// cancel
+				// We're not going through with the reset, so it is
+				// complete.
+				legacyWindow.firePerspectiveChanged(this, desc, CHANGE_RESET_COMPLETE);
+				return;
+			}
+		}
+
+		modelService.resetPerspectiveModel(persp, window);
+
+		if (saveablesList != null) {
+			saveablesList.postClose(postCloseInfo);
+		}
+
+		boolean revert = false;
+		if (desc instanceof PerspectiveDescriptor) {
+			PerspectiveDescriptor perspectiveDescriptor = (PerspectiveDescriptor) desc;
+			revert = perspectiveDescriptor.isPredefined()
+					&& !perspectiveDescriptor.hasCustomDefinition();
+		}
+
+		MPerspective dummyPerspective = null;
+		if (!revert) {
+			dummyPerspective = (MPerspective) modelService.cloneSnippet(application, desc.getId(),
+					window);
+			if (dummyPerspective != null) {
+				handleNullRefPlaceHolders(dummyPerspective, window);
+			}
+		}
+
+		if (dummyPerspective == null) {
+			// instantiate a dummy perspective perspective
+			dummyPerspective = modelService.createModelElement(MPerspective.class);
+			dummyPerspective.setElementId(persp.getElementId());
+
+			IPerspectiveFactory factory = ((PerspectiveDescriptor) desc).createFactory();
+			ModeledPageLayout modelLayout = new ModeledPageLayout(window, modelService,
+					partService, dummyPerspective, desc, this, true);
+			factory.createInitialLayout(modelLayout);
+
+			PerspectiveTagger.tagPerspective(dummyPerspective, modelService);
+			PerspectiveExtensionReader reader = new PerspectiveExtensionReader();
+			reader.extendLayout(getExtensionTracker(), desc.getId(), modelLayout);
+		}
+
+		String hiddenItems = dummyPerspective.getPersistedState().get(ModeledPageLayout.HIDDEN_ITEMS_KEY);
+		persp.getPersistedState().put(ModeledPageLayout.HIDDEN_ITEMS_KEY, hiddenItems);
+
+		legacyWindow.getMenuManager().updateAll(true);
+		// ((ICoolBarManager2) ((WorkbenchWindow)
+		// getWorkbenchWindow()).getCoolBarManager2())
+		// .resetItemOrder();
+
+		// Hide placeholders for parts that exist in the 'global' areas
+		modelService.hideLocalPlaceholders(window, dummyPerspective);
+
+		int dCount = dummyPerspective.getChildren().size();
+		while (dummyPerspective.getChildren().size() > 0) {
+			MPartSashContainerElement dChild = dummyPerspective.getChildren().remove(0);
+			persp.getChildren().add(dChild);
+		}
+
+		while (persp.getChildren().size() > dCount) {
+			MUIElement child = persp.getChildren().get(0);
+			child.setToBeRendered(false);
+			persp.getChildren().remove(0);
+		}
+
+		List<MWindow> existingDetachedWindows = new ArrayList<>();
+		existingDetachedWindows.addAll(persp.getWindows());
+
+		// Move any detached windows from template to perspective
+		while (dummyPerspective.getWindows().size() > 0) {
+			MWindow detachedWindow = dummyPerspective.getWindows().remove(0);
+			persp.getWindows().add(detachedWindow);
+		}
+
+		// Remove original windows.  Can't remove them first or the MParts will be disposed
+		for (MWindow detachedWindow : existingDetachedWindows) {
+			detachedWindow.setToBeRendered(false);
+			persp.getWindows().remove(detachedWindow);
+		}
+
+		// deactivate and activate other action sets as
+		Perspective oldPersp = getPerspective(persp);
+		Perspective dummyPersp = getPerspective(dummyPerspective);
+		updateActionSets(oldPersp, dummyPersp);
+		oldPersp.getAlwaysOnActionSets().clear();
+		oldPersp.getAlwaysOnActionSets().addAll(dummyPersp.getAlwaysOnActionSets());
+		oldPersp.getAlwaysOffActionSets().clear();
+		oldPersp.getAlwaysOffActionSets().addAll(dummyPersp.getAlwaysOffActionSets());
+
+		modelToPerspectiveMapping.remove(dummyPerspective);
+
+		// partly fixing toolbar refresh issue, see bug 383569 comment 10
+		legacyWindow.updateActionSets();
+
+		// migrate the tags
+		List<String> tags = persp.getTags();
+		tags.clear();
+		tags.addAll(dummyPerspective.getTags());
+
+		// remove HIDDEN_EXPLICITLY tag from trim elements
+		List<MTrimElement> trimElements = modelService.findElements(window, null,
+				MTrimElement.class, null);
+		for (MTrimElement mTrimElement : trimElements) {
+			mTrimElement.getTags().remove(IPresentationEngine.HIDDEN_EXPLICITLY);
+		}
+
+		partService.requestActivation();
+
+		// reset complete
+		legacyWindow.firePerspectiveChanged(this, desc, CHANGE_RESET_COMPLETE);
+		UIEvents.publishEvent(UIEvents.UILifeCycle.PERSPECTIVE_RESET, persp);
+	}
+
+	private void initActionSetListener() {
+		// actionSets.addListener(new IPropertyListener() {
+		// public void propertyChanged(Object source, int propId) {
+		// if (source instanceof IActionSetDescriptor) {
+		// final IActionSetDescriptor desc = (IActionSetDescriptor) source;
+		// final String actionSetId = ModeledPageLayout.ACTION_SET_TAG +
+		// desc.getId();
+		// final MPerspective currentPerspective = getCurrentPerspective();
+		// if (currentPerspective != null) {
+		// final List<String> tags = currentPerspective.getTags();
+		// if (propId == ActionSetManager.PROP_VISIBLE) {
+		// if (!tags.contains(actionSetId)) {
+		// tags.add(actionSetId);
+		// }
+		// } else if (propId == ActionSetManager.PROP_HIDDEN) {
+		// tags.remove(actionSetId);
+		// }
+		// }
+		// }
+		// }
+		// });
+	}
+
+    /**
+     * See IWorkbenchPage
+     */
+    @Override
+	public boolean saveAllEditors(boolean confirm) {
+        return saveAllEditors(confirm, false, false);
+    }
+
+	/**
+	 * @return {@link ISaveablePart} objects derived from {@link IWorkbenchPart}
+	 *         's on this page
+	 */
+	public ISaveablePart[] getDirtyParts() {
+		List<ISaveablePart> result = new ArrayList<>(3);
+		IWorkbenchPartReference[] allParts = getSortedParts(true, true, true);
+		for (IWorkbenchPartReference reference : allParts) {
+			IWorkbenchPart part = reference.getPart(false);
+			ISaveablePart saveable = SaveableHelper.getSaveable(part);
+			if (saveable != null && !result.contains(saveable)) {
+				if (saveable.isDirty()) {
+					result.add(saveable);
+				}
+			}
+		}
+		return result.toArray(new ISaveablePart[result.size()]);
+	}
+
+	/**
+	 * @return workbench parts which are dirty (implement or adapt to
+	 *         {@link ISaveablePart}). Only parts matching different saveables
+	 *         are returned.
+	 */
+	public IWorkbenchPart[] getDirtyWorkbenchParts() {
+		List<IWorkbenchPart> result = new ArrayList<>(3);
+		Map<ISaveablePart, IWorkbenchPart> saveables = new LinkedHashMap<>(3);
+		IWorkbenchPartReference[] allParts = getSortedParts(true, true, true);
+		for (IWorkbenchPartReference reference : allParts) {
+			IWorkbenchPart part = reference.getPart(false);
+			ISaveablePart saveable = SaveableHelper.getSaveable(part);
+			if (saveable == null || !saveable.isDirty()) {
+				continue;
+			}
+			IWorkbenchPart previousPart = saveables.get(saveable);
+			if (previousPart != null) {
+				// We have already a part claiming to handle this saveable.
+				// See bug 470076 where a property view might return
+				// saveable which is in turn just editor part
+				if (previousPart == saveable) {
+					// if the previous part matches saveable, we have a
+					// perfect match already
+					continue;
+				}
+				// if parts provide adapters to same saveable but
+				// saveable itself is not a part, we can try to keep
+				// editors and skip views
+				if (part != saveable && previousPart instanceof IEditorPart) {
+					continue;
+				}
+				// last part wins, since we don't want to return multiple parts
+				// representing same saveables
+				result.remove(previousPart);
+			}
+			result.add(part);
+			saveables.put(saveable, part);
+		}
+		return result.toArray(new IWorkbenchPart[result.size()]);
+	}
+
+	public boolean saveAllEditors(boolean confirm, boolean closing, boolean addNonPartSources) {
+		IWorkbenchPart[] parts = getDirtyWorkbenchParts();
+		if (parts.length == 0) {
+			return true;
+		}
+		// saveAll below expects a mutable list
+		List<IWorkbenchPart> dirtyParts = new ArrayList<>(parts.length);
+		for (IWorkbenchPart part : parts) {
+			dirtyParts.add(part);
+		}
+
+		// If confirmation is required ..
+		return saveAll(dirtyParts, confirm, closing, addNonPartSources, legacyWindow, legacyWindow);
+	}
+
+	public static boolean saveAll(List<IWorkbenchPart> dirtyParts, final boolean confirm, final boolean closing,
+			boolean addNonPartSources, final IRunnableContext runnableContext,
+			final IWorkbenchWindow workbenchWindow) {
+		// clone the input list
+		dirtyParts = new ArrayList<>(dirtyParts);
+
+		if (closing) {
+			// if the parts are going to be closed, then we only save those that
+			// need to be saved when closed, see bug 272070
+			removeSaveOnCloseNotNeededParts(dirtyParts);
+		}
+
+		SaveablesList saveablesList = (SaveablesList) PlatformUI.getWorkbench().getService(
+				ISaveablesLifecycleListener.class);
+		if (confirm) {
+			return processSaveable2(dirtyParts) ? false : saveablesList.preCloseParts(dirtyParts, true, true,
+					workbenchWindow, workbenchWindow) != null;
+		}
+		List<Saveable> modelsToSave = convertToSaveables(dirtyParts, closing, addNonPartSources);
+		return modelsToSave.isEmpty() ? true : !saveablesList.saveModels(modelsToSave, workbenchWindow,
+				runnableContext, closing);
+
+	}
+
+	/**
+	 * Removes from the provided list parts that don't need to be saved on
+	 * close.
+	 *
+	 * @param parts
+	 *            the list of the parts (ISaveablePart)
+	 */
+	private static void removeSaveOnCloseNotNeededParts(List<IWorkbenchPart> parts) {
+		for (Iterator<IWorkbenchPart> it = parts.iterator(); it.hasNext();) {
+			IWorkbenchPart part = it.next();
+			ISaveablePart saveable = SaveableHelper.getSaveable(part);
+			if (saveable == null || !saveable.isSaveOnCloseNeeded()) {
+				it.remove();
+			}
+		}
+	}
+
+	/**
+	 * Processes all parts that implement ISaveablePart2 and removes them from
+	 * the list.
+	 *
+	 * @param dirtyParts
+	 *            the list of the parts
+	 * @return true if cancelled
+	 */
+	private static boolean processSaveable2(List<IWorkbenchPart> dirtyParts) {
+		boolean saveable2Processed = false;
+		// Process all parts that implement ISaveablePart2.
+		// These parts are removed from the list after saving
+		// them. We then need to restore the workbench to
+		// its previous state, for now this is just last
+		// active perspective.
+		// Note that the given parts may come from multiple
+		// windows, pages and perspectives.
+		ListIterator<IWorkbenchPart> listIterator = dirtyParts.listIterator();
+
+		WorkbenchPage currentPage = null;
+		Perspective currentPageOriginalPerspective = null;
+		while (listIterator.hasNext()) {
+			IWorkbenchPart part = listIterator.next();
+			ISaveablePart2 saveable2 = SaveableHelper.getSaveable2(part);
+			if (saveable2 != null) {
+				WorkbenchPage page = (WorkbenchPage) part.getSite().getPage();
+				if (!Util.equals(currentPage, page)) {
+					if (currentPage != null && currentPageOriginalPerspective != null) {
+						if (!currentPageOriginalPerspective.equals(currentPage
+								.getActivePerspective())) {
+							currentPage
+									.setPerspective(currentPageOriginalPerspective.getDesc());
+						}
+					}
+					currentPage = page;
+					currentPageOriginalPerspective = page.getActivePerspective();
+				}
+				page.bringToTop(part);
+				// try to save the part
+				int choice = SaveableHelper.savePart(saveable2, page.getWorkbenchWindow(), true);
+				if (choice == ISaveablePart2.CANCEL) {
+					// If the user cancels, don't restore the previous
+					// workbench state, as that will
+					// be an unexpected switch from the current state.
+					return true;
+				} else if (choice != ISaveablePart2.DEFAULT) {
+					saveable2Processed = true;
+					listIterator.remove();
+				}
+			}
+		}
+
+		// try to restore the workbench to its previous state
+		if (currentPage != null && currentPageOriginalPerspective != null) {
+			if (!currentPageOriginalPerspective.equals(currentPage.getActivePerspective())) {
+				currentPage.setPerspective(currentPageOriginalPerspective.getDesc());
+			}
+		}
+
+		// if processing a ISaveablePart2 caused other parts to be
+		// saved, remove them from the list presented to the user.
+		if (saveable2Processed) {
+			removeNonDirtyParts(dirtyParts);
+		}
+
+		return false;
+	}
+
+	private static void removeNonDirtyParts(List<IWorkbenchPart> parts) {
+		ListIterator<IWorkbenchPart> listIterator;
+		listIterator = parts.listIterator();
+		while (listIterator.hasNext()) {
+			ISaveablePart part = SaveableHelper.getSaveable(listIterator.next());
+			if (part == null || !part.isDirty()) {
+				listIterator.remove();
+			}
+		}
+	}
+
+	/**
+	 * For each part (view or editor) in the given list, attempts to convert it
+	 * to one or more saveable models. Duplicate models are removed. If closing
+	 * is true, then models that will remain open in parts other than the given
+	 * parts are removed.
+	 *
+	 * @param parts
+	 *            the parts (list of IViewPart or IEditorPart)
+	 * @param closing
+	 *            whether the parts are being closed
+	 * @param addNonPartSources
+	 *            whether non-part sources should be added (true for the Save
+	 *            All action, see bug 139004)
+	 * @return the dirty models
+	 */
+	private static List<Saveable> convertToSaveables(List<IWorkbenchPart> parts, boolean closing,
+			boolean addNonPartSources) {
+		ArrayList<Saveable> result = new ArrayList<>();
+		HashSet<Saveable> seen = new HashSet<>();
+		for (IWorkbenchPart part : parts) {
+			for (Saveable saveable : getSaveables(part)) {
+				if (saveable.isDirty() && !seen.contains(saveable)) {
+					seen.add(saveable);
+					if (!closing
+							|| closingLastPartShowingModel(saveable, parts, part.getSite()
+									.getPage())) {
+						result.add(saveable);
+					}
+				}
+			}
+		}
+		if (addNonPartSources) {
+			SaveablesList saveablesList = (SaveablesList) PlatformUI.getWorkbench().getService(
+					ISaveablesLifecycleListener.class);
+			ISaveablesSource[] nonPartSources = saveablesList.getNonPartSources();
+			for (ISaveablesSource nonPartSource : nonPartSources) {
+				for (Saveable saveable : nonPartSource.getSaveables()) {
+					if (saveable.isDirty() && !seen.contains(saveable)) {
+						seen.add(saveable);
+						result.add(saveable);
+					}
+				}
+			}
+		}
+		return result;
+	}
+
+	/**
+	 * Returns the saveable models provided by the given part. If the part does
+	 * not provide any models, a default model is returned representing the
+	 * part.
+	 *
+	 * @param part
+	 *            the workbench part
+	 * @return the saveable models
+	 */
+	private static Saveable[] getSaveables(IWorkbenchPart part) {
+		if (part instanceof ISaveablesSource) {
+			ISaveablesSource source = (ISaveablesSource) part;
+			return source.getSaveables();
+		}
+		return new Saveable[] { new DefaultSaveable(part) };
+	}
+
+	/**
+	 * Returns true if, in the given page, no more parts will reference the
+	 * given model if the given parts are closed.
+	 *
+	 * @param model
+	 *            the model
+	 * @param closingParts
+	 *            the parts being closed (list of IViewPart or IEditorPart)
+	 * @param page
+	 *            the page
+	 * @return <code>true</code> if no more parts in the page will reference the
+	 *         given model, <code>false</code> otherwise
+	 */
+	private static boolean closingLastPartShowingModel(Saveable model, List<IWorkbenchPart> closingParts,
+			IWorkbenchPage page) {
+		HashSet<IWorkbenchPart> closingPartsWithSameModel = new HashSet<>();
+		for (IWorkbenchPart part : closingParts) {
+			Saveable[] models = getSaveables(part);
+			if (Arrays.asList(models).contains(model)) {
+				closingPartsWithSameModel.add(part);
+			}
+		}
+		IWorkbenchPartReference[] pagePartRefs = ((WorkbenchPage) page).getSortedParts();
+		HashSet<IWorkbenchPart> pagePartsWithSameModels = new HashSet<>();
+		for (IWorkbenchPartReference partRef : pagePartRefs) {
+			IWorkbenchPart part = partRef.getPart(false);
+			if (part != null) {
+				Saveable[] models = getSaveables(part);
+				if (Arrays.asList(models).contains(model)) {
+					pagePartsWithSameModels.add(part);
+				}
+			}
+		}
+		for (IWorkbenchPart part : closingPartsWithSameModel) {
+			pagePartsWithSameModels.remove(part);
+		}
+		return pagePartsWithSameModels.isEmpty();
+	}
+
+	/**
+	 * Saves the contents of the provided saveable and returns whether the
+	 * operation succeeded or not.
+	 *
+	 * @param saveable
+	 *            the saveable part to save
+	 * @param part
+	 * @param confirm
+	 *            whether the user should be prompted for confirmation of the
+	 *            save request
+	 * @param closing
+	 *            whether the part will be closed after the save operation has
+	 *            completed, this may determine whether whether the save
+	 *            operation will actually be invoked or not
+	 * @return <code>true</code> if the saveable's contents has been persisted,
+	 *         <code>false</code> otherwise
+	 * @see ISaveablePart#isSaveOnCloseNeeded()
+	 */
+	public boolean saveSaveable(ISaveablePart saveable, IWorkbenchPart part, boolean confirm,
+			boolean closing) {
+		if (closing && !saveable.isSaveOnCloseNeeded()) {
+			return true;
+		}
+		return SaveableHelper.savePart(saveable, part, legacyWindow, confirm);
+	}
+
+    /**
+     * Saves an editors in the workbench. If <code>confirm</code> is <code>true</code>
+     * the user is prompted to confirm the command.
+     *
+     * @param confirm
+     *            if user confirmation should be sought
+     * @return <code>true</code> if the command succeeded, or <code>false</code>
+     *         if the user cancels the command
+     */
+    @Override
+	public boolean saveEditor(IEditorPart editor, boolean confirm) {
+		return saveSaveable(editor, editor, confirm, false);
+    }
+
+	@Override
+	public void savePerspective() {
+		throw new UnsupportedOperationException();
+	}
+
+	@Override
+	public void savePerspectiveAs(IPerspectiveDescriptor perspective) {
+		MPerspective visiblePerspective = getPerspectiveStack().getSelectedElement();
+		// get the original perspective
+		String originalPerspectiveId = visiblePerspective.getElementId();
+		IPerspectiveDescriptor originalPerspective = getWorkbenchWindow().getWorkbench()
+				.getPerspectiveRegistry().findPerspectiveWithId(originalPerspectiveId);
+		// remove it from our collection of previously opened perspectives
+		sortedPerspectives.remove(originalPerspective);
+		// append the saved perspective
+		sortedPerspectives.add(perspective);
+
+		visiblePerspective.setLabel(perspective.getLabel());
+		visiblePerspective.setTooltip(perspective.getLabel());
+		visiblePerspective.setElementId(perspective.getId());
+		modelService.cloneElement(visiblePerspective, application);
+		if (perspective instanceof PerspectiveDescriptor) {
+			((PerspectiveDescriptor) perspective).setHasCustomDefinition(true);
+		}
+
+		UIEvents.publishEvent(UIEvents.UILifeCycle.PERSPECTIVE_SAVED, visiblePerspective);
+	}
+
+	@Override
+	public void setEditorAreaVisible(boolean showEditorArea) {
+		MUIElement find = findSharedArea();
+		if (find != null) {
+			if (showEditorArea) {
+				// make sure it's been rendered if it hasn't been
+				find.setToBeRendered(true);
+			}
+
+			// If the EA is minimized, restore it...
+			if (showEditorArea) {
+				find.getTags().remove(IPresentationEngine.MINIMIZED);
+			}
+
+			find.setVisible(showEditorArea);
+		}
+	}
+
+	private HashMap<MPerspective, Perspective> modelToPerspectiveMapping = new HashMap<>();
+
+	private Perspective getPerspective(MPerspective mperspective) {
+		if (mperspective == null) {
+			return null;
+		}
+		if (!modelToPerspectiveMapping.containsKey(mperspective)) {
+			boolean fixedPerspective = false;
+			PerspectiveDescriptor perspectiveDesc = (PerspectiveDescriptor) getPerspectiveDesc(mperspective.getElementId());
+			if (perspectiveDesc == null) {
+				fixedPerspective = true;
+				perspectiveDesc = fixOrphanPerspective(mperspective);
+			}
+			Perspective p = new Perspective(perspectiveDesc, mperspective, this);
+			modelToPerspectiveMapping.put(mperspective, p);
+			p.initActionSets();
+			if (fixedPerspective) {
+				UIEvents.publishEvent(UIEvents.UILifeCycle.PERSPECTIVE_SAVED, mperspective);
+			}
+		}
+		return modelToPerspectiveMapping.get(mperspective);
+	}
+
+	/**
+	 * An 'orphan' perspective is one that was originally created through a
+	 * contribution but whose contributing bundle is no longer available. In
+	 * order to allow it to behave correctly within the environment (for Close,
+	 * Reset...) we turn it into a 'custom' perspective on its first activation.
+	 *
+	 * @return
+	 */
+	private PerspectiveDescriptor fixOrphanPerspective(MPerspective mperspective) {
+		PerspectiveRegistry reg = (PerspectiveRegistry) PlatformUI.getWorkbench().getPerspectiveRegistry();
+		String perspId = mperspective.getElementId();
+		String label = mperspective.getLabel();
+		String msg = "Perspective with name '" + label + "' and id '" + perspId + "' has been made into a local copy"; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
+		IStatus status = StatusUtil.newStatus(IStatus.WARNING, msg, null);
+		StatusManager.getManager().handle(status, StatusManager.LOG);
+
+		String newDescId = NLS.bind(WorkbenchMessages.get().Perspective_localCopyLabel, label);
+		while (reg.findPerspectiveWithId(newDescId) != null) {
+			newDescId = NLS.bind(WorkbenchMessages.get().Perspective_localCopyLabel, newDescId);
+		}
+		PerspectiveDescriptor pd = new PerspectiveDescriptor(perspId, label, null);
+		PerspectiveDescriptor newDesc = reg.createPerspective(newDescId, pd);
+		if (mperspective.getIconURI() != null) {
+			try {
+				ImageDescriptor img = ImageDescriptor.createFromURL(new URI(mperspective.getIconURI()).toURL());
+				newDesc.setImageDescriptor(img);
+			} catch (MalformedURLException | URISyntaxException e) {
+				WorkbenchPlugin.log(MessageFormat.format("Error on applying configured perspective icon: {0}", //$NON-NLS-1$
+						mperspective.getIconURI(), e));
+			}
+		}
+
+		mperspective.setElementId(newDesc.getId());
+		mperspective.setLabel(newDesc.getLabel());
+		sortedPerspectives.add(newDesc);
+		modelService.cloneElement(mperspective, application);
+		newDesc.setHasCustomDefinition(true);
+		return newDesc;
+	}
+
+	@Override
+	public void setPerspective(IPerspectiveDescriptor perspective) {
+		if (perspective == null) {
+			return;
+		}
+
+		IPerspectiveDescriptor lastPerspective = getPerspective();
+		if (lastPerspective != null && lastPerspective.getId().equals(perspective.getId())) {
+			// no change
+			MPerspectiveStack perspectives = getPerspectiveStack();
+			for (MPerspective mperspective : perspectives.getChildren()) {
+				if (mperspective.getElementId().equals(perspective.getId())) {
+					handleNullRefPlaceHolders(mperspective, window);
+				}
+			}
+			return;
+		}
+
+		MPerspectiveStack perspectives = getPerspectiveStack();
+		for (MPerspective mperspective : perspectives.getChildren()) {
+			if (mperspective.getElementId().equals(perspective.getId())) {
+				if (lastPerspective != null) {
+					legacyWindow.firePerspectiveDeactivated(this, lastPerspective);
+				}
+
+				// this perspective already exists, switch to this one
+				perspectives.setSelectedElement(mperspective);
+				mperspective.getContext().activate();
+				handleNullRefPlaceHolders(mperspective, window);
+				return;
+			}
+		}
+
+		MPerspective modelPerspective = (MPerspective) modelService.cloneSnippet(application,
+				perspective.getId(), window);
+
+		if (modelPerspective == null) {
+			// couldn't find the perspective, create a new one
+			modelPerspective = createPerspective(perspective);
+		}
+
+		handleNullRefPlaceHolders(modelPerspective, window);
+
+		modelPerspective.setLabel(perspective.getLabel());
+
+		ImageDescriptor imageDescriptor = perspective.getImageDescriptor();
+		if (imageDescriptor != null) {
+			String imageURL = MenuHelper.getImageUrl(imageDescriptor);
+			modelPerspective.setIconURI(imageURL);
+		}
+
+		if (lastPerspective != null) {
+			legacyWindow.firePerspectiveDeactivated(this, lastPerspective);
+		}
+
+		// Hide placeholders for parts that exist in the 'global' areas
+		modelService.hideLocalPlaceholders(window, modelPerspective);
+
+		// add it to the stack
+		perspectives.getChildren().add(modelPerspective);
+		// activate it
+		perspectives.setSelectedElement(modelPerspective);
+
+		modelPerspective.getContext().activate();
+		modelPerspective.getContext().set(ISelectionService.class, selectionService);
+
+		legacyWindow.firePerspectiveOpened(this, perspective);
+		UIEvents.publishEvent(UIEvents.UILifeCycle.PERSPECTIVE_OPENED, modelPerspective);
+	}
+
+    private void handleNullRefPlaceHolders(MUIElement element, MWindow refWin) {
+//		List<MPlaceholder> nullRefList = ((ModelServiceImpl) modelService).getNullRefPlaceHolders(element, refWin);
+
+		List<MPart> partList = modelService.findElements(element, null, MPart.class, null);
+		for (MPart part : partList) {
+			if (CompatibilityPart.COMPATIBILITY_VIEW_URI.equals(part.getContributionURI())
+					&& part.getIconURI() == null) {
+				part.getTransientData().put(IPresentationEngine.OVERRIDE_ICON_IMAGE_KEY,
+						ImageDescriptor.getMissingImageDescriptor().createImage());
+			}
+		}
+
+//		if (nullRefList != null && nullRefList.size() > 0) {
+//			for (MPlaceholder ph : nullRefList) {
+//				replacePlaceholder(ph);
+//			}
+//		}
+	}
+
+	private void replacePlaceholder(MPlaceholder ph) {
+		MPart part = modelService.createModelElement(MPart.class);
+		part.setElementId(ph.getElementId());
+		part.getTransientData().put(IPresentationEngine.OVERRIDE_ICON_IMAGE_KEY,
+				ImageDescriptor.getMissingImageDescriptor().createImage());
+		String label = (String) ph.getTransientData().get(IWorkbenchConstants.TAG_LABEL);
+		if (label != null) {
+			part.setLabel(label);
+		} else {
+			part.setLabel(getLabel(ph.getElementId()));
+		}
+		part.setContributionURI(CompatibilityPart.COMPATIBILITY_VIEW_URI);
+		part.setCloseable(true);
+		MElementContainer<MUIElement> curParent = ph.getParent();
+		int curIndex = curParent.getChildren().indexOf(ph);
+		curParent.getChildren().remove(curIndex);
+		curParent.getChildren().add(curIndex, part);
+		if (curParent.getSelectedElement() == ph) {
+			curParent.setSelectedElement(part);
+		}
+	}
+
+	private String getLabel(String str) {
+		int index = str.lastIndexOf('.');
+		if (index == -1)
+			return str;
+		return str.substring(index + 1);
+	}
+
+	/**
+	 * @param perspective
+	 * @return never null
+	 */
+	private MPerspective createPerspective(IPerspectiveDescriptor perspective) {
+		MPerspective modelPerspective = modelService.createModelElement(MPerspective.class);
+
+		// tag it with the same id
+		modelPerspective.setElementId(perspective.getId());
+
+		// instantiate the perspective
+		IPerspectiveFactory factory = ((PerspectiveDescriptor) perspective).createFactory();
+		ModeledPageLayout modelLayout = new ModeledPageLayout(window, modelService,
+				partService, modelPerspective, perspective, this, true);
+		factory.createInitialLayout(modelLayout);
+		PerspectiveTagger.tagPerspective(modelPerspective, modelService);
+		PerspectiveExtensionReader reader = new PerspectiveExtensionReader();
+		reader.extendLayout(getExtensionTracker(), perspective.getId(), modelLayout);
+		return modelPerspective;
+	}
+
+	void perspectiveActionSetChanged(Perspective perspective, IActionSetDescriptor descriptor,
+			int changeType) {
+		if (perspective == getActivePerspective()) {
+			actionSets.change(descriptor, changeType);
+		}
+	}
+
+
+	/**
+	 * Retrieves the perspective stack of the window that's containing this
+	 * workbench page.
+	 *
+	 * @return the stack of perspectives of this page's containing window
+	 */
+	private MPerspectiveStack getPerspectiveStack() {
+		if (_perspectiveStack != null) {
+			return _perspectiveStack;
+		}
+		List<MPerspectiveStack> theStack = modelService.findElements(window, null,
+				MPerspectiveStack.class, null);
+		if (theStack.size() > 0) {
+			_perspectiveStack = theStack.get(0);
+			return _perspectiveStack;
+		}
+
+		for (MWindowElement child : window.getChildren()) {
+			if (child instanceof MPerspectiveStack) {
+				_perspectiveStack = (MPerspectiveStack) child;
+				return _perspectiveStack;
+			}
+		}
+
+		MPartSashContainer stickySash = modelService.createModelElement(MPartSashContainer.class);
+		stickySash.setHorizontal(true);
+
+		MPerspectiveStack perspectiveStack = modelService
+				.createModelElement(MPerspectiveStack.class);
+		perspectiveStack.setElementId(IWorkbenchConstants.PERSPECTIVE_STACK_ID);
+		perspectiveStack.setContainerData("7500"); //$NON-NLS-1$
+
+		MPartStack stickyFolder = modelService.createModelElement(MPartStack.class);
+		stickyFolder.setContainerData("2500"); //$NON-NLS-1$
+		stickyFolder.setElementId("stickyFolderRight"); //$NON-NLS-1$
+		stickyFolder.setToBeRendered(false);
+
+		IStickyViewDescriptor[] stickyViews = getWorkbenchWindow().getWorkbench().getViewRegistry()
+				.getStickyViews();
+		for (IStickyViewDescriptor stickyView : stickyViews) {
+			if (stickyView.getLocation() == IPageLayout.RIGHT) {
+				MStackElement viewModel = ModeledPageLayout.createViewModel(application,
+						stickyView.getId(), false, this, partService, true);
+				stickyFolder.getChildren().add(viewModel);
+			}
+		}
+
+		stickySash.getChildren().add(perspectiveStack);
+		stickySash.getChildren().add(stickyFolder);
+		stickySash.setSelectedElement(perspectiveStack);
+
+		window.getChildren().add(stickySash);
+		window.setSelectedElement(stickySash);
+		_perspectiveStack = perspectiveStack;
+		return perspectiveStack;
+	}
+
+    /**
+     * Sets the active working set for the workbench page. Notifies property
+     * change listener about the change.
+     *
+     * @param newWorkingSet
+     *            the active working set for the page. May be null.
+     * @since 2.0
+     * @deprecated individual views should store a working set if needed
+     */
+    @Deprecated
+	public void setWorkingSet(IWorkingSet newWorkingSet) {
+        IWorkingSet oldWorkingSet = workingSet;
+
+        workingSet = newWorkingSet;
+        if (oldWorkingSet != newWorkingSet) {
+            firePropertyChange(CHANGE_WORKING_SET_REPLACE, oldWorkingSet,
+                    newWorkingSet);
+        }
+        if (newWorkingSet != null) {
+            WorkbenchPlugin.getDefault().getWorkingSetManager()
+                    .addPropertyChangeListener(workingSetPropertyChangeListener);
+        } else {
+            WorkbenchPlugin.getDefault().getWorkingSetManager()
+                    .removePropertyChangeListener(workingSetPropertyChangeListener);
+        }
+    }
+
+    /**
+     * @see IWorkbenchPage
+     */
+    @Override
+	public void showActionSet(String actionSetID) {
+    	 Perspective persp = getActivePerspective();
+         if (persp != null) {
+             ActionSetRegistry reg = WorkbenchPlugin.getDefault()
+                  .getActionSetRegistry();
+
+             IActionSetDescriptor desc = reg.findActionSet(actionSetID);
+             if (desc != null) {
+				List<IActionSetDescriptor> offActionSets = persp.getAlwaysOffActionSets();
+				for (IActionSetDescriptor off : offActionSets) {
+					if (off.getId().equals(desc.getId())) {
+						return;
+					}
+				}
+                 persp.addActionSet(desc);
+                 legacyWindow.updateActionSets();
+                 legacyWindow.firePerspectiveChanged(this, getPerspective(),
+                         CHANGE_ACTION_SET_SHOW);
+             }
+         }
+    }
+
+    /**
+     * See IWorkbenchPage.
+     */
+    @Override
+	public IViewPart showView(String viewID) throws PartInitException {
+        return showView(viewID, null, VIEW_ACTIVATE);
+    }
+
+	@Override
+	public IViewPart showView(final String viewID, final String secondaryID, final int mode)
+			throws PartInitException {
+
+		if (secondaryID != null) {
+			if (secondaryID.length() == 0 || secondaryID.indexOf(":") != -1) { //$NON-NLS-1$
+				throw new IllegalArgumentException(
+						WorkbenchMessages.get().WorkbenchPage_IllegalSecondaryId);
+			}
+		}
+		if (!certifyMode(mode)) {
+			throw new IllegalArgumentException(WorkbenchMessages.get().WorkbenchPage_IllegalViewMode);
+		}
+
+		// Run op in busy cursor.
+		final String compoundId = secondaryID != null ? viewID + ':' + secondaryID : viewID;
+		final Object[] result = new Object[1];
+		BusyIndicator.showWhile(null, new Runnable() {
+			@Override
+			public void run() {
+				try {
+					result[0] = busyShowView(compoundId, mode);
+				} catch (PartInitException e) {
+					result[0] = e;
+				}
+			}
+		});
+		if (result[0] instanceof IViewPart) {
+			return (IViewPart) result[0];
+		} else if (result[0] instanceof PartInitException) {
+			throw (PartInitException) result[0];
+		} else {
+			throw new PartInitException(WorkbenchMessages.get().WorkbenchPage_AbnormalWorkbenchCondition);
+		}
+	}
+
+    /**
+     * @param mode the mode to test
+     * @return whether the mode is recognized
+     * @since 3.0
+     */
+    private boolean certifyMode(int mode) {
+        switch (mode) {
+        case VIEW_ACTIVATE:
+        case VIEW_VISIBLE:
+        case VIEW_CREATE:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+	public MUIElement getActiveElement(IWorkbenchPartReference ref) {
+		MUIElement element = null;
+
+		MPerspective curPersp = modelService.getActivePerspective(window);
+		if (curPersp == null)
+			return null;
+
+		MPlaceholder eaPH = (MPlaceholder) modelService.find(IPageLayout.ID_EDITOR_AREA, curPersp);
+		MPart model = ((WorkbenchPartReference) ref).getModel();
+		MPlaceholder placeholder = model.getCurSharedRef();
+
+		switch (modelService.getElementLocation(placeholder == null ? model : placeholder)) {
+		case EModelService.IN_ACTIVE_PERSPECTIVE:
+		case EModelService.OUTSIDE_PERSPECTIVE:
+			MUIElement parent = placeholder == null ? model.getParent() : placeholder.getParent();
+			if (parent instanceof MPartStack) {
+				element = parent;
+			}
+			break;
+		case EModelService.IN_SHARED_AREA:
+			element = eaPH;
+			break;
+		}
+		return element;
+	}
+
+	@Override
+	public void setPartState(IWorkbenchPartReference ref, int iState) {
+		MUIElement element = getActiveElement(ref);
+		String state = null;
+
+		if (iState == STATE_MINIMIZED) {
+			state = IPresentationEngine.MINIMIZED;
+		} else if (iState == STATE_MAXIMIZED) {
+			state = IPresentationEngine.MAXIMIZED;
+		}
+		setPartState(element, state);
+	}
+
+    @Override
+	public int getPartState(IWorkbenchPartReference ref) {
+		int state = STATE_RESTORED;
+		MUIElement element = getActiveElement(ref);
+
+		if (element != null) {
+			if (element.getTags().contains(IPresentationEngine.MINIMIZED)) {
+				state = STATE_MINIMIZED;
+			} else if (element.getTags().contains(IPresentationEngine.MAXIMIZED)) {
+				state = STATE_MAXIMIZED;
+			}
+		}
+		return state;
+	}
+
+	// if the state is null, then we'll just restore the view
+	private void setPartState(MUIElement element, String state) {
+		if (element != null) {
+			element.getTags().remove(IPresentationEngine.MINIMIZED_BY_ZOOM);
+			if (IPresentationEngine.MINIMIZED.equals(state)) {
+				element.getTags().remove(IPresentationEngine.MAXIMIZED);
+				element.getTags().add(IPresentationEngine.MINIMIZED);
+			} else if (IPresentationEngine.MAXIMIZED.equals(state)) {
+				element.getTags().remove(IPresentationEngine.MINIMIZED);
+				element.getTags().add(IPresentationEngine.MAXIMIZED);
+			} else {
+				element.getTags().remove(IPresentationEngine.MINIMIZED);
+				element.getTags().remove(IPresentationEngine.MAXIMIZED);
+			}
+		}
+	}
+
+    /**
+     * updateActionBars method comment.
+     */
+    public void updateActionBars() {
+		legacyWindow.updateActionBars();
+    }
+
+
+    @Override
+	public void zoomOut() {
+		// TODO compat: what does the zoom do?
+    }
+
+	@Override
+	public void toggleZoom(IWorkbenchPartReference ref) {
+		MUIElement element = getActiveElement(ref);
+		if (element != null) {
+			String state = null;
+			if (!element.getTags().contains(IPresentationEngine.MAXIMIZED)) {
+				state = IPresentationEngine.MAXIMIZED;
+			}
+			this.setPartState(element, state);
+		}
+	}
+
+
+	@Override
+	public IPerspectiveDescriptor[] getOpenPerspectives() {
+		MPerspectiveStack perspectiveStack = modelService.findElements(window, null,
+				MPerspectiveStack.class, null).get(0);
+		IPerspectiveRegistry registry = PlatformUI.getWorkbench().getPerspectiveRegistry();
+
+		ArrayList<IPerspectiveDescriptor> tmp = new ArrayList<>(
+				perspectiveStack.getChildren().size());
+		for (MPerspective persp : perspectiveStack.getChildren()) {
+			String perspectiveId = persp.getElementId();
+			IPerspectiveDescriptor desc = registry.findPerspectiveWithId(perspectiveId);
+			if (desc != null) {
+				tmp.add(desc);
+			}
+		}
+		IPerspectiveDescriptor[] descs = new IPerspectiveDescriptor[tmp.size()];
+		tmp.toArray(descs);
+
+		return descs;
+	}
+
+	@Override
+	public IPerspectiveDescriptor[] getSortedPerspectives() {
+		return sortedPerspectives.toArray(new IPerspectiveDescriptor[sortedPerspectives.size()]);
+	}
+
+
+
+    /**
+     * Returns the reference to the given part, or <code>null</code> if it has no reference
+     * (i.e. it is not a top-level part in this workbench page).
+     *
+     * @param part the part
+     * @return the part's reference or <code>null</code> if the given part does not belong
+     * to this workbench page
+     */
+	@Override
+	public IWorkbenchPartReference getReference(IWorkbenchPart part) {
+		if (part != null) {
+			IWorkbenchPartSite site = part.getSite();
+			if (site instanceof PartSite) {
+				return ((PartSite) site).getPartReference();
+			}
+		}
+		return null;
+	}
+
+	public MPerspective getCurrentPerspective() {
+		MPerspectiveStack stack = getPerspectiveStack();
+		return stack == null ? null : stack.getSelectedElement();
+	}
+
+	Perspective getActivePerspective() {
+		return getPerspective(getCurrentPerspective());
+	}
+
+	@Override
+	public IViewPart[] getViewStack(IViewPart part) {
+		MPart mpart = partService.findPart(part.getSite().getId());
+		if (mpart != null) {
+			MElementContainer<?> parent = mpart.getParent();
+			if (parent == null) {
+				// this is a shared part, check for placeholders
+				MPlaceholder placeholder = mpart.getCurSharedRef();
+				if (placeholder != null) {
+					parent = placeholder.getParent();
+				}
+			}
+
+			if (parent instanceof MPartStack) {
+				MStackElement selectedElement = ((MPartStack) parent).getSelectedElement();
+				final MUIElement topPart = selectedElement instanceof MPlaceholder ? ((MPlaceholder) selectedElement)
+						.getRef() : null;
+
+				List<CompatibilityView> stack = new ArrayList<>();
+				for (Object child : parent.getChildren()) {
+					MPart siblingPart = child instanceof MPart ? (MPart) child
+							: (MPart) ((MPlaceholder) child).getRef();
+					// Bug 398433 - guard against NPE
+					Object siblingObject = siblingPart != null ? siblingPart.getObject() : null;
+					if (siblingObject instanceof CompatibilityView) {
+						stack.add((CompatibilityView) siblingObject);
+					}
+				}
+
+				// sort the list by activation order (most recently activated
+				// first)
+				Collections.sort(stack, new Comparator<CompatibilityView>() {
+					@Override
+					public int compare(CompatibilityView o1, CompatibilityView o2) {
+						MPart model1 = o1.getModel();
+						MPart model2 = o2.getModel();
+
+						/*
+						 * WORKAROUND: Since we only have the activation list
+						 * and not a bingToTop list, we can't set/know the order
+						 * for inactive stacks. This workaround makes sure that
+						 * the topmost part is at least at the first position.
+						 */
+						if (model1 == topPart)
+							return Integer.MIN_VALUE;
+						if (model2 == topPart)
+							return Integer.MAX_VALUE;
+
+						int pos1 = activationList.indexOf(model1);
+						int pos2 = activationList.indexOf(model2);
+						if (pos1 == -1)
+							pos1 = Integer.MAX_VALUE;
+						if (pos2 == -1)
+							pos2 = Integer.MAX_VALUE;
+						return pos1 - pos2;
+					}
+				});
+
+				IViewPart[] result = new IViewPart[stack.size()];
+				for (int i = 0; i < result.length; i++) {
+					result[i] = stack.get(i).getView();
+				}
+				return result;
+			}
+
+			// not in a stack, standalone
+			return new IViewPart[] { part };
+		}
+		return null;
+	}
+
+
+	@Override
+	public IExtensionTracker getExtensionTracker() {
+		if (tracker == null) {
+			tracker = new UIExtensionTracker(getWorkbenchWindow().getWorkbench().getDisplay());
+		}
+		return tracker;
+	}
+
+	private final static String[] EMPTY_STRING_ARRAY = new String[0];
+
+	private String[] getArrayForTag(String tagPrefix) {
+		List<String> id = getCollectionForTag(tagPrefix);
+		if (id == null)
+			return EMPTY_STRING_ARRAY;
+		return id.toArray(new String[id.size()]);
+	}
+
+	private List<String> getCollectionForTag(String tagPrefix) {
+		MPerspective perspective = getPerspectiveStack().getSelectedElement();
+		if (perspective == null) {
+			return Collections.emptyList();
+		}
+		return ModeledPageLayout.getIds(perspective, tagPrefix);
+	}
+
+	@Override
+	public String[] getNewWizardShortcuts() {
+		return getArrayForTag(ModeledPageLayout.NEW_WIZARD_TAG);
+	}
+
+	@Override
+	public String[] getPerspectiveShortcuts() {
+		return getArrayForTag(ModeledPageLayout.PERSP_SHORTCUT_TAG);
+	}
+
+	@Override
+	public String[] getShowViewShortcuts() {
+		return getArrayForTag(ModeledPageLayout.SHOW_VIEW_TAG);
+	}
+
+
+
+    public boolean isPartVisible(IWorkbenchPartReference reference) {
+        IWorkbenchPart part = reference.getPart(false);
+        // Can't be visible if it isn't created yet
+        if (part == null) {
+            return false;
+        }
+
+        return isPartVisible(part);
+    }
+
+	@Override
+	public IWorkingSet[] getWorkingSets() {
+		return workingSets;
+	}
+
+	@Override
+	public void setWorkingSets(IWorkingSet[] newWorkingSets) {
+		if (newWorkingSets != null) {
+			WorkbenchPlugin
+					.getDefault()
+					.getWorkingSetManager()
+					.addPropertyChangeListener(workingSetPropertyChangeListener);
+		} else {
+			WorkbenchPlugin.getDefault().getWorkingSetManager()
+					.removePropertyChangeListener(
+							workingSetPropertyChangeListener);
+		}
+
+		if (newWorkingSets == null) {
+			newWorkingSets = new IWorkingSet[0];
+		}
+
+		IWorkingSet[] oldWorkingSets = workingSets;
+
+		// filter out any duplicates if necessary
+		if (newWorkingSets.length > 1) {
+			Set<IWorkingSet> setOfSets = new HashSet<>();
+			for (IWorkingSet workingSet : newWorkingSets) {
+				if (workingSet == null) {
+					throw new IllegalArgumentException();
+				}
+				setOfSets.add(workingSet);
+			}
+			newWorkingSets = setOfSets.toArray(new IWorkingSet[setOfSets.size()]);
+		}
+
+		workingSets = newWorkingSets;
+		if (!Arrays.equals(oldWorkingSets, newWorkingSets)) {
+			firePropertyChange(CHANGE_WORKING_SETS_REPLACE, oldWorkingSets,
+					newWorkingSets);
+			if (aggregateWorkingSet != null) {
+				aggregateWorkingSet.setComponents(workingSets);
+			}
+		}
+	}
+
+	@Override
+	public IWorkingSet getAggregateWorkingSet() {
+		if (aggregateWorkingSet == null) {
+			IWorkingSetManager workingSetManager = PlatformUI.getWorkbench()
+					.getWorkingSetManager();
+
+			if (aggregateWorkingSetId == null) {
+				aggregateWorkingSetId = generateAggregateWorkingSetId();
+			} else {
+				aggregateWorkingSet = (AggregateWorkingSet) workingSetManager.getWorkingSet(aggregateWorkingSetId);
+			}
+			if (aggregateWorkingSet == null) {
+				aggregateWorkingSet = (AggregateWorkingSet) workingSetManager
+						.createAggregateWorkingSet(aggregateWorkingSetId,
+								WorkbenchMessages.get().WorkbenchPage_workingSet_default_label,
+								getWorkingSets());
+				workingSetManager.addWorkingSet(aggregateWorkingSet);
+			}
+		}
+		return aggregateWorkingSet;
+	}
+
+	private String generateAggregateWorkingSetId() {
+		return "Aggregate for window " + System.currentTimeMillis(); //$NON-NLS-1$
+	}
+
+	@Override
+	public void showEditor(IEditorReference ref) {
+		// FIXME compat showEditor
+		E4Util.unsupported("showEditor"); //$NON-NLS-1$
+
+	}
+
+	@Override
+	public void hideEditor(IEditorReference ref) {
+		// FIXME compat hideEditor
+		E4Util.unsupported("hideEditor"); //$NON-NLS-1$
+
+	}
+
+	private String getEditorImageURI(EditorReference reference) {
+		String iconURI = null;
+
+		EditorDescriptor descriptor = reference.getDescriptor();
+		if (descriptor != null) {
+			IConfigurationElement element = descriptor.getConfigurationElement();
+			if (element != null) {
+				iconURI = MenuHelper.getIconURI(element, IWorkbenchRegistryConstants.ATT_ICON);
+			}
+		}
+		return iconURI;
+	}
+
+	@Override
+	public IMemento[] getEditorState(IEditorReference[] editorRefs, boolean includeInputState) {
+		IMemento[] m = new IMemento[editorRefs.length];
+		for (int i = 0; i < editorRefs.length; i++) {
+			m[i] = ((EditorReference) editorRefs[i]).getEditorState();
+			if (!includeInputState && m[i] != null) {
+				m[i] = m[i].getChild(IWorkbenchConstants.TAG_EDITOR_STATE);
+			}
+		}
+		return m;
+	}
+
+	@Override
+	public IEditorReference[] openEditors(IEditorInput[] inputs, String[] editorIDs, int matchFlags) throws MultiPartInitException {
+		return openEditors(inputs, editorIDs, null, matchFlags, 0);
+	}
+
+	@Override
+	public IEditorReference[] openEditors(IEditorInput[] inputs, String[] editorIDs,
+			IMemento[] mementos, int matchFlags, int activationIndex)
+			throws MultiPartInitException {
+		// If we are only working with mementos create a placeholder array of
+		// nulls
+		if (inputs == null) {
+			Assert.isTrue(mementos != null);
+			inputs = new IEditorInput[mementos.length];
+		}
+
+		// If we are only working with mementos create a placeholder array of
+		// nulls
+		if (editorIDs == null) {
+			Assert.isTrue(mementos != null);
+			editorIDs = new String[mementos.length];
+		}
+
+		Assert.isTrue(inputs.length == editorIDs.length);
+		Assert.isTrue(inputs.length > 0);
+		Assert.isTrue(mementos == null || mementos.length == inputs.length);
+
+		PartInitException[] exceptions = new PartInitException[inputs.length];
+		IEditorReference[] references = new IEditorReference[inputs.length];
+		boolean hasFailures = false;
+
+		IEditorRegistry reg = getWorkbenchWindow().getWorkbench().getEditorRegistry();
+		MPart editorToActivate = null;
+		for (int i = 0; i < inputs.length; i++) {
+			String curEditorID = editorIDs == null ? null : editorIDs[i];
+			IEditorInput curInput = inputs == null ? null : inputs[i];
+			IMemento curMemento = mementos == null ? null : mementos[i];
+
+			// If we don't have an editorID get it from the memento
+			if (curEditorID == null && curMemento != null) {
+				curEditorID = curMemento.getString(IWorkbenchConstants.TAG_ID);
+			}
+
+			// If we don't have an input create on from the memento
+			if (curInput == null && curMemento != null) {
+				try {
+					curInput = EditorReference.createInput(curMemento);
+				} catch (PartInitException e) {
+					curInput = null;
+					exceptions[i] = e;
+					hasFailures = true;
+					continue;
+				}
+			}
+
+			// Adjust the memento so that it's always 'comlpete (i.e. including
+			// both input and editor state)
+			if (curMemento != null && !curMemento.getID().equals(IWorkbenchConstants.TAG_EDITOR)) {
+				XMLMemento outerMem = XMLMemento.createWriteRoot(IWorkbenchConstants.TAG_EDITOR);
+				outerMem.putString(IWorkbenchConstants.TAG_ID, curEditorID);
+				outerMem.copyChild(curMemento);
+
+				XMLMemento inputMem = (XMLMemento) outerMem
+						.createChild(IWorkbenchConstants.TAG_INPUT);
+				inputMem.putString(IWorkbenchConstants.TAG_FACTORY_ID, curInput.getPersistable()
+						.getFactoryId());
+				inputMem.putString(IWorkbenchConstants.TAG_PATH, curInput.getName());
+			}
+
+			// OK, by this point we should have the EditorInput, the editor ID
+			// and the memento (if any)
+			if (reg.findEditor(curEditorID) == null) {
+				references[i] = null;
+				exceptions[i] = new PartInitException(NLS.bind(
+						WorkbenchMessages.get().EditorManager_unknownEditorIDMessage, curEditorID));
+				hasFailures = true;
+			} else if (curInput == null) {
+				references[i] = null;
+				exceptions[i] = new PartInitException(NLS.bind(
+						WorkbenchMessages.get().EditorManager_no_persisted_state, curEditorID));
+				hasFailures = true;
+			} else {
+				// Is there an existing editor ?
+				IEditorReference[] existingEditors = findEditors(curInput, curEditorID,
+						matchFlags);
+				if (existingEditors.length == 0) {
+					MPart editor = partService.createPart(CompatibilityEditor.MODEL_ELEMENT_ID);
+					references[i] = createEditorReferenceForPart(editor, curInput, curEditorID,
+							null);
+
+					if (i == activationIndex)
+						editorToActivate = editor;
+
+					// Set the information in the supplied IMemento into the
+					// editor's model
+					if (curMemento instanceof XMLMemento) {
+						XMLMemento memento = (XMLMemento) curMemento;
+						StringWriter writer = new StringWriter();
+						try {
+							memento.save(writer);
+							editor.getPersistedState().put(WorkbenchPartReference.MEMENTO_KEY,
+									writer.toString());
+						} catch (IOException e) {
+							WorkbenchPlugin.log(e);
+						}
+					}
+
+					editor.setLabel(references[i].getTitle());
+					editor.setTooltip(references[i].getTitleToolTip());
+					editor.setIconURI(getEditorImageURI((EditorReference) references[i]));
+					((PartServiceImpl) partService).addPart(editor);
+				} else {
+					// Use the existing editor, update the state if it has *not*
+					// been rendered
+					EditorReference ee = (EditorReference) existingEditors[0];
+					if (i == activationIndex)
+						editorToActivate = ee.getModel();
+
+					if (ee.getModel().getWidget() == null) {
+						// Set the information in the supplied IMemento into the
+						// editor's model
+						if (curMemento instanceof XMLMemento) {
+							XMLMemento momento = (XMLMemento) curMemento;
+							StringWriter writer = new StringWriter();
+							try {
+								momento.save(writer);
+								ee.getModel().getPersistedState()
+										.put(WorkbenchPartReference.MEMENTO_KEY, writer.toString());
+							} catch (IOException e) {
+								WorkbenchPlugin.log(e);
+							}
+						}
+					} else {
+						// editor already rendered, try to update its state
+						if (curMemento != null
+								&& ee.getModel().getObject() instanceof CompatibilityEditor) {
+							CompatibilityEditor ce = (CompatibilityEditor) ee.getModel()
+									.getObject();
+							if (ce.getEditor() instanceof IPersistableEditor) {
+								IPersistableEditor pe = (IPersistableEditor) ce.getEditor();
+
+								// Extract the 'editorState' from the memento
+								IMemento editorMem = curMemento
+										.getChild(IWorkbenchConstants.TAG_EDITOR_STATE);
+								if (editorMem == null) {
+									// Must be an externally defined memento,
+									// take the second child
+									IMemento[] kids = curMemento.getChildren();
+									if (kids.length == 2)
+										editorMem = kids[1];
+								}
+								if (editorMem != null)
+									pe.restoreState(editorMem);
+							}
+						}
+					}
+				}
+			}
+		}
+
+		if (editorToActivate != null) {
+			partService.activate(editorToActivate);
+		}
+
+		boolean hasSuccesses = false;
+		for (IEditorReference reference : references) {
+			if (reference != null) {
+				hasSuccesses = true;
+				legacyWindow.firePerspectiveChanged(this, getPerspective(), reference,
+						CHANGE_EDITOR_OPEN);
+			}
+		}
+
+		// only fire this event if an editor was opened
+		if (hasSuccesses) {
+			legacyWindow.firePerspectiveChanged(this, getPerspective(), CHANGE_EDITOR_OPEN);
+		}
+
+		if (hasFailures) {
+			throw new MultiPartInitException(references, exceptions);
+		}
+
+		return references;
+	}
+
+	void updatePerspectiveActionSets() {
+		updateActionSets(null, getActivePerspective());
+	}
+
+	void fireInitialPartVisibilityEvents() {
+		MPerspective selectedElement = getPerspectiveStack().getSelectedElement();
+		// technically shouldn't be null here
+		if (selectedElement != null) {
+			Collection<MPart> parts = modelService.findElements(selectedElement, null, MPart.class,
+					null);
+			List<MPart> visibleParts = new ArrayList<>(parts.size());
+			for (MPart part : parts) {
+				if (isVisible(selectedElement, part)) {
+					visibleParts.add(part);
+				}
+			}
+
+			for (MPart part : visibleParts) {
+				firePartVisible(part);
+			}
+		}
+	}
+
+	private boolean isVisible(MPerspective perspective, MUIElement element) {
+		if (element == perspective) {
+			return true;
+		} else if (element.isVisible() && element.isToBeRendered()) {
+			MElementContainer<?> parent = element.getParent();
+			if (parent instanceof MPartStack) {
+				if (parent.getSelectedElement() == element) {
+					return isVisible(perspective, parent);
+				}
+			} else if (parent == null) {
+				MPlaceholder placeholder = element.getCurSharedRef();
+				return placeholder == null ? false : isVisible(perspective, placeholder);
+			} else {
+				return isVisible(perspective, parent);
+			}
+		}
+		return false;
+	}
+
+	private void firePartActivated(MPart part) {
+
+		Object client = part.getObject();
+		if (client instanceof CompatibilityPart) {
+			final IWorkbenchPart workbenchPart = ((CompatibilityPart) client).getPart();
+			final IWorkbenchPartReference partReference = getReference(workbenchPart);
+			if (partReference == null) {
+				WorkbenchPlugin.log("Reference is null in firePartActivated"); //$NON-NLS-1$
+				return;
+			}
+
+			for (final IPartListener listener : partListenerList) {
+				SafeRunner.run(new SafeRunnable() {
+					@Override
+					public void run() throws Exception {
+						listener.partActivated(workbenchPart);
+					}
+				});
+			}
+
+			for (final IPartListener2 listener : partListener2List) {
+				SafeRunner.run(new SafeRunnable() {
+					@Override
+					public void run() throws Exception {
+						listener.partActivated(partReference);
+					}
+				});
+			}
+			
+		}
+		else if (client != null) {
+			if (part.getTransientData().get(E4PartWrapper.E4_WRAPPER_KEY) instanceof E4PartWrapper) {
+				IWorkbenchPart workbenchPart = (IWorkbenchPart) part.getTransientData()
+						.get(E4PartWrapper.E4_WRAPPER_KEY);
+				final IWorkbenchPartReference partReference = getReference(workbenchPart);
+
+				if (partReference != null) {
+					for (final IPartListener listener : partListenerList) {
+						SafeRunner.run(new SafeRunnable() {
+							@Override
+							public void run() throws Exception {
+								listener.partActivated(workbenchPart);
+							}
+						});
+					}
+
+					for (final IPartListener2 listener : partListener2List) {
+						SafeRunner.run(new SafeRunnable() {
+							@Override
+							public void run() throws Exception {
+								listener.partActivated(partReference);
+							}
+						});
+					}
+				}
+			}
+		}
+	}
+
+	private void firePartDeactivated(MPart part) {
+		Object client = part.getObject();
+		if (client instanceof CompatibilityPart) {
+			final IWorkbenchPart workbenchPart = ((CompatibilityPart) client).getPart();
+			final IWorkbenchPartReference partReference = getReference(workbenchPart);
+
+			for (final IPartListener listener : partListenerList) {
+				SafeRunner.run(new SafeRunnable() {
+					@Override
+					public void run() throws Exception {
+						listener.partDeactivated(workbenchPart);
+					}
+				});
+			}
+
+			for (final IPartListener2 listener : partListener2List) {
+				SafeRunner.run(new SafeRunnable() {
+					@Override
+					public void run() throws Exception {
+						listener.partDeactivated(partReference);
+					}
+				});
+			}
+		} else if (client != null) {
+			if (part.getTransientData().get(E4PartWrapper.E4_WRAPPER_KEY) instanceof E4PartWrapper) {
+				IWorkbenchPart workbenchPart = (IWorkbenchPart) part.getTransientData()
+						.get(E4PartWrapper.E4_WRAPPER_KEY);
+				final IWorkbenchPartReference partReference = getReference(workbenchPart);
+
+				if (partReference != null) {
+					for (final IPartListener listener : partListenerList) {
+						SafeRunner.run(new SafeRunnable() {
+							@Override
+							public void run() throws Exception {
+								listener.partDeactivated(workbenchPart);
+							}
+						});
+					}
+
+					for (final IPartListener2 listener : partListener2List) {
+						SafeRunner.run(new SafeRunnable() {
+							@Override
+							public void run() throws Exception {
+								listener.partDeactivated(partReference);
+							}
+						});
+					}
+				}
+			}
+		}
+	}
+
+	public void firePartOpened(CompatibilityPart compatibilityPart) {
+		final IWorkbenchPart part = compatibilityPart.getPart();
+		final IWorkbenchPartReference partReference = compatibilityPart.getReference();
+
+		SaveablesList saveablesList = (SaveablesList) getWorkbenchWindow().getService(
+				ISaveablesLifecycleListener.class);
+		saveablesList.postOpen(part);
+
+		for (final IPartListener listener : partListenerList) {
+			SafeRunner.run(new SafeRunnable() {
+				@Override
+				public void run() throws Exception {
+					listener.partOpened(part);
+				}
+			});
+		}
+
+		for (final IPartListener2 listener : partListener2List) {
+			SafeRunner.run(new SafeRunnable() {
+				@Override
+				public void run() throws Exception {
+					listener.partOpened(partReference);
+				}
+			});
+		}
+
+		if (part instanceof IPageChangeProvider) {
+			((IPageChangeProvider) part).addPageChangedListener(pageChangedListener);
+		}
+
+		if (compatibilityPart instanceof CompatibilityView) {
+			legacyWindow.firePerspectiveChanged(this, getPerspective(), partReference,
+					CHANGE_VIEW_SHOW);
+			legacyWindow.firePerspectiveChanged(this, getPerspective(), CHANGE_VIEW_SHOW);
+		}
+	}
+
+	public void firePartClosed(CompatibilityPart compatibilityPart) {
+		final IWorkbenchPart part = compatibilityPart.getPart();
+		final WorkbenchPartReference partReference = compatibilityPart.getReference();
+		MPart model = partReference.getModel();
+
+		SaveablesList modelManager = (SaveablesList) getWorkbenchWindow().getService(
+				ISaveablesLifecycleListener.class);
+		Object postCloseInfo = modelManager.preCloseParts(Collections.singletonList(part), false,
+				getWorkbenchWindow());
+		if (postCloseInfo != null) {
+			modelManager.postClose(postCloseInfo);
+		}
+
+		for (final IPartListener listener : partListenerList) {
+			SafeRunner.run(new SafeRunnable() {
+				@Override
+				public void run() throws Exception {
+					listener.partClosed(part);
+				}
+			});
+		}
+
+		for (final IPartListener2 listener : partListener2List) {
+			SafeRunner.run(new SafeRunnable() {
+				@Override
+				public void run() throws Exception {
+					listener.partClosed(partReference);
+				}
+			});
+		}
+
+		if (part instanceof IViewPart) {
+			viewReferences.remove(partReference);
+		} else {
+			editorReferences.remove(partReference);
+		}
+
+		for (int i = 0; i < activationList.size(); i++) {
+			if (model == activationList.get(i)) {
+				activationList.remove(i);
+				break;
+			}
+		}
+
+		MPart activePart = partService.getActivePart();
+		if (activePart == null) {
+			// unset active part/editor sources if no active part found
+			updateActivePartSources(null);
+			updateActiveEditorSources(null);
+		} else if (part instanceof IEditorPart) {
+			// an editor got closed, update information about active editor
+			IEditorPart activeEditor = getActiveEditor();
+			if (activeEditor == null) {
+				updateActiveEditorSources(activePart);
+			} else {
+				updateActiveEditorSources(findPart(activeEditor));
+			}
+		}
+
+		if (part instanceof IPageChangeProvider) {
+			((IPageChangeProvider) part).removePageChangedListener(pageChangedListener);
+		}
+
+		if (compatibilityPart instanceof CompatibilityView) {
+			legacyWindow.firePerspectiveChanged(this, getPerspective(), partReference,
+					CHANGE_VIEW_HIDE);
+			legacyWindow.firePerspectiveChanged(this, getPerspective(), CHANGE_VIEW_HIDE);
+		}
+	}
+
+	private void firePartBroughtToTop(MPart part) {
+		Object client = part.getObject();
+		if (client instanceof CompatibilityPart) {
+			final IWorkbenchPart workbenchPart = ((CompatibilityPart) client).getPart();
+			final IWorkbenchPartReference partReference = getReference(workbenchPart);
+
+			for (final IPartListener listener : partListenerList) {
+				SafeRunner.run(new SafeRunnable() {
+					@Override
+					public void run() throws Exception {
+						listener.partBroughtToTop(workbenchPart);
+					}
+				});
+			}
+
+			for (final IPartListener2 listener : partListener2List) {
+				SafeRunner.run(new SafeRunnable() {
+					@Override
+					public void run() throws Exception {
+						listener.partBroughtToTop(partReference);
+					}
+				});
+			}
+		} else {
+			Integer val = partEvents.get(part);
+			if (val == null) {
+				partEvents.put(part, Integer.valueOf(FIRE_PART_BROUGHTTOTOP));
+			} else {
+				partEvents.put(part, Integer.valueOf(val.intValue() | FIRE_PART_BROUGHTTOTOP));
+			}
+		}
+	}
+
+	private WeakHashMap<MPart, Integer> partEvents = new WeakHashMap<>();
+	private static final int FIRE_PART_VISIBLE = 0x1;
+	private static final int FIRE_PART_BROUGHTTOTOP = 0x2;
+
+	private EventHandler firingHandler = new EventHandler() {
+		@Override
+		public void handleEvent(Event event) {
+			Object element = event.getProperty(UIEvents.EventTags.ELEMENT);
+			Object value = event.getProperty(UIEvents.EventTags.NEW_VALUE);
+			if (value instanceof CompatibilityPart && element instanceof MPart) {
+				Integer events = partEvents.remove(element);
+				if (events != null) {
+					int e = events.intValue();
+					if ((e & FIRE_PART_VISIBLE) == FIRE_PART_VISIBLE) {
+						firePartVisible((MPart) element);
+					}
+					if ((e & FIRE_PART_BROUGHTTOTOP) == FIRE_PART_BROUGHTTOTOP) {
+						firePartBroughtToTop((MPart) element);
+					}
+				}
+			}
+		}
+	};
+
+	private EventHandler childrenHandler = new EventHandler() {
+		@Override
+		public void handleEvent(Event event) {
+			Object changedObj = event.getProperty(UIEvents.EventTags.ELEMENT);
+
+			// ...in this window ?
+			MUIElement changedElement = (MUIElement) changedObj;
+			if (modelService.getTopLevelWindowFor(changedElement) != window)
+				return;
+
+			if (UIEvents.isADD(event)) {
+				for (Object o : UIEvents.asIterable(event, UIEvents.EventTags.NEW_VALUE)) {
+					if (!(o instanceof MUIElement))
+						continue;
+
+					// We have to iterate through the new elements to see if any
+					// contain (or are) MParts (e.g. we may have dragged a split
+					// editor which contains two editors, both with EditorRefs)
+					MUIElement element = (MUIElement) o;
+					List<MPart> addedParts = modelService.findElements(element, null, MPart.class,
+							null);
+					for (MPart part : addedParts) {
+						IWorkbenchPartReference ref = (IWorkbenchPartReference) part
+								.getTransientData().get(
+								IWorkbenchPartReference.class.getName());
+
+						// For now we only check for editors changing pages
+						if (ref instanceof EditorReference && getEditorReference(part) == null) {
+							addEditorReference((EditorReference) ref);
+						}
+					}
+				}
+			}
+		}
+	};
+
+	// FIXME: convert me to e4 events!
+	private void firePartVisible(MPart part) {
+		Object client = part.getObject();
+		if (client instanceof CompatibilityPart) {
+			IWorkbenchPart workbenchPart = ((CompatibilityPart) client).getPart();
+			final IWorkbenchPartReference partReference = getReference(workbenchPart);
+
+			for (final IPartListener2 listener : partListener2List) {
+				SafeRunner.run(new SafeRunnable() {
+					@Override
+					public void run() throws Exception {
+						listener.partVisible(partReference);
+					}
+				});
+			}
+			
+		} else {
+			Integer val = partEvents.get(part);
+			if (val == null) {
+				partEvents.put(part, Integer.valueOf(FIRE_PART_VISIBLE));
+			} else {
+				partEvents.put(part, Integer.valueOf(val.intValue() | FIRE_PART_VISIBLE));
+			}
+		}
+	}
+
+	// FIXME: convert me to e4 events!
+	public void firePartHidden(MPart part) {
+		Object client = part.getObject();
+		if (client instanceof CompatibilityPart) {
+			IWorkbenchPart workbenchPart = ((CompatibilityPart) client).getPart();
+			final IWorkbenchPartReference partReference = getReference(workbenchPart);
+
+			for (final IPartListener2 listener : partListener2List) {
+				SafeRunner.run(new SafeRunnable() {
+					@Override
+					public void run() throws Exception {
+						listener.partHidden(partReference);
+					}
+				});
+			}
+		}
+	}
+
+	public void firePartInputChanged(final IWorkbenchPartReference partReference) {
+		for (final IPartListener2 listener : partListener2List) {
+			SafeRunner.run(new SafeRunnable() {
+				@Override
+				public void run() throws Exception {
+					listener.partInputChanged(partReference);
+				}
+			});
+		}
+	}
+
+	@Override
+	public int getEditorReuseThreshold() {
+		IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore();
+		return store.getInt(IPreferenceConstants.REUSE_EDITORS);
+	}
+
+	@Override
+	public void setEditorReuseThreshold(int openEditors) {
+		// this is an empty implementation in 3.x, see IPageLayout's
+		// setEditorReuseThreshold
+	}
+
+	/**
+	 * Opens an editor represented by the descriptor with the given input.
+	 *
+	 * @param fileEditorInput
+	 *            the input that the editor should open
+	 * @param editorDescriptor
+	 *            the descriptor of the editor to open
+	 * @param activate
+	 *            <tt>true</tt> if the editor should be activated,
+	 *            <tt>false</tt> otherwise
+	 * @param editorState
+	 *            the previously saved state of the editor as a memento, this
+	 *            may be <tt>null</tt>
+	 * @return the opened editor
+	 * @exception PartInitException
+	 *                if the editor could not be created or initialized
+	 */
+	public IEditorPart openEditorFromDescriptor(IEditorInput fileEditorInput,
+			IEditorDescriptor editorDescriptor, final boolean activate, final IMemento editorState)
+			throws PartInitException {
+		if (editorDescriptor.isOpenExternal()) {
+			openExternalEditor((EditorDescriptor) editorDescriptor, fileEditorInput);
+			return null;
+		}
+		return openEditor(fileEditorInput, editorDescriptor.getId(), activate, MATCH_INPUT,
+				editorState, true);
+	}
+
+	/**
+	 * Open a specific external editor on an file based on the descriptor.
+	 */
+	private IEditorReference openExternalEditor(final EditorDescriptor desc, IEditorInput input)
+			throws PartInitException {
+		final CoreException ex[] = new CoreException[1];
+
+		final IPathEditorInput pathInput = getPathEditorInput(input);
+		if (pathInput != null && pathInput.getPath() != null) {
+			BusyIndicator.showWhile(legacyWindow.getWorkbench().getDisplay(), new Runnable() {
+				@Override
+				public void run() {
+					try {
+						if (desc.getLauncher() != null) {
+							// open using launcher
+							Object launcher = WorkbenchPlugin.createExtension(desc
+									.getConfigurationElement(),
+									IWorkbenchRegistryConstants.ATT_LAUNCHER);
+							((IEditorLauncher) launcher).open(pathInput.getPath());
+						}
+						// RAP no external editors
+//						else {
+//							// open using command
+//							ExternalEditor oEditor = new ExternalEditor(pathInput.getPath(), desc);
+//							oEditor.open();
+//						}
+					} catch (CoreException e) {
+						ex[0] = e;
+					}
+				}
+			});
+		} else {
+			throw new PartInitException(NLS.bind(
+					WorkbenchMessages.get().EditorManager_errorOpeningExternalEditor, desc.getFileName(),
+					desc.getId()));
+		}
+
+		if (ex[0] != null) {
+			throw new PartInitException(NLS.bind(
+					WorkbenchMessages.get().EditorManager_errorOpeningExternalEditor, desc.getFileName(),
+					desc.getId()), ex[0]);
+		}
+
+		recordEditor(input, desc);
+		// we do not have an editor part for external editors
+		return null;
+	}
+
+	private IPathEditorInput getPathEditorInput(IEditorInput input) {
+		if (input instanceof IPathEditorInput)
+			return (IPathEditorInput) input;
+		return Adapters.adapt(input, IPathEditorInput.class);
+	}
+
+	/**
+	 * Unzooms the shared area if there are no more rendered parts contained
+	 * within it.
+	 *
+	 * @see #unzoomSharedArea(MUIElement)
+	 */
+	private void unzoomSharedArea() {
+		MPerspective curPersp = getPerspectiveStack().getSelectedElement();
+		if (curPersp == null)
+			return;
+
+		MPlaceholder eaPH = (MPlaceholder) modelService.find(IPageLayout.ID_EDITOR_AREA, curPersp);
+		for (MPart part : modelService.findElements(eaPH, null, MPart.class, null)) {
+			if (part.isToBeRendered()) {
+				MPlaceholder placeholder = part.getCurSharedRef();
+				if (placeholder == null || placeholder.isToBeRendered()) {
+					return;
+				}
+			}
+		}
+
+		setPartState(eaPH, null);
+	}
+
+	/**
+	 * Unzooms the shared area if the specified element is in the shared area.
+	 *
+	 * @param element
+	 *            the element to check if it is in the shared area
+	 * @see #unzoomSharedArea()
+	 */
+	private void unzoomSharedArea(MUIElement element) {
+		if (modelService.getElementLocation(element) == EModelService.IN_SHARED_AREA) {
+			unzoomSharedArea();
+		}
+	}
+
+	/**
+	 * An event handler for listening to parts and placeholders being
+	 * unrendered.
+	 */
+	private EventHandler referenceRemovalEventHandler = new EventHandler() {
+		@Override
+		public void handleEvent(Event event) {
+			if (Boolean.TRUE.equals(event.getProperty(UIEvents.EventTags.NEW_VALUE))) {
+				return;
+			}
+
+			Object element = event.getProperty(UIEvents.EventTags.ELEMENT);
+			if (element instanceof MPlaceholder) {
+				MUIElement ref = ((MPlaceholder) element).getRef();
+				// a placeholder has been unrendered, check to see if the shared
+				// area needs to be unzoomed
+				unzoomSharedArea(ref);
+
+				if (ref instanceof MPart) {
+					// find all placeholders for this part
+					List<MPlaceholder> placeholders = modelService.findElements(window,
+							ref.getElementId(), MPlaceholder.class, null,
+							EModelService.IN_ANY_PERSPECTIVE | EModelService.IN_SHARED_AREA
+									| EModelService.OUTSIDE_PERSPECTIVE);
+					for (MPlaceholder placeholder : placeholders) {
+						if (placeholder.getRef() == ref && placeholder.isToBeRendered()) {
+							// if there's a rendered placeholder, return
+							return;
+						}
+					}
+
+					// no rendered placeholders around, unsubscribe
+					ViewReference reference = getViewReference((MPart) ref);
+					if (reference != null) {
+						reference.unsubscribe();
+					}
+				}
+			} else if (element instanceof MPart) {
+				MPart part = (MPart) element;
+				// a part has been unrendered, check to see if the shared
+				// area needs to be unzoomed
+				unzoomSharedArea(part);
+
+				if (CompatibilityEditor.MODEL_ELEMENT_ID.equals(part.getElementId())) {
+					EditorReference reference = getEditorReference(part);
+					if (reference != null) {
+						reference.unsubscribe();
+					}
+				}
+			}
+		}
+	};
+
+	public String getHiddenItems() {
+		MPerspective perspective = getCurrentPerspective();
+		if (perspective == null)
+			return ""; //$NON-NLS-1$
+
+		String result = perspective.getPersistedState().get(ModeledPageLayout.HIDDEN_ITEMS_KEY);
+		if (result == null)
+			return ""; //$NON-NLS-1$
+
+		return result;
+	}
+
+	public void addHiddenItems(MPerspective perspective, String id) {
+		String hiddenIDs = perspective.getPersistedState().get(ModeledPageLayout.HIDDEN_ITEMS_KEY);
+		if (hiddenIDs == null)
+			hiddenIDs = ""; //$NON-NLS-1$
+
+		String persistedID = id + ","; //$NON-NLS-1$
+		if (!hiddenIDs.contains(persistedID)) {
+			hiddenIDs = hiddenIDs + persistedID;
+			perspective.getPersistedState().put(ModeledPageLayout.HIDDEN_ITEMS_KEY, hiddenIDs);
+		}
+	}
+
+	public void addHiddenItems(String id) {
+		MPerspective perspective = getCurrentPerspective();
+		if (perspective == null)
+			return;
+		addHiddenItems(perspective, id);
+	}
+
+	public void removeHiddenItems(MPerspective perspective, String id) {
+		String persistedID = id + ","; //$NON-NLS-1$
+
+		String hiddenIDs = perspective.getPersistedState().get(ModeledPageLayout.HIDDEN_ITEMS_KEY);
+		if (hiddenIDs == null)
+			return;
+
+		String newValue = hiddenIDs.replaceFirst(persistedID, ""); //$NON-NLS-1$
+		if (hiddenIDs.length() != newValue.length()) {
+			if (newValue.length() == 0)
+				perspective.getPersistedState().remove(ModeledPageLayout.HIDDEN_ITEMS_KEY);
+			else
+				perspective.getPersistedState().put(ModeledPageLayout.HIDDEN_ITEMS_KEY,
+						newValue);
+		}
+	}
+
+	public void removeHiddenItems(String id) {
+		MPerspective perspective = getCurrentPerspective();
+		if (perspective == null)
+			return;
+		removeHiddenItems(perspective, id);
+	}
+
+	public void setNewShortcuts(List<String> wizards, String tagPrefix) {
+		MPerspective persp = getCurrentPerspective();
+		if (persp == null)
+			return;
+
+		List<String> existingNewWizards = new ArrayList<>();
+		for (String tag : persp.getTags()) {
+			if (tag.contains(tagPrefix))
+				existingNewWizards.add(tag);
+		}
+
+		List<String> newWizards = new ArrayList<>(wizards.size());
+		for (String wizardName : wizards) {
+			newWizards.add(tagPrefix + wizardName);
+		}
+
+		persp.getTags().removeAll(existingNewWizards);
+		persp.getTags().addAll(newWizards);
+	}
+
+	/**
+	 *
+	 */
+	public void resetToolBarLayout() {
+		ICoolBarManager2 mgr = (ICoolBarManager2) legacyWindow.getCoolBarManager2();
+		mgr.resetItemOrder();
+	}
+
+	/**
+	 * Call {@link #firePartDeactivated(MPart)} if the passed part is the
+	 * currently active part according to the part service. This method should
+	 * only be called in the case of workbench shutdown, where E4 does not fire
+	 * deactivate listeners on the active part.
+	 *
+	 * @param part
+	 */
+	public void firePartDeactivatedIfActive(MPart part) {
+		if (partService.getActivePart() == part) {
+			// At shutdown, e4 doesn't fire part deactivated on the active
+			// part.
+			firePartDeactivated(part);
+		}
+	}
+
+	/**
+	 * Add ToolItems for perspectives specified in "PERSPECTIVE_BAR_EXTRAS"
+	 */
+	private void createPerspectiveBarExtras() {
+		String persps = PrefUtil.getAPIPreferenceStore()
+				.getString(IWorkbenchPreferenceConstants.PERSPECTIVE_BAR_EXTRAS);
+		// e3 allowed spaces and commas as separator
+		String[] parts = persps.split("[, ]"); //$NON-NLS-1$
+		Set<String> perspSet = new LinkedHashSet<>();
+		for (String part : parts) {
+			part = part.trim();
+			if (!part.isEmpty())
+				perspSet.add(part);
+		}
+
+		for (String perspId : perspSet) {
+			MPerspective persp = (MPerspective) modelService.find(perspId, window);
+			if (persp != null)
+				continue; // already in stack, i.e. has already been added above
+			IPerspectiveDescriptor desc = getDescriptorFor(perspId);
+			if (desc == null)
+				continue; // this perspective does not exist
+			persp = createPerspective(desc);
+			persp.setLabel(desc.getLabel());
+			getPerspectiveStack().getChildren().add(persp);
+			// "add" fires Event, causes creation of ToolItem on perspective bar
+		}
+	}
+
+	private IPerspectiveDescriptor getDescriptorFor(String id) {
+		IPerspectiveRegistry perspectiveRegistry = getWorkbenchWindow().getWorkbench().getPerspectiveRegistry();
+		if (perspectiveRegistry instanceof PerspectiveRegistry) {
+			return ((PerspectiveRegistry) perspectiveRegistry).findPerspectiveWithId(id, false);
+		}
+
+		return perspectiveRegistry.findPerspectiveWithId(id);
+	}
+	
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchPartReference.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchPartReference.java
new file mode 100644
index 0000000..e11a983
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchPartReference.java
@@ -0,0 +1,577 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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
+ *     Stefan Xenos, IBM; Chris Torrence, ITT Visual Information Solutions - bug 51580
+ *     Nikolay Botev - bug 240651
+ *     Andrey Loskutov <loskutov@gmx.de> - Bug 372799
+ *******************************************************************************/
+package org.eclipse.ui.internal;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.services.events.IEventBroker;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.workbench.IPresentationEngine;
+import org.eclipse.e4.ui.workbench.UIEvents;
+import org.eclipse.e4.ui.workbench.modeling.EPartService;
+import org.eclipse.e4.ui.workbench.modeling.EPartService.PartState;
+import org.eclipse.e4.ui.workbench.renderers.swt.SWTPartRenderer;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IPropertyListener;
+import org.eclipse.ui.ISaveablePart;
+import org.eclipse.ui.ISaveablesLifecycleListener;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.ISizeProvider;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPart2;
+import org.eclipse.ui.IWorkbenchPart3;
+import org.eclipse.ui.IWorkbenchPartConstants;
+import org.eclipse.ui.IWorkbenchPartReference;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.e4.compatibility.CompatibilityPart;
+import org.eclipse.ui.internal.misc.UIListenerLogging;
+import org.eclipse.ui.internal.util.Util;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventHandler;
+
+/**
+ *
+ */
+public abstract class WorkbenchPartReference implements IWorkbenchPartReference, ISizeProvider {
+
+	/**
+     * Internal property ID: Indicates that the underlying part was created
+     */
+    public static final int INTERNAL_PROPERTY_OPENED = 0x211;
+
+    /**
+     * Internal property ID: Indicates that the underlying part was destroyed
+     */
+    public static final int INTERNAL_PROPERTY_CLOSED = 0x212;
+
+    /**
+     * Internal property ID: Indicates that the result of IEditorReference.isPinned()
+     */
+    public static final int INTERNAL_PROPERTY_PINNED = 0x213;
+
+    /**
+     * Internal property ID: Indicates that the result of getVisible() has changed
+     */
+    public static final int INTERNAL_PROPERTY_VISIBLE = 0x214;
+
+    /**
+     * Internal property ID: Indicates that the result of isZoomed() has changed
+     */
+    public static final int INTERNAL_PROPERTY_ZOOMED = 0x215;
+
+    /**
+     * Internal property ID: Indicates that the part has an active child and the
+     * active child has changed. (fired by PartStack)
+     */
+    public static final int INTERNAL_PROPERTY_ACTIVE_CHILD_CHANGED = 0x216;
+
+    /**
+     * Internal property ID: Indicates that changed in the min / max
+     * state has changed
+     */
+    public static final int INTERNAL_PROPERTY_MAXIMIZED = 0x217;
+
+    // State constants //////////////////////////////
+
+    /**
+     * State constant indicating that the part is not created yet
+     */
+    public static int STATE_LAZY = 0;
+
+    /**
+     * State constant indicating that the part is in the process of being created
+     */
+    public static int STATE_CREATION_IN_PROGRESS = 1;
+
+    /**
+     * State constant indicating that the part has been created
+     */
+    public static int STATE_CREATED = 2;
+
+    /**
+     * State constant indicating that the reference has been disposed (the reference shouldn't be
+     * used anymore)
+     */
+    public static int STATE_DISPOSED = 3;
+
+	static String MEMENTO_KEY = "memento"; //$NON-NLS-1$
+
+    /**
+     * Current state of the reference. Used to detect recursive creation errors, disposed
+     * references, etc.
+     */
+    private int state = STATE_LAZY;
+
+	protected IWorkbenchPart legacyPart;
+    private boolean pinned = false;
+
+    /**
+     * API listener list
+     */
+	private ListenerList<IPropertyListener> propChangeListeners = new ListenerList<>();
+
+    /**
+     * Internal listener list. Listens to the INTERNAL_PROPERTY_* property change events that are not yet API.
+     * TODO: Make these properties API in 3.2
+     */
+	private ListenerList<IPropertyListener> internalPropChangeListeners = new ListenerList<>();
+
+	private ListenerList<IPropertyChangeListener> partChangeListeners = new ListenerList<>();
+
+    protected Map propertyCache = new HashMap();
+
+    private IPropertyListener propertyChangeListener = (source, propId) -> partPropertyChanged(source, propId);
+
+    private IPropertyChangeListener partPropertyChangeListener = event -> partPropertyChanged(event);
+
+	private IWorkbenchPage page;
+
+	private MPart part;
+
+	private IEclipseContext windowContext;
+
+	private EventHandler contextEventHandler;
+
+    public WorkbenchPartReference(IEclipseContext windowContext, IWorkbenchPage page, MPart part) {
+    	this.windowContext = windowContext;
+		this.page = page;
+		this.part = part;
+
+		// cache the reference in the MPart's transientData
+		if (part != null) {
+			part.getTransientData().put(IWorkbenchPartReference.class.getName(), this);
+		}
+	}
+
+	private EventHandler createContextEventHandler() {
+		if (contextEventHandler == null) {
+			contextEventHandler = new EventHandler() {
+				@Override
+				public void handleEvent(Event event) {
+					Object element = event.getProperty(UIEvents.EventTags.ELEMENT);
+					MPart part = getModel();
+					if (element == part) {
+						if (part.getContext() != null) {
+							part.getContext().set(getClass().getName(), this);
+							unsubscribe();
+						}
+					}
+				}
+			};
+		}
+		return contextEventHandler;
+	}
+
+	public void subscribe() {
+		IEventBroker broker = windowContext.get(IEventBroker.class);
+		broker.subscribe(UIEvents.Context.TOPIC_CONTEXT,
+				createContextEventHandler());
+	}
+
+	public void unsubscribe() {
+		if (contextEventHandler != null) {
+			IEventBroker broker = windowContext.get(IEventBroker.class);
+			broker.unsubscribe(contextEventHandler);
+			contextEventHandler = null;
+		}
+	}
+
+    public boolean isDisposed() {
+        return state == STATE_DISPOSED;
+    }
+
+    protected void checkReference() {
+        if (state == STATE_DISPOSED) {
+            throw new RuntimeException("Error: IWorkbenchPartReference disposed"); //$NON-NLS-1$
+        }
+    }
+
+	public MPart getModel() {
+		return part;
+	}
+
+
+    protected void partPropertyChanged(Object source, int propId) {
+		firePropertyChange(propId);
+
+        // Let the model manager know as well
+        if (propId == IWorkbenchPartConstants.PROP_DIRTY) {
+        	IWorkbenchPart actualPart = getPart(false);
+        	if (actualPart != null) {
+				SaveablesList modelManager = (SaveablesList) actualPart.getSite().getService(ISaveablesLifecycleListener.class);
+	        	modelManager.dirtyChanged(actualPart);
+        	}
+        }
+    }
+
+    protected void partPropertyChanged(PropertyChangeEvent event) {
+    	firePartPropertyChange(event);
+    }
+
+    /**
+     * Releases any references maintained by this part reference
+     * when its actual part becomes known (not called when it is disposed).
+     */
+    protected void releaseReferences() {
+
+    }
+
+    /* package */ void addInternalPropertyListener(IPropertyListener listener) {
+        internalPropChangeListeners.add(listener);
+    }
+
+    /* package */ void removeInternalPropertyListener(IPropertyListener listener) {
+        internalPropChangeListeners.remove(listener);
+    }
+
+    protected void fireInternalPropertyChange(int id) {
+		for (IPropertyListener listener : internalPropChangeListeners) {
+			listener.propertyChanged(this, id);
+        }
+    }
+
+    /**
+     * @see IWorkbenchPart
+     */
+    @Override
+	public void addPropertyListener(IPropertyListener listener) {
+        // The properties of a disposed reference will never change, so don't
+        // add listeners
+        if (isDisposed()) {
+            return;
+        }
+
+        propChangeListeners.add(listener);
+    }
+
+    /**
+     * @see IWorkbenchPart
+     */
+    @Override
+	public void removePropertyListener(IPropertyListener listener) {
+        // Currently I'm not calling checkReference here for fear of breaking things late in 3.1, but it may
+        // make sense to do so later. For now we just turn it into a NOP if the reference is disposed.
+        if (isDisposed()) {
+            return;
+        }
+        propChangeListeners.remove(listener);
+    }
+
+
+	@Override
+	public String getTitle() {
+		String title = legacyPart == null ? part.getLocalizedLabel() : legacyPart.getTitle();
+		return Util.safeString(title);
+	}
+
+	@Override
+	public String getTitleToolTip() {
+		String toolTip = (String) part.getTransientData().get(
+				IPresentationEngine.OVERRIDE_TITLE_TOOL_TIP_KEY);
+		if (toolTip == null || toolTip.length() == 0)
+			toolTip = part.getLocalizedTooltip();
+		return Util.safeString(toolTip);
+	}
+
+	@Override
+	public String getId() {
+		String id = part.getElementId();
+
+		// Only return the descriptor id
+		int colonIndex = id.indexOf(':');
+		return colonIndex == -1 ? id : id.substring(0, colonIndex);
+	}
+
+    /**
+     * Computes a new title for the part. Subclasses may override to change the default behavior.
+     *
+     * @return the title for the part
+     */
+    protected String computeTitle() {
+        return getRawTitle();
+    }
+
+    /**
+     * Returns the unmodified title for the part, or the empty string if none
+     *
+     * @return the unmodified title, as set by the IWorkbenchPart. Returns the empty string if none.
+     */
+    protected final String getRawTitle() {
+		return Util.safeString(legacyPart.getTitle());
+    }
+
+	@Override
+	public final Image getTitleImage() {
+		if (isDisposed()) {
+			return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_DEF_VIEW);
+		}
+
+		WorkbenchWindow wbw = (WorkbenchWindow) PlatformUI.getWorkbench()
+				.getActiveWorkbenchWindow();
+		if (part != null && wbw.getModel().getRenderer() instanceof SWTPartRenderer) {
+			SWTPartRenderer r = (SWTPartRenderer) wbw.getModel().getRenderer();
+			Image image = r.getImage(part);
+			if (image != null) {
+				return image;
+			}
+		}
+
+		return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_DEF_VIEW);
+	}
+
+    /* package */ void fireVisibilityChange() {
+        fireInternalPropertyChange(INTERNAL_PROPERTY_VISIBLE);
+    }
+
+    /* package */ void fireZoomChange() {
+        fireInternalPropertyChange(INTERNAL_PROPERTY_ZOOMED);
+    }
+
+	protected void firePropertyChange(int id) {
+        immediateFirePropertyChange(id);
+    }
+
+    private void immediateFirePropertyChange(int id) {
+        UIListenerLogging.logPartReferencePropertyChange(this, id);
+		for (IPropertyListener listener : propChangeListeners) {
+			listener.propertyChanged(legacyPart, id);
+        }
+
+        fireInternalPropertyChange(id);
+    }
+
+	public abstract PartSite getSite();
+
+	public abstract void initialize(IWorkbenchPart part) throws PartInitException;
+
+	void addPropertyListeners() {
+		IWorkbenchPart workbenchPart = getPart(false);
+		if (workbenchPart != null) {
+			workbenchPart.addPropertyListener(propertyChangeListener);
+
+			if (workbenchPart instanceof IWorkbenchPart3) {
+				((IWorkbenchPart3) workbenchPart)
+						.addPartPropertyListener(partPropertyChangeListener);
+
+			}
+		}
+	}
+
+    @Override
+	public final IWorkbenchPart getPart(boolean restore) {
+        if (isDisposed()) {
+            return null;
+        }
+
+        if (legacyPart == null) {
+			if (restore && part.getWidget() == null) {
+				// create the underlying client object backed by the part model
+				// with the rendering engine
+				EPartService partService = windowContext.get(EPartService.class);
+				partService.showPart(part, PartState.CREATE);
+			}
+
+			// check if we were actually created, it is insufficient to check
+			// whether the 'object' feature is valid or not because it is one of
+			// the last things to be unset during the teardown process, this
+			// means we may return a valid workbench part even if it is actually
+			// in the process of being destroyed, see bug 328944
+			if (part.getObject() instanceof CompatibilityPart) {
+				CompatibilityPart compatibilityPart = (CompatibilityPart) part.getObject();
+				if (compatibilityPart != null) {
+					legacyPart = compatibilityPart.getPart();
+				}
+			} else if (part.getObject() != null) {
+        		if (part.getTransientData().get(E4PartWrapper.E4_WRAPPER_KEY) instanceof E4PartWrapper) {
+        		  return (IWorkbenchPart) part.getTransientData().get(E4PartWrapper.E4_WRAPPER_KEY);
+				}
+        	}
+		}
+
+		return legacyPart;
+    }
+
+	public abstract IWorkbenchPart createPart() throws PartInitException;
+
+	abstract IWorkbenchPart createErrorPart();
+
+	public abstract IWorkbenchPart createErrorPart(IStatus status);
+
+	protected void doDisposeNestedParts() {
+		// To be implemented by subclasses
+	}
+
+    /**
+     *
+     */
+	private void doDisposePart() {
+		if (legacyPart != null) {
+            fireInternalPropertyChange(INTERNAL_PROPERTY_CLOSED);
+            // Don't let exceptions in client code bring us down. Log them and continue.
+            try {
+				legacyPart.removePropertyListener(propertyChangeListener);
+				if (legacyPart instanceof IWorkbenchPart3) {
+					((IWorkbenchPart3) legacyPart)
+							.removePartPropertyListener(partPropertyChangeListener);
+                }
+            } catch (Exception e) {
+                WorkbenchPlugin.log(e);
+            }
+			legacyPart = null;
+        }
+    }
+
+    public void setPinned(boolean newPinned) {
+        if (isDisposed()) {
+            return;
+        }
+
+        if (newPinned == pinned) {
+            return;
+        }
+
+        pinned = newPinned;
+
+		immediateFirePropertyChange(IWorkbenchPartConstants.PROP_TITLE);
+        if (pinned)
+        	part.getTags().add(IPresentationEngine.ADORNMENT_PIN);
+        else
+        	part.getTags().remove(IPresentationEngine.ADORNMENT_PIN);
+
+        fireInternalPropertyChange(INTERNAL_PROPERTY_PINNED);
+    }
+
+    public boolean isPinned() {
+        return pinned;
+    }
+
+    @Override
+	public String getPartProperty(String key) {
+		if (legacyPart != null) {
+			if (legacyPart instanceof IWorkbenchPart3) {
+				return ((IWorkbenchPart3) legacyPart).getPartProperty(key);
+			}
+		} else {
+			return (String)propertyCache.get(key);
+		}
+		return null;
+	}
+
+    @Override
+	public void addPartPropertyListener(IPropertyChangeListener listener) {
+    	if (isDisposed()) {
+    		return;
+    	}
+    	partChangeListeners.add(listener);
+    }
+
+    @Override
+	public void removePartPropertyListener(IPropertyChangeListener listener) {
+    	if (isDisposed()) {
+    		return;
+    	}
+    	partChangeListeners.remove(listener);
+    }
+
+    protected void firePartPropertyChange(PropertyChangeEvent event) {
+		for (IPropertyChangeListener l : partChangeListeners) {
+			l.propertyChange(event);
+		}
+	}
+
+    protected void createPartProperties(IWorkbenchPart3 workbenchPart) {
+		Iterator i = propertyCache.entrySet().iterator();
+		while (i.hasNext()) {
+			Map.Entry e = (Map.Entry) i.next();
+			workbenchPart.setPartProperty((String) e.getKey(), (String) e.getValue());
+		}
+	}
+
+    @Override
+	public int computePreferredSize(boolean width, int availableParallel,
+            int availablePerpendicular, int preferredResult) {
+
+		ISizeProvider sizeProvider = Adapters.adapt(legacyPart, ISizeProvider.class);
+        if (sizeProvider != null) {
+            return sizeProvider.computePreferredSize(width, availableParallel, availablePerpendicular, preferredResult);
+        }
+
+        return preferredResult;
+    }
+
+    @Override
+	public int getSizeFlags(boolean width) {
+		ISizeProvider sizeProvider = Adapters.adapt(legacyPart, ISizeProvider.class);
+        if (sizeProvider != null) {
+            return sizeProvider.getSizeFlags(width);
+        }
+        return 0;
+    }
+
+	@Override
+	public IWorkbenchPage getPage() {
+		return page;
+	}
+
+	public void setPage(IWorkbenchPage newPage) {
+		page = newPage;
+	}
+
+	@Override
+	public String getPartName() {
+		return part.getLocalizedLabel();
+	}
+
+	@Override
+	public String getContentDescription() {
+		IWorkbenchPart workbenchPart = getPart(false);
+		if (workbenchPart instanceof IWorkbenchPart2) {
+			return ((IWorkbenchPart2) workbenchPart).getContentDescription();
+		}
+		return workbenchPart.getTitle();
+	}
+
+	@Override
+	public boolean isDirty() {
+		IWorkbenchPart part = getPart(false);
+		ISaveablePart saveable = SaveableHelper.getSaveable(part);
+		if (saveable != null) {
+			return saveable.isDirty();
+		}
+		return false;
+	}
+
+	public void invalidate() {
+		doDisposePart();
+	}
+
+	public final PartPane getPane() {
+		return new PartPane() {
+			@Override
+			public Control getControl() {
+				return part == null ? null : (Control) part.getWidget();
+			}
+		};
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchPlugin.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchPlugin.java
new file mode 100644
index 0000000..c061ddc
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchPlugin.java
@@ -0,0 +1,1520 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 400714, 441267, 441184, 445723, 445724, 472654, 481608
+ *     Patrik Suzzi <psuzzi@gmail.com> - Bug 489250
+ *******************************************************************************/
+
+package org.eclipse.ui.internal;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Locale;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.e4.core.commands.internal.ICommandHelpService;
+import org.eclipse.e4.core.contexts.ContextFunction;
+import org.eclipse.e4.core.contexts.ContextInjectionFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.ui.services.help.EHelpService;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.PreferenceManager;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.jface.window.Window;
+import org.eclipse.osgi.service.debug.DebugOptions;
+import org.eclipse.osgi.service.localization.LocaleProvider;
+import org.eclipse.rap.rwt.internal.RWTProperties;
+import org.eclipse.rap.ui.internal.SessionLocaleProvider;
+import org.eclipse.rap.ui.internal.progress.JobManagerAdapter;
+import org.eclipse.rap.ui.internal.servlet.HttpServiceTracker;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IDecoratorManager;
+import org.eclipse.ui.IEditorRegistry;
+import org.eclipse.ui.IElementFactory;
+import org.eclipse.ui.IPerspectiveRegistry;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkingSetManager;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.decorators.DecoratorManager;
+import org.eclipse.ui.internal.dialogs.WorkbenchPreferenceManager;
+import org.eclipse.ui.internal.help.CommandHelpServiceImpl;
+import org.eclipse.ui.internal.help.HelpServiceImpl;
+import org.eclipse.ui.internal.intro.IIntroRegistry;
+import org.eclipse.ui.internal.intro.IntroRegistry;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.internal.operations.WorkbenchOperationSupport;
+import org.eclipse.ui.internal.progress.ProgressManager;
+import org.eclipse.ui.internal.registry.ActionSetRegistry;
+import org.eclipse.ui.internal.registry.EditorRegistry;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.registry.PerspectiveRegistry;
+import org.eclipse.ui.internal.registry.PreferencePageRegistryReader;
+import org.eclipse.ui.internal.registry.ViewRegistry;
+import org.eclipse.ui.internal.registry.WorkingSetRegistry;
+import org.eclipse.ui.internal.themes.IThemeRegistry;
+import org.eclipse.ui.internal.themes.ThemeRegistry;
+import org.eclipse.ui.internal.themes.ThemeRegistryReader;
+import org.eclipse.ui.internal.util.BundleUtility;
+import org.eclipse.ui.internal.wizards.ExportWizardRegistry;
+import org.eclipse.ui.internal.wizards.ImportWizardRegistry;
+import org.eclipse.ui.internal.wizards.NewWizardRegistry;
+import org.eclipse.ui.operations.IWorkbenchOperationSupport;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.eclipse.ui.testing.TestableObject;
+import org.eclipse.ui.views.IViewRegistry;
+import org.eclipse.ui.wizards.IWizardRegistry;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.util.tracker.ServiceTracker;
+
+import com.ibm.icu.text.MessageFormat;
+
+/**
+ * This class represents the TOP of the workbench UI world
+ * A plugin class is effectively an application wrapper
+ * for a plugin & its classes. This class should be thought
+ * of as the workbench UI's application class.
+ *
+ * This class is responsible for tracking various registries
+ * font, preference, graphics, dialog store.
+ *
+ * This class is explicitly referenced by the
+ * workbench plugin's  "plugin.xml" and places it
+ * into the UI start extension point of the main
+ * overall application harness
+ *
+ * When is this class started?
+ *      When the Application
+ *      calls createExecutableExtension to create an executable
+ *      instance of our workbench class.
+ */
+public class WorkbenchPlugin extends AbstractUIPlugin {
+
+    // RAP [rst] System property to disable workbench autostart
+    private static final String PROP_WORKBENCH_AUTOSTART = "org.eclipse.rap.workbenchAutostart";
+    
+	/**
+	 * Splash shell constant.
+	 */
+	private static final String DATA_SPLASH_SHELL = "org.eclipse.ui.workbench.splashShell"; //$NON-NLS-1$
+
+	/**
+	 * The OSGi splash property.
+	 *
+	 * @sicne 3.4
+	 */
+	private static final String PROP_SPLASH_HANDLE = "org.eclipse.equinox.launcher.splash.handle"; //$NON-NLS-1$
+
+	private static final String LEFT_TO_RIGHT = "ltr"; //$NON-NLS-1$
+	private static final String RIGHT_TO_LEFT = "rtl";//$NON-NLS-1$
+	private static final String ORIENTATION_COMMAND_LINE = "-dir";//$NON-NLS-1$
+	private static final String ORIENTATION_PROPERTY = "eclipse.orientation";//$NON-NLS-1$
+	private static final String NL_USER_PROPERTY = "osgi.nl.user"; //$NON-NLS-1$
+	private static final String BIDI_COMMAND_LINE = "-bidi";//$NON-NLS-1$
+	private static final String BIDI_SUPPORT_OPTION = "on";//$NON-NLS-1$
+	private static final String BIDI_TEXTDIR_OPTION = "textDir";//$NON-NLS-1$
+
+
+    // Default instance of the receiver
+    private static WorkbenchPlugin inst;
+
+    // Manager that maps resources to descriptors of editors to use
+    private EditorRegistry editorRegistry;
+
+    // Manager for the DecoratorManager
+    private DecoratorManager decoratorManager;
+
+    // Theme registry
+    private ThemeRegistry themeRegistry;
+
+    // Manager for working sets (IWorkingSet)
+    private WorkingSetManager workingSetManager;
+
+    // Working set registry, stores working set dialogs
+    private WorkingSetRegistry workingSetRegistry;
+
+    // The context within which this plugin was started.
+    private BundleContext bundleContext;
+
+    // The set of currently starting bundles
+	private Collection<Bundle> startingBundles = new HashSet<>();
+	
+    // RAP [rh] multi-session-aware LocaleProvider service
+    private ServiceRegistration localeProviderService;
+
+    /**
+     * Global workbench ui plugin flag. Only workbench implementation is allowed to use this flag
+     * All other plugins, examples, or test cases must *not* use this flag.
+     */
+    public static boolean DEBUG = false;
+
+    /**
+     * The workbench plugin ID.
+     *
+     * @issue we should just drop this constant and use PlatformUI.PLUGIN_ID instead
+     */
+    public static String PI_WORKBENCH = PlatformUI.PLUGIN_ID;
+
+    /**
+     * The character used to separate preference page category ids
+     */
+    public static char PREFERENCE_PAGE_CATEGORY_SEPARATOR = '/';
+
+    // Other data.
+    private WorkbenchPreferenceManager preferenceManager;
+
+//    private PerspectiveRegistry perspRegistry;
+
+    private ActionSetRegistry actionSetRegistry;
+
+    private SharedImages sharedImages;
+
+    /**
+     * Information describing the product (formerly called "primary plugin"); lazily
+     * initialized.
+     * @since 3.0
+     */
+    private ProductInfo productInfo = null;
+
+    private IntroRegistry introRegistry;
+
+    private WorkbenchOperationSupport operationSupport;
+	private BundleListener bundleListener;
+
+	private IEclipseContext e4Context;
+
+	private ServiceTracker debugTracker = null;
+
+	private ServiceTracker testableTracker = null;
+
+	private EHelpService helpService;
+
+	private ICommandHelpService commandHelpService;
+	
+	// RAP [bm]: 
+    private HttpServiceTracker httpServiceTracker;
+    // RAPEND: [bm] 
+
+    /**
+     * Create an instance of the WorkbenchPlugin. The workbench plugin is
+     * effectively the "application" for the workbench UI. The entire UI
+     * operates as a good plugin citizen.
+     */
+    public WorkbenchPlugin() {
+        super();
+        inst = this;
+    }
+
+    /**
+     * Unload all members.  This can be used to run a second instance of a workbench.
+     * @since 3.0
+     */
+    void reset() {
+        editorRegistry = null;
+
+        if (decoratorManager != null) {
+			decoratorManager.shutdown();
+            decoratorManager = null;
+        }
+
+        ProgressManager.shutdownProgressManager();
+
+        themeRegistry = null;
+        if (workingSetManager != null) {
+        	workingSetManager.dispose();
+        	workingSetManager = null;
+        }
+        workingSetRegistry = null;
+
+        preferenceManager = null;
+//        if (viewRegistry != null) {
+//			// nothing to dispose for viewRegistry
+//            viewRegistry = null;
+//        }
+//        if (perspRegistry != null) {
+//            perspRegistry.dispose();
+//            perspRegistry = null;
+//        }
+        ((PerspectiveRegistry) this.e4Context.get(IPerspectiveRegistry.class.getName())).dispose();
+        actionSetRegistry = null;
+        sharedImages = null;
+
+        productInfo = null;
+        introRegistry = null;
+
+		helpService = null;
+		commandHelpService = null;
+
+        if (operationSupport != null) {
+        	operationSupport.dispose();
+        	operationSupport = null;
+        }
+
+        DEBUG = false;
+
+    }
+
+    /**
+     * Creates an extension.  If the extension plugin has not
+     * been loaded a busy cursor will be activated during the duration of
+     * the load.
+     *
+     * @param element the config element defining the extension
+     * @param classAttribute the name of the attribute carrying the class
+     * @return the extension object
+     * @throws CoreException if the extension cannot be created
+     */
+    public static Object createExtension(final IConfigurationElement element,
+            final String classAttribute) throws CoreException {
+        try {
+            // If plugin has been loaded create extension.
+            // Otherwise, show busy cursor then create extension.
+			if (BundleUtility.isActivated(element.getContributor().getName())) {
+                return element.createExecutableExtension(classAttribute);
+            }
+            final Object[] ret = new Object[1];
+            final CoreException[] exc = new CoreException[1];
+            BusyIndicator.showWhile(null, () -> {
+			    try {
+			        ret[0] = element
+			                .createExecutableExtension(classAttribute);
+			    } catch (CoreException e) {
+			        exc[0] = e;
+			    }
+			});
+            if (exc[0] != null) {
+				throw exc[0];
+			}
+            return ret[0];
+
+        } catch (CoreException core) {
+            throw core;
+        } catch (Exception e) {
+            throw new CoreException(new Status(IStatus.ERROR, PI_WORKBENCH,
+                    IStatus.ERROR, WorkbenchMessages.get().WorkbenchPlugin_extension,e));
+        }
+    }
+
+    /**
+	 * Answers whether the provided element either has an attribute with the
+	 * given name or a child element with the given name with an attribute
+	 * called class.
+	 *
+	 * @param element
+	 *            the element to test
+	 * @param extensionName
+	 *            the name of the extension to test for
+	 * @return whether or not the extension is declared
+	 * @since 3.3
+	 */
+	public static boolean hasExecutableExtension(IConfigurationElement element,
+			String extensionName) {
+
+		if (element.getAttribute(extensionName) != null)
+			return true;
+		String elementText = element.getValue();
+		if (elementText != null && !elementText.equals("")) //$NON-NLS-1$
+			return true;
+		IConfigurationElement [] children = element.getChildren(extensionName);
+		if (children.length == 1) {
+			if (children[0].getAttribute(IWorkbenchRegistryConstants.ATT_CLASS) != null)
+				return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Checks to see if the provided element has the syntax for an executable
+	 * extension with a given name that resides in a bundle that is already
+	 * active. Determining the bundle happens in one of two ways:<br/>
+	 * <ul>
+	 * <li>The element has an attribute with the specified name or element text
+	 * in the form <code>bundle.id/class.name[:optional attributes]</code></li>
+	 * <li>The element has a child element with the specified name that has a
+	 * <code>plugin</code> attribute</li>
+	 * </ul>
+	 *
+	 * @param element
+	 *            the element to test
+	 * @param extensionName
+	 *            the name of the extension to test for
+	 * @return whether or not the bundle expressed by the above criteria is
+	 *         active. If the bundle cannot be determined then the state of the
+	 *         bundle that declared the element is returned.
+	 * @since 3.3
+	 */
+	public static boolean isBundleLoadedForExecutableExtension(
+			IConfigurationElement element, String extensionName) {
+		Bundle bundle = getBundleForExecutableExtension(element, extensionName);
+
+		if (bundle == null)
+			return true;
+		return bundle.getState() == Bundle.ACTIVE;
+	}
+
+	/**
+	 * Returns the bundle that contains the class referenced by an executable
+	 * extension. Determining the bundle happens in one of two ways:<br/>
+	 * <ul>
+	 * <li>The element has an attribute with the specified name or element text
+	 * in the form <code>bundle.id/class.name[:optional attributes]</code></li>
+	 * <li>The element has a child element with the specified name that has a
+	 * <code>plugin</code> attribute</li>
+	 * </ul>
+	 *
+	 * @param element
+	 *            the element to test
+	 * @param extensionName
+	 *            the name of the extension to test for
+	 * @return the bundle referenced by the extension. If that bundle cannot be
+	 *         determined the bundle that declared the element is returned. Note
+	 *         that this may be <code>null</code>.
+	 * @since 3.3
+	 */
+	public static Bundle getBundleForExecutableExtension(IConfigurationElement element, String extensionName) {
+		// this code is derived heavily from
+		// ConfigurationElement.createExecutableExtension.
+		String prop = null;
+		String executable;
+		String contributorName = null;
+		int i;
+
+		if (extensionName != null)
+			prop = element.getAttribute(extensionName);
+		else {
+			// property not specified, try as element value
+			prop = element.getValue();
+			if (prop != null) {
+				prop = prop.trim();
+				if (prop.equals("")) //$NON-NLS-1$
+					prop = null;
+			}
+		}
+
+		if (prop == null) {
+			// property not defined, try as a child element
+			IConfigurationElement[] exec = element.getChildren(extensionName);
+			if (exec.length != 0)
+				contributorName = exec[0].getAttribute("plugin"); //$NON-NLS-1$
+		} else {
+			// simple property or element value, parse it into its components
+			i = prop.indexOf(':');
+			if (i != -1)
+				executable = prop.substring(0, i).trim();
+			else
+				executable = prop;
+
+			i = executable.indexOf('/');
+			if (i != -1)
+				contributorName = executable.substring(0, i).trim();
+
+		}
+
+		if (contributorName == null)
+			contributorName = element.getContributor().getName();
+
+		return Platform.getBundle(contributorName);
+	}
+
+    /**
+	 * Returns the image registry for this plugin.
+	 *
+	 * Where are the images? The images (typically gifs) are found in the same
+	 * plugins directory.
+	 *
+	 * @see ImageRegistry
+	 *
+	 * Note: The workbench uses the standard JFace ImageRegistry to track its
+	 * images. In addition the class WorkbenchGraphicResources provides
+	 * convenience access to the graphics resources and fast field access for
+	 * some of the commonly used graphical images.
+	 */
+    @Override
+	protected ImageRegistry createImageRegistry() {
+        return WorkbenchImages.getImageRegistry();
+    }
+
+    /**
+     * Returns the action set registry for the workbench.
+     *
+     * @return the workbench action set registry
+     */
+    public ActionSetRegistry getActionSetRegistry() {
+		return e4Context.get(ActionSetRegistry.class);
+    }
+
+    /**
+     * Return the default instance of the receiver. This represents the runtime plugin.
+     * @return WorkbenchPlugin
+     * @see AbstractUIPlugin for the typical implementation pattern for plugin classes.
+     */
+    public static WorkbenchPlugin getDefault() {
+        return inst;
+    }
+
+    /**
+     * Answer the manager that maps resource types to a the
+     * description of the editor to use
+     * @return IEditorRegistry the editor registry used
+     * by this plug-in.
+     */
+
+    public IEditorRegistry getEditorRegistry() {
+		return e4Context.get(IEditorRegistry.class);
+    }
+
+    /**
+     * Answer the element factory for an id, or <code>null</code. if not found.
+     * @param targetID
+     * @return IElementFactory
+     */
+    public IElementFactory getElementFactory(String targetID) {
+
+        // Get the extension point registry.
+        IExtensionPoint extensionPoint;
+        extensionPoint = Platform.getExtensionRegistry().getExtensionPoint(
+                PlatformUI.PLUGIN_EXTENSION_NAME_SPACE, IWorkbenchRegistryConstants.PL_ELEMENT_FACTORY);
+
+        if (extensionPoint == null) {
+            WorkbenchPlugin
+                    .log("Unable to find element factory. Extension point: " + IWorkbenchRegistryConstants.PL_ELEMENT_FACTORY + " not found"); //$NON-NLS-2$ //$NON-NLS-1$
+            return null;
+        }
+
+        // Loop through the config elements.
+        IConfigurationElement targetElement = null;
+        IConfigurationElement[] configElements = extensionPoint
+                .getConfigurationElements();
+        for (IConfigurationElement configElement : configElements) {
+            String strID = configElement.getAttribute("id"); //$NON-NLS-1$
+            if (targetID.equals(strID)) {
+                targetElement = configElement;
+                break;
+            }
+        }
+        if (targetElement == null) {
+            // log it since we cannot safely display a dialog.
+            WorkbenchPlugin.log("Unable to find element factory: " + targetID); //$NON-NLS-1$
+            return null;
+        }
+
+        // Create the extension.
+        IElementFactory factory = null;
+        try {
+            factory = (IElementFactory) createExtension(targetElement, "class"); //$NON-NLS-1$
+        } catch (CoreException e) {
+            // log it since we cannot safely display a dialog.
+            WorkbenchPlugin.log(
+                    "Unable to create element factory.", e.getStatus()); //$NON-NLS-1$
+            factory = null;
+        }
+        return factory;
+    }
+
+    /**
+     * Return the perspective registry.
+     * @return IPerspectiveRegistry. The registry for the receiver.
+     */
+    public IPerspectiveRegistry getPerspectiveRegistry() {
+		return e4Context.get(IPerspectiveRegistry.class);
+    }
+
+    /**
+     * Returns the working set manager
+     *
+     * @return the working set manager
+     * @since 2.0
+     */
+    public IWorkingSetManager getWorkingSetManager() {
+		return e4Context.get(IWorkingSetManager.class);
+    }
+
+    /**
+     * Returns the working set registry
+     *
+     * @return the working set registry
+     * @since 2.0
+     */
+    public WorkingSetRegistry getWorkingSetRegistry() {
+		return e4Context.get(WorkingSetRegistry.class);
+    }
+
+    /**
+     * Returns the introduction registry.
+     *
+     * @return the introduction registry.
+     * @since 3.0
+     */
+    public IIntroRegistry getIntroRegistry() {
+		return e4Context.get(IIntroRegistry.class);
+    }
+
+    /**
+	 * Returns the operation support.
+	 *
+	 * @return the workbench operation support.
+	 * @since 3.1
+	 */
+    public IWorkbenchOperationSupport getOperationSupport() {
+		IWorkbenchOperationSupport op = e4Context.get(IWorkbenchOperationSupport.class);
+		if (op == null) {
+			// we're in shutdown, but some plugins get this in their stop()
+			// methods. In 3.x we just return a bogus one, so here it is
+			op = new WorkbenchOperationSupport();
+		}
+		return op;
+    }
+
+
+    /**
+     * Get the preference manager.
+     * @return PreferenceManager the preference manager for
+     * the receiver.
+     */
+    public PreferenceManager getPreferenceManager() {
+		return e4Context.get(PreferenceManager.class);
+    }
+
+    /**
+     * Returns the shared images for the workbench.
+     *
+     * @return the shared image manager
+     */
+    public ISharedImages getSharedImages() {
+    	if(sharedImages == null) {
+    		sharedImages = new SharedImages();
+    	}
+    	if(e4Context == null) {
+    		return sharedImages;
+    	}
+		return e4Context.get(ISharedImages.class);
+    }
+
+    /**
+     * Returns the theme registry for the workbench.
+     *
+     * @return the theme registry
+     */
+    public IThemeRegistry getThemeRegistry() {
+		return e4Context.get(IThemeRegistry.class);
+    }
+
+    /**
+     * Answer the view registry.
+     * @return IViewRegistry the view registry for the
+     * receiver.
+     */
+    public IViewRegistry getViewRegistry() {
+		return e4Context.get(IViewRegistry.class);
+    }
+
+    /**
+     * Answer the workbench.
+     * @deprecated Use <code>PlatformUI.getWorkbench()</code> instead.
+     */
+    @Deprecated
+	@Override
+	public IWorkbench getWorkbench() {
+        return PlatformUI.getWorkbench();
+    }
+
+    /**
+     * Set default preference values.
+     * This method must be called whenever the preference store is initially loaded
+     * because the default values are not stored in the preference store.
+     */
+    @Override
+	protected void initializeDefaultPreferences(IPreferenceStore store) {
+        // Do nothing.  This should not be called.
+        // Prefs are initialized in WorkbenchPreferenceInitializer.
+    }
+
+    /**
+     * Logs the given message to the platform log.
+     *
+     * If you have an exception in hand, call log(String, Throwable) instead.
+     *
+     * If you have a status object in hand call log(String, IStatus) instead.
+     *
+     * This convenience method is for internal use by the Workbench only and
+     * must not be called outside the Workbench.
+     *
+     * @param message
+     *            A high level UI message describing when the problem happened.
+     */
+    public static void log(String message) {
+        getDefault().getLog().log(
+                StatusUtil.newStatus(IStatus.ERROR, message, null));
+    }
+
+    /**
+     * Log the throwable.
+     * @param t
+     */
+    public static void log(Throwable t) {
+		getDefault().getLog().log(getStatus(t));
+	}
+
+	/**
+	 * Return the status from throwable
+	 * @param t throwable
+	 * @return IStatus
+	 */
+	public static IStatus getStatus(Throwable t) {
+		String message = StatusUtil.getLocalizedMessage(t);
+
+		return newError(message, t);
+	}
+
+	/**
+	 * Create a new error from the message and the
+	 * throwable.
+	 * @param message
+	 * @param t
+	 * @return IStatus
+	 */
+	public static IStatus newError(String message, Throwable t) {
+		String pluginId = "org.eclipse.ui.workbench"; //$NON-NLS-1$
+		int errorCode = IStatus.OK;
+
+		// If this was a CoreException, keep the original plugin ID and error
+		// code
+		if (t instanceof CoreException) {
+			CoreException ce = (CoreException) t;
+			pluginId = ce.getStatus().getPlugin();
+			errorCode = ce.getStatus().getCode();
+		}
+
+		return new Status(IStatus.ERROR, pluginId, errorCode, message,
+				StatusUtil.getCause(t));
+	}
+
+    /**
+	 * Logs the given message and throwable to the platform log.
+	 *
+	 * If you have a status object in hand call log(String, IStatus) instead.
+	 *
+	 * This convenience method is for internal use by the Workbench only and
+	 * must not be called outside the Workbench.
+	 *
+	 * @param message
+	 *            A high level UI message describing when the problem happened.
+	 * @param t
+	 *            The throwable from where the problem actually occurred.
+	 */
+    public static void log(String message, Throwable t) {
+        IStatus status = StatusUtil.newStatus(IStatus.ERROR, message, t);
+        log(message, status);
+    }
+
+    /**
+     * Logs the given throwable to the platform log, indicating the class and
+     * method from where it is being logged (this is not necessarily where it
+     * occurred).
+     *
+     * This convenience method is for internal use by the Workbench only and
+     * must not be called outside the Workbench.
+     *
+     * @param clazz
+     *            The calling class.
+     * @param methodName
+     *            The calling method name.
+     * @param t
+     *            The throwable from where the problem actually occurred.
+     */
+    public static void log(Class clazz, String methodName, Throwable t) {
+        String msg = MessageFormat.format("Exception in {0}.{1}: {2}", //$NON-NLS-1$
+				clazz.getName(), methodName, t);
+        log(msg, t);
+    }
+
+    /**
+     * Logs the given message and status to the platform log.
+     *
+     * This convenience method is for internal use by the Workbench only and
+     * must not be called outside the Workbench.
+     *
+     * @param message
+     *            A high level UI message describing when the problem happened.
+     *            May be <code>null</code>.
+     * @param status
+     *            The status describing the problem. Must not be null.
+     */
+    public static void log(String message, IStatus status) {
+
+        //1FTUHE0: ITPCORE:ALL - API - Status & logging - loss of semantic info
+
+		// Combine message and status into a MultiStatus to avoid losing
+		// context, but avoid creating the MultiStatus unnecessarily if message
+		// is the same
+		if (message != null && !message.equals(status.getMessage())) {
+			status = StatusUtil.newStatus(Collections.singletonList(status), message, null);
+        }
+		getDefault().getLog().log(status);
+    }
+
+    /**
+     * Log the status to the default log.
+     * @param status
+     */
+    public static void log(IStatus status) {
+        getDefault().getLog().log(status);
+    }
+
+    /**
+     * Get the decorator manager for the receiver
+     * @return DecoratorManager the decorator manager
+     * for the receiver.
+     */
+    public DecoratorManager getDecoratorManager() {
+		return (DecoratorManager) e4Context.get(IDecoratorManager.class);
+    }
+
+    @Override
+	public void start(BundleContext context) throws Exception {
+    	context.addBundleListener(getBundleListener());
+        super.start(context);
+        bundleContext = context;
+
+        JFaceUtil.initializeJFace();
+
+		parseBidiArguments();
+		Window.setDefaultOrientation(getDefaultOrientation());
+
+		// RAP [rh] regsister a multi-session-aware LocaleProvider
+        LocaleProvider localeProvider = new SessionLocaleProvider();
+        String localeProviderName = LocaleProvider.class.getName();
+        localeProviderService
+          = context.registerService( localeProviderName, localeProvider, new Hashtable() );
+
+        // RAP [fappel]: initialize session aware job management
+        JobManagerAdapter.getInstance();
+        
+        // RAP initialize RWT context and register RWT servlet
+        if( RWTProperties.getBooleanProperty( PROP_WORKBENCH_AUTOSTART, true ) ) {
+          httpServiceTracker = new HttpServiceTracker( context );
+          httpServiceTracker.open();
+        }
+		
+//        // The UI plugin needs to be initialized so that it can install the callback in PrefUtil,
+//        // which needs to be done as early as possible, before the workbench
+//        // accesses any API preferences.
+//        Bundle uiBundle = Platform.getBundle(PlatformUI.PLUGIN_ID);
+//        try {
+//            // Attempt to load the activator of the ui bundle.  This will force lazy start
+//            // of the ui bundle.  Using the bundle activator class here because it is a
+//            // class that needs to be loaded anyway so it should not cause extra classes
+//            // to be loaded.s
+//        	if(uiBundle != null)
+//        		uiBundle.start(Bundle.START_TRANSIENT);
+//        } catch (BundleException e) {
+//            WorkbenchPlugin.log("Unable to load UI activator", e); //$NON-NLS-1$
+//        }
+//		/*
+//		 * DO NOT RUN ANY OTHER CODE AFTER THIS LINE.  If you do, then you are
+//		 * likely to cause a deadlock in class loader code.  Please see Bug 86450
+//		 * for more information.
+//		 */
+
+    }
+
+	/**
+	 * Read the -bidi option from the command line arguments. The valid values /
+	 * syntax is as follows:
+	 *
+	 * <pre>
+	 * -bidi "on=[y/n];textDir=[ltr/rtl/auto]"
+	 * </pre>
+	 * <p>
+	 * Important:
+	 * <ul>
+	 * <li>The order of parameters under the <code>-bidi</code> switch is
+	 * arbitrary.</li>
+	 * <li>The presence of any parameter is not mandatory.</li>
+	 * <li>If any of the parameters is not specified, the default value is
+	 * assumed. Defaults:
+	 * <ul>
+	 * <li>on: n</li>
+	 * <li>textDir: no default value</li>
+	 * </ul>
+	 * </li>
+	 * <li>If no value (or an illegal value) is provided for handling of base
+	 * text direction functionality, then bidi support is turned off and no
+	 * handling occurs.</li>
+	 * </ul>
+	 */
+	private void parseBidiArguments() {
+		String[] commandLineArgs = Platform.getCommandLineArgs();
+		String bidiParams = null;
+		// Do not process the last one as it will never have a parameter
+		for (int i = 0; i < commandLineArgs.length - 1; i++) {
+			if (commandLineArgs[i].equals(BIDI_COMMAND_LINE)) {
+				bidiParams = commandLineArgs[i + 1];
+			}
+		}
+		//RAP
+//		if (bidiParams != null) {
+//			String[] bidiProps = bidiParams.split(";"); //$NON-NLS-1$
+//			for (String bidiProp : bidiProps) {
+//				int eqPos = bidiProp.indexOf("="); //$NON-NLS-1$
+//				if ((eqPos > 0) && (eqPos < bidiProp.length() - 1)) {
+//					String nameProp = bidiProp.substring(0, eqPos);
+//					String valProp = bidiProp.substring(eqPos + 1);
+//					if (nameProp.equals(BIDI_SUPPORT_OPTION)) {
+//						BidiUtils.setBidiSupport("y".equals(valProp)); //$NON-NLS-1$
+//					} else if (nameProp.equalsIgnoreCase(BIDI_TEXTDIR_OPTION)) {
+//						try {
+//							BidiUtils.setTextDirection(valProp.intern());
+//						} catch (IllegalArgumentException e) {
+//							WorkbenchPlugin.log(e);
+//						}
+//					}
+//				}
+//			}
+//		}
+	}
+
+	/**
+	 * Get the default orientation from the command line arguments. If there are
+	 * no arguments imply the orientation.
+	 *
+	 * @return int
+	 * @see SWT#NONE
+	 * @see SWT#RIGHT_TO_LEFT
+	 * @see SWT#LEFT_TO_RIGHT
+	 */
+    private int getDefaultOrientation() {
+
+		String[] commandLineArgs = Platform.getCommandLineArgs();
+
+		int orientation = getCommandLineOrientation(commandLineArgs);
+
+		if(orientation != SWT.NONE) {
+			return orientation;
+		}
+
+		orientation = getSystemPropertyOrientation();
+
+		if(orientation != SWT.NONE) {
+			return orientation;
+		}
+
+		return checkCommandLineLocale(); //Use the default value if there is nothing specified
+	}
+
+	/**
+	 * Check whether the workbench messages are in a Bidi language. This method
+	 * will return <code>null</code> if it is unable to determine message
+	 * properties.
+	 */
+	private Boolean isBidiMessageText() {
+		// Check if the user installed the NLS packs for bidi
+		String message = WorkbenchMessages.get().Startup_Loading_Workbench;
+		if (message == null)
+			return null;
+
+		try {
+			// use qualified class name to avoid import statement
+			// and premature attempt to resolve class reference
+			boolean isBidi = com.ibm.icu.text.Bidi.requiresBidi(message.toCharArray(), 0,
+					message.length());
+			return Boolean.valueOf(isBidi);
+		} catch (NoClassDefFoundError e) {
+			// the ICU Base bundle used in place of ICU?
+			return null;
+		}
+	}
+
+	/**
+	 * Check to see if the command line parameter for -nl
+	 * has been set. If so imply the orientation from this
+	 * specified Locale. If it is a bidirectional Locale
+	 * return SWT#RIGHT_TO_LEFT.
+	 * If it has not been set or has been set to
+	 * a unidirectional Locale then return SWT#NONE.
+	 *
+	 * Locale is determined differently by different JDKs
+	 * and may not be consistent with the users expectations.
+	 *
+
+	 * @return int
+	 * @see SWT#NONE
+	 * @see SWT#RIGHT_TO_LEFT
+	 */
+	private int checkCommandLineLocale() {
+		// Check if the user property is set. If not, do not rely on the VM.
+		if (System.getProperty(NL_USER_PROPERTY) == null) {
+			Boolean needRTL = isBidiMessageText();
+//			if (needRTL != null && needRTL.booleanValue())
+//				return SWT.RIGHT_TO_LEFT;
+		} else {
+			String lang = Locale.getDefault().getLanguage();
+			boolean bidiLangauage = "iw".equals(lang) || "he".equals(lang) || "ar".equals(lang) || //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+					"fa".equals(lang) || "ur".equals(lang); //$NON-NLS-1$ //$NON-NLS-2$
+			if (bidiLangauage) {
+				Boolean needRTL = isBidiMessageText();
+//				if (needRTL == null)
+//					return SWT.RIGHT_TO_LEFT;
+//				if (needRTL.booleanValue())
+//					return SWT.RIGHT_TO_LEFT;
+			}
+		}
+		return SWT.NONE;
+	}
+
+	/**
+	 * Check to see if the orientation was set in the
+	 * system properties. If there is no orientation
+	 * specified return SWT#NONE.
+	 * @return int
+	 * @see SWT#NONE
+	 * @see SWT#RIGHT_TO_LEFT
+	 * @see SWT#LEFT_TO_RIGHT
+	 */
+	private int getSystemPropertyOrientation() {
+		String orientation = System.getProperty(ORIENTATION_PROPERTY);
+//		if(RIGHT_TO_LEFT.equals(orientation)) {
+//			return SWT.RIGHT_TO_LEFT;
+//		}
+		if(LEFT_TO_RIGHT.equals(orientation)) {
+			return SWT.LEFT_TO_RIGHT;
+		}
+		return SWT.NONE;
+	}
+
+	/**
+	 * Find the orientation in the commandLineArgs. If there
+	 * is no orientation specified return SWT#NONE.
+	 * @param commandLineArgs
+	 * @return int
+	 * @see SWT#NONE
+	 * @see SWT#RIGHT_TO_LEFT
+	 * @see SWT#LEFT_TO_RIGHT
+	 */
+	private int getCommandLineOrientation(String[] commandLineArgs) {
+		//Do not process the last one as it will never have a parameter
+		for (int i = 0; i < commandLineArgs.length - 1; i++) {
+			if(commandLineArgs[i].equalsIgnoreCase(ORIENTATION_COMMAND_LINE)){
+				String orientation = commandLineArgs[i+1];
+//				if(orientation.equals(RIGHT_TO_LEFT)){
+//					System.setProperty(ORIENTATION_PROPERTY,RIGHT_TO_LEFT);
+//					return SWT.RIGHT_TO_LEFT;
+//				}
+				if(orientation.equals(LEFT_TO_RIGHT)){
+					System.setProperty(ORIENTATION_PROPERTY,LEFT_TO_RIGHT);
+					return SWT.LEFT_TO_RIGHT;
+				}
+			}
+		}
+
+		return SWT.NONE;
+	}
+
+	/**
+     * Return an array of all bundles contained in this workbench.
+     *
+     * @return an array of bundles in the workbench or an empty array if none
+     * @since 3.0
+     */
+    public Bundle[] getBundles() {
+        return bundleContext == null ? new Bundle[0] : bundleContext
+                .getBundles();
+    }
+
+    /**
+     * Returns the bundle context associated with the workbench plug-in.
+     *
+     * @return the bundle context
+     * @since 3.1
+     */
+    public BundleContext getBundleContext() {
+    	return bundleContext;
+    }
+
+    /**
+     * Returns the application name.
+     * <p>
+     * Note this is never shown to the user.
+     * It is used to initialize the SWT Display.
+     * On Motif, for example, this can be used
+     * to set the name used for resource lookup.
+     * </p>
+     *
+     * @return the application name, or <code>null</code>
+     * @see org.eclipse.swt.widgets.Display#setAppName
+     * @since 3.0
+     */
+    public String getAppName() {
+        return getProductInfo().getAppName();
+    }
+
+    /**
+     * Returns the name of the product.
+     *
+     * @return the product name, or <code>null</code> if none
+     * @since 3.0
+     */
+    public String getProductName() {
+        return getProductInfo().getProductName();
+    }
+
+    /**
+     * Returns the image descriptors for the window image to use for this product.
+     *
+     * @return an array of the image descriptors for the window image, or
+     *         <code>null</code> if none
+     * @since 3.0
+     */
+    public ImageDescriptor[] getWindowImages() {
+        return getProductInfo().getWindowImages();
+    }
+
+    /**
+     * Returns an instance that describes this plugin's product (formerly "primary
+     * plugin").
+     * @return ProductInfo the product info for the receiver
+     */
+    private ProductInfo getProductInfo() {
+        if (productInfo == null) {
+			productInfo = new ProductInfo(Platform.getProduct());
+		}
+        return productInfo;
+    }
+
+    @Override
+	public void stop(BundleContext context) throws Exception {
+    	if (bundleListener!=null) {
+    		context.removeBundleListener(bundleListener);
+    		bundleListener = null;
+    	}
+		if (debugTracker != null) {
+			debugTracker.close();
+			debugTracker = null;
+		}
+		if (testableTracker != null) {
+			testableTracker.close();
+			testableTracker = null;
+		}
+        super.stop(context);
+    }
+
+    /**
+     * Return the new wizard registry.
+     *
+     * @return the new wizard registry
+     * @since 3.1
+     */
+    public IWizardRegistry getNewWizardRegistry() {
+		return e4Context.get(NewWizardRegistry.class);
+    }
+
+    /**
+     * Return the import wizard registry.
+     *
+     * @return the import wizard registry
+     * @since 3.1
+     */
+    public IWizardRegistry getImportWizardRegistry() {
+		return e4Context.get(ImportWizardRegistry.class);
+    }
+
+    /**
+     * Return the export wizard registry.
+     *
+     * @return the export wizard registry
+     * @since 3.1
+     */
+    public IWizardRegistry getExportWizardRegistry() {
+		return e4Context.get(ExportWizardRegistry.class);
+    }
+
+    /**
+     * FOR INTERNAL WORKBENCH USE ONLY.
+     *
+     * Returns the path to a location in the file system that can be used
+     * to persist/restore state between workbench invocations.
+     * If the location did not exist prior to this call it will  be created.
+     * Returns <code>null</code> if no such location is available.
+     *
+     * @return path to a location in the file system where this plug-in can
+     * persist data between sessions, or <code>null</code> if no such
+     * location is available.
+     * @since 3.1
+     */
+    public IPath getDataLocation() {
+        try {
+            return getStateLocation();
+        } catch (IllegalStateException e) {
+            // This occurs if -data=@none is explicitly specified, so ignore this silently.
+            // Is this OK? See bug 85071.
+            return null;
+        }
+    }
+
+	/* package */ void addBundleListener(BundleListener bundleListener) {
+		bundleContext.addBundleListener(bundleListener);
+	}
+
+	/* package */ void removeBundleListener(BundleListener bundleListener) {
+		bundleContext.removeBundleListener(bundleListener);
+	}
+
+	/* package */ int getBundleCount() {
+		return bundleContext.getBundles().length;
+	}
+
+	/**
+	 * @return the bundle listener for this plug-in
+	 */
+	private BundleListener getBundleListener() {
+		if (bundleListener == null) {
+			bundleListener = event -> WorkbenchPlugin.this.bundleChanged(event);
+		}
+		return bundleListener;
+	}
+
+	private void bundleChanged(BundleEvent event) {
+		int eventType = event.getType();
+		// a bundle in the STARTING state generates 2 events, LAZY_ACTIVATION
+		// when it enters STARTING and STARTING when it exists STARTING :-)
+		synchronized (startingBundles) {
+			switch (eventType) {
+				case BundleEvent.STARTING :
+					startingBundles.add(event.getBundle());
+					break;
+				case BundleEvent.STARTED :
+				case BundleEvent.STOPPED :
+					startingBundles.remove(event.getBundle());
+					break;
+				default :
+					break;
+			}
+		}
+	}
+
+	public boolean isStarting(Bundle bundle) {
+		synchronized (startingBundles) {
+			return startingBundles.contains(bundle);
+		}
+	}
+
+	/**
+	 * Return whether or not the OSGi framework has specified the handle of a splash shell.
+	 *
+	 * @return whether or not the OSGi framework has specified the handle of a splash shell
+	 * @since 3.4
+	 */
+	public static boolean isSplashHandleSpecified() {
+		return System.getProperty(PROP_SPLASH_HANDLE) != null;
+	}
+
+	/**
+	 * Get the splash shell for this workbench instance, if any. This will find
+	 * the splash created by the launcher (native) code and wrap it in a SWT
+	 * shell. This may have the side effect of setting data on the provided
+	 * {@link Display}.
+	 *
+	 * @param display
+	 *            the display to parent the shell on
+	 *
+	 * @return the splash shell or <code>null</code>
+	 * @throws InvocationTargetException
+	 * @throws IllegalAccessException
+	 * @throws IllegalArgumentException
+	 * @throws NumberFormatException
+	 * @see Display#setData(String, Object)
+	 * @since 3.4
+	 */
+	public static Shell getSplashShell(Display display)
+			throws NumberFormatException, IllegalArgumentException,
+			IllegalAccessException, InvocationTargetException {
+		Shell splashShell = (Shell) display.getData(DATA_SPLASH_SHELL);
+		if (splashShell != null)
+			return splashShell;
+
+		String splashHandle = System.getProperty(PROP_SPLASH_HANDLE);
+		if (splashHandle == null) {
+			return null;
+		}
+
+		// look for the 32 bit internal_new shell method
+		try {
+			Method method = Shell.class.getMethod(
+					"internal_new", new Class[] { Display.class, int.class }); //$NON-NLS-1$
+			// we're on a 32 bit platform so invoke it with splash
+			// handle as an int
+			splashShell = (Shell) method.invoke(null, new Object[] { display,
+					Integer.valueOf(splashHandle) });
+		} catch (NoSuchMethodException e) {
+			// look for the 64 bit internal_new shell method
+			try {
+				Method method = Shell.class
+						.getMethod(
+								"internal_new", new Class[] { Display.class, long.class }); //$NON-NLS-1$
+
+				// we're on a 64 bit platform so invoke it with a long
+				splashShell = (Shell) method.invoke(null, new Object[] {
+						display, new Long(splashHandle) });
+			} catch (NoSuchMethodException e2) {
+				// cant find either method - don't do anything.
+			}
+		}
+
+		display.setData(DATA_SPLASH_SHELL, splashShell);
+		return splashShell;
+	}
+
+	/**
+	 * Removes any splash shell data set on the provided display and disposes
+	 * the shell if necessary.
+	 *
+	 * @param display
+	 *            the display to parent the shell on
+	 * @since 3.4
+	 */
+	public static void unsetSplashShell(Display display) {
+		Shell splashShell = (Shell) display.getData(DATA_SPLASH_SHELL);
+		if (splashShell != null) {
+			if (!splashShell.isDisposed())
+				splashShell.dispose();
+			display.setData(DATA_SPLASH_SHELL, null);
+		}
+
+	}
+
+	/**
+	 * Initialized the workbench plug-in with the e4 context
+	 * @param context the e4 context
+	 */
+	public void initializeContext(IEclipseContext context) {
+		e4Context = context;
+		e4Context.set(IPerspectiveRegistry.class.getName(), new ContextFunction() {
+
+		    private PerspectiveRegistry perspRegistry;
+            
+            @Override
+            public Object compute(IEclipseContext context, String contextKey) {
+                if (this.perspRegistry == null) {
+                    this.perspRegistry = ContextInjectionFactory.make(
+                            PerspectiveRegistry.class, e4Context);
+                }
+                return this.perspRegistry;
+            }
+		});
+		e4Context.set(IViewRegistry.class.getName(), new ContextFunction() {
+
+		    private ViewRegistry vr;
+            
+            @Override
+            public Object compute(IEclipseContext context, String contextKey) {
+                if (this.vr == null) {
+                    this.vr = ContextInjectionFactory.make(ViewRegistry.class,
+                            e4Context);
+                }
+                
+                return this.vr;
+            }
+		});
+		e4Context.set(ActionSetRegistry.class.getName(), new ContextFunction() {
+			@Override
+			public Object compute(IEclipseContext context, String contextKey) {
+				if (actionSetRegistry == null) {
+					actionSetRegistry = new ActionSetRegistry();
+				}
+				return actionSetRegistry;
+			}
+		});
+		context.set(IDecoratorManager.class.getName(), new ContextFunction() {
+			@Override
+			public Object compute(IEclipseContext context, String contextKey) {
+				if (decoratorManager == null) {
+					decoratorManager = new DecoratorManager();
+				}
+				return decoratorManager;
+			}
+		});
+		context.set(ExportWizardRegistry.class.getName(), new ContextFunction() {
+			@Override
+			public Object compute(IEclipseContext context, String contextKey) {
+				return ExportWizardRegistry.getInstance();
+			}
+		});
+		context.set(ImportWizardRegistry.class.getName(), new ContextFunction() {
+			@Override
+			public Object compute(IEclipseContext context, String contextKey) {
+				return ImportWizardRegistry.getInstance();
+			}
+		});
+		context.set(IIntroRegistry.class.getName(), new ContextFunction() {
+			@Override
+			public Object compute(IEclipseContext context, String contextKey) {
+				if (introRegistry == null) {
+					introRegistry = new IntroRegistry();
+				}
+				return introRegistry;
+			}
+		});
+		context.set(NewWizardRegistry.class.getName(), new ContextFunction() {
+			@Override
+			public Object compute(IEclipseContext context, String contextKey) {
+				return NewWizardRegistry.getInstance();
+			}
+		});
+		context.set(IWorkbenchOperationSupport.class.getName(), new ContextFunction() {
+			@Override
+			public Object compute(IEclipseContext context, String contextKey) {
+				if (operationSupport == null) {
+					operationSupport = new WorkbenchOperationSupport();
+				}
+				return operationSupport;
+			}
+		});
+		context.set(PreferenceManager.class.getName(), new ContextFunction() {
+			@Override
+			public Object compute(IEclipseContext context, String contextKey) {
+				if (preferenceManager == null) {
+					preferenceManager = new WorkbenchPreferenceManager(
+							PREFERENCE_PAGE_CATEGORY_SEPARATOR);
+
+					// Get the pages from the registry
+					PreferencePageRegistryReader registryReader = new PreferencePageRegistryReader(
+							getWorkbench());
+					registryReader.loadFromRegistry(Platform.getExtensionRegistry());
+					preferenceManager.addPages(registryReader.getTopLevelNodes());
+
+				}
+				return preferenceManager;
+			}
+		});
+		context.set(ISharedImages.class.getName(), new ContextFunction() {
+			@Override
+			public Object compute(IEclipseContext context, String contextKey) {
+				if (sharedImages == null) {
+					sharedImages = new SharedImages();
+				}
+				return sharedImages;
+			}
+		});
+
+		context.set(IThemeRegistry.class.getName(), new ContextFunction() {
+			@Override
+			public Object compute(IEclipseContext context, String contextKey) {
+				if (themeRegistry == null) {
+					themeRegistry = new ThemeRegistry();
+					ThemeRegistryReader reader = new ThemeRegistryReader();
+					reader.readThemes(Platform.getExtensionRegistry(), themeRegistry);
+				}
+				return themeRegistry;
+			}
+		});
+		context.set(IWorkingSetManager.class.getName(), new ContextFunction() {
+			@Override
+			public Object compute(IEclipseContext context, String contextKey) {
+				if (workingSetManager == null) {
+					workingSetManager = new WorkingSetManager(bundleContext);
+					workingSetManager.restoreState();
+				}
+				return workingSetManager;
+			}
+		});
+		context.set(WorkingSetRegistry.class.getName(), new ContextFunction() {
+			@Override
+			public Object compute(IEclipseContext context, String contextKey) {
+				if (workingSetRegistry == null) {
+					workingSetRegistry = new WorkingSetRegistry();
+					workingSetRegistry.load();
+				}
+				return workingSetRegistry;
+			}
+		});
+		context.set(IEditorRegistry.class.getName(), new ContextFunction() {
+			@Override
+			public Object compute(IEclipseContext context, String contextKey) {
+				if (editorRegistry == null) {
+					editorRegistry = new EditorRegistry();
+				}
+				return editorRegistry;
+			}
+		});
+		context.set(EHelpService.class.getName(), new ContextFunction() {
+			@Override
+			public Object compute(IEclipseContext context, String contextKey) {
+				if (helpService == null) {
+					helpService = new HelpServiceImpl();
+				}
+				return helpService;
+			}
+		});
+		context.set(ICommandHelpService.class.getName(), new ContextFunction() {
+			@Override
+			public Object compute(IEclipseContext context, String contextKey) {
+				if (commandHelpService == null) {
+					commandHelpService = ContextInjectionFactory.make(CommandHelpServiceImpl.class,
+							e4Context);
+				}
+				return commandHelpService;
+			}
+		});
+	}
+
+	/*
+	 * Return the debug options service, if available.
+	 */
+	public DebugOptions getDebugOptions() {
+		if (bundleContext == null)
+			return null;
+		if (debugTracker == null) {
+			debugTracker = new ServiceTracker(bundleContext, DebugOptions.class.getName(), null);
+			debugTracker.open();
+		}
+		return (DebugOptions) debugTracker.getService();
+	}
+
+
+	/**
+	 * Returns a {@link TestableObject} provided by a TestableObject
+	 * service or <code>null</code> if a service implementation cannot
+	 * be found.  The TestableObject is used to hook tests into the
+	 * application lifecycle.
+	 * <p>
+	 * It is recommended the testable object is obtained via service
+	 * over {@link Workbench#getWorkbenchTestable()} to avoid the
+	 * tests having a dependency on the Workbench.
+	 * </p>
+	 * @see PlatformUI#getTestableObject()
+	 * @return TestableObject provided via service or <code>null</code>
+	 */
+	public TestableObject getTestableObject() {
+		if (bundleContext == null)
+			return null;
+		if (testableTracker == null) {
+			testableTracker = new ServiceTracker(bundleContext, TestableObject.class.getName(), null);
+			testableTracker.open();
+		}
+		return (TestableObject) testableTracker.getService();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchPreferenceInitializer.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchPreferenceInitializer.java
new file mode 100644
index 0000000..519727a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchPreferenceInitializer.java
@@ -0,0 +1,142 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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
+ *     Semion Chichelnitsky (semion@il.ibm.com) - bug 278064
+ *     Tristan Hume - <trishume@gmail.com> -
+ *     		Fix for Bug 2369 [Workbench] Would like to be able to save workspace without exiting
+ *     		Implemented workbench auto-save to correctly restore state in case of crash.
+ *     Denis Zygann <d.zygann@web.de> - Bug 330453
+ *     Axel Richard <axel.richard@obeo.fr> - Bug 486644
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 146205
+ *******************************************************************************/
+package org.eclipse.ui.internal;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
+import org.eclipse.core.runtime.preferences.DefaultScope;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.IScopeContext;
+import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.jface.util.OpenStrategy;
+import org.eclipse.swt.SWT;
+import org.eclipse.ui.IWorkbenchPreferenceConstants;
+import org.osgi.service.prefs.BackingStoreException;
+
+/**
+ * Implementation of the workbench plugin's preferences extension's
+ * customization element. This is needed in order to force the workbench
+ * plugin's preferences to be initialized properly when running without
+ * org.eclipse.core.runtime.compatibility. For more details, see bug 58975 - New
+ * preference mechanism does not properly initialize defaults.
+ *
+ * @since 3.0
+ */
+public class WorkbenchPreferenceInitializer extends AbstractPreferenceInitializer {
+
+
+
+	@Override
+	public void initializeDefaultPreferences() {
+		IScopeContext context = DefaultScope.INSTANCE;
+		IEclipsePreferences node = context.getNode(WorkbenchPlugin
+				.getDefault().getBundle().getSymbolicName());
+
+		node.putBoolean(IPreferenceConstants.RUN_IN_BACKGROUND, true);
+		node.putBoolean(IPreferenceConstants.SHOULD_PROMPT_FOR_ENABLEMENT, true);
+
+		node.putBoolean(IPreferenceConstants.EDITORLIST_PULLDOWN_ACTIVE, false);
+		node.putBoolean(IPreferenceConstants.EDITORLIST_DISPLAY_FULL_NAME,
+				false);
+		node.putBoolean(IPreferenceConstants.STICKY_CYCLE, false);
+		node.putBoolean(IPreferenceConstants.REUSE_EDITORS_BOOLEAN, false);
+		node.putInt(IPreferenceConstants.REUSE_EDITORS, 8);
+		node.putBoolean(IPreferenceConstants.OPEN_ON_SINGLE_CLICK, false);
+		node.putBoolean(IPreferenceConstants.SELECT_ON_HOVER, false);
+		node.putBoolean(IPreferenceConstants.OPEN_AFTER_DELAY, false);
+		node.putInt(IPreferenceConstants.RECENT_FILES, 4);
+
+		// FIXME this does not actually set the default since it is the wrong
+		// node. It works because the default-default is false.
+		node.putBoolean(IWorkbenchPreferenceConstants.DISABLE_OPEN_EDITOR_IN_PLACE, false);
+
+		// 5 minute workbench save interval
+		node.putInt(IPreferenceConstants.WORKBENCH_SAVE_INTERVAL, 5);
+
+		node.putBoolean(IPreferenceConstants.USE_IPERSISTABLE_EDITORS, true);
+
+		node.putBoolean(IPreferenceConstants.COOLBAR_VISIBLE, true);
+		node.putBoolean(IPreferenceConstants.PERSPECTIVEBAR_VISIBLE, true);
+
+		node.putInt(IPreferenceConstants.EDITOR_TAB_WIDTH, 3); // high
+		node.putInt(IPreferenceConstants.OPEN_PERSP_MODE,
+				IPreferenceConstants.OPM_ACTIVE_PAGE);
+		node.put(IPreferenceConstants.ENABLED_DECORATORS, ""); //$NON-NLS-1$
+		node.putInt(IPreferenceConstants.EDITORLIST_SELECTION_SCOPE,
+				IPreferenceConstants.EDITORLIST_SET_PAGE_SCOPE); // Current
+																 // Window
+		node.putInt(IPreferenceConstants.EDITORLIST_SORT_CRITERIA,
+				IPreferenceConstants.EDITORLIST_NAME_SORT); // Name Sort
+		node.putBoolean(IPreferenceConstants.COLOR_ICONS, true);
+		node.putInt(IPreferenceConstants.KEYS_PREFERENCE_SELECTED_TAB, 0);
+		node.putBoolean(IPreferenceConstants.MULTI_KEY_ASSIST, true);
+		node.putInt(IPreferenceConstants.MULTI_KEY_ASSIST_TIME, 1000);
+
+		// Temporary option to enable wizard for project capability
+		node.putBoolean("ENABLE_CONFIGURABLE_PROJECT_WIZARD", false); //$NON-NLS-1$
+		// Temporary option to enable single click
+		node.putInt("SINGLE_CLICK_METHOD", OpenStrategy.DOUBLE_CLICK); //$NON-NLS-1$
+		// Temporary option to enable cool bars
+		node.putBoolean("ENABLE_COOL_BARS", true); //$NON-NLS-1$
+		// Temporary option to enable new menu organization
+		node.putBoolean("ENABLE_NEW_MENUS", true); //$NON-NLS-1$
+		//Temporary option to turn off the dialog font
+		node.putBoolean("DISABLE_DIALOG_FONT", false); //$NON-NLS-1$
+
+		// Heap status preferences
+		// FIXME this does not actually set the default since it is the wrong
+		// node. It works because the default-default is false.
+		node.putBoolean(IWorkbenchPreferenceConstants.SHOW_MEMORY_MONITOR, false);
+		node.putInt(IHeapStatusConstants.PREF_UPDATE_INTERVAL, 500);
+		node.putBoolean(IHeapStatusConstants.PREF_SHOW_MAX, false);
+		node.putBoolean(IPreferenceConstants.OVERRIDE_PRESENTATION, false);
+
+		// Globalization preferences
+		node.put(IPreferenceConstants.NL_EXTENSIONS, ""); //$NON-NLS-1$
+		node.putInt(IPreferenceConstants.LAYOUT_DIRECTION, SWT.NONE);
+		node.putBoolean(IPreferenceConstants.BIDI_SUPPORT, false);
+		node.put(IPreferenceConstants.TEXT_DIRECTION, ""); //$NON-NLS-1$
+
+		// Auto-save
+		node.putBoolean(IPreferenceConstants.SAVE_AUTOMATICALLY, false);
+		node.putInt(IPreferenceConstants.SAVE_AUTOMATICALLY_INTERVAL, 20);
+
+		IEclipsePreferences rootNode = (IEclipsePreferences) Platform
+				.getPreferencesService().getRootNode()
+				.node(InstanceScope.SCOPE);
+
+		final String workbenchName = WorkbenchPlugin.getDefault().getBundle()
+				.getSymbolicName();
+		try {
+			if (rootNode.nodeExists(workbenchName)) {
+				((IEclipsePreferences) rootNode.node(workbenchName))
+						.addPreferenceChangeListener(PlatformUIPreferenceListener
+								.getSingleton());
+			}
+		} catch (BackingStoreException e) {
+			IStatus status = new Status(IStatus.ERROR, WorkbenchPlugin
+					.getDefault().getBundle().getSymbolicName(), IStatus.ERROR,
+					e.getLocalizedMessage(), e);
+			WorkbenchPlugin.getDefault().getLog().log(status);
+		}
+
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchSupportFactory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchSupportFactory.java
new file mode 100644
index 0000000..e344ee6
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchSupportFactory.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *******************************************************************************/
+
+package org.eclipse.ui.internal;
+
+import org.eclipse.ui.IPageService;
+import org.eclipse.ui.IPartService;
+import org.eclipse.ui.ISelectionService;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.internal.services.IWorkbenchLocationService;
+import org.eclipse.ui.progress.IProgressService;
+import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
+import org.eclipse.ui.services.AbstractServiceFactory;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * Create singleton services to make the Workbench singletons available. This is
+ * a "hack" to provide access to the Workbench singletons.
+ *
+ * @since 3.4
+ */
+public class WorkbenchSupportFactory extends AbstractServiceFactory {
+
+	@Override
+	public Object create(Class serviceInterface, IServiceLocator parentLocator,
+			IServiceLocator locator) {
+
+		IWorkbenchLocationService wls = locator
+				.getService(IWorkbenchLocationService.class);
+		final IWorkbench wb = wls.getWorkbench();
+		if (wb == null) {
+			return null;
+		}
+		final IWorkbenchWindow window = wls.getWorkbenchWindow();
+		final IWorkbenchPartSite site = wls.getPartSite();
+		Object parent = parentLocator.getService(serviceInterface);
+
+		if (parent == null) {
+			// return top level services
+			if (IProgressService.class.equals(serviceInterface)) {
+				return wb.getProgressService();
+			}
+			if (IWorkbenchSiteProgressService.class.equals(serviceInterface)) {
+				if (site instanceof PartSite) {
+					return ((PartSite) site).getSiteProgressService();
+				}
+			}
+			if (IPartService.class.equals(serviceInterface)) {
+				if (window != null) {
+					return window.getPartService();
+				}
+			}
+			if (IPageService.class.equals(serviceInterface)) {
+				if (window != null) {
+					return window;
+				}
+			}
+			if (ISelectionService.class.equals(serviceInterface)) {
+				if (window != null) {
+					return window.getSelectionService();
+				}
+			}
+			return null;
+		}
+
+		if (ISelectionService.class.equals(serviceInterface)) {
+			if (parent instanceof WindowSelectionService && window != null
+					&& window.getActivePage() != null) {
+				return new SlaveSelectionService(window.getActivePage());
+			}
+			return new SlaveSelectionService((ISelectionService) parent);
+		}
+
+		if (IProgressService.class.equals(serviceInterface)) {
+			if (site instanceof PartSite) {
+				return ((PartSite) site).getSiteProgressService();
+			}
+		}
+		if (IPartService.class.equals(serviceInterface)) {
+			return new SlavePartService((IPartService) parent);
+		}
+		if (IPageService.class.equals(serviceInterface)) {
+			return new SlavePageService((IPageService) parent);
+		}
+
+		return null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchWindow.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchWindow.java
new file mode 100644
index 0000000..07d5541
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchWindow.java
@@ -0,0 +1,3015 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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
+ *     Zhongwei Zhao - Bug 379495 - Two "Run" on top menu
+ *     Patrick Chuong - Bug 391481 - Contributing perspectiveExtension, hiddenMenuItem
+ *     								 removes a menu from multiple perspectives
+ *     René Brandstetter - Bug 411821 - [QuickAccess] Contribute SearchField
+ *                                      through a fragment or other means
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 431446, 433979, 440810, 441184, 472654, 486632
+ *     Denis Zygann <d.zygann@web.de> - Bug 457390
+ *     Andrey Loskutov <loskutov@gmx.de> - Bug 372799
+ *     Axel Richard <axel.richard@obeo.fr> - Bug 354538
+ *******************************************************************************/
+
+package org.eclipse.ui.internal;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.ExpressionInfo;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
+import org.eclipse.e4.core.commands.internal.HandlerServiceImpl;
+import org.eclipse.e4.core.contexts.ContextFunction;
+import org.eclipse.e4.core.contexts.ContextInjectionFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.contexts.RunAndTrack;
+import org.eclipse.e4.core.di.InjectionException;
+import org.eclipse.e4.core.di.annotations.Optional;
+import org.eclipse.e4.core.services.events.IEventBroker;
+import org.eclipse.e4.core.services.log.Logger;
+import org.eclipse.e4.ui.di.UIEventTopic;
+import org.eclipse.e4.ui.internal.workbench.E4Workbench;
+import org.eclipse.e4.ui.internal.workbench.OpaqueElementUtil;
+import org.eclipse.e4.ui.internal.workbench.PartServiceSaveHandler;
+import org.eclipse.e4.ui.internal.workbench.URIHelper;
+import org.eclipse.e4.ui.internal.workbench.renderers.swt.IUpdateService;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.ui.MElementContainer;
+import org.eclipse.e4.ui.model.application.ui.MUIElement;
+import org.eclipse.e4.ui.model.application.ui.SideValue;
+import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective;
+import org.eclipse.e4.ui.model.application.ui.advanced.MPerspectiveStack;
+import org.eclipse.e4.ui.model.application.ui.advanced.MPlaceholder;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.model.application.ui.basic.MTrimBar;
+import org.eclipse.e4.ui.model.application.ui.basic.MTrimElement;
+import org.eclipse.e4.ui.model.application.ui.basic.MTrimmedWindow;
+import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
+import org.eclipse.e4.ui.model.application.ui.menu.MMenu;
+import org.eclipse.e4.ui.model.application.ui.menu.MMenuItem;
+import org.eclipse.e4.ui.model.application.ui.menu.MMenuSeparator;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolControl;
+import org.eclipse.e4.ui.model.internal.Position;
+import org.eclipse.e4.ui.model.internal.PositionInfo;
+import org.eclipse.e4.ui.services.EContextService;
+import org.eclipse.e4.ui.workbench.IPresentationEngine;
+import org.eclipse.e4.ui.workbench.UIEvents;
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+import org.eclipse.e4.ui.workbench.modeling.EPartService;
+import org.eclipse.e4.ui.workbench.modeling.ISaveHandler;
+import org.eclipse.e4.ui.workbench.modeling.IWindowCloseHandler;
+import org.eclipse.e4.ui.workbench.renderers.swt.MenuManagerRenderer;
+import org.eclipse.e4.ui.workbench.renderers.swt.MenuManagerRendererFilter;
+import org.eclipse.e4.ui.workbench.renderers.swt.ToolBarManagerRenderer;
+import org.eclipse.e4.ui.workbench.renderers.swt.TrimBarLayout;
+import org.eclipse.e4.ui.workbench.renderers.swt.TrimmedPartLayout;
+import org.eclipse.e4.ui.workbench.swt.factories.IRendererFactory;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.jface.action.AbstractGroupMarker;
+import org.eclipse.jface.action.CoolBarManager;
+import org.eclipse.jface.action.GroupMarker;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.IContributionManagerOverrides;
+import org.eclipse.jface.action.ICoolBarManager;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.StatusLineManager;
+import org.eclipse.jface.action.SubContributionItem;
+import org.eclipse.jface.commands.ActionHandler;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.internal.provisional.action.CoolBarManager2;
+import org.eclipse.jface.internal.provisional.action.ICoolBarManager2;
+import org.eclipse.jface.internal.provisional.action.IToolBarManager2;
+import org.eclipse.jface.internal.provisional.action.ToolBarManager2;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.operation.ModalContext;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.jface.util.SafeRunnable;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.osgi.util.TextProcessor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.swt.events.ShellAdapter;
+import org.eclipse.swt.events.ShellEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Layout;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.ActiveShellExpression;
+import org.eclipse.ui.IPageListener;
+import org.eclipse.ui.IPageService;
+import org.eclipse.ui.IPartService;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.IPerspectiveRegistry;
+import org.eclipse.ui.ISaveablePart;
+import org.eclipse.ui.ISaveablesLifecycleListener;
+import org.eclipse.ui.ISelectionService;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchActionConstants;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartReference;
+import org.eclipse.ui.IWorkbenchPreferenceConstants;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.WorkbenchException;
+import org.eclipse.ui.application.ActionBarAdvisor;
+import org.eclipse.ui.application.WorkbenchAdvisor;
+import org.eclipse.ui.application.WorkbenchWindowAdvisor;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.contexts.IContextService;
+import org.eclipse.ui.dialogs.ListSelectionDialog;
+import org.eclipse.ui.handlers.IHandlerActivation;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.internal.StartupThreading.StartupRunnable;
+import org.eclipse.ui.internal.actions.CommandAction;
+import org.eclipse.ui.internal.commands.SlaveCommandService;
+import org.eclipse.ui.internal.contexts.ContextService;
+import org.eclipse.ui.internal.dialogs.cpd.CustomizePerspectiveDialog;
+import org.eclipse.ui.internal.e4.compatibility.CompatibilityPart;
+import org.eclipse.ui.internal.e4.compatibility.ModeledPageLayout;
+import org.eclipse.ui.internal.e4.compatibility.SelectionService;
+import org.eclipse.ui.internal.handlers.ActionCommandMappingService;
+import org.eclipse.ui.internal.handlers.IActionCommandMappingService;
+import org.eclipse.ui.internal.handlers.LegacyHandlerService;
+import org.eclipse.ui.internal.menus.ActionSet;
+import org.eclipse.ui.internal.menus.IActionSetsListener;
+import org.eclipse.ui.internal.menus.LegacyActionPersistence;
+import org.eclipse.ui.internal.menus.MenuHelper;
+import org.eclipse.ui.internal.menus.SlaveMenuService;
+import org.eclipse.ui.internal.misc.UIListenerLogging;
+import org.eclipse.ui.internal.progress.ProgressRegion;
+import org.eclipse.ui.internal.provisional.application.IActionBarConfigurer2;
+import org.eclipse.ui.internal.registry.IActionSetDescriptor;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.registry.UIExtensionTracker;
+import org.eclipse.ui.internal.services.EvaluationReference;
+import org.eclipse.ui.internal.services.IServiceLocatorCreator;
+import org.eclipse.ui.internal.services.IWorkbenchLocationService;
+import org.eclipse.ui.internal.services.ServiceLocator;
+import org.eclipse.ui.internal.services.WorkbenchLocationService;
+import org.eclipse.ui.internal.util.PrefUtil;
+import org.eclipse.ui.keys.IBindingService;
+import org.eclipse.ui.menus.CommandContributionItem;
+import org.eclipse.ui.menus.IMenuService;
+import org.eclipse.ui.services.IDisposable;
+import org.eclipse.ui.services.IEvaluationService;
+import org.eclipse.ui.services.IServiceScopes;
+import org.eclipse.ui.views.IViewDescriptor;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventHandler;
+/**
+ * A window within the workbench.
+ */
+public class WorkbenchWindow implements IWorkbenchWindow {
+
+	/**
+	 * The 'elementId' of the spacer used to right-align it in the trim
+	 */
+	public static final String PERSPECTIVE_SPACER_ID = "PerspectiveSpacer"; //$NON-NLS-1$
+
+	public static final String STATUS_LINE_ID = "org.eclipse.ui.StatusLine"; //$NON-NLS-1$
+
+	public static final String TRIM_CONTRIBUTION_URI = "bundleclass://org.eclipse.rap.ui.workbench/org.eclipse.ui.internal.StandardTrim"; //$NON-NLS-1$
+
+	private static final String MAIN_TOOLBAR_ID = ActionSet.MAIN_TOOLBAR;
+	private static final String COMMAND_ID_TOGGLE_COOLBAR = "org.eclipse.ui.ToggleCoolbarAction"; //$NON-NLS-1$
+
+	public static final String ACTION_SET_CMD_PREFIX = "AS::"; //$NON-NLS-1$
+
+	private static final String PERSISTED_STATE_RESTORED = "isRestored"; //$NON-NLS-1$
+
+	@Inject
+	private IWorkbench workbench;
+	@Inject
+	private MTrimmedWindow model;
+	@Inject
+	private IPresentationEngine engine;
+
+	@Inject
+	private IRendererFactory rendererFactory;
+
+	@Inject
+	private MApplication application;
+
+	@Inject
+	EModelService modelService;
+
+	@Inject
+	private IEventBroker eventBroker;
+
+	@Inject
+	@Optional
+	private Logger logger;
+
+	@Inject
+	private IExtensionRegistry extensionRegistry;
+
+	private WorkbenchPage page;
+
+	private WorkbenchWindowAdvisor windowAdvisor;
+
+	private ActionBarAdvisor actionBarAdvisor;
+
+	private MenuManagerRenderer renderer;
+
+	private MMenu mainMenu;
+
+	private PageListenerList pageListeners = new PageListenerList();
+
+	private PerspectiveListenerList perspectiveListeners = new PerspectiveListenerList();
+
+	private PartService partService = new WWinPartService();
+
+	private WWinActionBars actionBars;
+
+	private boolean updateDisabled = false;
+
+	private boolean closing = false;
+
+	private boolean shellActivated = false;
+
+	ProgressRegion progressRegion = null;
+
+	private List<MTrimElement> workbenchTrimElements = new ArrayList<>();
+
+	private Map<MToolControl, IConfigurationElement> iceMap = new HashMap<>();
+
+	public IConfigurationElement getICEFor(MToolControl mtc) {
+		return iceMap.get(mtc);
+	}
+
+	/**
+	 * The map of services maintained by the workbench window. These services
+	 * are initialized when the workbench window is being constructed by
+	 * dependency injection.
+	 */
+	private ServiceLocator serviceLocator;
+
+	/**
+	 * Bit flags indication which submenus (New, Show Views, ...) this window
+	 * contains. Initially none.
+	 *
+	 * @since 3.0
+	 */
+	private int submenus = 0x00;
+
+	/**
+	 * Object for configuring this workbench window. Lazily initialized to an
+	 * instance unique to this window.
+	 *
+	 * @since 3.0
+	 */
+	private WorkbenchWindowConfigurer windowConfigurer = null;
+
+	/**
+	 * List of generic property listeners.
+	 *
+	 * @since 3.3
+	 */
+	private ListenerList<IPropertyChangeListener> genericPropertyListeners = new ListenerList<>();
+
+	private IAdaptable input;
+
+	private IPerspectiveDescriptor perspective;
+
+	private EventHandler windowWidgetHandler = new EventHandler() {
+		@Override
+		public void handleEvent(Event event) {
+			if (event.getProperty(UIEvents.EventTags.ELEMENT) == model
+					&& event.getProperty(UIEvents.EventTags.NEW_VALUE) == null) {
+				// HandledContributionItem.toolItemUpdater.removeWindowRunnable(menuUpdater);
+				manageChanges = false;
+				canUpdateMenus = false;
+				menuUpdater = null;
+
+				MMenu menu = model.getMainMenu();
+				if (menu != null) {
+					engine.removeGui(menu);
+					model.setMainMenu(null);
+				}
+
+				eventBroker.unsubscribe(windowWidgetHandler);
+			}
+		}
+	};
+
+	static final String TEXT_DELIMITERS = TextProcessor.getDefaultDelimiters() + "-"; //$NON-NLS-1$
+
+	// constants for shortcut bar group ids
+	static final String GRP_PAGES = "pages"; //$NON-NLS-1$
+
+	static final String GRP_PERSPECTIVES = "perspectives"; //$NON-NLS-1$
+
+	static final String GRP_FAST_VIEWS = "fastViews"; //$NON-NLS-1$
+
+	// static fields for inner classes.
+	static final int VGAP = 0;
+
+	static final int CLIENT_INSET = 3;
+
+	static final int BAR_SIZE = 23;
+
+	/** Marks the beginning of a tag which contains positioning information. */
+	static final String MOVE_TAG = "move_"; //$NON-NLS-1$
+
+	/**
+	 * Ordered list of element IDs which belong to the QuickAccess
+	 * {@link MToolControl}s.
+	 *
+	 * <p>
+	 * Element IDs which belong to QuickAccess:
+	 * <ul>
+	 * <li><code>Spacer Glue</code></li>
+	 * <li><code>SearchField</code></li>
+	 * <li><code>Search-PS Glue</code></li>
+	 * </ul>
+	 * </p>
+	 */
+	private static final List<String> QUICK_ACCESS_ELEMENT_IDS = Collections
+			.unmodifiableList(Arrays.asList("Spacer Glue", "SearchField", "Search-PS Glue")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+	/**
+	 * Coolbar visibility change property.
+	 *
+	 * @since 3.3
+	 */
+	public static final String PROP_COOLBAR_VISIBLE = "coolbarVisible"; //$NON-NLS-1$
+
+	/**
+	 * Perspective bar visibility change property.
+	 *
+	 * @since 3.3
+	 */
+	public static final String PROP_PERSPECTIVEBAR_VISIBLE = "perspectiveBarVisible"; //$NON-NLS-1$
+
+	/**
+	 * The status line visibility change property. for internal use only.
+	 *
+	 * @since 3.4
+	 */
+	public static final String PROP_STATUS_LINE_VISIBLE = "statusLineVisible"; //$NON-NLS-1$
+
+	/**
+	 * Constant (bit mask) indicating which the Show View submenu is probably
+	 * present somewhere in this window.
+	 *
+	 * @see #addSubmenu
+	 * @since 3.0
+	 */
+	public static final int SHOW_VIEW_SUBMENU = 0x01;
+
+	/**
+	 * Constant (bit mask) indicating which the Open Perspective submenu is
+	 * probably present somewhere in this window.
+	 *
+	 * @see #addSubmenu
+	 * @since 3.0
+	 */
+	public static final int OPEN_PERSPECTIVE_SUBMENU = 0x02;
+
+	/**
+	 * Constant (bit mask) indicating which the New Wizard submenu is probably
+	 * present somewhere in this window.
+	 *
+	 * @see #addSubmenu
+	 * @since 3.0
+	 */
+	public static final int NEW_WIZARD_SUBMENU = 0x04;
+
+	/**
+	 * Remembers that this window contains the given submenu.
+	 *
+	 * @param type
+	 *            the type of submenu, one of: {@link #NEW_WIZARD_SUBMENU
+	 *            NEW_WIZARD_SUBMENU}, {@link #OPEN_PERSPECTIVE_SUBMENU
+	 *            OPEN_PERSPECTIVE_SUBMENU}, {@link #SHOW_VIEW_SUBMENU
+	 *            SHOW_VIEW_SUBMENU}
+	 * @see #containsSubmenu
+	 * @since 3.0
+	 */
+	public void addSubmenu(int type) {
+		submenus |= type;
+	}
+
+	/**
+	 * Checks to see if this window contains the given type of submenu.
+	 *
+	 * @param type
+	 *            the type of submenu, one of: {@link #NEW_WIZARD_SUBMENU
+	 *            NEW_WIZARD_SUBMENU}, {@link #OPEN_PERSPECTIVE_SUBMENU
+	 *            OPEN_PERSPECTIVE_SUBMENU}, {@link #SHOW_VIEW_SUBMENU
+	 *            SHOW_VIEW_SUBMENU}
+	 * @return <code>true</code> if window contains submenu, <code>false</code>
+	 *         otherwise
+	 * @see #addSubmenu
+	 * @since 3.0
+	 */
+	public boolean containsSubmenu(int type) {
+		return ((submenus & type) != 0);
+	}
+
+	/**
+	 * Constant indicating that all the actions bars should be filled.
+	 *
+	 * @since 3.0
+	 */
+	private static final int FILL_ALL_ACTION_BARS = ActionBarAdvisor.FILL_MENU_BAR
+			| ActionBarAdvisor.FILL_COOL_BAR | ActionBarAdvisor.FILL_STATUS_LINE;
+
+	/**
+	 * Creates and initializes a new workbench window.
+	 *
+	 * @param input
+	 *            the input for this workbench window
+	 * @param pers
+	 *            the perspective to initialize this workbench window with
+	 */
+	public WorkbenchWindow(IAdaptable input, IPerspectiveDescriptor pers) {
+		this.input = input;
+		perspective = pers;
+	}
+
+	@PostConstruct
+	public void setup() {
+		try {
+			// if workbench window is opened as a result of command execution,
+			// the context in which the new workbench window's commands are
+			// initialized has to to match the workbench context
+			final IEclipseContext windowContext = model.getContext();
+			HandlerServiceImpl.push(windowContext.getParent(), null);
+
+			// Initialize a previous 'saved' state if applicable. We no longer
+			// update the preference store.
+			if (getModel().getPersistedState().containsKey(IPreferenceConstants.COOLBAR_VISIBLE)) {
+				this.coolBarVisible = Boolean.parseBoolean(getModel().getPersistedState().get(
+						IPreferenceConstants.COOLBAR_VISIBLE));
+			} else {
+				this.coolBarVisible = PrefUtil.getInternalPreferenceStore().getBoolean(
+						IPreferenceConstants.COOLBAR_VISIBLE);
+				getModel().getPersistedState().put(IPreferenceConstants.COOLBAR_VISIBLE,
+						Boolean.toString(this.coolBarVisible));
+			}
+			if (getModel().getPersistedState().containsKey(
+					IPreferenceConstants.PERSPECTIVEBAR_VISIBLE)) {
+				this.perspectiveBarVisible = Boolean.parseBoolean(getModel().getPersistedState()
+						.get(IPreferenceConstants.PERSPECTIVEBAR_VISIBLE));
+			} else {
+				this.perspectiveBarVisible = PrefUtil.getInternalPreferenceStore().getBoolean(
+						IPreferenceConstants.PERSPECTIVEBAR_VISIBLE);
+				getModel().getPersistedState().put(IPreferenceConstants.PERSPECTIVEBAR_VISIBLE,
+						Boolean.toString(this.perspectiveBarVisible));
+			}
+
+			IServiceLocatorCreator slc = workbench
+					.getService(IServiceLocatorCreator.class);
+			this.serviceLocator = (ServiceLocator) slc.createServiceLocator(workbench, null,
+					new IDisposable() {
+						@Override
+						public void dispose() {
+							final Shell shell = getShell();
+							if (shell != null && !shell.isDisposed()) {
+								close();
+							}
+						}
+					}, windowContext);
+
+			windowContext.set(IExtensionTracker.class.getName(), new ContextFunction() {
+				@Override
+				public Object compute(IEclipseContext context, String contextKey) {
+					if (tracker == null) {
+						tracker = new UIExtensionTracker(getWorkbench().getDisplay());
+					}
+					return tracker;
+				}
+			});
+
+			windowContext.set(IWindowCloseHandler.class.getName(), new IWindowCloseHandler() {
+				@Override
+				public boolean close(MWindow window) {
+					return getWindowAdvisor().preWindowShellClose() && WorkbenchWindow.this.close();
+				}
+			});
+
+			final ISaveHandler defaultSaveHandler = windowContext.get(ISaveHandler.class);
+			final PartServiceSaveHandler localSaveHandler = new PartServiceSaveHandler() {
+				@Override
+				public Save promptToSave(MPart dirtyPart) {
+					Object object = dirtyPart.getObject();
+					if (object instanceof CompatibilityPart) {
+						IWorkbenchPart part = ((CompatibilityPart) object).getPart();
+						ISaveablePart saveable = SaveableHelper.getSaveable(part);
+						if (saveable != null) {
+							if (!saveable.isSaveOnCloseNeeded()) {
+								return Save.NO;
+							}
+							return SaveableHelper.savePart(saveable, part,
+									WorkbenchWindow.this, true) ? Save.NO : Save.CANCEL;
+						}
+					}
+					return defaultSaveHandler.promptToSave(dirtyPart);
+				}
+
+				@Override
+				public Save[] promptToSave(Collection<MPart> dirtyParts) {
+					LabelProvider labelProvider = new LabelProvider() {
+						@Override
+						public String getText(Object element) {
+							return ((MPart) element).getLocalizedLabel();
+						}
+					};
+					List<MPart> parts = new ArrayList<>(dirtyParts);
+					ListSelectionDialog dialog = new ListSelectionDialog(getShell(), parts,
+							ArrayContentProvider.getInstance(), labelProvider,
+							WorkbenchMessages.get().EditorManager_saveResourcesMessage);
+					dialog.setInitialSelections(parts.toArray());
+					dialog.setTitle(WorkbenchMessages.get().EditorManager_saveResourcesTitle);
+					if (dialog.open() == IDialogConstants.CANCEL_ID) {
+						return new Save[] { Save.CANCEL };
+					}
+
+					Object[] toSave = dialog.getResult();
+					Save[] retSaves = new Save[parts.size()];
+					Arrays.fill(retSaves, Save.NO);
+					for (int i = 0; i < retSaves.length; i++) {
+						MPart part = parts.get(i);
+						for (Object o : toSave) {
+							if (o == part) {
+								retSaves[i] = Save.YES;
+								break;
+							}
+						}
+					}
+					return retSaves;
+				}
+
+				@Override
+				public boolean save(MPart dirtyPart, boolean confirm) {
+					Object object = dirtyPart.getObject();
+					if (object instanceof CompatibilityPart) {
+						IWorkbenchPart workbenchPart = ((CompatibilityPart) object).getPart();
+						if (SaveableHelper.isSaveable(workbenchPart)) {
+							SaveablesList saveablesList = (SaveablesList) PlatformUI.getWorkbench()
+									.getService(ISaveablesLifecycleListener.class);
+							Object saveResult = saveablesList.preCloseParts(
+									Collections.singletonList(workbenchPart), true,
+									WorkbenchWindow.this);
+							return saveResult != null;
+						}
+					}
+					return super.save(dirtyPart, confirm);
+				}
+
+				@Override
+				public boolean saveParts(Collection<MPart> dirtyParts, boolean confirm) {
+					ArrayList<IWorkbenchPart> saveableParts = new ArrayList<>();
+					for (MPart part : dirtyParts) {
+						Object object = part.getObject();
+						if (object instanceof CompatibilityPart) {
+							IWorkbenchPart workbenchPart = ((CompatibilityPart) object).getPart();
+							if (SaveableHelper.isSaveable(workbenchPart)) {
+								saveableParts.add(workbenchPart);
+							}
+						}
+					}
+					if (saveableParts.isEmpty()) {
+						return super.saveParts(dirtyParts, confirm);
+					}
+
+					SaveablesList saveablesList = (SaveablesList) PlatformUI.getWorkbench()
+							.getService(ISaveablesLifecycleListener.class);
+					Object saveResult = saveablesList.preCloseParts(saveableParts, true,
+							WorkbenchWindow.this);
+					return saveResult != null;
+				}
+			};
+			localSaveHandler.logger = logger;
+			windowContext.set(ISaveHandler.class, localSaveHandler);
+
+			windowContext.set(IWorkbenchWindow.class.getName(), this);
+			windowContext.set(IPageService.class, this);
+			windowContext.set(IPartService.class, partService);
+
+			windowContext.set(ISources.ACTIVE_WORKBENCH_WINDOW_NAME, this);
+			windowContext.set(ISources.ACTIVE_WORKBENCH_WINDOW_SHELL_NAME, getShell());
+			EContextService cs = (EContextService) windowContext.get(EContextService.class
+					.getName());
+			cs.activateContext(IContextService.CONTEXT_ID_WINDOW);
+			cs.getActiveContextIds();
+
+			initializeDefaultServices();
+
+			/*
+			 * Remove the second QuickAccess control if an older workspace is
+			 * opened.
+			 *
+			 * An older workspace will create an ApplicationModel which already
+			 * contains the QuickAccess elements, from the old
+			 * "popuolateTopTrimContribution()" method. The new implementation
+			 * of this method doesn't add the QuickAccess elements anymore but
+			 * an old workbench.xmi still has these entries in it and so they
+			 * need to be removed.
+			 */
+			cleanLegacyQuickAccessContribution();
+
+			// register with the tracker
+
+			fireWindowOpening();
+			configureShell(getShell(), windowContext);
+
+			try {
+				page = new WorkbenchPage(this, input);
+			} catch (WorkbenchException e) {
+				WorkbenchPlugin.log(e);
+			}
+
+			ContextInjectionFactory.inject(page, model.getContext());
+			windowContext.set(IWorkbenchPage.class, page);
+
+			menuManager.setOverrides(menuOverride);
+			((CoolBarToTrimManager) getCoolBarManager2()).setOverrides(toolbarOverride);
+
+			// Fill the action bars
+			fillActionBars(FILL_ALL_ACTION_BARS);
+			firePageOpened();
+
+			populateTopTrimContributions();
+			populateBottomTrimContributions();
+
+			// Trim gets populated during rendering (?) so make sure we have al/
+			// sides. See bug 383269 for details
+			modelService.getTrim(model, SideValue.LEFT);
+			modelService.getTrim(model, SideValue.RIGHT);
+
+			// move the QuickAccess ToolControl to the correct position (only if
+			// it exists)
+			positionQuickAccess();
+
+			Shell shell = (Shell) model.getWidget();
+			if (model.getMainMenu() == null) {
+				mainMenu = modelService.createModelElement(MMenu.class);
+				mainMenu.setElementId(ActionSet.MAIN_MENU);
+
+				renderer = (MenuManagerRenderer) rendererFactory
+						.getRenderer(mainMenu, null);
+				renderer.linkModelToManager(mainMenu, menuManager);
+				fill(renderer, mainMenu, menuManager);
+				model.setMainMenu(mainMenu);
+				final Menu menu = (Menu) engine.createGui(mainMenu, model.getWidget(),
+						model.getContext());
+				shell.setMenuBar(menu);
+
+				menuUpdater = new Runnable() {
+					@Override
+					public void run() {
+						try {
+							if (model.getMainMenu() == null || model.getWidget() == null
+									|| menu.isDisposed() || mainMenu.getWidget() == null) {
+								return;
+							}
+							MenuManagerRendererFilter.updateElementVisibility(mainMenu, renderer,
+									menuManager, windowContext.getActiveLeaf(), 1, false);
+							menuManager.update(true);
+						} finally {
+							canUpdateMenus = true;
+						}
+					}
+				};
+
+				RunAndTrack menuChangeManager = new RunAndTrack() {
+					@Override
+					public boolean changed(IEclipseContext context) {
+						ExpressionInfo info = new ExpressionInfo();
+						IEclipseContext leafContext = windowContext.getActiveLeaf();
+						MenuManagerRendererFilter.collectInfo(info, mainMenu, renderer,
+								leafContext, true);
+						// if one of these variables change, re-run the RAT
+						for (String name : info.getAccessedVariableNames()) {
+							leafContext.get(name);
+						}
+						if (canUpdateMenus && workbench.getDisplay() != null) {
+							canUpdateMenus = false;
+							workbench.getDisplay().asyncExec(menuUpdater);
+						}
+						return manageChanges;
+					}
+				};
+				windowContext.runAndTrack(menuChangeManager);
+			}
+
+			eventBroker.subscribe(UIEvents.UIElement.TOPIC_WIDGET, windowWidgetHandler);
+
+			boolean newWindow = setupPerspectiveStack(windowContext);
+			partService.setPage(page);
+			page.setPerspective(perspective);
+			firePageActivated();
+
+			if (newWindow) {
+				page.fireInitialPartVisibilityEvents();
+			} else {
+				page.updatePerspectiveActionSets();
+			}
+			updateActionSets();
+
+			IPreferenceStore preferenceStore = PrefUtil.getAPIPreferenceStore();
+			boolean enableAnimations = preferenceStore
+					.getBoolean(IWorkbenchPreferenceConstants.ENABLE_ANIMATIONS);
+			preferenceStore.setValue(IWorkbenchPreferenceConstants.ENABLE_ANIMATIONS, false);
+
+			// Hack!! don't show the intro if there's more than one open
+			// perspective
+			List<MPerspective> persps = modelService.findElements(model, null, MPerspective.class,
+					null);
+			if (persps.size() > 1) {
+				PrefUtil.getAPIPreferenceStore().setValue(IWorkbenchPreferenceConstants.SHOW_INTRO,
+						false);
+				PrefUtil.saveAPIPrefs();
+			}
+
+			if (Boolean.valueOf(getModel().getPersistedState().get(PERSISTED_STATE_RESTORED))) {
+				SafeRunnable.run(new SafeRunnable() {
+
+					@Override
+					public void run() throws Exception {
+						getWindowAdvisor().postWindowRestore();
+					}
+				});
+			} else {
+				getModel().getPersistedState().put(PERSISTED_STATE_RESTORED, Boolean.TRUE.toString());
+			}
+
+			getWindowAdvisor().postWindowCreate();
+			getWindowAdvisor().openIntro();
+
+			preferenceStore.setValue(IWorkbenchPreferenceConstants.ENABLE_ANIMATIONS,
+					enableAnimations);
+
+			getShell().setData(this);
+			trackShellActivation();
+		} finally {
+			HandlerServiceImpl.pop(model.getContext());
+		}
+	}
+
+	@PreDestroy
+	void preDestroy() {
+		if (mainMenu != null) {
+			renderer.clearModelToManager(mainMenu, menuManager);
+			mainMenu = null;
+		}
+		renderer = null;
+	}
+
+	private void configureShell(Shell shell, IEclipseContext context) {
+		String title = getWindowConfigurer().basicGetTitle();
+		if (title != null) {
+			shell.setText(TextProcessor.process(title, TEXT_DELIMITERS));
+		}
+		workbench.getHelpSystem().setHelp(shell, IWorkbenchHelpContextIds.WORKBENCH_WINDOW);
+
+		IContextService contextService = context.get(IContextService.class);
+		contextService.registerShell(shell, IContextService.TYPE_WINDOW);
+		if (model.getContext().get(E4Workbench.NO_SAVED_MODEL_FOUND) != null) {
+			Point initialSize = getWindowConfigurer().getInitialSize();
+			Rectangle bounds = shell.getBounds();
+			// actually set the shell size, so that setting the
+			// menuBar on the shell doesn't override the model changes.
+			bounds.width = initialSize.x;
+			bounds.height = initialSize.y;
+			shell.setBounds(bounds);
+		}
+	}
+
+	private boolean setupPerspectiveStack(IEclipseContext context) {
+		IPerspectiveRegistry registry = getWorkbench().getPerspectiveRegistry();
+		String forcedPerspectiveId = (String) context.get(E4Workbench.FORCED_PERSPECTIVE_ID);
+
+		if (forcedPerspectiveId != null) {
+			perspective = registry.findPerspectiveWithId(forcedPerspectiveId);
+		}
+
+		List<MPerspectiveStack> perspStackList = modelService.findElements(model, null,
+				MPerspectiveStack.class, null);
+		MPerspective selectedPersp = null;
+
+		if (!perspStackList.isEmpty()) {
+			selectedPersp = perspStackList.get(0).getSelectedElement();
+		}
+
+		if (forcedPerspectiveId == null && selectedPersp != null) {
+			perspective = registry.findPerspectiveWithId(selectedPersp.getElementId());
+		}
+
+		if (perspective == null) {
+			perspective = registry.findPerspectiveWithId(registry.getDefaultPerspective());
+		}
+
+		// the perspective stack doesn't have a selected element what means that
+		// we have a new window
+		return selectedPersp == null;
+	}
+
+	private boolean manageChanges = true;
+	private boolean canUpdateMenus = true;
+
+	void populateTopTrimContributions() {
+		getCoolBarManager2().update(true);
+		getCoolBarManager2().add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));
+
+		final MTrimBar trimBar = getTopTrim();
+		// TODO why aren't these added as trim contributions
+		// that would remove everything from this method except the fill(*)
+		/*
+		 * Reason Why: The setup() method which calls this method also calls the
+		 * ActionBarAdvisor to fill the TopTrim-Bar. Both this and the
+		 * ActionBarAdvisor fill method will be called after the entire
+		 * application model and all its fragments have been build already. This
+		 * leads to the effect that all the elements contributed via the
+		 * application model would be placed in front of the elements
+		 * contributed by the setup() method. (Means all the "Save", "Save All",
+		 * and so on, buttons which are normally placed at the beginning of the
+		 * trimbar (left) would be moved to the end of it (right).)
+		 */
+		MToolControl spacerControl = (MToolControl) modelService.find(PERSPECTIVE_SPACER_ID, model);
+		if (spacerControl == null) {
+			spacerControl = modelService.createModelElement(MToolControl.class);
+			spacerControl.setElementId(PERSPECTIVE_SPACER_ID);
+			spacerControl
+					.setContributionURI("bundleclass://org.eclipse.e4.ui.workbench.renderers.swt/org.eclipse.e4.ui.workbench.renderers.swt.LayoutModifierToolControl"); //$NON-NLS-1$
+			spacerControl.getTags().add(TrimBarLayout.SPACER);
+			spacerControl.getTags().add("SHOW_RESTORE_MENU"); //$NON-NLS-1$
+			trimBar.getChildren().add(spacerControl);
+		} else {
+			if (!spacerControl.getTags().contains("SHOW_RESTORE_MENU")) { //$NON-NLS-1$
+				spacerControl.getTags().add("SHOW_RESTORE_MENU"); //$NON-NLS-1$
+			}
+		}
+
+		MToolControl switcherControl = (MToolControl) modelService.find(
+				"PerspectiveSwitcher", model); //$NON-NLS-1$
+		if (switcherControl == null && getWindowConfigurer().getShowPerspectiveBar()) {
+			switcherControl = modelService.createModelElement(MToolControl.class);
+			switcherControl.setToBeRendered(getWindowConfigurer().getShowPerspectiveBar());
+			switcherControl.setElementId("PerspectiveSwitcher"); //$NON-NLS-1$
+			switcherControl.getTags().add(IPresentationEngine.DRAGGABLE);
+			switcherControl.getTags().add("HIDEABLE"); //$NON-NLS-1$
+			switcherControl.getTags().add("SHOW_RESTORE_MENU"); //$NON-NLS-1$
+			switcherControl
+					.setContributionURI("bundleclass://org.eclipse.rap.ui.workbench/org.eclipse.e4.ui.workbench.addons.perspectiveswitcher.PerspectiveSwitcher"); //$NON-NLS-1$
+			trimBar.getChildren().add(switcherControl);
+		} else if (switcherControl != null) {
+			if (!getWindowConfigurer().getShowPerspectiveBar()) {
+				trimBar.getChildren().remove(switcherControl);
+			} else {
+				List<String> tags = switcherControl.getTags();
+				if (!tags.contains("HIDEABLE")) { //$NON-NLS-1$
+					tags.add("HIDEABLE"); //$NON-NLS-1$
+				}
+				if (!tags.contains("SHOW_RESTORE_MENU")) { //$NON-NLS-1$
+					tags.add("SHOW_RESTORE_MENU"); //$NON-NLS-1$
+				}
+			}
+		}
+
+		// render now after everything has been added so contributions can be
+		// inserted in the right place
+		updateLayoutDataForContents();
+	}
+
+	/**
+	 * Removes the "legacy" QuickAccess related fields from the
+	 * ApplicationModel.
+	 * <p>
+	 * The "legacy" QuickAccess fields exist in the ApplicationModel if an older
+	 * workspace is opened which was build before the QuickAccess was
+	 * contributed via e4xmi-fragment.
+	 * </p>
+	 */
+	private void cleanLegacyQuickAccessContribution() {
+		for (String quickAccessElementId : QUICK_ACCESS_ELEMENT_IDS) {
+			MToolControl legacyElement = (MToolControl) modelService.find(quickAccessElementId,
+					model);
+			if (legacyElement != null) {
+				EcoreUtil.remove((EObject) legacyElement);
+			}
+		}
+	}
+
+	/**
+	 * Moves the QucickAccess related fields to the wanted position.
+	 * <p>
+	 * If the elements "Spacer Glue", "SearchField" and "Search-PS Glue" are
+	 * available in the model this method will move them to the correct place if
+	 * required. The movement can be influenced by a tag which begins with
+	 * {@value #MOVE_TAG} followed by the normal positioning information (e.g.:
+	 * move_after:PerspectiveSpacer). For more information about positioning
+	 * have a look at: {@link PositionInfo#parse(String)}.
+	 * </p>
+	 */
+	private void positionQuickAccess() {
+		/*
+		 * The QUICK_ACCESS_ELEMENT_IDS array contains the IDs of optional
+		 * elements provided via an e4xmi application model fragment. The method
+		 * checks if they should be moved to a special position. This behavior
+		 * is required because nearly all elements in the legacy workbench are
+		 * not provided via e4xmi application model. They are provided
+		 * programmatically after the e4xmi application model and the
+		 * corresponding fragment models are already processed.
+		 */
+		for (String quickAccessElementId : QUICK_ACCESS_ELEMENT_IDS) {
+			MToolControl quickAccessElement = (MToolControl) modelService.find(
+					quickAccessElementId, model);
+			if (quickAccessElement != null) {
+				moveControl(quickAccessElement.getParent(), quickAccessElement);
+
+				// target the quick access field specifically
+				if (QUICK_ACCESS_ID.equals(quickAccessElement.getElementId())) {
+					if (model.getTags().contains(QUICK_ACCESS_HIDDEN)) {
+						if (!quickAccessElement.getTags().contains(
+								IPresentationEngine.HIDDEN_EXPLICITLY)) {
+							quickAccessElement.getTags().add(IPresentationEngine.HIDDEN_EXPLICITLY);
+						}
+					}
+				}
+			}
+		}
+
+	}
+
+	private static final String QUICK_ACCESS_ID = "SearchField"; //$NON-NLS-1$
+	private static final String QUICK_ACCESS_HIDDEN = "QUICK_ACCESS_HIDDEN"; //$NON-NLS-1$
+
+	@Inject
+	private void hideQuickAccess(
+			@Optional @UIEventTopic(UIEvents.ApplicationElement.TOPIC_TAGS) Event event) {
+		if (event == null) {
+			return;
+		}
+		Object origin = event.getProperty(UIEvents.EventTags.ELEMENT);
+		if (!(origin instanceof MToolControl)) {
+			return;
+		}
+		MToolControl control = (MToolControl) origin;
+		if (!QUICK_ACCESS_ID.equals(control.getElementId())) {
+			return;
+		}
+		MWindow myWindow = modelService.getTopLevelWindowFor(control);
+		if (myWindow != model) {
+			return;
+		}
+		if (UIEvents.isADD(event)) {
+			if (UIEvents.contains(event, UIEvents.EventTags.NEW_VALUE,
+					IPresentationEngine.HIDDEN_EXPLICITLY)) {
+				if (!model.getTags().contains(QUICK_ACCESS_HIDDEN)) {
+					model.getTags().add(QUICK_ACCESS_HIDDEN);
+				}
+			}
+		} else if (UIEvents.isREMOVE(event)) {
+			if (UIEvents.contains(event, UIEvents.EventTags.OLD_VALUE,
+					IPresentationEngine.HIDDEN_EXPLICITLY)) {
+				model.getTags().remove(QUICK_ACCESS_HIDDEN);
+			}
+		}
+	}
+
+	/**
+	 * Moves the given element from its current position to the position
+	 * mentioned in one of its tags.
+	 *
+	 * @param elementContainer
+	 *            the list of elements in which the element should be moved
+	 * @param element
+	 *            the element to move
+	 */
+	private void moveControl(MElementContainer<MUIElement> elementContainer, MUIElement element) {
+		if (element == null || elementContainer == null)
+			return;
+
+		PositionInfo positionInfo = findMovePositionInfo(element);
+
+		// does the element has a tag with a "move_" position info
+		if (positionInfo != null) {
+			List<MUIElement> elements = elementContainer.getChildren();
+
+			if (elements.remove(element)) {
+				// reposition only if the element was in the list
+
+				switch (positionInfo.getPosition()) {
+				case LAST:
+					elements.add(element);
+					break;
+
+				case FIRST:
+					elements.add(0, element);
+					break;
+
+				case INDEX:
+					int index = positionInfo.getPositionReferenceAsInteger();
+					if (index >= 0 && index < elements.size()) {
+						elements.add(index, element);
+					} else {
+						elements.add(element);
+					}
+					break;
+
+				case BEFORE:
+				case AFTER:
+					int idx = indexOfElementWithID(elements, positionInfo.getPositionReference());
+					if (idx < 0) {
+						// element no found
+						elements.add(element);
+					} else {
+						if (positionInfo.getPosition() == Position.AFTER) {
+							idx++;
+						}
+
+						if (idx < elements.size()) {
+							elements.add(idx, element);
+						} else {
+							elements.add(element);
+						}
+					}
+					break;
+
+				default:
+					WorkbenchPlugin.log("Can't position control '" + element.getElementId() //$NON-NLS-1$
+							+ "' because of the unknown position type '" //$NON-NLS-1$
+							+ positionInfo.getPosition() + "'!"); //$NON-NLS-1$
+				}
+			}
+		}
+	}
+
+	/**
+	 * Find the element with the given id in the given list of
+	 * {@link MUIElement}s.
+	 *
+	 * @param elements
+	 *            the list of {@link MUIElement}s to search
+	 * @param id
+	 *            the id of the {@link MUIElement} to find
+	 * @return the index of the {@link MUIElement} in the given list or -1 if
+	 *         element wasn't found
+	 */
+	private int indexOfElementWithID(List<MUIElement> elements, String id) {
+		if (elements == null || id == null)
+			return -1;
+
+		int index = 0;
+		for (MUIElement element : elements) {
+			if (id.equals(element.getElementId())) {
+				return index;
+			}
+			index++;
+		}
+
+		return -1;
+	}
+
+	/**
+	 * Checks if the {@link MUIElement} has a tag starting with
+	 * {@value #MOVE_TAG} and if so it will extract the {@link PositionInfo} out
+	 * of it.
+	 *
+	 * @param element
+	 *            the element to check
+	 * @return the found {@link PositionInfo} on the given {@link MUIElement},
+	 *         or <code>null</code> if none was found
+	 */
+	private PositionInfo findMovePositionInfo(MUIElement element) {
+		if (element != null) {
+			for (String tag : element.getTags()) {
+				if (tag.startsWith(MOVE_TAG)) {
+					return PositionInfo.parse(tag.substring(MOVE_TAG.length()));
+				}
+			}
+		}
+
+		return null;
+	}
+
+	private void populateStandardTrim(MTrimBar bottomTrim) {
+		// StatusLine
+		MToolControl slElement = (MToolControl) modelService.find(
+STATUS_LINE_ID, model);
+		if (slElement == null) {
+			slElement = modelService.createModelElement(MToolControl.class);
+			slElement.setElementId(STATUS_LINE_ID);
+			slElement.setContributionURI(TRIM_CONTRIBUTION_URI);
+			bottomTrim.getChildren().add(slElement);
+		}
+		slElement.setToBeRendered(statusLineVisible);
+		slElement.getTags().add(TrimBarLayout.SPACER);
+
+		// Heap Status
+		MToolControl hsElement = (MToolControl) modelService.find(
+				"org.eclipse.ui.HeapStatus", model); //$NON-NLS-1$
+		if (hsElement == null) {
+			hsElement = modelService.createModelElement(MToolControl.class);
+			hsElement.setElementId("org.eclipse.ui.HeapStatus"); //$NON-NLS-1$
+			hsElement.setContributionURI(TRIM_CONTRIBUTION_URI);
+			hsElement.getTags().add(IPresentationEngine.DRAGGABLE);
+			bottomTrim.getChildren().add(hsElement);
+		}
+		hsElement.setToBeRendered(getShowHeapStatus());
+
+		// Progress Bar
+		MToolControl pbElement = (MToolControl) modelService.find(
+				"org.eclipse.ui.ProgressBar", model); //$NON-NLS-1$
+		if (pbElement == null) {
+			pbElement = modelService.createModelElement(MToolControl.class);
+			pbElement.setElementId("org.eclipse.ui.ProgressBar"); //$NON-NLS-1$
+			pbElement.getTags().add(IPresentationEngine.DRAGGABLE);
+			pbElement.setContributionURI(TRIM_CONTRIBUTION_URI);
+			bottomTrim.getChildren().add(pbElement);
+		}
+		pbElement.setToBeRendered(getWindowConfigurer().getShowProgressIndicator());
+	}
+
+	private void populateTrimContributions(MTrimBar bottomTrim) {
+		// Part 1: Add groups
+		IConfigurationElement[] exts = extensionRegistry
+				.getConfigurationElementsFor("org.eclipse.ui.menus"); //$NON-NLS-1$
+		List<IConfigurationElement> items = new ArrayList<>();
+		for (IConfigurationElement ice : exts) {
+			if ("group".equals(ice.getName()) || "widget".equals(ice.getName())) { //$NON-NLS-1$ //$NON-NLS-2$
+				items.add(ice);
+			}
+		}
+
+		if (items.size() == 0)
+			return;
+
+		// Iterate over the items until they've all been placed or until
+		// an iteration doesn't place anything
+		List<IConfigurationElement> handledElements = new ArrayList<>();
+		handledElements.add(items.get(0)); // Hack!! startup seeding
+		MUIElement createdTrim = null;
+		while (items.size() > 0 && handledElements.size() > 0) {
+			handledElements.clear();
+
+			for (IConfigurationElement item : items) {
+				String id = item.getAttribute("id"); //$NON-NLS-1$
+				String classSpec = item.getAttribute("class"); //$NON-NLS-1$
+				//boolean sepVisible = "true".equals(item.getAttribute("separatorsVisible")); //$NON-NLS-1$ //$NON-NLS-2$
+				IConfigurationElement[] locs = item.getChildren("location"); //$NON-NLS-1$
+				for (IConfigurationElement loc : locs) {
+					IConfigurationElement[] bars = loc.getChildren("bar"); //$NON-NLS-1$
+					if (bars.length > 0) {
+						IConfigurationElement bar = bars[0];
+						boolean isTrim = "trim".equals(bar.getAttribute("type")); //$NON-NLS-1$//$NON-NLS-2$
+						if (isTrim) {
+							String path = bar.getAttribute("path"); //$NON-NLS-1$
+							if (path != null && path.length() > 0) {
+								createdTrim = addTrimElement(bottomTrim, item, id, false, path,
+										classSpec);
+							} else {
+								IConfigurationElement[] orders = loc.getChildren("order"); //$NON-NLS-1$
+								if (orders.length > 0) {
+									boolean isBefore = "before".equals(orders[0].getAttribute("position")); //$NON-NLS-1$//$NON-NLS-2$
+									String relTo = orders[0].getAttribute("relativeTo"); //$NON-NLS-1$
+									if ("status".equals(relTo)) //$NON-NLS-1$
+										relTo = STATUS_LINE_ID;
+
+									createdTrim = addTrimElement(bottomTrim, item, id, isBefore,
+											relTo, classSpec);
+								}
+							}
+
+							if (createdTrim != null) {
+								handledElements.add(item);
+							}
+						}
+					}
+				}
+			}
+
+			items.removeAll(handledElements);
+		}
+	}
+
+	private MToolControl addTrimElement(MTrimBar bottomTrim, IConfigurationElement ice, String id,
+			boolean isBefore, String relTo, String classSpec) {
+		// is it already in the trim ?
+		MUIElement existingTrim = modelService.find(id, bottomTrim);
+		if (existingTrim != null) {
+			iceMap.put((MToolControl) existingTrim, ice);
+			return (MToolControl) existingTrim;
+		}
+
+		// Ok, create one but only if we can site it correctly
+		int insertIndex = bottomTrim.getChildren().size();
+		if (relTo != null) {
+			MUIElement foundRel = modelService.find(relTo, bottomTrim);
+			if (foundRel == null)
+				return null;
+			insertIndex = bottomTrim.getChildren().indexOf(foundRel);
+			if (!isBefore)
+				insertIndex++;
+		}
+
+		MToolControl newTrimElement = modelService.createModelElement(MToolControl.class);
+		newTrimElement.setElementId(id);
+		newTrimElement.setToBeRendered(classSpec != null);
+		if (classSpec != null) {
+			newTrimElement
+					.setContributionURI("bundleclass://org.eclipse.ui.workbench/org.eclipse.ui.internal.LegacyTrim"); //$NON-NLS-1$
+		}
+		newTrimElement.setContributorURI(URIHelper.constructPlatformURI(ice.getContributor()));
+
+		iceMap.put(newTrimElement, ice);
+		bottomTrim.getChildren().add(insertIndex, newTrimElement);
+
+		return newTrimElement;
+	}
+
+	void populateBottomTrimContributions() {
+		MTrimBar bottomTrim = modelService.getTrim(model, SideValue.BOTTOM);
+
+		populateStandardTrim(bottomTrim);
+		populateTrimContributions(bottomTrim);
+	}
+
+	public MTrimBar getTopTrim() {
+		List<MTrimBar> trimBars = model.getTrimBars();
+		for (MTrimBar bar : trimBars) {
+			if (MAIN_TOOLBAR_ID.equals(bar.getElementId())) {
+				return bar;
+			}
+		}
+		return null;
+	}
+
+	public void fill(MenuManagerRenderer renderer, MMenu menu, IMenuManager manager) {
+		for (IContributionItem item : manager.getItems()) {
+			if (item instanceof MenuManager) {
+				MenuManager menuManager = (MenuManager) item;
+				MMenu subMenu = MenuHelper.createMenu(menuManager);
+				if (subMenu != null) {
+					renderer.linkModelToContribution(subMenu, item);
+					renderer.linkModelToManager(subMenu, menuManager);
+					fill(renderer, subMenu, menuManager);
+					menu.getChildren().add(subMenu);
+				}
+			} else if (item instanceof CommandContributionItem) {
+				CommandContributionItem cci = (CommandContributionItem) item;
+				MMenuItem menuItem = MenuHelper.createItem(application, cci);
+				manager.remove(item);
+				if (menuItem != null) {
+					menu.getChildren().add(menuItem);
+				}
+			} else if (item instanceof AbstractGroupMarker) {
+				MMenuSeparator separator = modelService.createModelElement(MMenuSeparator.class);
+				separator.setVisible(item.isVisible());
+				separator.setElementId(item.getId());
+				if (item instanceof GroupMarker) {
+					separator.getTags().add(MenuManagerRenderer.GROUP_MARKER);
+				}
+				menu.getChildren().add(separator);
+				manager.remove(item);
+			} else {
+				MMenuItem menuItem = OpaqueElementUtil.createOpaqueMenuItem();
+				menuItem.setElementId(item.getId());
+				menuItem.setVisible(item.isVisible());
+				OpaqueElementUtil.setOpaqueItem(menuItem, item);
+				menu.getChildren().add(menuItem);
+				renderer.linkModelToContribution(menuItem, item);
+			}
+		}
+	}
+
+	public static String getId(IConfigurationElement element) {
+		String id = element.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+
+		// For sub-menu management -all- items must be id'd so enforce this
+		// here (we could optimize by checking the 'name' of the config
+		// element == "menu"
+		if (id == null || id.length() == 0) {
+			id = getCommandId(element);
+		}
+		if (id == null || id.length() == 0) {
+			id = element.toString();
+		}
+
+		return id;
+	}
+
+	public static String getCommandId(IConfigurationElement element) {
+		return element.getAttribute(IWorkbenchRegistryConstants.ATT_COMMAND_ID);
+	}
+
+	public static String getActionSetCommandId(IConfigurationElement element) {
+		String id = getDefinitionId(element);
+		if (id != null) {
+			return id;
+		}
+		id = getId(element);
+		String actionSetId = null;
+		Object obj = element.getParent();
+		while (obj instanceof IConfigurationElement && actionSetId == null) {
+			IConfigurationElement parent = (IConfigurationElement) obj;
+			if (parent.getName().equals(IWorkbenchRegistryConstants.TAG_ACTION_SET)) {
+				actionSetId = getId(parent);
+			}
+			obj = parent.getParent();
+		}
+		return ACTION_SET_CMD_PREFIX + actionSetId + '/' + id;
+	}
+
+	public static String getDefinitionId(IConfigurationElement element) {
+		return element.getAttribute(IWorkbenchRegistryConstants.ATT_DEFINITION_ID);
+	}
+
+	public static boolean getRetarget(IConfigurationElement element) {
+		String r = element.getAttribute(IWorkbenchRegistryConstants.ATT_RETARGET);
+		return Boolean.valueOf(r);
+	}
+
+	/**
+	 * Return the style bits for the shortcut bar.
+	 *
+	 * @return int
+	 */
+	protected int perspectiveBarStyle() {
+		return SWT.FLAT | SWT.WRAP | SWT.RIGHT | SWT.HORIZONTAL;
+	}
+
+	private boolean coolBarVisible = true;
+
+	private boolean perspectiveBarVisible = true;
+
+	private boolean statusLineVisible = true;
+
+	/**
+	 * The handlers for global actions that were last submitted to the workbench
+	 * command support. This is a map of command identifiers to
+	 * <code>ActionHandler</code>. This map is never <code>null</code>, and is
+	 * never empty as long as at least one global action has been registered.
+	 */
+	private Map<String, ActionHandler> globalActionHandlersByCommandId = new HashMap<>();
+
+	/**
+	 * The list of handler submissions submitted to the workbench command
+	 * support. This list may be empty, but it is never <code>null</code>.
+	 */
+	private List<IHandlerActivation> handlerActivations = new ArrayList<>();
+
+	/**
+	 * The number of large updates that are currently going on. If this is
+	 * number is greater than zero, then UI updateActionBars is a no-op.
+	 *
+	 * @since 3.1
+	 */
+	private int largeUpdates = 0;
+
+	private IExtensionTracker tracker;
+
+	private void firePageClosed() {
+		pageListeners.firePageClosed(page);
+	}
+
+	private void firePageOpened() {
+		pageListeners.firePageOpened(page);
+	}
+
+	private void firePageActivated() {
+		pageListeners.firePageActivated(page);
+	}
+
+	void registerGlobalAction(IAction globalAction) {
+		String commandId = globalAction.getActionDefinitionId();
+
+		if (commandId != null) {
+			final Object value = globalActionHandlersByCommandId.remove(commandId);
+			if (value instanceof ActionHandler) {
+				// This handler is about to get clobbered, so dispose it.
+				final ActionHandler handler = (ActionHandler) value;
+				handler.dispose();
+			}
+
+			if (globalAction instanceof CommandAction) {
+				final String actionId = globalAction.getId();
+				if (actionId != null) {
+					final IActionCommandMappingService mappingService = serviceLocator
+							.getService(IActionCommandMappingService.class);
+					mappingService.map(actionId, commandId);
+				}
+			} else {
+				globalActionHandlersByCommandId.put(commandId, new ActionHandler(globalAction));
+			}
+		}
+
+		submitGlobalActions();
+	}
+
+	/**
+	 * <p>
+	 * Submits the action handlers for action set actions and global actions.
+	 * Global actions are given priority, so that if a global action and an
+	 * action set action both handle the same command, the global action is
+	 * given priority.
+	 * </p>
+	 * <p>
+	 * These submissions are submitted as <code>Priority.LEGACY</code>, which
+	 * means that they are the lowest priority. This means that if a higher
+	 * priority submission handles the same command under the same conditions,
+	 * that that submission will become the handler.
+	 * </p>
+	 */
+	void submitGlobalActions() {
+		final IHandlerService handlerService = getService(IHandlerService.class);
+
+		/*
+		 * Mash the action sets and global actions together, with global actions
+		 * taking priority.
+		 */
+		Map<String, ActionHandler> handlersByCommandId = new HashMap<>();
+		handlersByCommandId.putAll(globalActionHandlersByCommandId);
+
+		List<IHandlerActivation> newHandlers = new ArrayList<>(
+				handlersByCommandId.size());
+
+		Iterator<IHandlerActivation> existingIter = handlerActivations.iterator();
+		while (existingIter.hasNext()) {
+			IHandlerActivation next = existingIter.next();
+
+			String cmdId = next.getCommandId();
+
+			Object handler = handlersByCommandId.get(cmdId);
+			if (handler == next.getHandler()) {
+				handlersByCommandId.remove(cmdId);
+				newHandlers.add(next);
+			} else {
+				handlerService.deactivateHandler(next);
+			}
+		}
+
+		final Shell shell = getShell();
+		if (shell != null) {
+			final Expression expression = new ActiveShellExpression(shell);
+			for (Entry<String, ActionHandler> entry : handlersByCommandId.entrySet()) {
+				String commandId = entry.getKey();
+				IHandler handler = entry.getValue();
+				newHandlers.add(handlerService.activateHandler(commandId, handler, expression));
+			}
+		}
+
+		handlerActivations = newHandlers;
+	}
+
+	/**
+	 * Add a generic property listener.
+	 *
+	 * @param listener
+	 *            the listener to add
+	 * @since 3.3
+	 */
+	public void addPropertyChangeListener(IPropertyChangeListener listener) {
+		genericPropertyListeners.add(listener);
+	}
+
+	/**
+	 * Removes a generic property listener.
+	 *
+	 * @param listener
+	 *            the listener to remove
+	 * @since 3.3
+	 */
+	public void removePropertyChangeListener(IPropertyChangeListener listener) {
+		genericPropertyListeners.remove(listener);
+	}
+
+	private void firePropertyChanged(final String property, final Object oldValue,
+			final Object newValue) {
+		PropertyChangeEvent event = new PropertyChangeEvent(this, property, oldValue, newValue);
+		for (Object listener : genericPropertyListeners.getListeners()) {
+			IPropertyChangeListener propertyChangeListener = (IPropertyChangeListener) listener;
+			propertyChangeListener.propertyChange(event);
+		}
+	}
+
+	/*
+	 * Adds an listener to the part service.
+	 */
+	@Override
+	public void addPageListener(IPageListener l) {
+		pageListeners.addPageListener(l);
+	}
+
+	/**
+	 * @see org.eclipse.ui.IPageService
+	 */
+	@Override
+	public void addPerspectiveListener(org.eclipse.ui.IPerspectiveListener l) {
+		perspectiveListeners.addPerspectiveListener(l);
+	}
+
+	/**
+	 * Close the window.
+	 *
+	 * Assumes that busy cursor is active.
+	 */
+	private boolean busyClose(boolean remove) {
+		/*
+		 * Warning: Intricate flow of control and re-entrant invocations of this
+		 * method:
+		 *
+		 * - busyClose(true) is called from WorkbenchWindow#close() when the
+		 * user closes a workbench window.
+		 *
+		 * - busyClose(false) is called from Workbench#close(int, boolean). This
+		 * happens on File > Exit/Restart, [Mac] Quit Eclipse, AND ... tadaa ...
+		 * from busyClose(true) when the user closes the last window => [Case A]
+		 *
+		 * Additional complication: busyClose(true) can also be called again
+		 * when someone runs an event loop during the shutdown sequence. In that
+		 * case, the nested busyClose(true) should be dropped (bug 381555) =>
+		 * [Case B]
+		 */
+		if (closing) {
+			// [Case A] Window is already closing.
+			return false;
+		}
+		if (updateDisabled && remove) {
+			// [Case B] User closed this window, which triggered
+			// "workbench.close()", during which the user tried to close this
+			// window again.
+			return false;
+		}
+
+		// Whether the window was actually closed or not
+		boolean windowClosed = false;
+
+		// Setup internal flags to indicate window is in
+		// progress of closing and no update should be done.
+		updateDisabled = true;
+
+		try {
+			// Tag the currently active part so we can restore focus on startup
+			IWorkbenchPage activePage = getActivePage();
+			if (activePage != null) {
+				WorkbenchPartReference ref = (WorkbenchPartReference) activePage
+						.getActivePartReference();
+				if (ref != null) {
+					ref.getModel().getTags().add(EPartService.ACTIVE_ON_CLOSE_TAG);
+				}
+			}
+
+			// Only do the check if it is OK to close if we are not closing
+			// via the workbench as the workbench will check this itself.
+			Workbench workbench = getWorkbenchImpl();
+			int count = workbench.getWorkbenchWindowCount();
+			// also check for starting - if the first window dies on startup
+			// then we'll need to open a default window.
+			if (!workbench.isStarting() && !workbench.isClosing() && count <= 1
+					&& workbench.getWorkbenchConfigurer().getExitOnLastWindowClose()) {
+				windowClosed = workbench.close();
+			} else {
+				if (okToClose()) {
+					closing = true;
+					windowClosed = hardClose(remove);
+				}
+			}
+		} finally {
+			if (!windowClosed) {
+				// Reset the internal flags if window was not closed.
+				closing = false;
+				updateDisabled = false;
+			}
+		}
+
+		if (windowClosed && tracker != null) {
+			tracker.close();
+		}
+
+		return windowClosed;
+	}
+
+	@Override
+	public Shell getShell() {
+		return (Shell) model.getWidget();
+	}
+
+	public boolean close(final boolean remove) {
+		final boolean[] ret = new boolean[1];
+		BusyIndicator.showWhile(null, new Runnable() {
+			@Override
+			public void run() {
+				ret[0] = busyClose(remove);
+			}
+		});
+		return ret[0];
+	}
+
+	/**
+	 * @see IWorkbenchWindow
+	 */
+	@Override
+	public boolean close() {
+		return close(true);
+	}
+
+	protected boolean isClosing() {
+		return closing || getWorkbenchImpl().isClosing();
+	}
+
+	/**
+	 * Notifies interested parties (namely the advisor) that the window is about
+	 * to be opened.
+	 *
+	 * @since 3.1
+	 */
+	private void fireWindowOpening() {
+		// let the application do further configuration
+		getWindowAdvisor().preWindowOpen();
+	}
+
+	void fireWindowOpened() {
+		// notify the advisor
+		getWindowAdvisor().postWindowOpen();
+	}
+
+	/**
+	 * Notifies interested parties (namely the advisor) that the window has been
+	 * restored from a previously saved state.
+	 *
+	 * @throws WorkbenchException
+	 *             passed through from the advisor
+	 * @since 3.1
+	 */
+	void fireWindowRestored() throws WorkbenchException {
+		StartupThreading.runWithWorkbenchExceptions(new StartupRunnable() {
+			@Override
+			public void runWithException() throws Throwable {
+				getWindowAdvisor().postWindowRestore();
+			}
+		});
+	}
+
+	/**
+	 * Notifies interested parties (namely the advisor and the window listeners)
+	 * that the window has been closed.
+	 *
+	 * @since 3.1
+	 */
+	private void fireWindowClosed() {
+		// let the application do further deconfiguration
+		getWindowAdvisor().postWindowClose();
+		getWorkbenchImpl().fireWindowClosed(this);
+	}
+
+	/**
+	 * Mark contributions dirty for future update.
+	 */
+	private void allowUpdates(IMenuManager menuManager) {
+		menuManager.markDirty();
+		for (IContributionItem item : menuManager.getItems()) {
+			if (item instanceof IMenuManager) {
+				allowUpdates((IMenuManager) item);
+			} else if (item instanceof SubContributionItem) {
+				final IContributionItem innerItem = ((SubContributionItem) item).getInnerItem();
+				if (innerItem instanceof IMenuManager) {
+					allowUpdates((IMenuManager) innerItem);
+				}
+			}
+		}
+	}
+
+	/**
+	 * Fires perspective activated
+	 */
+	void firePerspectiveActivated(IWorkbenchPage page, IPerspectiveDescriptor perspective) {
+		IMenuManager windowManager = ((WorkbenchPage) page).getActionBars().getMenuManager();
+		allowUpdates(windowManager);
+		windowManager.update(false);
+
+		UIListenerLogging.logPerspectiveEvent(this, page, perspective,
+				UIListenerLogging.PLE_PERSP_ACTIVATED);
+		perspectiveListeners.firePerspectiveActivated(page, perspective);
+	}
+
+	/**
+	 * Fires perspective deactivated.
+	 *
+	 * @since 3.2
+	 */
+	void firePerspectivePreDeactivate(IWorkbenchPage page, IPerspectiveDescriptor perspective) {
+		UIListenerLogging.logPerspectiveEvent(this, page, perspective,
+				UIListenerLogging.PLE_PERSP_PRE_DEACTIVATE);
+		perspectiveListeners.firePerspectivePreDeactivate(page, perspective);
+	}
+
+	/**
+	 * Fires perspective deactivated.
+	 *
+	 * @since 3.1
+	 */
+	void firePerspectiveDeactivated(IWorkbenchPage page, IPerspectiveDescriptor perspective) {
+		UIListenerLogging.logPerspectiveEvent(this, page, perspective,
+				UIListenerLogging.PLE_PERSP_DEACTIVATED);
+		perspectiveListeners.firePerspectiveDeactivated(page, perspective);
+	}
+
+	/**
+	 * Fires perspective changed
+	 *
+	 * @param page
+	 * @param perspective
+	 * @param changeId
+	 */
+	public void firePerspectiveChanged(IWorkbenchPage page, IPerspectiveDescriptor perspective,
+			String changeId) {
+		// Some callers call this even when there is no active perspective.
+		// Just ignore this case.
+		if (perspective != null) {
+			UIListenerLogging.logPerspectiveChangedEvent(this, page, perspective, null, changeId);
+			perspectiveListeners.firePerspectiveChanged(page, perspective, changeId);
+		}
+	}
+
+	/**
+	 * Fires perspective changed for an affected part
+	 *
+	 * @param page
+	 * @param perspective
+	 * @param partRef
+	 * @param changeId
+	 */
+	public void firePerspectiveChanged(IWorkbenchPage page, IPerspectiveDescriptor perspective,
+			IWorkbenchPartReference partRef, String changeId) {
+		// Some callers call this even when there is no active perspective.
+		// Just ignore this case.
+		if (perspective != null) {
+			UIListenerLogging
+					.logPerspectiveChangedEvent(this, page, perspective, partRef, changeId);
+			perspectiveListeners.firePerspectiveChanged(page, perspective, partRef, changeId);
+		}
+	}
+
+	/**
+	 * Fires perspective closed
+	 */
+	void firePerspectiveClosed(IWorkbenchPage page, IPerspectiveDescriptor perspective) {
+		UIListenerLogging.logPerspectiveEvent(this, page, perspective,
+				UIListenerLogging.PLE_PERSP_CLOSED);
+		perspectiveListeners.firePerspectiveClosed(page, perspective);
+	}
+
+	/**
+	 * Fires perspective opened
+	 */
+	void firePerspectiveOpened(IWorkbenchPage page, IPerspectiveDescriptor perspective) {
+		UIListenerLogging.logPerspectiveEvent(this, page, perspective,
+				UIListenerLogging.PLE_PERSP_OPENED);
+		perspectiveListeners.firePerspectiveOpened(page, perspective);
+	}
+
+	/**
+	 * Fires perspective saved as.
+	 *
+	 * @since 3.1
+	 */
+	void firePerspectiveSavedAs(IWorkbenchPage page, IPerspectiveDescriptor oldPerspective,
+			IPerspectiveDescriptor newPerspective) {
+		UIListenerLogging.logPerspectiveSavedAs(this, page, oldPerspective, newPerspective);
+		perspectiveListeners.firePerspectiveSavedAs(page, oldPerspective, newPerspective);
+	}
+
+	/**
+	 * Returns the action bars for this window.
+	 *
+	 * @return this window's action bars
+	 */
+	public WWinActionBars getActionBars() {
+		if (actionBars == null) {
+			actionBars = new WWinActionBars(this);
+		}
+		return actionBars;
+	}
+
+	@Override
+	public IWorkbenchPage getActivePage() {
+		return page;
+	}
+
+	@Override
+	public IWorkbenchPage[] getPages() {
+		return page == null ? new IWorkbenchPage[0] : new IWorkbenchPage[] { page };
+	}
+
+	/**
+	 * @see IWorkbenchWindow
+	 */
+	@Override
+	public IPartService getPartService() {
+		return partService;
+	}
+
+	/**
+	 * Returns the layout for the shell.
+	 *
+	 * @return the layout for the shell
+	 */
+	protected Layout getLayout() {
+		return null;
+	}
+
+	/**
+	 * @see IWorkbenchWindow
+	 */
+	@Override
+	public ISelectionService getSelectionService() {
+		return selectionService;
+	}
+
+	/**
+	 * Returns <code>true</code> when the window's shell is activated,
+	 * <code>false</code> when it's shell is deactivated
+	 *
+	 * @return boolean <code>true</code> when shell activated,
+	 *         <code>false</code> when shell deactivated
+	 */
+	public boolean getShellActivated() {
+		return shellActivated;
+	}
+
+	/**
+	 * @see IWorkbenchWindow
+	 */
+	@Override
+	public IWorkbench getWorkbench() {
+		return PlatformUI.getWorkbench();
+	}
+
+	private void hideNonRestorableViews() {
+		List<MPart> sharedPartsToRemove = new ArrayList<>();
+		List<MPlaceholder> phList = modelService
+				.findElements(model, null, MPlaceholder.class, null);
+		for (MPlaceholder ph : phList) {
+			if (!(ph.getRef() instanceof MPart))
+				continue;
+
+			String partId = ph.getElementId();
+
+			// If the id contains a ':' use the part before it as the
+			// descriptor id
+			int colonIndex = partId.indexOf(':');
+			String descId = colonIndex == -1 ? partId : partId.substring(0, colonIndex);
+			String secondaryId = colonIndex == -1 ? null : partId.substring(colonIndex + 1);
+			IViewDescriptor regEntry = ((Workbench) workbench).getViewRegistry().find(descId);
+			if (regEntry != null && !regEntry.isRestorable() && !("*".equals(secondaryId))) { //$NON-NLS-1$
+				MElementContainer<MUIElement> phParent = ph.getParent();
+				if (colonIndex != -1) {
+					// if it's a multi-instance part remove it (and its MPart)
+					if (!sharedPartsToRemove.contains(ph.getRef()))
+						sharedPartsToRemove.add((MPart) ph.getRef());
+					ph.getParent().getChildren().remove(ph);
+				} else if (ph.isToBeRendered()) {
+					// just hide it (so we remember where to open it again
+					ph.setToBeRendered(false);
+				}
+
+				// We need to do our own cleanup here...
+				int vc = modelService.countRenderableChildren(phParent);
+				if (vc == 0) {
+					if (!isLastEditorStack(phParent))
+						phParent.setToBeRendered(false);
+				}
+			}
+		}
+
+		// Remove the actual shared Parts for any placeholder that was removed
+		List<MUIElement> seList = model.getSharedElements();
+		for (MPart partToRemove : sharedPartsToRemove) {
+			seList.remove(partToRemove);
+		}
+	}
+
+	private boolean isLastEditorStack(MUIElement element) {
+		return modelService.isLastEditorStack(element);
+	}
+
+	/**
+	 * Unconditionally close this window. Assumes the proper flags have been set
+	 * correctly (e.i. closing and updateDisabled)
+	 *
+	 * @param remove
+	 *            <code>true</code> if this window should be removed from the
+	 *            application model
+	 */
+	private boolean hardClose(boolean remove) {
+		try {
+			if (!remove) {
+				// we're in a shutdown case so we need to hide views that should
+				// not be restored
+				hideNonRestorableViews();
+			}
+
+			// clear some lables
+			// Remove the handler submissions. Bug 64024.
+			final IWorkbench workbench = getWorkbench();
+			final IHandlerService handlerService = workbench
+					.getService(IHandlerService.class);
+			handlerService.deactivateHandlers(handlerActivations);
+			final Iterator<IHandlerActivation> activationItr = handlerActivations.iterator();
+			while (activationItr.hasNext()) {
+				final IHandlerActivation activation = activationItr.next();
+				activation.getHandler().dispose();
+			}
+			handlerActivations.clear();
+			globalActionHandlersByCommandId.clear();
+
+			// Remove the enabled submissions. Bug 64024.
+			final IContextService contextService = workbench
+					.getService(IContextService.class);
+			contextService.unregisterShell(getShell());
+
+			// time to wipe our our populate
+			// IMenuService menuService = (IMenuService)
+			// workbench.getService(IMenuService.class);
+			// menuService.releaseContributions(((ContributionManager)
+			// getActionBars()
+			// .getMenuManager()));
+			// ICoolBarManager coolbar = getActionBars().getCoolBarManager();
+			// if (coolbar != null) {
+			// menuService.releaseContributions(((ContributionManager)
+			// coolbar));
+			// }
+
+			getActionBarAdvisor().dispose();
+			getWindowAdvisor().dispose();
+			coolbarToTrim.dispose();
+
+			// Null out the progress region. Bug 64024.
+			progressRegion = null;
+
+			MWindow window = model;
+			engine.removeGui(model);
+
+			MElementContainer<MUIElement> parent = window.getParent();
+			if (remove) {
+				parent.getChildren().remove(window);
+
+				if (parent.getSelectedElement() == window) {
+					if (!parent.getChildren().isEmpty()) {
+						parent.setSelectedElement(parent.getChildren().get(0));
+					}
+				}
+			}
+			if (getActivePage() != null) {
+				firePageClosed();
+			}
+			fireWindowClosed();
+		} finally {
+
+			try {
+				// Bring down all of the services ... after the window goes away
+				serviceLocator.dispose();
+			} catch (Exception ex) {
+				WorkbenchPlugin.log(ex);
+			}
+			menuRestrictions.clear();
+		}
+		return true;
+	}
+
+	/**
+	 * @see IWorkbenchWindow
+	 */
+	@Override
+	public boolean isApplicationMenu(String menuID) {
+		// delegate this question to the action bar advisor
+		return getActionBarAdvisor().isApplicationMenu(menuID);
+	}
+
+	boolean isWorkbenchCoolItemId(String id) {
+		return windowConfigurer.containsCoolItem(id);
+	}
+
+	/**
+	 * Called when this window is about to be closed.
+	 */
+	private boolean okToClose() {
+		// Save all of the editors.
+		if (!getWorkbenchImpl().isClosing()) {
+			IWorkbenchPage page = getActivePage();
+			if (page != null) {
+				return ((WorkbenchPage) page).saveAllEditors(true, true, true);
+			}
+		}
+		return true;
+	}
+
+	@Override
+	public IWorkbenchPage openPage(final String perspectiveId, final IAdaptable input)
+			throws WorkbenchException {
+		final Object[] result = new Object[1];
+		BusyIndicator.showWhile(null, new Runnable() {
+			@Override
+			public void run() {
+				try {
+					result[0] = busyOpenPage(perspectiveId, input);
+				} catch (WorkbenchException e) {
+					result[0] = e;
+				}
+			}
+		});
+
+		if (result[0] instanceof IWorkbenchPage) {
+			return (IWorkbenchPage) result[0];
+		} else if (result[0] instanceof WorkbenchException) {
+			throw (WorkbenchException) result[0];
+		} else {
+			throw new WorkbenchException(WorkbenchMessages.get().WorkbenchWindow_exceptionMessage);
+		}
+	}
+
+	private IWorkbenchPage busyOpenPage(String perspectiveId, IAdaptable input)
+			throws WorkbenchException {
+		IPerspectiveDescriptor descriptor = workbench.getPerspectiveRegistry()
+				.findPerspectiveWithId(perspectiveId);
+		if (descriptor == null) {
+			throw new WorkbenchException(NLS.bind(
+					WorkbenchMessages.get().WorkbenchPage_ErrorCreatingPerspective, perspectiveId));
+		}
+
+		if (page == null) {
+			page = new WorkbenchPage(this, input);
+			model.getContext().set(IWorkbenchPage.class.getName(), page);
+
+			try {
+				ContextInjectionFactory.inject(page, model.getContext());
+			} catch (InjectionException e) {
+				throw new WorkbenchException(e.getMessage(), e);
+			}
+
+			firePageOpened();
+
+			partService.setPage(page);
+		} else {
+			IWorkbenchWindow window = getWorkbench().openWorkbenchWindow(perspectiveId, input);
+			return window.getActivePage();
+		}
+
+		perspective = descriptor;
+		page.setPerspective(perspective);
+		firePageActivated();
+
+		return page;
+	}
+
+	@Override
+	public IWorkbenchPage openPage(IAdaptable input) throws WorkbenchException {
+		return openPage(workbench.getPerspectiveRegistry().getDefaultPerspective(), input);
+	}
+
+	/*
+	 * Removes an listener from the part service.
+	 */
+	@Override
+	public void removePageListener(IPageListener l) {
+		pageListeners.removePageListener(l);
+	}
+
+	/**
+	 * @see org.eclipse.ui.IPageService
+	 */
+	@Override
+	public void removePerspectiveListener(org.eclipse.ui.IPerspectiveListener l) {
+		perspectiveListeners.removePerspectiveListener(l);
+	}
+
+	private void disableControl(Control ctrl, List<Control> toEnable) {
+		if (ctrl != null && !ctrl.isDisposed() && ctrl.isEnabled()) {
+			ctrl.setEnabled(false);
+			toEnable.add(ctrl);
+		}
+	}
+
+	@Override
+	public void run(final boolean fork, boolean cancelable, final IRunnableWithProgress runnable)
+			throws InvocationTargetException, InterruptedException {
+		final StatusLineManager manager = getStatusLineManager();
+
+		// Temporary Hack for bug 330106, remove when bug 334093 is fixed
+		boolean progressHack = manager.getControl() == null;
+		if (manager == null || progressHack) {
+			runnable.run(new NullProgressMonitor());
+		} else {
+			EPartService partService = model.getContext().get(EPartService.class);
+			final MPart curActive = partService.getActivePart();
+			boolean wasCancelEnabled = manager.isCancelEnabled();
+			boolean enableMainMenu = false;
+
+			IBindingService bs = model.getContext().get(IBindingService.class);
+			boolean keyFilterEnabled = bs.isKeyFilterEnabled();
+			List<Control> toEnable = new ArrayList<>();
+			Shell theShell = getShell();
+			Display display = theShell.getDisplay();
+			Control currentFocus = display.getFocusControl();
+
+			try {
+				Menu mainMenu = (Menu) model.getMainMenu().getWidget();
+				if (mainMenu != null && !mainMenu.isDisposed() && mainMenu.isEnabled()) {
+					mainMenu.setEnabled(false);
+					enableMainMenu = true;
+				}
+
+				if (keyFilterEnabled)
+					bs.setKeyFilterEnabled(false);
+
+				// disable all other shells
+				for (Shell childShell : display.getShells()) {
+					if (childShell != theShell) {
+						disableControl(childShell, toEnable);
+					}
+				}
+
+
+				//Disable the presentation (except the bottom trim)
+				TrimmedPartLayout tpl = (TrimmedPartLayout) getShell().getLayout();
+				disableControl(tpl.clientArea, toEnable);
+				disableControl(tpl.top, toEnable);
+				disableControl(tpl.left, toEnable);
+				disableControl(tpl.right, toEnable);
+
+				// Disable everything in the bottom trim except the status line
+				if (tpl.bottom != null && !tpl.bottom.isDisposed() && tpl.bottom.isEnabled()) {
+					MUIElement statusLine = modelService.find(STATUS_LINE_ID, model);
+					Object slCtrl = statusLine != null ? statusLine.getWidget() : null;
+					for (Control bottomCtrl : tpl.bottom.getChildren()) {
+						if (bottomCtrl != slCtrl)
+							disableControl(bottomCtrl, toEnable);
+					}
+				}
+
+				manager.setCancelEnabled(cancelable);
+
+				final InvocationTargetException[] ite = new InvocationTargetException[1];
+				final InterruptedException[] ie = new InterruptedException[1];
+
+				BusyIndicator.showWhile(getShell().getDisplay(), new Runnable() {
+					@Override
+					public void run() {
+						try {
+							ModalContext.run(runnable, fork, manager.getProgressMonitor(),
+									getShell().getDisplay());
+						} catch (InvocationTargetException e) {
+							ite[0] = e;
+						} catch (InterruptedException e) {
+							ie[0] = e;
+						} finally {
+							manager.getProgressMonitor().done();
+						}
+					}
+				});
+
+				if (ite[0] != null) {
+					throw ite[0];
+				} else if (ie[0] != null) {
+					throw ie[0];
+				}
+			} finally {
+				manager.setCancelEnabled(wasCancelEnabled);
+
+				// re-enable the main menu if necessary
+				if (enableMainMenu) {
+					Menu mainMenu = (Menu) model.getMainMenu().getWidget();
+					mainMenu.setEnabled(true);
+				}
+
+				if (keyFilterEnabled)
+					bs.setKeyFilterEnabled(true);
+
+				// Re-enable any disabled controls
+				for (Control ctrl : toEnable) {
+					if (!ctrl.isDisposed() && !ctrl.isEnabled())
+						ctrl.setEnabled(true);
+				}
+
+				MPart activePart = partService.getActivePart();
+				if (curActive != activePart && activePart != null) {
+					engine.focusGui(activePart);
+				} else if (currentFocus != null && !currentFocus.isDisposed()) {
+					// It's necessary to restore focus after reenabling the
+					// controls
+					// because disabling them causes focus to jump elsewhere.
+					// Use forceFocus rather than setFocus to avoid SWT's
+					// search for children which can take focus, so focus
+					// ends up back on the actual control that previously had
+					// it.
+					currentFocus.forceFocus();
+				}
+			}
+		}
+	}
+
+	@Override
+	public void setActivePage(final IWorkbenchPage in) {
+		if (getActivePage() != in) {
+			if (in == null) {
+				firePageClosed();
+			}
+
+			page = (WorkbenchPage) in;
+			model.getContext().set(IWorkbenchPage.class, page);
+			partService.setPage(page);
+			updateActionSets();
+			// submitGlobalActions();
+		}
+	}
+
+	private Set<Object> menuRestrictions = new HashSet<>();
+
+	private Boolean valueOf(boolean result) {
+		return result ? Boolean.TRUE : Boolean.FALSE;
+	}
+
+	public Set<Object> getMenuRestrictions() {
+		return menuRestrictions;
+	}
+
+	void liftRestrictions() {
+		if (menuRestrictions.isEmpty()) {
+			return;
+		}
+		EvaluationReference[] refs = menuRestrictions
+				.toArray(new EvaluationReference[menuRestrictions.size()]);
+		IEvaluationService es = serviceLocator
+				.getService(IEvaluationService.class);
+		IEvaluationContext currentState = es.getCurrentState();
+		for (EvaluationReference reference : refs) {
+			reference.setPostingChanges(true);
+
+			boolean os = reference.evaluate(currentState);
+			reference.clearResult();
+			boolean ns = reference.evaluate(currentState);
+			if (os != ns) {
+				reference.getListener().propertyChange(
+						new PropertyChangeEvent(reference, reference.getProperty(), valueOf(os),
+								valueOf(ns)));
+			}
+		}
+	}
+
+	void imposeRestrictions() {
+		Iterator<?> i = menuRestrictions.iterator();
+		while (i.hasNext()) {
+			EvaluationReference ref = (EvaluationReference) i.next();
+			ref.setPostingChanges(false);
+		}
+	}
+
+	/**
+	 * Hooks a listener to track the activation and deactivation of the window's
+	 * shell.
+	 */
+	private void trackShellActivation() {
+		getShell().addShellListener(new ShellAdapter() {
+			@Override
+			public void shellActivated(ShellEvent event) {
+				shellActivated = true;
+				serviceLocator.activate();
+				if (getActivePage() != null) {
+					getWorkbenchImpl().fireWindowActivated(WorkbenchWindow.this);
+				}
+				liftRestrictions();
+			}
+
+			@Override
+			public void shellDeactivated(ShellEvent event) {
+				shellActivated = false;
+				imposeRestrictions();
+				serviceLocator.deactivate();
+				if (getActivePage() != null) {
+					getWorkbenchImpl().fireWindowDeactivated(WorkbenchWindow.this);
+				}
+			}
+		});
+	}
+
+	/**
+	 * update the action bars.
+	 */
+	public void updateActionBars() {
+		if (getShell() == null || getShell().isDisposed() || updateDisabled || updatesDeferred()) {
+			return;
+		}
+		// updateAll required in order to enable accelerators on pull-down menus
+		getMenuBarManager().update(false);
+
+		try {
+			getShell().setLayoutDeferred(true);
+			eventBroker.send(UIEvents.REQUEST_ENABLEMENT_UPDATE_TOPIC, UIEvents.ALL_ELEMENT_ID);
+			getCoolBarManager2().update(false);
+		} finally {
+			getShell().setLayoutDeferred(false);
+		}
+
+		getStatusLineManager().update(false);
+	}
+
+	/**
+	 * Returns true iff we are currently deferring UI processing due to a large
+	 * update
+	 *
+	 * @return true iff we are deferring UI updates.
+	 * @since 3.1
+	 */
+	private boolean updatesDeferred() {
+		return largeUpdates > 0;
+	}
+
+	/**
+	 * <p>
+	 * Indicates the start of a large update within this window. This is used to
+	 * disable CPU-intensive, change-sensitive services that were temporarily
+	 * disabled in the midst of large changes. This method should always be
+	 * called in tandem with <code>largeUpdateEnd</code>, and the event loop
+	 * should not be allowed to spin before that method is called.
+	 * </p>
+	 * <p>
+	 * Important: always use with <code>largeUpdateEnd</code>!
+	 * </p>
+	 *
+	 * @since 3.1
+	 */
+	public final void largeUpdateStart() {
+		largeUpdates++;
+	}
+
+	/**
+	 * <p>
+	 * Indicates the end of a large update within this window. This is used to
+	 * re-enable services that were temporarily disabled in the midst of large
+	 * changes. This method should always be called in tandem with
+	 * <code>largeUpdateStart</code>, and the event loop should not be allowed
+	 * to spin before this method is called.
+	 * </p>
+	 * <p>
+	 * Important: always protect this call by using <code>finally</code>!
+	 * </p>
+	 *
+	 * @since 3.1
+	 */
+	public final void largeUpdateEnd() {
+		if (--largeUpdates == 0) {
+			updateActionBars();
+		}
+	}
+
+	/**
+	 * Update the visible action sets. This method is typically called from a
+	 * page when the user changes the visible action sets within the
+	 * prespective.
+	 */
+	public void updateActionSets() {
+		if (updateDisabled) {
+			return;
+		}
+
+		WorkbenchPage currentPage = (WorkbenchPage) getActivePage();
+		if (currentPage == null) {
+			getActionPresentation().clearActionSets();
+		} else {
+			ICoolBarManager2 coolBarManager = (ICoolBarManager2) getCoolBarManager2();
+			if (coolBarManager != null) {
+				coolBarManager.refresh();
+			}
+			getActionPresentation().setActionSets(currentPage.getActionSets());
+		}
+		fireActionSetsChanged();
+		updateActionBars();
+
+		// hide the launch menu if it is empty
+		String path = IWorkbenchActionConstants.M_WINDOW + IWorkbenchActionConstants.SEP
+				+ IWorkbenchActionConstants.M_LAUNCH;
+		IMenuManager manager = getMenuBarManager().findMenuUsingPath(path);
+		IContributionItem item = getMenuBarManager().findUsingPath(path);
+
+		if (manager == null || item == null) {
+			return;
+		}
+		item.setVisible(manager.getItems().length >= 2);
+		// there is a separator for the additions group thus >= 2
+	}
+
+	private ListenerList<IActionSetsListener> actionSetListeners = null;
+
+	private ListenerList<IBackgroundSaveListener> backgroundSaveListeners = new ListenerList<>(ListenerList.IDENTITY);
+
+	private SelectionService selectionService;
+
+	private ActionPresentation actionPresentation;
+
+	private final void fireActionSetsChanged() {
+		if (actionSetListeners != null) {
+			for (Object listener : actionSetListeners.getListeners()) {
+				final IActionSetsListener actionSetsListener = (IActionSetsListener) listener;
+				final WorkbenchPage currentPage = (WorkbenchPage) getActivePage();
+				final IActionSetDescriptor[] newActionSets;
+				if (currentPage == null) {
+					newActionSets = null;
+				} else {
+					newActionSets = currentPage.getActionSets();
+				}
+				final ActionSetsEvent event = new ActionSetsEvent(newActionSets);
+				actionSetsListener.actionSetsChanged(event);
+			}
+		}
+	}
+
+	final void addActionSetsListener(final IActionSetsListener listener) {
+		if (actionSetListeners == null) {
+			actionSetListeners = new ListenerList<>();
+		}
+
+		actionSetListeners.add(listener);
+	}
+
+	final void removeActionSetsListener(final IActionSetsListener listener) {
+		if (actionSetListeners != null) {
+			actionSetListeners.remove(listener);
+			if (actionSetListeners.isEmpty()) {
+				actionSetListeners = null;
+			}
+		}
+	}
+
+	/**
+	 * Returns whether the heap status indicator should be shown.
+	 *
+	 * @return <code>true</code> to show the heap status indicator,
+	 *         <code>false</code> otherwise
+	 */
+	private boolean getShowHeapStatus() {
+		return // Show if the preference is set or debug option is on
+		PrefUtil.getAPIPreferenceStore().getBoolean(
+				IWorkbenchPreferenceConstants.SHOW_MEMORY_MONITOR)
+				|| Boolean
+						.valueOf(
+								Platform.getDebugOption(PlatformUI.PLUGIN_ID
+										+ "/perf/showHeapStatus")).booleanValue(); //$NON-NLS-1$
+	}
+
+	public void showHeapStatus(boolean show) {
+		MUIElement hsElement = modelService.find("org.eclipse.ui.HeapStatus", model); //$NON-NLS-1$
+		if (hsElement != null && hsElement.isToBeRendered() != show) {
+			hsElement.setToBeRendered(show);
+			getShell().layout(null, SWT.ALL | SWT.CHANGED | SWT.DEFER);
+		}
+	}
+
+	/**
+	 * Returns the unique object that applications use to configure this window.
+	 * <p>
+	 * IMPORTANT This method is declared package-private to prevent regular
+	 * plug-ins from downcasting IWorkbenchWindow to WorkbenchWindow and getting
+	 * hold of the workbench window configurer that would allow them to tamper
+	 * with the workbench window. The workbench window configurer is available
+	 * only to the application.
+	 * </p>
+	 */
+	/* package - DO NOT CHANGE */
+	WorkbenchWindowConfigurer getWindowConfigurer() {
+		if (windowConfigurer == null) {
+			// lazy initialize
+			windowConfigurer = new WorkbenchWindowConfigurer(this);
+		}
+		return windowConfigurer;
+	}
+
+	/**
+	 * Returns the workbench advisor. Assumes the workbench has been created
+	 * already.
+	 * <p>
+	 * IMPORTANT This method is declared private to prevent regular plug-ins
+	 * from downcasting IWorkbenchWindow to WorkbenchWindow and getting hold of
+	 * the workbench advisor that would allow them to tamper with the workbench.
+	 * The workbench advisor is internal to the application.
+	 * </p>
+	 */
+	private/* private - DO NOT CHANGE */
+	WorkbenchAdvisor getAdvisor() {
+		return getWorkbenchImpl().getAdvisor();
+	}
+
+	/**
+	 * Returns the window advisor, creating a new one for this window if needed.
+	 * <p>
+	 * IMPORTANT This method is declared package private to prevent regular
+	 * plug-ins from downcasting IWorkbenchWindow to WorkbenchWindow and getting
+	 * hold of the window advisor that would allow them to tamper with the
+	 * window. The window advisor is internal to the application.
+	 * </p>
+	 */
+	/* package private - DO NOT CHANGE */
+	WorkbenchWindowAdvisor getWindowAdvisor() {
+		if (windowAdvisor == null) {
+			windowAdvisor = getAdvisor().createWorkbenchWindowAdvisor(getWindowConfigurer());
+			Assert.isNotNull(windowAdvisor);
+		}
+		return windowAdvisor;
+	}
+
+	/**
+	 * Returns the action bar advisor, creating a new one for this window if
+	 * needed.
+	 * <p>
+	 * IMPORTANT This method is declared private to prevent regular plug-ins
+	 * from downcasting IWorkbenchWindow to WorkbenchWindow and getting hold of
+	 * the action bar advisor that would allow them to tamper with the window's
+	 * action bars. The action bar advisor is internal to the application.
+	 * </p>
+	 */
+	private/* private - DO NOT CHANGE */
+	ActionBarAdvisor getActionBarAdvisor() {
+		if (actionBarAdvisor == null) {
+			actionBarAdvisor = getWindowAdvisor().createActionBarAdvisor(
+					getWindowConfigurer().getActionBarConfigurer());
+			Assert.isNotNull(actionBarAdvisor);
+		}
+		return actionBarAdvisor;
+	}
+
+	/*
+	 * Returns the IWorkbench implementation.
+	 */
+	private Workbench getWorkbenchImpl() {
+		return Workbench.getInstance();
+	}
+
+	/**
+	 * Fills the window's real action bars.
+	 *
+	 * @param flags
+	 *            indicate which bars to fill
+	 */
+	public void fillActionBars(int flags) {
+		Workbench workbench = getWorkbenchImpl();
+		workbench.largeUpdateStart();
+		try {
+			getActionBarAdvisor().fillActionBars(flags);
+		} finally {
+			workbench.largeUpdateEnd();
+		}
+	}
+
+	/**
+	 * Fills the window's proxy action bars.
+	 *
+	 * @param proxyBars
+	 *            the proxy configurer
+	 * @param flags
+	 *            indicate which bars to fill
+	 */
+	public void fillActionBars(IActionBarConfigurer2 proxyBars, int flags) {
+		Assert.isNotNull(proxyBars);
+		WorkbenchWindowConfigurer.WindowActionBarConfigurer wab = (WorkbenchWindowConfigurer.WindowActionBarConfigurer) getWindowConfigurer()
+				.getActionBarConfigurer();
+		wab.setProxy(proxyBars);
+		try {
+			getActionBarAdvisor().fillActionBars(flags | ActionBarAdvisor.FILL_PROXY);
+		} finally {
+			wab.setProxy(null);
+		}
+	}
+
+	/**
+	 * Cause the coolbar to be shown or hidden; note that the coolbar may still
+	 * be visible depending on the visibility state of other elements. This
+	 * method is a lower-level method that affects the visibility but does not
+	 * update any associated preference values.
+	 *
+	 * @param visible
+	 *            whether the cool bar should be shown. This is only applicable
+	 *            if the window configurer also wishes either the cool bar to be
+	 *            visible.
+	 * @since 3.0
+	 */
+	public void setCoolBarVisible(boolean visible) {
+		boolean oldValue = coolBarVisible;
+		coolBarVisible = visible;
+		if (oldValue != coolBarVisible) {
+			getModel().getPersistedState().put(IPreferenceConstants.COOLBAR_VISIBLE,
+					Boolean.toString(visible));
+			updateLayoutDataForContents();
+			firePropertyChanged(PROP_COOLBAR_VISIBLE, oldValue ? Boolean.TRUE : Boolean.FALSE,
+					coolBarVisible ? Boolean.TRUE : Boolean.FALSE);
+		}
+	}
+
+	/**
+	 * @return whether the cool bar should be shown. This is only applicable if
+	 *         the window configurer also wishes either the cool bar to be
+	 *         visible.
+	 * @since 3.0
+	 */
+	public boolean getCoolBarVisible() {
+		return getWindowConfigurer().getShowCoolBar() && coolBarVisible;
+	}
+
+	public ActionPresentation getActionPresentation() {
+		if (actionPresentation == null) {
+			actionPresentation = new ActionPresentation(this);
+		}
+		return actionPresentation;
+	}
+
+	/**
+	 * Cause the perspective bar to be shown or hidden; note that the
+	 * perspective bar may still be visible depending on the visibility state of
+	 * other elements. This method is a lower-level method that affects the
+	 * visibility but does not update any associated preference values.
+	 *
+	 * @param visible
+	 *            whether the perspective bar should be shown. This is only
+	 *            applicable if the window configurer also wishes either the
+	 *            perspective bar to be visible.
+	 * @since 3.0
+	 */
+	public void setPerspectiveBarVisible(boolean visible) {
+		boolean oldValue = perspectiveBarVisible;
+		perspectiveBarVisible = visible;
+		if (oldValue != perspectiveBarVisible) {
+			getModel().getPersistedState().put(IPreferenceConstants.PERSPECTIVEBAR_VISIBLE,
+					Boolean.toString(visible));
+			updateLayoutDataForContents();
+			firePropertyChanged(PROP_PERSPECTIVEBAR_VISIBLE, oldValue ? Boolean.TRUE
+					: Boolean.FALSE, perspectiveBarVisible ? Boolean.TRUE : Boolean.FALSE);
+		}
+	}
+
+	/**
+	 * @return whether the perspective bar should be shown. This is only
+	 *         applicable if the window configurer also wishes either the
+	 *         perspective bar to be visible.
+	 * @since 3.0
+	 */
+	public boolean getPerspectiveBarVisible() {
+		return getWindowConfigurer().getShowPerspectiveBar() && perspectiveBarVisible;
+	}
+
+	/**
+	 * @param visible
+	 *            whether the perspective bar should be shown. This is only
+	 *            applicable if the window configurer also wishes either the
+	 *            perspective bar to be visible.
+	 * @since 3.0
+	 */
+	public void setStatusLineVisible(boolean visible) {
+		boolean oldValue = statusLineVisible;
+		statusLineVisible = visible;
+		if (oldValue != statusLineVisible) {
+			getModel().getPersistedState().put(IPreferenceConstants.PERSPECTIVEBAR_VISIBLE,
+					Boolean.toString(visible));
+			updateLayoutDataForContents();
+			firePropertyChanged(PROP_STATUS_LINE_VISIBLE, oldValue ? Boolean.TRUE : Boolean.FALSE,
+					statusLineVisible ? Boolean.TRUE : Boolean.FALSE);
+		}
+	}
+
+	/**
+	 * @return whether the perspective bar should be shown. This is only
+	 *         applicable if the window configurer also wishes either the
+	 *         perspective bar to be visible.
+	 * @since 3.0
+	 */
+	public boolean getStatusLineVisible() {
+		return statusLineVisible;
+	}
+
+	protected boolean showTopSeperator() {
+		return false;
+	}
+
+	/**
+	 * @return Returns the progressRegion.
+	 */
+	public ProgressRegion getProgressRegion() {
+		return progressRegion;
+	}
+
+	@Override
+	public IExtensionTracker getExtensionTracker() {
+		return (IExtensionTracker) model.getContext().get(IExtensionTracker.class.getName());
+	}
+
+	/**
+	 * Returns the default page input for workbench pages opened in this window.
+	 *
+	 * @return the default page input or <code>null</code> if none
+	 * @since 3.1
+	 */
+	IAdaptable getDefaultPageInput() {
+		return getWorkbenchImpl().getDefaultPageInput();
+	}
+
+	/**
+	 * Initializes all of the default command-based services for the workbench
+	 * window.
+	 */
+	private final void initializeDefaultServices() {
+		IEclipseContext windowContext = model.getContext();
+		serviceLocator.registerService(IWorkbenchLocationService.class,
+				new WorkbenchLocationService(IServiceScopes.WINDOW_SCOPE, getWorkbench(), this,
+						null, null, null, 1));
+		// added back for legacy reasons
+		serviceLocator.registerService(IWorkbenchWindow.class, this);
+
+		final ActionCommandMappingService mappingService = new ActionCommandMappingService();
+		serviceLocator.registerService(IActionCommandMappingService.class, mappingService);
+
+		selectionService = ContextInjectionFactory.make(SelectionService.class, model.getContext());
+		serviceLocator.registerService(ISelectionService.class, selectionService);
+
+		LegacyHandlerService hs = new LegacyHandlerService(windowContext);
+		windowContext.set(IHandlerService.class.getName(), hs);
+
+		final LegacyActionPersistence actionPersistence = new LegacyActionPersistence(this);
+		serviceLocator.registerService(LegacyActionPersistence.class, actionPersistence);
+		actionPersistence.read();
+
+		ICommandService cmdService = workbench.getService(ICommandService.class);
+		SlaveCommandService slaveCmdService = new SlaveCommandService(cmdService,
+				IServiceScopes.WINDOW_SCOPE, this, model.getContext());
+		serviceLocator.registerService(ICommandService.class, slaveCmdService);
+		serviceLocator.registerService(IUpdateService.class, slaveCmdService);
+
+		IContextService cxs = ContextInjectionFactory
+				.make(ContextService.class, model.getContext());
+		serviceLocator.registerService(IContextService.class, cxs);
+
+		IMenuService parent = getWorkbench().getService(IMenuService.class);
+		IMenuService msvs = new SlaveMenuService(parent, model);
+		serviceLocator.registerService(IMenuService.class, msvs);
+	}
+
+	@Override
+	public final <T> T getService(final Class<T> key) {
+		return serviceLocator.getService(key);
+	}
+
+	@Override
+	public final boolean hasService(final Class<?> key) {
+		return serviceLocator.hasService(key);
+	}
+
+	/**
+	 * Toggle the visibility of the coolbar/perspective bar. This method
+	 * respects the window configurer and will only toggle visibility if the
+	 * item in question was originally declared visible by the window advisor.
+	 *
+	 * @since 3.3
+	 */
+	public void toggleToolbarVisibility() {
+		boolean coolbarVisible = getCoolBarVisible();
+		boolean perspectivebarVisible = getPerspectiveBarVisible();
+
+		// only toggle the visibility of the components that
+		// were on initially
+		if (getWindowConfigurer().getShowCoolBar()) {
+			setCoolBarVisible(!coolbarVisible);
+		}
+		if (getWindowConfigurer().getShowPerspectiveBar()) {
+			setPerspectiveBarVisible(!perspectivebarVisible);
+		}
+		ICommandService commandService = getService(ICommandService.class);
+		Map<String, WorkbenchWindow> filter = new HashMap<>();
+		filter.put(IServiceScopes.WINDOW_SCOPE, this);
+		commandService.refreshElements(COMMAND_ID_TOGGLE_COOLBAR, filter);
+	}
+
+	/**
+	 * Return true if the toolbar is visible. Note that it may not be possible
+	 * to make the toolbar visible (i.e., the window configurer).
+	 *
+	 * @return true if the toolbar is visible
+	 * @since 4.2
+	 */
+	public boolean isToolbarVisible() {
+		return (getCoolBarVisible() && getWindowConfigurer().getShowCoolBar())
+				|| (getPerspectiveBarVisible() && getWindowConfigurer().getShowPerspectiveBar());
+	}
+
+	private void updateLayoutDataForContents() {
+		MTrimBar topTrim = getTopTrim();
+		if (topTrim != null) {
+			topTrim.setVisible(isToolbarVisible());
+			getShell().layout();
+		}
+	}
+
+	/* package */void addBackgroundSaveListener(IBackgroundSaveListener listener) {
+		backgroundSaveListeners.add(listener);
+	}
+
+	/* package */void fireBackgroundSaveStarted() {
+		for (Object listener : backgroundSaveListeners.getListeners()) {
+			IBackgroundSaveListener backgroundSaveListener = (IBackgroundSaveListener) listener;
+			backgroundSaveListener.handleBackgroundSaveStarted();
+		}
+	}
+
+	/* package */void removeBackgroundSaveListener(IBackgroundSaveListener listener) {
+		backgroundSaveListeners.remove(listener);
+	}
+
+	public MWindow getModel() {
+		return model;
+	}
+
+	StatusLineManager statusLineManager = null;
+
+	public StatusLineManager getStatusLineManager() {
+		if (statusLineManager == null) {
+			statusLineManager = new StatusLineManager();
+		}
+		return statusLineManager;
+	}
+
+	private CoolBarManager2 oldCBM = new CoolBarManager2();
+	private CoolBarToTrimManager coolbarToTrim;
+
+	public ICoolBarManager getCoolBarManager2() {
+		if (coolbarToTrim == null) {
+			coolbarToTrim = new CoolBarToTrimManager(application, model, workbenchTrimElements,
+					rendererFactory);
+		}
+		return coolbarToTrim;
+	}
+
+	public CoolBarManager getCoolBarManager() {
+		WorkbenchPlugin.log(new Exception("Bad call to getCoolBarManager()")); //$NON-NLS-1$
+		return oldCBM;
+	}
+
+	private IContributionManagerOverrides toolbarOverride = new IContributionManagerOverrides() {
+
+		@Override
+		public Integer getAccelerator(IContributionItem item) {
+			return null;
+		}
+
+		@Override
+		public String getAcceleratorText(IContributionItem item) {
+			return null;
+		}
+
+		@Override
+		public Boolean getEnabled(IContributionItem item) {
+			return null;
+		}
+
+		@Override
+		public String getText(IContributionItem item) {
+			return null;
+		}
+
+		@Override
+		public Boolean getVisible(IContributionItem item) {
+			if (page == null)
+				return null;
+
+			MPerspective curPersp = page.getCurrentPerspective();
+			if (curPersp == null)
+				return null;
+
+			// Find the command ID
+			String id = CustomizePerspectiveDialog.getIDFromIContributionItem(item);
+			if (id == null)
+				return null;
+
+			String hiddenToolItems = page.getHiddenItems();
+			if (hiddenToolItems.contains(ModeledPageLayout.HIDDEN_TOOLBAR_PREFIX + id + ",")) { //$NON-NLS-1$
+				return Boolean.FALSE;
+			}
+			return null;
+		}
+	};
+
+	MenuManager menuManager = new MenuManager("MenuBar", ActionSet.MAIN_MENU); //$NON-NLS-1$
+
+	public MenuManager getMenuManager() {
+		return menuManager;
+	}
+
+	public IMenuManager getMenuBarManager() {
+		return menuManager;
+	}
+
+	private IContributionManagerOverrides menuOverride = new IContributionManagerOverrides() {
+
+		@Override
+		public Integer getAccelerator(IContributionItem item) {
+			return null;
+		}
+
+		@Override
+		public String getAcceleratorText(IContributionItem item) {
+			return null;
+		}
+
+		@Override
+		public Boolean getEnabled(IContributionItem item) {
+			return null;
+		}
+
+		@Override
+		public String getText(IContributionItem item) {
+			return null;
+		}
+
+		@Override
+		public Boolean getVisible(IContributionItem item) {
+			if (page == null)
+				return null;
+
+			MPerspective curPersp = page.getCurrentPerspective();
+			if (curPersp == null)
+				return null;
+
+			// Find the command ID
+			String id = CustomizePerspectiveDialog.getIDFromIContributionItem(item);
+			if (id == null)
+				return null;
+
+			String hiddenToolItems = page.getHiddenItems();
+			if (hiddenToolItems.contains(ModeledPageLayout.HIDDEN_MENU_PREFIX + id + ",")) { //$NON-NLS-1$
+				return Boolean.FALSE;
+			}
+			return null;
+		}
+	};
+
+	ToolBarManager2 toolBarManager = new ToolBarManager2();
+
+	private Runnable menuUpdater;
+
+	@Inject
+	@Optional
+	private ToolBarManagerRenderer toolBarManagerRenderer;
+
+	public IToolBarManager2 getToolBarManager2() {
+		return toolBarManager;
+	}
+
+	public IToolBarManager getToolBarManager() {
+		return getToolBarManager2();
+	}
+
+	public CustomizePerspectiveDialog createCustomizePerspectiveDialog(Perspective persp,
+			IEclipseContext context) {
+		return new CustomizePerspectiveDialog(getWindowConfigurer(), persp, context);
+	}
+
+	private class WWinPartService extends PartService {
+
+		@Override
+		public void partActivated(IWorkbenchPart part) {
+			super.partActivated(part);
+			selectionService.notifyListeners(part);
+		}
+
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchWindowConfigurer.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchWindowConfigurer.java
new file mode 100644
index 0000000..32c290a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchWindowConfigurer.java
@@ -0,0 +1,489 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 441184, 440136
+ *     Denis Zygann <d.zygann@web.de> - Bug 457390
+ *******************************************************************************/
+package org.eclipse.ui.internal;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.ICoolBarManager;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.IStatusLineManager;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.internal.provisional.action.IToolBarContributionItem;
+import org.eclipse.jface.internal.provisional.action.ToolBarContributionItem2;
+import org.eclipse.jface.internal.provisional.action.ToolBarManager2;
+import org.eclipse.jface.window.Window;
+import org.eclipse.osgi.util.TextProcessor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.dnd.DropTargetListener;
+import org.eclipse.swt.dnd.Transfer;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.application.IActionBarConfigurer;
+import org.eclipse.ui.application.IWorkbenchConfigurer;
+import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
+import org.eclipse.ui.application.WorkbenchAdvisor;
+import org.eclipse.ui.internal.provisional.application.IActionBarConfigurer2;
+
+/**
+ * Internal class providing special access for configuring workbench windows.
+ * <p>
+ * Note that these objects are only available to the main application
+ * (the plug-in that creates and owns the workbench).
+ * </p>
+ * <p>
+ * This class is not intended to be instantiated or subclassed by clients.
+ * </p>
+ *
+ * @since 3.0
+ */
+public final class WorkbenchWindowConfigurer implements
+        IWorkbenchWindowConfigurer {
+
+    /**
+     * The workbench window associated with this configurer.
+     */
+    private WorkbenchWindow window;
+
+    /**
+     * The shell style bits to use when the window's shell is being created.
+     */
+    private int shellStyle = SWT.SHELL_TRIM | Window.getDefaultOrientation();
+
+    /**
+     * The window title to set when the window's shell has been created.
+     */
+    private String windowTitle;
+
+    /**
+     * Whether the workbench window should show the perspective bar
+     */
+    private boolean showPerspectiveBar = false;
+
+    /**
+     * Whether the workbench window should show the status line.
+     */
+    private boolean showStatusLine = true;
+
+    /**
+     * Whether the workbench window should show the main tool bar.
+     */
+    private boolean showToolBar = true;
+
+    /**
+     * Whether the workbench window should show the main menu bar.
+     */
+    private boolean showMenuBar = true;
+
+    /**
+     * Whether the workbench window should have a progress indicator.
+     */
+    private boolean showProgressIndicator = false;
+
+    /**
+     * Table to hold arbitrary key-data settings (key type: <code>String</code>,
+     * value type: <code>Object</code>).
+     * @see #setData
+     */
+    private Map extraData = new HashMap(1);
+
+    /**
+     * Holds the list drag and drop <code>Transfer</code> for the
+     * editor area
+     */
+    private ArrayList transferTypes = new ArrayList(3);
+
+    /**
+     * The <code>DropTargetListener</code> implementation for handling a
+     * drop into the editor area.
+     */
+    private DropTargetListener dropTargetListener = null;
+
+    /**
+     * Object for configuring this workbench window's action bars.
+     * Lazily initialized to an instance unique to this window.
+     */
+    private WindowActionBarConfigurer actionBarConfigurer = null;
+
+    /**
+     * The initial size to use for the shell.
+     */
+    private Point initialSize = new Point(1024, 768);
+
+    /**
+     * Action bar configurer that changes this workbench window.
+     * This implementation keeps track of of cool bar items
+     */
+    class WindowActionBarConfigurer implements IActionBarConfigurer2 {
+
+        private IActionBarConfigurer2 proxy;
+
+        /**
+         * Sets the proxy to use, or <code>null</code> for none.
+         *
+         * @param proxy the proxy
+         */
+        public void setProxy(IActionBarConfigurer2 proxy) {
+            this.proxy = proxy;
+        }
+
+        @Override
+		public IWorkbenchWindowConfigurer getWindowConfigurer() {
+            return window.getWindowConfigurer();
+        }
+
+        /**
+         * Returns whether the given id is for a cool item.
+         *
+         * @param the item id
+         * @return <code>true</code> if it is a cool item,
+         * and <code>false</code> otherwise
+         */
+        /* package */boolean containsCoolItem(String id) {
+            ICoolBarManager cbManager = getCoolBarManager();
+            if (cbManager == null) {
+				return false;
+			}
+            IContributionItem cbItem = cbManager.find(id);
+            if (cbItem == null) {
+				return false;
+			}
+            //@ issue: maybe we should check if cbItem is visible?
+            return true;
+        }
+
+        @Override
+		public IStatusLineManager getStatusLineManager() {
+            if (proxy != null) {
+                return proxy.getStatusLineManager();
+            }
+			return window.getStatusLineManager();
+        }
+
+        @Override
+		public IMenuManager getMenuManager() {
+            if (proxy != null) {
+                return proxy.getMenuManager();
+            }
+			return window.getMenuManager();
+        }
+
+        @Override
+		public ICoolBarManager getCoolBarManager() {
+            if (proxy != null) {
+                return proxy.getCoolBarManager();
+            }
+			return window.getCoolBarManager2();
+        }
+
+        @Override
+		public void registerGlobalAction(IAction action) {
+            if (proxy != null) {
+                proxy.registerGlobalAction(action);
+            }
+            window.registerGlobalAction(action);
+        }
+
+		@Override
+		public IToolBarManager createToolBarManager() {
+			if (proxy != null) {
+				return proxy.createToolBarManager();
+			}
+			return new ToolBarManager2(SWT.WRAP | SWT.FLAT | SWT.RIGHT);
+		}
+
+		@Override
+		public IToolBarContributionItem createToolBarContributionItem(IToolBarManager toolBarManager, String id) {
+			if (proxy != null) {
+				return proxy.createToolBarContributionItem(toolBarManager, id);
+			}
+			return new ToolBarContributionItem2(toolBarManager, id);
+		}
+    }
+
+    /**
+     * Creates a new workbench window configurer.
+     * <p>
+     * This method is declared package-private. Clients obtain instances
+     * via {@link WorkbenchAdvisor#getWindowConfigurer
+     * WorkbenchAdvisor.getWindowConfigurer}
+     * </p>
+     *
+     * @param window the workbench window that this object configures
+     * @see WorkbenchAdvisor#getWindowConfigurer
+     */
+    WorkbenchWindowConfigurer(WorkbenchWindow window) {
+        if (window == null) {
+            throw new IllegalArgumentException();
+        }
+        this.window = window;
+        windowTitle = WorkbenchPlugin.getDefault().getProductName();
+        if (windowTitle == null) {
+            windowTitle = ""; //$NON-NLS-1$
+        }
+    }
+
+    @Override
+	public IWorkbenchWindow getWindow() {
+        return window;
+    }
+
+    @Override
+	public IWorkbenchConfigurer getWorkbenchConfigurer() {
+        return Workbench.getInstance().getWorkbenchConfigurer();
+    }
+
+    /**
+     * Returns the title as set by <code>setTitle</code>, without consulting the shell.
+     *
+     * @return the window title as set, or <code>null</code> if not set
+     */
+    /* package */String basicGetTitle() {
+        return windowTitle;
+    }
+
+    @Override
+	public String getTitle() {
+        Shell shell = window.getShell();
+        if (shell != null) {
+            // update the cached title
+            windowTitle = shell.getText();
+        }
+        return windowTitle;
+    }
+
+    @Override
+	public void setTitle(String title) {
+        if (title == null) {
+            throw new IllegalArgumentException();
+        }
+        windowTitle = title;
+        Shell shell = window.getShell();
+        if (shell != null && !shell.isDisposed()) {
+            shell.setText(TextProcessor.process(title, WorkbenchWindow.TEXT_DELIMITERS));
+        }
+    }
+
+    @Override
+	public boolean getShowMenuBar() {
+        return showMenuBar;
+    }
+
+    @Override
+	public void setShowMenuBar(boolean show) {
+        showMenuBar = show;
+        WorkbenchWindow win = (WorkbenchWindow) getWindow();
+        Shell shell = win.getShell();
+        if (shell != null) {
+            boolean showing = shell.getMenuBar() != null;
+            if (show != showing) {
+                if (show) {
+					shell.setMenuBar(null);
+                } else {
+                    shell.setMenuBar(null);
+                }
+            }
+        }
+    }
+
+    @Override
+	public boolean getShowCoolBar() {
+        return showToolBar;
+    }
+
+    @Override
+	public void setShowCoolBar(boolean show) {
+        showToolBar = show;
+        // @issue need to be able to reconfigure after window's controls created
+    }
+
+    @Override
+    public boolean getShowFastViewBars() {
+        // not supported anymore
+        return false;
+    }
+
+    @Override
+    public void setShowFastViewBars(boolean show) {
+        // not supported anymore
+    }
+
+    @Override
+	public boolean getShowPerspectiveBar() {
+        return showPerspectiveBar;
+    }
+
+    @Override
+	public void setShowPerspectiveBar(boolean show) {
+        showPerspectiveBar = show;
+        // @issue need to be able to reconfigure after window's controls created
+    }
+
+    @Override
+	public boolean getShowStatusLine() {
+        return showStatusLine;
+    }
+
+    @Override
+	public void setShowStatusLine(boolean show) {
+        showStatusLine = show;
+        window.setStatusLineVisible(show);
+        // @issue need to be able to reconfigure after window's controls created
+    }
+
+    @Override
+	public boolean getShowProgressIndicator() {
+        return showProgressIndicator;
+    }
+
+    @Override
+	public void setShowProgressIndicator(boolean show) {
+        showProgressIndicator = show;
+        // @issue need to be able to reconfigure after window's controls created
+    }
+
+    @Override
+	public Object getData(String key) {
+        if (key == null) {
+            throw new IllegalArgumentException();
+        }
+        return extraData.get(key);
+    }
+
+    @Override
+	public void setData(String key, Object data) {
+        if (key == null) {
+            throw new IllegalArgumentException();
+        }
+        if (data != null) {
+            extraData.put(key, data);
+        } else {
+            extraData.remove(key);
+        }
+    }
+
+    @Override
+	public void addEditorAreaTransfer(Transfer tranfer) {
+		if (tranfer != null && !transferTypes.contains(tranfer)) {
+			transferTypes.add(tranfer);
+		}
+    }
+
+    @Override
+	public void configureEditorAreaDropListener(
+            DropTargetListener dropTargetListener) {
+		this.dropTargetListener = dropTargetListener;
+    }
+
+    /**
+     * Returns the array of <code>Transfer</code> added by the application
+     */
+    /* package */Transfer[] getTransfers() {
+        Transfer[] transfers = new Transfer[transferTypes.size()];
+        transferTypes.toArray(transfers);
+        return transfers;
+    }
+
+    /**
+     * Returns the drop listener provided by the application.
+     */
+    /* package */DropTargetListener getDropTargetListener() {
+        return dropTargetListener;
+    }
+
+    @Override
+	public IActionBarConfigurer getActionBarConfigurer() {
+        if (actionBarConfigurer == null) {
+            // lazily initialize
+            actionBarConfigurer = new WindowActionBarConfigurer();
+        }
+        return actionBarConfigurer;
+    }
+
+    /**
+     * Returns whether the given id is for a cool item.
+     *
+     * @param the item id
+     * @return <code>true</code> if it is a cool item,
+     * and <code>false</code> otherwise
+     */
+    /* package */boolean containsCoolItem(String id) {
+        // trigger lazy initialization
+        getActionBarConfigurer();
+        return actionBarConfigurer.containsCoolItem(id);
+    }
+
+    @Override
+	public int getShellStyle() {
+        return shellStyle;
+    }
+
+    @Override
+	public void setShellStyle(int shellStyle) {
+        this.shellStyle = shellStyle;
+    }
+
+    @Override
+	public Point getInitialSize() {
+        return initialSize;
+    }
+
+    @Override
+	public void setInitialSize(Point size) {
+        initialSize = size;
+    }
+
+    /**
+     * Creates the default window contents.
+     *
+     * @param shell the shell
+     */
+    public void createDefaultContents(Shell shell) {
+
+    }
+
+    @Override
+	public Menu createMenuBar() {
+		return null;
+    }
+
+    @Override
+	public Control createCoolBarControl(Composite parent) {
+
+        return null;
+    }
+
+    @Override
+	public Control createStatusLineControl(Composite parent) {
+		return null;
+    }
+
+    @Override
+	public Control createPageComposite(Composite parent) {
+		return null;
+    }
+
+	@Override
+	public IStatus saveState(IMemento memento) {
+		return null;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchWindowPropertyTester.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchWindowPropertyTester.java
new file mode 100644
index 0000000..7fc1533
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbenchWindowPropertyTester.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal;
+
+import org.eclipse.core.expressions.PropertyTester;
+
+/**
+ * Tests various workbench window properties.
+ *
+ * @since 3.3
+ *
+ */
+public class WorkbenchWindowPropertyTester extends PropertyTester {
+
+	private static final String PROPERTY_IS_COOLBAR_VISIBLE = "isCoolbarVisible"; //$NON-NLS-1$
+	private static final String PROPERTY_IS_PERSPECTIVEBAR_VISIBLE = "isPerspectiveBarVisible"; //$NON-NLS-1$
+
+	@Override
+	public boolean test(Object receiver, String property, Object[] args,
+			Object expectedValue) {
+
+		if (args.length == 0 && receiver instanceof WorkbenchWindow) {
+			boolean defaultExpectedValue = true;
+			if (expectedValue != null) {
+				if (expectedValue instanceof Boolean)
+					defaultExpectedValue = ((Boolean) expectedValue).booleanValue();
+				else
+					return false; // cant work with anything else
+			}
+			final WorkbenchWindow window = (WorkbenchWindow) receiver;
+			if (PROPERTY_IS_COOLBAR_VISIBLE.equals(property)) {
+				return defaultExpectedValue == window.getCoolBarVisible();
+			} else if (PROPERTY_IS_PERSPECTIVEBAR_VISIBLE.equals(property)) {
+				return defaultExpectedValue == window.getPerspectiveBarVisible();
+			}
+		}
+		return false;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbookEditorsHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbookEditorsHandler.java
new file mode 100644
index 0000000..f8f34a5
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkbookEditorsHandler.java
@@ -0,0 +1,269 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *     Marc-Andre Laperle (Ericsson) - Bug 413278
+ *     Patrik Suzzi <psuzzi@gmail.com> - Bug 497618, 368977, 504088, 506019
+ ******************************************************************************/
+
+package org.eclipse.ui.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.workbench.renderers.swt.StackRenderer;
+import org.eclipse.e4.ui.workbench.swt.internal.copy.SearchPattern;
+import org.eclipse.jface.viewers.CellLabelProvider;
+import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerCell;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.swt.custom.CTabItem;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.ui.IEditorReference;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.themes.ITheme;
+
+/**
+ * Shows a list of open editor and parts in the current or last active workbook.
+ *
+ * @since 3.4
+ *
+ */
+public class WorkbookEditorsHandler extends FilteredTableBaseHandler {
+
+	/**
+	 * Preference node for the workbench SWT renderer
+	 */
+	private static final String ORG_ECLIPSE_E4_UI_WORKBENCH_RENDERERS_SWT = "org.eclipse.e4.ui.workbench.renderers.swt"; //$NON-NLS-1$
+
+	/**
+	 * Id for the command that opens the editor drop down
+	 */
+	private static final String ORG_ECLIPSE_UI_WINDOW_OPEN_EDITOR_DROP_DOWN = "org.eclipse.ui.window.openEditorDropDown"; //$NON-NLS-1$
+
+	/**
+	 * E4 Tag used to identify the active part
+	 */
+	private static final String TAG_ACTIVE = "active"; //$NON-NLS-1$
+
+	private SearchPattern searchPattern;
+
+	/**
+	 * Gets the preference "show most recently used tabs" (MRU tabs)
+	 *
+	 * @return Returns the enableMRU.
+	 */
+	private static boolean isMruEnabled() {
+		IEclipsePreferences preferences = InstanceScope.INSTANCE.getNode(ORG_ECLIPSE_E4_UI_WORKBENCH_RENDERERS_SWT);
+		boolean initialMRUValue = preferences.getBoolean(StackRenderer.MRU_KEY_DEFAULT, StackRenderer.MRU_DEFAULT);
+		boolean enableMRU = preferences.getBoolean(StackRenderer.MRU_KEY, initialMRUValue);
+		return enableMRU;
+	}
+
+	@Override
+	protected Object getInput(WorkbenchPage page) {
+		return getParts(page);
+	}
+
+	private List<EditorReference> getParts(WorkbenchPage page) {
+		List<EditorReference> refs;
+		if (isMruEnabled()) {
+			// sorted, MRU order
+			refs = page.getSortedEditorReferences();
+		} else {
+			// non sorted, First Opened order
+			refs = new ArrayList<>();
+			for (IEditorReference ier : page.getEditorReferences()) {
+				refs.add((EditorReference) ier);
+			}
+		}
+		return refs;
+	}
+
+	@Override
+	protected boolean isFiltered() {
+		return true;
+	}
+
+	SearchPattern getMatcher() {
+		return searchPattern;
+	}
+
+	@Override
+	protected void setMatcherString(String pattern) {
+		if (pattern.length() == 0) {
+			searchPattern = null;
+		} else {
+			SearchPattern patternMatcher = new SearchPattern();
+			patternMatcher.setPattern(pattern);
+			searchPattern = patternMatcher;
+		}
+	}
+
+	/**
+	 * Specializes
+	 * {@link FilteredTableBaseHandler#setLabelProvider(TableViewerColumn)} by
+	 * providing custom styles to the table cells
+	 */
+	@Override
+	protected void setLabelProvider(final TableViewerColumn tableViewerColumn) {
+
+	    // RAP [DM] no styled cell
+//	    tableViewerColumn.setLabelProvider(new StyledCellLabelProvider() {
+		tableViewerColumn.setLabelProvider(new CellLabelProvider() {
+
+			@Override
+			public void update(ViewerCell cell) {
+				Object element = cell.getElement();
+				if (element instanceof WorkbenchPartReference) {
+					WorkbenchPartReference ref = (WorkbenchPartReference) element;
+					String text = getWorkbenchPartReferenceText(ref);
+					cell.setText(text);
+					cell.setImage(ref.getTitleImage());
+					
+					// RAP [DM] no styled cell
+//					// get the model to define the style
+//					MPart model = ref.getModel();
+//					// build the style range
+//					StyleRange style = new StyleRange();
+//					style.start = 0;
+//					style.length = cell.getText().length();
+//					// if hidden use the bold font, if active italic
+//					style.font = getFont(isHiddenEditor(model), isActiveEditor(model));
+//					cell.setStyleRanges(new StyleRange[] { style });
+				}
+			}
+
+			@Override
+			public String getToolTipText(Object element) {
+				if (element instanceof WorkbenchPartReference) {
+					WorkbenchPartReference ref = (WorkbenchPartReference) element;
+					return ref.getTitleToolTip();
+				}
+				return super.getToolTipText(element);
+			}
+
+		});
+
+		ColumnViewerToolTipSupport.enableFor(tableViewerColumn.getViewer());
+	}
+
+	/** True if the given model represents the active editor */
+	protected boolean isActiveEditor(MPart model) {
+		if (model == null || model.getTags() == null) {
+			return false;
+		}
+		return model.getTags().contains(TAG_ACTIVE);
+	}
+
+	/** True is the given model represents an hidden editor */
+	protected boolean isHiddenEditor(MPart model) {
+		if (model == null || model.getParent() == null || !(model.getParent().getRenderer() instanceof StackRenderer)) {
+			return false;
+		}
+		StackRenderer renderer = (StackRenderer) model.getParent().getRenderer();
+		CTabItem item = renderer.findItemForPart(model);
+		return (item != null && !item.isShowing());
+	}
+
+	private Font getFont(boolean hidden, boolean active) {
+		ITheme theme = PlatformUI.getWorkbench().getThemeManager().getCurrentTheme();
+		if (active) {
+			return theme.getFontRegistry().getItalic(IWorkbenchThemeConstants.TAB_TEXT_FONT);
+		}
+		if (hidden) {
+			return theme.getFontRegistry().getBold(IWorkbenchThemeConstants.TAB_TEXT_FONT);
+		}
+		return theme.getFontRegistry().get(IWorkbenchThemeConstants.TAB_TEXT_FONT);
+	}
+
+	@Override
+	protected ViewerFilter getFilter() {
+		return new ViewerFilter() {
+			@Override
+			public boolean select(Viewer viewer, Object parentElement, Object element) {
+				SearchPattern matcher = getMatcher();
+				if (matcher == null || !(viewer instanceof TableViewer)) {
+					return true;
+				}
+				String matchName = null;
+				if (element instanceof EditorReference) {
+					matchName = ((EditorReference) element).getTitle();
+					// skips dirty editor prefix
+					if (matchName.startsWith("*")) { //$NON-NLS-1$
+						matchName = matchName.substring(1);
+					}
+				}
+				if (matchName == null) {
+					return false;
+				}
+				return matcher.matches(matchName);
+			}
+		};
+	}
+
+	@Override
+	protected ParameterizedCommand getBackwardCommand() {
+		return null;
+	}
+
+	@Override
+	protected ParameterizedCommand getForwardCommand() {
+		final ICommandService commandService = window.getWorkbench().getService(ICommandService.class);
+		final Command command = commandService.getCommand(ORG_ECLIPSE_UI_WINDOW_OPEN_EDITOR_DROP_DOWN);
+		ParameterizedCommand commandF = new ParameterizedCommand(command, null);
+		return commandF;
+	}
+
+	@Override
+	protected int getCurrentItemIndex() {
+		if (isMruEnabled()) {
+			return 0;
+		}
+		// We need to find previously selected part and return the index of the
+		// part before this part in our list, which ordered not by use but by
+		// position
+
+		WorkbenchPage page = (WorkbenchPage) window.getActivePage();
+		List<EditorReference> sortedByUse = page.getSortedEditorReferences();
+		if (sortedByUse.size() < 2) {
+			return 0;
+		}
+
+		// this is the previously used editor
+		EditorReference next = sortedByUse.get(1);
+
+		// now let's find it position in our list
+		List<EditorReference> sortedByPosition = getParts(page);
+		for (int i = 0; i < sortedByPosition.size(); i++) {
+			EditorReference ref = sortedByPosition.get(i);
+			if (ref == next) {
+				if (i > 0) {
+					// return the position of the previous part in our list
+					gotoDirection = true;
+					return i - 1;
+				}
+				// if the previous part is the *first* one in our list,
+				// we should invert the traversal direction to "back".
+				gotoDirection = false;
+				return 1;
+			}
+		}
+		return super.getCurrentItemIndex();
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkingSet.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkingSet.java
new file mode 100644
index 0000000..209a7ea
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkingSet.java
@@ -0,0 +1,300 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Tomasz Zarna <tomasz.zarna@tasktop.com> - Bug 37183
+ *******************************************************************************/
+package org.eclipse.ui.internal;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.util.SafeRunnable;
+import org.eclipse.ui.IElementFactory;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IPersistableElement;
+import org.eclipse.ui.IWorkingSetManager;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.misc.Policy;
+import org.eclipse.ui.internal.registry.WorkingSetDescriptor;
+import org.eclipse.ui.internal.registry.WorkingSetRegistry;
+import org.eclipse.ui.internal.util.Util;
+
+/**
+ * A working set holds a number of IAdaptable elements. A working set is
+ * intended to group elements for presentation to the user or for operations on
+ * a set of elements.
+ *
+ * @see org.eclipse.ui.IWorkingSet
+ * @since 2.0
+ */
+public class WorkingSet extends AbstractWorkingSet {
+	private static final String DEFAULT_ID = "org.eclipse.ui.resourceWorkingSetPage"; //$NON-NLS-1$
+
+	private String editPageId;
+
+	/**
+	 * Creates a new working set.
+	 *
+	 * @param name
+	 *            the name of the new working set. Should not have leading or
+	 *            trailing whitespace.
+	 * @param label
+	 *            the label of the new working set
+	 * @param elements
+	 *            the content of the new working set. May be empty but not
+	 *            <code>null</code>.
+	 */
+	public WorkingSet(String name, String label, IAdaptable[] elements) {
+		super(name, label);
+		internalSetElements(elements);
+	}
+
+	/**
+	 * Creates a new working set from a memento.
+	 *
+	 * @param name
+	 *            the name of the new working set. Should not have leading or
+	 *            trailing whitespace.
+	 * @param memento
+	 *            persistence memento containing the elements of the working
+	 *            set.
+	 */
+	protected WorkingSet(String name, String label, IMemento memento) {
+		super(name, label);
+		workingSetMemento = memento;
+		if (workingSetMemento != null) {
+			String uniqueId = workingSetMemento
+					.getString(IWorkbenchConstants.TAG_ID);
+			if (uniqueId != null) {
+				setUniqueId(uniqueId);
+			}
+		}
+	}
+
+	/**
+	 * Tests the receiver and the object for equality
+	 *
+	 * @param object
+	 *            object to compare the receiver to
+	 * @return true=the object equals the receiver, the name is the same. false
+	 *         otherwise
+	 */
+	@Override
+	public boolean equals(Object object) {
+		if (this == object) {
+			return true;
+		}
+		if (object instanceof WorkingSet) {
+			WorkingSet workingSet = (WorkingSet) object;
+			return Util.equals(workingSet.getName(), getName())
+					&& Util.equals(workingSet.getElementsArray(),
+							getElementsArray())
+					&& Util.equals(workingSet.getId(), getId());
+		}
+		return false;
+	}
+
+	@Override
+	public String toString() {
+		return "WS [name=" + getName() + ", elements=" + getElementsArray() + ", id=" + getId() + "]"; //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean isEditable() {
+		WorkingSetDescriptor descriptor = getDescriptor(null);
+		return descriptor != null && descriptor.isEditable();
+	}
+
+	@Override
+	public String getId() {
+		return editPageId;
+	}
+
+	@Override
+	public ImageDescriptor getImageDescriptor() {
+		WorkingSetDescriptor descriptor = getDescriptor(DEFAULT_ID);
+		if (descriptor == null) {
+			return null;
+		}
+		return descriptor.getIcon();
+	}
+
+	/**
+	 * Returns the hash code.
+	 *
+	 * @return the hash code.
+	 */
+	@Override
+	public int hashCode() {
+		int hashCode = getName().hashCode();
+
+		if (editPageId != null) {
+			hashCode &= editPageId.hashCode();
+		}
+		return hashCode;
+	}
+
+	/**
+	 * Recreates the working set elements from the persistence memento.
+	 */
+	@Override
+	void restoreWorkingSet() {
+		IMemento[] itemMementos = workingSetMemento
+				.getChildren(IWorkbenchConstants.TAG_ITEM);
+		final Set items = new HashSet();
+		for (final IMemento itemMemento : itemMementos) {
+			final String factoryID = itemMemento
+					.getString(IWorkbenchConstants.TAG_FACTORY_ID);
+
+			if (factoryID == null) {
+				WorkbenchPlugin
+						.log("Unable to restore working set item - no factory ID."); //$NON-NLS-1$
+				continue;
+			}
+			final IElementFactory factory = PlatformUI.getWorkbench()
+					.getElementFactory(factoryID);
+			if (factory == null) {
+				WorkbenchPlugin
+						.log("Unable to restore working set item - cannot instantiate factory: " + factoryID); //$NON-NLS-1$
+				continue;
+			}
+			SafeRunner
+					.run(new SafeRunnable(
+							"Unable to restore working set item - exception while invoking factory: " + factoryID) { //$NON-NLS-1$
+
+						@Override
+						public void run() throws Exception {
+							IAdaptable item = factory
+									.createElement(itemMemento);
+							if (item == null) {
+								if (Policy.DEBUG_WORKING_SETS)
+									WorkbenchPlugin
+											.log("Unable to restore working set item - cannot instantiate item: " + factoryID); //$NON-NLS-1$
+
+							} else
+								items.add(item);
+						}
+					});
+		}
+		internalSetElements((IAdaptable[]) items.toArray(new IAdaptable[items
+				.size()]));
+	}
+
+	/**
+	 * Implements IPersistableElement. Persist the working set name and working
+	 * set contents. The contents has to be either IPersistableElements or
+	 * provide adapters for it to be persistent.
+	 *
+	 * @see org.eclipse.ui.IPersistableElement#saveState(IMemento)
+	 */
+	@Override
+	public void saveState(IMemento memento) {
+		if (workingSetMemento != null) {
+			// just re-save the previous memento if the working set has
+			// not been restored
+			memento.putMemento(workingSetMemento);
+		} else {
+			memento.putString(IWorkbenchConstants.TAG_NAME, getName());
+			memento.putString(IWorkbenchConstants.TAG_LABEL, getLabel());
+			memento.putString(IWorkbenchConstants.TAG_ID, getUniqueId());
+			memento.putString(IWorkbenchConstants.TAG_EDIT_PAGE_ID, editPageId);
+			Iterator iterator = elements.iterator();
+			while (iterator.hasNext()) {
+				IAdaptable adaptable = (IAdaptable) iterator.next();
+				final IPersistableElement persistable = Adapters.adapt(adaptable, IPersistableElement.class);
+				if (persistable != null) {
+					final IMemento itemMemento = memento
+							.createChild(IWorkbenchConstants.TAG_ITEM);
+
+					itemMemento.putString(IWorkbenchConstants.TAG_FACTORY_ID,
+							persistable.getFactoryId());
+					SafeRunner
+							.run(new SafeRunnable(
+									"Problems occurred while saving persistable item state") { //$NON-NLS-1$
+
+								@Override
+								public void run() throws Exception {
+									persistable.saveState(itemMemento);
+								}
+							});
+				}
+			}
+		}
+	}
+
+	@Override
+	public void setElements(IAdaptable[] newElements) {
+		AbstractWorkingSet oldWorkingSet = clone();
+		internalSetElements(newElements);
+		fireWorkingSetChanged(IWorkingSetManager.CHANGE_WORKING_SET_CONTENT_CHANGE, oldWorkingSet);
+	}
+
+	@Override
+	public void setId(String pageId) {
+		editPageId = pageId;
+	}
+
+	@Override
+	public boolean isVisible() {
+		return true;
+	}
+
+	@Override
+	public boolean isSelfUpdating() {
+		WorkingSetDescriptor descriptor = getDescriptor(null);
+		return descriptor != null && descriptor.getUpdaterClassName() != null;
+	}
+
+	@Override
+	public boolean isAggregateWorkingSet() {
+		return false;
+	}
+
+	/**
+	 * Return the working set descriptor for this working set.
+	 *
+	 * @param defaultId
+	 *            the default working set type ID to use if this set has no
+	 *            defined type
+	 * @return the descriptor for this working set or <code>null</code> if it
+	 *         cannot be determined
+	 * @since 3.3
+	 */
+	private WorkingSetDescriptor getDescriptor(String defaultId) {
+		WorkingSetRegistry registry = WorkbenchPlugin.getDefault()
+				.getWorkingSetRegistry();
+		String id = getId();
+		if (id == null)
+			id = defaultId;
+		if (id == null)
+			return null;
+
+		return registry.getWorkingSetDescriptor(id);
+	}
+
+	@Override
+	public IAdaptable[] adaptElements(IAdaptable[] objects) {
+		IWorkingSetManager manager = getManager();
+		if (manager instanceof WorkingSetManager) {
+			WorkingSetDescriptor descriptor = getDescriptor(null);
+			if (descriptor == null || !descriptor.isElementAdapterClassLoaded())
+				return objects;
+			return ((WorkingSetManager) manager).getElementAdapter(
+						descriptor).adaptElements(this, objects);
+		}
+		return objects;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkingSetComparator.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkingSetComparator.java
new file mode 100644
index 0000000..2655e4c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkingSetComparator.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import java.util.Comparator;
+
+import org.eclipse.ui.IWorkingSet;
+
+import com.ibm.icu.text.Collator;
+
+/**
+ * Compares two working sets by name.
+ */
+public class WorkingSetComparator implements Comparator {
+
+	private static ThreadLocal INSTANCES = new ThreadLocal() {
+		@Override
+		protected synchronized Object initialValue() {
+			return new WorkingSetComparator();
+		}
+	};
+
+	public static WorkingSetComparator getInstance() {
+		return (WorkingSetComparator) INSTANCES.get();
+	}
+
+    private Collator fCollator = Collator.getInstance();
+
+    /**
+     * Implements Comparator.
+     *
+     * @see Comparator#compare(Object, Object)
+     */
+    @Override
+	public int compare(Object o1, Object o2) {
+		String name1 = null;
+		String name2 = null;
+
+		if (o1 instanceof IWorkingSet) {
+			name1 = ((IWorkingSet) o1).getLabel();
+		}
+
+		if (o2 instanceof IWorkingSet) {
+			name2 = ((IWorkingSet) o2).getLabel();
+		}
+
+		int result = fCollator.compare(name1, name2);
+		if (result == 0) { // okay, same name - now try the unique id
+
+			if (o1 instanceof IWorkingSet) {
+				name1 = ((IWorkingSet) o1).getName();
+			}
+
+			if (o2 instanceof IWorkingSet) {
+				name2 = ((IWorkingSet) o2).getName();
+			}
+			result = name1.compareTo(name2);
+		}
+		return result;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkingSetFactory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkingSetFactory.java
new file mode 100644
index 0000000..85b9dd8
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkingSetFactory.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.ui.IElementFactory;
+import org.eclipse.ui.IMemento;
+
+/**
+ * A WorkingSetFactory is used to recreate a persisted WorkingSet
+ * object.
+ */
+public class WorkingSetFactory implements IElementFactory {
+
+    @Override
+	public IAdaptable createElement(IMemento memento) {
+        String workingSetName = memento.getString(IWorkbenchConstants.TAG_NAME);
+        String label = memento.getString(IWorkbenchConstants.TAG_LABEL);
+        if (label == null) {
+			label = workingSetName;
+		}
+        String workingSetEditPageId = memento
+                .getString(IWorkbenchConstants.TAG_EDIT_PAGE_ID);
+        String aggregateString = memento
+				.getString(AbstractWorkingSet.TAG_AGGREGATE);
+		boolean isAggregate = aggregateString != null
+				&& Boolean.valueOf(aggregateString).booleanValue();
+
+		if (workingSetName == null) {
+			return null;
+		}
+
+        AbstractWorkingSet workingSet = null;
+
+        if (isAggregate) {
+			workingSet = new AggregateWorkingSet(workingSetName, label, memento);
+		} else {
+			workingSet = new WorkingSet(workingSetName, label, memento);
+		}
+
+        if (workingSetEditPageId != null) {
+            workingSet.setId(workingSetEditPageId);
+        } else if (!isAggregate) {
+            // working sets created with builds 20020418 and 20020419 will not
+            // have an edit page id. fix this automatically.
+            workingSet.setId("org.eclipse.ui.resourceWorkingSetPage"); //$NON-NLS-1$
+        }
+        return workingSet;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkingSetManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkingSetManager.java
new file mode 100644
index 0000000..e1c2409
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkingSetManager.java
@@ -0,0 +1,188 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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
+ *     Tasktop Technologies - fix for bug 327396
+ *******************************************************************************/
+package org.eclipse.ui.internal;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IWorkingSet;
+import org.eclipse.ui.IWorkingSetManager;
+import org.eclipse.ui.WorkbenchException;
+import org.eclipse.ui.XMLMemento;
+import org.eclipse.ui.statushandlers.IStatusAdapterConstants;
+import org.eclipse.ui.statushandlers.StatusAdapter;
+import org.eclipse.ui.statushandlers.StatusManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleListener;
+
+/**
+ * A working set manager stores working sets and provides property change
+ * notification when a working set is added or removed. Working sets are
+ * persisted whenever one is added or removed.
+ *
+ * @see IWorkingSetManager
+ * @since 2.0
+ */
+public class WorkingSetManager extends AbstractWorkingSetManager implements
+		IWorkingSetManager, BundleListener {
+
+	// Working set persistence
+	public static final String WORKING_SET_STATE_FILENAME = "workingsets.xml"; //$NON-NLS-1$
+
+	private boolean restoreInProgress;
+
+	private boolean savePending;
+
+	public WorkingSetManager(BundleContext context) {
+		super(context);
+	}
+
+	@Override
+	public void addRecentWorkingSet(IWorkingSet workingSet) {
+		internalAddRecentWorkingSet(workingSet);
+		saveState();
+	}
+
+	@Override
+	public void addWorkingSet(IWorkingSet workingSet) {
+		super.addWorkingSet(workingSet);
+		saveState();
+	}
+
+	/**
+	 * Returns the file used as the persistence store, or <code>null</code> if
+	 * there is no available file.
+	 *
+	 * @return the file used as the persistence store, or <code>null</code>
+	 */
+	private File getWorkingSetStateFile() {
+		IPath path = WorkbenchPlugin.getDefault().getDataLocation();
+		if (path == null) {
+			return null;
+		}
+		path = path.append(WORKING_SET_STATE_FILENAME);
+		return path.toFile();
+	}
+
+	@Override
+	public void removeWorkingSet(IWorkingSet workingSet) {
+		if (internalRemoveWorkingSet(workingSet)) {
+			saveState();
+		}
+	}
+
+	/**
+	 * Reads the persistence store and creates the working sets stored in it.
+	 */
+	public void restoreState() {
+		File stateFile = getWorkingSetStateFile();
+
+		if (stateFile != null && stateFile.exists()) {
+			try {
+				restoreInProgress = true;
+
+				FileInputStream input = new FileInputStream(stateFile);
+				BufferedReader reader = new BufferedReader(
+						new InputStreamReader(input, StandardCharsets.UTF_8));
+
+				IMemento memento = XMLMemento.createReadRoot(reader);
+				restoreWorkingSetState(memento);
+				restoreMruList(memento);
+				reader.close();
+			} catch (IOException e) {
+				handleInternalError(
+						e,
+						WorkbenchMessages.get().ProblemRestoringWorkingSetState_title,
+						WorkbenchMessages.get().ProblemRestoringWorkingSetState_message);
+			} catch (WorkbenchException e) {
+				handleInternalError(
+						e,
+						WorkbenchMessages.get().ProblemRestoringWorkingSetState_title,
+						WorkbenchMessages.get().ProblemRestoringWorkingSetState_message);
+			} finally {
+				restoreInProgress = false;
+			}
+
+			if (savePending) {
+				saveState();
+				savePending = false;
+			}
+		}
+	}
+
+	/**
+	 * Saves the working sets in the persistence store
+	 */
+	private void saveState() {
+		if (restoreInProgress) {
+			// bug 327396: avoid saving partial state
+			savePending = true;
+			return;
+		}
+
+		File stateFile = getWorkingSetStateFile();
+		if (stateFile == null) {
+			return;
+		}
+		try {
+			saveState(stateFile);
+		} catch (IOException e) {
+			stateFile.delete();
+			handleInternalError(e,
+					WorkbenchMessages.get().ProblemSavingWorkingSetState_title,
+					WorkbenchMessages.get().ProblemSavingWorkingSetState_message);
+		}
+	}
+
+	/**
+	 * Persists all working sets and fires a property change event for the
+	 * changed working set. Should only be called by
+	 * org.eclipse.ui.internal.WorkingSet.
+	 *
+	 * @param changedWorkingSet
+	 *            the working set that has changed
+	 * @param propertyChangeId
+	 *            the changed property. one of CHANGE_WORKING_SET_CONTENT_CHANGE
+	 *            and CHANGE_WORKING_SET_NAME_CHANGE
+	 */
+	@Override
+	public void workingSetChanged(IWorkingSet changedWorkingSet,
+			String propertyChangeId, Object oldValue) {
+		saveState();
+		super.workingSetChanged(changedWorkingSet, propertyChangeId, oldValue);
+	}
+
+	/**
+	 * Show and Log the exception using StatusManager.
+	 */
+	private void handleInternalError(Exception exp, String title, String message) {
+		Status status = new Status(IStatus.ERROR, WorkbenchPlugin.PI_WORKBENCH,
+				message, exp);
+		StatusAdapter sa = new StatusAdapter(status);
+		sa.setProperty(IStatusAdapterConstants.TITLE_PROPERTY, title);
+		StatusManager.getManager().handle(sa,
+				StatusManager.SHOW | StatusManager.LOG);
+	}
+
+	@Override
+	protected void restoreWorkingSetState(IMemento memento) {
+		super.restoreWorkingSetState(memento);
+		saveState();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkingSetMenuContributionItem.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkingSetMenuContributionItem.java
new file mode 100644
index 0000000..f71dc9e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/WorkingSetMenuContributionItem.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.action.ContributionItem;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.ui.IWorkingSet;
+import org.eclipse.ui.IWorkingSetManager;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.WorkingSetFilterActionGroup;
+
+/**
+ * Menu contribution item which shows a working set.
+ *
+ * @since 2.1
+ */
+public class WorkingSetMenuContributionItem extends ContributionItem {
+    private Image image;
+
+    private int id;
+
+    private IWorkingSet workingSet;
+
+    private WorkingSetFilterActionGroup actionGroup;
+
+    /**
+     * Returns the id of this menu contribution item
+     *
+     * @param id numerical id
+     * @return String string id
+     */
+    public static String getId(int id) {
+        return WorkingSetMenuContributionItem.class.getName() + "." + id; //$NON-NLS-1$
+    }
+
+    /**
+     * Creates a new instance of the receiver.
+     *
+     * @param id sequential id of the new instance
+     * @param actionGroup the action group this contribution item is created in
+     */
+    public WorkingSetMenuContributionItem(int id,
+            WorkingSetFilterActionGroup actionGroup, IWorkingSet workingSet) {
+        super(getId(id));
+        Assert.isNotNull(actionGroup);
+        Assert.isNotNull(workingSet);
+        this.id = id;
+        this.actionGroup = actionGroup;
+        this.workingSet = workingSet;
+    }
+
+    /**
+     * Adds a menu item for the working set.
+     * Overrides method from ContributionItem.
+     *
+     * @see org.eclipse.jface.action.ContributionItem#fill(Menu,int)
+     */
+    @Override
+	public void fill(Menu menu, int index) {
+        MenuItem mi = new MenuItem(menu, SWT.RADIO, index);
+        mi.setText("&" + id + " " + workingSet.getLabel()); //$NON-NLS-1$  //$NON-NLS-2$
+        mi.setSelection(workingSet.equals(actionGroup.getWorkingSet()));
+        mi.addSelectionListener(new SelectionAdapter()
+        {
+            public void widgetSelected(SelectionEvent e) 
+            {
+                IWorkingSetManager manager = PlatformUI.getWorkbench().getWorkingSetManager();
+                actionGroup.setWorkingSet(workingSet);
+                manager.addRecentWorkingSet(workingSet);
+            }
+		});
+        if (image == null) {
+			ImageDescriptor imageDescriptor = workingSet.getImageDescriptor();
+			if (imageDescriptor != null)
+				image = imageDescriptor.createImage();
+		}
+		mi.setImage(image);
+    }
+
+    /**
+     * Overridden to always return true and force dynamic menu building.
+     */
+    @Override
+	public boolean isDynamic() {
+        return true;
+    }
+
+	/*
+	 * @see org.eclipse.jface.action.ContributionItem#dispose()
+	 * @since 3.3
+	 */
+	@Override
+	public void dispose() {
+		if (image != null && !image.isDisposed())
+			image.dispose();
+		image = null;
+
+		super.dispose();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/AboutBundleData.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/AboutBundleData.java
new file mode 100644
index 0000000..b8af115
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/AboutBundleData.java
@@ -0,0 +1,224 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.about;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.osgi.signedcontent.SignedContent;
+import org.eclipse.osgi.signedcontent.SignedContentFactory;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+
+
+/**
+ * A small class to manage the about dialog information for a single bundle.
+ * @since 3.0
+ */
+public class AboutBundleData extends AboutData {
+
+	private Bundle bundle;
+
+    private boolean isSignedDetermined = false;
+
+	private boolean isSigned;
+
+    public AboutBundleData(Bundle bundle) {
+        super(getResourceString(bundle, Constants.BUNDLE_VENDOR),
+                getResourceString(bundle, Constants.BUNDLE_NAME),
+                getResourceString(bundle, Constants.BUNDLE_VERSION), bundle
+                        .getSymbolicName());
+
+        this.bundle = bundle;
+
+    }
+
+    public int getState() {
+        return bundle.getState();
+    }
+
+    /**
+    * @return a string representation of the argument state.
+    *         Does not return null.
+    */
+    public String getStateName() {
+        switch (getState()) {
+        case Bundle.INSTALLED:
+            return WorkbenchMessages.get().AboutPluginsDialog_state_installed;
+        case Bundle.RESOLVED:
+            return WorkbenchMessages.get().AboutPluginsDialog_state_resolved;
+        case Bundle.STARTING:
+            return WorkbenchMessages.get().AboutPluginsDialog_state_starting;
+        case Bundle.STOPPING:
+            return WorkbenchMessages.get().AboutPluginsDialog_state_stopping;
+        case Bundle.UNINSTALLED:
+            return WorkbenchMessages.get().AboutPluginsDialog_state_uninstalled;
+        case Bundle.ACTIVE:
+            return WorkbenchMessages.get().AboutPluginsDialog_state_active;
+        default:
+            return WorkbenchMessages.get().AboutPluginsDialog_state_unknown;
+        }
+    }
+
+    /**
+     * A function to translate the resource tags that may be embedded in a
+     * string associated with some bundle.
+     *
+     * @param headerName
+     *            the used to retrieve the correct string
+     * @return the string or null if the string cannot be found
+     */
+    private static String getResourceString(Bundle bundle, String headerName) {
+        String value = bundle.getHeaders().get(headerName);
+        return value == null ? null : Platform.getResourceString(bundle, value);
+    }
+
+    public boolean isSignedDetermined() {
+    	return isSignedDetermined;
+    }
+
+    public boolean isSigned() throws IllegalStateException {
+
+		if (isSignedDetermined)
+			return isSigned;
+
+		BundleContext bundleContext = WorkbenchPlugin.getDefault()
+				.getBundleContext();
+		ServiceReference<?> factoryRef = bundleContext
+				.getServiceReference(SignedContentFactory.class.getName());
+		if (factoryRef == null)
+			throw new IllegalStateException();
+		SignedContentFactory contentFactory = (SignedContentFactory) bundleContext
+				.getService(factoryRef);
+		try {
+			SignedContent signedContent = contentFactory.getSignedContent(bundle);
+			isSigned = signedContent != null && signedContent.isSigned();
+			isSignedDetermined = true;
+			return isSigned;
+		} catch (IOException e) {
+			throw (IllegalStateException) new IllegalStateException().initCause(e);
+		} catch (GeneralSecurityException e){
+			throw (IllegalStateException) new IllegalStateException().initCause(e);
+		} finally {
+			bundleContext.ungetService(factoryRef);
+		}
+	}
+
+	/**
+	 * @return current bundle
+	 */
+	public Bundle getBundle() {
+		return bundle;
+	}
+
+// private boolean isBundleSigned(Bundle bundle)
+//    {
+//    	isSignedDetermined = true;
+//
+//    	boolean bRet = false;
+//    	if ( null != bundle.findEntries("META-INF", "*.SF", false) ) { //$NON-NLS-1$//$NON-NLS-2$
+//    		bRet = true;
+//    	}
+//    	return bRet;
+//
+//
+//    	/*
+//    	 * The below code features implementations that do more.
+//    	 */
+//
+//
+//    /*	String loc = "";
+//
+//        StringTokenizer st = new StringTokenizer(this.location,"@");
+//
+//        try
+//        {
+//        	st.nextToken();
+//        	loc = st.nextToken();
+//        }
+//        catch( NoSuchElementException e )
+//        {
+//        	return "Not a jar file";
+//        }
+//        if(! loc.endsWith(".jar"))
+//       	{
+//        	return "Not a jar file";
+//        }
+//
+//        try
+//        {
+//        	String fileLocation = Platform.getInstallLocation().getURL().getFile() + loc;
+//			JarFile jar = new JarFile( fileLocation );
+//
+//			Enumeration e = jar.entries();
+//			/*ArrayList list = new ArrayList();
+//			byte[] buffer = new byte[8192];
+//			while( e.hasMoreElements())
+//			{
+//				JarEntry currentEntry = (JarEntry)e.nextElement();
+//				list.add(currentEntry);
+//				InputStream is = jar.getInputStream(currentEntry);
+//				while(( is.read(buffer, 0, buffer.length)) != -1 ){
+//					//can't get certificates until you read the whole dang thing.
+//				}
+//			if(is != null ) is.close();
+//			}
+//
+//
+//					int checked = 0;
+//					boolean signed =false;
+//					for( int index = 0; index < list.size(); index++ )
+//					{
+//						checked++;
+//						JarEntry je = (JarEntry)list.get(index);
+//						Certificate[] certs = je.getCertificates();
+//						if( certs != null )
+//						{
+//							//Something in this jar is signed by something!!
+//							signed = true;
+//							infoLine[5] = "Signed by "+certs[0].toString();
+//							break;
+//						}
+//
+//					}
+//					if( !signed )
+//					{
+//						infoLine[5] = "Not signed";
+//					}
+//
+//			boolean isSigned = false;
+//        	while( e.hasMoreElements() )
+//        	{
+//        		JarEntry entry = (JarEntry)e.nextElement();
+//
+//        		if( entry.getName().matches("[mM][eE][tT][aA][-][iI][nN][fF]/.*[.][sS][fF]"))
+//        		{
+//        			isSigned = true;
+//        			break;
+//        		}
+//        		if( !entry.getName().matches("[mM][eE][tT][aA][-][iI][nN][fF].*"))
+//        		{
+//        			break;
+//        		}
+//        	}
+//        	return isSigned ? "Signed!" : "Not Signed.";
+//
+//		} catch (IOException e) {
+//			return "Couldn't open jar file: " + e.toString();
+//		} */
+//    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/AboutBundleGroupData.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/AboutBundleGroupData.java
new file mode 100644
index 0000000..ddbee65
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/AboutBundleGroupData.java
@@ -0,0 +1,115 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2006 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.ui.internal.about;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.zip.CRC32;
+import java.util.zip.CheckedInputStream;
+
+import org.eclipse.core.runtime.IBundleGroup;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.branding.IBundleGroupConstants;
+
+/**
+ * A small class to manage the information related to IBundleGroup's.
+ * @since 3.0
+ */
+public class AboutBundleGroupData extends AboutData {
+    private IBundleGroup bundleGroup;
+
+    private URL licenseUrl;
+
+    private URL featureImageUrl;
+
+    private Long featureImageCrc;
+
+    private ImageDescriptor featureImage;
+
+    public AboutBundleGroupData(IBundleGroup bundleGroup) {
+        super(bundleGroup.getProviderName(), bundleGroup.getName(), bundleGroup
+                .getVersion(), bundleGroup.getIdentifier());
+        this.bundleGroup = bundleGroup;
+    }
+
+    public IBundleGroup getBundleGroup() {
+        return bundleGroup;
+    }
+
+    public URL getLicenseUrl() {
+        if (licenseUrl == null) {
+			licenseUrl = getURL(bundleGroup
+                    .getProperty(IBundleGroupConstants.LICENSE_HREF));
+		}
+
+        return licenseUrl;
+    }
+
+    public URL getFeatureImageUrl() {
+        if (featureImageUrl == null) {
+			featureImageUrl = getURL(bundleGroup
+                    .getProperty(IBundleGroupConstants.FEATURE_IMAGE));
+		}
+        return featureImageUrl;
+    }
+
+    public ImageDescriptor getFeatureImage() {
+        if (featureImage == null) {
+			featureImage = getImage(getFeatureImageUrl());
+		}
+        return featureImage;
+    }
+
+    public Long getFeatureImageCrc() {
+        if (featureImageCrc != null) {
+			return featureImageCrc;
+		}
+
+        URL url = getFeatureImageUrl();
+        if (url == null) {
+			return null;
+		}
+
+        // Get the image bytes
+        InputStream in = null;
+        try {
+            CRC32 checksum = new CRC32();
+            in = new CheckedInputStream(url.openStream(), checksum);
+
+            // the contents don't matter, the read just needs a place to go
+            byte[] sink = new byte[1024];
+            while (true) {
+				if (in.read(sink) <= 0) {
+					break;
+				}
+			}
+
+            featureImageCrc = new Long(checksum.getValue());
+            return featureImageCrc;
+
+        } catch (IOException e) {
+            return null;
+        } finally {
+            if (in != null) {
+				try {
+                    in.close();
+                } catch (IOException e) {
+                    // do nothing
+                }
+			}
+        }
+    }
+
+    public String getAboutText() {
+        return bundleGroup.getProperty(IBundleGroupConstants.ABOUT_TEXT);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/AboutData.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/AboutData.java
new file mode 100644
index 0000000..4d461ae
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/AboutData.java
@@ -0,0 +1,237 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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
+ *     Pablo Cabrera <pablo.cabrera@mulesoft.com> - Bug 428355
+ *******************************************************************************/
+package org.eclipse.ui.internal.about;
+
+import com.ibm.icu.text.Collator;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Locale;
+import org.eclipse.jface.resource.ImageDescriptor;
+
+/**
+ * An abstract parent that describes data that can be displayed in a table in one of
+ * the about dialogs.
+ * @since 3.0
+ */
+public abstract class AboutData {
+    private String providerName;
+
+    private String name;
+
+    private String version;
+
+    private String id;
+
+    private String versionedId = null;
+
+    protected AboutData(String providerName, String name, String version,
+            String id) {
+        this.providerName = providerName == null ? "" : providerName; //$NON-NLS-1$
+        this.name = name == null ? "" : name; //$NON-NLS-1$
+        this.version = version == null ? "" : version; //$NON-NLS-1$
+        this.id = id == null ? "" : id; //$NON-NLS-1$
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getProviderName() {
+        return providerName;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public String getVersionedId() {
+        if (versionedId == null) {
+			versionedId = getId() + "_" + getVersion(); //$NON-NLS-1$
+		}
+        return versionedId;
+    }
+
+    /**
+     * Modify the argument array to reverse the sort order.
+     * @param infos
+     */
+    private static void reverse(AboutData[] infos) {
+		List<AboutData> infoList = Arrays.asList(infos);
+        Collections.reverse(infoList);
+        for (int i = 0; i < infos.length; ++i) {
+			infos[i] = infoList.get(i);
+		}
+    }
+
+    /**
+     * Modify the argument array to be sorted by provider. If the reverse
+     * boolean is true, the array is assumed to already be sorted and the
+     * direction of sort (ascending vs. descending) is reversed.  Entries
+     * with the same name are sorted by name.
+     *
+     * @param reverse
+     *            if true then the order of the argument is reversed without
+     *            examining the value of the fields
+     * @param infos
+     *            the data to be sorted
+     */
+    public static void sortByProvider(boolean reverse, AboutData[] infos) {
+        if (reverse) {
+            reverse(infos);
+            return;
+        }
+
+		Arrays.sort(infos, new Comparator<AboutData>() {
+            Collator collator = Collator.getInstance(Locale.getDefault());
+
+			@Override
+			public int compare(AboutData info1, AboutData info2) {
+
+				String provider1 = info1.getProviderName();
+                String provider2 = info2.getProviderName();
+
+                if (!provider1.equals(provider2)) {
+					return collator.compare(provider1, provider2);
+				}
+
+                return collator.compare(info1.getName(), info2.getName());
+            }
+        });
+    }
+
+    /**
+     * Modify the argument array to be sorted by name. If the reverse
+     * boolean is true, the array is assumed to already be sorted and the
+     * direction of sort (ascending vs. descending) is reversed.
+     *
+     * @param reverse
+     *            if true then the order of the argument is reversed without
+     *            examining the value of the fields
+     * @param infos
+     *            the data to be sorted
+     */
+    public static void sortByName(boolean reverse, AboutData[] infos) {
+        if (reverse) {
+            reverse(infos);
+            return;
+        }
+
+		Arrays.sort(infos, new Comparator<AboutData>() {
+            Collator collator = Collator.getInstance(Locale.getDefault());
+
+			@Override
+			public int compare(AboutData info1, AboutData info2) {
+				return collator.compare(info1.getName(), info2.getName());
+            }
+        });
+    }
+
+    /**
+     * Modify the argument array to be sorted by version. If the reverse
+     * boolean is true, the array is assumed to already be sorted and the
+     * direction of sort (ascending vs. descending) is reversed.  Entries
+     * with the same name are sorted by name.
+     *
+     * @param reverse
+     *            if true then the order of the argument is reversed without
+     *            examining the value of the fields
+     * @param infos
+     *            the data to be sorted
+     */
+    public static void sortByVersion(boolean reverse, AboutData[] infos) {
+        if (reverse) {
+            reverse(infos);
+            return;
+        }
+
+		Arrays.sort(infos, new Comparator<AboutData>() {
+            Collator collator = Collator.getInstance(Locale.getDefault());
+
+			@Override
+			public int compare(AboutData info1, AboutData info2) {
+
+                String version1 = info1.getVersion();
+                String version2 = info2.getVersion();
+
+                if (!version1.equals(version2)) {
+					return collator.compare(version1, version2);
+				}
+
+                return collator.compare(info1.getName(), info2.getName());
+            }
+        });
+    }
+
+    /**
+     * Modify the argument array to be sorted by id. If the reverse
+     * boolean is true, the array is assumed to already be sorted and the
+     * direction of sort (ascending vs. descending) is reversed.  Entries
+     * with the same name are sorted by name.
+     *
+     * @param reverse
+     *            if true then the order of the argument is reversed without
+     *            examining the value of the fields
+     * @param infos
+     *            the data to be sorted
+     */
+    public static void sortById(boolean reverse, AboutData[] infos) {
+        if (reverse) {
+            reverse(infos);
+            return;
+        }
+
+		Arrays.sort(infos, new Comparator<AboutData>() {
+            Collator collator = Collator.getInstance(Locale.getDefault());
+
+			@Override
+			public int compare(AboutData info1, AboutData info2) {
+
+                String id1 = info1.getId();
+                String id2 = info2.getId();
+
+                if (!id1.equals(id2)) {
+					return collator.compare(id1, id2);
+				}
+
+                return collator.compare(info1.getName(), info2.getName());
+            }
+        });
+    }
+
+    protected static URL getURL(String value) {
+        try {
+            if (value != null) {
+				return new URL(value);
+			}
+        } catch (IOException e) {
+            // do nothing
+        }
+
+        return null;
+    }
+
+    protected static ImageDescriptor getImage(URL url) {
+        return url == null ? null : ImageDescriptor.createFromURL(url);
+    }
+
+    protected static ImageDescriptor getImage(String value) {
+        return getImage(getURL(value));
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/AboutFeaturesButtonManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/AboutFeaturesButtonManager.java
new file mode 100644
index 0000000..725a12c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/AboutFeaturesButtonManager.java
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2014 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.ui.internal.about;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Utility class used to associate BundleInfo's that have the same provider and
+ * image.  The algorithm in <code>java.util.zip.CRC32</code> is used to determine
+ * image identity.
+ */
+public class AboutFeaturesButtonManager {
+    private Map providerMap = new HashMap();
+
+    private static class Key {
+        public String providerName;
+
+        public Long crc;
+
+        /**
+         * @param crc must not be null
+         */
+        public Key(String providerName, Long crc) {
+            this.providerName = providerName;
+            this.crc = crc;
+        }
+
+        @Override
+		public boolean equals(Object o) {
+            if (!(o instanceof Key)) {
+				return false;
+			}
+            Key other = (Key) o;
+            if (!providerName.equals(other.providerName)) {
+				return false;
+			}
+            return crc.equals(other.crc);
+        }
+
+        @Override
+		public int hashCode() {
+            return providerName.hashCode();
+        }
+    }
+
+    /**
+     * @return true if a button should be added (i.e., the argument has an image
+     *         and it does not already have a button)
+     */
+    public boolean add(AboutBundleGroupData info) {
+        // no button for features without an image
+        Long crc = info.getFeatureImageCrc();
+        if (crc == null) {
+			return false;
+		}
+
+        String providerName = info.getProviderName();
+        Key key = new Key(providerName, crc);
+
+        List infoList = (List) providerMap.get(key);
+        if (infoList != null) {
+            infoList.add(info);
+            return false;
+        }
+
+        infoList = new ArrayList();
+        infoList.add(info);
+        providerMap.put(key, infoList);
+        return true;
+    }
+
+    /**
+     * Return an array of all bundle groups that share the argument's provider and
+     * image.  Returns an empty array if there isn't any related information.
+     */
+    public AboutBundleGroupData[] getRelatedInfos(AboutBundleGroupData info) {
+        // if there's no image, then there won't be a button
+        Long crc = info.getFeatureImageCrc();
+        if (crc == null) {
+			return new AboutBundleGroupData[0];
+		}
+
+        String providerName = info.getProviderName();
+        Key key = new Key(providerName, crc);
+
+        List infoList = (List) providerMap.get(key);
+        if (infoList == null) {
+			return new AboutBundleGroupData[0];
+		}
+
+        return (AboutBundleGroupData[]) infoList
+                .toArray(new AboutBundleGroupData[0]);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/AboutItem.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/AboutItem.java
new file mode 100644
index 0000000..c44fcf9
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/AboutItem.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 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.ui.internal.about;
+
+/**
+ * Holds the information for text appearing in the about dialog
+ */
+public class AboutItem {
+    private String text;
+
+    private int[][] linkRanges;
+
+    private String[] hrefs;
+
+    /**
+     * Creates a new about item
+     */
+    public AboutItem(String text, int[][] linkRanges, String[] hrefs) {
+
+        this.text = text;
+        this.linkRanges = linkRanges;
+        this.hrefs = hrefs;
+    }
+
+    /**
+     * Returns the link ranges (character locations)
+     */
+    public int[][] getLinkRanges() {
+        return linkRanges;
+    }
+
+    /**
+     * Returns the text to display
+     */
+    public String getText() {
+        return text;
+    }
+
+    /**
+     * Returns true if a link is present at the given character location
+     */
+    public boolean isLinkAt(int offset) {
+        // Check if there is a link at the offset
+        for (int[] linkRange : linkRanges) {
+            if (offset >= linkRange[0]
+                    && offset < linkRange[0] + linkRange[1]) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns the link at the given offset (if there is one),
+     * otherwise returns <code>null</code>.
+     */
+    public String getLinkAt(int offset) {
+        // Check if there is a link at the offset
+        for (int i = 0; i < linkRanges.length; i++) {
+            if (offset >= linkRanges[i][0]
+                    && offset < linkRanges[i][0] + linkRanges[i][1]) {
+                return hrefs[i];
+            }
+        }
+        return null;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/AboutPluginsPage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/AboutPluginsPage.java
new file mode 100644
index 0000000..a292da1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/AboutPluginsPage.java
@@ -0,0 +1,732 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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
+ *  	Sebastian Davids <sdavids@gmx.de> - Fix for bug 19346 - Dialog
+ * 		font should be activated and used by other components.
+ *      Robin Stocker <robin@nibor.org> - Add filter text field
+ *      Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ *      Simon Scholz <simon.scholz@vogella.com> - Bug 488704, 491316
+ *******************************************************************************/
+package org.eclipse.ui.internal.about;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
+
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.util.ConfigureColumns;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.LabelProviderChangedEvent;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.internal.misc.StringMatcher;
+import org.eclipse.ui.internal.util.BundleUtility;
+import org.eclipse.ui.progress.WorkbenchJob;
+import org.eclipse.ui.statushandlers.StatusManager;
+import org.osgi.framework.Bundle;
+
+/**
+ * Displays information about the product plugins.
+ *
+ * PRIVATE this class is internal to the IDE
+ */
+public class AboutPluginsPage extends ProductInfoPage {
+
+	public class BundleTableLabelProvider extends LabelProvider implements
+			ITableLabelProvider {
+
+		/**
+		 * Queue containing bundle signing info to be resolved.
+		 */
+		private LinkedList<AboutBundleData> resolveQueue = new LinkedList<>();
+
+		/**
+		 * Queue containing bundle data that's been resolve and needs updating.
+		 */
+		private List<AboutBundleData> updateQueue = new ArrayList<>();
+
+		/*
+		 * this job will attempt to discover the signing state of a given bundle
+		 * and then send it along to the update job
+		 */
+		private Job resolveJob = new Job(AboutPluginsPage.class.getName()) {
+			{
+				setSystem(true);
+				setPriority(Job.SHORT);
+			}
+
+			@Override
+			protected IStatus run(IProgressMonitor monitor) {
+				while (true) {
+					// If the UI has not been created, nothing to do.
+					if (vendorInfo == null)
+						return Status.OK_STATUS;
+					// If the UI has been disposed since we were asked to
+					// render, nothing to do.
+					Table table = vendorInfo.getTable();
+					// the table has been disposed since we were asked to render
+					if (table == null || table.isDisposed())
+						return Status.OK_STATUS;
+					AboutBundleData data = null;
+					synchronized (resolveQueue) {
+						if (resolveQueue.isEmpty())
+							return Status.OK_STATUS;
+						data = resolveQueue.removeFirst();
+					}
+					try {
+						// following is an expensive call
+						data.isSigned();
+
+						synchronized (updateQueue) {
+							updateQueue.add(data);
+						}
+						// start the update job
+						updateJob.schedule();
+					} catch (IllegalStateException e) {
+						// the bundle we're testing has been unloaded. Do
+						// nothing.
+					}
+				}
+			}
+		};
+
+		/*
+		 * this job is responsible for feeding label change events into the
+		 * viewer as they become available from the resolve job
+		 */
+		private Job updateJob = new WorkbenchJob(PlatformUI.getWorkbench()
+				.getDisplay(), AboutPluginsPage.class.getName()) {
+			{
+				setSystem(true);
+				setPriority(Job.DECORATE);
+			}
+
+			@Override
+			public IStatus runInUIThread(IProgressMonitor monitor) {
+				while (true) {
+					Control page = getControl();
+					// the page has gone down since we were asked to render
+					if (page == null || page.isDisposed())
+						return Status.OK_STATUS;
+					AboutBundleData[] data = null;
+					synchronized (updateQueue) {
+						if (updateQueue.isEmpty())
+							return Status.OK_STATUS;
+
+						data = updateQueue
+								.toArray(new AboutBundleData[updateQueue.size()]);
+						updateQueue.clear();
+
+					}
+					fireLabelProviderChanged(new LabelProviderChangedEvent(
+							BundleTableLabelProvider.this, data));
+				}
+			}
+		};
+
+		@Override
+		public Image getColumnImage(Object element, int columnIndex) {
+			if (columnIndex == 0) {
+				if (element instanceof AboutBundleData) {
+					final AboutBundleData data = (AboutBundleData) element;
+					if (data.isSignedDetermined()) {
+						return WorkbenchImages
+								.getImage(data.isSigned() ? IWorkbenchGraphicConstants.IMG_OBJ_SIGNED_YES
+										: IWorkbenchGraphicConstants.IMG_OBJ_SIGNED_NO);
+					}
+
+					synchronized (resolveQueue) {
+						resolveQueue.add(data);
+					}
+					resolveJob.schedule();
+
+					return WorkbenchImages
+							.getImage(IWorkbenchGraphicConstants.IMG_OBJ_SIGNED_UNKNOWN);
+				}
+			}
+			return null;
+		}
+
+		@Override
+		public String getColumnText(Object element, int columnIndex) {
+			if (element instanceof AboutBundleData) {
+				AboutBundleData data = (AboutBundleData) element;
+				switch (columnIndex) {
+				case 1:
+					return data.getProviderName();
+				case 2:
+					return data.getName();
+				case 3:
+					return data.getVersion();
+				case 4:
+					return data.getId();
+				}
+			}
+			return ""; //$NON-NLS-1$
+		}
+	}
+
+	// This id is used when the page is created inside its own dialog
+	private static final String ID = "productInfo.plugins"; //$NON-NLS-1$
+
+	/**
+	 * Table height in dialog units (value 200).
+	 */
+	private static final int TABLE_HEIGHT = 200;
+
+	private final static int MORE_ID = IDialogConstants.CLIENT_ID + 1;
+	private final static int SIGNING_ID = MORE_ID + 1;
+	private final static int COLUMNS_ID = MORE_ID + 2;
+
+	private static final IPath baseNLPath = new Path("$nl$"); //$NON-NLS-1$
+
+	private static final String PLUGININFO = "about.html"; //$NON-NLS-1$
+
+	private static final int PLUGIN_NAME_COLUMN_INDEX = 2;
+
+	private static final int SIGNING_AREA_PERCENTAGE = 30;
+
+	private TableViewer vendorInfo;
+
+	private Button moreInfo, signingInfo;
+
+	private String message;
+
+	private String helpContextId = IWorkbenchHelpContextIds.ABOUT_PLUGINS_DIALOG;
+
+	private String columnTitles[] = {
+			WorkbenchMessages.get().AboutPluginsDialog_signed,
+			WorkbenchMessages.get().AboutPluginsDialog_provider,
+			WorkbenchMessages.get().AboutPluginsDialog_pluginName,
+			WorkbenchMessages.get().AboutPluginsDialog_version,
+			WorkbenchMessages.get().AboutPluginsDialog_pluginId,
+
+	};
+	private Bundle[] bundles = WorkbenchPlugin.getDefault().getBundles();
+	private SashForm sashForm;
+	private BundleSigningInfo signingArea;
+
+	public void setBundles(Bundle[] bundles) {
+		this.bundles = bundles;
+	}
+
+	public void setHelpContextId(String id) {
+		this.helpContextId = id;
+	}
+
+	@Override
+	public void setMessage(String message) {
+		this.message = message;
+	}
+
+	/**
+	 */
+	protected void handleSigningInfoPressed() {
+		if (signingArea == null) {
+			signingArea = new BundleSigningInfo();
+			AboutBundleData bundleInfo = (AboutBundleData) vendorInfo.getStructuredSelection().getFirstElement();
+			signingArea.setData(bundleInfo);
+
+			signingArea.createContents(sashForm);
+			sashForm.setWeights(new int[] { 100 - SIGNING_AREA_PERCENTAGE,
+					SIGNING_AREA_PERCENTAGE });
+			signingInfo
+					.setText(WorkbenchMessages.get().AboutPluginsDialog_signingInfo_hide);
+
+		} else {
+			// hide
+			signingInfo
+					.setText(WorkbenchMessages.get().AboutPluginsDialog_signingInfo_show);
+			signingArea.dispose();
+			signingArea = null;
+			sashForm.setWeights(new int[] { 100 });
+		}
+	}
+
+	@Override
+	public void createPageButtons(Composite parent) {
+
+		moreInfo = createButton(parent, MORE_ID,
+				WorkbenchMessages.get().AboutPluginsDialog_moreInfo);
+		moreInfo.setEnabled(false);
+
+		signingInfo = createButton(parent, SIGNING_ID,
+				WorkbenchMessages.get().AboutPluginsDialog_signingInfo_show);
+		signingInfo.setEnabled(false);
+
+		createButton(parent, COLUMNS_ID,
+				WorkbenchMessages.get().AboutPluginsDialog_columns);
+	}
+
+	@Override
+	public void createControl(Composite parent) {
+		initializeDialogUnits(parent);
+
+		WorkbenchPlugin.class.getSigners();
+
+		sashForm = new SashForm(parent, SWT.HORIZONTAL | SWT.SMOOTH);
+		FillLayout layout = new FillLayout();
+		sashForm.setLayout(layout);
+		layout.marginHeight = 0;
+		layout.marginWidth = 0;
+		GridData data = new GridData(GridData.FILL_BOTH);
+		sashForm.setLayoutData(data);
+
+		Composite outer = createOuterComposite(sashForm);
+		PlatformUI.getWorkbench().getHelpSystem().setHelp(outer, helpContextId);
+
+		if (message != null) {
+			Label label = new Label(outer, SWT.NONE);
+			label.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+			label.setFont(parent.getFont());
+			label.setText(message);
+		}
+
+		createTable(outer);
+		setControl(outer);
+	}
+
+	private void calculateAboutBundleData(Consumer<Collection<AboutBundleData>> aboutBundleDataConsumer,
+			Display display) {
+		Job loadBundleDataJob = Job.create(WorkbenchMessages.get().AboutPluginsPage_Load_Bundle_Data, monitor -> {
+			// create a data object for each bundle, remove duplicates, and
+			// include only resolved bundles (bug 65548)
+			SubMonitor subMonitor = SubMonitor.convert(monitor, bundles.length + 1);
+			Map<String, AboutBundleData> map = new HashMap<>();
+			for (Bundle bundle : bundles) {
+				subMonitor.split(1);
+				AboutBundleData data = new AboutBundleData(bundle);
+				if (BundleUtility.isReady(data.getState()) && !map.containsKey(data.getVersionedId())) {
+					map.put(data.getVersionedId(), data);
+				}
+			}
+			subMonitor.split(1);
+			display.asyncExec(() -> aboutBundleDataConsumer.accept(map.values()));
+		});
+		loadBundleDataJob.schedule();
+	}
+
+	/**
+	 * Create the table part of the dialog.
+	 *
+	 * @param parent
+	 *            the parent composite to contain the dialog area
+	 */
+	protected void createTable(Composite parent) {
+		final Text filterText = new Text(parent, SWT.BORDER | SWT.SEARCH | SWT.ICON_CANCEL);
+		filterText.setLayoutData(GridDataFactory.fillDefaults().create());
+		filterText.setMessage(WorkbenchMessages.get().AboutPluginsDialog_filterTextMessage);
+		filterText.setFocus();
+
+		vendorInfo = new TableViewer(parent, SWT.H_SCROLL | SWT.V_SCROLL
+				| SWT.SINGLE | SWT.FULL_SELECTION | SWT.BORDER);
+		vendorInfo.setUseHashlookup(true);
+		vendorInfo.getTable().setHeaderVisible(true);
+		vendorInfo.getTable().setLinesVisible(true);
+		vendorInfo.getTable().setFont(parent.getFont());
+		vendorInfo.addSelectionChangedListener(event -> checkEnablement());
+
+		final TableComparator comparator = new TableComparator();
+		vendorInfo.setComparator(comparator);
+		int[] columnWidths = {
+				convertHorizontalDLUsToPixels(30), // signature
+				convertHorizontalDLUsToPixels(120),
+				convertHorizontalDLUsToPixels(120),
+				convertHorizontalDLUsToPixels(70),
+				convertHorizontalDLUsToPixels(130), };
+
+		// create table headers
+		for (int i = 0; i < columnTitles.length; i++) {
+			TableColumn column = new TableColumn(vendorInfo.getTable(),
+					SWT.NULL);
+			if (i == PLUGIN_NAME_COLUMN_INDEX) { // prime initial sorting
+				updateTableSorting(i);
+			}
+			column.setWidth(columnWidths[i]);
+			column.setText(columnTitles[i]);
+			final int columnIndex = i;
+			column.addSelectionListener(new SelectionAdapter() {
+                @Override
+                public void widgetSelected(SelectionEvent e) {
+                    updateTableSorting(columnIndex);
+                }
+            });
+		}
+
+		vendorInfo.setContentProvider(new ArrayContentProvider());
+		vendorInfo.setLabelProvider(new BundleTableLabelProvider());
+
+		final BundlePatternFilter searchFilter = new BundlePatternFilter();
+		filterText.addModifyListener(e -> {
+			searchFilter.setPattern(filterText.getText());
+			vendorInfo.refresh();
+		});
+		vendorInfo.addFilter(searchFilter);
+
+		GridData gridData = new GridData(GridData.FILL, GridData.FILL, true,
+				true);
+		gridData.heightHint = convertVerticalDLUsToPixels(TABLE_HEIGHT);
+		vendorInfo.getTable().setLayoutData(gridData);
+
+		calculateAboutBundleData(vendorInfo::setInput, parent.getDisplay());
+	}
+
+	/**
+	 * Update the sort information on both the comparator and the table.
+	 *
+	 * @param columnIndex
+	 *            the index to sort by
+	 * @since 3.4
+	 */
+	private void updateTableSorting(final int columnIndex) {
+		TableComparator comparator = (TableComparator) vendorInfo
+				.getComparator();
+		// toggle direction if it's the same column
+		if (columnIndex == comparator.getSortColumn()) {
+			comparator.setAscending(!comparator.isAscending());
+		}
+		comparator.setSortColumn(columnIndex);
+		vendorInfo.getTable().setSortColumn(
+				vendorInfo.getTable().getColumn(columnIndex));
+		vendorInfo.getTable().setSortDirection(
+				comparator.isAscending() ? SWT.UP : SWT.DOWN);
+		vendorInfo.refresh(false);
+	}
+
+	/**
+	 * Return an URL to the plugin's about.html file (what is shown when
+	 * "More info" is pressed) or null if no such file exists. The method does
+	 * nl lookup to allow for i18n.
+	 *
+	 * @param bundleInfo
+	 *            the bundle info
+	 * @param makeLocal
+	 *            whether to make the about content local
+	 * @return the URL or <code>null</code>
+	 */
+	private URL getMoreInfoURL(AboutBundleData bundleInfo, boolean makeLocal) {
+		Bundle bundle = Platform.getBundle(bundleInfo.getId());
+		if (bundle == null) {
+			return null;
+		}
+
+		URL aboutUrl = FileLocator.find(bundle, baseNLPath.append(PLUGININFO), null);
+		if (!makeLocal) {
+			return aboutUrl;
+		}
+		if (aboutUrl != null) {
+			try {
+				URL result = FileLocator.toFileURL(aboutUrl);
+				try {
+					// Make local all content in the "about" directory.
+					// This is needed to handle jar'ed plug-ins.
+					// See Bug 88240 [About] About dialog needs to extract
+					// subdirs.
+					URL about = new URL(aboutUrl, "about_files"); //$NON-NLS-1$
+					if (about != null) {
+						FileLocator.toFileURL(about);
+					}
+				} catch (IOException e) {
+					// skip the about dir if its not found or there are other
+					// problems.
+				}
+				return result;
+			} catch (IOException e) {
+				// do nothing
+			}
+		}
+		return null;
+	}
+
+	@Override
+	String getId() {
+		return ID;
+	}
+
+	private void checkEnablement() {
+		// enable if there is an item selected and that
+		// item has additional info
+		IStructuredSelection selection = vendorInfo.getStructuredSelection();
+		if (selection.getFirstElement() instanceof AboutBundleData) {
+			AboutBundleData selected = (AboutBundleData) selection
+					.getFirstElement();
+			moreInfo.setEnabled(selectionHasInfo(selected));
+			signingInfo.setEnabled(true);
+			if (signingArea != null) {
+				signingArea.setData(selected);
+			}
+		} else {
+			signingInfo.setEnabled(false);
+			moreInfo.setEnabled(false);
+		}
+	}
+
+	@Override
+	protected void buttonPressed(int buttonId) {
+		switch (buttonId) {
+		case MORE_ID:
+			handleMoreInfoPressed();
+			break;
+		case SIGNING_ID:
+			handleSigningInfoPressed();
+			break;
+		case COLUMNS_ID:
+			handleColumnsPressed();
+			break;
+		default:
+			super.buttonPressed(buttonId);
+			break;
+		}
+	}
+
+	/**
+	 * Check if the currently selected plugin has additional information to
+	 * show.
+	 *
+	 * @param bundleInfo
+	 *
+	 * @return true if the selected plugin has additional info available to
+	 *         display
+	 */
+	private boolean selectionHasInfo(AboutBundleData bundleInfo) {
+
+		URL infoURL = getMoreInfoURL(bundleInfo, false);
+
+		// only report ini problems if the -debug command line argument is used
+		if (infoURL == null && WorkbenchPlugin.DEBUG) {
+			WorkbenchPlugin.log("Problem reading plugin info for: " //$NON-NLS-1$
+					+ bundleInfo.getName());
+		}
+
+		return infoURL != null;
+	}
+
+	/**
+	 * The More Info button was pressed. Open a browser showing the license
+	 * information for the selected bundle or an error dialog if the browser
+	 * cannot be opened.
+	 */
+	protected void handleMoreInfoPressed() {
+		if (vendorInfo == null) {
+			return;
+		}
+
+		if (vendorInfo.getSelection().isEmpty())
+			return;
+
+		AboutBundleData bundleInfo = (AboutBundleData) vendorInfo.getStructuredSelection().getFirstElement();
+
+		if (!AboutUtils.openBrowser(getShell(),
+				getMoreInfoURL(bundleInfo, true))) {
+			String message = NLS.bind(
+					WorkbenchMessages.get().AboutPluginsDialog_unableToOpenFile,
+					PLUGININFO, bundleInfo.getId());
+			StatusUtil.handleStatus(
+					WorkbenchMessages.get().AboutPluginsDialog_errorTitle
+							+ ": " + message, StatusManager.SHOW, getShell()); //$NON-NLS-1$
+		}
+	}
+
+	/**
+	 *
+	 */
+	private void handleColumnsPressed() {
+		ConfigureColumns.forTable(vendorInfo.getTable(), this);
+	}
+}
+
+class TableComparator extends ViewerComparator {
+
+	private int sortColumn = 0;
+	private int lastSortColumn = 0;
+	private boolean ascending = true;
+	private boolean lastAscending = true;
+
+	@Override
+	public int compare(Viewer viewer, Object e1, Object e2) {
+		if (sortColumn == 0 && e1 instanceof AboutBundleData
+				&& e2 instanceof AboutBundleData) {
+			AboutBundleData d1 = (AboutBundleData) e1;
+			AboutBundleData d2 = (AboutBundleData) e2;
+			int diff = getSignedSortValue(d1) - getSignedSortValue(d2);
+			// If values are different, or there is no secondary column defined,
+			// we are done
+			if (diff != 0 || lastSortColumn == 0)
+				return ascending ? diff : -diff;
+			// try a secondary sort
+			if (viewer instanceof TableViewer) {
+				TableViewer tableViewer = (TableViewer) viewer;
+				IBaseLabelProvider baseLabel = tableViewer.getLabelProvider();
+				if (baseLabel instanceof ITableLabelProvider) {
+					ITableLabelProvider tableProvider = (ITableLabelProvider) baseLabel;
+					String e1p = tableProvider
+							.getColumnText(e1, lastSortColumn);
+					String e2p = tableProvider
+							.getColumnText(e2, lastSortColumn);
+					int result = getComparator().compare(e1p, e2p);
+					return lastAscending ? result : (-1) * result;
+				}
+			}
+			// we couldn't determine a secondary sort, call it equal
+			return 0;
+		}
+		if (viewer instanceof TableViewer) {
+			TableViewer tableViewer = (TableViewer) viewer;
+			IBaseLabelProvider baseLabel = tableViewer.getLabelProvider();
+			if (baseLabel instanceof ITableLabelProvider) {
+				ITableLabelProvider tableProvider = (ITableLabelProvider) baseLabel;
+				String e1p = tableProvider.getColumnText(e1, sortColumn);
+				String e2p = tableProvider.getColumnText(e2, sortColumn);
+				int result = getComparator().compare(e1p, e2p);
+				// Secondary column sort
+				if (result == 0) {
+					if (lastSortColumn != 0) {
+						e1p = tableProvider.getColumnText(e1, lastSortColumn);
+						e2p = tableProvider.getColumnText(e2, lastSortColumn);
+						result = getComparator().compare(e1p, e2p);
+						return lastAscending ? result : (-1) * result;
+					} // secondary sort is by column 0
+					if (e1 instanceof AboutBundleData
+							&& e2 instanceof AboutBundleData) {
+						AboutBundleData d1 = (AboutBundleData) e1;
+						AboutBundleData d2 = (AboutBundleData) e2;
+						int diff = getSignedSortValue(d1)
+								- getSignedSortValue(d2);
+						return lastAscending ? diff : -diff;
+					}
+				}
+				// primary column sort
+				return ascending ? result : (-1) * result;
+			}
+		}
+
+		return super.compare(viewer, e1, e2);
+	}
+
+	/**
+	 * @param data
+	 * @return a sort value depending on the signed state
+	 */
+	private int getSignedSortValue(AboutBundleData data) {
+		if (!data.isSignedDetermined()) {
+			return 0;
+		} else if (data.isSigned()) {
+			return 1;
+		} else {
+			return -1;
+		}
+	}
+
+	/**
+	 * @return Returns the sortColumn.
+	 */
+	public int getSortColumn() {
+		return sortColumn;
+	}
+
+	/**
+	 * @param sortColumn
+	 *            The sortColumn to set.
+	 */
+	public void setSortColumn(int sortColumn) {
+		if (this.sortColumn != sortColumn) {
+			lastSortColumn = this.sortColumn;
+			lastAscending = this.ascending;
+			this.sortColumn = sortColumn;
+		}
+	}
+
+	/**
+	 * @return Returns the ascending.
+	 */
+	public boolean isAscending() {
+		return ascending;
+	}
+
+	/**
+	 * @param ascending
+	 *            The ascending to set.
+	 */
+	public void setAscending(boolean ascending) {
+		this.ascending = ascending;
+	}
+}
+
+class BundlePatternFilter extends ViewerFilter {
+
+	private StringMatcher matcher;
+
+	public void setPattern(String searchPattern) {
+		if (searchPattern == null || searchPattern.length() == 0) {
+			this.matcher = null;
+		} else {
+			String pattern = "*" + searchPattern + "*"; //$NON-NLS-1$//$NON-NLS-2$
+			this.matcher = new StringMatcher(pattern, true, false);
+		}
+	}
+
+	@Override
+	public boolean select(Viewer viewer, Object parentElement, Object element) {
+		if (matcher == null) {
+			return true;
+		}
+
+		if (element instanceof AboutBundleData) {
+			AboutBundleData data = (AboutBundleData) element;
+			return matcher.match(data.getName()) || matcher.match(data.getProviderName())
+					|| matcher.match(data.getId());
+		}
+		return true;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/AboutUtils.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/AboutUtils.java
new file mode 100644
index 0000000..5d7aba5
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/AboutUtils.java
@@ -0,0 +1,270 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.about;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.browser.IWebBrowser;
+import org.eclipse.ui.browser.IWorkbenchBrowserSupport;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+/**
+ * Manages links in styled text.
+ */
+
+public class AboutUtils {
+
+	private final static String ERROR_LOG_COPY_FILENAME = "log"; //$NON-NLS-1$
+
+	/**
+	 * Scan the contents of the about text
+	 *
+	 * @param s
+	 * @return
+	 */
+	public static AboutItem scan(String s) {
+		ArrayList linkRanges = new ArrayList();
+		ArrayList links = new ArrayList();
+
+		// slightly modified version of jface url detection
+		// see org.eclipse.jface.text.hyperlink.URLHyperlinkDetector
+
+		int urlSeparatorOffset = s.indexOf("://"); //$NON-NLS-1$
+		while (urlSeparatorOffset >= 0) {
+
+			boolean startDoubleQuote = false;
+
+			// URL protocol (left to "://")
+			int urlOffset = urlSeparatorOffset;
+			char ch;
+			do {
+				urlOffset--;
+				ch = ' ';
+				if (urlOffset > -1)
+					ch = s.charAt(urlOffset);
+				startDoubleQuote = ch == '"';
+			} while (Character.isUnicodeIdentifierStart(ch));
+			urlOffset++;
+
+			// Right to "://"
+			StringTokenizer tokenizer = new StringTokenizer(s
+					.substring(urlSeparatorOffset + 3), " \t\n\r\f<>", false); //$NON-NLS-1$
+			if (!tokenizer.hasMoreTokens())
+				return null;
+
+			int urlLength = tokenizer.nextToken().length() + 3
+					+ urlSeparatorOffset - urlOffset;
+
+			if (startDoubleQuote) {
+				int endOffset = -1;
+				int nextDoubleQuote = s.indexOf('"', urlOffset);
+				int nextWhitespace = s.indexOf(' ', urlOffset);
+				if (nextDoubleQuote != -1 && nextWhitespace != -1)
+					endOffset = Math.min(nextDoubleQuote, nextWhitespace);
+				else if (nextDoubleQuote != -1)
+					endOffset = nextDoubleQuote;
+				else if (nextWhitespace != -1)
+					endOffset = nextWhitespace;
+				if (endOffset != -1)
+					urlLength = endOffset - urlOffset;
+			}
+
+			linkRanges.add(new int[] { urlOffset, urlLength });
+			links.add(s.substring(urlOffset, urlOffset + urlLength));
+
+			urlSeparatorOffset = s.indexOf("://", urlOffset + urlLength + 1); //$NON-NLS-1$
+		}
+		return new AboutItem(s, (int[][]) linkRanges.toArray(new int[linkRanges
+				.size()][2]), (String[]) links
+				.toArray(new String[links.size()]));
+	}
+
+	/**
+	 * Open a browser with the argument title on the argument url. If the url
+	 * refers to a resource within a bundle, then a temp copy of the file will
+	 * be extracted and opened.
+	 *
+	 * @see <code>Platform.asLocalUrl</code>
+	 * @param url
+	 *            The target url to be displayed, null will be safely ignored
+	 * @return true if the url was successfully displayed and false otherwise
+	 */
+	public static boolean openBrowser(Shell shell, URL url) {
+		if (url != null) {
+			try {
+				url = Platform.asLocalURL(url);
+			} catch (IOException e) {
+				return false;
+			}
+		}
+		if (url == null) {
+			return false;
+		}
+		openLink(shell, url.toString());
+		return true;
+	}
+
+	/**
+	 * Open a link
+	 */
+	public static void openLink(Shell shell, String href) {
+		// format the href for an html file (file:///<filename.html>
+		// required for Mac only.
+		if (href.startsWith("file:")) { //$NON-NLS-1$
+			href = href.substring(5);
+			while (href.startsWith("/")) { //$NON-NLS-1$
+				href = href.substring(1);
+			}
+			href = "file:///" + href; //$NON-NLS-1$
+		}
+		IWorkbenchBrowserSupport support = PlatformUI.getWorkbench()
+				.getBrowserSupport();
+		try {
+			IWebBrowser browser = support.getExternalBrowser();
+			browser.openURL(new URL(urlEncodeForSpaces(href.toCharArray())));
+		} catch (MalformedURLException e) {
+			openWebBrowserError(shell, href, e);
+		} catch (PartInitException e) {
+			openWebBrowserError(shell, href, e);
+		}
+	}
+
+	/**
+	 * This method encodes the url, removes the spaces from the url and replaces
+	 * the same with <code>"%20"</code>. This method is required to fix Bug
+	 * 77840.
+	 *
+	 * @since 3.0.2
+	 */
+	private static String urlEncodeForSpaces(char[] input) {
+		StringBuffer retu = new StringBuffer(input.length);
+		for (char element : input) {
+			if (element == ' ') {
+				retu.append("%20"); //$NON-NLS-1$
+			} else {
+				retu.append(element);
+			}
+		}
+		return retu.toString();
+	}
+
+	/**
+	 * display an error message
+	 */
+	private static void openWebBrowserError(Shell shell, final String href,
+			final Throwable t) {
+		String title = WorkbenchMessages.get().ProductInfoDialog_errorTitle;
+		String msg = NLS.bind(
+				WorkbenchMessages.get().ProductInfoDialog_unableToOpenWebBrowser,
+				href);
+		IStatus status = WorkbenchPlugin.getStatus(t);
+		StatusUtil.handleStatus(status, title + ": " + msg, StatusManager.SHOW, //$NON-NLS-1$
+				shell);
+	}
+
+	public static void openErrorLogBrowser(Shell shell) {
+		String filename = Platform.getLogFileLocation().toOSString();
+
+		File log = new File(filename);
+		if (log.exists()) {
+			// Make a copy of the file with a temporary name.
+			// Working around an issue with windows file associations/browser
+			// malfunction whereby the browser doesn't open on ".log" and we
+			// aren't returned an error.
+			// See https://bugs.eclipse.org/bugs/show_bug.cgi?id=97783
+			File logCopy = makeDisplayCopy(log);
+			if (logCopy != null) {
+				AboutUtils.openLink(shell,
+						"file:///" + logCopy.getAbsolutePath()); //$NON-NLS-1$
+				return;
+			}
+			// Couldn't make copy, try to open the original log.
+			// We try the original in this case rather than putting up an error,
+			// because the copy could fail due to an I/O or out of space
+			// problem.
+			// In that case we may still be able to show the original log,
+			// depending on the platform. The risk is that users with
+			// configurations that have bug #97783 will still get nothing
+			// (vs. an error) but we'd rather
+			// try again than put up an error dialog on platforms where the
+			// ability to view the original log works just fine.
+			AboutUtils.openLink(shell, "file:///" + filename); //$NON-NLS-1$
+			return;
+		}
+		MessageDialog.openInformation(shell,
+				WorkbenchMessages.get().AboutSystemDialog_noLogTitle, NLS.bind(
+						WorkbenchMessages.get().AboutSystemDialog_noLogMessage,
+						filename));
+	}
+
+	/**
+	 * Returns a copy of the given file to be used for display in a browser.
+	 *
+	 * @return the file, or <code>null</code>
+	 */
+	private static File makeDisplayCopy(File file) {
+		IPath path = WorkbenchPlugin.getDefault().getDataLocation();
+		if (path == null) {
+			return null;
+		}
+		path = path.append(ERROR_LOG_COPY_FILENAME);
+		File copy = path.toFile();
+		FileReader in = null;
+		FileWriter out = null;
+		try {
+			in = new FileReader(file);
+			// don't append data, overwrite what was there
+			out = new FileWriter(copy);
+			char buffer[] = new char[4096];
+			int count;
+			while ((count = in.read(buffer, 0, buffer.length)) > 0) {
+				out.write(buffer, 0, count);
+			}
+		} catch (FileNotFoundException e) {
+			return null;
+		} catch (IOException e) {
+			return null;
+		} finally {
+			try {
+				if (in != null) {
+					in.close();
+				}
+				if (out != null) {
+					out.close();
+				}
+			} catch (IOException e) {
+				return null;
+			}
+		}
+		return copy;
+
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/BundleSigningInfo.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/BundleSigningInfo.java
new file mode 100644
index 0000000..f475f43
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/BundleSigningInfo.java
@@ -0,0 +1,290 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 474273
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.about;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.text.DateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+import java.util.StringTokenizer;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.IJobFunction;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.osgi.signedcontent.SignedContent;
+import org.eclipse.osgi.signedcontent.SignedContentFactory;
+import org.eclipse.osgi.signedcontent.SignerInfo;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.statushandlers.StatusManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * @since 3.3
+ *
+ */
+public class BundleSigningInfo {
+
+	private Composite composite;
+	private Text date;
+	private Text certificate;
+	private AboutBundleData data;
+
+	public void setData(AboutBundleData data) {
+		this.data = data;
+		startJobs();
+	}
+
+	public Control createContents(Composite parent) {
+
+		composite = new Composite(parent, SWT.BORDER);
+		composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+		GridLayout layout = new GridLayout(2, false);
+		layout.marginHeight = 0;
+		layout.marginWidth = 0;
+		composite.setLayout(layout);
+
+		// date
+		{
+			Label label = new Label(composite, SWT.NONE);
+			label.setText(WorkbenchMessages.get().BundleSigningTray_Signing_Date);
+			GridData data = new GridData(SWT.FILL, SWT.BEGINNING, true, false);
+			date = new Text(composite, SWT.READ_ONLY);
+			GC gc = new GC(date);
+			gc.setFont(JFaceResources.getDialogFont());
+			Point size = gc.stringExtent(DateFormat.getDateTimeInstance()
+					.format(new Date()));
+			data.widthHint = size.x;
+			gc.dispose();
+			date.setText(WorkbenchMessages.get().BundleSigningTray_Working);
+			date.setLayoutData(data);
+		}
+		// signer
+		{
+			Label label = new Label(composite, SWT.NONE);
+			label
+					.setText(WorkbenchMessages.get().BundleSigningTray_Signing_Certificate);
+			GridData data = new GridData(SWT.BEGINNING, SWT.BEGINNING, true,
+					false);
+			data.horizontalSpan = 2;
+			data = new GridData(SWT.FILL, SWT.FILL, true, true);
+			data.horizontalSpan = 2;
+			certificate = new Text(composite, SWT.READ_ONLY | SWT.MULTI
+					| SWT.WRAP);
+			certificate.setText(WorkbenchMessages.get().BundleSigningTray_Working);
+			certificate.setLayoutData(data);
+		}
+		Dialog.applyDialogFont(composite);
+
+		startJobs(); // start the jobs that will prime the content
+		return composite;
+	}
+
+	/**
+	 *
+	 */
+	private void startJobs() {
+		if (!isOpen())
+			return;
+		certificate.setText(WorkbenchMessages.get().BundleSigningTray_Working);
+		date.setText(WorkbenchMessages.get().BundleSigningTray_Working);
+		final BundleContext bundleContext = WorkbenchPlugin.getDefault()
+				.getBundleContext();
+		final ServiceReference factoryRef = bundleContext
+				.getServiceReference(SignedContentFactory.class.getName());
+		if (factoryRef == null) {
+			StatusManager
+					.getManager()
+					.handle(
+							new Status(
+									IStatus.WARNING,
+									WorkbenchPlugin.PI_WORKBENCH,
+									WorkbenchMessages.get().BundleSigningTray_Cant_Find_Service),
+							StatusManager.LOG);
+			return;
+		}
+
+		final SignedContentFactory contentFactory = (SignedContentFactory) bundleContext
+				.getService(factoryRef);
+		if (contentFactory == null) {
+			StatusManager
+					.getManager()
+					.handle(
+							new Status(
+									IStatus.WARNING,
+									WorkbenchPlugin.PI_WORKBENCH,
+									WorkbenchMessages.get().BundleSigningTray_Cant_Find_Service),
+							StatusManager.LOG);
+			return;
+		}
+
+		final AboutBundleData myData = data;
+		final Job signerJob = Job.create(NLS.bind(
+				WorkbenchMessages.get().BundleSigningTray_Determine_Signer_For,
+				myData.getId()), (IJobFunction) monitor -> {
+					try {
+						if (myData != data)
+							return Status.OK_STATUS;
+						SignedContent signedContent = contentFactory
+								.getSignedContent(myData.getBundle());
+						if (myData != data)
+							return Status.OK_STATUS;
+						SignerInfo[] signers = signedContent.getSignerInfos();
+						final String signerText, dateText;
+						if (!isOpen() && BundleSigningInfo.this.data == myData)
+							return Status.OK_STATUS;
+
+						if (signers.length == 0) {
+							signerText = WorkbenchMessages.get().BundleSigningTray_Unsigned;
+							dateText = WorkbenchMessages.get().BundleSigningTray_Unsigned;
+						} else {
+							Properties[] certs = parseCerts(signers[0]
+									.getCertificateChain());
+							if (certs.length == 0)
+								signerText = WorkbenchMessages.get().BundleSigningTray_Unknown;
+							else {
+								StringBuffer buffer = new StringBuffer();
+								for (Iterator i = certs[0].entrySet().iterator(); i
+										.hasNext();) {
+									Map.Entry entry = (Entry) i.next();
+									buffer.append(entry.getKey());
+									buffer.append('=');
+									buffer.append(entry.getValue());
+									if (i.hasNext())
+										buffer.append('\n');
+								}
+								signerText = buffer.toString();
+							}
+
+							Date signDate = signedContent
+									.getSigningTime(signers[0]);
+							if (signDate != null)
+								dateText = DateFormat.getDateTimeInstance().format(
+										signDate);
+							else
+								dateText = WorkbenchMessages.get().BundleSigningTray_Unknown;
+						}
+
+						PlatformUI.getWorkbench().getDisplay().asyncExec(
+								() -> {
+									// check to see if the tray is still visible
+									// and if
+									// we're still looking at the same item
+									if (!isOpen()
+											&& BundleSigningInfo.this.data != myData)
+										return;
+									certificate.setText(signerText);
+									date.setText(dateText);
+								});
+
+					} catch (IOException e1) {
+						return new Status(IStatus.ERROR,
+								WorkbenchPlugin.PI_WORKBENCH, e1.getMessage(), e1);
+					} catch (GeneralSecurityException e2) {
+						return new Status(IStatus.ERROR,
+								WorkbenchPlugin.PI_WORKBENCH, e2.getMessage(), e2);
+					}
+					return Status.OK_STATUS;
+				});
+		signerJob.setSystem(true);
+		signerJob.belongsTo(signerJob);
+		signerJob.schedule();
+
+		Job cleanup = Job.create(WorkbenchMessages.get().BundleSigningTray_Unget_Signing_Service, (IJobFunction) monitor -> {
+			try {
+				Job.getJobManager().join(signerJob, monitor);
+			} catch (OperationCanceledException e1) {
+			} catch (InterruptedException e2) {
+			}
+			bundleContext.ungetService(factoryRef);
+			return Status.OK_STATUS;
+		});
+		cleanup.setSystem(true);
+		cleanup.schedule();
+
+	}
+
+	/**
+	 *
+	 */
+	private boolean isOpen() {
+		return certificate != null && !certificate.isDisposed();
+	}
+
+	private Properties[] parseCerts(Certificate[] chain) {
+		List certs = new ArrayList(chain.length);
+		for (int i = 0; i < chain.length; i++) {
+			if (!(chain[i] instanceof X509Certificate))
+				continue;
+			Map cert = parseCert(((X509Certificate) chain[i]).getSubjectDN()
+					.getName());
+			if (cert != null)
+				certs.add(cert);
+		}
+		return (Properties[]) certs.toArray(new Properties[certs.size()]);
+
+	}
+
+	/**
+	 * @param certString
+	 * @return
+	 */
+	private Properties parseCert(String certString) {
+		StringTokenizer toker = new StringTokenizer(certString, ","); //$NON-NLS-1$
+		Properties cert = new Properties();
+		while (toker.hasMoreTokens()) {
+			String pair = toker.nextToken();
+			int idx = pair.indexOf('=');
+			if (idx > 0 && idx < pair.length() - 2) {
+				String key = pair.substring(0, idx).trim();
+				String value = pair.substring(idx + 1).trim();
+				if (value.length() > 2) {
+					if (value.charAt(0) == '\"')
+						value = value.substring(1);
+
+					if (value.charAt(value.length() - 1) == '\"')
+						value = value.substring(0, value.length() - 1);
+				}
+				cert.setProperty(key, value);
+			}
+		}
+		return cert;
+	}
+
+	public void dispose() {
+		composite.dispose();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/ConfigurationLogDefaultSection.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/ConfigurationLogDefaultSection.java
new file mode 100644
index 0000000..722a6af
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/ConfigurationLogDefaultSection.java
@@ -0,0 +1,189 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.internal.about;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Properties;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IBundleGroup;
+import org.eclipse.core.runtime.IBundleGroupProvider;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.IPreferencesService;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.about.ISystemSummarySection;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.osgi.framework.Bundle;
+
+/**
+ * This class puts basic platform information into the system summary log.  This
+ * includes sections for the java properties, the ids of all installed features
+ * and plugins, as well as a the current contents of the preferences service.
+ *
+ * @since 3.0
+ */
+public class ConfigurationLogDefaultSection implements ISystemSummarySection {
+
+    private static final String ECLIPSE_PROPERTY_PREFIX = "eclipse."; //$NON-NLS-1$
+
+    @Override
+	public void write(PrintWriter writer) {
+        appendProperties(writer);
+        appendFeatures(writer);
+        appendRegistry(writer);
+        appendUserPreferences(writer);
+    }
+
+    /**
+     * Appends the <code>System</code> properties.
+     */
+    private void appendProperties(PrintWriter writer) {
+        writer.println();
+        writer.println(WorkbenchMessages.get().SystemSummary_systemProperties);
+        Properties properties = System.getProperties();
+        SortedSet set = new TreeSet((o1, o2) -> {
+		    String s1 = (String) o1;
+		    String s2 = (String) o2;
+		    return s1.compareTo(s2);
+		});
+        set.addAll(properties.keySet());
+        Iterator i = set.iterator();
+        while (i.hasNext()) {
+            String key = (String)i.next();
+            String value = properties.getProperty(key);
+
+            writer.print(key);
+            writer.print('=');
+
+            // some types of properties have special characters embedded
+            if (key.startsWith(ECLIPSE_PROPERTY_PREFIX)) {
+				printEclipseProperty(writer, value);
+            } else if (key.toUpperCase().indexOf("PASSWORD") != -1) { //$NON-NLS-1$
+            	// We should obscure any property that may be a password
+            	for (int j = 0; j < value.length(); j++) {
+					writer.print('*');
+				}
+            	writer.println();
+			} else {
+				writer.println(value);
+			}
+        }
+    }
+
+    private static void printEclipseProperty(PrintWriter writer, String value) {
+		String[] lines = value.split("\n"); //$NON-NLS-1$
+        for (String line : lines) {
+			writer.println(line);
+		}
+    }
+
+    /**
+     * Appends the installed and configured features.
+     */
+    private void appendFeatures(PrintWriter writer) {
+        writer.println();
+        writer.println(WorkbenchMessages.get().SystemSummary_features);
+
+        IBundleGroupProvider[] providers = Platform.getBundleGroupProviders();
+        LinkedList groups = new LinkedList();
+        if (providers != null) {
+			for (IBundleGroupProvider provider : providers) {
+                IBundleGroup[] bundleGroups = provider.getBundleGroups();
+                for (IBundleGroup bundleGroup : bundleGroups) {
+					groups.add(new AboutBundleGroupData(bundleGroup));
+				}
+            }
+		}
+        AboutBundleGroupData[] bundleGroupInfos = (AboutBundleGroupData[]) groups
+                .toArray(new AboutBundleGroupData[0]);
+
+        AboutData.sortById(false, bundleGroupInfos);
+
+        for (AboutBundleGroupData info : bundleGroupInfos) {
+            String[] args = new String[] { info.getId(), info.getVersion(),
+                    info.getName() };
+            writer.println(NLS.bind(WorkbenchMessages.get().SystemSummary_featureVersion, args));
+        }
+    }
+
+    /**
+     * Appends the contents of the Plugin Registry.
+     */
+    private void appendRegistry(PrintWriter writer) {
+        writer.println();
+        writer.println(WorkbenchMessages.get().SystemSummary_pluginRegistry);
+
+        Bundle[] bundles = WorkbenchPlugin.getDefault().getBundles();
+        AboutBundleData[] bundleInfos = new AboutBundleData[bundles.length];
+
+        for (int i = 0; i < bundles.length; ++i) {
+			bundleInfos[i] = new AboutBundleData(bundles[i]);
+		}
+
+        AboutData.sortById(false, bundleInfos);
+
+        for (AboutBundleData info : bundleInfos) {
+            String[] args = new String[] { info.getId(), info.getVersion(),
+                    info.getName(), info.getStateName() };
+            writer.println(NLS.bind(WorkbenchMessages.get().SystemSummary_descriptorIdVersionState, args));
+        }
+    }
+
+    /**
+     * Appends the preferences
+     */
+    private void appendUserPreferences(PrintWriter writer) {
+        // write the prefs to a byte array
+        IPreferencesService service = Platform.getPreferencesService();
+        IEclipsePreferences node = service.getRootNode();
+        ByteArrayOutputStream stm = new ByteArrayOutputStream();
+        try {
+            service.exportPreferences(node, stm, null);
+        } catch (CoreException e) {
+            writer.println("Error reading preferences " + e.toString());//$NON-NLS-1$
+        }
+
+        // copy the prefs from the byte array to the writer
+        writer.println();
+        writer.println(WorkbenchMessages.get().SystemSummary_userPreferences);
+
+        BufferedReader reader = null;
+        try {
+            ByteArrayInputStream in = new ByteArrayInputStream(stm
+                    .toByteArray());
+            reader = new BufferedReader(new InputStreamReader(in, "8859_1")); //$NON-NLS-1$
+            char[] chars = new char[8192];
+
+            while (true) {
+                int read = reader.read(chars);
+                if (read <= 0) {
+					break;
+				}
+                writer.write(chars, 0, read);
+            }
+        } catch (IOException e) {
+            writer.println("Error reading preferences " + e.toString());//$NON-NLS-1$
+        }
+
+        // ByteArray streams don't need to be closed
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/InstallationDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/InstallationDialog.java
new file mode 100644
index 0000000..d7ad842
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/InstallationDialog.java
@@ -0,0 +1,375 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2015 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.ui.internal.about;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IProduct;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.dialogs.TrayDialog;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.FontMetrics;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.TabFolder;
+import org.eclipse.swt.widgets.TabItem;
+import org.eclipse.ui.about.IInstallationPageContainer;
+import org.eclipse.ui.about.InstallationPage;
+import org.eclipse.ui.internal.ConfigurationInfo;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * @since 3.5
+ *
+ */
+public class InstallationDialog extends TrayDialog implements
+		IInstallationPageContainer {
+	class ButtonManager {
+
+		private Composite composite;
+		HashMap buttonMap = new HashMap(); // page id->Collection of page
+
+		// buttons
+
+		public ButtonManager(Composite composite) {
+			this.composite = composite;
+		}
+
+		public Composite getParent() {
+			return composite;
+		}
+
+		public void update(String currentPageId) {
+			if (composite == null || composite.isDisposed())
+				return;
+			GC metricsGC = new GC(composite);
+			FontMetrics metrics = metricsGC.getFontMetrics();
+			metricsGC.dispose();
+			List buttons = (List) buttonMap.get(currentPageId);
+			Control[] children = composite.getChildren();
+
+			int visibleChildren = 0;
+			Button closeButton = getButton(IDialogConstants.CLOSE_ID);
+
+			for (Control control : children) {
+				if (closeButton == control)
+					closeButton.dispose();
+				else {
+					control.setVisible(false);
+					setButtonLayoutData(metrics, control, false);
+				}
+			}
+			if (buttons != null) {
+				for (int i = 0; i < buttons.size(); i++) {
+					Button button = (Button) buttons.get(i);
+					button.setVisible(true);
+					setButtonLayoutData(metrics, button, true);
+					GridData data = (GridData) button.getLayoutData();
+					data.exclude = false;
+					visibleChildren++;
+				}
+			}
+
+			GridLayout compositeLayout = (GridLayout) composite.getLayout();
+			compositeLayout.numColumns = visibleChildren;
+			composite.layout(true);
+		}
+
+		protected void setButtonLayoutData(FontMetrics metrics, Control button,
+				boolean visible) {
+			GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
+			int widthHint = Dialog.convertHorizontalDLUsToPixels(metrics,
+					IDialogConstants.BUTTON_WIDTH);
+			Point minSize = button.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
+			data.widthHint = Math.max(widthHint, minSize.x);
+			data.exclude = !visible;
+			button.setLayoutData(data);
+		}
+
+		public void addPageButton(String id, Button button) {
+			List list = (List) buttonMap.get(id);
+			if (list == null) {
+				list = new ArrayList(1);
+				buttonMap.put(id, list);
+			}
+			list.add(button);
+		}
+
+		public void clear() {
+			buttonMap = new HashMap();
+		}
+	}
+
+	protected static final String ID = "ID"; //$NON-NLS-1$
+	private static final String DIALOG_SETTINGS_SECTION = "InstallationDialogSettings"; //$NON-NLS-1$
+	private final static int TAB_WIDTH_IN_DLUS = 440;
+	private final static int TAB_HEIGHT_IN_DLUS = 320;
+
+	private static String lastSelectedTabId = null;
+	private TabFolder folder;
+	IServiceLocator serviceLocator;
+	private ButtonManager buttonManager;
+	private Map pageToId = new HashMap();
+	private Dialog modalParent;
+
+	/**
+	 * @param parentShell
+	 * @param locator
+	 */
+	public InstallationDialog(Shell parentShell, IServiceLocator locator) {
+		super(parentShell);
+		serviceLocator = locator;
+
+	}
+
+	@Override
+	protected void configureShell(Shell newShell) {
+		super.configureShell(newShell);
+		String productName = ""; //$NON-NLS-1$
+		IProduct product = Platform.getProduct();
+		if (product != null && product.getName() != null)
+			productName = product.getName();
+		newShell.setText(NLS.bind(
+				WorkbenchMessages.get().InstallationDialog_ShellTitle, productName));
+	}
+
+	@Override
+	protected boolean isResizable() {
+		return true;
+	}
+
+	@Override
+	protected Control createDialogArea(Composite parent) {
+		Composite composite = (Composite) super.createDialogArea(parent);
+
+		folder = new TabFolder(composite, SWT.NONE);
+		configureFolder();
+		createFolderItems(folder);
+
+		GridData folderData = new GridData(SWT.FILL, SWT.FILL, true, true);
+		folderData.widthHint = convertHorizontalDLUsToPixels(TAB_WIDTH_IN_DLUS);
+		folderData.heightHint = convertVerticalDLUsToPixels(TAB_HEIGHT_IN_DLUS);
+		folder.setLayoutData(folderData);
+		folder.addSelectionListener(createFolderSelectionListener());
+		folder.addDisposeListener(e -> releaseContributions());
+		return composite;
+	}
+
+	protected void createFolderItems(TabFolder folder) {
+		IConfigurationElement[] elements = ConfigurationInfo
+				.getSortedExtensions(loadElements());
+		for (IConfigurationElement element : elements) {
+			TabItem item = new TabItem(folder, SWT.NONE);
+			item.setText(element
+					.getAttribute(IWorkbenchRegistryConstants.ATT_NAME));
+			item.setData(element);
+			item.setData(ID, element
+					.getAttribute(IWorkbenchRegistryConstants.ATT_ID));
+
+			Composite control = new Composite(folder, SWT.NONE);
+			control.setLayout(new GridLayout());
+			item.setControl(control);
+		}
+	}
+
+	@Override
+	protected Control createContents(Composite parent) {
+		Control control = super.createContents(parent);
+		boolean selected = false;
+		if (folder.getItemCount() > 0) {
+			if (lastSelectedTabId != null) {
+				TabItem[] items = folder.getItems();
+				for (int i = 0; i < items.length; i++)
+					if (items[i].getData(ID).equals(lastSelectedTabId)) {
+						folder.setSelection(i);
+						tabSelected(items[i]);
+						selected = true;
+						break;
+					}
+			}
+			if (!selected)
+				tabSelected(folder.getItem(0));
+		}
+		// need to reapply the dialog font now that we've created new
+		// tab items
+		Dialog.applyDialogFont(folder);
+		return control;
+	}
+
+	private SelectionListener createFolderSelectionListener() {
+		return new SelectionAdapter()
+        {
+            public void widgetSelected(SelectionEvent e) 
+            {
+                tabSelected((TabItem) e.item);
+            }
+        };
+	}
+
+	/*
+	 * Must be called after contributions and button manager are created.
+	 */
+	private void tabSelected(TabItem item) {
+		if (item.getData() instanceof IConfigurationElement) {
+			final IConfigurationElement element = (IConfigurationElement) item
+					.getData();
+
+			Composite pageComposite = (Composite) item.getControl();
+			try {
+				final InstallationPage page = (InstallationPage) element
+						.createExecutableExtension(IWorkbenchRegistryConstants.ATT_CLASS);
+				page.createControl(pageComposite);
+				// new controls created since the dialog font was applied, so
+				// apply again.
+				Dialog.applyDialogFont(pageComposite);
+				page.setPageContainer(this);
+				// Must be done before creating the buttons because the control
+				// button creation methods
+				// use this map.
+				pageToId.put(page, element
+						.getAttribute(IWorkbenchRegistryConstants.ATT_ID));
+				createButtons(page);
+				item.setData(page);
+				item.addDisposeListener(e -> page.dispose());
+				pageComposite.layout(true, true);
+
+			} catch (CoreException e1) {
+				Label label = new Label(pageComposite, SWT.NONE);
+				label.setText(e1.getMessage());
+				item.setData(null);
+			}
+
+		}
+		String id = (String) item.getData(ID);
+		rememberSelectedTab(id);
+		buttonManager.update(id);
+		Button button = createButton(buttonManager.getParent(),
+				IDialogConstants.CLOSE_ID, IDialogConstants.get().CLOSE_LABEL, true);
+		GridData gd = (GridData) button.getLayoutData();
+		gd.horizontalAlignment = SWT.BEGINNING;
+		gd.horizontalIndent = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH) / 2;
+		// Layout the button bar's parent and all of its children.  We must
+		// cascade through all children because the buttons have changed and
+		// because tray dialog inserts an extra composite in the button bar
+		// hierarchy.
+		getButtonBar().getParent().layout(true, true);
+
+	}
+
+	protected void createButtons(InstallationPage page) {
+		page.createPageButtons(buttonManager.getParent());
+		Dialog.applyDialogFont(buttonManager.getParent());
+	}
+
+	private void rememberSelectedTab(String pageId) {
+		lastSelectedTabId = pageId;
+	}
+
+	@Override
+	protected void createButtonsForButtonBar(Composite parent) {
+		// The button manager will handle the correct sizing of the buttons.
+		// We do not want columns equal width because we are going to add some
+		// padding in the final column (close button).
+		GridLayout layout = (GridLayout) parent.getLayout();
+		layout.makeColumnsEqualWidth = false;
+		buttonManager = new ButtonManager(parent);
+	}
+
+	private void configureFolder() {
+	}
+
+	private IConfigurationElement[] loadElements() {
+		IExtensionPoint point = Platform.getExtensionRegistry()
+				.getExtensionPoint("org.eclipse.ui", "installationPages"); //$NON-NLS-1$ //$NON-NLS-2$
+		return point.getConfigurationElements();
+	}
+
+	@Override
+	protected IDialogSettings getDialogBoundsSettings() {
+		IDialogSettings settings = WorkbenchPlugin.getDefault()
+				.getDialogSettings();
+		IDialogSettings section = settings.getSection(DIALOG_SETTINGS_SECTION);
+		if (section == null) {
+			section = settings.addNewSection(DIALOG_SETTINGS_SECTION);
+		}
+		return section;
+	}
+
+	protected void releaseContributions() {
+		buttonManager.clear();
+	}
+
+	@Override
+	public void closeModalContainers() {
+		close();
+		if (modalParent != null)
+			modalParent.close();
+	}
+
+	@Override
+	protected void buttonPressed(int buttonId) {
+		if (IDialogConstants.CLOSE_ID == buttonId) {
+			okPressed();
+		}
+	}
+
+	@Override
+	public void registerPageButton(InstallationPage page, Button button) {
+		buttonManager.addPageButton(pageToId(page), button);
+	}
+
+	protected String pageToId(InstallationPage page) {
+		String pageId = (String) pageToId.get(page);
+		Assert.isLegal(pageId != null);
+		return pageId;
+	}
+
+	/**
+	 * Set the modal parent dialog that was used to launch this dialog. This
+	 * should be used by any launching dialog so that the {
+	 * {@link #closeModalContainers()} method can be properly implemented.
+	 *
+	 * @param parent
+	 *            the modal parent dialog that launched this dialog, or
+	 *            <code>null</code> if there was no parent.
+	 *
+	 *            This is an internal method and should not be used outside of
+	 *            platform UI.
+	 */
+	public void setModalParent(Dialog parent) {
+		this.modalParent = parent;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/InstallationHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/InstallationHandler.java
new file mode 100644
index 0000000..61e2f78
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/InstallationHandler.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2015 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.ui.internal.about;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+public class InstallationHandler extends AbstractHandler{
+
+	@Override
+	public Object execute(ExecutionEvent event) {
+		IWorkbenchWindow workbenchWindow = HandlerUtil.getActiveWorkbenchWindow(event);
+		if (workbenchWindow == null)
+			workbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+		InstallationDialog dialog = new InstallationDialog(HandlerUtil.getActiveShell(event), workbenchWindow);
+		dialog.open();
+		return null;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/ProductInfoDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/ProductInfoDialog.java
new file mode 100644
index 0000000..73ed279
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/ProductInfoDialog.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.about;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.TabFolder;
+import org.eclipse.swt.widgets.TabItem;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.about.InstallationPage;
+
+/**
+ * Abstract superclass of the individual about dialogs that appear outside of
+ * the InstallationDialog. These dialogs contain a single installation page, and
+ * scope the page to something more specific than it would be in the standard
+ * installation dialog.
+ *
+ * It is important that the visibility and enablement expressions of
+ * contributions to this dialog, and the source variables that drive them, do
+ * not conflict with those used inside the normal InstallationDialog. Otherwise,
+ * the button manager of the InstallationDialog will be affected by changes in
+ * the launched dialog. Where commands have enablement expressions in this
+ * dialog, we use a unique command id so that there are no handler conflicts
+ * with the regular dialog.
+ */
+
+public abstract class ProductInfoDialog extends InstallationDialog {
+
+	ProductInfoPage page;
+	String title;
+	String helpContextId;
+
+	protected ProductInfoDialog(Shell shell) {
+		super(shell, PlatformUI.getWorkbench().getActiveWorkbenchWindow());
+	}
+
+	public void initializeDialog(ProductInfoPage page, String title,
+			String helpContextId) {
+		this.page = page;
+		this.title = title;
+		this.helpContextId = helpContextId;
+	}
+
+	@Override
+	protected void createFolderItems(TabFolder folder) {
+		TabItem item = new TabItem(folder, SWT.NONE);
+		item.setText(title);
+		Composite control = new Composite(folder, SWT.BORDER);
+		control.setLayout(new GridLayout());
+		item.setControl(control);
+		page.createControl(control);
+		item.setData(page);
+		item.setData(ID, page.getId());
+		page.setPageContainer(this);
+		item.addDisposeListener(e -> page.dispose());
+		control.layout(true, true);
+	}
+
+	@Override
+	protected void createButtonsForButtonBar(Composite parent) {
+		super.createButtonsForButtonBar(parent);
+		createButtons(page);
+	}
+
+	@Override
+	protected void configureShell(Shell newShell) {
+		super.configureShell(newShell);
+		newShell.setText(title);
+		if (helpContextId != null)
+			PlatformUI.getWorkbench().getHelpSystem().setHelp(newShell,
+					helpContextId);
+	}
+
+	@Override
+	protected String pageToId(InstallationPage page) {
+		Assert.isLegal(page == this.page);
+		return this.page.getId();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/ProductInfoPage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/ProductInfoPage.java
new file mode 100644
index 0000000..f9d946c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/about/ProductInfoPage.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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.ui.internal.about;
+
+import org.eclipse.core.runtime.IProduct;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.window.IShellProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.about.InstallationPage;
+import org.eclipse.ui.internal.WorkbenchMessages;
+
+/**
+ * Abstract superclass of about dialog installation pages.  The ProductInfoPage
+ * is set up so that the page can be hosted as one of many pages in the
+ * InstallationDialog, or as the only page in a ProductInfoDialog.
+ */
+
+public abstract class ProductInfoPage extends InstallationPage implements
+		IShellProvider {
+
+	private IProduct product;
+
+	private String productName;
+
+	protected IProduct getProduct() {
+		if (product == null)
+			product = Platform.getProduct();
+		return product;
+	}
+
+	public String getProductName() {
+		if (productName == null) {
+			if (getProduct() != null) {
+				productName = getProduct().getName();
+			}
+			if (productName == null) {
+				productName = WorkbenchMessages.get().AboutDialog_defaultProductName;
+			}
+		}
+		return productName;
+	}
+
+	public void setProductName(String name) {
+		productName = name;
+	}
+
+	abstract String getId();
+
+	protected Composite createOuterComposite(Composite parent) {
+		Composite composite = new Composite(parent, SWT.NONE);
+		GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
+		composite.setLayoutData(gd);
+		GridLayout layout = new GridLayout();
+		layout.marginWidth = 0;
+		layout.marginHeight = 0;
+		composite.setLayout(layout);
+		return composite;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/actions/AbstractWorkingSetPulldownDelegate.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/actions/AbstractWorkingSetPulldownDelegate.java
new file mode 100644
index 0000000..098a1ea
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/actions/AbstractWorkingSetPulldownDelegate.java
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.actions;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.swt.events.MenuAdapter;
+import org.eclipse.swt.events.MenuEvent;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.IWorkbenchWindowActionDelegate;
+import org.eclipse.ui.IWorkbenchWindowPulldownDelegate2;
+import org.eclipse.ui.IWorkingSet;
+import org.eclipse.ui.activities.WorkbenchActivityHelper;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.registry.WorkingSetRegistry;
+
+/**
+ * Baseclass for working set pulldown actions.
+ *
+ * @since 3.3
+ */
+public abstract class AbstractWorkingSetPulldownDelegate implements
+		IWorkbenchWindowActionDelegate, IWorkbenchWindowPulldownDelegate2 {
+
+	private Menu menubarMenu;
+
+	private Menu toolbarMenu;
+
+	private ISelection selection;
+
+	private IWorkbenchWindow window;
+
+	/**
+	 *
+	 */
+	public AbstractWorkingSetPulldownDelegate() {
+		super();
+	}
+
+	@Override
+	public void dispose() {
+		if (menubarMenu != null) {
+			menubarMenu.dispose();
+			menubarMenu = null;
+		}
+		if (toolbarMenu != null) {
+			toolbarMenu.dispose();
+			toolbarMenu = null;
+		}
+	}
+
+	@Override
+	public Menu getMenu(Control parent) {
+		if (toolbarMenu != null) {
+			toolbarMenu.dispose();
+		}
+		toolbarMenu = new Menu(parent);
+		initMenu(toolbarMenu);
+		return toolbarMenu;
+	}
+
+	@Override
+	public Menu getMenu(Menu parent) {
+		if (menubarMenu != null) {
+			menubarMenu.dispose();
+		}
+		menubarMenu = new Menu(parent);
+		initMenu(menubarMenu);
+		return menubarMenu;
+	}
+
+	/**
+	 * Creates the menu for the action
+	 */
+	private void initMenu(Menu menu) {
+		menu.addMenuListener(new MenuAdapter() {
+			@Override
+			public void menuShown(MenuEvent e) {
+				Menu m = (Menu) e.widget;
+				MenuItem[] items = m.getItems();
+				for (MenuItem item : items) {
+					item.dispose();
+				}
+				fillMenu(m);
+			}
+
+		});
+	}
+
+	/**
+	 * @param m
+	 */
+	protected abstract void fillMenu(Menu m);
+
+	/**
+	 * Split the working sets known by the manager into arrays based on their
+	 * defining page Id.
+	 *
+	 * @return an array of arrays
+	 */
+	protected IWorkingSet[][] splitSets() {
+		IWorkingSet[] allSets = getWindow().getWorkbench().getWorkingSetManager()
+				.getWorkingSets();
+
+		Map map = new HashMap();
+		WorkingSetRegistry registry = WorkbenchPlugin.getDefault()
+				.getWorkingSetRegistry();
+
+		for (IWorkingSet allSet : allSets) {
+			String setType = allSet.getId();
+			if (WorkbenchActivityHelper.filterItem(registry
+					.getWorkingSetDescriptor(setType))) {
+				continue;
+			}
+			List setsOfType = (List) map.get(setType);
+			if (setsOfType == null) {
+				setsOfType = new ArrayList();
+				map.put(setType, setsOfType);
+			}
+			setsOfType.add(allSet);
+		}
+
+		IWorkingSet[][] typedSets = new IWorkingSet[map.keySet().size()][];
+		int i = 0;
+		for (Iterator iter = map.keySet().iterator(); iter.hasNext();) {
+			List setsOfType = (List) map.get(iter.next());
+			typedSets[i] = new IWorkingSet[setsOfType.size()];
+			setsOfType.toArray(typedSets[i++]);
+		}
+		return typedSets;
+	}
+
+	@Override
+	public void init(IWorkbenchWindow window) {
+		this.window = window;
+	}
+
+	protected IWorkbenchWindow getWindow() {
+		return window;
+	}
+
+	@Override
+	public void selectionChanged(IAction action, ISelection selection) {
+		this.selection = selection;
+	}
+
+	protected ISelection getSelection() {
+		return selection;
+	}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/actions/ClearWorkingSetAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/actions/ClearWorkingSetAction.java
new file mode 100644
index 0000000..0c8ffd0
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/actions/ClearWorkingSetAction.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.actions;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.action.Action;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.WorkingSetFilterActionGroup;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchMessages;
+
+/**
+ * Clears the selected working set in the working set action group.
+ *
+ * @since 2.1
+ */
+public class ClearWorkingSetAction extends Action {
+    private WorkingSetFilterActionGroup actionGroup;
+
+    /**
+     * Creates a new instance of the receiver.
+     *
+     * @param actionGroup the action group this action is created in
+     */
+    public ClearWorkingSetAction(WorkingSetFilterActionGroup actionGroup) {
+        super(WorkbenchMessages.get().ClearWorkingSetAction_text);
+        Assert.isNotNull(actionGroup);
+        setToolTipText(WorkbenchMessages.get().ClearWorkingSetAction_toolTip);
+        setEnabled(actionGroup.getWorkingSet() != null);
+        PlatformUI.getWorkbench().getHelpSystem().setHelp(this,
+				IWorkbenchHelpContextIds.CLEAR_WORKING_SET_ACTION);
+        this.actionGroup = actionGroup;
+    }
+
+    /**
+     * Overrides method from Action
+     *
+     * @see Action#run
+     */
+    @Override
+	public void run() {
+        actionGroup.setWorkingSet(null);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/actions/CommandAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/actions/CommandAction.java
new file mode 100644
index 0000000..0550539
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/actions/CommandAction.java
@@ -0,0 +1,208 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.actions;
+
+import java.util.Map;
+
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.ICommandListener;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.jface.action.Action;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.ui.commands.ICommandImageService;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * Instantiate an action that will execute the command.
+ * <p>
+ * This is a legacy bridge class, and should not be used outside of the
+ * framework. Please use menu contributions to display a command in a menu or
+ * toolbar.
+ * </p>
+ * <p>
+ * <b>Note:</b> Clients my instantiate, but they must not subclass.
+ * </p>
+ *
+ * @since 3.3
+ */
+public class CommandAction extends Action {
+
+	private IHandlerService handlerService = null;
+
+	private ParameterizedCommand parameterizedCommand = null;
+
+	private ICommandListener commandListener;
+
+	protected CommandAction() {
+
+	}
+
+	/**
+	 * Creates the action backed by a command. For commands that don't take
+	 * parameters.
+	 *
+	 * @param serviceLocator
+	 *            The service locator that is closest in lifecycle to this
+	 *            action.
+	 * @param commandIdIn
+	 *            the command id. Must not be <code>null</code>.
+	 */
+	public CommandAction(IServiceLocator serviceLocator, String commandIdIn) {
+		this(serviceLocator, commandIdIn, null);
+	}
+
+	/**
+	 * Creates the action backed by a parameterized command. The parameterMap
+	 * must contain only all required parameters, and may contain the optional
+	 * parameters.
+	 *
+	 * @param serviceLocator
+	 *            The service locator that is closest in lifecycle to this
+	 *            action.
+	 * @param commandIdIn
+	 *            the command id. Must not be <code>null</code>.
+	 * @param parameterMap
+	 *            the parameter map. May be <code>null</code>.
+	 */
+	public CommandAction(IServiceLocator serviceLocator, String commandIdIn,
+			Map parameterMap) {
+		if (commandIdIn == null) {
+			throw new NullPointerException("commandIdIn must not be null"); //$NON-NLS-1$
+		}
+		init(serviceLocator, commandIdIn, parameterMap);
+	}
+
+	protected ICommandListener getCommandListener() {
+		if (commandListener == null) {
+			commandListener = commandEvent -> {
+				if (commandEvent.isHandledChanged()
+						|| commandEvent.isEnabledChanged()) {
+					if (commandEvent.getCommand().isDefined()) {
+						setEnabled(commandEvent.getCommand().isEnabled());
+					}
+				}
+			};
+		}
+		return commandListener;
+	}
+
+	/**
+	 * Build a command from the executable extension information.
+	 *
+	 * @param commandService
+	 *            to get the Command object
+	 * @param commandId
+	 *            the command id for this action
+	 * @param parameterMap
+	 */
+	private void createCommand(ICommandService commandService,
+			String commandId, Map parameterMap) {
+		Command cmd = commandService.getCommand(commandId);
+		if (!cmd.isDefined()) {
+			WorkbenchPlugin.log("Command " + commandId + " is undefined"); //$NON-NLS-1$//$NON-NLS-2$
+			return;
+		}
+
+		if (parameterMap == null) {
+			parameterizedCommand = new ParameterizedCommand(cmd, null);
+			return;
+		}
+
+		parameterizedCommand = ParameterizedCommand.generateCommand(cmd,
+				parameterMap);
+	}
+
+	public void dispose() {
+		// not important for command ID, maybe for command though.
+		handlerService = null;
+		if (commandListener != null) {
+			parameterizedCommand.getCommand().removeCommandListener(
+					commandListener);
+			commandListener = null;
+		}
+		parameterizedCommand = null;
+	}
+
+	@Override
+	public void runWithEvent(Event event) {
+		if (handlerService == null) {
+			String commandId = (parameterizedCommand == null ? "unknownCommand" //$NON-NLS-1$
+					: parameterizedCommand.getId());
+			WorkbenchPlugin.log("Cannot run " + commandId //$NON-NLS-1$
+					+ " before command action has been initialized"); //$NON-NLS-1$
+			return;
+		}
+		try {
+			if (parameterizedCommand != null) {
+				handlerService.executeCommand(parameterizedCommand, event);
+			}
+		} catch (Exception e) {
+			WorkbenchPlugin.log(e);
+		}
+	}
+
+	@Override
+	public void run() {
+		// hopefully this is never called
+		runWithEvent(null);
+	}
+
+	protected void init(IServiceLocator serviceLocator, String commandIdIn,
+			Map parameterMap) {
+		if (handlerService != null) {
+			// already initialized
+			return;
+		}
+		handlerService = serviceLocator
+				.getService(IHandlerService.class);
+		ICommandService commandService = serviceLocator
+				.getService(ICommandService.class);
+		ICommandImageService commandImageService = serviceLocator
+				.getService(ICommandImageService.class);
+
+		createCommand(commandService, commandIdIn, parameterMap);
+		if (parameterizedCommand != null) {
+			setId(parameterizedCommand.getId());
+			setActionDefinitionId(parameterizedCommand.getId());
+			try {
+				setText(parameterizedCommand.getName());
+			} catch (NotDefinedException e) {
+				// if we get this far it shouldn't be a problem
+			}
+			parameterizedCommand.getCommand().addCommandListener(
+					getCommandListener());
+			parameterizedCommand.getCommand().setEnabled(
+					handlerService.getCurrentState());
+			setEnabled(parameterizedCommand.getCommand().isEnabled());
+			setImageDescriptor(commandImageService.getImageDescriptor(
+					commandIdIn, ICommandImageService.TYPE_DEFAULT));
+			setDisabledImageDescriptor(commandImageService.getImageDescriptor(
+					commandIdIn, ICommandImageService.TYPE_DISABLED));
+			setHoverImageDescriptor(commandImageService.getImageDescriptor(
+					commandIdIn, ICommandImageService.TYPE_HOVER));
+		}
+	}
+
+	protected ParameterizedCommand getParameterizedCommand() {
+		return parameterizedCommand;
+	}
+
+	@Override
+	public String getActionDefinitionId() {
+		return super.getActionDefinitionId();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/actions/DynamicHelpAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/actions/DynamicHelpAction.java
new file mode 100644
index 0000000..9c14909
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/actions/DynamicHelpAction.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.actions;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.IWorkbenchPreferenceConstants;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.util.PrefUtil;
+
+/**
+ * Action to open the dynamic help.
+ *
+ * @since 3.1
+ */
+public class DynamicHelpAction extends Action implements IWorkbenchAction {
+	/**
+	 * The workbench window; or <code>null</code> if this action has been
+	 * <code>dispose</code>d.
+	 */
+	private IWorkbenchWindow workbenchWindow;
+
+	/**
+	 * Zero-arg constructor to allow cheat sheets to reuse this action.
+	 */
+	public DynamicHelpAction() {
+		this(PlatformUI.getWorkbench().getActiveWorkbenchWindow());
+	}
+
+	/**
+	 * Constructor for use by ActionFactory.
+	 *
+	 * @param window
+	 *            the window
+	 */
+	public DynamicHelpAction(IWorkbenchWindow window) {
+		if (window == null) {
+			throw new IllegalArgumentException();
+		}
+		this.workbenchWindow = window;
+		setActionDefinitionId(IWorkbenchCommandConstants.HELP_DYNAMIC_HELP);
+
+		// support for allowing a product to override the text for the action
+		String overrideText = PrefUtil.getAPIPreferenceStore().getString(
+				IWorkbenchPreferenceConstants.DYNAMIC_HELP_ACTION_TEXT);
+		if ("".equals(overrideText)) { //$NON-NLS-1$
+			setText(appendAccelerator(WorkbenchMessages.get().DynamicHelpAction_text));
+			setToolTipText(WorkbenchMessages.get().DynamicHelpAction_toolTip);
+		} else {
+			setText(appendAccelerator(overrideText));
+			setToolTipText(Action.removeMnemonics(overrideText));
+		}
+		window.getWorkbench().getHelpSystem().setHelp(this,
+				IWorkbenchHelpContextIds.DYNAMIC_HELP_ACTION);
+	}
+
+	private String appendAccelerator(String text) {
+		// We know that on Windows context help key is F1
+		// and cannot be changed by the user.
+		//
+		// Commented out due to the problem described in
+		// Bugzilla bug #95057
+
+		//if (Platform.getWS().equals(Platform.WS_WIN32))
+		//	return text + "\t" + KeyStroke.getInstance(SWT.F1).format(); //$NON-NLS-1$
+		return text;
+	}
+
+	@Override
+	public void run() {
+		if (workbenchWindow == null) {
+			// action has been disposed
+			return;
+		}
+		// This may take a while, so use the busy indicator
+		BusyIndicator.showWhile(null, () -> workbenchWindow.getWorkbench().getHelpSystem()
+				.displayDynamicHelp());
+	}
+
+	@Override
+	public void dispose() {
+		workbenchWindow = null;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/actions/EditWorkingSetAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/actions/EditWorkingSetAction.java
new file mode 100644
index 0000000..7bdbe91
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/actions/EditWorkingSetAction.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.actions;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.window.Window;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkingSet;
+import org.eclipse.ui.IWorkingSetManager;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.WorkingSetFilterActionGroup;
+import org.eclipse.ui.dialogs.IWorkingSetEditWizard;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchMessages;
+
+/**
+ * Displays an IWorkingSetEditWizard for editing a working set.
+ *
+ * @since 2.1
+ */
+public class EditWorkingSetAction extends Action {
+    private Shell shell;
+
+    private WorkingSetFilterActionGroup actionGroup;
+
+    /**
+     * Creates a new instance of the receiver.
+     *
+     * @param actionGroup the action group this action is created in
+     * @param shell the parent shell
+     */
+    public EditWorkingSetAction(WorkingSetFilterActionGroup actionGroup,
+            Shell shell) {
+        super(WorkbenchMessages.get().EditWorkingSetAction_text);
+        Assert.isNotNull(actionGroup);
+        setToolTipText(WorkbenchMessages.get().EditWorkingSetAction_toolTip);
+
+        this.shell = shell;
+        this.actionGroup = actionGroup;
+        PlatformUI.getWorkbench().getHelpSystem().setHelp(this,
+				IWorkbenchHelpContextIds.EDIT_WORKING_SET_ACTION);
+    }
+
+    /**
+     * Overrides method from Action
+     *
+     * @see Action#run
+     */
+    @Override
+	public void run() {
+        IWorkingSetManager manager = PlatformUI.getWorkbench()
+                .getWorkingSetManager();
+        IWorkingSet workingSet = actionGroup.getWorkingSet();
+
+        if (workingSet == null) {
+            setEnabled(false);
+            return;
+        }
+        IWorkingSetEditWizard wizard = manager
+                .createWorkingSetEditWizard(workingSet);
+        if (wizard == null) {
+            String title = WorkbenchMessages.get().EditWorkingSetAction_error_nowizard_title;
+            String message = WorkbenchMessages.get().EditWorkingSetAction_error_nowizard_message;
+            MessageDialog.openError(shell, title, message);
+            return;
+        }
+        WizardDialog dialog = new WizardDialog(shell, wizard);
+        dialog.create();
+        if (dialog.open() == Window.OK) {
+			actionGroup.setWorkingSet(wizard.getSelection());
+		}
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/actions/HelpContentsAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/actions/HelpContentsAction.java
new file mode 100644
index 0000000..fd58039
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/actions/HelpContentsAction.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.actions;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.IWorkbenchPreferenceConstants;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction;
+import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.util.PrefUtil;
+
+/**
+ * Action to open the help contents.
+ *
+ * @since 3.0
+ */
+public class HelpContentsAction extends Action implements IWorkbenchAction {
+    /**
+     * The workbench window; or <code>null</code> if this
+     * action has been <code>dispose</code>d.
+     */
+    private IWorkbenchWindow workbenchWindow;
+
+    /**
+     * Zero-arg constructor to allow cheat sheets to reuse this action.
+     */
+    public HelpContentsAction() {
+        this(PlatformUI.getWorkbench().getActiveWorkbenchWindow());
+    }
+
+    /**
+     * Constructor for use by ActionFactory.
+     *
+     * @param window the window
+     */
+    public HelpContentsAction(IWorkbenchWindow window) {
+        if (window == null) {
+            throw new IllegalArgumentException();
+        }
+        this.workbenchWindow = window;
+        setActionDefinitionId(IWorkbenchCommandConstants.HELP_HELP_CONTENTS);
+
+        // support for allowing a product to override the text for the action
+        String overrideText = PrefUtil.getAPIPreferenceStore().getString(
+                IWorkbenchPreferenceConstants.HELP_CONTENTS_ACTION_TEXT);
+        if ("".equals(overrideText)) { //$NON-NLS-1$
+            setText(WorkbenchMessages.get().HelpContentsAction_text);
+            setToolTipText(WorkbenchMessages.get().HelpContentsAction_toolTip);
+        } else {
+            setText(overrideText);
+            setToolTipText(Action.removeMnemonics(overrideText));
+        }
+        setImageDescriptor(WorkbenchImages
+                .getImageDescriptor(IWorkbenchGraphicConstants.IMG_ETOOL_HELP_CONTENTS));
+        window.getWorkbench().getHelpSystem().setHelp(this,
+				IWorkbenchHelpContextIds.HELP_CONTENTS_ACTION);
+    }
+
+    @Override
+	public void run() {
+        if (workbenchWindow == null) {
+            // action has been disposed
+            return;
+        }
+        //This may take a while, so use the busy indicator
+        BusyIndicator.showWhile(null, () -> workbenchWindow.getWorkbench().getHelpSystem().displayHelp());
+    }
+
+    @Override
+	public void dispose() {
+        workbenchWindow = null;
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/actions/HelpSearchAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/actions/HelpSearchAction.java
new file mode 100644
index 0000000..19e333c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/actions/HelpSearchAction.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.actions;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.IWorkbenchPreferenceConstants;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction;
+import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.util.PrefUtil;
+
+/**
+ * Action to open the help search.
+ *
+ * @since 3.1
+ */
+public class HelpSearchAction extends Action implements IWorkbenchAction {
+    /**
+     * The workbench window; or <code>null</code> if this
+     * action has been <code>dispose</code>d.
+     */
+    private IWorkbenchWindow workbenchWindow;
+
+    /**
+     * Zero-arg constructor to allow cheat sheets to reuse this action.
+     */
+    public HelpSearchAction() {
+        this(PlatformUI.getWorkbench().getActiveWorkbenchWindow());
+    }
+
+    /**
+     * Constructor for use by ActionFactory.
+     *
+     * @param window the window
+     */
+    public HelpSearchAction(IWorkbenchWindow window) {
+        if (window == null) {
+            throw new IllegalArgumentException();
+        }
+        this.workbenchWindow = window;
+        setActionDefinitionId(IWorkbenchCommandConstants.HELP_HELP_SEARCH);
+
+        // support for allowing a product to override the text for the action
+        String overrideText = PrefUtil.getAPIPreferenceStore().getString(
+                IWorkbenchPreferenceConstants.HELP_SEARCH_ACTION_TEXT);
+        if ("".equals(overrideText)) { //$NON-NLS-1$
+            setText(WorkbenchMessages.get().HelpSearchAction_text);
+            setToolTipText(WorkbenchMessages.get().HelpSearchAction_toolTip);
+        } else {
+            setText(overrideText);
+            setToolTipText(Action.removeMnemonics(overrideText));
+        }
+        setImageDescriptor(WorkbenchImages
+                .getImageDescriptor(IWorkbenchGraphicConstants.IMG_ETOOL_HELP_SEARCH));
+        window.getWorkbench().getHelpSystem().setHelp(this,
+				IWorkbenchHelpContextIds.HELP_SEARCH_ACTION);
+    }
+
+    @Override
+	public void run() {
+        if (workbenchWindow == null) {
+            // action has been disposed
+            return;
+        }
+        //This may take a while, so use the busy indicator
+        BusyIndicator.showWhile(null, () -> workbenchWindow.getWorkbench().getHelpSystem().displaySearch());
+    }
+
+    @Override
+	public void dispose() {
+        workbenchWindow = null;
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/actions/HelpSearchContributionItem.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/actions/HelpSearchContributionItem.java
new file mode 100644
index 0000000..104d994
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/actions/HelpSearchContributionItem.java
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.actions;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.action.ControlContribution;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+
+/**
+ * This is the contribution item that is used to add a help search field to
+ * the cool bar.
+ *
+ * @since 3.1
+ */
+public class HelpSearchContributionItem extends ControlContribution {
+	private static final String ID = "org.eclipse.ui.helpSearch"; //$NON-NLS-1$
+
+	private IWorkbenchWindow window;
+
+	private Combo combo;
+
+	private int MAX_ITEM_COUNT = 10;
+
+	/**
+	 * Creates the contribution item.
+	 *
+	 * @param window the window
+	 */
+	public HelpSearchContributionItem(IWorkbenchWindow window) {
+		this(window, ID);
+	}
+
+	/**
+	 * Creates the contribution item.
+	 *
+	 * @param window the window
+	 * @param id the contribution item id
+	 */
+	public HelpSearchContributionItem(IWorkbenchWindow window, String id) {
+		super(id);
+        Assert.isNotNull(window);
+		this.window = window;
+	}
+
+	@Override
+	protected Control createControl(Composite parent) {
+		combo = new Combo(parent, SWT.NONE);
+		combo.setToolTipText(WorkbenchMessages.get().WorkbenchWindow_searchCombo_toolTip);
+		String[] items = WorkbenchPlugin.getDefault().getDialogSettings()
+				.getArray(ID);
+		if (items != null) {
+			combo.setItems(items);
+		}
+		combo.setText(WorkbenchMessages.get().WorkbenchWindow_searchCombo_text);
+		combo.addKeyListener(new KeyAdapter() {
+			@Override
+			public void keyReleased(KeyEvent e) {
+				if (e.character == SWT.CR) {
+					doSearch(combo.getText(), true);
+				}
+			}
+		});
+		combo.addSelectionListener(new SelectionAdapter()
+        {
+            public void widgetSelected(SelectionEvent e) 
+            {
+    			int index = combo.getSelectionIndex();
+    			if (index != -1) {
+    				doSearch(combo.getItem(index), false);
+    			}
+            }
+		});
+		return combo;
+	}
+
+	@Override
+	protected int computeWidth(Control control) {
+		return control.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x;
+	}
+
+	private void doSearch(String phrase, boolean updateList) {
+		if (phrase.length() == 0) {
+            window.getWorkbench().getHelpSystem().displaySearch();
+			return;
+		}
+		if (updateList) {
+			boolean exists = false;
+			for (int i = 0; i < combo.getItemCount(); i++) {
+				String item = combo.getItem(i);
+				if (item.equalsIgnoreCase(phrase)) {
+					exists = true;
+					break;
+				}
+			}
+			if (!exists) {
+				combo.add(phrase, 0);
+				if (combo.getItemCount() > MAX_ITEM_COUNT) {
+					combo.remove(combo.getItemCount() - 1);
+				}
+				WorkbenchPlugin.getDefault().getDialogSettings().put(ID,
+						combo.getItems());
+			}
+		}
+		window.getWorkbench().getHelpSystem().search(phrase);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/actions/ModifyWorkingSetDelegate.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/actions/ModifyWorkingSetDelegate.java
new file mode 100644
index 0000000..a5870ee
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/actions/ModifyWorkingSetDelegate.java
@@ -0,0 +1,341 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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
+ *     Benjamin Muskalla - Bug 169023 [WorkingSets] "Add to working set"
+ *     						drop down should include a "new working set" option
+ *******************************************************************************/
+package org.eclipse.ui.internal.actions;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExecutableExtension;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.ActionContributionItem;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.window.Window;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.ui.IActionDelegate2;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.IWorkingSet;
+import org.eclipse.ui.IWorkingSetManager;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.QuickMenuCreator;
+import org.eclipse.ui.dialogs.IWorkingSetNewWizard;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+
+/**
+ * @since 3.3
+ *
+ */
+public class ModifyWorkingSetDelegate extends
+		AbstractWorkingSetPulldownDelegate implements IExecutableExtension, IActionDelegate2 {
+
+	public class NewWorkingSetAction extends Action {
+
+		/**
+		 * Create a new instance of this action.
+		 */
+		public NewWorkingSetAction() {
+			super(WorkbenchMessages.get().NewWorkingSet);
+		}
+
+		@Override
+		public void run() {
+			IWorkingSetManager manager = WorkbenchPlugin.getDefault()
+			.getWorkingSetManager();
+			IWorkingSetNewWizard wizard = manager.createWorkingSetNewWizard(null);
+			// the wizard can never be null since we have at least a resource
+			// working set
+			// creation page
+			WizardDialog dialog = new WizardDialog(PlatformUI.getWorkbench()
+								.getDisplay().getActiveShell(), wizard);
+
+			dialog.create();
+			PlatformUI.getWorkbench().getHelpSystem().setHelp(dialog.getShell(),
+					IWorkbenchHelpContextIds.WORKING_SET_NEW_WIZARD);
+			if (dialog.open() == Window.OK) {
+				IWorkingSet workingSet = wizard.getSelection();
+				if(workingSet != null) {
+					manager.addWorkingSet(workingSet);
+				}
+			}
+		}
+
+	}
+
+	private class ModifyAction extends Action {
+
+		private IWorkingSet set;
+
+		private IAdaptable [] selectedElements;
+
+		/**
+		 * @param set
+		 * @param selectedElements
+		 * @param add
+		 */
+		private ModifyAction(IWorkingSet set, IAdaptable [] selectedElements) {
+			super(set.getLabel(), IAction.AS_CHECK_BOX);
+			this.set = set;
+			this.selectedElements = selectedElements;
+			setImageDescriptor(set.getImageDescriptor());
+		}
+
+		@Override
+		public void run() {
+
+			Collection oldElements = Arrays.asList(set.getElements());
+			Set newElements = new HashSet(oldElements.size()
+					+ selectedElements.length);
+			newElements.addAll(oldElements);
+			List selectedAsList = Arrays.asList(selectedElements);
+			if (add) {
+				newElements.addAll(selectedAsList);
+			} else {
+				newElements.removeAll(selectedAsList);
+			}
+			set.setElements((IAdaptable[]) newElements
+					.toArray(new IAdaptable[newElements.size()]));
+		}
+	}
+
+	private QuickMenuCreator contextMenuCreator = new QuickMenuCreator() {
+		@Override
+		protected void fillMenu(IMenuManager menu) {
+			ModifyWorkingSetDelegate.this.fillMenu(menu);
+		}
+	};
+
+	private boolean add = true;
+
+	private IPropertyChangeListener listener = new IPropertyChangeListener() {
+
+		@Override
+		public void propertyChange(PropertyChangeEvent event) {
+			refreshEnablement();
+		}
+
+		/**
+		 *
+		 */
+		private void refreshEnablement() {
+			selectionChanged(actionProxy, getSelection());
+		}
+	};
+
+	private IAction actionProxy;
+
+	/**
+	 *
+	 */
+	public ModifyWorkingSetDelegate() {
+	}
+
+	@Override
+	public void run(IAction action) {
+		contextMenuCreator.createMenu();
+	}
+
+	@Override
+	public void runWithEvent(IAction action, Event event) {
+		if (event.type == SWT.KeyDown || event.type == SWT.KeyUp)
+			run(action);
+	}
+
+	@Override
+	public void init(IWorkbenchWindow window) {
+		super.init(window);
+		getWindow().getWorkbench().getWorkingSetManager()
+				.addPropertyChangeListener(listener);
+	}
+
+	@Override
+	public void dispose() {
+		getWindow().getWorkbench().getWorkingSetManager()
+				.removePropertyChangeListener(listener);
+		super.dispose();
+		contextMenuCreator.dispose();
+	}
+
+	@Override
+	public void fillMenu(Menu menu) {
+		List menuItems = getItems();
+		for (int i = 0; i < menuItems.size(); i++) {
+			Object object = menuItems.get(i);
+			if (object instanceof IAction) {
+				ActionContributionItem item = new ActionContributionItem((IAction) object);
+				item.fill(menu, -1);
+			} else {
+				IContributionItem item = (IContributionItem) object;
+				item.fill(menu, -1);
+			}
+		}
+		// create working set action only for add menu
+		if(add) {
+			IContributionItem item = null;
+			if (menu.getItemCount() > 0) {
+				item = new Separator();
+				item.fill(menu, -1);
+			}
+
+			item = new ActionContributionItem(new NewWorkingSetAction());
+			item.fill(menu, -1);
+		}
+	}
+	/**
+	 * Return the list of items to show in the submenu.
+	 *
+	 * @return the items to show in the submenu
+	 */
+	private List getItems() {
+		List menuItems = new ArrayList();
+		ISelection selection = getSelection();
+		if (!(selection instanceof IStructuredSelection)) {
+			if(!add) {
+				IAction emptyAction = new Action(WorkbenchMessages.get().NoApplicableWorkingSets) {};
+				emptyAction.setEnabled(false);
+				menuItems.add(emptyAction);
+			}
+			return menuItems;
+		}
+
+		IWorkingSet[][] typedSets = splitSets();
+		Object [] selectedElements = ((IStructuredSelection)selection).toArray();
+
+		// keep a tab of whether or not we need a separator. If a given type
+		// of working set has contributed some items then this will be true
+		// after the processing of the working set type. The next type will
+		// then consult this field and add a separator before adding any
+		// items of its own. In this way the list will never end with a
+		// separator.
+		boolean needsSeparator = false;
+
+		for (IWorkingSet[] sets : typedSets) {
+			int oldCount = menuItems.size();
+
+			for (IWorkingSet set : sets) {
+				Set existingElements = new HashSet();
+				existingElements.addAll(Arrays
+						.asList(set.getElements()));
+
+				boolean visible = false;
+				IAdaptable [] adaptables = new IAdaptable[selectedElements.length];
+				System.arraycopy(selectedElements, 0, adaptables, 0, selectedElements.length);
+				adaptables = set.adaptElements(adaptables);
+				if (adaptables.length > 0 && add) {
+					for (int k = 0; k < adaptables.length; k++) {
+						if (!existingElements.contains(adaptables[k])) {
+							// show if any element is not present in
+							// addition
+							visible = true;
+							break;
+						}
+					}
+				}
+				else if (adaptables.length > 0) {
+					for (IAdaptable adaptable : adaptables) {
+						if (existingElements.contains(adaptable)){
+							visible = true; // show if any element
+											// is present in removal
+							break;
+						}
+					}
+				}
+
+				if (visible) {
+					if (needsSeparator) {
+						menuItems.add(new Separator());
+						needsSeparator = false;
+					}
+					ModifyAction action = new ModifyAction(set,
+							adaptables);
+					menuItems.add(action);
+				}
+			}
+			// we need a separator if we needed one before but never added it or
+			// we've added new items to the list.
+			needsSeparator |= menuItems.size() > oldCount;
+		}
+		if (menuItems.isEmpty() && !add) {
+			IAction emptyAction = new Action(
+					WorkbenchMessages.get().NoApplicableWorkingSets) {
+			};
+			emptyAction.setEnabled(false);
+			menuItems.add(emptyAction);
+		}
+		return menuItems;
+	}
+
+	private void fillMenu(IMenuManager menu) {
+		List menuItems = getItems();
+		for (int i = 0; i < menuItems.size(); i++) {
+			Object object = menuItems.get(i);
+			if (object instanceof IAction) {
+				menu.add((IAction) object);
+			} else {
+				IContributionItem item = (IContributionItem) object;
+				menu.add(item);
+			}
+		}
+	}
+
+	@Override
+	public void selectionChanged(IAction actionProxy, ISelection selection) {
+		super.selectionChanged(actionProxy, selection);
+		if (selection instanceof IStructuredSelection) {
+			Object[] selectedElements = ((IStructuredSelection) getSelection())
+					.toArray();
+			// ensure every item is of type IAdaptable and is NOT an IWorkingSet (minimal fix for 157799)
+			boolean minimallyOkay = true;
+			for (Object selectedElement : selectedElements) {
+				Object object = selectedElement;
+				if (!(object instanceof IAdaptable) || object instanceof IWorkingSet) {
+					minimallyOkay = false;
+					break;
+				}
+			}
+			actionProxy.setEnabled(minimallyOkay);
+
+		}
+		else
+			actionProxy.setEnabled(false);
+	}
+
+	@Override
+	public void setInitializationData(IConfigurationElement config,
+			String propertyName, Object data) {
+		if (data instanceof String) {
+			add = Boolean.valueOf((String) data).booleanValue();
+		}
+	}
+
+	@Override
+	public void init(IAction action) {
+		this.actionProxy = action;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/actions/NewWizardShortcutAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/actions/NewWizardShortcutAction.java
new file mode 100644
index 0000000..5ea87ff
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/actions/NewWizardShortcutAction.java
@@ -0,0 +1,164 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.actions;
+
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.dialogs.ErrorDialog;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.INewWizard;
+import org.eclipse.ui.IPluginContribution;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.actions.ActionFactory;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.LegacyResourceSupport;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.wizards.IWizardDescriptor;
+
+/**
+ * Opens a specific new wizard.
+ */
+public class NewWizardShortcutAction extends Action implements
+        IPluginContribution {
+    private IWizardDescriptor wizardElement;
+
+    /**
+     * The wizard dialog width
+     */
+    private static final int SIZING_WIZARD_WIDTH = 500;
+
+    /**
+     * The wizard dialog height
+     */
+    private static final int SIZING_WIZARD_HEIGHT = 500;
+
+    private IWorkbenchWindow window;
+
+    /**
+     * Create an instance of this class.
+     *
+     * @param window the workbench window in which this action will appear
+     * @param wizardDesc a wizard element
+     */
+    public NewWizardShortcutAction(IWorkbenchWindow window,
+            IWizardDescriptor wizardDesc) {
+        super(wizardDesc.getLabel());
+        setToolTipText(wizardDesc.getDescription());
+        setImageDescriptor(wizardDesc.getImageDescriptor());
+        setId(ActionFactory.NEW.getId());
+        wizardElement = wizardDesc;
+        this.window = window;
+    }
+
+    /**
+     * Get the wizard descriptor for this action.
+     *
+     * @return the wizard descriptor
+     */
+    public IWizardDescriptor getWizardDescriptor() {
+		return wizardElement;
+	}
+
+    @Override
+	public void run() {
+        // create instance of target wizard
+
+        INewWizard wizard;
+        try {
+            wizard = (INewWizard) wizardElement.createWizard();
+        } catch (CoreException e) {
+            ErrorDialog.openError(window.getShell(), WorkbenchMessages.get().NewWizardShortcutAction_errorTitle,
+                    WorkbenchMessages.get().NewWizardShortcutAction_errorMessage,
+                    e.getStatus());
+            return;
+        }
+
+        ISelection selection = window.getSelectionService().getSelection();
+        IStructuredSelection selectionToPass = StructuredSelection.EMPTY;
+        if (selection instanceof IStructuredSelection) {
+            selectionToPass = wizardElement
+                    .adaptedSelection((IStructuredSelection) selection);
+        } else {
+            // Build the selection from the IFile of the editor
+            IWorkbenchPart part = window.getPartService().getActivePart();
+            if (part instanceof IEditorPart) {
+                IEditorInput input = ((IEditorPart) part).getEditorInput();
+                Class fileClass = LegacyResourceSupport.getFileClass();
+                if (input != null && fileClass != null) {
+					Object file = Adapters.adapt(input, fileClass);
+                    if (file != null) {
+                        selectionToPass = new StructuredSelection(file);
+                    }
+                }
+            }
+        }
+
+        // even tho we MAY finish early without showing a dialog, prep the
+		// wizard with a dialog and such in case it's logic requires it
+		// - yes, it wastes a dialog but they are plentiful...
+		wizard.init(window.getWorkbench(), selectionToPass);
+
+        Shell parent = window.getShell();
+        WizardDialog dialog = new WizardDialog(parent, wizard);
+        dialog.create();
+        Point defaultSize = dialog.getShell().getSize();
+        dialog.getShell().setSize(
+                Math.max(SIZING_WIZARD_WIDTH, defaultSize.x),
+                Math.max(SIZING_WIZARD_HEIGHT, defaultSize.y));
+        window.getWorkbench().getHelpSystem().setHelp(dialog.getShell(),
+				IWorkbenchHelpContextIds.NEW_WIZARD_SHORTCUT);
+
+        // if the wizard can finish early and doesn't have any pages, just finish it.
+        if (wizardElement.canFinishEarly() && !wizardElement.hasPages()) {
+			wizard.performFinish();
+			dialog.close();
+		} else {
+			dialog.open();
+		}
+    }
+
+    @Override
+	public String getLocalId() {
+    	IPluginContribution contribution = getPluginContribution();
+    	if (contribution != null) {
+			return contribution.getLocalId();
+		}
+    	return wizardElement.getId();
+    }
+
+    @Override
+	public String getPluginId() {
+    	IPluginContribution contribution = getPluginContribution();
+    	if (contribution != null) {
+			return contribution.getPluginId();
+		}
+    	return null;
+    }
+
+    /**
+     * Return the plugin contribution associated with the wizard.
+     *
+     * @return the contribution or <code>null</code>
+     * @since 3.1
+     */
+    private IPluginContribution getPluginContribution() {
+		return Adapters.adapt(wizardElement, IPluginContribution.class);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/actions/SelectWorkingSetAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/actions/SelectWorkingSetAction.java
new file mode 100644
index 0000000..f15b2b3
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/actions/SelectWorkingSetAction.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.actions;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkingSet;
+import org.eclipse.ui.IWorkingSetManager;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.WorkingSetFilterActionGroup;
+import org.eclipse.ui.dialogs.IWorkingSetSelectionDialog;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchMessages;
+
+/**
+ * Displays an IWorkingSetSelectionDialog and sets the selected
+ * working set in the action group.
+ *
+ * @since 2.1
+ */
+public class SelectWorkingSetAction extends Action {
+    private Shell shell;
+
+    private WorkingSetFilterActionGroup actionGroup;
+
+    /**
+     * Creates a new instance of the receiver.
+     *
+     * @param actionGroup the action group this action is created in
+     * @param shell shell to use for opening working set selection dialog.
+     */
+    public SelectWorkingSetAction(WorkingSetFilterActionGroup actionGroup,
+            Shell shell) {
+        super(WorkbenchMessages.get().SelectWorkingSetAction_text);
+        Assert.isNotNull(actionGroup);
+        setToolTipText(WorkbenchMessages.get().SelectWorkingSetAction_toolTip);
+
+        this.shell = shell;
+        this.actionGroup = actionGroup;
+        PlatformUI.getWorkbench().getHelpSystem().setHelp(this,
+				IWorkbenchHelpContextIds.SELECT_WORKING_SET_ACTION);
+    }
+
+    /**
+     * Overrides method from Action
+     *
+     * @see Action#run()
+     */
+    @Override
+	public void run() {
+        IWorkingSetManager manager = PlatformUI.getWorkbench()
+                .getWorkingSetManager();
+        IWorkingSetSelectionDialog dialog = manager
+                .createWorkingSetSelectionDialog(shell, false);
+        IWorkingSet workingSet = actionGroup.getWorkingSet();
+
+        if (workingSet != null) {
+			dialog.setSelection(new IWorkingSet[] { workingSet });
+		}
+
+        if (dialog.open() == Window.OK) {
+            IWorkingSet[] result = dialog.getSelection();
+            if (result != null && result.length > 0) {
+                actionGroup.setWorkingSet(result[0]);
+                manager.addRecentWorkingSet(result[0]);
+            } else {
+                actionGroup.setWorkingSet(null);
+            }
+        } else {
+			actionGroup.setWorkingSet(workingSet);
+		}
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/actions/SelectWorkingSetsAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/actions/SelectWorkingSetsAction.java
new file mode 100644
index 0000000..7b3d745
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/actions/SelectWorkingSetsAction.java
@@ -0,0 +1,150 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.actions;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.ActionContributionItem;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.bindings.keys.IKeyLookup;
+import org.eclipse.jface.bindings.keys.KeyLookupFactory;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.IWorkingSet;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.dialogs.SimpleWorkingSetSelectionDialog;
+
+/**
+ * Action to select the visible working sets for a given workbench page.
+ *
+ * @since 3.2
+ */
+public class SelectWorkingSetsAction extends AbstractWorkingSetPulldownDelegate  {
+
+	private class ManageWorkingSetsAction extends Action {
+
+		ManageWorkingSetsAction() {
+			super(WorkbenchMessages.get().Edit);
+		}
+
+		@Override
+		public void run() {
+			SelectWorkingSetsAction.this.run(this);
+		}
+	}
+
+	private class ToggleWorkingSetAction extends Action {
+		private IWorkingSet set;
+
+		ToggleWorkingSetAction(IWorkingSet set) {
+			super(set.getLabel(), IAction.AS_CHECK_BOX);
+			setImageDescriptor(set.getImageDescriptor());
+			this.set = set;
+			setChecked(isWorkingSetEnabled(set));
+		}
+
+		@Override
+		public void runWithEvent(Event event) {
+
+			Set newList = new HashSet(Arrays.asList(getWindow().getActivePage()
+					.getWorkingSets()));
+
+			if (isChecked()) {
+				// if the primary modifier key is down then clear the list
+				// first. this makes the selection exclusive rather than
+				// additive.
+				boolean modified = (event.stateMask & KeyLookupFactory
+						.getDefault().formalModifierLookup(IKeyLookup.M1_NAME)) != 0;
+
+				if (modified)
+					newList.clear();
+				newList.add(set);
+			} else {
+				newList.remove(set);
+			}
+
+			getWindow().getActivePage().setWorkingSets(
+					(IWorkingSet[]) newList.toArray(new IWorkingSet[newList
+							.size()]));
+		}
+	}
+
+	@Override
+	protected void fillMenu(Menu menu) {
+		IWorkingSet[][] typedSets = splitSets();
+
+		for (IWorkingSet[] sets : typedSets) {
+			for (IWorkingSet set : sets) {
+				// only add visible sets
+				// if (set.isVisible()) {
+				ActionContributionItem item = new ActionContributionItem(
+						new ToggleWorkingSetAction(set));
+				item.fill(menu, -1);
+				// }
+			}
+			Separator separator = new Separator();
+			separator.fill(menu, -1);
+		}
+
+		ActionContributionItem item = new ActionContributionItem(
+				new ManageWorkingSetsAction());
+		item.fill(menu, -1);
+
+	}
+
+	private IWorkingSet[] getEnabledSets() {
+		return getWindow().getActivePage().getWorkingSets();
+	}
+
+	private boolean isWorkingSetEnabled(IWorkingSet set) {
+		IWorkingSet[] enabledSets = getEnabledSets();
+		for (IWorkingSet enabledSet : enabledSets) {
+			if (enabledSet.equals(set)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	@Override
+	public void run(IAction action) {
+		ConfigureWindowWorkingSetsDialog dialog = new ConfigureWindowWorkingSetsDialog(
+				getWindow());
+		if (dialog.open() == Window.OK) {
+
+		}
+
+	}
+}
+
+class ConfigureWindowWorkingSetsDialog extends SimpleWorkingSetSelectionDialog {
+
+	private IWorkbenchWindow window;
+
+	protected ConfigureWindowWorkingSetsDialog(IWorkbenchWindow window) {
+		super(window.getShell(), null, window.getActivePage().getWorkingSets(), true);
+		this.window = window;
+		setTitle(WorkbenchMessages.get().WorkingSetSelectionDialog_title_multiSelect);
+		setMessage(WorkbenchMessages.get().WorkingSetSelectionDialog_message_multiSelect);
+	}
+
+	@Override
+	protected void okPressed() {
+		super.okPressed();
+		window.getActivePage().setWorkingSets(getSelection());
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/AbstractActivityManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/AbstractActivityManager.java
new file mode 100644
index 0000000..e5c9f98
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/AbstractActivityManager.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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.ui.internal.activities;
+
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.ui.activities.ActivityManagerEvent;
+import org.eclipse.ui.activities.IActivityManager;
+import org.eclipse.ui.activities.IActivityManagerListener;
+
+public abstract class AbstractActivityManager implements IActivityManager {
+	private ListenerList<IActivityManagerListener> activityManagerListeners;
+
+    protected AbstractActivityManager() {
+    }
+
+    @Override
+	public void addActivityManagerListener(
+            IActivityManagerListener activityManagerListener) {
+        if (activityManagerListener == null) {
+			throw new NullPointerException();
+		}
+
+        if (activityManagerListeners == null) {
+			activityManagerListeners = new ListenerList<>();
+		}
+
+		activityManagerListeners.add(activityManagerListener);
+    }
+
+    protected void fireActivityManagerChanged(
+            ActivityManagerEvent activityManagerEvent) {
+        if (activityManagerEvent == null) {
+			throw new NullPointerException();
+		}
+
+		if (activityManagerListeners != null) {
+			for (IActivityManagerListener listener : activityManagerListeners) {
+				listener.activityManagerChanged(activityManagerEvent);
+			}
+		}
+    }
+
+    @Override
+	public void removeActivityManagerListener(
+            IActivityManagerListener activityManagerListener) {
+        if (activityManagerListener == null) {
+			throw new NullPointerException();
+		}
+
+        if (activityManagerListeners != null) {
+			activityManagerListeners.remove(activityManagerListener);
+		}
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/AbstractActivityRegistry.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/AbstractActivityRegistry.java
new file mode 100644
index 0000000..d4871f3
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/AbstractActivityRegistry.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2014 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.ui.internal.activities;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public abstract class AbstractActivityRegistry implements IActivityRegistry {
+    protected List activityRequirementBindingDefinitions = Collections.EMPTY_LIST;
+
+    protected List activityDefinitions = Collections.EMPTY_LIST;
+
+    protected List activityPatternBindingDefinitions = Collections.EMPTY_LIST;
+
+    private ActivityRegistryEvent activityRegistryEvent;
+
+    private List activityRegistryListeners;
+
+    protected List categoryActivityBindingDefinitions = Collections.EMPTY_LIST;
+
+    protected List categoryDefinitions = Collections.EMPTY_LIST;
+
+    protected List defaultEnabledActivities = Collections.EMPTY_LIST;
+
+    protected AbstractActivityRegistry() {
+    }
+
+    @Override
+	public void addActivityRegistryListener(
+            IActivityRegistryListener activityRegistryListener) {
+        if (activityRegistryListener == null) {
+			throw new NullPointerException();
+		}
+
+        if (activityRegistryListeners == null) {
+			activityRegistryListeners = new ArrayList();
+		}
+
+        if (!activityRegistryListeners.contains(activityRegistryListener)) {
+			activityRegistryListeners.add(activityRegistryListener);
+		}
+    }
+
+    protected void fireActivityRegistryChanged() {
+        if (activityRegistryListeners != null) {
+            for (int i = 0; i < activityRegistryListeners.size(); i++) {
+                if (activityRegistryEvent == null) {
+					activityRegistryEvent = new ActivityRegistryEvent(this);
+				}
+
+                ((IActivityRegistryListener) activityRegistryListeners.get(i))
+                        .activityRegistryChanged(activityRegistryEvent);
+            }
+        }
+    }
+
+    @Override
+	public List getActivityRequirementBindingDefinitions() {
+        return activityRequirementBindingDefinitions;
+    }
+
+    @Override
+	public List getActivityDefinitions() {
+        return activityDefinitions;
+    }
+
+    @Override
+	public List getActivityPatternBindingDefinitions() {
+        return activityPatternBindingDefinitions;
+    }
+
+    @Override
+	public List getCategoryActivityBindingDefinitions() {
+        return categoryActivityBindingDefinitions;
+    }
+
+    @Override
+	public List getCategoryDefinitions() {
+        return categoryDefinitions;
+    }
+
+    @Override
+	public void removeActivityRegistryListener(
+            IActivityRegistryListener activityRegistryListener) {
+        if (activityRegistryListener == null) {
+			throw new NullPointerException();
+		}
+
+        if (activityRegistryListeners != null) {
+			activityRegistryListeners.remove(activityRegistryListener);
+		}
+    }
+
+    @Override
+	public List getDefaultEnabledActivities() {
+        return defaultEnabledActivities;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/Activity.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/Activity.java
new file mode 100644
index 0000000..75bc6ef
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/Activity.java
@@ -0,0 +1,387 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.activities;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.ui.activities.ActivityEvent;
+import org.eclipse.ui.activities.IActivity;
+import org.eclipse.ui.activities.IActivityListener;
+import org.eclipse.ui.activities.IActivityPatternBinding;
+import org.eclipse.ui.activities.IActivityRequirementBinding;
+import org.eclipse.ui.activities.NotDefinedException;
+import org.eclipse.ui.internal.util.Util;
+
+final class Activity implements IActivity {
+    private final static int HASH_FACTOR = 89;
+
+    private final static int HASH_INITIAL = Activity.class.getName().hashCode();
+
+    private final static Set strongReferences = new HashSet();
+
+    private Set activityRequirementBindings;
+
+    private transient IActivityRequirementBinding[] activityRequirementBindingsAsArray;
+
+    private List activityListeners;
+
+    private Set activityPatternBindings;
+
+    private transient IActivityPatternBinding[] activityPatternBindingsAsArray;
+
+    private boolean defined;
+
+    private boolean enabled;
+
+    private transient int hashCode = HASH_INITIAL;
+
+    private String id;
+
+    private String name;
+
+    private transient String string;
+
+    private String description;
+
+    private boolean defaultEnabled;
+
+	private Expression expression;
+
+    Activity(String id) {
+        if (id == null) {
+			throw new NullPointerException();
+		}
+
+        this.id = id;
+    }
+
+    @Override
+	public void addActivityListener(IActivityListener activityListener) {
+        if (activityListener == null) {
+			throw new NullPointerException();
+		}
+
+        if (activityListeners == null) {
+			activityListeners = new ArrayList();
+		}
+
+        if (!activityListeners.contains(activityListener)) {
+			activityListeners.add(activityListener);
+		}
+
+        strongReferences.add(this);
+    }
+
+    @Override
+	public int compareTo(Object object) {
+        Activity castedObject = (Activity) object;
+
+        int compareTo = Util.compare(
+                activityRequirementBindingsAsArray,
+                castedObject.activityRequirementBindingsAsArray);
+
+        if (compareTo == 0) {
+            compareTo = Util.compare(
+                    activityPatternBindingsAsArray,
+                    castedObject.activityPatternBindingsAsArray);
+
+            if (compareTo == 0) {
+                compareTo = Util.compare(defined, castedObject.defined);
+
+                if (compareTo == 0) {
+                    compareTo = Util.compare(enabled, castedObject.enabled);
+
+                    if (compareTo == 0) {
+                        compareTo = Util.compare(id, castedObject.id);
+
+                        if (compareTo == 0) {
+							compareTo = Util.compare(name, castedObject.name);
+						}
+                    }
+                }
+            }
+        }
+
+        return compareTo;
+    }
+
+    @Override
+	public boolean equals(Object object) {
+        if (!(object instanceof Activity)) {
+			return false;
+		}
+
+        final Activity castedObject = (Activity) object;
+
+        if (!Util.equals(activityRequirementBindings,
+                castedObject.activityRequirementBindings)) {
+            return false;
+        }
+
+        if (!Util.equals(activityPatternBindings,
+                castedObject.activityPatternBindings)) {
+            return false;
+        }
+
+        if (!Util.equals(defined, castedObject.defined)) {
+            return false;
+        }
+
+        if (!Util.equals(enabled, castedObject.enabled)) {
+            return false;
+        }
+
+        if (!Util.equals(id, castedObject.id)) {
+            return false;
+        }
+
+        return Util.equals(name, castedObject.name);
+    }
+
+    void fireActivityChanged(ActivityEvent activityEvent) {
+        if (activityEvent == null) {
+			throw new NullPointerException();
+		}
+
+        if (activityListeners != null) {
+			for (int i = 0; i < activityListeners.size(); i++) {
+				((IActivityListener) activityListeners.get(i))
+                        .activityChanged(activityEvent);
+			}
+		}
+    }
+
+    @Override
+	public Set getActivityRequirementBindings() {
+        return activityRequirementBindings;
+    }
+
+    @Override
+	public Set getActivityPatternBindings() {
+        return activityPatternBindings;
+    }
+
+    @Override
+	public String getId() {
+        return id;
+    }
+
+    @Override
+	public String getName() throws NotDefinedException {
+        if (!defined) {
+			throw new NotDefinedException();
+		}
+
+        return name;
+    }
+
+    @Override
+	public Expression getExpression() {
+    	return expression;
+    }
+
+    @Override
+	public int hashCode() {
+        if (hashCode == HASH_INITIAL) {
+            hashCode = hashCode * HASH_FACTOR
+                    + Util.hashCode(activityRequirementBindings);
+            hashCode = hashCode * HASH_FACTOR
+                    + Util.hashCode(activityPatternBindings);
+            hashCode = hashCode * HASH_FACTOR + Util.hashCode(defined);
+            hashCode = hashCode * HASH_FACTOR + Util.hashCode(enabled);
+            hashCode = hashCode * HASH_FACTOR + Util.hashCode(id);
+            hashCode = hashCode * HASH_FACTOR + Util.hashCode(name);
+            if (hashCode == HASH_INITIAL) {
+				hashCode++;
+			}
+        }
+
+        return hashCode;
+    }
+
+    @Override
+	public boolean isDefined() {
+        return defined;
+    }
+
+    @Override
+	public boolean isEnabled() {
+        return enabled;
+    }
+
+    public boolean isMatch(String string) {
+        if (isDefined()) {
+			for (Iterator iterator = activityPatternBindings.iterator(); iterator
+                    .hasNext();) {
+                ActivityPatternBinding activityPatternBinding = (ActivityPatternBinding) iterator
+                        .next();
+
+                if (activityPatternBinding.isMatch(string)) {
+					return true;
+				}
+            }
+		}
+
+        return false;
+    }
+
+    @Override
+	public void removeActivityListener(IActivityListener activityListener) {
+        if (activityListener == null) {
+			throw new NullPointerException();
+		}
+
+        if (activityListeners != null) {
+			activityListeners.remove(activityListener);
+		}
+
+        if (activityListeners.isEmpty()) {
+			strongReferences.remove(this);
+		}
+    }
+
+    boolean setActivityRequirementBindings(Set activityRequirementBindings) {
+        activityRequirementBindings = Util.safeCopy(
+                activityRequirementBindings, IActivityRequirementBinding.class);
+
+        if (!Util.equals(activityRequirementBindings,
+                this.activityRequirementBindings)) {
+            this.activityRequirementBindings = activityRequirementBindings;
+            this.activityRequirementBindingsAsArray = (IActivityRequirementBinding[]) this.activityRequirementBindings
+                    .toArray(new IActivityRequirementBinding[this.activityRequirementBindings
+                            .size()]);
+            hashCode = HASH_INITIAL;
+            string = null;
+            return true;
+        }
+
+        return false;
+    }
+
+    boolean setActivityPatternBindings(Set activityPatternBindings) {
+        activityPatternBindings = Util.safeCopy(activityPatternBindings,
+                IActivityPatternBinding.class);
+
+        if (!Util.equals(activityPatternBindings, this.activityPatternBindings)) {
+            this.activityPatternBindings = activityPatternBindings;
+            this.activityPatternBindingsAsArray = (IActivityPatternBinding[]) this.activityPatternBindings
+                    .toArray(new IActivityPatternBinding[this.activityPatternBindings
+                            .size()]);
+            hashCode = HASH_INITIAL;
+            string = null;
+            return true;
+        }
+
+        return false;
+    }
+
+    boolean setDefined(boolean defined) {
+        if (defined != this.defined) {
+            this.defined = defined;
+            hashCode = HASH_INITIAL;
+            string = null;
+            return true;
+        }
+
+        return false;
+    }
+
+    boolean setEnabled(boolean enabled) {
+        if (enabled != this.enabled) {
+            this.enabled = enabled;
+            hashCode = HASH_INITIAL;
+            string = null;
+            return true;
+        }
+
+        return false;
+    }
+
+    boolean setName(String name) {
+        if (!Util.equals(name, this.name)) {
+            this.name = name;
+            hashCode = HASH_INITIAL;
+            string = null;
+            return true;
+        }
+
+        return false;
+    }
+
+    void setExpression(Expression exp) {
+    	expression = exp;
+    }
+
+    boolean setDescription(String description) {
+        if (!Util.equals(description, this.description)) {
+            this.description = description;
+            hashCode = HASH_INITIAL;
+            string = null;
+            return true;
+        }
+
+        return false;
+    }
+
+    @Override
+	public String toString() {
+        if (string == null) {
+            final StringBuffer stringBuffer = new StringBuffer();
+            stringBuffer.append('[');
+            stringBuffer.append(activityRequirementBindings);
+            stringBuffer.append(',');
+            stringBuffer.append(activityPatternBindings);
+            stringBuffer.append(',');
+            stringBuffer.append(defined);
+            stringBuffer.append(',');
+            stringBuffer.append(enabled);
+            stringBuffer.append(',');
+            stringBuffer.append(id);
+            stringBuffer.append(',');
+            stringBuffer.append(name);
+            stringBuffer.append(']');
+            string = stringBuffer.toString();
+        }
+
+        return string;
+    }
+
+    @Override
+	public String getDescription() throws NotDefinedException {
+        if (!defined) {
+			throw new NotDefinedException();
+		}
+
+        return description;
+    }
+
+    @Override
+	public boolean isDefaultEnabled() {
+        return defaultEnabled;
+    }
+
+    boolean setDefaultEnabled(boolean defaultEnabled) {
+        if (!Util.equals(defaultEnabled, this.defaultEnabled)) {
+            this.defaultEnabled = defaultEnabled;
+            hashCode = HASH_INITIAL;
+            string = null;
+            return true;
+        }
+
+        return false;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ActivityDefinition.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ActivityDefinition.java
new file mode 100644
index 0000000..af77bc2
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ActivityDefinition.java
@@ -0,0 +1,192 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.activities;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.ui.internal.util.Util;
+
+public final class ActivityDefinition implements Comparable {
+    private final static int HASH_FACTOR = 89;
+
+    private final static int HASH_INITIAL = ActivityDefinition.class.getName()
+            .hashCode();
+
+    static Map activityDefinitionsById(Collection activityDefinitions,
+            boolean allowNullIds) {
+        if (activityDefinitions == null) {
+			throw new NullPointerException();
+		}
+
+        Map map = new HashMap();
+        Iterator iterator = activityDefinitions.iterator();
+
+        while (iterator.hasNext()) {
+            Object object = iterator.next();
+            Util.assertInstance(object, ActivityDefinition.class);
+            ActivityDefinition activityDefinition = (ActivityDefinition) object;
+            String id = activityDefinition.getId();
+
+            if (allowNullIds || id != null) {
+				map.put(id, activityDefinition);
+			}
+        }
+
+        return map;
+    }
+
+    static Map activityDefinitionsByName(Collection activityDefinitions,
+            boolean allowNullNames) {
+        if (activityDefinitions == null) {
+			throw new NullPointerException();
+		}
+
+        Map map = new HashMap();
+        Iterator iterator = activityDefinitions.iterator();
+
+        while (iterator.hasNext()) {
+            Object object = iterator.next();
+            Util.assertInstance(object, ActivityDefinition.class);
+            ActivityDefinition activityDefinition = (ActivityDefinition) object;
+            String name = activityDefinition.getName();
+
+            if (allowNullNames || name != null) {
+                Collection activityDefinitions2 = (Collection) map.get(name);
+
+                if (activityDefinitions2 == null) {
+                    activityDefinitions2 = new HashSet();
+                    map.put(name, activityDefinitions2);
+                }
+
+                activityDefinitions2.add(activityDefinition);
+            }
+        }
+
+        return map;
+    }
+
+    private transient int hashCode = HASH_INITIAL;
+
+    private String id;
+
+    private String name;
+
+    private String sourceId;
+
+    private String description;
+
+    private transient String string;
+
+	private Expression enabledWhen;
+
+    public ActivityDefinition(String id, String name, String sourceId,
+            String description) {
+        this.id = id;
+        this.name = name;
+        this.sourceId = sourceId;
+        this.description = description;
+    }
+
+    @Override
+	public int compareTo(Object object) {
+        ActivityDefinition castedObject = (ActivityDefinition) object;
+        int compareTo = Util.compare(id, castedObject.id);
+
+        if (compareTo == 0) {
+            compareTo = Util.compare(name, castedObject.name);
+
+            if (compareTo == 0) {
+				compareTo = Util.compare(sourceId, castedObject.sourceId);
+			}
+        }
+
+        return compareTo;
+    }
+
+    @Override
+	public boolean equals(Object object) {
+        if (!(object instanceof ActivityDefinition)) {
+			return false;
+		}
+
+        final ActivityDefinition castedObject = (ActivityDefinition) object;
+        if (!Util.equals(id, castedObject.id)) {
+            return false;
+        }
+
+        if (!Util.equals(name, castedObject.name)) {
+            return false;
+        }
+
+        return Util.equals(sourceId, castedObject.sourceId);
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getSourceId() {
+        return sourceId;
+    }
+
+    @Override
+	public int hashCode() {
+        if (hashCode == HASH_INITIAL) {
+            hashCode = hashCode * HASH_FACTOR + Util.hashCode(id);
+            hashCode = hashCode * HASH_FACTOR + Util.hashCode(name);
+            hashCode = hashCode * HASH_FACTOR + Util.hashCode(sourceId);
+            if (hashCode == HASH_INITIAL) {
+				hashCode++;
+			}
+        }
+
+        return hashCode;
+    }
+
+    @Override
+	public String toString() {
+        if (string == null) {
+            final StringBuffer stringBuffer = new StringBuffer();
+            stringBuffer.append('[');
+            stringBuffer.append(id);
+            stringBuffer.append(',');
+            stringBuffer.append(name);
+            stringBuffer.append(',');
+            stringBuffer.append(sourceId);
+            stringBuffer.append(']');
+            string = stringBuffer.toString();
+        }
+
+        return string;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    void setEnabledWhen(Expression expression) {
+    	enabledWhen = expression;
+    }
+
+    public Expression getEnabledWhen() {
+    	return enabledWhen;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ActivityPatternBinding.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ActivityPatternBinding.java
new file mode 100644
index 0000000..b36c671
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ActivityPatternBinding.java
@@ -0,0 +1,186 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.activities;
+
+import java.util.regex.Pattern;
+
+import org.eclipse.ui.activities.IActivityPatternBinding;
+import org.eclipse.ui.internal.util.Util;
+
+public final class ActivityPatternBinding implements IActivityPatternBinding {
+    private final static int HASH_FACTOR = 89;
+
+    private final static int HASH_INITIAL = ActivityPatternBinding.class
+            .getName().hashCode();
+
+    private String activityId;
+
+    private transient int hashCode = HASH_INITIAL;
+
+    private Pattern pattern;
+
+    private String patternString;
+
+    private boolean isEqualityPattern;
+
+    private transient String string;
+
+    /**
+     * @param activityId The id.
+     * @param pattern A string that will be compiled to a pattern matcher.
+     */
+    public ActivityPatternBinding(String activityId, String pattern) {
+    	this(activityId, Pattern.compile(pattern));
+    }
+
+    /**
+     *
+     * @param activityId The id
+     * @param pattern This string will be used as plain string, or as pattern-
+     * 		  matcher pattern. The use depends on parameter <code>nonRegExp</code>.
+     * @param isEqualityPattern If true the <code>pattern</code> string will be
+     * 	      interpreted as normal string, not as pattern.
+     */
+    public ActivityPatternBinding(String activityId, String pattern, boolean
+    		isEqualityPattern) {
+    	if (pattern == null) {
+			throw new NullPointerException();
+		}
+
+    	this.activityId = activityId;
+    	this.isEqualityPattern = isEqualityPattern;
+    	if (isEqualityPattern) {
+    		this.patternString = pattern;
+    		this.pattern = null;
+    	} else {
+    		this.patternString = null;
+    		this.pattern = Pattern.compile(pattern);
+    	}
+    }
+
+    public ActivityPatternBinding(String activityId, Pattern pattern) {
+        if (pattern == null) {
+			throw new NullPointerException();
+		}
+
+        this.activityId = activityId;
+        this.pattern = pattern;
+        this.isEqualityPattern = false;
+        this.patternString = null;
+    }
+
+    @Override
+	public int compareTo(Object object) {
+        ActivityPatternBinding castedObject = (ActivityPatternBinding) object;
+        int compareTo = Util.compare(activityId, castedObject.activityId);
+
+        if (compareTo == 0) {
+        	compareTo = Util.compare(isEqualityPattern,
+					castedObject.isEqualityPattern);
+
+        	if (compareTo == 0)
+				compareTo = Util.compare(getPattern().pattern(), castedObject
+						.getPattern().pattern());
+		}
+
+        return compareTo;
+    }
+
+    @Override
+	public boolean equals(Object object) {
+        if (!(object instanceof ActivityPatternBinding)) {
+			return false;
+		}
+
+        final ActivityPatternBinding castedObject = (ActivityPatternBinding) object;
+        if (!Util.equals(activityId, castedObject.activityId)) {
+            return false;
+        }
+
+        if (!Util.equals(isEqualityPattern, castedObject.isEqualityPattern)) {
+            return false;
+        }
+
+        return Util.equals(getPattern(), castedObject.getPattern());
+    }
+
+    @Override
+	public String getActivityId() {
+        return activityId;
+    }
+
+    @Override
+	public Pattern getPattern() {
+    	if (pattern == null) {
+    		pattern = Pattern.compile(PatternUtil.quotePattern(patternString));
+    	}
+    	return pattern;
+    }
+
+    @Override
+	public String getString() {
+    	if (isEqualityPattern) {
+    		return patternString;
+    	}
+    	return getPattern().pattern();
+    }
+
+	@Override
+	public boolean isEqualityPattern() {
+		return isEqualityPattern;
+	}
+
+
+    @Override
+	public int hashCode() {
+        if (hashCode == HASH_INITIAL) {
+            hashCode = hashCode * HASH_FACTOR + Util.hashCode(activityId);
+            hashCode = hashCode * HASH_FACTOR + Util.hashCode(pattern);
+            if (hashCode == HASH_INITIAL) {
+				hashCode++;
+			}
+        }
+
+        return hashCode;
+    }
+
+    @Override
+	public String toString() {
+        if (string == null) {
+            final StringBuffer stringBuffer = new StringBuffer();
+            stringBuffer.append('[');
+            stringBuffer.append(activityId);
+            stringBuffer.append(',');
+            stringBuffer.append(isEqualityPattern());
+            stringBuffer.append(',');
+            stringBuffer.append(getString());
+            stringBuffer.append(']');
+            string = stringBuffer.toString();
+        }
+
+        return string;
+    }
+
+	/**
+	 * Returns whether this binding's pattern matches the given string.
+	 *
+	 * @param toMatch the string to match
+	 * @return <code>true</code> if it matches, <code>false</code> if not
+     * @since 3.1
+	 */
+	public boolean isMatch(String toMatch) {
+		if (isEqualityPattern) {
+			return patternString.equals(toMatch);
+		}
+		return pattern.matcher(toMatch).matches();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ActivityPatternBindingDefinition.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ActivityPatternBindingDefinition.java
new file mode 100644
index 0000000..09fb6be
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ActivityPatternBindingDefinition.java
@@ -0,0 +1,178 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.activities;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.eclipse.ui.internal.util.Util;
+
+public final class ActivityPatternBindingDefinition {
+    private final static int HASH_FACTOR = 89;
+
+    private final static int HASH_INITIAL = ActivityPatternBindingDefinition.class
+            .getName().hashCode();
+
+    static Map activityPatternBindingDefinitionsByActivityId(
+            Collection activityPatternBindingDefinitions) {
+        if (activityPatternBindingDefinitions == null) {
+			throw new NullPointerException();
+		}
+
+        Map map = new HashMap();
+        Iterator iterator = activityPatternBindingDefinitions.iterator();
+
+        while (iterator.hasNext()) {
+            Object object = iterator.next();
+            Util.assertInstance(object, ActivityPatternBindingDefinition.class);
+            ActivityPatternBindingDefinition activityPatternBindingDefinition = (ActivityPatternBindingDefinition) object;
+            String activityId = activityPatternBindingDefinition
+                    .getActivityId();
+
+            if (activityId != null) {
+                Collection activityPatternBindingDefinitions2 = (Collection) map
+                        .get(activityId);
+
+                if (activityPatternBindingDefinitions2 == null) {
+                    activityPatternBindingDefinitions2 = new ArrayList();
+                    map.put(activityId, activityPatternBindingDefinitions2);
+                }
+
+                activityPatternBindingDefinitions2
+                        .add(activityPatternBindingDefinition);
+            }
+        }
+
+        return map;
+    }
+
+    private String activityId;
+
+    private transient int hashCode = HASH_INITIAL;
+
+    private String pattern;
+
+    private String sourceId;
+
+    private transient String string;
+
+    /**
+     * If the string is taken "as is", without interpreting it as a regular
+     * expression.
+     */
+    private boolean isEqualityPattern;
+
+    public ActivityPatternBindingDefinition(String activityId, String pattern,
+            String sourceId) {
+    	this(activityId, pattern, sourceId, false);
+    }
+
+    public ActivityPatternBindingDefinition(String activityId, String pattern,
+			String sourceId, boolean isEqualityPattern) {
+		this.activityId = activityId;
+		this.pattern = pattern;
+		this.sourceId = sourceId;
+		this.isEqualityPattern = isEqualityPattern;
+	}
+
+    public int compareTo(Object object) {
+        ActivityPatternBindingDefinition castedObject = (ActivityPatternBindingDefinition) object;
+        int compareTo = Util.compare(activityId, castedObject.activityId);
+
+        if (compareTo == 0) {
+            compareTo = Util.compare(pattern, castedObject.pattern);
+
+            if (compareTo == 0) {
+            	compareTo = Util.compare(isEqualityPattern, castedObject.isEqualityPattern);
+
+            	if (compareTo == 0)
+            		compareTo = Util.compare(sourceId, castedObject.sourceId);
+			}
+        }
+
+        return compareTo;
+    }
+
+    @Override
+	public boolean equals(Object object) {
+        if (!(object instanceof ActivityPatternBindingDefinition)) {
+			return false;
+		}
+
+        final ActivityPatternBindingDefinition castedObject = (ActivityPatternBindingDefinition) object;
+        if (!Util.equals(activityId, castedObject.activityId)) {
+            return false;
+        }
+
+        if (!Util.equals(pattern, castedObject.pattern)) {
+            return false;
+        }
+
+        if (!Util.equals(isEqualityPattern, castedObject.isEqualityPattern)) {
+            return false;
+        }
+
+        return Util.equals(sourceId, castedObject.sourceId);
+    }
+
+    public String getActivityId() {
+        return activityId;
+    }
+
+    public String getPattern() {
+        return pattern;
+    }
+
+    public String getSourceId() {
+        return sourceId;
+    }
+
+    public boolean isEqualityPattern() {
+    	return isEqualityPattern;
+    }
+
+    @Override
+	public int hashCode() {
+        if (hashCode == HASH_INITIAL) {
+            hashCode = hashCode * HASH_FACTOR + Util.hashCode(activityId);
+            hashCode = hashCode * HASH_FACTOR + Util.hashCode(pattern);
+            hashCode = hashCode * HASH_FACTOR + Util.hashCode(sourceId);
+            if (hashCode == HASH_INITIAL) {
+				hashCode++;
+			}
+        }
+
+        return hashCode;
+    }
+
+    @Override
+	public String toString() {
+        if (string == null) {
+            final StringBuffer stringBuffer = new StringBuffer();
+            stringBuffer.append('[');
+            stringBuffer.append(activityId);
+            stringBuffer.append(',');
+            stringBuffer.append(isEqualityPattern);
+            stringBuffer.append(',');
+            stringBuffer.append(pattern);
+            stringBuffer.append(',');
+            stringBuffer.append(sourceId);
+            stringBuffer.append(']');
+            string = stringBuffer.toString();
+        }
+
+        return string;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ActivityPropertyTester.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ActivityPropertyTester.java
new file mode 100644
index 0000000..7fc99ce
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ActivityPropertyTester.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.activities;
+
+import org.eclipse.core.expressions.PropertyTester;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.activities.IActivityManager;
+import org.eclipse.ui.activities.IWorkbenchActivitySupport;
+import org.eclipse.ui.activities.WorkbenchActivityHelper;
+
+/**
+ * An expressions property tester that tests whether or not an activity or
+ * category of activities is enabled. Useful for cross-component links and to
+ * control discoverability of functionality.
+ *
+ * @since 3.3
+ */
+public class ActivityPropertyTester extends PropertyTester {
+
+	private static final String PROPERTY_IS_ACTIVITY_ENABLED = "isActivityEnabled"; //$NON-NLS-1$
+	private static final String PROPERTY_IS_CATEGORY_ENABLED = "isCategoryEnabled"; //$NON-NLS-1$
+
+	@Override
+	public boolean test(Object receiver, String property, Object[] args,
+			Object expectedValue) {
+		if (args.length == 1 && receiver instanceof IWorkbench && args[0] instanceof String) {
+			if (PROPERTY_IS_ACTIVITY_ENABLED.equals(property)) {
+				return isActivityEnabled((String) args[0], (IWorkbench)receiver);
+			} else if (PROPERTY_IS_CATEGORY_ENABLED.equals(property)) {
+				return isCategoryEnabled((String) args[0], (IWorkbench)receiver);
+			}
+		}
+		return false;
+	}
+
+	private static boolean isActivityEnabled(String activityId, IWorkbench workbench) {
+		try {
+			IWorkbenchActivitySupport workbenchActivitySupport =
+					workbench.getActivitySupport();
+			IActivityManager activityManager = workbenchActivitySupport
+					.getActivityManager();
+			return activityManager.getActivity(activityId).isEnabled();
+		} catch (Exception e) {
+			// workbench not yet activated; nothing enabled yet
+		}
+		return false;
+	}
+
+	private static boolean isCategoryEnabled(String categoryId, IWorkbench workbench) {
+		try {
+			IWorkbenchActivitySupport workbenchActivitySupport =
+					workbench.getActivitySupport();
+			IActivityManager activityManager = workbenchActivitySupport
+					.getActivityManager();
+			return WorkbenchActivityHelper.isEnabled(activityManager,
+					categoryId);
+		} catch (Exception e) {
+			// workbench not yet activated; nothing enabled yet
+		}
+		return false;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ActivityRegistryEvent.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ActivityRegistryEvent.java
new file mode 100644
index 0000000..cf8a5b0
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ActivityRegistryEvent.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 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.ui.internal.activities;
+
+final class ActivityRegistryEvent {
+    private IActivityRegistry activityRegistry;
+
+    ActivityRegistryEvent(IActivityRegistry activityRegistry) {
+        if (activityRegistry == null) {
+			throw new NullPointerException();
+		}
+
+        this.activityRegistry = activityRegistry;
+    }
+
+    IActivityRegistry getActivityRegistry() {
+        return activityRegistry;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ActivityRequirementBinding.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ActivityRequirementBinding.java
new file mode 100644
index 0000000..f9f7b8f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ActivityRequirementBinding.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2014 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.ui.internal.activities;
+
+import org.eclipse.ui.activities.IActivityRequirementBinding;
+import org.eclipse.ui.internal.util.Util;
+
+public final class ActivityRequirementBinding implements
+        IActivityRequirementBinding {
+    private final static int HASH_FACTOR = 89;
+
+    private final static int HASH_INITIAL = ActivityRequirementBinding.class
+            .getName().hashCode();
+
+    private String requiredActivityId;
+
+    private transient int hashCode = HASH_INITIAL;
+
+    private String activityId;
+
+    private transient String string;
+
+    public ActivityRequirementBinding(String requiredActivityId,
+            String activityId) {
+        if (requiredActivityId == null || activityId == null) {
+			throw new NullPointerException();
+		}
+
+        this.requiredActivityId = requiredActivityId;
+        this.activityId = activityId;
+    }
+
+    @Override
+	public int compareTo(Object object) {
+        ActivityRequirementBinding castedObject = (ActivityRequirementBinding) object;
+        int compareTo = Util.compare(requiredActivityId,
+                castedObject.requiredActivityId);
+
+        if (compareTo == 0) {
+			compareTo = Util.compare(activityId, castedObject.activityId);
+		}
+
+        return compareTo;
+    }
+
+    @Override
+	public boolean equals(Object object) {
+        if (!(object instanceof ActivityRequirementBinding)) {
+			return false;
+		}
+
+        final ActivityRequirementBinding castedObject = (ActivityRequirementBinding) object;
+        if (!Util.equals(requiredActivityId, castedObject.requiredActivityId)) {
+            return false;
+        }
+
+        return Util.equals(activityId, castedObject.activityId);
+    }
+
+    @Override
+	public String getRequiredActivityId() {
+        return requiredActivityId;
+    }
+
+    @Override
+	public String getActivityId() {
+        return activityId;
+    }
+
+    @Override
+	public int hashCode() {
+        if (hashCode == HASH_INITIAL) {
+            hashCode = hashCode * HASH_FACTOR
+                    + Util.hashCode(requiredActivityId);
+            hashCode = hashCode * HASH_FACTOR + Util.hashCode(activityId);
+            if (hashCode == HASH_INITIAL) {
+				hashCode++;
+			}
+        }
+
+        return hashCode;
+    }
+
+    @Override
+	public String toString() {
+        if (string == null) {
+            final StringBuffer stringBuffer = new StringBuffer();
+            stringBuffer.append('[');
+            stringBuffer.append(requiredActivityId);
+            stringBuffer.append(',');
+            stringBuffer.append(activityId);
+            stringBuffer.append(']');
+            string = stringBuffer.toString();
+        }
+
+        return string;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ActivityRequirementBindingDefinition.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ActivityRequirementBindingDefinition.java
new file mode 100644
index 0000000..ec8e306
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ActivityRequirementBindingDefinition.java
@@ -0,0 +1,158 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.activities;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.eclipse.ui.internal.util.Util;
+
+public final class ActivityRequirementBindingDefinition {
+    private final static int HASH_FACTOR = 89;
+
+    private final static int HASH_INITIAL = ActivityRequirementBindingDefinition.class
+            .getName().hashCode();
+
+    static Map activityRequirementBindingDefinitionsByActivityId(
+            Collection activityRequirementBindingDefinitions) {
+        if (activityRequirementBindingDefinitions == null) {
+			throw new NullPointerException();
+		}
+
+        Map map = new HashMap();
+        Iterator iterator = activityRequirementBindingDefinitions.iterator();
+
+        while (iterator.hasNext()) {
+            Object object = iterator.next();
+            Util.assertInstance(object,
+                    ActivityRequirementBindingDefinition.class);
+            ActivityRequirementBindingDefinition activityRequirementBindingDefinition = (ActivityRequirementBindingDefinition) object;
+            String parentActivityId = activityRequirementBindingDefinition
+                    .getActivityId();
+
+            if (parentActivityId != null) {
+                Collection activityRequirementBindingDefinitions2 = (Collection) map
+                        .get(parentActivityId);
+
+                if (activityRequirementBindingDefinitions2 == null) {
+                    activityRequirementBindingDefinitions2 = new HashSet();
+                    map.put(parentActivityId,
+                            activityRequirementBindingDefinitions2);
+                }
+
+                activityRequirementBindingDefinitions2
+                        .add(activityRequirementBindingDefinition);
+            }
+        }
+
+        return map;
+    }
+
+    private String requiredActivityId;
+
+    private transient int hashCode = HASH_INITIAL;
+
+    private String activityId;
+
+    private String sourceId;
+
+    private transient String string;
+
+    public ActivityRequirementBindingDefinition(String requiredActivityId,
+            String activityId, String sourceId) {
+        this.requiredActivityId = requiredActivityId;
+        this.activityId = activityId;
+        this.sourceId = sourceId;
+    }
+
+    public int compareTo(Object object) {
+        ActivityRequirementBindingDefinition castedObject = (ActivityRequirementBindingDefinition) object;
+        int compareTo = Util.compare(requiredActivityId,
+                castedObject.requiredActivityId);
+
+        if (compareTo == 0) {
+            compareTo = Util.compare(activityId, castedObject.activityId);
+
+            if (compareTo == 0) {
+				compareTo = Util.compare(sourceId, castedObject.sourceId);
+			}
+        }
+
+        return compareTo;
+    }
+
+    @Override
+	public boolean equals(Object object) {
+        if (!(object instanceof ActivityRequirementBindingDefinition)) {
+			return false;
+		}
+
+        final ActivityRequirementBindingDefinition castedObject = (ActivityRequirementBindingDefinition) object;
+        if (!Util.equals(requiredActivityId,
+                castedObject.requiredActivityId)) {
+            return false;
+        }
+
+        if (!Util.equals(activityId, castedObject.activityId)) {
+            return false;
+        }
+
+        return Util.equals(sourceId, castedObject.sourceId);
+    }
+
+    public String getRequiredActivityId() {
+        return requiredActivityId;
+    }
+
+    public String getActivityId() {
+        return activityId;
+    }
+
+    public String getSourceId() {
+        return sourceId;
+    }
+
+    @Override
+	public int hashCode() {
+        if (hashCode == HASH_INITIAL) {
+            hashCode = hashCode * HASH_FACTOR
+                    + Util.hashCode(requiredActivityId);
+            hashCode = hashCode * HASH_FACTOR + Util.hashCode(activityId);
+            hashCode = hashCode * HASH_FACTOR + Util.hashCode(sourceId);
+            if (hashCode == HASH_INITIAL) {
+				hashCode++;
+			}
+        }
+
+        return hashCode;
+    }
+
+    @Override
+	public String toString() {
+        if (string == null) {
+            final StringBuffer stringBuffer = new StringBuffer();
+            stringBuffer.append('[');
+            stringBuffer.append(requiredActivityId);
+            stringBuffer.append(',');
+            stringBuffer.append(activityId);
+            stringBuffer.append(',');
+            stringBuffer.append(sourceId);
+            stringBuffer.append(']');
+            string = stringBuffer.toString();
+        }
+
+        return string;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/Category.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/Category.java
new file mode 100644
index 0000000..e86cdbf
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/Category.java
@@ -0,0 +1,267 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.activities;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.ui.activities.CategoryEvent;
+import org.eclipse.ui.activities.ICategory;
+import org.eclipse.ui.activities.ICategoryActivityBinding;
+import org.eclipse.ui.activities.ICategoryListener;
+import org.eclipse.ui.activities.NotDefinedException;
+import org.eclipse.ui.internal.util.Util;
+
+final class Category implements ICategory {
+    private final static int HASH_FACTOR = 89;
+
+    private final static int HASH_INITIAL = Category.class.getName().hashCode();
+
+    private final static Set strongReferences = new HashSet();
+
+    private Set categoryActivityBindings;
+
+    private transient ICategoryActivityBinding[] categoryActivityBindingsAsArray;
+
+    private List categoryListeners;
+
+    private boolean defined;
+
+    private transient int hashCode = HASH_INITIAL;
+
+    private String id;
+
+    private String name;
+
+    private transient String string;
+
+    private String description;
+
+    Category(String id) {
+        if (id == null) {
+			throw new NullPointerException();
+		}
+
+        this.id = id;
+    }
+
+    @Override
+	public void addCategoryListener(ICategoryListener categoryListener) {
+        if (categoryListener == null) {
+			throw new NullPointerException();
+		}
+
+        if (categoryListeners == null) {
+			categoryListeners = new ArrayList();
+		}
+
+        if (!categoryListeners.contains(categoryListener)) {
+			categoryListeners.add(categoryListener);
+		}
+
+        strongReferences.add(this);
+    }
+
+    @Override
+	public int compareTo(Object object) {
+        Category castedObject = (Category) object;
+        int compareTo = Util.compare(
+                categoryActivityBindingsAsArray,
+                castedObject.categoryActivityBindingsAsArray);
+
+        if (compareTo == 0) {
+            compareTo = Util.compare(defined, castedObject.defined);
+
+            if (compareTo == 0) {
+                compareTo = Util.compare(id, castedObject.id);
+
+                if (compareTo == 0) {
+					compareTo = Util.compare(name, castedObject.name);
+				}
+            }
+        }
+
+        return compareTo;
+    }
+
+    @Override
+	public boolean equals(Object object) {
+        if (!(object instanceof Category)) {
+			return false;
+		}
+
+        final Category castedObject = (Category) object;
+        if (!Util.equals(categoryActivityBindings,
+                castedObject.categoryActivityBindings)) {
+            return false;
+        }
+
+        if (!Util.equals(defined, castedObject.defined)) {
+            return false;
+        }
+
+        if (!Util.equals(id, castedObject.id)) {
+            return false;
+        }
+
+        return Util.equals(name, castedObject.name);
+    }
+
+    void fireCategoryChanged(CategoryEvent categoryEvent) {
+        if (categoryEvent == null) {
+			throw new NullPointerException();
+		}
+
+        if (categoryListeners != null) {
+			for (int i = 0; i < categoryListeners.size(); i++) {
+				((ICategoryListener) categoryListeners.get(i))
+                        .categoryChanged(categoryEvent);
+			}
+		}
+    }
+
+    @Override
+	public Set getCategoryActivityBindings() {
+        return categoryActivityBindings;
+    }
+
+    @Override
+	public String getId() {
+        return id;
+    }
+
+    @Override
+	public String getName() throws NotDefinedException {
+        if (!defined) {
+			throw new NotDefinedException();
+		}
+
+        return name;
+    }
+
+    @Override
+	public int hashCode() {
+        if (hashCode == HASH_INITIAL) {
+            hashCode = hashCode * HASH_FACTOR
+                    + Util.hashCode(categoryActivityBindings);
+            hashCode = hashCode * HASH_FACTOR + Util.hashCode(defined);
+            hashCode = hashCode * HASH_FACTOR + Util.hashCode(id);
+            hashCode = hashCode * HASH_FACTOR + Util.hashCode(name);
+            if (hashCode == HASH_INITIAL) {
+				hashCode++;
+			}
+        }
+
+        return hashCode;
+    }
+
+    @Override
+	public boolean isDefined() {
+        return defined;
+    }
+
+    @Override
+	public void removeCategoryListener(ICategoryListener categoryListener) {
+        if (categoryListener == null) {
+			throw new NullPointerException();
+		}
+
+        if (categoryListeners != null) {
+			categoryListeners.remove(categoryListener);
+		}
+
+        if (categoryListeners.isEmpty()) {
+			strongReferences.remove(this);
+		}
+    }
+
+    boolean setCategoryActivityBindings(Set categoryActivityBindings) {
+        categoryActivityBindings = Util.safeCopy(categoryActivityBindings,
+                ICategoryActivityBinding.class);
+
+        if (!Util.equals(categoryActivityBindings,
+                this.categoryActivityBindings)) {
+            this.categoryActivityBindings = categoryActivityBindings;
+            this.categoryActivityBindingsAsArray = (ICategoryActivityBinding[]) this.categoryActivityBindings
+                    .toArray(new ICategoryActivityBinding[this.categoryActivityBindings
+                            .size()]);
+            hashCode = HASH_INITIAL;
+            string = null;
+            return true;
+        }
+
+        return false;
+    }
+
+    boolean setDefined(boolean defined) {
+        if (defined != this.defined) {
+            this.defined = defined;
+            hashCode = HASH_INITIAL;
+            string = null;
+            return true;
+        }
+
+        return false;
+    }
+
+    boolean setName(String name) {
+        if (!Util.equals(name, this.name)) {
+            this.name = name;
+            hashCode = HASH_INITIAL;
+            string = null;
+            return true;
+        }
+
+        return false;
+    }
+
+    @Override
+	public String toString() {
+        if (string == null) {
+            final StringBuffer stringBuffer = new StringBuffer();
+            stringBuffer.append('[');
+            stringBuffer.append(categoryActivityBindings);
+            stringBuffer.append(',');
+            stringBuffer.append(defined);
+            stringBuffer.append(',');
+            stringBuffer.append(id);
+            stringBuffer.append(',');
+            stringBuffer.append(name);
+            stringBuffer.append(']');
+            string = stringBuffer.toString();
+        }
+
+        return string;
+    }
+
+    @Override
+	public String getDescription() throws NotDefinedException {
+        if (!defined) {
+			throw new NotDefinedException();
+		}
+
+        return description;
+    }
+
+    public boolean setDescription(String description) {
+        if (!Util.equals(description, this.description)) {
+            this.description = description;
+            hashCode = HASH_INITIAL;
+            string = null;
+            return true;
+        }
+
+        return false;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/CategoryActivityBinding.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/CategoryActivityBinding.java
new file mode 100644
index 0000000..2453b37
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/CategoryActivityBinding.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2014 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.ui.internal.activities;
+
+import org.eclipse.ui.activities.ICategoryActivityBinding;
+import org.eclipse.ui.internal.util.Util;
+
+public final class CategoryActivityBinding implements ICategoryActivityBinding {
+    private final static int HASH_FACTOR = 89;
+
+    private final static int HASH_INITIAL = CategoryActivityBinding.class
+            .getName().hashCode();
+
+    private String activityId;
+
+    private String categoryId;
+
+    private transient int hashCode = HASH_INITIAL;
+
+    private transient String string;
+
+    public CategoryActivityBinding(String activityId, String categoryId) {
+        if (activityId == null || categoryId == null) {
+			throw new NullPointerException();
+		}
+
+        this.activityId = activityId;
+        this.categoryId = categoryId;
+    }
+
+    @Override
+	public int compareTo(Object object) {
+        CategoryActivityBinding castedObject = (CategoryActivityBinding) object;
+        int compareTo = Util.compare(activityId, castedObject.activityId);
+
+        if (compareTo == 0) {
+			compareTo = Util.compare(categoryId, castedObject.categoryId);
+		}
+
+        return compareTo;
+    }
+
+    @Override
+	public boolean equals(Object object) {
+        if (!(object instanceof CategoryActivityBinding)) {
+			return false;
+		}
+
+        final CategoryActivityBinding castedObject = (CategoryActivityBinding) object;
+        if (!Util.equals(activityId, castedObject.activityId)) {
+            return false;
+        }
+
+        return Util.equals(categoryId, castedObject.categoryId);
+    }
+
+    @Override
+	public String getActivityId() {
+        return activityId;
+    }
+
+    @Override
+	public String getCategoryId() {
+        return categoryId;
+    }
+
+    @Override
+	public int hashCode() {
+        if (hashCode == HASH_INITIAL){
+            hashCode = hashCode * HASH_FACTOR + Util.hashCode(activityId);
+            hashCode = hashCode * HASH_FACTOR + Util.hashCode(categoryId);
+            if (hashCode == HASH_INITIAL) {
+				hashCode++;
+			}
+        }
+
+        return hashCode;
+    }
+
+    @Override
+	public String toString() {
+        if (string == null) {
+            final StringBuffer stringBuffer = new StringBuffer();
+            stringBuffer.append('[');
+            stringBuffer.append(activityId);
+            stringBuffer.append(',');
+            stringBuffer.append(categoryId);
+            stringBuffer.append(']');
+            string = stringBuffer.toString();
+        }
+
+        return string;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/CategoryActivityBindingDefinition.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/CategoryActivityBindingDefinition.java
new file mode 100644
index 0000000..7735589
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/CategoryActivityBindingDefinition.java
@@ -0,0 +1,155 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2014 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.ui.internal.activities;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.eclipse.ui.internal.util.Util;
+
+public final class CategoryActivityBindingDefinition {
+    private final static int HASH_FACTOR = 89;
+
+    private final static int HASH_INITIAL = CategoryActivityBindingDefinition.class
+            .getName().hashCode();
+
+    static Map categoryActivityBindingDefinitionsByCategoryId(
+            Collection categoryActivityBindingDefinitions) {
+        if (categoryActivityBindingDefinitions == null) {
+			throw new NullPointerException();
+		}
+
+        Map map = new HashMap();
+        Iterator iterator = categoryActivityBindingDefinitions.iterator();
+
+        while (iterator.hasNext()) {
+            Object object = iterator.next();
+            Util
+                    .assertInstance(object,
+                            CategoryActivityBindingDefinition.class);
+            CategoryActivityBindingDefinition categoryActivityBindingDefinition = (CategoryActivityBindingDefinition) object;
+            String categoryId = categoryActivityBindingDefinition
+                    .getCategoryId();
+
+            if (categoryId != null) {
+                Collection categoryActivityBindingDefinitions2 = (Collection) map
+                        .get(categoryId);
+
+                if (categoryActivityBindingDefinitions2 == null) {
+                    categoryActivityBindingDefinitions2 = new HashSet();
+                    map.put(categoryId, categoryActivityBindingDefinitions2);
+                }
+
+                categoryActivityBindingDefinitions2
+                        .add(categoryActivityBindingDefinition);
+            }
+        }
+
+        return map;
+    }
+
+    private String activityId;
+
+    private String categoryId;
+
+    private transient int hashCode = HASH_INITIAL;
+
+    private String sourceId;
+
+    private transient String string;
+
+    public CategoryActivityBindingDefinition(String activityId,
+            String categoryId, String sourceId) {
+        this.activityId = activityId;
+        this.categoryId = categoryId;
+        this.sourceId = sourceId;
+    }
+
+    public int compareTo(Object object) {
+        CategoryActivityBindingDefinition castedObject = (CategoryActivityBindingDefinition) object;
+        int compareTo = Util.compare(activityId, castedObject.activityId);
+
+        if (compareTo == 0) {
+            compareTo = Util.compare(categoryId, castedObject.categoryId);
+
+            if (compareTo == 0) {
+				compareTo = Util.compare(sourceId, castedObject.sourceId);
+			}
+        }
+
+        return compareTo;
+    }
+
+    @Override
+	public boolean equals(Object object) {
+        if (!(object instanceof CategoryActivityBindingDefinition)) {
+			return false;
+		}
+
+        final CategoryActivityBindingDefinition castedObject = (CategoryActivityBindingDefinition) object;
+        if (!Util.equals(activityId, castedObject.activityId)) {
+            return false;
+        }
+
+        if (!Util.equals(categoryId, castedObject.categoryId)) {
+            return false;
+        }
+
+        return Util.equals(sourceId, castedObject.sourceId);
+    }
+
+    public String getActivityId() {
+        return activityId;
+    }
+
+    public String getCategoryId() {
+        return categoryId;
+    }
+
+    public String getSourceId() {
+        return sourceId;
+    }
+
+    @Override
+	public int hashCode() {
+        if (hashCode == HASH_INITIAL) {
+            hashCode = hashCode * HASH_FACTOR + Util.hashCode(activityId);
+            hashCode = hashCode * HASH_FACTOR + Util.hashCode(categoryId);
+            hashCode = hashCode * HASH_FACTOR + Util.hashCode(sourceId);
+            if (hashCode == HASH_INITIAL) {
+				hashCode++;
+			}
+        }
+
+        return hashCode;
+    }
+
+    @Override
+	public String toString() {
+        if (string == null) {
+            final StringBuffer stringBuffer = new StringBuffer();
+            stringBuffer.append('[');
+            stringBuffer.append(activityId);
+            stringBuffer.append(',');
+            stringBuffer.append(categoryId);
+            stringBuffer.append(',');
+            stringBuffer.append(sourceId);
+            stringBuffer.append(']');
+            string = stringBuffer.toString();
+        }
+
+        return string;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/CategoryDefinition.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/CategoryDefinition.java
new file mode 100644
index 0000000..3483513
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/CategoryDefinition.java
@@ -0,0 +1,181 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.activities;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.eclipse.ui.internal.util.Util;
+
+public final class CategoryDefinition implements Comparable {
+    private final static int HASH_FACTOR = 89;
+
+    private final static int HASH_INITIAL = CategoryDefinition.class.getName()
+            .hashCode();
+
+    static Map categoryDefinitionsById(Collection categoryDefinitions,
+            boolean allowNullIds) {
+        if (categoryDefinitions == null) {
+			throw new NullPointerException();
+		}
+
+        Map map = new HashMap();
+        Iterator iterator = categoryDefinitions.iterator();
+
+        while (iterator.hasNext()) {
+            Object object = iterator.next();
+            Util.assertInstance(object, CategoryDefinition.class);
+            CategoryDefinition categoryDefinition = (CategoryDefinition) object;
+            String id = categoryDefinition.getId();
+
+            if (allowNullIds || id != null) {
+				map.put(id, categoryDefinition);
+			}
+        }
+
+        return map;
+    }
+
+    static Map categoryDefinitionsByName(Collection categoryDefinitions,
+            boolean allowNullNames) {
+        if (categoryDefinitions == null) {
+			throw new NullPointerException();
+		}
+
+        Map map = new HashMap();
+        Iterator iterator = categoryDefinitions.iterator();
+
+        while (iterator.hasNext()) {
+            Object object = iterator.next();
+            Util.assertInstance(object, CategoryDefinition.class);
+            CategoryDefinition categoryDefinition = (CategoryDefinition) object;
+            String name = categoryDefinition.getName();
+
+            if (allowNullNames || name != null) {
+                Collection categoryDefinitions2 = (Collection) map.get(name);
+
+                if (categoryDefinitions2 == null) {
+                    categoryDefinitions2 = new HashSet();
+                    map.put(name, categoryDefinitions2);
+                }
+
+                categoryDefinitions2.add(categoryDefinition);
+            }
+        }
+
+        return map;
+    }
+
+    private transient int hashCode = HASH_INITIAL;
+
+    private String id;
+
+    private String name;
+
+    private String sourceId;
+
+    private transient String string;
+
+    private String description;
+
+    public CategoryDefinition(String id, String name, String sourceId,
+            String description) {
+        this.id = id;
+        this.name = name;
+        this.sourceId = sourceId;
+        this.description = description;
+    }
+
+    @Override
+	public int compareTo(Object object) {
+        CategoryDefinition castedObject = (CategoryDefinition) object;
+        int compareTo = Util.compare(id, castedObject.id);
+
+        if (compareTo == 0) {
+            compareTo = Util.compare(name, castedObject.name);
+
+            if (compareTo == 0) {
+				compareTo = Util.compare(sourceId, castedObject.sourceId);
+			}
+        }
+
+        return compareTo;
+    }
+
+    @Override
+	public boolean equals(Object object) {
+        if (!(object instanceof CategoryDefinition)) {
+			return false;
+		}
+
+        final CategoryDefinition castedObject = (CategoryDefinition) object;
+        if (!Util.equals(id, castedObject.id)) {
+            return false;
+        }
+
+        if (!Util.equals(name, castedObject.name)) {
+            return false;
+        }
+
+        return Util.equals(sourceId, castedObject.sourceId);
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getSourceId() {
+        return sourceId;
+    }
+
+    @Override
+	public int hashCode() {
+        if (hashCode == HASH_INITIAL) {
+            hashCode = hashCode * HASH_FACTOR + Util.hashCode(id);
+            hashCode = hashCode * HASH_FACTOR + Util.hashCode(name);
+            hashCode = hashCode * HASH_FACTOR + Util.hashCode(sourceId);
+            if (hashCode == HASH_INITIAL) {
+				hashCode++;
+			}
+        }
+
+        return hashCode;
+    }
+
+    @Override
+	public String toString() {
+        if (string == null) {
+            final StringBuffer stringBuffer = new StringBuffer();
+            stringBuffer.append('[');
+            stringBuffer.append(id);
+            stringBuffer.append(',');
+            stringBuffer.append(name);
+            stringBuffer.append(',');
+            stringBuffer.append(sourceId);
+            stringBuffer.append(']');
+            string = stringBuffer.toString();
+        }
+
+        return string;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ExtensionActivityRegistry.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ExtensionActivityRegistry.java
new file mode 100644
index 0000000..7b2c31e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ExtensionActivityRegistry.java
@@ -0,0 +1,388 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.activities;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.ExpressionConverter;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionDelta;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.util.ConfigurationElementMemento;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+final class ExtensionActivityRegistry extends AbstractActivityRegistry {
+
+	/**
+	 * Prefix for all activity preferences
+	 */
+	private final static String PREFIX = "UIActivities."; //$NON-NLS-1$
+
+    private List activityRequirementBindingDefinitions;
+
+    private List activityDefinitions;
+
+    private List activityPatternBindingDefinitions;
+
+    private List categoryActivityBindingDefinitions;
+
+    private List categoryDefinitions;
+
+    private List defaultEnabledActivities;
+
+    private IExtensionRegistry extensionRegistry;
+
+    ExtensionActivityRegistry(IExtensionRegistry extensionRegistry) {
+        if (extensionRegistry == null) {
+			throw new NullPointerException();
+		}
+
+        this.extensionRegistry = extensionRegistry;
+
+        this.extensionRegistry
+                .addRegistryChangeListener(registryChangeEvent -> {
+                  IExtensionDelta[] extensionDeltas = registryChangeEvent
+				    .getExtensionDeltas(Persistence.PACKAGE_PREFIX,
+				            Persistence.PACKAGE_BASE);
+
+                  if (extensionDeltas.length != 0) {
+				try {
+				    load();
+				} catch (IOException eIO) {
+				}
+}
+               });
+
+        try {
+            load();
+        } catch (IOException eIO) {
+        }
+    }
+
+    private String getNamespace(IConfigurationElement configurationElement) {
+        String namespace = null;
+
+        if (configurationElement != null) {
+            IExtension extension = configurationElement.getDeclaringExtension();
+
+            if (extension != null) {
+				namespace = extension.getNamespace();
+			}
+        }
+
+        return namespace;
+    }
+
+    /**
+     * Returns the activity definition found at this id.
+     *
+     * @param id <code>ActivityDefinition</code> id.
+     * @return <code>ActivityDefinition</code> with given id or <code>null</code> if not found.
+     */
+    private ActivityDefinition getActivityDefinitionById(String id) {
+		int size = activityDefinitions.size();
+		for (int i = 0; i < size; i++) {
+			ActivityDefinition activityDef = (ActivityDefinition) activityDefinitions
+					.get(i);
+			if (activityDef.getId().equals(id)) {
+				return activityDef;
+			}
+		}
+		return null;
+	}
+
+    private void load() throws IOException {
+        if (activityRequirementBindingDefinitions == null) {
+			activityRequirementBindingDefinitions = new ArrayList();
+		} else {
+			activityRequirementBindingDefinitions.clear();
+		}
+
+        if (activityDefinitions == null) {
+			activityDefinitions = new ArrayList();
+		} else {
+			activityDefinitions.clear();
+		}
+
+        if (activityPatternBindingDefinitions == null) {
+			activityPatternBindingDefinitions = new ArrayList();
+		} else {
+			activityPatternBindingDefinitions.clear();
+		}
+
+        if (categoryActivityBindingDefinitions == null) {
+			categoryActivityBindingDefinitions = new ArrayList();
+		} else {
+			categoryActivityBindingDefinitions.clear();
+		}
+
+        if (categoryDefinitions == null) {
+			categoryDefinitions = new ArrayList();
+		} else {
+			categoryDefinitions.clear();
+		}
+
+        if (defaultEnabledActivities == null) {
+			defaultEnabledActivities = new ArrayList();
+		} else {
+			defaultEnabledActivities.clear();
+		}
+
+        IConfigurationElement[] configurationElements = extensionRegistry
+                .getConfigurationElementsFor(Persistence.PACKAGE_FULL);
+
+        for (IConfigurationElement configurationElement : configurationElements) {
+            String name = configurationElement.getName();
+
+            if (Persistence.TAG_ACTIVITY_REQUIREMENT_BINDING.equals(name)) {
+				readActivityRequirementBindingDefinition(configurationElement);
+			} else if (Persistence.TAG_ACTIVITY.equals(name)) {
+				readActivityDefinition(configurationElement);
+			} else if (Persistence.TAG_ACTIVITY_PATTERN_BINDING.equals(name)) {
+				readActivityPatternBindingDefinition(configurationElement);
+			} else if (Persistence.TAG_CATEGORY_ACTIVITY_BINDING.equals(name)) {
+				readCategoryActivityBindingDefinition(configurationElement);
+			} else if (Persistence.TAG_CATEGORY.equals(name)) {
+				readCategoryDefinition(configurationElement);
+			} else if (Persistence.TAG_DEFAULT_ENABLEMENT.equals(name)) {
+				readDefaultEnablement(configurationElement);
+			}
+        }
+
+		// merge enablement overrides from plugin_customization.ini
+		IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore();
+		for (Iterator i = activityDefinitions.iterator(); i.hasNext();) {
+			ActivityDefinition activityDef = (ActivityDefinition) i.next();
+			String id = activityDef.getId();
+			String preferenceKey = createPreferenceKey(id);
+			if ("".equals(store.getDefaultString(preferenceKey))) //$NON-NLS-1$
+				continue;
+			if (store.getDefaultBoolean(preferenceKey)) {
+				if (!defaultEnabledActivities.contains(id) && activityDef.getEnabledWhen() == null)
+					defaultEnabledActivities.add(id);
+			} else {
+				defaultEnabledActivities.remove(id);
+			}
+		}
+
+        // Removal of all defaultEnabledActivites which target to expression
+        // controlled activities.
+		for (int i = 0; i < defaultEnabledActivities.size();) {
+			String id = (String) defaultEnabledActivities.get(i);
+			ActivityDefinition activityDef = getActivityDefinitionById(id);
+			if (activityDef != null && activityDef.getEnabledWhen() != null) {
+				defaultEnabledActivities.remove(i);
+				StatusManager
+						.getManager()
+						.handle(
+								new Status(
+										IStatus.WARNING,
+										PlatformUI.PLUGIN_ID,
+										"Default enabled activity declarations will be ignored (id: " + id + ")")); //$NON-NLS-1$ //$NON-NLS-2$
+			} else {
+				i++;
+			}
+		}
+
+		// remove all requirement bindings that reference expression-bound activities
+		for (Iterator i = activityRequirementBindingDefinitions.iterator(); i
+				.hasNext();) {
+			ActivityRequirementBindingDefinition bindingDef = (ActivityRequirementBindingDefinition) i
+					.next();
+			ActivityDefinition activityDef = getActivityDefinitionById(bindingDef
+					.getRequiredActivityId());
+			if (activityDef != null && activityDef.getEnabledWhen() != null) {
+				i.remove();
+				StatusManager
+						.getManager()
+						.handle(
+								new Status(
+										IStatus.WARNING,
+										PlatformUI.PLUGIN_ID,
+										"Expression activity cannot have requirements (id: " + activityDef.getId() + ")")); //$NON-NLS-1$ //$NON-NLS-2$
+				continue;
+			}
+
+			activityDef = getActivityDefinitionById(bindingDef.getActivityId());
+			if (activityDef != null && activityDef.getEnabledWhen() != null) {
+				i.remove();
+				StatusManager
+						.getManager()
+						.handle(
+								new Status(
+										IStatus.WARNING,
+										PlatformUI.PLUGIN_ID,
+										"Expression activity cannot be required (id: " + activityDef.getId() + ")")); //$NON-NLS-1$ //$NON-NLS-2$
+			}
+		}
+
+        boolean activityRegistryChanged = false;
+
+        if (!activityRequirementBindingDefinitions
+                .equals(super.activityRequirementBindingDefinitions)) {
+            super.activityRequirementBindingDefinitions = Collections
+                    .unmodifiableList(new ArrayList(activityRequirementBindingDefinitions));
+            activityRegistryChanged = true;
+        }
+
+        if (!activityDefinitions.equals(super.activityDefinitions)) {
+            super.activityDefinitions = Collections
+                    .unmodifiableList(new ArrayList(activityDefinitions));
+            activityRegistryChanged = true;
+        }
+
+        if (!activityPatternBindingDefinitions
+                .equals(super.activityPatternBindingDefinitions)) {
+            super.activityPatternBindingDefinitions = Collections
+                    .unmodifiableList(new ArrayList(activityPatternBindingDefinitions));
+            activityRegistryChanged = true;
+        }
+
+        if (!categoryActivityBindingDefinitions
+                .equals(super.categoryActivityBindingDefinitions)) {
+            super.categoryActivityBindingDefinitions = Collections
+                    .unmodifiableList(new ArrayList(categoryActivityBindingDefinitions));
+            activityRegistryChanged = true;
+        }
+
+        if (!categoryDefinitions.equals(super.categoryDefinitions)) {
+            super.categoryDefinitions = Collections
+                    .unmodifiableList(new ArrayList(categoryDefinitions));
+            activityRegistryChanged = true;
+        }
+
+        if (!defaultEnabledActivities.equals(super.defaultEnabledActivities)) {
+            super.defaultEnabledActivities = Collections
+                    .unmodifiableList(new ArrayList(defaultEnabledActivities));
+            activityRegistryChanged = true;
+        }
+
+        if (activityRegistryChanged) {
+			fireActivityRegistryChanged();
+		}
+    }
+
+	/**
+	 * Create the preference key for the activity.
+	 *
+	 * @param activityId
+	 *            the activity id.
+	 * @return String a preference key representing the activity.
+	 */
+	private String createPreferenceKey(String activityId) {
+		return PREFIX + activityId;
+	}
+
+    private void readDefaultEnablement(
+            IConfigurationElement configurationElement) {
+        String enabledActivity = Persistence
+                .readDefaultEnablement(new ConfigurationElementMemento(
+                        configurationElement));
+
+        if (enabledActivity != null) {
+			defaultEnabledActivities.add(enabledActivity);
+		}
+
+    }
+
+    private void readActivityRequirementBindingDefinition(
+            IConfigurationElement configurationElement) {
+        ActivityRequirementBindingDefinition activityRequirementBindingDefinition = Persistence
+                .readActivityRequirementBindingDefinition(
+                        new ConfigurationElementMemento(configurationElement),
+                        getNamespace(configurationElement));
+
+        if (activityRequirementBindingDefinition != null) {
+			activityRequirementBindingDefinitions
+                    .add(activityRequirementBindingDefinition);
+		}
+    }
+
+    private void readActivityDefinition(
+            IConfigurationElement configurationElement) {
+        ActivityDefinition activityDefinition = Persistence
+                .readActivityDefinition(new ConfigurationElementMemento(
+                        configurationElement),
+                        getNamespace(configurationElement));
+
+        if (activityDefinition != null) {
+        	// this is not ideal, but core expressions takes an
+        	// IConfigurationElement or a w3c dom Document
+			IConfigurationElement[] enabledWhen = configurationElement
+					.getChildren(IWorkbenchRegistryConstants.TAG_ENABLED_WHEN);
+			if (enabledWhen.length == 1) {
+				IConfigurationElement[] expElement = enabledWhen[0]
+						.getChildren();
+				if (expElement.length == 1) {
+					try {
+						Expression expression = ExpressionConverter
+								.getDefault().perform(expElement[0]);
+						activityDefinition.setEnabledWhen(expression);
+					} catch (CoreException e) {
+						StatusManager.getManager().handle(e, WorkbenchPlugin.PI_WORKBENCH);
+					}
+				}
+			}
+			activityDefinitions.add(activityDefinition);
+		}
+    }
+
+    private void readActivityPatternBindingDefinition(
+            IConfigurationElement configurationElement) {
+        ActivityPatternBindingDefinition activityPatternBindingDefinition = Persistence
+                .readActivityPatternBindingDefinition(
+                        new ConfigurationElementMemento(configurationElement),
+                        getNamespace(configurationElement));
+
+        if (activityPatternBindingDefinition != null) {
+			activityPatternBindingDefinitions
+                    .add(activityPatternBindingDefinition);
+		}
+    }
+
+    private void readCategoryActivityBindingDefinition(
+            IConfigurationElement configurationElement) {
+        CategoryActivityBindingDefinition categoryActivityBindingDefinition = Persistence
+                .readCategoryActivityBindingDefinition(
+                        new ConfigurationElementMemento(configurationElement),
+                        getNamespace(configurationElement));
+
+        if (categoryActivityBindingDefinition != null) {
+			categoryActivityBindingDefinitions
+                    .add(categoryActivityBindingDefinition);
+		}
+    }
+
+    private void readCategoryDefinition(
+            IConfigurationElement configurationElement) {
+        CategoryDefinition categoryDefinition = Persistence
+                .readCategoryDefinition(new ConfigurationElementMemento(
+                        configurationElement),
+                        getNamespace(configurationElement));
+
+        if (categoryDefinition != null) {
+			categoryDefinitions.add(categoryDefinition);
+		}
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/IActivityRegistry.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/IActivityRegistry.java
new file mode 100644
index 0000000..ef523ac
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/IActivityRegistry.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 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.ui.internal.activities;
+
+import java.util.List;
+
+public interface IActivityRegistry {
+
+    void addActivityRegistryListener(
+            IActivityRegistryListener activityRegistryListener);
+
+    List getActivityRequirementBindingDefinitions();
+
+    List getActivityDefinitions();
+
+    List getActivityPatternBindingDefinitions();
+
+    List getCategoryActivityBindingDefinitions();
+
+    List getCategoryDefinitions();
+
+    List getDefaultEnabledActivities();
+
+    void removeActivityRegistryListener(
+            IActivityRegistryListener activityRegistryListener);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/IActivityRegistryListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/IActivityRegistryListener.java
new file mode 100644
index 0000000..3798d28
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/IActivityRegistryListener.java
@@ -0,0 +1,17 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 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.ui.internal.activities;
+
+public interface IActivityRegistryListener {
+
+    void activityRegistryChanged(ActivityRegistryEvent activityRegistryEvent);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/Identifier.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/Identifier.java
new file mode 100644
index 0000000..dd434e9
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/Identifier.java
@@ -0,0 +1,199 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.activities;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.ui.activities.IIdentifier;
+import org.eclipse.ui.activities.IIdentifierListener;
+import org.eclipse.ui.activities.IdentifierEvent;
+import org.eclipse.ui.internal.util.Util;
+
+final class Identifier implements IIdentifier {
+    private final static int HASH_FACTOR = 89;
+
+    private final static int HASH_INITIAL = Identifier.class.getName()
+            .hashCode();
+
+	private final static Set<Identifier> strongReferences = new HashSet<>();
+
+	private Set<String> activityIds = Collections.emptySet();
+
+    private transient String[] activityIdsAsArray = {};
+
+    private boolean enabled;
+
+    private transient int hashCode = HASH_INITIAL;
+
+    private String id;
+
+	private ListenerList<IIdentifierListener> identifierListeners;
+
+    private transient String string;
+
+    Identifier(String id) {
+        if (id == null) {
+			throw new NullPointerException();
+		}
+
+        this.id = id;
+    }
+
+    @Override
+	public void addIdentifierListener(IIdentifierListener identifierListener) {
+        if (identifierListener == null) {
+			throw new NullPointerException();
+		}
+
+        if (identifierListeners == null) {
+			identifierListeners = new ListenerList<>(ListenerList.IDENTITY);
+		}
+
+		identifierListeners.add(identifierListener);
+        strongReferences.add(this);
+    }
+
+    @Override
+	public int compareTo(Object object) {
+        Identifier castedObject = (Identifier) object;
+        int compareTo = Util.compare(activityIdsAsArray,
+                castedObject.activityIdsAsArray);
+
+        if (compareTo == 0) {
+            compareTo = Util.compare(enabled, castedObject.enabled);
+
+            if (compareTo == 0) {
+				compareTo = Util.compare(id, castedObject.id);
+			}
+        }
+
+        return compareTo;
+    }
+
+    @Override
+	public boolean equals(Object object) {
+        if (!(object instanceof Identifier)) {
+			return false;
+		}
+
+        final Identifier castedObject = (Identifier) object;
+        if (!Util.equals(activityIds, castedObject.activityIds)) {
+            return false;
+        }
+
+        if (!Util.equals(enabled, castedObject.enabled)) {
+            return false;
+        }
+
+        return Util.equals(id, castedObject.id);
+    }
+
+    void fireIdentifierChanged(IdentifierEvent identifierEvent) {
+        if (identifierEvent == null) {
+			throw new NullPointerException();
+		}
+
+        if (identifierListeners != null) {
+			for (IIdentifierListener listener : identifierListeners) {
+				listener.identifierChanged(identifierEvent);
+			}
+		}
+    }
+
+	@Override
+	public Set<String> getActivityIds() {
+        return activityIds;
+    }
+
+    @Override
+	public String getId() {
+        return id;
+    }
+
+    @Override
+	public int hashCode() {
+        if (hashCode == HASH_INITIAL) {
+            hashCode = hashCode * HASH_FACTOR + Util.hashCode(activityIds);
+            hashCode = hashCode * HASH_FACTOR + Util.hashCode(enabled);
+            hashCode = hashCode * HASH_FACTOR + Util.hashCode(id);
+            if (hashCode == HASH_INITIAL) {
+				hashCode++;
+			}
+        }
+
+        return hashCode;
+    }
+
+    @Override
+	public boolean isEnabled() {
+        return enabled;
+    }
+
+    @Override
+	public void removeIdentifierListener(IIdentifierListener identifierListener) {
+        if (identifierListener == null) {
+			throw new NullPointerException();
+		}
+
+        if (identifierListeners != null) {
+			identifierListeners.remove(identifierListener);
+			if (identifierListeners.isEmpty()) {
+				strongReferences.remove(this);
+			}
+		}
+    }
+
+	boolean setActivityIds(Set<String> activityIds) {
+		activityIds = Util.safeCopy(activityIds, String.class);
+
+        if (!Util.equals(activityIds, this.activityIds)) {
+            this.activityIds = activityIds;
+			this.activityIdsAsArray = this.activityIds.toArray(new String[this.activityIds.size()]);
+            hashCode = HASH_INITIAL;
+            string = null;
+            return true;
+        }
+
+        return false;
+    }
+
+    boolean setEnabled(boolean enabled) {
+        if (enabled != this.enabled) {
+            this.enabled = enabled;
+            hashCode = HASH_INITIAL;
+            string = null;
+            return true;
+        }
+
+        return false;
+    }
+
+    @Override
+	public String toString() {
+        if (string == null) {
+            final StringBuffer stringBuffer = new StringBuffer();
+            stringBuffer.append('[');
+            stringBuffer.append(activityIds);
+            stringBuffer.append(',');
+            stringBuffer.append(enabled);
+            stringBuffer.append(',');
+            stringBuffer.append(id);
+            stringBuffer.append(']');
+            string = stringBuffer.toString();
+        }
+
+        return string;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/InternalActivityHelper.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/InternalActivityHelper.java
new file mode 100644
index 0000000..e061cae
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/InternalActivityHelper.java
@@ -0,0 +1,112 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2015 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.ui.internal.activities;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.eclipse.ui.activities.IActivityManager;
+import org.eclipse.ui.activities.ICategory;
+import org.eclipse.ui.activities.ICategoryActivityBinding;
+
+/**
+ * Internal modifications to the (regrettably) public API in
+ * WorkbenchActivityHelper. Much of the logic for what to display in the
+ * preference page is bound to the API contracts in this class and these are no
+ * longer suitable now that we have expression bound activities to consider.
+ *
+ * <p>
+ * These methods are the same as the originals except that activities with
+ * expressions are not considered in any calculations.
+ * </p>
+ *
+ * <p>
+ * See bug 229424 for details.
+ * </p>
+ *
+ * @since 3.4
+ *
+ */
+public final class InternalActivityHelper {
+
+	public static Set getActivityIdsForCategory(
+			IActivityManager activityManager, ICategory category) {
+		Set bindings = category.getCategoryActivityBindings();
+		Set activityIds = new HashSet();
+		for (Iterator i = bindings.iterator(); i.hasNext();) {
+			ICategoryActivityBinding binding = (ICategoryActivityBinding) i
+					.next();
+			String id = binding.getActivityId();
+			if (activityManager.getActivity(id).getExpression() == null)
+				activityIds.add(id);
+		}
+		return activityIds;
+	}
+
+	private static boolean isEnabled(IActivityManager activityManager,
+			String categoryId) {
+
+		ICategory category = activityManager.getCategory(categoryId);
+		if (category.isDefined()) {
+			Set activityIds = getActivityIdsForCategory(activityManager,
+					category);
+			if (activityManager.getEnabledActivityIds()
+					.containsAll(activityIds)) {
+				return true;
+			}
+		}
+
+		return false;
+	}
+
+	public static Set getEnabledCategories(IActivityManager activityManager) {
+
+		Set definedCategoryIds = activityManager.getDefinedCategoryIds();
+		Set enabledCategories = new HashSet();
+		for (Iterator i = definedCategoryIds.iterator(); i.hasNext();) {
+			String categoryId = (String) i.next();
+			if (isEnabled(activityManager, categoryId)) {
+				enabledCategories.add(categoryId);
+			}
+		}
+		return enabledCategories;
+	}
+
+	public static Set getPartiallyEnabledCategories(
+			IActivityManager activityManager) {
+		Set definedCategoryIds = activityManager.getDefinedCategoryIds();
+		Set partialCategories = new HashSet();
+		for (Iterator i = definedCategoryIds.iterator(); i.hasNext();) {
+			String categoryId = (String) i.next();
+			if (isPartiallyEnabled(activityManager, categoryId)) {
+				partialCategories.add(categoryId);
+			}
+		}
+
+		return partialCategories;
+	}
+
+	private static boolean isPartiallyEnabled(IActivityManager activityManager,
+			String categoryId) {
+		Set activityIds = getActivityIdsForCategory(activityManager,
+				activityManager.getCategory(categoryId));
+		int foundCount = 0;
+		for (Iterator i = activityIds.iterator(); i.hasNext();) {
+			String activityId = (String) i.next();
+			if (activityManager.getEnabledActivityIds().contains(activityId)) {
+				foundCount++;
+			}
+		}
+
+		return foundCount > 0 && foundCount != activityIds.size();
+	}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/MutableActivityManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/MutableActivityManager.java
new file mode 100644
index 0000000..57d6327
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/MutableActivityManager.java
@@ -0,0 +1,976 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 474273
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.activities;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.IJobFunction;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.activities.ActivityEvent;
+import org.eclipse.ui.activities.ActivityManagerEvent;
+import org.eclipse.ui.activities.CategoryEvent;
+import org.eclipse.ui.activities.IActivity;
+import org.eclipse.ui.activities.IActivityPatternBinding;
+import org.eclipse.ui.activities.IActivityRequirementBinding;
+import org.eclipse.ui.activities.ICategory;
+import org.eclipse.ui.activities.ICategoryActivityBinding;
+import org.eclipse.ui.activities.IIdentifier;
+import org.eclipse.ui.activities.IMutableActivityManager;
+import org.eclipse.ui.activities.ITriggerPointAdvisor;
+import org.eclipse.ui.activities.IdentifierEvent;
+import org.eclipse.ui.progress.UIJob;
+import org.eclipse.ui.services.IEvaluationReference;
+import org.eclipse.ui.services.IEvaluationService;
+
+/**
+ * An activity registry that may be altered.
+ *
+ * @since 3.0
+ */
+public final class MutableActivityManager extends AbstractActivityManager
+        implements IMutableActivityManager, Cloneable {
+
+    private Map activitiesById = new HashMap();
+
+    private Map activityRequirementBindingsByActivityId = new HashMap();
+
+    private Map activityDefinitionsById = new HashMap();
+
+    private Map activityPatternBindingsByActivityId = new HashMap();
+
+    private IActivityRegistry activityRegistry;
+
+    private Map categoriesById = new HashMap();
+
+    private Map categoryActivityBindingsByCategoryId = new HashMap();
+
+    private Map categoryDefinitionsById = new HashMap();
+
+    private Set definedActivityIds = new HashSet();
+
+    private Set definedCategoryIds = new HashSet();
+
+    private Set enabledActivityIds = new HashSet();
+
+    private Map identifiersById = new HashMap();
+
+    /**
+     * Avoid endless circular referencing of re-adding activity to evaluation
+     * listener, because of adding it the first time to evaluation listener.
+     */
+    private boolean addingEvaluationListener = false;
+
+    /**
+     * A list of identifiers that need to have their activity sets reconciled in the background job.
+     */
+    private List deferredIdentifiers = Collections.synchronizedList(new LinkedList());
+
+    /**
+     * The identifier update job.  Lazily initialized.
+     */
+    private Job deferredIdentifierJob = null;
+
+    private final IActivityRegistryListener activityRegistryListener = new IActivityRegistryListener() {
+                @Override
+				public void activityRegistryChanged(
+                        ActivityRegistryEvent activityRegistryEvent) {
+                    readRegistry(false);
+                }
+            };
+
+	private Map refsByActivityDefinition = new HashMap();
+
+    /**
+     * Create a new instance of this class using the platform extension registry.
+     * @param triggerPointAdvisor
+     */
+    public MutableActivityManager(ITriggerPointAdvisor triggerPointAdvisor) {
+        this(triggerPointAdvisor, new ExtensionActivityRegistry(Platform.getExtensionRegistry()));
+    }
+
+    /**
+     * Create a new instance of this class using the provided registry.
+     * @param triggerPointAdvisor
+     *
+     * @param activityRegistry the activity registry
+     */
+    public MutableActivityManager(ITriggerPointAdvisor triggerPointAdvisor, IActivityRegistry activityRegistry) {
+        Assert.isNotNull(activityRegistry);
+        Assert.isNotNull(triggerPointAdvisor);
+
+        this.advisor = triggerPointAdvisor;
+        this.activityRegistry = activityRegistry;
+
+        this.activityRegistry
+                .addActivityRegistryListener(activityRegistryListener);
+
+        readRegistry(true);
+    }
+
+	@Override
+	synchronized public IActivity getActivity(String activityId) {
+        if (activityId == null) {
+			throw new NullPointerException();
+		}
+
+        Activity activity = (Activity) activitiesById.get(activityId);
+
+        if (activity == null) {
+            activity = new Activity(activityId);
+            updateActivity(activity);
+            activitiesById.put(activityId, activity);
+        }
+
+        return activity;
+    }
+
+	@Override
+	synchronized public ICategory getCategory(String categoryId) {
+        if (categoryId == null) {
+			throw new NullPointerException();
+		}
+
+        Category category = (Category) categoriesById.get(categoryId);
+
+        if (category == null) {
+            category = new Category(categoryId);
+            updateCategory(category);
+            categoriesById.put(categoryId, category);
+        }
+
+        return category;
+    }
+
+	@Override
+	synchronized public Set getDefinedActivityIds() {
+        return Collections.unmodifiableSet(definedActivityIds);
+    }
+
+	@Override
+	synchronized public Set getDefinedCategoryIds() {
+        return Collections.unmodifiableSet(definedCategoryIds);
+    }
+
+	@Override
+	synchronized public Set getEnabledActivityIds() {
+        return Collections.unmodifiableSet(enabledActivityIds);
+    }
+
+	@Override
+	synchronized public IIdentifier getIdentifier(String identifierId) {
+        if (identifierId == null) {
+			throw new NullPointerException();
+		}
+
+        Identifier identifier = (Identifier) identifiersById.get(identifierId);
+
+        if (identifier == null) {
+            identifier = new Identifier(identifierId);
+            updateIdentifier(identifier);
+            identifiersById.put(identifierId, identifier);
+        }
+
+        return identifier;
+    }
+
+    private void getRequiredActivityIds(Set activityIds, Set requiredActivityIds) {
+        for (Iterator iterator = activityIds.iterator(); iterator.hasNext();) {
+            String activityId = (String) iterator.next();
+            IActivity activity = getActivity(activityId);
+            Set childActivityIds = new HashSet();
+            Set activityRequirementBindings = activity
+                    .getActivityRequirementBindings();
+
+            for (Iterator iterator2 = activityRequirementBindings.iterator(); iterator2
+                    .hasNext();) {
+                IActivityRequirementBinding activityRequirementBinding = (IActivityRequirementBinding) iterator2
+                        .next();
+                childActivityIds.add(activityRequirementBinding
+                        .getRequiredActivityId());
+            }
+
+            childActivityIds.removeAll(requiredActivityIds);
+            requiredActivityIds.addAll(childActivityIds);
+            getRequiredActivityIds(childActivityIds, requiredActivityIds);
+        }
+    }
+
+    private void notifyActivities(Map activityEventsByActivityId) {
+        for (Iterator iterator = activityEventsByActivityId.entrySet()
+                .iterator(); iterator.hasNext();) {
+            Map.Entry entry = (Map.Entry) iterator.next();
+            String activityId = (String) entry.getKey();
+            ActivityEvent activityEvent = (ActivityEvent) entry.getValue();
+            Activity activity = (Activity) activitiesById.get(activityId);
+
+            if (activity != null) {
+				activity.fireActivityChanged(activityEvent);
+			}
+        }
+    }
+
+    private void notifyCategories(Map categoryEventsByCategoryId) {
+        for (Iterator iterator = categoryEventsByCategoryId.entrySet()
+                .iterator(); iterator.hasNext();) {
+            Map.Entry entry = (Map.Entry) iterator.next();
+            String categoryId = (String) entry.getKey();
+            CategoryEvent categoryEvent = (CategoryEvent) entry.getValue();
+            Category category = (Category) categoriesById.get(categoryId);
+
+            if (category != null) {
+				category.fireCategoryChanged(categoryEvent);
+			}
+        }
+    }
+
+    private void notifyIdentifiers(Map identifierEventsByIdentifierId) {
+        for (Iterator iterator = identifierEventsByIdentifierId.entrySet()
+                .iterator(); iterator.hasNext();) {
+            Map.Entry entry = (Map.Entry) iterator.next();
+            String identifierId = (String) entry.getKey();
+            IdentifierEvent identifierEvent = (IdentifierEvent) entry
+                    .getValue();
+            Identifier identifier = (Identifier) identifiersById
+                    .get(identifierId);
+
+            if (identifier != null) {
+				identifier.fireIdentifierChanged(identifierEvent);
+			}
+        }
+    }
+
+    private void readRegistry(boolean setDefaults) {
+    	if (!isRegexpSupported()) {
+    		return;
+    	}
+    	clearExpressions();
+        Collection activityDefinitions = new ArrayList();
+        activityDefinitions.addAll(activityRegistry.getActivityDefinitions());
+        Map activityDefinitionsById = new HashMap(ActivityDefinition
+                .activityDefinitionsById(activityDefinitions, false));
+
+        for (Iterator iterator = activityDefinitionsById.values().iterator(); iterator
+                .hasNext();) {
+            ActivityDefinition activityDefinition = (ActivityDefinition) iterator
+                    .next();
+            String name = activityDefinition.getName();
+
+            if (name == null || name.length() == 0) {
+				iterator.remove();
+			}
+        }
+
+        Collection categoryDefinitions = new ArrayList();
+        categoryDefinitions.addAll(activityRegistry.getCategoryDefinitions());
+        Map categoryDefinitionsById = new HashMap(CategoryDefinition
+                .categoryDefinitionsById(categoryDefinitions, false));
+
+        for (Iterator iterator = categoryDefinitionsById.values().iterator(); iterator
+                .hasNext();) {
+            CategoryDefinition categoryDefinition = (CategoryDefinition) iterator
+                    .next();
+            String name = categoryDefinition.getName();
+
+            if (name == null || name.length() == 0) {
+				iterator.remove();
+			}
+        }
+
+        Map activityRequirementBindingDefinitionsByActivityId = ActivityRequirementBindingDefinition
+                .activityRequirementBindingDefinitionsByActivityId(activityRegistry
+                        .getActivityRequirementBindingDefinitions());
+        Map activityRequirementBindingsByActivityId = new HashMap();
+
+        for (Iterator iterator = activityRequirementBindingDefinitionsByActivityId
+                .entrySet().iterator(); iterator.hasNext();) {
+            Map.Entry entry = (Map.Entry) iterator.next();
+            String parentActivityId = (String) entry.getKey();
+
+            if (activityDefinitionsById.containsKey(parentActivityId)) {
+                Collection activityRequirementBindingDefinitions = (Collection) entry
+                        .getValue();
+
+                if (activityRequirementBindingDefinitions != null) {
+					for (Iterator iterator2 = activityRequirementBindingDefinitions
+                            .iterator(); iterator2.hasNext();) {
+                        ActivityRequirementBindingDefinition activityRequirementBindingDefinition = (ActivityRequirementBindingDefinition) iterator2
+                                .next();
+                        String childActivityId = activityRequirementBindingDefinition
+                                .getRequiredActivityId();
+
+                        if (activityDefinitionsById
+                                .containsKey(childActivityId)) {
+                            IActivityRequirementBinding activityRequirementBinding = new ActivityRequirementBinding(
+                                    childActivityId, parentActivityId);
+                            Set activityRequirementBindings = (Set) activityRequirementBindingsByActivityId
+                                    .get(parentActivityId);
+
+                            if (activityRequirementBindings == null) {
+                                activityRequirementBindings = new HashSet();
+                                activityRequirementBindingsByActivityId.put(
+                                        parentActivityId,
+                                        activityRequirementBindings);
+                            }
+
+                            activityRequirementBindings
+                                    .add(activityRequirementBinding);
+                        }
+                    }
+				}
+            }
+        }
+
+        Map activityPatternBindingDefinitionsByActivityId = ActivityPatternBindingDefinition
+                .activityPatternBindingDefinitionsByActivityId(activityRegistry
+                        .getActivityPatternBindingDefinitions());
+        Map activityPatternBindingsByActivityId = new HashMap();
+
+        for (Iterator iterator = activityPatternBindingDefinitionsByActivityId
+                .entrySet().iterator(); iterator.hasNext();) {
+            Map.Entry entry = (Map.Entry) iterator.next();
+            String activityId = (String) entry.getKey();
+
+            if (activityDefinitionsById.containsKey(activityId)) {
+                Collection activityPatternBindingDefinitions = (Collection) entry
+                        .getValue();
+
+                if (activityPatternBindingDefinitions != null) {
+					for (Iterator iterator2 = activityPatternBindingDefinitions
+                            .iterator(); iterator2.hasNext();) {
+                        ActivityPatternBindingDefinition activityPatternBindingDefinition = (ActivityPatternBindingDefinition) iterator2
+                                .next();
+                        String pattern = activityPatternBindingDefinition
+                                .getPattern();
+
+                        if (pattern != null && pattern.length() != 0) {
+                            IActivityPatternBinding activityPatternBinding = new ActivityPatternBinding(
+                                    activityId, pattern, activityPatternBindingDefinition.isEqualityPattern());
+                            Set activityPatternBindings = (Set) activityPatternBindingsByActivityId
+                                    .get(activityId);
+
+                            if (activityPatternBindings == null) {
+                                activityPatternBindings = new HashSet();
+                                activityPatternBindingsByActivityId.put(
+                                        activityId, activityPatternBindings);
+                            }
+
+                            activityPatternBindings.add(activityPatternBinding);
+                        }
+                    }
+				}
+            }
+        }
+
+        Map categoryActivityBindingDefinitionsByCategoryId = CategoryActivityBindingDefinition
+                .categoryActivityBindingDefinitionsByCategoryId(activityRegistry
+                        .getCategoryActivityBindingDefinitions());
+        Map categoryActivityBindingsByCategoryId = new HashMap();
+
+        for (Iterator iterator = categoryActivityBindingDefinitionsByCategoryId
+                .entrySet().iterator(); iterator.hasNext();) {
+            Map.Entry entry = (Map.Entry) iterator.next();
+            String categoryId = (String) entry.getKey();
+
+            if (categoryDefinitionsById.containsKey(categoryId)) {
+                Collection categoryActivityBindingDefinitions = (Collection) entry
+                        .getValue();
+
+                if (categoryActivityBindingDefinitions != null) {
+					for (Iterator iterator2 = categoryActivityBindingDefinitions
+                            .iterator(); iterator2.hasNext();) {
+                        CategoryActivityBindingDefinition categoryActivityBindingDefinition = (CategoryActivityBindingDefinition) iterator2
+                                .next();
+                        String activityId = categoryActivityBindingDefinition
+                                .getActivityId();
+
+                        if (activityDefinitionsById.containsKey(activityId)) {
+                            ICategoryActivityBinding categoryActivityBinding = new CategoryActivityBinding(
+                                    activityId, categoryId);
+                            Set categoryActivityBindings = (Set) categoryActivityBindingsByCategoryId
+                                    .get(categoryId);
+
+                            if (categoryActivityBindings == null) {
+                                categoryActivityBindings = new HashSet();
+                                categoryActivityBindingsByCategoryId.put(
+                                        categoryId, categoryActivityBindings);
+                            }
+
+                            categoryActivityBindings
+                                    .add(categoryActivityBinding);
+                        }
+                    }
+				}
+            }
+        }
+
+        this.activityRequirementBindingsByActivityId = activityRequirementBindingsByActivityId;
+        this.activityDefinitionsById = activityDefinitionsById;
+        this.activityPatternBindingsByActivityId = activityPatternBindingsByActivityId;
+        this.categoryActivityBindingsByCategoryId = categoryActivityBindingsByCategoryId;
+        this.categoryDefinitionsById = categoryDefinitionsById;
+        boolean definedActivityIdsChanged = false;
+        Set definedActivityIds = new HashSet(activityDefinitionsById.keySet());
+
+        Set previouslyDefinedActivityIds = null;
+        if (!definedActivityIds.equals(this.definedActivityIds)) {
+            previouslyDefinedActivityIds = this.definedActivityIds;
+            this.definedActivityIds = definedActivityIds;
+            definedActivityIdsChanged = true;
+        }
+
+        boolean definedCategoryIdsChanged = false;
+        Set definedCategoryIds = new HashSet(categoryDefinitionsById.keySet());
+
+        Set previouslyDefinedCategoryIds = null;
+        if (!definedCategoryIds.equals(this.definedCategoryIds)) {
+            previouslyDefinedCategoryIds = this.definedCategoryIds;
+            this.definedCategoryIds = definedCategoryIds;
+            definedCategoryIdsChanged = true;
+        }
+
+        Set enabledActivityIds = new HashSet(this.enabledActivityIds);
+        getRequiredActivityIds(this.enabledActivityIds, enabledActivityIds);
+        boolean enabledActivityIdsChanged = false;
+
+        Set previouslyEnabledActivityIds = null;
+        if (!this.enabledActivityIds.equals(enabledActivityIds)) {
+            previouslyEnabledActivityIds = this.enabledActivityIds;
+            this.enabledActivityIds = enabledActivityIds;
+            enabledActivityIdsChanged = true;
+        }
+
+        Map activityEventsByActivityId = updateActivities(activitiesById
+                .keySet());
+
+        Map categoryEventsByCategoryId = updateCategories(categoriesById
+                .keySet());
+
+        Map identifierEventsByIdentifierId = updateIdentifiers(identifiersById
+                .keySet());
+
+        if (definedActivityIdsChanged || definedCategoryIdsChanged
+                || enabledActivityIdsChanged) {
+			fireActivityManagerChanged(new ActivityManagerEvent(this,
+                    definedActivityIdsChanged, definedCategoryIdsChanged,
+                    enabledActivityIdsChanged, previouslyDefinedActivityIds,
+                    previouslyDefinedCategoryIds, previouslyEnabledActivityIds));
+		}
+
+        if (activityEventsByActivityId != null) {
+			notifyActivities(activityEventsByActivityId);
+		}
+
+        if (categoryEventsByCategoryId != null) {
+			notifyCategories(categoryEventsByCategoryId);
+		}
+
+        if (identifierEventsByIdentifierId != null) {
+			notifyIdentifiers(identifierEventsByIdentifierId);
+		}
+
+        if (setDefaults) {
+            setEnabledActivityIds(new HashSet(activityRegistry
+                    .getDefaultEnabledActivities()));
+        }
+    }
+
+	private void clearExpressions() {
+		IEvaluationService evaluationService = PlatformUI
+				.getWorkbench().getService(IEvaluationService.class);
+		Iterator i = refsByActivityDefinition.values().iterator();
+		while (i.hasNext()) {
+			IEvaluationReference ref = (IEvaluationReference) i.next();
+			evaluationService.removeEvaluationListener(ref);
+		}
+		refsByActivityDefinition.clear();
+	}
+
+	/**
+     * Returns whether the Java 1.4 regular expression support is available.
+     * Regexp support will not be available when running against JCL Foundation (see bug 80053).
+     *
+	 * @return <code>true</code> if regexps are supported, <code>false</code> otherwise.
+	 *
+	 * @since 3.1
+	 */
+	private boolean isRegexpSupported() {
+		try {
+			Class.forName("java.util.regex.Pattern"); //$NON-NLS-1$
+			return true;
+		}
+		catch (Exception e) {
+			return false;
+		}
+	}
+
+	@Override
+	synchronized public void setEnabledActivityIds(Set enabledActivityIds) {
+        enabledActivityIds = new HashSet(enabledActivityIds);
+        Set requiredActivityIds = new HashSet(enabledActivityIds);
+        getRequiredActivityIds(enabledActivityIds, requiredActivityIds);
+        enabledActivityIds = requiredActivityIds;
+        Set deltaActivityIds = null;
+        boolean activityManagerChanged = false;
+        Map activityEventsByActivityId = null;
+
+        Set previouslyEnabledActivityIds = null;
+        // the sets are different so there may be work to do.
+        if (!this.enabledActivityIds.equals(enabledActivityIds)) {
+            previouslyEnabledActivityIds = this.enabledActivityIds;
+            activityManagerChanged = true;
+
+            // break out the additions to the current set
+            Set additions = new HashSet(enabledActivityIds);
+            additions.removeAll(previouslyEnabledActivityIds);
+
+            // and the removals
+            Set removals = new HashSet(previouslyEnabledActivityIds);
+            removals.removeAll(enabledActivityIds);
+
+            // remove from each set the expression-activities
+            removeExpressionControlledActivities(additions);
+            removeExpressionControlledActivities(removals);
+
+            // merge the two sets into one delta - these are the changes that
+			// need to be made after taking expressions into account
+            deltaActivityIds = new HashSet(additions);
+            deltaActivityIds.addAll(removals);
+
+            if (deltaActivityIds.size() > 0) {
+            	// instead of blowing away the old set with the new we will
+				// instead modify it based on the deltas
+            	// add in all the new activities to the current set
+            	enabledActivityIds.addAll(additions);
+            	// and remove the stale ones
+            	enabledActivityIds.removeAll(removals);
+            	// finally set the internal set of activities
+            	this.enabledActivityIds = enabledActivityIds;
+				activityEventsByActivityId = updateActivities(deltaActivityIds);
+			} else {
+				return;
+			}
+        }
+
+        updateListeners(activityManagerChanged, activityEventsByActivityId,
+				deltaActivityIds, previouslyEnabledActivityIds);
+    }
+
+	/**
+	 * Updates all the listeners to changes in the state.
+	 *
+	 * @param activityManagerChanged
+	 * @param activityEventsByActivityId
+	 * @param deltaActivityIds
+	 * @param previouslyEnabledActivityIds
+	 */
+	private void updateListeners(boolean activityManagerChanged,
+			Map activityEventsByActivityId, Set deltaActivityIds,
+			Set previouslyEnabledActivityIds) {
+		// don't update identifiers if the enabled activity set has not changed
+        if (activityManagerChanged) {
+            Map identifierEventsByIdentifierId = updateIdentifiers(identifiersById
+                    .keySet(), deltaActivityIds);
+            if (identifierEventsByIdentifierId != null) {
+				notifyIdentifiers(identifierEventsByIdentifierId);
+			}
+        }
+        if (activityEventsByActivityId != null) {
+			notifyActivities(activityEventsByActivityId);
+		}
+
+        if (activityManagerChanged) {
+			fireActivityManagerChanged(new ActivityManagerEvent(this, false,
+                    false, true, null, null, previouslyEnabledActivityIds));
+		}
+	}
+
+	private void addExpressionEnabledActivity(String id) {
+		Set previouslyEnabledActivityIds = new HashSet(this.enabledActivityIds);
+		this.enabledActivityIds.add(id);
+
+		updateExpressionEnabledActivities(id, previouslyEnabledActivityIds);
+	}
+
+	private void removeExpressionEnabledActivity(String id) {
+		Set previouslyEnabledActivityIds = new HashSet(this.enabledActivityIds);
+		this.enabledActivityIds.remove(id);
+
+		updateExpressionEnabledActivities(id, previouslyEnabledActivityIds);
+	}
+
+	/**
+	 * @param id
+	 * @param previouslyEnabledActivityIds
+	 */
+	private void updateExpressionEnabledActivities(String id,
+			Set previouslyEnabledActivityIds) {
+		Set deltaActivityIds = new HashSet();
+		deltaActivityIds.add(id);
+		Map activityEventsByActivityId = updateActivities(deltaActivityIds);
+
+		updateListeners(true, activityEventsByActivityId, deltaActivityIds,
+				previouslyEnabledActivityIds);
+	}
+
+
+	/**
+	 * Removes from a list of activity changes all those that are based on expressions
+	 *
+	 * @param delta the set to modify
+	 */
+	private void removeExpressionControlledActivities(Set delta) {
+
+		for (Iterator i = delta.iterator(); i.hasNext();) {
+			String id = (String) i.next();
+			IActivity activity = (IActivity) activitiesById.get(id);
+			Expression expression = activity.getExpression();
+
+			if (expression != null) {
+				i.remove();
+			}
+		}
+	}
+
+    private Map updateActivities(Collection activityIds) {
+        Map activityEventsByActivityId = new TreeMap();
+
+        for (Iterator iterator = activityIds.iterator(); iterator.hasNext();) {
+            String activityId = (String) iterator.next();
+            Activity activity = (Activity) activitiesById.get(activityId);
+
+            if (activity != null) {
+                ActivityEvent activityEvent = updateActivity(activity);
+
+                if (activityEvent != null) {
+					activityEventsByActivityId.put(activityId, activityEvent);
+				}
+            }
+        }
+
+        return activityEventsByActivityId;
+    }
+
+    private IPropertyChangeListener enabledWhenListener = new IPropertyChangeListener() {
+		@Override
+		public void propertyChange(PropertyChangeEvent event) {
+			if (addingEvaluationListener) {
+				return;
+			}
+
+			Object nv = event.getNewValue();
+			boolean enabledWhen = nv == null ? false : ((Boolean) nv)
+					.booleanValue();
+			String id = event.getProperty();
+			IActivity activity = (IActivity)activitiesById.get(id);
+			if (activity.isEnabled() != enabledWhen) {
+				if (enabledWhen) {
+					addExpressionEnabledActivity(id);
+				} else {
+					removeExpressionEnabledActivity(id);
+				}
+			}
+		}
+	};
+
+	private ITriggerPointAdvisor advisor;
+
+    private ActivityEvent updateActivity(Activity activity) {
+        Set activityRequirementBindings = (Set) activityRequirementBindingsByActivityId
+                .get(activity.getId());
+        boolean activityRequirementBindingsChanged = activity
+                .setActivityRequirementBindings(activityRequirementBindings != null ? activityRequirementBindings
+                        : Collections.EMPTY_SET);
+        Set activityPatternBindings = (Set) activityPatternBindingsByActivityId
+                .get(activity.getId());
+        boolean activityPatternBindingsChanged = activity
+                .setActivityPatternBindings(activityPatternBindings != null ? activityPatternBindings
+                        : Collections.EMPTY_SET);
+        ActivityDefinition activityDefinition = (ActivityDefinition) activityDefinitionsById
+                .get(activity.getId());
+        boolean definedChanged = activity
+                .setDefined(activityDefinition != null);
+
+        // enabledWhen comes into play
+        IEvaluationReference ref = (IEvaluationReference) refsByActivityDefinition
+				.get(activityDefinition);
+		IEvaluationService evaluationService = PlatformUI
+				.getWorkbench().getService(IEvaluationService.class);
+		boolean newRef = false;
+		if (activityDefinition != null && evaluationService!=null) {
+			activity.setExpression(activityDefinition.getEnabledWhen());
+			if (ref == null && activityDefinition.getEnabledWhen()!=null) {
+				addingEvaluationListener = true;
+				try {
+					ref = evaluationService.addEvaluationListener(
+						activityDefinition.getEnabledWhen(),
+						enabledWhenListener, activityDefinition.getId());
+					newRef = true;
+				} finally {
+					addingEvaluationListener = false;
+				}
+				if (ref != null) {
+					refsByActivityDefinition.put(activityDefinition, ref);
+				}
+			}
+		}
+		final boolean enabledChanged;
+		if (ref != null && evaluationService!=null) {
+			enabledChanged = activity.setEnabled(ref.evaluate(evaluationService
+					.getCurrentState()));
+			if (newRef && activity.isEnabled()) {
+				// make sure this activity is in the enabled set for this
+				// manager - event firing will be handled by the caller to this
+				// method.
+				this.enabledActivityIds.add(activity.getId());
+			}
+		} else {
+			enabledChanged = activity.setEnabled(enabledActivityIds
+					.contains(activity.getId()));
+		}
+
+        boolean nameChanged = activity
+                .setName(activityDefinition != null ? activityDefinition
+                        .getName() : null);
+        boolean descriptionChanged = activity
+                .setDescription(activityDefinition != null ? activityDefinition
+                        .getDescription() : null);
+        boolean defaultEnabledChanged = activity.setDefaultEnabled(activityRegistry
+                .getDefaultEnabledActivities().contains(activity.getId()));
+        if (activityRequirementBindingsChanged
+                || activityPatternBindingsChanged || definedChanged
+                || enabledChanged || nameChanged || descriptionChanged
+                || defaultEnabledChanged) {
+			return new ActivityEvent(activity,
+                    activityRequirementBindingsChanged,
+                    activityPatternBindingsChanged, definedChanged,
+                    descriptionChanged, enabledChanged, nameChanged, defaultEnabledChanged);
+		}
+
+        return null;
+    }
+
+    private Map updateCategories(Collection categoryIds) {
+        Map categoryEventsByCategoryId = new TreeMap();
+
+        for (Iterator iterator = categoryIds.iterator(); iterator.hasNext();) {
+            String categoryId = (String) iterator.next();
+            Category category = (Category) categoriesById.get(categoryId);
+
+            if (category != null) {
+                CategoryEvent categoryEvent = updateCategory(category);
+
+                if (categoryEvent != null) {
+					categoryEventsByCategoryId.put(categoryId, categoryEvent);
+				}
+            }
+        }
+
+        return categoryEventsByCategoryId;
+    }
+
+    private CategoryEvent updateCategory(Category category) {
+        Set categoryActivityBindings = (Set) categoryActivityBindingsByCategoryId
+                .get(category.getId());
+        boolean categoryActivityBindingsChanged = category
+                .setCategoryActivityBindings(categoryActivityBindings != null ? categoryActivityBindings
+                        : Collections.EMPTY_SET);
+        CategoryDefinition categoryDefinition = (CategoryDefinition) categoryDefinitionsById
+                .get(category.getId());
+        boolean definedChanged = category
+                .setDefined(categoryDefinition != null);
+        boolean nameChanged = category
+                .setName(categoryDefinition != null ? categoryDefinition
+                        .getName() : null);
+        boolean descriptionChanged = category
+                .setDescription(categoryDefinition != null ? categoryDefinition
+                        .getDescription() : null);
+
+        if (categoryActivityBindingsChanged || definedChanged || nameChanged
+                || descriptionChanged) {
+			return new CategoryEvent(category, categoryActivityBindingsChanged,
+                    definedChanged, descriptionChanged, nameChanged);
+		}
+
+        return null;
+    }
+
+    private IdentifierEvent updateIdentifier(Identifier identifier) {
+        return updateIdentifier(identifier, definedActivityIds);
+    }
+
+    private IdentifierEvent updateIdentifier(Identifier identifier, Set changedActivityIds) {
+        String id = identifier.getId();
+        Set activityIds = new HashSet();
+
+        boolean enabled = false;
+
+        boolean activityIdsChanged = false;
+
+        boolean enabledChanged = false;
+
+        // short-circut logic. If all activities are enabled, then the
+        // identifier must be as well. Return true and schedule the remainder of
+        // the work to run in a background job.
+        if (enabledActivityIds.size() == definedActivityIds.size()) {
+            enabled = true;
+            enabledChanged = identifier.setEnabled(enabled);
+            identifier.setActivityIds(Collections.EMPTY_SET);
+            deferredIdentifiers.add(identifier);
+            getUpdateJob().schedule();
+            if (enabledChanged) {
+				return new IdentifierEvent(identifier, activityIdsChanged,
+                        enabledChanged);
+			}
+        } else {
+            Set activityIdsToUpdate = new HashSet(changedActivityIds);
+            if (identifier.getActivityIds() != null) {
+                activityIdsToUpdate.addAll(identifier.getActivityIds());
+            }
+            for (Iterator iterator = activityIdsToUpdate.iterator(); iterator
+                    .hasNext();) {
+                String activityId = (String) iterator.next();
+                Activity activity = (Activity) getActivity(activityId);
+
+                if (activity.isMatch(id)) {
+                    activityIds.add(activityId);
+               }
+            }
+
+            activityIdsChanged = identifier.setActivityIds(activityIds);
+
+            if (advisor != null) {
+            	enabled = advisor.computeEnablement(this, identifier);
+            }
+            enabledChanged = identifier.setEnabled(enabled);
+
+            if (activityIdsChanged || enabledChanged) {
+				return new IdentifierEvent(identifier, activityIdsChanged,
+                        enabledChanged);
+			}
+        }
+        return null;
+    }
+
+    private Map updateIdentifiers(Collection identifierIds) {
+        return updateIdentifiers(identifierIds, definedActivityIds);
+    }
+
+    private Map updateIdentifiers(Collection identifierIds, Set changedActivityIds) {
+        Map identifierEventsByIdentifierId = new TreeMap();
+
+        for (Iterator iterator = identifierIds.iterator(); iterator.hasNext();) {
+            String identifierId = (String) iterator.next();
+            Identifier identifier = (Identifier) identifiersById
+                    .get(identifierId);
+
+            if (identifier != null) {
+                IdentifierEvent identifierEvent = updateIdentifier(identifier, changedActivityIds);
+
+                if (identifierEvent != null) {
+					identifierEventsByIdentifierId.put(identifierId,
+                            identifierEvent);
+				}
+            }
+        }
+
+        return identifierEventsByIdentifierId;
+    }
+
+    /**
+     * Unhook this manager from its registry.
+     *
+     * @since 3.1
+     */
+    public void unhookRegistryListeners() {
+        activityRegistry.removeActivityRegistryListener(activityRegistryListener);
+    }
+
+	@Override
+	synchronized public Object clone() {
+        MutableActivityManager clone = new MutableActivityManager(advisor, activityRegistry);
+        clone.setEnabledActivityIds(getEnabledActivityIds());
+        return clone;
+    }
+
+    /**
+     * Return the identifier update job.
+     *
+     * @return the job
+     * @since 3.1
+     */
+    private Job getUpdateJob() {
+        if (deferredIdentifierJob == null) {
+			deferredIdentifierJob = Job.create("Activity Identifier Update", new IJobFunction() { //$NON-NLS-1$
+                @Override
+				public IStatus run(IProgressMonitor monitor) {
+					final Map identifierEventsByIdentifierId = new HashMap();
+
+                    while (!deferredIdentifiers.isEmpty()) {
+                        Identifier identifier = (Identifier) deferredIdentifiers.remove(0);
+                        Set activityIds = new HashSet();
+                        for (Iterator iterator = definedActivityIds.iterator(); iterator
+                                .hasNext();) {
+                            String activityId = (String) iterator.next();
+                            Activity activity = (Activity) getActivity(activityId);
+
+                            if (activity.isMatch(identifier.getId())) {
+                                activityIds.add(activityId);
+                            }
+                        }
+
+                        boolean activityIdsChanged = identifier.setActivityIds(activityIds);
+                        if (activityIdsChanged) {
+                            IdentifierEvent identifierEvent = new IdentifierEvent(identifier, activityIdsChanged,
+                                    false);
+                            identifierEventsByIdentifierId.put(identifier.getId(),
+                                    identifierEvent);
+						}
+					}
+					if (!identifierEventsByIdentifierId.isEmpty()) {
+						UIJob notifyJob = new UIJob("Activity Identifier Update UI") { //$NON-NLS-1$
+							@Override
+							public IStatus runInUIThread(IProgressMonitor monitor) {
+								notifyIdentifiers(identifierEventsByIdentifierId);
+								return Status.OK_STATUS;
+							}
+						};
+						notifyJob.setSystem(true);
+						notifyJob.schedule();
+                    }
+                    return Status.OK_STATUS;
+                }
+			});
+            deferredIdentifierJob.setSystem(true);
+        }
+        return deferredIdentifierJob;
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/PatternUtil.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/PatternUtil.java
new file mode 100644
index 0000000..08ef38d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/PatternUtil.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2015 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
+ *     Bredex GmbH - Creator of this class.
+ ******************************************************************************/
+
+package org.eclipse.ui.internal.activities;
+
+/**
+ * Utility helper class for regular expression string patterns.
+ *
+ * @since 3.4
+ * @author Jan Diederich
+ */
+public class PatternUtil {
+
+	/**
+	 * Quotes a string pattern as non-regular expression string.
+	 * That means: no regular expresion instructions in the given string
+	 * won't be taken into account.<br/>
+	 * Example:
+	 * <code>String searchString = "xy[^a]";<br/>
+	 * Pattern.compile(quotePattern(searchString)).matcher(searchString)
+	 * 		.matches();
+	 * <br/> </code> will return true.
+	 * @param pattern pattern to quote
+	 * @return the quoted pattern
+	 */
+	public static String quotePattern(String pattern) {
+		final String START = "\\Q";  //$NON-NLS-1$
+		final String STOP = "\\E"; //$NON-NLS-1$
+		final int STOP_LENGTH = 2;  // STOP.length()
+
+		int stopIndex = pattern.indexOf(STOP);
+		if (stopIndex < 0) {
+			return START + pattern + STOP;
+		}
+
+		String result = START;
+		for (int position=0; ;) {
+			stopIndex = pattern.indexOf(STOP, position);
+			if (stopIndex >= 0) {
+				result += pattern.substring(position, stopIndex + 2)
+						+ "\\" + STOP + START; //$NON-NLS-1$
+				position = stopIndex + STOP_LENGTH;
+			} else {
+				result += pattern.substring(position) + STOP;
+				break;
+			}
+		}
+
+		return result;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/Persistence.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/Persistence.java
new file mode 100644
index 0000000..dd4a8cd
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/Persistence.java
@@ -0,0 +1,206 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.activities;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.util.ConfigurationElementMemento;
+
+public final class Persistence {
+    final static String PACKAGE_BASE = "activities"; //$NON-NLS-1$
+
+    final static String PACKAGE_FULL = "org.eclipse.ui.activities"; //$NON-NLS-1$
+
+    final static String PACKAGE_PREFIX = "org.eclipse.ui"; //$NON-NLS-1$
+
+    final static String TAG_ACTIVITY = "activity"; //$NON-NLS-1$
+
+    final static String TAG_ACTIVITY_REQUIREMENT_BINDING = "activityRequirementBinding"; //$NON-NLS-1$
+
+    final static String TAG_DEFAULT_ENABLEMENT = "defaultEnablement"; //$NON-NLS-1$
+
+    final static String TAG_ACTIVITY_ID = "activityId"; //$NON-NLS-1$
+
+    final static String TAG_ACTIVITY_PATTERN_BINDING = "activityPatternBinding"; //$NON-NLS-1$
+
+    final static String TAG_CATEGORY = "category"; //$NON-NLS-1$
+
+    final static String TAG_CATEGORY_ACTIVITY_BINDING = "categoryActivityBinding"; //$NON-NLS-1$
+
+    final static String TAG_CATEGORY_ID = "categoryId"; //$NON-NLS-1$
+
+    final static String TAG_REQUIRED_ACTIVITY_ID = "requiredActivityId"; //$NON-NLS-1$
+
+    final static String TAG_ID = "id"; //$NON-NLS-1$
+
+    final static String TAG_NAME = "name"; //$NON-NLS-1$
+
+    final static String TAG_PATTERN = "pattern"; //$NON-NLS-1$
+
+    final static String TAG_IS_EQUALITY_PATTERN = "isEqualityPattern"; //$NON-NLS-1$
+
+    final static String TAG_SOURCE_ID = "sourceId"; //$NON-NLS-1$
+
+    final static String TAG_DESCRIPTION = "description"; //$NON-NLS-1$
+
+    // Used only in error messages addressed to plug-in developers
+    public final static String ACTIVITY_REQUIREMENT_BINDING_DESC = "Invalid activity requirement binding"; //$NON-NLS-1$
+    public final static String ACTIVITY_DESC = "Invalid activity"; //$NON-NLS-1$
+    public final static String ACTIVITY_PATTERN_BINDING_DESC = "Invalid activity pattern binding"; //$NON-NLS-1$
+    public final static String CATEGORY_ACTIVITY_BINDING_DESC = "Invalid category activity binding"; //$NON-NLS-1$
+    public final static String CATEGORY_DESC = "Invalid category description"; //$NON-NLS-1$
+    public final static String ACTIVITY_IMAGE_BINDING_DESC = "Invalid activity image binding"; //$NON-NLS-1$
+    public final static String ACTIVITY_TRIGGER_DESC = "Invalid trigger point"; //$NON-NLS-1$
+    public final static String ACTIVITY_TRIGGER_HINT_DESC = "Invalid trigger point hint"; //$NON-NLS-1$
+
+    // Non-translatable error messages for plug-in developers
+    public final static String shortContextTemplate = " (contributed by ''{0}'')"; //$NON-NLS-1$;
+    public final static String fullContextTemplate = " (contributed by ''{0}'', extension ID ''{1}'')"; //$NON-NLS-1$;
+
+    static ActivityRequirementBindingDefinition readActivityRequirementBindingDefinition(
+            IMemento memento, String sourceIdOverride) { //, IStatus status) {
+        String childActivityId = memento.getString(TAG_REQUIRED_ACTIVITY_ID);
+        if (childActivityId == null) {
+        	log(memento, ACTIVITY_REQUIREMENT_BINDING_DESC, "missing ID of the required activity"); //$NON-NLS-1$
+			return null;
+		}
+        String parentActivityId = memento.getString(TAG_ACTIVITY_ID);
+        if (parentActivityId == null) {
+        	log(memento, ACTIVITY_REQUIREMENT_BINDING_DESC, "missing ID of the activity to bind"); //$NON-NLS-1$
+			return null;
+		}
+        String sourceId = sourceIdOverride != null ? sourceIdOverride : memento
+                .getString(TAG_SOURCE_ID);
+        return new ActivityRequirementBindingDefinition(childActivityId,
+                parentActivityId, sourceId);
+    }
+
+    static String readDefaultEnablement(IMemento memento) {
+        return memento.getString(TAG_ID);
+    }
+
+    static ActivityDefinition readActivityDefinition(IMemento memento,
+            String sourceIdOverride) {
+
+        String id = memento.getString(TAG_ID);
+        if (id == null) {
+        	log(memento, ACTIVITY_DESC, "missing a unique identifier"); //$NON-NLS-1$
+			return null;
+		}
+        String name = memento.getString(TAG_NAME);
+        if (name == null) {
+        	log(memento, ACTIVITY_DESC, "missing a translatable name"); //$NON-NLS-1$
+			return null;
+		}
+        String description = memento.getString(TAG_DESCRIPTION);
+        if (description == null) {
+			description = ""; //$NON-NLS-1$
+		}
+        String sourceId = sourceIdOverride != null ? sourceIdOverride : memento
+                .getString(TAG_SOURCE_ID);
+        return new ActivityDefinition(id, name, sourceId, description);
+    }
+
+    static ActivityPatternBindingDefinition readActivityPatternBindingDefinition(
+            IMemento memento, String sourceIdOverride) {
+
+        String activityId = memento.getString(TAG_ACTIVITY_ID);
+        if (activityId == null) {
+        	log(memento, ACTIVITY_PATTERN_BINDING_DESC, "missing an ID of the activity to bind"); //$NON-NLS-1$
+			return null;
+		}
+        String pattern = memento.getString(TAG_PATTERN);
+        if (pattern == null) {
+        	log(memento, ACTIVITY_PATTERN_BINDING_DESC, "missing the pattern to be bound"); //$NON-NLS-1$
+			return null;
+		}
+        String sourceId = sourceIdOverride != null ? sourceIdOverride : memento
+                .getString(TAG_SOURCE_ID);
+
+        final String isEqualityPatternStr = memento.getString(TAG_IS_EQUALITY_PATTERN);
+        final boolean isEqualityPattern = (isEqualityPatternStr != null && isEqualityPatternStr
+				.equals("true")); //$NON-NLS-1$
+
+        return new ActivityPatternBindingDefinition(activityId, pattern,
+                sourceId, isEqualityPattern);
+    }
+
+    static CategoryActivityBindingDefinition readCategoryActivityBindingDefinition(
+            IMemento memento, String sourceIdOverride) {
+
+        String activityId = memento.getString(TAG_ACTIVITY_ID);
+        if (activityId == null) {
+        	log(memento, CATEGORY_ACTIVITY_BINDING_DESC, "missing the ID of the activity to bind"); //$NON-NLS-1$
+			return null;
+		}
+        String categoryId = memento.getString(TAG_CATEGORY_ID);
+        if (categoryId == null) {
+        	log(memento, CATEGORY_ACTIVITY_BINDING_DESC, "missing the ID of the category to bind"); //$NON-NLS-1$
+			return null;
+		}
+        String sourceId = sourceIdOverride != null ? sourceIdOverride : memento
+                .getString(TAG_SOURCE_ID);
+        return new CategoryActivityBindingDefinition(activityId, categoryId,
+                sourceId);
+    }
+
+    static CategoryDefinition readCategoryDefinition(IMemento memento,
+            String sourceIdOverride) {
+
+        String id = memento.getString(TAG_ID);
+        if (id == null) {
+        	log(memento, CATEGORY_DESC, "has no ID"); //$NON-NLS-1$
+			return null;
+		}
+        String name = memento.getString(TAG_NAME);
+        if (name == null) {
+        	log(memento, CATEGORY_DESC, "missing a translatable name"); //$NON-NLS-1$
+			return null;
+		}
+        String description = memento.getString(TAG_DESCRIPTION);
+        if (description == null) {
+			description = ""; //$NON-NLS-1$
+		}
+        String sourceId = sourceIdOverride != null ? sourceIdOverride : memento
+                .getString(TAG_SOURCE_ID);
+        return new CategoryDefinition(id, name, sourceId, description);
+    }
+
+    private Persistence() {
+        //no-op
+    }
+
+    static public void log(IMemento memento, String elementName, String msg) {
+    	if (memento instanceof ConfigurationElementMemento) {
+    		ConfigurationElementMemento cMemento = (ConfigurationElementMemento) memento;
+    		log(elementName, msg, cMemento.getContributorName(), cMemento.getExtensionID());
+    	} else
+    		log(elementName, msg, null, null);
+    }
+
+    static public void log(IConfigurationElement element, String elementName, String msg) {
+    	String contributorName = element.getContributor().getName();
+    	String extensionID = element.getDeclaringExtension().getUniqueIdentifier();
+   		log(elementName, msg, contributorName, extensionID);
+    }
+
+    static public void log(String elementName, String msg, String contributorName, String extensionID) {
+    	String msgInContext = elementName + ": " + msg; //$NON-NLS-1$;
+    	if (contributorName != null && extensionID != null)
+    		msgInContext += NLS.bind(fullContextTemplate, contributorName, extensionID);
+    	else if (contributorName != null)
+    		msgInContext += NLS.bind(shortContextTemplate, contributorName);
+        WorkbenchPlugin.log(msgInContext);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ProxyActivityManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ProxyActivityManager.java
new file mode 100644
index 0000000..1694862
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ProxyActivityManager.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2014 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.ui.internal.activities;
+
+import java.util.Set;
+
+import org.eclipse.ui.activities.ActivityManagerEvent;
+import org.eclipse.ui.activities.IActivity;
+import org.eclipse.ui.activities.IActivityManager;
+import org.eclipse.ui.activities.ICategory;
+import org.eclipse.ui.activities.IIdentifier;
+
+public final class ProxyActivityManager extends AbstractActivityManager {
+    private IActivityManager activityManager;
+
+    public ProxyActivityManager(IActivityManager activityManager) {
+        if (activityManager == null) {
+			throw new NullPointerException();
+		}
+
+        this.activityManager = activityManager;
+
+        this.activityManager
+                .addActivityManagerListener(activityManagerEvent -> {
+                  ActivityManagerEvent proxyActivityManagerEvent = new ActivityManagerEvent(
+				    ProxyActivityManager.this, activityManagerEvent
+				            .haveDefinedActivityIdsChanged(),
+				    activityManagerEvent
+				            .haveDefinedCategoryIdsChanged(),
+				    activityManagerEvent
+				            .haveEnabledActivityIdsChanged(),
+				    activityManagerEvent
+				            .getPreviouslyDefinedActivityIds(),
+				    activityManagerEvent
+				            .getPreviouslyDefinedCategoryIds(),
+				    activityManagerEvent
+				            .getPreviouslyEnabledActivityIds());
+                  fireActivityManagerChanged(proxyActivityManagerEvent);
+               });
+    }
+
+    @Override
+	public IActivity getActivity(String activityId) {
+        return activityManager.getActivity(activityId);
+    }
+
+    @Override
+	public ICategory getCategory(String categoryId) {
+        return activityManager.getCategory(categoryId);
+    }
+
+    @Override
+	public Set getDefinedActivityIds() {
+        return activityManager.getDefinedActivityIds();
+    }
+
+    @Override
+	public Set getDefinedCategoryIds() {
+        return activityManager.getDefinedCategoryIds();
+    }
+
+    @Override
+	public Set getEnabledActivityIds() {
+        return activityManager.getEnabledActivityIds();
+    }
+
+    @Override
+	public IIdentifier getIdentifier(String identifierId) {
+        return activityManager.getIdentifier(identifierId);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/AbstractTriggerPoint.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/AbstractTriggerPoint.java
new file mode 100644
index 0000000..7b8b66a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/AbstractTriggerPoint.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.activities.ws;
+
+import org.eclipse.ui.activities.ITriggerPoint;
+
+/**
+ * @since 3.1
+ */
+public abstract class AbstractTriggerPoint implements ITriggerPoint {
+
+
+	@Override
+	public boolean equals(Object obj) {
+		if (obj instanceof ITriggerPoint) {
+			return getId().equals(((ITriggerPoint)obj).getId());
+		}
+
+		return false;
+	}
+
+	@Override
+	public int hashCode() {
+		return getId().hashCode();
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/ActivityCategoryContentProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/ActivityCategoryContentProvider.java
new file mode 100644
index 0000000..b26d5bd
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/ActivityCategoryContentProvider.java
@@ -0,0 +1,255 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2016 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.ui.internal.activities.ws;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.ui.activities.IActivity;
+import org.eclipse.ui.activities.IActivityManager;
+import org.eclipse.ui.activities.IActivityRequirementBinding;
+import org.eclipse.ui.activities.ICategory;
+import org.eclipse.ui.internal.activities.InternalActivityHelper;
+
+/**
+ * Tree provider that provides <code>ICategory</code> objects in an
+ * <code>IActivityManager</code> at the top level, with <code>IActivity</code>
+ * objects as second level children under the <code>ICategory</code>.
+ * <p>
+ * Note that the <code>IActivity</code> objects are not instances of
+ * <code>org.eclipse.ui.internal.activities.Activity</code>, but rather proxies
+ * that also have a pointer to the <code>ICategory</code> for which the
+ * <code>IActivity</code> should be represented under.
+ *
+ * @since 3.0
+ */
+public class ActivityCategoryContentProvider implements ITreeContentProvider {
+
+    /**
+     * The manager to extract content from.
+     */
+    private IActivityManager manager;
+
+    @Override
+	public void dispose() {
+        manager = null;
+    }
+
+    /**
+	 * @param category
+	 * 		the category to fetch.
+	 * @return all activities in the category.
+	 */
+	private IActivity[] getCategoryActivities(ICategory category) {
+		Set activityIds = InternalActivityHelper.getActivityIdsForCategory(
+				manager, category);
+		List categoryActivities = new ArrayList(activityIds.size());
+		for (Iterator i = activityIds.iterator(); i.hasNext();) {
+			String activityId = (String) i.next();
+			categoryActivities.add(new CategorizedActivity(category, manager
+					.getActivity(activityId)));
+
+		}
+		return (IActivity[]) categoryActivities
+				.toArray(new IActivity[categoryActivities.size()]);
+	}
+
+	/**
+	 * Get the duplicate activities found in the other defined categories.
+	 *
+	 * @param categorizedActivity
+	 *            The categorized activity.
+	 * @return the list of duplicate categorized activities.
+	 */
+	public Object[] getDuplicateCategoryActivities(
+			CategorizedActivity categorizedActivity) {
+		ArrayList duplicateCategorizedactivities = new ArrayList();
+		Set categoryIds = manager.getDefinedCategoryIds();
+		ICategory currentCategory = null;
+		String currentActivityId = null;
+		IActivity[] categoryActivities = null;
+		String currentCategoryId = null;
+		// find the duplicate activities in the defined categories
+		for (Iterator i = categoryIds.iterator(); i.hasNext();) {
+			currentCategoryId = (String) i.next();
+			if (!currentCategoryId.equals(categorizedActivity.getCategory()
+					.getId())) {
+				currentCategory = manager.getCategory(currentCategoryId);
+				categoryActivities = getCategoryActivities(currentCategory);
+				// traverse the category's activities to find a duplicate
+				for (IActivity categoryActivity : categoryActivities) {
+					currentActivityId = categoryActivity.getId();
+					if (currentActivityId.equals(categorizedActivity
+							.getActivity().getId())) {
+						duplicateCategorizedactivities
+								.add(new CategorizedActivity(currentCategory,
+										manager.getActivity(currentActivityId)));
+						// Assuming only one unique activity per category -
+						// break
+						break;
+					}
+				}
+
+			}
+
+		}
+		return duplicateCategorizedactivities.toArray();
+	}
+
+	/**
+	 * Get the child required activities.
+	 *
+	 * @param activityId
+	 *            The parent activity id.
+	 * @return the list of child required activities.
+	 */
+	public Object[] getChildRequiredActivities(String activityId) {
+		ArrayList childRequiredActivities = new ArrayList();
+		IActivity activity = manager.getActivity(activityId);
+		Set actvitiyRequirementBindings = activity
+				.getActivityRequirementBindings();
+		String requiredActivityId = null;
+		IActivityRequirementBinding currentActivityRequirementBinding = null;
+		Object[] currentCategoryIds = null;
+		for (Iterator i = actvitiyRequirementBindings.iterator(); i.hasNext();) {
+			currentActivityRequirementBinding = (IActivityRequirementBinding) i
+					.next();
+			requiredActivityId = currentActivityRequirementBinding
+					.getRequiredActivityId();
+			currentCategoryIds = getActivityCategories(requiredActivityId);
+			for (Object currentCategoryId : currentCategoryIds) {
+				childRequiredActivities.add(new CategorizedActivity(manager
+						.getCategory((String) currentCategoryId),
+						manager.getActivity(requiredActivityId)));
+			}
+
+		}
+
+		return childRequiredActivities.toArray();
+	}
+
+	/**
+	 * Get the parent required activities.
+	 *
+	 * @param activityId
+	 *            The child activity id.
+	 * @return the list of parent required activities.
+	 */
+	public Object[] getParentRequiredActivities(String activityId) {
+		ArrayList parentRequiredActivities = new ArrayList();
+		Set definedActivities = manager.getDefinedActivityIds();
+		String currentActivityId = null;
+		Set activityRequirementBindings = null;
+		IActivityRequirementBinding currentActivityRequirementBinding = null;
+		Object[] currentCategoryIds = null;
+		for (Iterator i = definedActivities.iterator(); i.hasNext();) {
+			currentActivityId = (String) i.next();
+			activityRequirementBindings = manager
+					.getActivity(currentActivityId)
+					.getActivityRequirementBindings();
+			for (Iterator j = activityRequirementBindings.iterator(); j
+					.hasNext();) {
+				currentActivityRequirementBinding = (IActivityRequirementBinding) j
+						.next();
+				if (currentActivityRequirementBinding.getRequiredActivityId()
+						.equals(activityId)) {
+					// We found one - add it to the list
+					currentCategoryIds = getActivityCategories(currentActivityId);
+					for (Object currentCategoryId : currentCategoryIds) {
+						parentRequiredActivities
+								.add(new CategorizedActivity(
+										manager
+												.getCategory((String) currentCategoryId),
+										manager.getActivity(currentActivityId)));
+					}
+				}
+			}
+
+		}
+		return parentRequiredActivities.toArray();
+	}
+
+	/**
+	 * Get the activity's categories (there could be more than one).
+	 *
+	 * @param activityId
+	 *            The activity id.
+	 * @return the activity's categories.
+	 */
+	private Object[] getActivityCategories(String activityId) {
+		ArrayList activityCategories = new ArrayList();
+		Set categoryIds = manager.getDefinedCategoryIds();
+		String currentCategoryId = null;
+		IActivity[] categoryActivities = null;
+		for (Iterator i = categoryIds.iterator(); i.hasNext();) {
+			currentCategoryId = (String) i.next();
+			categoryActivities = getCategoryActivities(manager
+					.getCategory(currentCategoryId));
+			for (IActivity categoryActivity : categoryActivities) {
+				if (categoryActivity.getId().equals(activityId)) {
+					activityCategories.add(currentCategoryId);
+					break;
+				}
+			}
+		}
+		return activityCategories.toArray();
+	}
+
+    @Override
+	public Object[] getChildren(Object parentElement) {
+        if (parentElement instanceof IActivityManager) {
+            Set categoryIds = manager.getDefinedCategoryIds();
+            ArrayList categories = new ArrayList(categoryIds.size());
+            for (Iterator i = categoryIds.iterator(); i.hasNext();) {
+                String categoryId = (String) i.next();
+                ICategory category = manager.getCategory(categoryId);
+				if (getCategoryActivities(category).length > 0) {
+					categories.add(category);
+				}
+            }
+            return categories.toArray();
+        } else if (parentElement instanceof ICategory) {
+            return getCategoryActivities((ICategory) parentElement);
+        }
+        return new Object[0];
+    }
+
+    @Override
+	public Object[] getElements(Object inputElement) {
+        return getChildren(inputElement);
+    }
+
+    @Override
+	public Object getParent(Object element) {
+        if (element instanceof CategorizedActivity) {
+            return ((CategorizedActivity) element).getCategory();
+        }
+        return null;
+    }
+
+    @Override
+	public boolean hasChildren(Object element) {
+        if (element instanceof IActivityManager || element instanceof ICategory) {
+			return true;
+		}
+        return false;
+    }
+
+    @Override
+	public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+		if (newInput instanceof IActivityManager) {
+			manager = (IActivityManager) newInput;
+		}
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/ActivityCategoryLabelProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/ActivityCategoryLabelProvider.java
new file mode 100644
index 0000000..aaeff3f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/ActivityCategoryLabelProvider.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.internal.activities.ws;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.jface.resource.DeviceResourceException;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.activities.IActivity;
+import org.eclipse.ui.activities.ICategory;
+import org.eclipse.ui.activities.NotDefinedException;
+
+/**
+ * Provides labels for elements drawn from <code>IActivityManagers</code>.
+ * Ie:  <code>IActivity</code> and <code>ICategory</code> objects.
+ *
+ * @since 3.0
+ */
+public class ActivityCategoryLabelProvider extends LabelProvider {
+
+	private LocalResourceManager manager;
+	private Map descriptorMap = new HashMap();
+
+	/**
+	 * Create a new instance of this class.
+	 */
+	public ActivityCategoryLabelProvider() {
+		manager = new LocalResourceManager(JFaceResources.getResources());
+	}
+
+    @Override
+	public Image getImage(Object element) {
+    	try {
+    		ImageDescriptor descriptor = getDescriptor(element);
+	        if (descriptor != null) {
+				return manager.createImage(descriptor);
+			}
+    	}
+    	catch (DeviceResourceException e) {
+    		//ignore
+    	}
+        return null;
+    }
+
+    private ImageDescriptor getDescriptor(Object element) {
+    	ImageDescriptor descriptor = (ImageDescriptor) descriptorMap.get(element);
+    	if (descriptor != null) {
+			return descriptor;
+		}
+
+    	if (element instanceof ICategory) {
+        	ICategory category = (ICategory) element;
+			descriptor = PlatformUI.getWorkbench().getActivitySupport()
+					.getImageDescriptor(category);
+			if (descriptor != null) {
+				descriptorMap.put(element, descriptor);
+			}
+        } else if (element instanceof IActivity) {
+        	IActivity activity = (IActivity) element;
+			descriptor = PlatformUI.getWorkbench().getActivitySupport()
+					.getImageDescriptor(activity);
+			if (descriptor != null) {
+				descriptorMap.put(element, descriptor);
+			}
+        }
+    	return descriptor;
+    }
+
+    @Override
+	public String getText(Object element) {
+        if (element instanceof IActivity) {
+            IActivity activity = (IActivity) element;
+            try {
+                return activity.getName();
+            } catch (NotDefinedException e) {
+                return activity.getId();
+            }
+        } else if (element instanceof ICategory) {
+            ICategory category = ((ICategory) element);
+            try {
+                return category.getName();
+            } catch (NotDefinedException e) {
+                return category.getId();
+            }
+        }
+        return super.getText(element);
+    }
+
+    @Override
+	public void dispose() {
+    	manager.dispose();
+    	descriptorMap.clear();
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/ActivityContentProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/ActivityContentProvider.java
new file mode 100644
index 0000000..fc5e489
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/ActivityContentProvider.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.internal.activities.ws;
+
+import java.util.Collection;
+
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.ui.activities.IActivityManager;
+
+/**
+ * @since 3.0
+ */
+public class ActivityContentProvider implements IStructuredContentProvider {
+
+    @Override
+	public Object[] getElements(Object inputElement) {
+        Object[] activities = new Object[0];
+        if (inputElement instanceof IActivityManager) {
+			activities = ((IActivityManager) inputElement).getDefinedActivityIds().toArray();
+        } else if (inputElement instanceof Collection) {
+            activities = ((Collection) inputElement).toArray();
+        }
+        return activities;
+    }
+    
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.eclipse.jface.viewers.IContentProvider#dispose()
+     */
+    @Override
+    public void dispose() {
+    }
+    
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer,
+     *      java.lang.Object, java.lang.Object)
+     */
+    @Override
+    public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/ActivityEnabler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/ActivityEnabler.java
new file mode 100644
index 0000000..5975a88
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/ActivityEnabler.java
@@ -0,0 +1,484 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2016 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.ui.internal.activities.ws;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.viewers.AbstractTreeViewer;
+import org.eclipse.jface.viewers.CheckStateChangedEvent;
+import org.eclipse.jface.viewers.CheckboxTreeViewer;
+import org.eclipse.jface.viewers.ICheckStateListener;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.FontMetrics;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.activities.ActivitiesPreferencePage;
+import org.eclipse.ui.activities.IActivity;
+import org.eclipse.ui.activities.ICategory;
+import org.eclipse.ui.activities.IMutableActivityManager;
+import org.eclipse.ui.activities.NotDefinedException;
+import org.eclipse.ui.internal.activities.InternalActivityHelper;
+
+/**
+ * A simple control provider that will allow the user to toggle on/off the
+ * activities bound to categories.
+ *
+ * @since 3.0
+ */
+public class ActivityEnabler {
+
+	private static final int ALL = 2;
+
+	private static final int NONE = 0;
+
+	private static final int SOME = 1;
+
+	private ISelectionChangedListener selectionListener = new ISelectionChangedListener() {
+
+		@Override
+		public void selectionChanged(SelectionChangedEvent event) {
+			Object element = ((IStructuredSelection) event.getSelection())
+					.getFirstElement();
+			try {
+				if (element instanceof ICategory) {
+					descriptionText.setText(((ICategory) element)
+							.getDescription());
+				} else if (element instanceof IActivity) {
+					descriptionText.setText(((IActivity) element)
+							.getDescription());
+				}
+			} catch (NotDefinedException e) {
+				descriptionText.setText(""); //$NON-NLS-1$
+			}
+		}
+	};
+
+	/**
+	 * Listener that manages the grey/check state of categories.
+	 */
+	private ICheckStateListener checkListener = new ICheckStateListener() {
+
+		@Override
+		public void checkStateChanged(CheckStateChangedEvent event) {
+			Set checked = new HashSet(Arrays.asList(dualViewer
+					.getCheckedElements()));
+			Object element = event.getElement();
+			if (element instanceof ICategory) {
+				// clicking on a category should enable/disable all activities
+				// within it
+				dualViewer.setSubtreeChecked(element, event.getChecked());
+				// the state of the category is always absolute after clicking
+				// on it. Never gray.
+				dualViewer.setGrayed(element, false);
+				// Update the category's activities for multiplicity in other
+				// categories
+				for (Object categoryActivity : provider.getChildren(element)) {
+					handleDuplicateActivities(event.getChecked(),
+							categoryActivity);
+				}
+
+			} else {
+				// Activity checked
+				handleActivityCheck(checked, element);
+				handleDuplicateActivities(event.getChecked(), element);
+			}
+		}
+
+		/**
+		 * Handle duplicate activities.
+		 *
+		 * @param checkedState
+		 *            Checked state of the element.
+		 * @param element
+		 *            The checked element.
+		 */
+		private void handleDuplicateActivities(boolean checkedState,
+				Object element) {
+			// Retrieve duplicate activities from the other categories
+			Object[] duplicateActivities = provider.getDuplicateCategoryActivities((CategorizedActivity) element);
+			for (Object activity : duplicateActivities) {
+				// Update the duplicate activity with the same state as the
+				// original
+				dualViewer.setChecked(activity, checkedState);
+				// handle the activity check to potentially update its
+				// category's enablement
+				handleActivityCheck(new HashSet(Arrays.asList(dualViewer
+						.getCheckedElements())), activity);
+			}
+		}
+
+		/**
+		 * Handle the checking of an activity and update its category's checked
+		 * state.
+		 *
+		 * @param checked
+		 *            The set of checked elements in the viewer.
+		 * @param element
+		 *            The checked element.
+		 */
+		private void handleActivityCheck(Set checked, Object element) {
+			// clicking on an activity can potentially change the check/gray
+			// state of its category.
+			CategorizedActivity proxy = (CategorizedActivity) element;
+			Object[] children = provider.getChildren(proxy.getCategory());
+			int state = NONE;
+			int count = 0;
+			for (Object child : children) {
+				if (checked.contains(child)) {
+					count++;
+				}
+			}
+
+			if (count == children.length) {
+				state = ALL;
+			} else if (count != 0) {
+				state = SOME;
+			}
+
+			if (state == NONE) {
+				checked.remove(proxy.getCategory());
+			} else {
+				checked.add(proxy.getCategory());
+			}
+
+			dualViewer.setGrayed(proxy.getCategory(), state == SOME);
+			dualViewer.setCheckedElements(checked.toArray());
+			// Check child required activities and uncheck parent required activities
+			// if needed
+			handleRequiredActivities(checked, element);
+		}
+
+		/**
+		 * Handle the activity's required activities (parent and child).
+		 *
+		 * @param checked
+		 *            The set of checked elements in the viewer.
+		 * @param element
+		 *            The checked element.
+		 *
+		 */
+		private void handleRequiredActivities(Set checked, Object element) {
+			Object[] requiredActivities = null;
+			// An element has been checked - we want to check its child required
+			// activities
+			if (checked.contains(element)) {
+				requiredActivities = provider
+						.getChildRequiredActivities(((CategorizedActivity) element)
+								.getId());
+				for (int index = 0; index < requiredActivities.length; index++) {
+					// We want to check the element if it is unchecked
+					if (!checked.contains(requiredActivities[index])) {
+						dualViewer.setChecked(requiredActivities[index], true);
+						handleActivityCheck(new HashSet(Arrays
+								.asList(dualViewer.getCheckedElements())),
+								requiredActivities[index]);
+					}
+				}
+			}
+			// An element has been unchecked - we want to uncheck its parent
+			// required activities
+			else {
+				requiredActivities = provider.getParentRequiredActivities(((CategorizedActivity) element).getId());
+				for (Object requiredActivity : requiredActivities) {
+					// We want to uncheck the element if it is checked
+					if (checked.contains(requiredActivity)) {
+						dualViewer.setChecked(requiredActivity, false);
+						handleActivityCheck(new HashSet(Arrays
+								.asList(dualViewer.getCheckedElements())),
+								requiredActivity);
+					}
+				}
+			}
+		}
+
+	};
+
+	protected CheckboxTreeViewer dualViewer;
+
+	/**
+	 * The Set of activities that belong to at least one category.
+	 */
+	private Set managedActivities = new HashSet(7);
+
+	/**
+	 * The content provider.
+	 */
+	protected ActivityCategoryContentProvider provider = new ActivityCategoryContentProvider();
+
+	/**
+	 * The descriptive text.
+	 */
+	protected Text descriptionText;
+
+	private Properties strings;
+
+    private IMutableActivityManager activitySupport;
+
+	private TableViewer dependantViewer;
+
+	/**
+	 * Create a new instance.
+	 *
+	 * @param activitySupport
+	 *            the <code>IMutableActivityMananger</code> to use.
+	 * @param strings
+	 *            map of strings to use. See the constants on
+	 *            {@link org.eclipse.ui.activities.ActivitiesPreferencePage} for
+	 *            details.
+	 */
+	public ActivityEnabler(IMutableActivityManager activitySupport, Properties strings) {
+		this.activitySupport = activitySupport;
+		this.strings = strings;
+	}
+
+	/**
+	 * Create the controls.
+	 *
+	 * @param parent
+	 *            the parent in which to create the controls.
+	 * @return the composite in which the controls exist.
+	 */
+	public Control createControl(Composite parent) {
+        GC gc = new GC(parent);
+        gc.setFont(JFaceResources.getDialogFont());
+        FontMetrics fontMetrics = gc.getFontMetrics();
+        gc.dispose();
+
+		Composite composite = new Composite(parent, SWT.NONE);
+
+		composite.setLayout(new GridLayout(2, true));
+
+		new Label(composite, SWT.NONE).setText(strings.getProperty(ActivitiesPreferencePage.ACTIVITY_NAME,
+				ActivityMessages.ActivityEnabler_activities));
+		new Label(composite, SWT.NONE).setText(ActivityMessages.ActivityEnabler_description);
+
+		dualViewer = new CheckboxTreeViewer(composite);
+		dualViewer.setComparator(new ViewerComparator());
+		dualViewer.setLabelProvider(new ActivityCategoryLabelProvider());
+		dualViewer.setContentProvider(provider);
+		dualViewer.setInput(activitySupport);
+		GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
+		data.heightHint = 200;
+		dualViewer.getControl().setLayoutData(data);
+
+		Composite detailsComp = new Composite(composite, SWT.NONE);
+		detailsComp.setLayout(new GridLayout());
+		detailsComp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+		descriptionText = new Text(detailsComp, SWT.READ_ONLY | SWT.WRAP | SWT.BORDER | SWT.V_SCROLL);
+		data = new GridData(SWT.FILL, SWT.FILL, true, false);
+		data.heightHint = Dialog.convertHeightInCharsToPixels(fontMetrics, 5);
+		descriptionText.setLayoutData(data);
+		setInitialStates();
+
+		new Label(detailsComp, SWT.NONE).setText(ActivityMessages.ActivitiesPreferencePage_requirements);
+		dependantViewer = new TableViewer(detailsComp, SWT.BORDER);
+		dependantViewer.getControl().setLayoutData(new GridData(GridData.FILL_BOTH));
+		dependantViewer.setContentProvider(new ActivityCategoryContentProvider());
+		dependantViewer.setLabelProvider(new ActivityCategoryLabelProvider());
+		dependantViewer.setInput(Collections.EMPTY_SET);
+		Composite buttonComposite = new Composite(composite, SWT.NONE);
+		buttonComposite.setLayout(createGridLayoutWithoutMargins(2, fontMetrics));
+
+		Button selectAllButton = new Button(buttonComposite, SWT.PUSH);
+		selectAllButton.setText(ActivityMessages.ActivityEnabler_selectAll);
+		selectAllButton.addSelectionListener(new SelectionAdapter()
+        {
+            public void widgetSelected(SelectionEvent e) 
+            {
+                toggleTreeEnablement(true);
+            }
+        });
+		setButtonLayoutData(selectAllButton, fontMetrics);
+
+		Button deselectAllButton = new Button(buttonComposite, SWT.PUSH);
+		deselectAllButton.setText(ActivityMessages.ActivityEnabler_deselectAll);
+		deselectAllButton.addSelectionListener(new SelectionAdapter()
+        {
+            public void widgetSelected(SelectionEvent e) 
+            {
+                toggleTreeEnablement(false);
+            }
+        });
+		setButtonLayoutData(deselectAllButton, fontMetrics);
+
+
+		dualViewer.addCheckStateListener(checkListener);
+		dualViewer.addSelectionChangedListener(selectionListener);
+
+		dualViewer.setSelection(new StructuredSelection());
+
+        Dialog.applyDialogFont(composite);
+
+		return composite;
+	}
+
+	private GridLayout createGridLayoutWithoutMargins(int nColumns, FontMetrics fontMetrics) {
+		GridLayout layout = new GridLayout(nColumns, false);
+		layout.marginHeight = 0;
+		layout.marginWidth = 0;
+		layout.horizontalSpacing = Dialog.convertHorizontalDLUsToPixels(fontMetrics, IDialogConstants.HORIZONTAL_SPACING);
+		layout.verticalSpacing = Dialog.convertVerticalDLUsToPixels(fontMetrics, IDialogConstants.VERTICAL_SPACING);
+		return layout;
+	}
+
+    private GridData setButtonLayoutData(Button button, FontMetrics fontMetrics) {
+        GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
+        int widthHint = Dialog.convertHorizontalDLUsToPixels(fontMetrics, IDialogConstants.BUTTON_WIDTH);
+        Point minSize = button.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
+        data.widthHint = Math.max(widthHint, minSize.x);
+        button.setLayoutData(data);
+        return data;
+    }
+
+	/**
+	 * Set the enabled category/activity check/grey states based on initial
+	 * activity enablement.
+	 */
+	private void setInitialStates() {
+		Set enabledActivities = activitySupport
+				.getEnabledActivityIds();
+		setEnabledStates(enabledActivities);
+	}
+
+	private void setEnabledStates(Set enabledActivities) {
+		Set categories = activitySupport
+				.getDefinedCategoryIds();
+		List checked = new ArrayList(10), grayed = new ArrayList(10);
+		for (Iterator i = categories.iterator(); i.hasNext();) {
+			String categoryId = (String) i.next();
+			ICategory category = activitySupport
+					.getCategory(categoryId);
+
+			int state = NONE;
+
+			Collection activities = InternalActivityHelper
+					.getActivityIdsForCategory(activitySupport, category);
+			int foundCount = 0;
+			for (Iterator j = activities.iterator(); j.hasNext();) {
+				String activityId = (String) j.next();
+				managedActivities.add(activityId);
+				if (enabledActivities.contains(activityId)) {
+					IActivity activity = activitySupport
+							.getActivity(activityId);
+					checked.add(new CategorizedActivity(category, activity));
+					//add activity proxy
+					foundCount++;
+				}
+			}
+
+			if (foundCount == activities.size()) {
+				state = ALL;
+			} else if (foundCount > 0) {
+				state = SOME;
+			}
+
+			if (state == NONE) {
+				continue;
+			}
+			checked.add(category);
+
+			if (state == SOME) {
+				grayed.add(category);
+			}
+		}
+
+		dualViewer.setCheckedElements(checked.toArray());
+		dualViewer.setGrayedElements(grayed.toArray());
+	}
+
+	/**
+	 * Update activity enablement based on the check states of activities in the
+	 * tree.
+	 */
+	public void updateActivityStates() {
+		Set enabledActivities = new HashSet(activitySupport.getEnabledActivityIds());
+
+		// remove all but the unmanaged activities (if any).
+		enabledActivities.removeAll(managedActivities);
+
+		for (Object element : dualViewer.getCheckedElements()) {
+			if (element instanceof ICategory || dualViewer.getGrayed(element)) {
+				continue;
+			}
+			enabledActivities.add(((IActivity) element).getId());
+		}
+
+		activitySupport.setEnabledActivityIds(enabledActivities);
+	}
+
+	/**
+	 * Restore the default activity states.
+	 */
+	public void restoreDefaults() {
+	    Set defaultEnabled = new HashSet();
+	    Set activityIds = activitySupport.getDefinedActivityIds();
+	    for (Iterator i = activityIds.iterator(); i.hasNext();) {
+            String activityId = (String) i.next();
+            IActivity activity = activitySupport.getActivity(activityId);
+            try {
+                if (activity.isDefaultEnabled()) {
+                    defaultEnabled.add(activityId);
+                }
+            } catch (NotDefinedException e) {
+                // this can't happen - we're iterating over defined activities.
+            }
+        }
+
+		setEnabledStates(defaultEnabled);
+	}
+
+	/**
+	 * Toggles the enablement state of all activities.
+	 *
+	 * @param enabled
+	 *            whether the tree should be enabled
+	 */
+	protected void toggleTreeEnablement(boolean enabled) {
+		Object[] elements = provider.getElements(activitySupport);
+
+		//reset grey state to null
+		dualViewer.setGrayedElements(new Object[0]);
+
+		//enable all categories
+		for (Object element : elements) {
+			dualViewer
+					.expandToLevel(element, AbstractTreeViewer.ALL_LEVELS);
+			dualViewer.setSubtreeChecked(element, enabled);
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/ActivityLabelProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/ActivityLabelProvider.java
new file mode 100644
index 0000000..c469dc1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/ActivityLabelProvider.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.internal.activities.ws;
+
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.activities.IActivity;
+import org.eclipse.ui.activities.IActivityManager;
+import org.eclipse.ui.activities.NotDefinedException;
+
+/**
+ * Provides labels for <code>IActivity</code> objects. They may be passed
+ * directly or as <code>String</code> identifiers that are matched against
+ * the activity manager.
+ *
+ * @since 3.0
+ */
+public class ActivityLabelProvider extends LabelProvider {
+
+    private IActivityManager activityManager;
+
+    /**
+     * Create a new instance of the receiver.
+     *
+     * @param activityManager
+     * @since 3.0
+     */
+    public ActivityLabelProvider(IActivityManager activityManager) {
+        this.activityManager = activityManager;
+    }
+
+    /**
+     * @param activity
+     * @return
+     */
+    private String getActivityText(IActivity activity) {
+        try {
+            return activity.getName();
+        } catch (NotDefinedException e) {
+            return activity.getId();
+        }
+    }
+
+    @Override
+	public Image getImage(Object element) {
+        return null;
+    }
+
+    @Override
+	public String getText(Object element) {
+        if (element instanceof String) {
+            return getActivityText(activityManager
+                    .getActivity((String) element));
+        } else if (element instanceof IActivity) {
+            return getActivityText((IActivity) element);
+        } else {
+            throw new IllegalArgumentException();
+        }
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/ActivityMessages.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/ActivityMessages.java
new file mode 100644
index 0000000..5a13535
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/ActivityMessages.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.activities.ws;
+
+import org.eclipse.osgi.util.NLS;
+
+
+/**
+ * The ActivtyMessages are the messages used by the activities
+ * support.
+ *
+ */
+public class ActivityMessages extends NLS {
+	private static final String BUNDLE_NAME = "org.eclipse.ui.internal.activities.ws.messages";//$NON-NLS-1$
+
+	public static String ActivityEnabler_description;
+	public static String ActivityEnabler_activities;
+    public static String ActivityEnabler_categories;
+	public static String ActivityEnabler_selectAll;
+	public static String ActivityEnabler_deselectAll;
+    public static String ActivitiesPreferencePage_advancedDialogTitle;
+    public static String ActivitiesPreferencePage_advancedButton;
+    public static String ActivitiesPreferencePage_lockedMessage;
+    public static String ActivitiesPreferencePage_captionMessage;
+    public static String ActivitiesPreferencePage_requirements;
+	public static String ManagerTask;
+	public static String ManagerWindowSubTask;
+	public static String ManagerViewsSubTask;
+	public static String Perspective_showAll;
+	public static String activityPromptButton;
+	public static String activityPromptToolTip;
+
+	static {
+		// load message values from bundle file
+		NLS.initializeMessages(BUNDLE_NAME, ActivityMessages.class);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/ActivityViewerFilter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/ActivityViewerFilter.java
new file mode 100644
index 0000000..2efef19
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/ActivityViewerFilter.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.activities.ws;
+
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.ui.activities.WorkbenchActivityHelper;
+
+/**
+ * Generic viewer filter that works based on activity enablement.
+ *
+ * @since 3.0
+ */
+public class ActivityViewerFilter extends ViewerFilter {
+
+    private boolean hasEncounteredFilteredItem = false;
+
+    @Override
+	public boolean select(Viewer viewer, Object parentElement, Object element) {
+        if (WorkbenchActivityHelper.filterItem(element)) {
+            setHasEncounteredFilteredItem(true);
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * @return returns whether the filter has filtered an item
+     */
+    public boolean getHasEncounteredFilteredItem() {
+        return hasEncounteredFilteredItem;
+    }
+
+    /**
+     * @param sets whether the filter has filtered an item
+     */
+    public void setHasEncounteredFilteredItem(boolean hasEncounteredFilteredItem) {
+        this.hasEncounteredFilteredItem = hasEncounteredFilteredItem;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/CategorizedActivity.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/CategorizedActivity.java
new file mode 100644
index 0000000..b52a162
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/CategorizedActivity.java
@@ -0,0 +1,147 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.internal.activities.ws;
+
+import java.util.Set;
+
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.ui.activities.IActivity;
+import org.eclipse.ui.activities.IActivityListener;
+import org.eclipse.ui.activities.ICategory;
+import org.eclipse.ui.activities.NotDefinedException;
+
+/**
+ * IActivity proxy that is used by the
+ * <code>IActivityCategoryContentProvider</code>.  Each
+ * proxy keeps a pointer to the <code>ICategory</code> under which it is being
+ * provided.
+ *
+ * @since 3.0
+ */
+public class CategorizedActivity implements IActivity {
+
+    /**
+     * The real <code>IActivity</code>.
+     */
+    private IActivity activity;
+
+    /**
+     * The <code>ICategory</code> under which this proxy will be rendered.
+     */
+    private ICategory category;
+
+    /**
+     * Create a new instance.
+     *
+     * @param category the <code>ICategory</code> under which this proxy will be
+     * rendered.
+     * @param activity the real <code>IActivity</code>.
+     */
+    public CategorizedActivity(ICategory category, IActivity activity) {
+        this.activity = activity;
+        this.category = category;
+    }
+
+    @Override
+	public void addActivityListener(IActivityListener activityListener) {
+        activity.addActivityListener(activityListener);
+    }
+
+    @Override
+	public int compareTo(Object o) {
+        return activity.compareTo(o);
+    }
+
+    @Override
+	public boolean equals(Object o) {
+        if (o instanceof CategorizedActivity) {
+            if (((CategorizedActivity) o).getCategory().equals(getCategory())) {
+				return ((CategorizedActivity) o).getActivity().equals(
+                        getActivity());
+			}
+        }
+        return false;
+    }
+
+    /**
+     * @return returns the <code>IActivity</code>.
+     */
+    public IActivity getActivity() {
+        return activity;
+    }
+
+    @Override
+	public Set getActivityRequirementBindings() {
+        return activity.getActivityRequirementBindings();
+    }
+
+    @Override
+	public Set getActivityPatternBindings() {
+        return activity.getActivityPatternBindings();
+    }
+
+    /**
+     * @return returns the <code>ICategory</code>.
+     */
+    public ICategory getCategory() {
+        return category;
+    }
+
+    @Override
+	public String getId() {
+        return activity.getId();
+    }
+
+    @Override
+	public String getName() throws NotDefinedException {
+        return activity.getName();
+    }
+
+    @Override
+	public int hashCode() {
+        return activity.hashCode();
+    }
+
+    @Override
+	public boolean isDefined() {
+        return activity.isDefined();
+    }
+
+    @Override
+	public boolean isEnabled() {
+        return activity.isEnabled();
+    }
+
+    @Override
+	public void removeActivityListener(IActivityListener activityListener) {
+        activity.removeActivityListener(activityListener);
+    }
+
+    @Override
+	public String toString() {
+        return category.getId() + " -> " + activity.getId(); //$NON-NLS-1$
+    }
+
+    @Override
+	public String getDescription() throws NotDefinedException {
+        return activity.getDescription();
+    }
+
+    @Override
+	public boolean isDefaultEnabled() throws NotDefinedException {
+        return activity.isDefaultEnabled();
+    }
+
+    @Override
+	public Expression getExpression() {
+    	return activity.getExpression();
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/EnablementDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/EnablementDialog.java
new file mode 100644
index 0000000..06780e6
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/EnablementDialog.java
@@ -0,0 +1,310 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2016 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
+ *     Patrik Suzzi <psuzzi@gmail.com> - Bug 489250
+ *******************************************************************************/
+package org.eclipse.ui.internal.activities.ws;
+
+import com.ibm.icu.text.MessageFormat;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Properties;
+import java.util.ResourceBundle;
+import java.util.Set;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.viewers.CheckboxTableViewer;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.activities.IActivity;
+import org.eclipse.ui.activities.IActivityManager;
+import org.eclipse.ui.activities.NotDefinedException;
+import org.eclipse.ui.activities.WorkbenchTriggerPointAdvisor;
+
+/**
+ * Dialog that will prompt the user and confirm that they wish to activate a set
+ * of activities.
+ *
+ * @since 3.0
+ */
+public class EnablementDialog extends Dialog {
+
+	/**
+     * The translation bundle in which to look up internationalized text.
+     */
+    private final static ResourceBundle RESOURCE_BUNDLE = ResourceBundle
+            .getBundle(EnablementDialog.class.getName());
+
+    private Button dontAskButton;
+
+    private Set activitiesToEnable = new HashSet(7);
+
+    private Collection activityIds;
+
+    private boolean dontAsk;
+
+    private Button detailsButton;
+
+    boolean showDetails = false;
+
+    private Composite detailsComposite;
+
+    private Label detailsLabel;
+
+    private String selectedActivity;
+
+    private Text detailsText;
+
+	private Properties strings;
+
+    /**
+     * Create a new instance of the reciever.
+     *
+     * @param parentShell the parent shell
+     * @param activityIds the candidate activities
+     * @param strings string overrides
+     */
+    public EnablementDialog(Shell parentShell, Collection activityIds, Properties strings) {
+        super(parentShell);
+        this.activityIds = activityIds;
+		this.strings = strings;
+    }
+
+    @Override
+	protected Control createDialogArea(Composite parent) {
+        Composite composite = (Composite) super.createDialogArea(parent);
+        Font dialogFont = parent.getFont();
+        composite.setFont(dialogFont);
+        Label text = new Label(composite, SWT.NONE);
+        text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+        text.setFont(dialogFont);
+        IActivityManager manager = PlatformUI.getWorkbench()
+                .getActivitySupport().getActivityManager();
+
+        if (activityIds.size() == 1) {
+            String activityId = (String) activityIds.iterator().next();
+            activitiesToEnable.add(activityId);
+            selectedActivity = activityId;
+
+            IActivity activity = manager.getActivity(activityId);
+            String activityText;
+            try {
+                activityText = activity.getName();
+            } catch (NotDefinedException e) {
+                activityText = activity.getId();
+            }
+            text.setText(MessageFormat.format(RESOURCE_BUNDLE
+                    .getString("requiresSingle"), //$NON-NLS-1$
+					activityText));
+
+            text = new Label(composite, SWT.NONE);
+			text
+					.setText(strings
+							.getProperty(
+									WorkbenchTriggerPointAdvisor.PROCEED_SINGLE,
+									RESOURCE_BUNDLE
+											.getString(WorkbenchTriggerPointAdvisor.PROCEED_SINGLE)));
+            text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+            text.setFont(dialogFont);
+        } else {
+            text.setText(RESOURCE_BUNDLE.getString("requiresMulti")); //$NON-NLS-1$
+            Set activityIdsCopy = new HashSet(activityIds);
+            CheckboxTableViewer viewer = CheckboxTableViewer.newCheckList(
+					composite, SWT.CHECK | SWT.BORDER | SWT.SINGLE);
+            viewer.setContentProvider(new ActivityContentProvider());
+            viewer.setLabelProvider(new ActivityLabelProvider(manager));
+            viewer.setInput(activityIdsCopy);
+            viewer.setCheckedElements(activityIdsCopy.toArray());
+            viewer.addCheckStateListener(event -> {
+			    if (event.getChecked()) {
+					activitiesToEnable.add(event.getElement());
+				} else {
+					activitiesToEnable.remove(event.getElement());
+				}
+
+			    getButton(Window.OK).setEnabled(
+			            !activitiesToEnable.isEmpty());
+			});
+            viewer.addSelectionChangedListener(event -> {
+			    selectedActivity = (String) ((IStructuredSelection) event
+			            .getSelection()).getFirstElement();
+			    setDetails();
+			});
+            activitiesToEnable.addAll(activityIdsCopy);
+
+            viewer.getControl().setLayoutData(
+                    new GridData(GridData.FILL_HORIZONTAL));
+            viewer.getControl().setFont(dialogFont);
+
+            text = new Label(composite, SWT.NONE);
+            text.setText(strings.getProperty(WorkbenchTriggerPointAdvisor.PROCEED_MULTI, RESOURCE_BUNDLE
+					.getString(WorkbenchTriggerPointAdvisor.PROCEED_MULTI)));
+            text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+            text.setFont(dialogFont);
+        }
+        Label seperator = new Label(composite, SWT.SEPARATOR | SWT.HORIZONTAL);
+        seperator.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+        dontAskButton = new Button(composite, SWT.CHECK);
+        dontAskButton.setSelection(false);
+        dontAskButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+        dontAskButton.setText(strings.getProperty(
+				WorkbenchTriggerPointAdvisor.DONT_ASK, RESOURCE_BUNDLE
+						.getString(WorkbenchTriggerPointAdvisor.DONT_ASK)));
+        dontAskButton.setFont(dialogFont);
+
+        detailsComposite = new Composite(composite, SWT.NONE);
+        GridLayout layout = new GridLayout();
+        layout.marginHeight = 0;
+        layout.marginWidth = 0;
+        detailsComposite.setLayout(layout);
+        detailsLabel = new Label(detailsComposite, SWT.NONE);
+        detailsLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+        detailsLabel.setFont(dialogFont);
+
+        detailsText = new Text(detailsComposite, SWT.WRAP | SWT.V_SCROLL
+                | SWT.BORDER | SWT.READ_ONLY);
+        detailsText.setLayoutData(new GridData(GridData.FILL_BOTH));
+        detailsText.setFont(dialogFont);
+
+        setDetails();
+
+        GridData data = new GridData(GridData.FILL_BOTH);
+        detailsComposite.setLayoutData(data);
+        setDetailHints();
+
+        return composite;
+    }
+
+    /**
+     * Set the text of the detail label and text area.
+     */
+    protected void setDetails() {
+        if (selectedActivity == null) {
+            detailsLabel
+					.setText(strings
+							.getProperty(
+									WorkbenchTriggerPointAdvisor.NO_DETAILS,
+									RESOURCE_BUNDLE
+											.getString(WorkbenchTriggerPointAdvisor.NO_DETAILS)));
+            detailsText.setText(""); //$NON-NLS-1$
+        } else {
+            IActivity activity = PlatformUI.getWorkbench().getActivitySupport()
+                    .getActivityManager().getActivity(selectedActivity);
+            String name;
+            try {
+                name = activity.getName();
+            } catch (NotDefinedException e1) {
+                name = selectedActivity;
+            }
+            String desc;
+            try {
+                desc = activity.getDescription();
+            } catch (NotDefinedException e) {
+                desc = RESOURCE_BUNDLE.getString("noDescAvailable"); //$NON-NLS-1$
+            }
+            detailsLabel.setText(MessageFormat.format(RESOURCE_BUNDLE
+					.getString("detailsLabel"), name)); //$NON-NLS-1$
+            detailsText.setText(desc);
+        }
+    }
+
+    /**
+     *
+     */
+    protected void setDetailHints() {
+        GridData data = (GridData) detailsComposite.getLayoutData();
+        if (showDetails) {
+            Composite parent = detailsComposite.getParent();
+            data.widthHint = parent.getSize().x - ((GridLayout)parent.getLayout()).marginWidth * 2;
+            data.heightHint = convertHeightInCharsToPixels(5);
+        } else {
+            data.widthHint = 0;
+            data.heightHint = 0;
+        }
+    }
+
+    /**
+     * Set the label of the detail button based on whether we're currently showing the description text.
+     */
+    private void setDetailButtonLabel() {
+        if (!showDetails) {
+			detailsButton.setText(RESOURCE_BUNDLE.getString("showDetails")); //$NON-NLS-1$
+		} else {
+			detailsButton.setText(RESOURCE_BUNDLE.getString("hideDetails")); //$NON-NLS-1$
+		}
+    }
+
+    @Override
+	protected void configureShell(Shell newShell) {
+        super.configureShell(newShell);
+        newShell.setText(RESOURCE_BUNDLE.getString("title")); //$NON-NLS-1$
+    }
+
+    /**
+     * @return Returns whether the user has declared that there is to be no further
+     * prompting for the supplied activities
+     */
+    public boolean getDontAsk() {
+        return dontAsk;
+    }
+
+    /**
+     * @return Returns the activities to enable
+     */
+    public Set getActivitiesToEnable() {
+        return activitiesToEnable;
+    }
+
+    @Override
+	protected void okPressed() {
+        dontAsk = dontAskButton.getSelection();
+        super.okPressed();
+    }
+
+    @Override
+	protected void createButtonsForButtonBar(Composite parent) {
+        super.createButtonsForButtonBar(parent);
+        detailsButton = createButton(parent, IDialogConstants.DETAILS_ID,
+                "", false); //$NON-NLS-1$
+        setDetailButtonLabel();
+    }
+
+    @Override
+	protected void buttonPressed(int buttonId) {
+        if (buttonId == IDialogConstants.DETAILS_ID) {
+            detailsPressed();
+            return;
+        }
+        super.buttonPressed(buttonId);
+    }
+
+    /**
+     * Handles selection of the Details button.
+     */
+    private void detailsPressed() {
+        showDetails = !showDetails;
+        setDetailButtonLabel();
+        setDetailHints();
+        setDetails();
+        ((Composite) getDialogArea()).layout(true);
+        getShell().setSize(getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT));
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/EnablementDialog.properties b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/EnablementDialog.properties
new file mode 100644
index 0000000..b94c6a0
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/EnablementDialog.properties
@@ -0,0 +1,22 @@
+###############################################################################
+# Copyright (c) 2004, 2005 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
+###############################################################################
+
+title=Confirm Enablement
+proceedMulti=Enable the selected activities?
+proceedSingle=Enable the required activity?
+requiresSingle=This action requires the enablement of "{0}".
+requiresMulti=This action requires the enablement of at least one of the following:\n
+dontAsk=&Always enable activities and don't ask me again
+noDescAvailable=No description available.
+noDetails=Select an activity to view its description.
+detailsLabel=D&escription of \"{0}\":
+showDetails=&Details >>
+hideDetails=<< &Details
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/ImageBindingRegistry.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/ImageBindingRegistry.java
new file mode 100644
index 0000000..de882a9
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/ImageBindingRegistry.java
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.activities.ws;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.activities.Persistence;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+/**
+ * @since 3.1
+ */
+public class ImageBindingRegistry implements IExtensionChangeHandler {
+	private String tag;
+	private ImageRegistry registry = new ImageRegistry();
+
+	/**
+	 * @param tag
+	 *
+	 */
+	public ImageBindingRegistry(String tag) {
+		super();
+		this.tag = tag;
+		IExtension [] extensions = getExtensionPointFilter().getExtensions();
+		for (IExtension extension : extensions) {
+			addExtension(PlatformUI.getWorkbench().getExtensionTracker(), extension);
+		}
+	}
+
+	@Override
+	public void addExtension(IExtensionTracker tracker, IExtension extension) {
+		IConfigurationElement [] elements = extension.getConfigurationElements();
+		for (IConfigurationElement element : elements) {
+			if (element.getName().equals(tag)) {
+				String id = element.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+				String file = element.getAttribute(IWorkbenchRegistryConstants.ATT_ICON);
+				if (file == null || id == null) {
+					Persistence.log(element, Persistence.ACTIVITY_IMAGE_BINDING_DESC, "definition must contain icon and ID"); //$NON-NLS-1$
+					continue; //ignore - malformed
+				}
+				if (registry.getDescriptor(id) == null) { // first come, first serve
+					ImageDescriptor descriptor = AbstractUIPlugin.imageDescriptorFromPlugin(element.getNamespace(), file);
+					if (descriptor != null) {
+						registry.put(id, descriptor);
+						tracker.registerObject(extension, id, IExtensionTracker.REF_WEAK);
+					}
+				}
+			}
+		}
+
+	}
+
+    /**
+     * Return the activity support extension point that this registry is interested in.
+     *
+     * @return the extension point
+     */
+	public IExtensionPoint getExtensionPointFilter() {
+		return Platform.getExtensionRegistry().getExtensionPoint(
+                PlatformUI.PLUGIN_EXTENSION_NAME_SPACE, IWorkbenchRegistryConstants.PL_ACTIVITYSUPPORT);
+	}
+
+	@Override
+	public void removeExtension(IExtension extension, Object[] objects) {
+		for (Object object : objects) {
+			if (object instanceof String) {
+				registry.remove((String) object);
+			}
+		}
+	}
+
+	/**
+	 * Get the ImageDescriptor for the given id.
+	 *
+	 * @param id the id
+	 * @return the descriptor
+	 */
+	public ImageDescriptor getImageDescriptor(String id) {
+		return registry.getDescriptor(id);
+	}
+
+	/**
+	 * Dispose of this registry.
+	 */
+	void dispose() {
+		registry.dispose();
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/RegistryTriggerPoint.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/RegistryTriggerPoint.java
new file mode 100644
index 0000000..0384a37
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/RegistryTriggerPoint.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.activities.ws;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.ui.internal.activities.Persistence;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+
+/**
+ * @since 3.1
+ */
+public class RegistryTriggerPoint extends AbstractTriggerPoint {
+
+    private String id;
+
+    private IConfigurationElement element;
+
+    private Map hints;
+
+    /**
+     * Create a new instance of this class.
+     *
+     * @param id the id of the trigger point
+     * @param element the defining configuration element
+     */
+    public RegistryTriggerPoint(String id, IConfigurationElement element) {
+        this.id = id;
+        this.element = element;
+    }
+
+    @Override
+	public String getId() {
+        return id;
+    }
+
+    @Override
+	public String getStringHint(String key) {
+        return (String) getHints().get(key);
+    }
+
+    @Override
+	public boolean getBooleanHint(String key) {
+        return Boolean.valueOf(getStringHint(key)).booleanValue();
+    }
+
+    /**
+     * Lazily create the hints.
+     *
+     * @return the hint map
+     */
+    private Map getHints() {
+        if (hints == null) {
+            hints = new HashMap();
+
+            IConfigurationElement[] hintElements = element
+                    .getChildren(IWorkbenchRegistryConstants.TAG_HINT);
+            for (IConfigurationElement hintElement : hintElements) {
+                String id = hintElement
+                        .getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+                String value = hintElement
+                        .getAttribute(IWorkbenchRegistryConstants.ATT_VALUE);
+
+                if (id == null || value == null) {
+					Persistence.log(element, Persistence.ACTIVITY_TRIGGER_HINT_DESC, "hint must contain ID and value"); //$NON-NLS-1$
+					continue;
+				}
+				hints.put(id, value);
+            }
+        }
+
+        return hints;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/TriggerPointAdvisorDescriptor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/TriggerPointAdvisorDescriptor.java
new file mode 100644
index 0000000..ceacb76
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/TriggerPointAdvisorDescriptor.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.activities.ws;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.ui.activities.ITriggerPointAdvisor;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.registry.RegistryReader;
+
+/**
+ * Descriptor for trigger point advisor extensions.
+ *
+ * @since 3.1
+ */
+public final class TriggerPointAdvisorDescriptor {
+
+	private String id;
+
+	private IConfigurationElement element;
+
+	/**
+	 * Create a new instance of this class.
+	 *
+	 * @param element
+	 *            the configuration element
+	 * @throws IllegalArgumentException
+	 *             thrown if the element is missing an id attribute
+	 */
+	public TriggerPointAdvisorDescriptor(IConfigurationElement element)
+			throws IllegalArgumentException {
+		id = element.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+		if (id == null
+				|| RegistryReader.getClassValue(element,
+						IWorkbenchRegistryConstants.ATT_CLASS) == null) {
+			throw new IllegalArgumentException();
+		}
+		this.element = element;
+	}
+
+	/**
+	 * Return the id.
+	 *
+	 * @return the id
+	 */
+	public String getId() {
+		return id;
+	}
+
+	/**
+	 * Create the advisor for this descriptor.
+	 *
+	 * @return the advisor
+	 * @throws CoreException
+	 *             thrown if there is an issue creating the advisor
+	 */
+	public ITriggerPointAdvisor createAdvisor() throws CoreException {
+		return (ITriggerPointAdvisor) element
+				.createExecutableExtension(IWorkbenchRegistryConstants.ATT_CLASS);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/TriggerPointAdvisorRegistry.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/TriggerPointAdvisorRegistry.java
new file mode 100644
index 0000000..67d95ff
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/TriggerPointAdvisorRegistry.java
@@ -0,0 +1,167 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.activities.ws;
+
+import java.util.ArrayList;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.registry.RegistryReader;
+
+/**
+ * @since 3.1
+ */
+public class TriggerPointAdvisorRegistry {
+
+	private static TriggerPointAdvisorRegistry instance;
+
+	/**
+	 *
+	 */
+	private TriggerPointAdvisorRegistry() {
+	}
+
+	/**
+	 * Return the instance of this registry.
+	 *
+	 * @return the instance of this registry
+	 */
+	public static TriggerPointAdvisorRegistry getInstance() {
+		if (instance == null) {
+			instance = new TriggerPointAdvisorRegistry();
+		}
+
+		return instance;
+	}
+
+	/**
+	 * Return the trigger point advisors.
+	 *
+	 * @return the advisors
+	 */
+	public TriggerPointAdvisorDescriptor[] getAdvisors() {
+		IExtensionPoint point = Platform.getExtensionRegistry()
+				.getExtensionPoint(PlatformUI.PLUGIN_EXTENSION_NAME_SPACE,
+						IWorkbenchRegistryConstants.PL_ACTIVITYSUPPORT);
+		if (point == null) {
+			return new TriggerPointAdvisorDescriptor[0];
+		}
+
+		IExtension[] extensions = point.getExtensions();
+		extensions = RegistryReader.orderExtensions(extensions);
+
+		ArrayList list = new ArrayList(extensions.length);
+		for (IExtension extension : extensions) {
+			IConfigurationElement[] elements = extension
+					.getConfigurationElements();
+			for (IConfigurationElement element : elements) {
+				if (element.getName().equals(
+						IWorkbenchRegistryConstants.TAG_TRIGGERPOINTADVISOR)) {
+					try {
+						TriggerPointAdvisorDescriptor descriptor = new TriggerPointAdvisorDescriptor(
+								element);
+						list.add(descriptor);
+					} catch (IllegalArgumentException e) {
+						// log an error since its not safe to open a dialog here
+						WorkbenchPlugin.log(
+								"invalid trigger point advisor extension", //$NON-NLS-1$
+								StatusUtil.newStatus(IStatus.ERROR, e
+										.getMessage(), e));
+					}
+				}
+			}
+		}
+
+		return (TriggerPointAdvisorDescriptor[]) list
+				.toArray(new TriggerPointAdvisorDescriptor[list.size()]);
+	}
+
+	/**
+	 * Return the trigger point advisor bound to a given product.
+	 *
+	 * @param productId
+	 *            the product id
+	 * @return the advisor
+	 */
+	public TriggerPointAdvisorDescriptor getAdvisorForProduct(String productId) {
+		IExtensionPoint point = Platform.getExtensionRegistry()
+				.getExtensionPoint(PlatformUI.PLUGIN_EXTENSION_NAME_SPACE,
+						IWorkbenchRegistryConstants.PL_ACTIVITYSUPPORT);
+		if (point == null) {
+			return null;
+		}
+
+		IExtension[] extensions = point.getExtensions();
+		extensions = RegistryReader.orderExtensions(extensions);
+
+		String targetIntroId = getAdvisorForProduct(productId, extensions);
+		if (targetIntroId == null) {
+			return null;
+		}
+
+		TriggerPointAdvisorDescriptor[] advisors = getAdvisors();
+		for (TriggerPointAdvisorDescriptor advisor : advisors) {
+			if (advisor.getId().equals(targetIntroId)) {
+				return advisor;
+			}
+		}
+
+		return null;
+	}
+
+	/**
+	 * @param targetProductId
+	 * @param extensions
+	 * @return the advisor id
+	 */
+	private String getAdvisorForProduct(String targetProductId,
+			IExtension[] extensions) {
+		for (IExtension extension : extensions) {
+			IConfigurationElement[] elements = extension
+					.getConfigurationElements();
+			for (IConfigurationElement element : elements) {
+				if (element.getName().equals(
+						IWorkbenchRegistryConstants.TAG_ADVISORPRODUCTBINDING)) {
+					String advisorId = element
+							.getAttribute(IWorkbenchRegistryConstants.ATT_ADVISORID);
+					String productId = element
+							.getAttribute(IWorkbenchRegistryConstants.ATT_PRODUCTID);
+
+					if (advisorId == null || productId == null) {
+						IStatus status = new Status(
+								IStatus.ERROR,
+								element.getDeclaringExtension()
+										.getNamespace(),
+								IStatus.ERROR,
+								"triggerPointAdvisorId and productId must be defined.", new IllegalArgumentException()); //$NON-NLS-1$
+						WorkbenchPlugin
+								.log(
+										"Invalid trigger point advisor binding", status); //$NON-NLS-1$
+						continue;
+					}
+
+					if (targetProductId.equals(productId)) {
+						return advisorId;
+					}
+				}
+			}
+		}
+		return null;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/TriggerPointManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/TriggerPointManager.java
new file mode 100644
index 0000000..bad2cb1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/TriggerPointManager.java
@@ -0,0 +1,130 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.activities.ws;
+
+import java.util.HashMap;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.dynamichelpers.ExtensionTracker;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.activities.ITriggerPoint;
+import org.eclipse.ui.activities.ITriggerPointManager;
+import org.eclipse.ui.internal.activities.Persistence;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+
+/**
+ * Workbench implementation of the trigger point manager.
+ *
+ * @since 3.1
+ */
+public class TriggerPointManager implements ITriggerPointManager, IExtensionChangeHandler {
+
+    private HashMap triggerMap = new HashMap();
+
+    /**
+     *
+     */
+    public TriggerPointManager() {
+        super();
+        triggerMap.put(ITriggerPointManager.UNKNOWN_TRIGGER_POINT_ID,
+                new AbstractTriggerPoint() {
+
+                    @Override
+					public String getId() {
+                        return ITriggerPointManager.UNKNOWN_TRIGGER_POINT_ID;
+                    }
+
+                    @Override
+					public String getStringHint(String key) {
+                        if (ITriggerPoint.HINT_INTERACTIVE.equals(key)) {
+                            // TODO: change to false when we have mapped our
+                            // trigger points
+                            return Boolean.TRUE.toString();
+                        }
+                        return null;
+                    }
+
+                    @Override
+					public boolean getBooleanHint(String key) {
+                        if (ITriggerPoint.HINT_INTERACTIVE.equals(key)) {
+                            // TODO: change to false when we have mapped our
+                            // trigger points
+                            return true;
+                        }
+                        return false;
+                    }
+                });
+        IExtensionTracker tracker = PlatformUI.getWorkbench().getExtensionTracker();
+        tracker.registerHandler(this, ExtensionTracker.createExtensionPointFilter(getExtensionPointFilter()));
+
+        IExtensionPoint point = getExtensionPointFilter();
+        IExtension[] extensions = point.getExtensions();
+        for (IExtension extension : extensions) {
+            addExtension(tracker,
+                    extension);
+        }
+    }
+
+    @Override
+	public ITriggerPoint getTriggerPoint(String id) {
+        return (ITriggerPoint) triggerMap.get(id);
+    }
+
+    @Override
+	public Set getDefinedTriggerPointIds() {
+        return triggerMap.entrySet();
+    }
+
+    @Override
+	public void removeExtension(IExtension extension, Object[] objects) {
+        for (Object object : objects) {
+            if (object instanceof RegistryTriggerPoint) {
+                triggerMap.remove(((RegistryTriggerPoint) object).getId());
+            }
+        }
+    }
+
+    @Override
+	public void addExtension(IExtensionTracker tracker, IExtension extension) {
+        IConfigurationElement[] elements = extension.getConfigurationElements();
+        for (IConfigurationElement element : elements) {
+            if (element.getName().equals(
+                    IWorkbenchRegistryConstants.TAG_TRIGGERPOINT)) {
+                String id = element
+                        .getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+                if (id == null) {
+					Persistence.log(element, Persistence.ACTIVITY_TRIGGER_DESC, "missing a unique identifier"); //$NON-NLS-1$
+					continue;
+				}
+                RegistryTriggerPoint triggerPoint = new RegistryTriggerPoint(
+                        id, element);
+                triggerMap.put(id, triggerPoint);
+                tracker.registerObject(extension, triggerPoint,
+                        IExtensionTracker.REF_WEAK);
+            }
+        }
+    }
+
+    private IExtensionPoint getExtensionPointFilter() {
+     // RAP [bm]: 
+//        return Platform.getExtensionRegistry().getExtensionPoint(
+//                "org.eclipse.ui", IWorkbenchRegistryConstants.PL_ACTIVITYSUPPORT);
+        return Platform.getExtensionRegistry().getExtensionPoint(
+                PlatformUI.PLUGIN_EXTENSION_NAME_SPACE, IWorkbenchRegistryConstants.PL_ACTIVITYSUPPORT);
+        // RAPEND: [bm]
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/WorkbenchActivitySupport.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/WorkbenchActivitySupport.java
new file mode 100644
index 0000000..51b4b1c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/WorkbenchActivitySupport.java
@@ -0,0 +1,454 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.internal.activities.ws;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashSet;
+import java.util.Set;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IProduct;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.dynamichelpers.ExtensionTracker;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
+import org.eclipse.jface.action.IContributionManager;
+import org.eclipse.jface.dialogs.ProgressMonitorDialog;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IViewReference;
+import org.eclipse.ui.IViewSite;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.activities.ActivityManagerEvent;
+import org.eclipse.ui.activities.IActivity;
+import org.eclipse.ui.activities.IActivityManager;
+import org.eclipse.ui.activities.IActivityManagerListener;
+import org.eclipse.ui.activities.ICategory;
+import org.eclipse.ui.activities.IMutableActivityManager;
+import org.eclipse.ui.activities.ITriggerPointAdvisor;
+import org.eclipse.ui.activities.ITriggerPointManager;
+import org.eclipse.ui.activities.IWorkbenchActivitySupport;
+import org.eclipse.ui.activities.WorkbenchTriggerPointAdvisor;
+import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.WorkbenchWindow;
+import org.eclipse.ui.internal.activities.MutableActivityManager;
+import org.eclipse.ui.internal.activities.ProxyActivityManager;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+
+/**
+ * Implementation of {@link org.eclipse.ui.activities.IWorkbenchActivitySupport}.
+ * @since 3.0
+ */
+public class WorkbenchActivitySupport implements IWorkbenchActivitySupport, IExtensionChangeHandler {
+    private MutableActivityManager mutableActivityManager;
+
+    private ProxyActivityManager proxyActivityManager;
+
+	private ImageBindingRegistry activityImageBindingRegistry;
+
+	private ImageBindingRegistry categoryImageBindingRegistry;
+
+	private ITriggerPointManager triggerPointManager;
+
+	private ITriggerPointAdvisor advisor;
+
+	/**
+	 * Create a new instance of this class.
+	 */
+    public WorkbenchActivitySupport() {
+		triggerPointManager = new TriggerPointManager();
+		IExtensionTracker tracker = PlatformUI.getWorkbench().getExtensionTracker();
+        tracker.registerHandler(this, ExtensionTracker.createExtensionPointFilter(getActivitySupportExtensionPoint()));
+        mutableActivityManager = new MutableActivityManager(getTriggerPointAdvisor());
+        proxyActivityManager = new ProxyActivityManager(mutableActivityManager);
+        mutableActivityManager
+                .addActivityManagerListener(new IActivityManagerListener() {
+
+                    private Set lastEnabled = new HashSet(
+                            mutableActivityManager.getEnabledActivityIds());
+
+                    @Override
+					public void activityManagerChanged(
+                            ActivityManagerEvent activityManagerEvent) {
+                        Set activityIds = mutableActivityManager
+                                .getEnabledActivityIds();
+                        // only update the windows if we've not processed this new enablement state already.
+                        if (!activityIds.equals(lastEnabled)) {
+                            lastEnabled = new HashSet(activityIds);
+
+                            // abort if the workbench isn't running
+                            if (!PlatformUI.isWorkbenchRunning()) {
+								return;
+							}
+
+                            // refresh the managers on all windows.
+							final IWorkbench workbench = PlatformUI.getWorkbench();
+							IWorkbenchWindow[] windows = workbench.getWorkbenchWindows();
+                            for (IWorkbenchWindow wWindow : windows) {
+                                if (wWindow instanceof WorkbenchWindow) {
+                                    final WorkbenchWindow window = (WorkbenchWindow) wWindow;
+
+									final ProgressMonitorDialog dialog = new ProgressMonitorDialog(window.getShell());
+
+                                    final IRunnableWithProgress runnable = new IRunnableWithProgress() {
+
+                                        /**
+                                         * When this operation should open a dialog
+                                         */
+                                        private long openTime;
+
+                                        /**
+                                         * Whether the dialog has been opened yet.
+                                         */
+                                        private boolean dialogOpened = false;
+
+                                        @Override
+										public void run(IProgressMonitor monitor) {
+
+                                            openTime = System
+                                                    .currentTimeMillis()
+                                                    + workbench
+                                                            .getProgressService()
+                                                            .getLongOperationTime();
+
+                                            //two work units - updating the window bars, and updating view bars
+                                            monitor
+                                                    .beginTask(
+                                                            ActivityMessages.ManagerTask, 2);
+
+                                            monitor
+                                                    .subTask(ActivityMessages.ManagerWindowSubTask);
+
+                                            //update window managers...
+                                            updateWindowBars(window);
+                                            monitor.worked(1);
+
+                                            monitor
+                                                    .subTask(ActivityMessages.ManagerViewsSubTask);
+                                            // update all of the (realized) views in all of the pages
+                                            IWorkbenchPage[] pages = window
+                                                    .getPages();
+                                            for (IWorkbenchPage page : pages) {
+												IViewReference[] refs = page.getViewReferences();
+                                                for (IViewReference ref : refs) {
+													IViewPart part = ref.getView(false);
+                                                    if (part != null) {
+                                                        updateViewBars(part);
+                                                    }
+                                                }
+                                            }
+                                            monitor.worked(1);
+
+                                            monitor.done();
+                                        }
+
+                                        /**
+                                         * Update the managers on the given given view.
+                                         *
+                                         * @param part the view to update
+                                         */
+                                        private void updateViewBars(
+                                                IViewPart part) {
+                                            IViewSite viewSite = part
+                                                    .getViewSite();
+                                            // check for badly behaving or badly initialized views
+                                            if (viewSite == null) {
+												return;
+											}
+                                            IActionBars bars = viewSite
+                                                    .getActionBars();
+                                            IContributionManager manager = bars
+                                                    .getMenuManager();
+                                            if (manager != null) {
+												updateManager(manager);
+											}
+                                            manager = bars.getToolBarManager();
+                                            if (manager != null) {
+												updateManager(manager);
+											}
+                                            manager = bars
+                                                    .getStatusLineManager();
+                                            if (manager != null) {
+												updateManager(manager);
+											}
+                                        }
+
+                                        /**
+                                         * Update the managers on the given window.
+                                         *
+                                         * @param window the window to update
+                                         */
+                                        private void updateWindowBars(
+                                                final WorkbenchWindow window) {
+                                            IContributionManager manager = window
+                                                    .getMenuBarManager();
+                                            if (manager != null) {
+												updateManager(manager);
+											}
+                                            manager = window
+                                                    .getCoolBarManager2();
+                                            if (manager != null) {
+												updateManager(manager);
+											}
+                                            manager = window
+                                                    .getToolBarManager2();
+                                            if (manager != null) {
+												updateManager(manager);
+											}
+                                            manager = window
+                                                    .getStatusLineManager();
+                                            if (manager != null) {
+												updateManager(manager);
+											}
+                                        }
+
+                                        /**
+                                         * Update the given manager in the UI thread.
+                                         * This may also open the progress dialog if
+                                         * the operation is taking too long.
+                                         *
+                                         * @param manager the manager to update
+                                         */
+                                        private void updateManager(
+                                                final IContributionManager manager) {
+                                            if (!dialogOpened
+                                                    && System
+                                                            .currentTimeMillis() > openTime) {
+                                                dialog.open();
+                                                dialogOpened = true;
+                                            }
+
+                                            manager.update(true);
+                                        }
+                                    };
+
+                                    // don't open the dialog by default - that'll be
+                                    // handled by the runnable if we take too long
+                                    dialog.setOpenOnRun(false);
+                                    // run this in the UI thread
+                                    workbench.getDisplay().asyncExec(
+                                            () -> BusyIndicator
+											        .showWhile(
+											                workbench
+											                        .getDisplay(),
+											                () -> {
+															    try {
+															        dialog
+															                .run(
+															                        false,
+															                        false,
+															                        runnable);
+															    } catch (InvocationTargetException e1) {
+															        log(e1);
+															    } catch (InterruptedException e2) {
+															        log(e2);
+															    }
+															}));
+                                }
+                            }
+                        }
+                    }
+
+                    /**
+                     * Logs an error message to the workbench log.
+                     *
+                     * @param e the exception to log
+                     */
+                    private void log(Exception e) {
+                        StatusUtil.newStatus(IStatus.ERROR,
+                                "Could not update contribution managers", e); //$NON-NLS-1$
+                    }
+                });
+    }
+
+    @Override
+	public IActivityManager getActivityManager() {
+        return proxyActivityManager;
+    }
+
+    @Override
+	public void setEnabledActivityIds(Set enabledActivityIds) {
+        mutableActivityManager.setEnabledActivityIds(enabledActivityIds);
+    }
+
+	@Override
+	public ImageDescriptor getImageDescriptor(IActivity activity) {
+		if (activity.isDefined()) {
+			ImageDescriptor descriptor = getActivityImageBindingRegistry()
+					.getImageDescriptor(activity.getId());
+			if (descriptor != null) {
+				return descriptor;
+			}
+		}
+		return WorkbenchImages
+				.getImageDescriptor(IWorkbenchGraphicConstants.IMG_OBJ_ACTIVITY);
+	}
+
+	@Override
+	public ImageDescriptor getImageDescriptor(ICategory category) {
+		if (category.isDefined()) {
+			ImageDescriptor descriptor = getCategoryImageBindingRegistry()
+					.getImageDescriptor(category.getId());
+			if (descriptor != null) {
+				return descriptor;
+			}
+		}
+		return WorkbenchImages
+				.getImageDescriptor(IWorkbenchGraphicConstants.IMG_OBJ_ACTIVITY_CATEGORY);
+	}
+
+
+	/**
+	 * Return the activity image registry.
+	 *
+	 * @return the activity image registry
+	 * @since 3.1
+	 */
+	private ImageBindingRegistry getActivityImageBindingRegistry() {
+		if (activityImageBindingRegistry == null) {
+			activityImageBindingRegistry = new ImageBindingRegistry(IWorkbenchRegistryConstants.TAG_ACTIVITY_IMAGE_BINDING);
+			PlatformUI
+					.getWorkbench()
+					.getExtensionTracker()
+					.registerHandler(
+							activityImageBindingRegistry,
+							ExtensionTracker
+									.createExtensionPointFilter(getActivitySupportExtensionPoint()));
+		}
+		return activityImageBindingRegistry;
+	}
+
+	/**
+	 * Return the category image registry.
+	 *
+	 * @return the category image registry
+	 * @since 3.1
+	 */
+	private ImageBindingRegistry getCategoryImageBindingRegistry() {
+		if (categoryImageBindingRegistry == null) {
+			categoryImageBindingRegistry = new ImageBindingRegistry(IWorkbenchRegistryConstants.TAG_CATEGORY_IMAGE_BINDING);
+			PlatformUI
+			.getWorkbench()
+			.getExtensionTracker()
+			.registerHandler(
+					categoryImageBindingRegistry,
+					ExtensionTracker
+							.createExtensionPointFilter(getActivitySupportExtensionPoint()));
+		}
+		return categoryImageBindingRegistry;
+	}
+
+	/**
+	 * Dispose of the image registries.
+	 *
+	 * @since 3.1
+	 */
+	public void dispose() {
+		if (activityImageBindingRegistry != null) {
+			activityImageBindingRegistry.dispose();
+			PlatformUI.getWorkbench().getExtensionTracker().unregisterHandler(activityImageBindingRegistry);
+		}
+		if (categoryImageBindingRegistry != null) {
+			categoryImageBindingRegistry.dispose();
+			PlatformUI.getWorkbench().getExtensionTracker().unregisterHandler(categoryImageBindingRegistry);
+		}
+
+		PlatformUI.getWorkbench().getExtensionTracker().unregisterHandler(this);
+	}
+
+	/**
+	 * Return the trigger point advisor.
+	 *
+	 * TODO: should this be part of the interface?
+	 *
+	 * @return the trigger point advisor
+	 * @since 3.1
+	 */
+	public ITriggerPointAdvisor getTriggerPointAdvisor() {
+		if (advisor != null) {
+			return advisor;
+		}
+
+		IProduct product = Platform.getProduct();
+        if (product != null) {
+			TriggerPointAdvisorDescriptor descriptor = TriggerPointAdvisorRegistry
+					.getInstance().getAdvisorForProduct(product.getId());
+			if (descriptor != null) {
+				try {
+					advisor = descriptor.createAdvisor();
+				} catch (CoreException e) {
+					WorkbenchPlugin.log("could not create trigger point advisor", e); //$NON-NLS-1$
+				}
+			}
+        }
+
+		if (advisor == null) {
+			advisor = new WorkbenchTriggerPointAdvisor();
+		}
+
+		return advisor;
+	}
+
+	@Override
+	public ITriggerPointManager getTriggerPointManager() {
+		return triggerPointManager;
+	}
+
+	@Override
+	public void addExtension(IExtensionTracker tracker, IExtension extension) {
+		// reset the advisor if it's the "default" advisor.
+		// this will give getAdvisor the chance to find a proper trigger/binding if
+		// it exists.
+		if (advisor != null && advisor.getClass().equals(WorkbenchTriggerPointAdvisor.class)) {
+			advisor = null;
+		}
+	}
+
+    /**
+     * Return the activity support extension point.
+     *
+     * @return the activity support extension point.
+     * @since 3.1
+     */
+	private IExtensionPoint getActivitySupportExtensionPoint() {
+		return Platform.getExtensionRegistry().getExtensionPoint(
+				PlatformUI.PLUGIN_EXTENSION_NAME_SPACE, IWorkbenchRegistryConstants.PL_ACTIVITYSUPPORT);
+	}
+
+	@Override
+	public void removeExtension(IExtension extension, Object[] objects) {
+		for (Object object : objects) {
+			if (object == advisor) {
+				advisor = null;
+				break;
+			}
+		}
+	}
+
+    @Override
+	public IMutableActivityManager createWorkingCopy() {
+        MutableActivityManager clone = (MutableActivityManager) mutableActivityManager.clone();
+        clone.unhookRegistryListeners();
+        return clone;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/WorkbenchTriggerPoints.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/WorkbenchTriggerPoints.java
new file mode 100644
index 0000000..6c76e5f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/WorkbenchTriggerPoints.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.activities.ws;
+
+/**
+ * @since 3.1
+ */
+public interface WorkbenchTriggerPoints {
+
+    /**
+     * New wizard trigger point identifier.  Value <code>org.eclipse.ui.newWizards</code>.
+     */
+    public static final String NEW_WIZARDS = "org.eclipse.ui.newWizards"; //$NON-NLS-1$
+
+    /**
+     * Perspective opening trigger point identifier.  Value <code>org.eclipse.ui.openPerspectiveDialog</code>.
+     */
+    public static final String OPEN_PERSPECITVE_DIALOG = "org.eclipse.ui.openPerspectiveDialog"; //$NON-NLS-1$
+
+    /**
+     * Import wizards trigger point identifier.  Value <code>org.eclipse.ui.importWizards</code>.
+     */
+    public static final String IMPORT_WIZARDS = "org.eclipse.ui.importWizards"; //$NON-NLS-1$
+
+    /**
+     * Export wizards trigger point identifier.  Value <code>org.eclipse.ui.exportWizards</code>.
+     */
+    public static final String EXPORT_WIZARDS = "org.eclipse.ui.exportWizards"; //$NON-NLS-1$
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/messages.properties b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/messages.properties
new file mode 100644
index 0000000..0f1d03d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/activities/ws/messages.properties
@@ -0,0 +1,29 @@
+###############################################################################
+# Copyright (c) 2004, 2015 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
+###############################################################################
+
+ActivityEnabler_description=Descriptio&n:
+ActivityEnabler_activities=&Activities:
+ActivityEnabler_categories=&Categories:
+ActivityEnabler_selectAll=&Enable All
+ActivityEnabler_deselectAll=D&isable All
+ActivitiesPreferencePage_advancedDialogTitle=Advanced {0} Settings
+ActivitiesPreferencePage_advancedButton=Ad&vanced...
+ActivitiesPreferencePage_lockedMessage={0} (locked)
+ActivitiesPreferencePage_captionMessage=Activities allow you to enable or disable various product components.  These activities are grouped according to a set of predefined categories.
+ActivitiesPreferencePage_requirements=Re&quires:
+ManagerTask = Updating windows
+ManagerWindowSubTask = Updating window contributions
+ManagerViewsSubTask = Updating view contributions
+Perspective_showAll=&Show all
+activityPromptButton = &Prompt when enabling activities
+activityPromptToolTip = Prompt when a feature is first used that requires enablement of activities
+
+
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/application/CompatibilityActionBarAdvisor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/application/CompatibilityActionBarAdvisor.java
new file mode 100644
index 0000000..307c9ec
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/application/CompatibilityActionBarAdvisor.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.application;
+
+import org.eclipse.ui.application.ActionBarAdvisor;
+import org.eclipse.ui.application.IActionBarConfigurer;
+import org.eclipse.ui.application.WorkbenchAdvisor;
+
+/**
+ * An implementation of <code>ActionBarAdvisor</code> that
+ * calls back to the 3.0 legacy methods on <code>WorkbenchAdvisor</code>
+ * for backwards compatibility.
+ *
+ * @since 3.1
+ */
+public class CompatibilityActionBarAdvisor extends ActionBarAdvisor {
+
+    private WorkbenchAdvisor wbAdvisor;
+
+    /**
+     * Creates a new compatibility action bar advisor.
+     *
+     * @param wbAdvisor the workbench advisor
+     * @param configurer the action bar configurer
+     */
+    public CompatibilityActionBarAdvisor(WorkbenchAdvisor wbAdvisor, IActionBarConfigurer configurer) {
+        super(configurer);
+        this.wbAdvisor = wbAdvisor;
+    }
+
+    @Override
+	public void fillActionBars(int flags) {
+        IActionBarConfigurer abc = getActionBarConfigurer();
+        wbAdvisor.fillActionBars(abc.getWindowConfigurer().getWindow(), abc, flags);
+    }
+
+    @Override
+	public boolean isApplicationMenu(String menuId) {
+        IActionBarConfigurer abc = getActionBarConfigurer();
+        return wbAdvisor.isApplicationMenu(abc.getWindowConfigurer(), menuId);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/application/CompatibilityWorkbenchWindowAdvisor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/application/CompatibilityWorkbenchWindowAdvisor.java
new file mode 100644
index 0000000..88ecd68
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/application/CompatibilityWorkbenchWindowAdvisor.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.application;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.WorkbenchException;
+import org.eclipse.ui.application.ActionBarAdvisor;
+import org.eclipse.ui.application.IActionBarConfigurer;
+import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
+import org.eclipse.ui.application.WorkbenchAdvisor;
+import org.eclipse.ui.application.WorkbenchWindowAdvisor;
+
+/**
+ * An implementation of <code>WorkbenchWindowAdvisor</code> that
+ * calls back to the 3.0 legacy methods on <code>WorkbenchAdvisor</code>
+ * for backwards compatibility.
+ *
+ * @since 3.1
+ */
+public class CompatibilityWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor {
+
+    private WorkbenchAdvisor wbAdvisor;
+
+    /**
+     * Creates a new compatibility workbench window advisor.
+     *
+     * @param wbAdvisor the workbench advisor
+     * @param windowConfigurer the window configurer
+     */
+    public CompatibilityWorkbenchWindowAdvisor(WorkbenchAdvisor wbAdvisor, IWorkbenchWindowConfigurer windowConfigurer) {
+        super(windowConfigurer);
+        this.wbAdvisor = wbAdvisor;
+    }
+
+    @Override
+	public void preWindowOpen() {
+        wbAdvisor.preWindowOpen(getWindowConfigurer());
+    }
+
+    @Override
+	public ActionBarAdvisor createActionBarAdvisor(IActionBarConfigurer configurer) {
+        return new CompatibilityActionBarAdvisor(wbAdvisor, configurer);
+    }
+
+    @Override
+	public void postWindowRestore() throws WorkbenchException {
+        wbAdvisor.postWindowRestore(getWindowConfigurer());
+    }
+
+    @Override
+	public void openIntro() {
+        wbAdvisor.openIntro(getWindowConfigurer());
+    }
+
+    @Override
+	public void postWindowCreate() {
+        wbAdvisor.postWindowCreate(getWindowConfigurer());
+    }
+
+    @Override
+	public void postWindowOpen() {
+        wbAdvisor.postWindowOpen(getWindowConfigurer());
+    }
+
+    @Override
+	public boolean preWindowShellClose() {
+        return wbAdvisor.preWindowShellClose(getWindowConfigurer());
+    }
+
+    @Override
+	public void postWindowClose() {
+        wbAdvisor.postWindowClose(getWindowConfigurer());
+    }
+
+    public boolean isApplicationMenu(String menuId) {
+        return wbAdvisor.isApplicationMenu(getWindowConfigurer(), menuId);
+    }
+
+    public IAdaptable getDefaultPageInput() {
+        return wbAdvisor.getDefaultPageInput();
+    }
+
+    @Override
+	public void createWindowContents(Shell shell) {
+        wbAdvisor.createWindowContents(getWindowConfigurer(), shell);
+    }
+
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/browser/DefaultWebBrowser.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/browser/DefaultWebBrowser.java
new file mode 100644
index 0000000..50e0ef1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/browser/DefaultWebBrowser.java
@@ -0,0 +1,185 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.browser;
+
+import java.io.IOException;
+import java.net.URL;
+
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.util.Util;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.browser.AbstractWebBrowser;
+import org.eclipse.ui.internal.WorkbenchMessages;
+
+/**
+ * The default implementation of the web browser instance.
+ * <p>
+ * This class is used when no alternative implementation is plugged in via the
+ * 'org.eclipse.ui.browserSupport' extension point.
+ * </p>
+ *
+ * @since 3.1
+ */
+public class DefaultWebBrowser extends AbstractWebBrowser {
+	private DefaultWorkbenchBrowserSupport support;
+
+	private String webBrowser;
+
+	private boolean webBrowserOpened;
+
+	/**
+	 * Creates the browser instance.
+	 *
+	 * @param support
+	 * @param id
+	 */
+	public DefaultWebBrowser(DefaultWorkbenchBrowserSupport support, String id) {
+		super(id);
+		this.support = support;
+	}
+
+	@Override
+	public void openURL(URL url) throws PartInitException {
+		// format the href for an html file (file:///<filename.html>
+		// required for Mac only.
+		String href = url.toString();
+		if (href.startsWith("file:")) { //$NON-NLS-1$
+			href = href.substring(5);
+			while (href.startsWith("/")) { //$NON-NLS-1$
+				href = href.substring(1);
+			}
+			href = "file:///" + href; //$NON-NLS-1$
+		}
+		final String localHref = href;
+
+		final Display d = Display.getCurrent();
+
+		// RAP
+//		if (Util.isWindows()) {
+//			Program.launch(localHref);
+//		} else 
+			if (Util.isMac()) {
+			try {
+				Runtime.getRuntime().exec("/usr/bin/open " + localHref); //$NON-NLS-1$
+			} catch (IOException e) {
+				throw new PartInitException(
+						WorkbenchMessages.get().ProductInfoDialog_unableToOpenWebBrowser,
+						e);
+			}
+		} else {
+			Thread launcher = new Thread("About Link Launcher") {//$NON-NLS-1$
+				@Override
+				public void run() {
+					try {
+						/*
+						 * encoding the href as the browser does not open if
+						 * there is a space in the url. Bug 77840
+						 */
+						String encodedLocalHref = urlEncodeForSpaces(localHref
+								.toCharArray());
+						if (webBrowserOpened) {
+							Runtime
+									.getRuntime()
+									.exec(
+											webBrowser
+													+ " -remote openURL(" + encodedLocalHref + ")"); //$NON-NLS-1$ //$NON-NLS-2$
+						} else {
+							Process p = openWebBrowser(encodedLocalHref);
+							webBrowserOpened = true;
+							try {
+								if (p != null) {
+									p.waitFor();
+								}
+							} catch (InterruptedException e) {
+								openWebBrowserError(d);
+							} finally {
+								webBrowserOpened = false;
+							}
+						}
+					} catch (IOException e) {
+						openWebBrowserError(d);
+					}
+				}
+			};
+			launcher.start();
+		}
+	}
+
+	@Override
+	public boolean close() {
+		support.unregisterBrowser(this);
+		return super.close();
+	}
+
+	/**
+	 * This method encodes the url, removes the spaces from the url and replaces
+	 * the same with <code>"%20"</code>. This method is required to fix Bug
+	 * 77840.
+	 *
+	 */
+	private String urlEncodeForSpaces(char[] input) {
+		StringBuffer retu = new StringBuffer(input.length);
+		for (char element : input) {
+			if (element == ' ') {
+				retu.append("%20"); //$NON-NLS-1$
+			} else {
+				retu.append(element);
+			}
+		}
+		return retu.toString();
+	}
+
+	// TODO: Move browser support from Help system, remove this method
+	private Process openWebBrowser(String href) throws IOException {
+		Process p = null;
+		if (webBrowser == null) {
+			try {
+				webBrowser = "firefox"; //$NON-NLS-1$
+				p = Runtime.getRuntime().exec(webBrowser + "  " + href); //$NON-NLS-1$;
+			} catch (IOException e) {
+				p = null;
+				webBrowser = "mozilla"; //$NON-NLS-1$
+			}
+		}
+
+		if (p == null) {
+			try {
+				p = Runtime.getRuntime().exec(webBrowser + " " + href); //$NON-NLS-1$;
+			} catch (IOException e) {
+				p = null;
+				webBrowser = "netscape"; //$NON-NLS-1$
+			}
+		}
+
+		if (p == null) {
+			try {
+				p = Runtime.getRuntime().exec(webBrowser + " " + href); //$NON-NLS-1$;
+			} catch (IOException e) {
+				p = null;
+				throw e;
+			}
+		}
+
+		return p;
+	}
+
+	/**
+	 * display an error message
+	 */
+	private void openWebBrowserError(Display display) {
+		display.asyncExec(() -> MessageDialog
+				.openError(
+						null,
+						WorkbenchMessages.get().ProductInfoDialog_errorTitle,
+						WorkbenchMessages.get().ProductInfoDialog_unableToOpenWebBrowser));
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/browser/DefaultWorkbenchBrowserSupport.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/browser/DefaultWorkbenchBrowserSupport.java
new file mode 100644
index 0000000..e80b4a6
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/browser/DefaultWorkbenchBrowserSupport.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.browser;
+
+import java.util.Hashtable;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.browser.AbstractWorkbenchBrowserSupport;
+import org.eclipse.ui.browser.IWebBrowser;
+
+/**
+ * Extends the abstract browser support class by providing minimal support for
+ * external browsers.
+ * <p>
+ * This class is used when no alternative implementation is plugged in via the
+ * 'org.eclipse.ui.browserSupport' extension point.
+ * </p>
+ *
+ * @since 3.1
+ */
+public class DefaultWorkbenchBrowserSupport extends
+		AbstractWorkbenchBrowserSupport {
+	private Hashtable browsers;
+	private static final String DEFAULT_BROWSER_ID_BASE = "org.eclipse.ui.defaultBrowser"; //$NON-NLS-1$
+
+	/**
+	 * The default constructor.
+	 */
+	public DefaultWorkbenchBrowserSupport() {
+		browsers = new Hashtable();
+	}
+
+	void registerBrowser(IWebBrowser browser) {
+		browsers.put(browser.getId(), browser);
+	}
+
+	void unregisterBrowser(IWebBrowser browser) {
+		browsers.remove(browser.getId());
+	}
+
+	IWebBrowser findBrowser(String id) {
+		return (IWebBrowser) browsers.get(id);
+	}
+
+	protected IWebBrowser doCreateBrowser(int style, String browserId,
+			String name, String tooltip) throws PartInitException {
+		return new DefaultWebBrowser(this, browserId);
+	}
+
+	@Override
+	public IWebBrowser createBrowser(int style, String browserId, String name,
+			String tooltip) throws PartInitException {
+		IWebBrowser browser = findBrowser(browserId == null? getDefaultId():browserId);
+		if (browser != null) {
+			return browser;
+		}
+		browser = doCreateBrowser(style, browserId, name, tooltip);
+		registerBrowser(browser);
+		return browser;
+	}
+
+	@Override
+	public IWebBrowser createBrowser(String browserId) throws PartInitException {
+		return createBrowser(AS_EXTERNAL, browserId, null, null);
+	}
+
+	private String getDefaultId() {
+		String id = null;
+		for (int i = 0; i < Integer.MAX_VALUE; i++) {
+			id = DEFAULT_BROWSER_ID_BASE + i;
+			if (browsers.get(id) == null)
+				break;
+		}
+		return id;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/browser/WorkbenchBrowserSupport.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/browser/WorkbenchBrowserSupport.java
new file mode 100644
index 0000000..1817182
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/browser/WorkbenchBrowserSupport.java
@@ -0,0 +1,240 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.browser;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.dynamichelpers.ExtensionTracker;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.browser.AbstractWorkbenchBrowserSupport;
+import org.eclipse.ui.browser.IWebBrowser;
+import org.eclipse.ui.browser.IWorkbenchBrowserSupport;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+
+/**
+ * Implements the support interface and delegates the calls to the active
+ * support if contributed via the extension point, or the default support
+ * otherwise.
+ *
+ * @since 3.1
+ */
+public class WorkbenchBrowserSupport extends AbstractWorkbenchBrowserSupport {
+
+	private static WorkbenchBrowserSupport instance;
+
+	private IWorkbenchBrowserSupport activeSupport;
+
+	private boolean initialized;
+
+    private String desiredBrowserSupportId;
+
+	private IExtensionChangeHandler handler = new IExtensionChangeHandler() {
+
+        @Override
+		public void addExtension(IExtensionTracker tracker,IExtension extension) {
+            //Do nothing
+        }
+
+        @Override
+		public void removeExtension(IExtension source, Object[] objects) {
+			for (Object object : objects) {
+				if (object == activeSupport) {
+					dispose();
+					// remove ourselves - we'll be added again in initalize if
+					// needed
+					PlatformUI.getWorkbench().getExtensionTracker()
+							.unregisterHandler(handler);
+				}
+			}
+		}
+	};
+
+	/**
+	 * Cannot be instantiated from outside.
+	 */
+	private WorkbenchBrowserSupport() {
+	}
+
+	/**
+	 * Returns the shared instance.
+	 *
+	 * @return shared instance
+	 */
+	public static IWorkbenchBrowserSupport getInstance() {
+		if (instance == null) {
+			instance = new WorkbenchBrowserSupport();
+		}
+		return instance;
+	}
+
+	@Override
+	public IWebBrowser createBrowser(int style, String browserId, String name,
+			String tooltip) throws PartInitException {
+		return getActiveSupport()
+				.createBrowser(style, browserId, name, tooltip);
+	}
+
+	@Override
+	public IWebBrowser createBrowser(String browserId) throws PartInitException {
+		return getActiveSupport().createBrowser(browserId);
+	}
+
+	@Override
+	public boolean isInternalWebBrowserAvailable() {
+		return getActiveSupport().isInternalWebBrowserAvailable();
+	}
+
+	private IWorkbenchBrowserSupport getActiveSupport() {
+		if (initialized == false) {
+			loadActiveSupport();
+		}
+		// ensure we always have an active instance
+		if (activeSupport == null) {
+			activeSupport = new DefaultWorkbenchBrowserSupport();
+		}
+		return activeSupport;
+	}
+
+    /**
+     * Answers whether the system has a non-default browser installed.
+     *
+     * @return whether the system has a non-default browser installed
+     */
+    public boolean hasNonDefaultBrowser() {
+        return !(getActiveSupport() instanceof DefaultWorkbenchBrowserSupport);
+    }
+
+	private void loadActiveSupport() {
+		BusyIndicator.showWhile(Display.getCurrent(), new Runnable() {
+			@Override
+			public void run() {
+                IConfigurationElement[] elements = Platform
+                        .getExtensionRegistry().getConfigurationElementsFor(
+                                PlatformUI.PLUGIN_EXTENSION_NAME_SPACE,
+                                IWorkbenchRegistryConstants.PL_BROWSER_SUPPORT);
+				IConfigurationElement elementToUse = null;
+
+                if (desiredBrowserSupportId != null) {
+					elementToUse = findDesiredElement(elements);
+				} else {
+					elementToUse = getElementToUse(elements);
+				}
+				if (elementToUse != null) {
+					initialized = initializePluggableBrowserSupport(elementToUse);
+				}
+			}
+
+            /**
+             * Search for the element whose extension has ID equal to that of
+             * the field desiredBrowserSupport.
+             *
+             * @param elements
+             *            the elements to search
+             * @return the element or <code>null</code>
+             */
+            private IConfigurationElement findDesiredElement(IConfigurationElement [] elements) {
+                for (IConfigurationElement element : elements) {
+                    if (desiredBrowserSupportId.equals(element.getDeclaringExtension().getUniqueIdentifier())) {
+						return element;
+					}
+                }
+                return null;
+            }
+
+            private IExtensionPoint getExtensionPoint() {
+                return Platform.getExtensionRegistry()
+						.getExtensionPoint(PlatformUI.PLUGIN_EXTENSION_NAME_SPACE, IWorkbenchRegistryConstants.PL_BROWSER_SUPPORT);
+            }
+
+			private IConfigurationElement getElementToUse(
+					IConfigurationElement[] elements) {
+				if (elements.length == 0) {
+					return null;
+				}
+				IConfigurationElement defaultElement = null;
+				IConfigurationElement choice = null;
+				// find the first default element and
+				// the first non-default element. If non-default
+				// is found, pick it. Otherwise, use default.
+				for (IConfigurationElement element : elements) {
+					if (element.getName().equals(IWorkbenchRegistryConstants.TAG_SUPPORT)) {
+						String def = element.getAttribute(IWorkbenchRegistryConstants.ATT_DEFAULT);
+						if (def != null && Boolean.valueOf(def).booleanValue()) {
+							if (defaultElement == null) {
+								defaultElement = element;
+							}
+						} else {
+							// non-default
+							if (choice == null) {
+								choice = element;
+							}
+						}
+					}
+				}
+				if (choice == null) {
+					choice = defaultElement;
+				}
+				return choice;
+			}
+
+			private boolean initializePluggableBrowserSupport(
+					IConfigurationElement element) {
+				// Instantiate the browser support
+				try {
+					activeSupport = (AbstractWorkbenchBrowserSupport) WorkbenchPlugin
+							.createExtension(element, IWorkbenchRegistryConstants.ATT_CLASS);
+					// start listening for removals
+					IExtensionTracker extensionTracker = PlatformUI.getWorkbench().getExtensionTracker();
+                    extensionTracker.registerHandler(handler, ExtensionTracker
+                            .createExtensionPointFilter(getExtensionPoint()));
+					// register the new browser support for removal
+					// notification
+					extensionTracker
+							.registerObject(element.getDeclaringExtension(),
+									activeSupport, IExtensionTracker.REF_WEAK);
+					return true;
+				} catch (CoreException e) {
+					WorkbenchPlugin
+							.log("Unable to instantiate browser support" + e.getStatus(), e);//$NON-NLS-1$
+				}
+				return false;
+			}
+
+		});
+	}
+
+    /**
+     * For debug purposes only.
+     *
+     * @param desiredBrowserSupportId the desired browser system id
+     */
+    public void setDesiredBrowserSupportId(String desiredBrowserSupportId) {
+        dispose(); // prep for a new help system
+        this.desiredBrowserSupportId = desiredBrowserSupportId;
+    }
+
+    /**
+     * Dispose of the active support.
+     */
+    protected void dispose() {
+        activeSupport = null;
+        initialized = false;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/CommandImageManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/CommandImageManager.java
new file mode 100644
index 0000000..2ca700a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/CommandImageManager.java
@@ -0,0 +1,340 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.commands;
+
+import java.net.URL;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.commands.common.EventManager;
+import org.eclipse.jface.resource.ImageDescriptor;
+
+/**
+ * <p>
+ * A central lookup facility for images for commands. Images can be associated
+ * with commands using this manager.
+ * </p>
+ * <p>
+ * Clients may instantiate, but must not extend.
+ * </p>
+ * <p>
+ * <strong>PROVISIONAL</strong>. This class or interface has been added as part
+ * of a work in progress. There is a guarantee neither that this API will work
+ * nor that it will remain the same. Please do not use this API without
+ * consulting with the Platform/UI team.
+ * </p>
+ * <p>
+ * This class is eventually intended to exist in
+ * <code>org.eclipse.jface.commands</code>.
+ * </p>
+ *
+ * @since 3.2
+ */
+public final class CommandImageManager extends EventManager {
+
+	/**
+	 * The type of image to display in the default case.
+	 */
+	public static final int TYPE_DEFAULT = 0;
+
+	/**
+	 * The type of image to display if the corresponding command is disabled.
+	 */
+	public static final int TYPE_DISABLED = 1;
+
+	/**
+	 * The type of image to display if the mouse is hovering over the command
+	 * and the command is enabled.
+	 */
+	public static final int TYPE_HOVER = 2;
+
+	/**
+	 * The map of command identifiers (<code>String</code>) to images. The
+	 * images are an array indexed by type. The values in the array are either
+	 * an <code>ImageDescriptor</code> or a <code>Map</code> of style (<code>String</code>)
+	 * to <code>ImageDescriptor</code>.
+	 */
+	private final Map imagesById = new HashMap();
+
+	/**
+	 * Adds a listener to this command image manager. The listener will be
+	 * notified when the set of image bindings changes. This can be used to
+	 * track the global appearance and disappearance of image bindings.
+	 *
+	 * @param listener
+	 *            The listener to attach; must not be <code>null</code>.
+	 */
+	public final void addCommandImageManagerListener(
+			final ICommandImageManagerListener listener) {
+		addListenerObject(listener);
+	}
+
+	/**
+	 * Binds a particular image path to a command id, type and style triple
+	 *
+	 * @param commandId
+	 *            The identifier of the command to which the image should be
+	 *            bound; must not be <code>null</code>.
+	 * @param type
+	 *            The type of image to retrieve. This value must be one of the
+	 *            <code>TYPE</code> constants defined in this class.
+	 * @param style
+	 *            The style of the image; may be <code>null</code>.
+	 * @param url
+	 *            The URL to the image. Should not be <code>null</code>.
+	 */
+	public final void bind(final String commandId, final int type,
+			final String style, final URL url) {
+		final ImageDescriptor descriptor = ImageDescriptor.createFromURL(url);
+		bind(commandId, type, style, descriptor);
+	}
+
+	/**
+	 * Binds a particular image path to a command id, type and style triple
+	 *
+	 * @param commandId
+	 *            The identifier of the command to which the image should be
+	 *            bound; must not be <code>null</code>.
+	 * @param type
+	 *            The type of image to retrieve. This value must be one of the
+	 *            <code>TYPE</code> constants defined in this class.
+	 * @param style
+	 *            The style of the image; may be <code>null</code>.
+	 * @param descriptor
+	 *            The image descriptor. Should not be <code>null</code>.
+	 */
+	public final void bind(final String commandId, final int type,
+			final String style, final ImageDescriptor descriptor) {
+		Object[] images = (Object[]) imagesById.get(commandId);
+		if (images == null) {
+			images = new Object[3];
+			imagesById.put(commandId, images);
+		}
+
+		if ((type < 0) || (type >= images.length)) {
+			throw new IllegalArgumentException(
+					"The type must be one of TYPE_DEFAULT, TYPE_DISABLED and TYPE_HOVER."); //$NON-NLS-1$
+		}
+
+		final Object typedImage = images[type];
+		if (style == null) {
+			if ((typedImage == null) || (typedImage instanceof ImageDescriptor)) {
+				images[type] = descriptor;
+			} else if (typedImage instanceof Map) {
+				final Map styleMap = (Map) typedImage;
+				styleMap.put(style, descriptor);
+			}
+		} else {
+			if (typedImage instanceof Map) {
+				final Map styleMap = (Map) typedImage;
+				styleMap.put(style, descriptor);
+			} else if (typedImage instanceof ImageDescriptor
+					|| typedImage == null) {
+				final Map styleMap = new HashMap();
+				styleMap.put(null, typedImage);
+				styleMap.put(style, descriptor);
+				images[type] = styleMap;
+			}
+		}
+
+		fireManagerChanged(new CommandImageManagerEvent(this,
+				new String[] { commandId }, type, style));
+	}
+
+	/**
+	 * Removes all of the images from this manager.
+	 */
+	public final void clear() {
+		imagesById.clear();
+		if (isListenerAttached()) {
+			final String[] commandIds = (String[]) imagesById.keySet().toArray(
+					new String[imagesById.size()]);
+			fireManagerChanged(new CommandImageManagerEvent(this, commandIds,
+					TYPE_DEFAULT, null));
+		}
+	}
+
+	/**
+	 * Notifies all of the listeners to this manager that the image bindings
+	 * have changed.
+	 *
+	 * @param event
+	 *            The event to send to all of the listeners; must not be
+	 *            <code>null</code>.
+	 */
+	private final void fireManagerChanged(final CommandImageManagerEvent event) {
+		if (event == null) {
+			throw new NullPointerException();
+		}
+
+		final Object[] listeners = getListeners();
+		for (Object l : listeners) {
+			final ICommandImageManagerListener listener = (ICommandImageManagerListener) l;
+			listener.commandImageManagerChanged(event);
+		}
+	}
+
+	/**
+	 * Generates a style tag that is not currently used for the given command.
+	 * This can be used by applications trying to create a unique style for a
+	 * new set of images.
+	 *
+	 * @param commandId
+	 *            The identifier of the command for which a unique style is
+	 *            required; must not be <code>null</code>.
+	 * @return A style tag that is not currently used; may be <code>null</code>.
+	 */
+	public final String generateUnusedStyle(final String commandId) {
+		final Object[] existingImages = (Object[]) imagesById.get(commandId);
+		if (existingImages == null) {
+			return null;
+		}
+
+		final Set existingStyles = new HashSet(3);
+		for (final Object styledImages : existingImages) {
+			if (styledImages instanceof ImageDescriptor) {
+				existingStyles.add(null);
+			} else if (styledImages instanceof Map) {
+				final Map styleMap = (Map) styledImages;
+				existingStyles.addAll(styleMap.keySet());
+			}
+		}
+
+		if (!existingStyles.contains(null)) {
+			return null;
+		}
+
+		String generatedStyle = "AUTOGEN:::"; //$NON-NLS-1$
+		int index = 0;
+		while (existingStyles.contains(generatedStyle)) {
+			generatedStyle += (index++ % 10);
+		}
+
+		return generatedStyle;
+	}
+
+	/**
+	 * Retrieves the default image associated with the given command in the
+	 * default style.
+	 *
+	 * @param commandId
+	 *            The identifier to find; must not be <code>null</code>.
+	 * @return An image appropriate for the given command; never
+	 *         <code>null</code>.
+	 */
+	public final ImageDescriptor getImageDescriptor(final String commandId) {
+		return getImageDescriptor(commandId, TYPE_DEFAULT, null);
+	}
+
+	/**
+	 * Retrieves the image of the given type associated with the given command
+	 * in the default style.
+	 *
+	 * @param commandId
+	 *            The identifier to find; must not be <code>null</code>.
+	 * @param type
+	 *            The type of image to retrieve. This value must be one of the
+	 *            <code>TYPE</code> constants defined in this class.
+	 * @return An image appropriate for the given command; <code>null</code>
+	 *         if the given image type cannot be found.
+	 */
+	public final ImageDescriptor getImageDescriptor(final String commandId,
+			final int type) {
+		return getImageDescriptor(commandId, type, null);
+	}
+
+	/**
+	 * Retrieves the image of the given type associated with the given command
+	 * in the given style.
+	 *
+	 * @param commandId
+	 *            The identifier to find; must not be <code>null</code>.
+	 * @param type
+	 *            The type of image to retrieve. This value must be one of the
+	 *            <code>TYPE</code> constants defined in this class.
+	 * @param style
+	 *            The style of the image to retrieve; may be <code>null</code>.
+	 * @return An image appropriate for the given command; <code>null</code>
+	 *         if the given image style and type cannot be found.
+	 */
+	public final ImageDescriptor getImageDescriptor(final String commandId,
+			final int type, final String style) {
+		if (commandId == null) {
+			throw new NullPointerException();
+		}
+
+		final Object[] images = (Object[]) imagesById.get(commandId);
+		if (images == null) {
+			return null;
+		}
+
+		if ((type < 0) || (type >= images.length)) {
+			throw new IllegalArgumentException(
+					"The type must be one of TYPE_DEFAULT, TYPE_DISABLED and TYPE_HOVER."); //$NON-NLS-1$
+		}
+
+		Object typedImage = images[type];
+
+		if (typedImage == null) {
+			return null;
+		}
+
+		if (typedImage instanceof ImageDescriptor) {
+			return (ImageDescriptor) typedImage;
+		}
+
+		if (typedImage instanceof Map) {
+			final Map styleMap = (Map) typedImage;
+			Object styledImage = styleMap.get(style);
+			if (styledImage instanceof ImageDescriptor) {
+				return (ImageDescriptor) styledImage;
+			}
+
+			if (style != null) {
+				styledImage = styleMap.get(null);
+				if (styledImage instanceof ImageDescriptor) {
+					return (ImageDescriptor) styledImage;
+				}
+			}
+		}
+
+		return null;
+	}
+
+	/**
+	 * Retrieves the default image associated with the given command in the
+	 * given style.
+	 *
+	 * @param commandId
+	 *            The identifier to find; must not be <code>null</code>.
+	 * @param style
+	 *            The style of the image to retrieve; may be <code>null</code>.
+	 * @return An image appropriate for the given command; <code>null</code>
+	 *         if the given image style cannot be found.
+	 */
+	public final ImageDescriptor getImageDescriptor(final String commandId,
+			final String style) {
+		return getImageDescriptor(commandId, TYPE_DEFAULT, style);
+	}
+
+	/**
+	 * Removes a listener from this command image manager.
+	 *
+	 * @param listener
+	 *            The listener to be removed; must not be <code>null</code>.
+	 */
+	public final void removeCommandImageManagerListener(
+			final ICommandImageManagerListener listener) {
+		removeListenerObject(listener);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/CommandImageManagerEvent.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/CommandImageManagerEvent.java
new file mode 100644
index 0000000..8296b1a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/CommandImageManagerEvent.java
@@ -0,0 +1,209 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.commands;
+
+/**
+ * <p>
+ * An event indicating that the image bindings have changed.
+ * </p>
+ * <p>
+ * Clients must neither instantiate nor extend.
+ * </p>
+ * <p>
+ * <strong>PROVISIONAL</strong>. This class or interface has been added as
+ * part of a work in progress. There is a guarantee neither that this API will
+ * work nor that it will remain the same. Please do not use this API without
+ * consulting with the Platform/UI team.
+ * </p>
+ * <p>
+ * This class is eventually intended to exist in
+ * <code>org.eclipse.jface.commands</code>.
+ * </p>
+ *
+ * @since 3.2
+ * @see ICommandImageManagerListener#commandImageManagerChanged(CommandImageManagerEvent)
+ */
+public final class CommandImageManagerEvent {
+
+	/**
+	 * The identifiers of the commands whose image bindings have changed. This
+	 * value is never <code>null</code> and never empty.
+	 */
+	private final String[] changedCommandIds;
+
+	/**
+	 * The command image manager that has changed. This value is never
+	 * <code>null</code>.
+	 */
+	private final CommandImageManager commandImageManager;
+
+	/**
+	 * The style of image that changed.
+	 */
+	private final String style;
+
+	/**
+	 * The type of image that changed.
+	 */
+	private final int type;
+
+	/**
+	 * Creates a new instance of this class.
+	 *
+	 * @param commandImageManager
+	 *            the instance of the manager that changed; must not be
+	 *            <code>null</code>.
+	 * @param changedCommandIds
+	 *            The identifiers of the commands whose image bindings have
+	 *            changed; this value must not be <code>null</code> and must
+	 *            not be empty. This value is not copied.
+	 */
+	CommandImageManagerEvent(final CommandImageManager commandImageManager,
+			final String[] changedCommandIds, final int type, final String style) {
+		if (commandImageManager == null) {
+			throw new NullPointerException("An event must refer to its manager"); //$NON-NLS-1$
+		}
+
+		if ((changedCommandIds == null) || (changedCommandIds.length < 1)) {
+			throw new IllegalArgumentException(
+					"There must be at least one change command identifier"); //$NON-NLS-1$
+		}
+
+		this.commandImageManager = commandImageManager;
+		this.changedCommandIds = changedCommandIds;
+		this.type = type;
+		this.style = style;
+	}
+
+	/**
+	 * Returns the identifiers of the commands whose bindings have changed.
+	 *
+	 * @return The identifiers of the commands whose bindings have changed;
+	 *         neither <code>null</code> nor empty.
+	 */
+	public final String[] getChangedCommandIds() {
+		final String[] copy = new String[changedCommandIds.length];
+		System.arraycopy(changedCommandIds, 0, copy, 0,
+				changedCommandIds.length);
+		return copy;
+	}
+
+	/**
+	 * Returns the instance of the interface that changed.
+	 *
+	 * @return the instance of the interface that changed. Guaranteed not to be
+	 *         <code>null</code>.
+	 */
+	public final CommandImageManager getCommandImageManager() {
+		return commandImageManager;
+	}
+
+	/**
+	 * Returns whether one of the images of the given command has changed.
+	 *
+	 * @param commandId
+	 *            The identifier of the command to check; must not be
+	 *            <code>null</code>.
+	 * @return <code>true</code> if one of the command's images has changed;
+	 *         <code>false</code> otherwise.
+	 */
+	public final boolean isCommandIdChanged(final String commandId) {
+		// PERFORMANCE
+		for (String changedCommandId : changedCommandIds) {
+			if (commandId.equals(changedCommandId)) {
+				return true;
+			}
+		}
+
+		return false;
+	}
+
+	/**
+	 * Returns whether the image for the command has changed.
+	 *
+	 * @param commandId
+	 *            The identifier of the command to check; must not be
+	 *            <code>null</code>.
+	 * @return <code>true</code> if the command's image has changed
+	 * @see CommandImageManager#getImageDescriptor(String)
+	 */
+	public final boolean isCommandImageChanged(final String commandId) {
+		return isCommandIdChanged(commandId)
+				&& (type == CommandImageManager.TYPE_DEFAULT)
+				&& (style == null);
+	}
+
+	/**
+	 * Returns whether the image of the given type for the command has changed.
+	 *
+	 * @param commandId
+	 *            The identifier of the command to check; must not be
+	 *            <code>null</code>.
+	 * @param type
+	 *            The type of image, one of
+	 *            {@link CommandImageManager#TYPE_DEFAULT},
+	 *            {@link CommandImageManager#TYPE_DISABLED} or
+	 *            {@link CommandImageManager#TYPE_HOVER}.
+	 * @return <code>true</code> if the command's image of the given type has
+	 *         changed.
+	 * @see CommandImageManager#getImageDescriptor(String, int)
+	 */
+	public final boolean isCommandImageChanged(final String commandId,
+			final int type) {
+		return isCommandIdChanged(commandId)
+				&& ((type == CommandImageManager.TYPE_DEFAULT) || (type == this.type))
+				&& (style == null);
+	}
+
+	/**
+	 * Returns whether the image of the given type and style for the command has
+	 * changed.
+	 *
+	 * @param commandId
+	 *            The identifier of the command to check; must not be
+	 *            <code>null</code>.
+	 * @param type
+	 *            The type of image, one of
+	 *            {@link CommandImageManager#TYPE_DEFAULT},
+	 *            {@link CommandImageManager#TYPE_DISABLED} or
+	 *            {@link CommandImageManager#TYPE_HOVER}.
+	 * @param style
+	 *            The style of the image; may be anything.
+	 * @return <code>true</code> if the command's image of the given type and
+	 *         style has changed.
+	 * @see CommandImageManager#getImageDescriptor(String, int, String)
+	 */
+	public final boolean isCommandImageChanged(final String commandId,
+			final int type, final String style) {
+		return isCommandIdChanged(commandId)
+				&& ((type == CommandImageManager.TYPE_DEFAULT) || (type == this.type))
+				&& ((style == null) || (style.equals(this.style)));
+	}
+
+	/**
+	 * Returns whether the image of the given style for the command has changed.
+	 *
+	 * @param commandId
+	 *            The identifier of the command to check; must not be
+	 *            <code>null</code>.
+	 * @param style
+	 *            The style of the image; may be anything.
+	 * @return <code>true</code> if the command's image of the given style has
+	 *         changed.
+	 * @see CommandImageManager#getImageDescriptor(String, String)
+	 */
+	public final boolean isCommandImageChanged(final String commandId,
+			final String style) {
+		return isCommandIdChanged(commandId)
+				&& (type == CommandImageManager.TYPE_DEFAULT)
+				&& ((style == null) || (style.equals(this.style)));
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/CommandImagePersistence.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/CommandImagePersistence.java
new file mode 100644
index 0000000..e7d40c8
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/CommandImagePersistence.java
@@ -0,0 +1,238 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.commands;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionDelta;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.IProduct;
+import org.eclipse.core.runtime.IRegistryChangeEvent;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.services.RegistryPersistence;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.Bundle;
+
+/**
+ * <p>
+ * Handles persistence for the command images.
+ * </p>
+ * <p>
+ * This class is only intended for internal use within the
+ * <code>org.eclipse.ui.workbench</code> plug-in.
+ * </p>
+ * <p>
+ * <strong>PROVISIONAL</strong>. This class or interface has been added as part
+ * of a work in progress. There is a guarantee neither that this API will work
+ * nor that it will remain the same. Please do not use this API without
+ * consulting with the Platform/UI team.
+ * </p>
+ *
+ * @since 3.2
+ */
+public final class CommandImagePersistence extends RegistryPersistence {
+
+	/**
+	 * The index of the image elements in the indexed array.
+	 *
+	 * @see CommandImagePersistence#read()
+	 */
+	private static final int INDEX_IMAGES = 0;
+
+	/**
+	 * Reads all of the images from the command images extension point.
+	 *
+	 * @param configurationElements
+	 *            The configuration elements in the command images extension
+	 *            point; must not be <code>null</code>, but may be empty.
+	 * @param configurationElementCount
+	 *            The number of configuration elements that are really in the
+	 *            array.
+	 * @param commandImageManager
+	 *            The command image manager to which the images should be added;
+	 *            must not be <code>null</code>.
+	 * @param commandService
+	 *            The command service for the workbench; must not be
+	 *            <code>null</code>.
+	 */
+	private static final void readImagesFromRegistry(
+			final IConfigurationElement[] configurationElements,
+			final int configurationElementCount,
+			final CommandImageManager commandImageManager,
+			final ICommandService commandService) {
+		// Undefine all the previous images.
+		commandImageManager.clear();
+
+		final List warningsToLog = new ArrayList(1);
+
+		for (int i = 0; i < configurationElementCount; i++) {
+			final IConfigurationElement configurationElement = configurationElements[i];
+
+			// Read out the command identifier.
+			final String commandId = readRequired(configurationElement,
+					ATT_COMMAND_ID, warningsToLog, "Image needs an id"); //$NON-NLS-1$
+			if (commandId == null) {
+				continue;
+			}
+
+			if (!commandService.getCommand(commandId).isDefined()) {
+				// Reference to an undefined command. This is invalid.
+				addWarning(warningsToLog,
+						"Cannot bind to an undefined command", //$NON-NLS-1$
+						configurationElement, commandId);
+				continue;
+			}
+
+			// Read out the style.
+			final String style = readOptional(configurationElement, ATT_STYLE);
+
+			// Read out the default icon.
+			final String icon = readRequired(configurationElement, ATT_ICON,
+					warningsToLog, commandId);
+			if (icon == null) {
+				continue;
+			}
+
+			final String disabledIcon = readOptional(configurationElement,
+					ATT_DISABLEDICON);
+			final String hoverIcon = readOptional(configurationElement,
+					ATT_HOVERICON);
+
+			String namespaceId = configurationElement.getNamespaceIdentifier();
+			ImageDescriptor iconDescriptor = AbstractUIPlugin
+					.imageDescriptorFromPlugin(namespaceId, icon);
+			commandImageManager.bind(commandId,
+					CommandImageManager.TYPE_DEFAULT, style, iconDescriptor);
+			if (disabledIcon != null) {
+				ImageDescriptor disabledIconDescriptor = AbstractUIPlugin
+						.imageDescriptorFromPlugin(namespaceId, disabledIcon);
+				commandImageManager.bind(commandId,
+						CommandImageManager.TYPE_DISABLED, style,
+						disabledIconDescriptor);
+			}
+			if (hoverIcon != null) {
+				ImageDescriptor hoverIconDescriptor = AbstractUIPlugin
+						.imageDescriptorFromPlugin(namespaceId, hoverIcon);
+				commandImageManager.bind(commandId,
+						CommandImageManager.TYPE_HOVER, style,
+						hoverIconDescriptor);
+			}
+		}
+
+		logWarnings(
+				warningsToLog,
+				"Warnings while parsing the images from the 'org.eclipse.ui.commandImages' extension point."); //$NON-NLS-1$
+	}
+
+	/**
+	 * The command image manager which should be populated with the values from
+	 * the registry; must not be <code>null</code>.
+	 */
+	private final CommandImageManager commandImageManager;
+
+	/**
+	 * The command service for the workbench; must not be <code>null</code>.
+	 */
+	private final ICommandService commandService;
+
+	/**
+	 * Constructs a new instance of <code>CommandImagePersistence</code>.
+	 *
+	 * @param commandImageManager
+	 *            The command image manager which should be populated with the
+	 *            values from the registry; must not be <code>null</code>.
+	 * @param commandService
+	 *            The command service for the workbench; must not be
+	 *            <code>null</code>.
+	 */
+	CommandImagePersistence(final CommandImageManager commandImageManager,
+			final ICommandService commandService) {
+		this.commandImageManager = commandImageManager;
+		this.commandService = commandService;
+	}
+
+	@Override
+	protected final boolean isChangeImportant(final IRegistryChangeEvent event) {
+        // RAP [bm]: 
+//      final IExtensionDelta[] imageDeltas = event.getExtensionDeltas(
+//              PlatformUI.PLUGIN_ID,
+//              IWorkbenchRegistryConstants.PL_COMMAND_IMAGES);
+        final IExtensionDelta[] imageDeltas = event.getExtensionDeltas(
+                PlatformUI.PLUGIN_EXTENSION_NAME_SPACE,
+                IWorkbenchRegistryConstants.PL_COMMAND_IMAGES);
+        // RAPEND: [bm] 
+		return (imageDeltas.length != 0);
+	}
+
+	public void reRead() {
+		read();
+	}
+
+	/**
+	 * Reads all of the command images from the registry.
+	 */
+	@Override
+	protected final void read() {
+		super.read();
+
+		// Create the extension registry mementos.
+		final IExtensionRegistry registry = Platform.getExtensionRegistry();
+		int imageCount = 0;
+		final IConfigurationElement[][] indexedConfigurationElements = new IConfigurationElement[1][];
+
+		// Sort the commands extension point based on element name.
+		final IConfigurationElement[] commandImagesExtensionPoint = registry
+				.getConfigurationElementsFor(EXTENSION_COMMAND_IMAGES);
+		for (final IConfigurationElement configurationElement : commandImagesExtensionPoint) {
+			final String name = configurationElement.getName();
+
+			// Check if it is a binding definition.
+			if (TAG_IMAGE.equals(name)) {
+				addElementToIndexedArray(configurationElement,
+						indexedConfigurationElements, INDEX_IMAGES,
+						imageCount++);
+			}
+		}
+
+		readImagesFromRegistry(indexedConfigurationElements[INDEX_IMAGES],
+				imageCount, commandImageManager, commandService);
+		// Associate product icon to About command
+		IProduct product = Platform.getProduct();
+		if (product != null) {
+			Bundle productBundle = product.getDefiningBundle();
+			if (productBundle != null) {
+				String imageList = product.getProperty("windowImages"); //$NON-NLS-1$
+				if (imageList != null) {
+					String iconPath = imageList.split(",")[0]; //$NON-NLS-1$
+					URL iconUrl = productBundle.getEntry(iconPath);
+					ImageDescriptor icon = ImageDescriptor.createFromURL(iconUrl);
+					if (icon != null) {
+						commandImageManager.bind(IWorkbenchCommandConstants.HELP_ABOUT,
+								CommandImageManager.TYPE_DEFAULT, null, icon);
+						commandImageManager.bind(IWorkbenchCommandConstants.HELP_ABOUT,
+								CommandImageManager.TYPE_DISABLED, null, icon);
+						commandImageManager.bind(IWorkbenchCommandConstants.HELP_ABOUT,
+								CommandImageManager.TYPE_HOVER, null, icon);
+					}
+
+				}
+			}
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/CommandImageService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/CommandImageService.java
new file mode 100644
index 0000000..7955073
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/CommandImageService.java
@@ -0,0 +1,151 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.commands;
+
+import java.net.URL;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.commands.ICommandImageService;
+import org.eclipse.ui.commands.ICommandService;
+
+/**
+ * <p>
+ * Provides services related to the command architecture within the workbench.
+ * This service can be used to access the set of commands and handlers.
+ * </p>
+ *
+ * @since 3.2
+ */
+public final class CommandImageService implements ICommandImageService {
+
+	/**
+	 * The command image manager that supports this service. This value is never
+	 * <code>null</code>.
+	 */
+	private final CommandImageManager commandImageManager;
+
+	/**
+	 * The class providing persistence for this service.
+	 */
+	private final CommandImagePersistence commandImagePersistence;
+
+	/**
+	 * Constructs a new instance of <code>CommandService</code> using a
+	 * command image manager.
+	 *
+	 * @param commandImageManager
+	 *            The command image manager to use; must not be
+	 *            <code>null</code>.
+	 * @param commandService
+	 *            The workbench command service; must not be <code>null</code>.
+	 *            This is used for checking whether a command is defined when
+	 *            reading the registry.
+	 */
+	public CommandImageService(final CommandImageManager commandImageManager,
+			final ICommandService commandService) {
+		if (commandImageManager == null) {
+			throw new NullPointerException(
+					"Cannot create a command image service with a null manager"); //$NON-NLS-1$
+		}
+		if (commandService == null) {
+			throw new NullPointerException(
+					"Cannot create a command image service with a null command service"); //$NON-NLS-1$
+		}
+		this.commandImageManager = commandImageManager;
+		this.commandImagePersistence = new CommandImagePersistence(
+				commandImageManager, commandService);
+	}
+
+	/**
+	 * Binds a particular image descriptor to a command id, type and style
+	 * triple
+	 *
+	 * @param commandId
+	 *            The identifier of the command to which the image should be
+	 *            bound; must not be <code>null</code>.
+	 * @param type
+	 *            The type of image to retrieve. This value must be one of the
+	 *            <code>TYPE</code> constants defined in this class.
+	 * @param style
+	 *            The style of the image; may be <code>null</code>.
+	 * @param descriptor
+	 *            The image descriptor. Should not be <code>null</code>.
+	 */
+	public final void bind(final String commandId, final int type,
+			final String style, final ImageDescriptor descriptor) {
+		commandImageManager.bind(commandId, type, style, descriptor);
+	}
+
+	/**
+	 * Binds a particular image path to a command id, type and style triple
+	 *
+	 * @param commandId
+	 *            The identifier of the command to which the image should be
+	 *            bound; must not be <code>null</code>.
+	 * @param type
+	 *            The type of image to retrieve. This value must be one of the
+	 *            <code>TYPE</code> constants defined in this class.
+	 * @param style
+	 *            The style of the image; may be <code>null</code>.
+	 * @param url
+	 *            The URL to the image. Should not be <code>null</code>.
+	 */
+	public final void bind(final String commandId, final int type,
+			final String style, final URL url) {
+		commandImageManager.bind(commandId, type, style, url);
+	}
+
+	@Override
+	public final void dispose() {
+		commandImagePersistence.dispose();
+	}
+
+	/**
+	 * Generates a style tag that is not currently used for the given command.
+	 * This can be used by applications trying to create a unique style for a
+	 * new set of images.
+	 *
+	 * @param commandId
+	 *            The identifier of the command for which a unique style is
+	 *            required; must not be <code>null</code>.
+	 * @return A style tag that is not currently used; may be <code>null</code>.
+	 */
+	public final String generateUnusedStyle(final String commandId) {
+		return commandImageManager.generateUnusedStyle(commandId);
+	}
+
+	@Override
+	public final ImageDescriptor getImageDescriptor(final String commandId) {
+		return commandImageManager.getImageDescriptor(commandId);
+	}
+
+	@Override
+	public final ImageDescriptor getImageDescriptor(final String commandId,
+			final int type) {
+		return commandImageManager.getImageDescriptor(commandId, type);
+	}
+
+	@Override
+	public final ImageDescriptor getImageDescriptor(final String commandId,
+			final int type, final String style) {
+		return commandImageManager.getImageDescriptor(commandId, type, style);
+	}
+
+	@Override
+	public final ImageDescriptor getImageDescriptor(final String commandId,
+			final String style) {
+		return commandImageManager.getImageDescriptor(commandId, style);
+	}
+
+	public final void readRegistry() {
+		commandImagePersistence.read();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/CommandLegacyWrapper.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/CommandLegacyWrapper.java
new file mode 100644
index 0000000..6a2ac45
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/CommandLegacyWrapper.java
@@ -0,0 +1,199 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *******************************************************************************/
+package org.eclipse.ui.internal.commands;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.jface.bindings.BindingManager;
+import org.eclipse.jface.bindings.TriggerSequence;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.commands.ExecutionException;
+import org.eclipse.ui.commands.ICommand;
+import org.eclipse.ui.commands.ICommandListener;
+import org.eclipse.ui.commands.NotDefinedException;
+import org.eclipse.ui.commands.NotHandledException;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.internal.keys.KeySequenceBinding;
+import org.eclipse.ui.keys.IBindingService;
+import org.eclipse.ui.keys.KeySequence;
+
+/**
+ * A wrapper around a core command so that it satisfies the deprecated
+ * <code>ICommand</code> interface.
+ *
+ * @since 3.1
+ */
+final class CommandLegacyWrapper implements ICommand {
+
+	/**
+	 * The supporting binding manager; never <code>null</code>.
+	 */
+	private final BindingManager bindingManager;
+
+	/**
+	 * The wrapped command; never <code>null</code>.
+	 */
+	private final Command command;
+
+	/**
+	 * A parameterized representation of the command. This is created lazily. If
+	 * it has not yet been created, it is <code>null</code>.
+	 */
+	private ParameterizedCommand parameterizedCommand;
+
+	/**
+	 * Constructs a new <code>CommandWrapper</code>
+	 *
+	 * @param command
+	 *            The command to be wrapped; must not be <code>null</code>.
+	 * @param bindingManager
+	 *            The binding manager to support this wrapper; must not be
+	 *            <code>null</code>.
+	 */
+	CommandLegacyWrapper(final Command command,
+			final BindingManager bindingManager) {
+		if (command == null) {
+			throw new NullPointerException(
+					"The wrapped command cannot be <code>null</code>."); //$NON-NLS-1$
+		}
+
+		if (bindingManager == null) {
+			throw new NullPointerException(
+					"A binding manager is required to wrap a command"); //$NON-NLS-1$
+		}
+
+		this.command = command;
+		this.bindingManager = bindingManager;
+	}
+
+
+	@Override
+	public final void addCommandListener(final ICommandListener commandListener) {
+		command.addCommandListener(new LegacyCommandListenerWrapper(
+				commandListener, bindingManager));
+	}
+
+	@Override
+	public final Object execute(Map parameterValuesByName)
+			throws ExecutionException, NotHandledException {
+		try {
+			IHandlerService service = PlatformUI.getWorkbench().getService(
+					IHandlerService.class);
+
+			return command.execute(new ExecutionEvent(command,
+					(parameterValuesByName == null) ? Collections.EMPTY_MAP
+									: parameterValuesByName, null, service.getCurrentState()));
+		} catch (final org.eclipse.core.commands.ExecutionException e) {
+			throw new ExecutionException(e);
+		} catch (final org.eclipse.core.commands.NotHandledException e) {
+			throw new NotHandledException(e);
+		}
+	}
+
+	@Override
+	public final Map getAttributeValuesByName() {
+		final Map attributeValues = new HashMap();
+		// avoid using Boolean.valueOf to allow compilation against JCL
+		// Foundation (bug 80053)
+		attributeValues.put(ILegacyAttributeNames.ENABLED,
+				command.isEnabled() ? Boolean.TRUE : Boolean.FALSE);
+		attributeValues.put(ILegacyAttributeNames.HANDLED,
+				command.isHandled() ? Boolean.TRUE : Boolean.FALSE);
+		return attributeValues;
+	}
+
+	@Override
+	public final String getCategoryId() throws NotDefinedException {
+		try {
+			return command.getCategory().getId();
+		} catch (final org.eclipse.core.commands.common.NotDefinedException e) {
+			throw new NotDefinedException(e);
+		}
+	}
+
+	@Override
+	public final String getDescription() throws NotDefinedException {
+		try {
+			return command.getDescription();
+		} catch (final org.eclipse.core.commands.common.NotDefinedException e) {
+			throw new NotDefinedException(e);
+		}
+	}
+
+	@Override
+	public final String getId() {
+		return command.getId();
+	}
+
+	@Override
+	public final List getKeySequenceBindings() {
+		final List legacyBindings = new ArrayList();
+		if (parameterizedCommand == null) {
+			parameterizedCommand = new ParameterizedCommand(command, null);
+		}
+		IBindingService bindingService = PlatformUI.getWorkbench().getService(
+				IBindingService.class);
+		final TriggerSequence[] activeBindings = bindingService
+				.getActiveBindingsFor(parameterizedCommand);
+		final int activeBindingsCount = activeBindings.length;
+		for (int i = 0; i < activeBindingsCount; i++) {
+			final TriggerSequence triggerSequence = activeBindings[i];
+			if (triggerSequence instanceof org.eclipse.jface.bindings.keys.KeySequence) {
+				legacyBindings
+						.add(new KeySequenceBinding(
+								KeySequence
+										.getInstance((org.eclipse.jface.bindings.keys.KeySequence) triggerSequence),
+								0));
+			}
+		}
+
+		return legacyBindings;
+	}
+
+	@Override
+	public final String getName() throws NotDefinedException {
+		try {
+			return command.getName();
+		} catch (final org.eclipse.core.commands.common.NotDefinedException e) {
+			throw new NotDefinedException(e);
+		}
+	}
+
+	@Override
+	public final boolean isDefined() {
+		return command.isDefined();
+	}
+
+	@Override
+	public final boolean isHandled() {
+		return command.isHandled();
+	}
+
+	@Override
+	public final void removeCommandListener(
+			final ICommandListener commandListener) {
+		command.removeCommandListener(new LegacyCommandListenerWrapper(
+				commandListener, bindingManager));
+	}
+
+	@Override
+	public final int compareTo(final Object o) {
+		return command.compareTo(o);
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/CommandManagerFactory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/CommandManagerFactory.java
new file mode 100644
index 0000000..ef25962
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/CommandManagerFactory.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.commands;
+
+import org.eclipse.core.commands.CommandManager;
+import org.eclipse.core.commands.contexts.ContextManager;
+import org.eclipse.jface.bindings.BindingManager;
+
+/**
+ * This class allows clients to broker instances of <code>ICommandManager</code>.
+ * <p>
+ * This class is not intended to be extended by clients.
+ * </p>
+ *
+ * @since 3.0
+ */
+public final class CommandManagerFactory {
+
+	/**
+	 * Creates a new instance of <code>IMutableCommandManager</code>.
+	 *
+	 * @param bindingManager
+	 *            The binding manager providing support for the command manager;
+	 *            must not be <code>null</code>.
+	 * @param commandManager
+	 *            The command manager providing support for this command
+	 *            manager; must not be <code>null</code>.
+	 * @param contextManager
+	 *            The context manager for this command manager; must not be
+	 *            <code>null</code>.
+	 * @return a new instance of <code>IMutableCommandManager</code>. Clients
+	 *         should not make assumptions about the concrete implementation
+	 *         outside the contract of the interface. Guaranteed not to be
+	 *         <code>null</code>.
+	 */
+	public static CommandManagerLegacyWrapper getCommandManagerWrapper(
+			final BindingManager bindingManager,
+			final CommandManager commandManager,
+			final ContextManager contextManager) {
+		return new CommandManagerLegacyWrapper(bindingManager, commandManager,
+				contextManager);
+	}
+
+	private CommandManagerFactory() {
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/CommandManagerLegacyWrapper.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/CommandManagerLegacyWrapper.java
new file mode 100644
index 0000000..c2f2e07
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/CommandManagerLegacyWrapper.java
@@ -0,0 +1,429 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.commands;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.CommandManager;
+import org.eclipse.core.commands.contexts.ContextManager;
+import org.eclipse.core.commands.contexts.ContextManagerEvent;
+import org.eclipse.core.commands.contexts.IContextManagerListener;
+import org.eclipse.e4.core.commands.internal.HandlerServiceImpl;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.jface.bindings.Binding;
+import org.eclipse.jface.bindings.BindingManager;
+import org.eclipse.jface.bindings.BindingManagerEvent;
+import org.eclipse.jface.bindings.IBindingManagerListener;
+import org.eclipse.jface.bindings.Scheme;
+import org.eclipse.jface.bindings.TriggerSequence;
+import org.eclipse.jface.bindings.keys.ParseException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.commands.CommandManagerEvent;
+import org.eclipse.ui.commands.ICategory;
+import org.eclipse.ui.commands.ICommand;
+import org.eclipse.ui.commands.ICommandManager;
+import org.eclipse.ui.commands.ICommandManagerListener;
+import org.eclipse.ui.commands.IKeyConfiguration;
+import org.eclipse.ui.internal.handlers.LegacyHandlerWrapper;
+import org.eclipse.ui.internal.keys.SchemeLegacyWrapper;
+import org.eclipse.ui.internal.util.Util;
+import org.eclipse.ui.keys.KeySequence;
+
+/**
+ * Provides support for the old <code>ICommandManager</code> interface.
+ *
+ * @since 3.1
+ */
+public final class CommandManagerLegacyWrapper implements ICommandManager,
+		org.eclipse.core.commands.ICommandManagerListener,
+		IBindingManagerListener, IContextManagerListener {
+
+	/**
+	 * Whether commands should print out information about which handlers are
+	 * being executed. Change this value if you want console output on command
+	 * execution.
+	 */
+	public static boolean DEBUG_COMMAND_EXECUTION = false;
+
+	/**
+	 * Whether commands should print out information about handler changes.
+	 * Change this value if you want console output when commands change
+	 * handlers.
+	 */
+	public static boolean DEBUG_HANDLERS = false;
+
+	/**
+	 * Which command should print out debugging information. Change this value
+	 * if you want to only here when a command with a particular identifier
+	 * changes its handler.
+	 */
+	public static String DEBUG_HANDLERS_COMMAND_ID = null;
+
+	static boolean validateKeySequence(KeySequence keySequence) {
+		if (keySequence == null) {
+			return false;
+		}
+		List keyStrokes = keySequence.getKeyStrokes();
+		int size = keyStrokes.size();
+		if (size == 0 || size > 4 || !keySequence.isComplete()) {
+			return false;
+		}
+		return true;
+	}
+
+	/**
+	 * The JFace binding machine that provides binding support for this
+	 * workbench mutable command manager. This value will never be
+	 * <code>null</code>.
+	 *
+	 * @since 3.1
+	 */
+	private final BindingManager bindingManager;
+
+	/**
+	 * The command manager that provides functionality for this workbench
+	 * command manager. This value will never be <code>null</code>.
+	 *
+	 * @since 3.1
+	 */
+	private final CommandManager commandManager;
+
+	private List commandManagerListeners;
+
+	/**
+	 * The context manager that provides functionality for this workbench
+	 * command manager. This value will never be <code>null</code>.
+	 *
+	 * @since 3.1
+	 */
+	private final ContextManager contextManager;
+
+	/**
+	 * Constructs a new instance of <code>MutableCommandManager</code>. The
+	 * binding manager and command manager providing support for this manager
+	 * are constructed at this time.
+	 *
+	 * @param bindingManager
+	 *            The binding manager providing support for the command manager;
+	 *            must not be <code>null</code>.
+	 * @param commandManager
+	 *            The command manager providing support for this command
+	 *            manager; must not be <code>null</code>.
+	 * @param contextManager
+	 *            The context manager to provide context support to this
+	 *            manager. This value must not be <code>null</code>.
+	 *
+	 */
+	public CommandManagerLegacyWrapper(final BindingManager bindingManager,
+			final CommandManager commandManager,
+			final ContextManager contextManager) {
+		if (contextManager == null) {
+			throw new NullPointerException(
+					"The context manager cannot be null."); //$NON-NLS-1$
+		}
+		this.bindingManager = bindingManager;
+		this.commandManager = commandManager;
+		this.contextManager = contextManager;
+	}
+
+	@Override
+	public final void addCommandManagerListener(
+			final ICommandManagerListener commandManagerListener) {
+		if (commandManagerListener == null) {
+			throw new NullPointerException("Cannot add a null listener."); //$NON-NLS-1$
+		}
+
+		if (commandManagerListeners == null) {
+			commandManagerListeners = new ArrayList();
+			this.commandManager.addCommandManagerListener(this);
+			this.bindingManager.addBindingManagerListener(this);
+			this.contextManager.addContextManagerListener(this);
+		}
+
+		if (!commandManagerListeners.contains(commandManagerListener)) {
+			commandManagerListeners.add(commandManagerListener);
+		}
+	}
+
+	@Override
+	public final void bindingManagerChanged(final BindingManagerEvent event) {
+		final boolean schemeDefinitionsChanged = event.getScheme() != null;
+		final Set previousSchemes;
+		if (schemeDefinitionsChanged) {
+			previousSchemes = new HashSet();
+			final Scheme scheme = event.getScheme();
+			final Scheme[] definedSchemes = event.getManager()
+					.getDefinedSchemes();
+			final int definedSchemesCount = definedSchemes.length;
+			for (int i = 0; i < definedSchemesCount; i++) {
+				final Scheme definedScheme = definedSchemes[0];
+				if ((definedScheme == scheme) && (event.isSchemeDefined())) {
+					continue; // skip this one, it was just defined.
+				}
+				previousSchemes.add(definedSchemes[0].getId());
+			}
+			if (!event.isSchemeDefined()) {
+				previousSchemes.add(scheme.getId());
+			}
+		} else {
+			previousSchemes = null;
+		}
+
+		fireCommandManagerChanged(new CommandManagerEvent(this, false, event
+				.isActiveSchemeChanged(), event.isLocaleChanged(), event
+				.isPlatformChanged(), false, false, schemeDefinitionsChanged,
+				null, null, previousSchemes));
+	}
+
+	@Override
+	public final void commandManagerChanged(
+			final org.eclipse.core.commands.CommandManagerEvent event) {
+		// Figure out the set of previous category identifiers.
+		final boolean categoryIdsChanged = event.isCategoryChanged();
+		final Set previousCategoryIds;
+		if (categoryIdsChanged) {
+			previousCategoryIds = new HashSet(commandManager
+					.getDefinedCategoryIds());
+			final String categoryId = event.getCategoryId();
+			if (event.isCategoryDefined()) {
+				previousCategoryIds.remove(categoryId);
+			} else {
+				previousCategoryIds.add(categoryId);
+			}
+		} else {
+			previousCategoryIds = null;
+		}
+
+		// Figure out the set of previous command identifiers.
+		final boolean commandIdsChanged = event.isCommandChanged();
+		final Set previousCommandIds;
+		if (commandIdsChanged) {
+			previousCommandIds = new HashSet(commandManager
+					.getDefinedCommandIds());
+			final String commandId = event.getCommandId();
+			if (event.isCommandDefined()) {
+				previousCommandIds.remove(commandId);
+			} else {
+				previousCommandIds.add(commandId);
+			}
+		} else {
+			previousCommandIds = null;
+		}
+
+		fireCommandManagerChanged(new CommandManagerEvent(this, false, false,
+				false, false, categoryIdsChanged, commandIdsChanged, false,
+				previousCategoryIds, previousCommandIds, null));
+	}
+
+	@Override
+	public final void contextManagerChanged(final ContextManagerEvent event) {
+		fireCommandManagerChanged(new CommandManagerEvent(this, event
+				.isActiveContextsChanged(), false, false, false, false, false,
+				false, null, null, null));
+	}
+
+	private void fireCommandManagerChanged(
+			CommandManagerEvent commandManagerEvent) {
+		if (commandManagerEvent == null) {
+			throw new NullPointerException();
+		}
+		if (commandManagerListeners != null) {
+			for (int i = 0; i < commandManagerListeners.size(); i++) {
+				((ICommandManagerListener) commandManagerListeners.get(i))
+						.commandManagerChanged(commandManagerEvent);
+			}
+		}
+	}
+
+	@Override
+	public Set getActiveContextIds() {
+		return contextManager.getActiveContextIds();
+	}
+
+	@Override
+	public String getActiveKeyConfigurationId() {
+		final Scheme scheme = bindingManager.getActiveScheme();
+		if (scheme != null) {
+			return scheme.getId();
+		}
+
+		/*
+		 * TODO This is possibly a breaking change. The id should be non-null,
+		 * and presumably, a real scheme id.
+		 */
+		return Util.ZERO_LENGTH_STRING;
+	}
+
+	@Override
+	public String getActiveLocale() {
+		return bindingManager.getLocale();
+	}
+
+	@Override
+	public String getActivePlatform() {
+		return bindingManager.getPlatform();
+	}
+
+	@Override
+	public ICategory getCategory(String categoryId) {
+		// TODO Provide access to the categories.
+		// return new CategoryWrapper(commandManager.getCategory(categoryId));
+		return null;
+	}
+
+	@Override
+	public ICommand getCommand(String commandId) {
+		final Command command = commandManager.getCommand(commandId);
+		if (!command.isDefined()) {
+			command.setHandler(HandlerServiceImpl.getHandler(commandId, PlatformUI.getWorkbench().getService(IEclipseContext.class)));
+		}
+		return new CommandLegacyWrapper(command, bindingManager);
+	}
+
+	@Override
+	public Set getDefinedCategoryIds() {
+		return commandManager.getDefinedCategoryIds();
+	}
+
+	@Override
+	public Set getDefinedCommandIds() {
+		return commandManager.getDefinedCommandIds();
+	}
+
+	@Override
+	public Set getDefinedKeyConfigurationIds() {
+		final Set definedIds = new HashSet();
+		final Scheme[] schemes = bindingManager.getDefinedSchemes();
+		for (Scheme scheme : schemes) {
+			definedIds.add(scheme.getId());
+		}
+		return definedIds;
+	}
+
+	@Override
+	public IKeyConfiguration getKeyConfiguration(String keyConfigurationId) {
+		final Scheme scheme = bindingManager.getScheme(keyConfigurationId);
+		return new SchemeLegacyWrapper(scheme, bindingManager);
+	}
+
+	@Override
+	public Map getPartialMatches(KeySequence keySequence) {
+		try {
+			final org.eclipse.jface.bindings.keys.KeySequence sequence = org.eclipse.jface.bindings.keys.KeySequence
+					.getInstance(keySequence.toString());
+			final Map partialMatches = bindingManager
+					.getPartialMatches(sequence);
+			final Map returnValue = new HashMap();
+			final Iterator matchItr = partialMatches.entrySet().iterator();
+			while (matchItr.hasNext()) {
+				final Map.Entry entry = (Map.Entry) matchItr.next();
+				final TriggerSequence trigger = (TriggerSequence) entry
+						.getKey();
+				if (trigger instanceof org.eclipse.jface.bindings.keys.KeySequence) {
+					final org.eclipse.jface.bindings.keys.KeySequence triggerKey = (org.eclipse.jface.bindings.keys.KeySequence) trigger;
+					returnValue.put(KeySequence.getInstance(triggerKey
+							.toString()), entry.getValue());
+				}
+			}
+			return returnValue;
+		} catch (final ParseException e) {
+			return new HashMap();
+		} catch (final org.eclipse.ui.keys.ParseException e) {
+			return new HashMap();
+		}
+	}
+
+	@Override
+	public String getPerfectMatch(KeySequence keySequence) {
+		try {
+			final org.eclipse.jface.bindings.keys.KeySequence sequence = org.eclipse.jface.bindings.keys.KeySequence
+					.getInstance(keySequence.toString());
+			final Binding binding = bindingManager.getPerfectMatch(sequence);
+			if (binding == null) {
+				return null;
+			}
+
+			return binding.getParameterizedCommand().getId();
+
+		} catch (final ParseException e) {
+			return null;
+		}
+	}
+
+	@Override
+	public boolean isPartialMatch(KeySequence keySequence) {
+		try {
+			final org.eclipse.jface.bindings.keys.KeySequence sequence = org.eclipse.jface.bindings.keys.KeySequence
+					.getInstance(keySequence.toString());
+			return bindingManager.isPartialMatch(sequence);
+		} catch (final ParseException e) {
+			return false;
+		}
+	}
+
+	@Override
+	public boolean isPerfectMatch(KeySequence keySequence) {
+		try {
+			final org.eclipse.jface.bindings.keys.KeySequence sequence = org.eclipse.jface.bindings.keys.KeySequence
+					.getInstance(keySequence.toString());
+			return bindingManager.isPerfectMatch(sequence);
+		} catch (final ParseException e) {
+			return false;
+		}
+	}
+
+	@Override
+	public void removeCommandManagerListener(
+			ICommandManagerListener commandManagerListener) {
+		if (commandManagerListener == null) {
+			throw new NullPointerException("Cannot remove a null listener"); //$NON-NLS-1$
+		}
+
+		if (commandManagerListeners != null) {
+			commandManagerListeners.remove(commandManagerListener);
+			if (commandManagerListeners.isEmpty()) {
+				commandManagerListeners = null;
+				this.commandManager.removeCommandManagerListener(this);
+				this.bindingManager.removeBindingManagerListener(this);
+				this.contextManager.removeContextManagerListener(this);
+			}
+		}
+	}
+
+	/**
+	 * Updates the handlers for a block of commands all at once.
+	 *
+	 * @param handlersByCommandId
+	 *            The map of command identifier (<code>String</code>) to
+	 *            handler (<code>IHandler</code>).
+	 */
+	public final void setHandlersByCommandId(final Map handlersByCommandId) {
+		// Wrap legacy handlers so they can be passed to the new API.
+		final Iterator entryItr = handlersByCommandId.entrySet().iterator();
+		while (entryItr.hasNext()) {
+			final Map.Entry entry = (Map.Entry) entryItr.next();
+			final Object handler = entry.getValue();
+			if (handler instanceof org.eclipse.ui.commands.IHandler) {
+				final String commandId = (String) entry.getKey();
+				handlersByCommandId.put(commandId, new LegacyHandlerWrapper(
+						(org.eclipse.ui.commands.IHandler) handler));
+			}
+		}
+
+		commandManager.setHandlersByCommandId(handlersByCommandId);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/CommandPersistence.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/CommandPersistence.java
new file mode 100644
index 0000000..bd9db96
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/CommandPersistence.java
@@ -0,0 +1,526 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.commands;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.eclipse.core.commands.AbstractParameterValueConverter;
+import org.eclipse.core.commands.Category;
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.CommandManager;
+import org.eclipse.core.commands.ParameterType;
+import org.eclipse.core.commands.State;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionDelta;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.IRegistryChangeEvent;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.e4.core.commands.internal.HandlerServiceImpl;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.ui.internal.workbench.Parameter;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.services.RegistryPersistence;
+import org.eclipse.ui.internal.util.PrefUtil;
+
+/**
+ * <p>
+ * A static class for accessing the registry and the preference store.
+ * </p>
+ *
+ * @since 3.1
+ */
+public final class CommandPersistence extends RegistryPersistence {
+
+	/**
+	 * The index of the category elements in the indexed array.
+	 *
+	 * @see CommandPersistence#read()
+	 */
+	private static final int INDEX_CATEGORY_DEFINITIONS = 0;
+
+	/**
+	 * The index of the command elements in the indexed array.
+	 *
+	 * @see CommandPersistence#read()
+	 */
+	private static final int INDEX_COMMAND_DEFINITIONS = 1;
+
+	/**
+	 * The index of the commandParameterType elements in the indexed array.
+	 *
+	 * @see CommandPersistence#read()
+	 * @since 3.2
+	 */
+	private static final int INDEX_PARAMETER_TYPE_DEFINITIONS = 2;
+
+    @Inject
+    private IEclipseContext context;
+
+
+	/**
+	 * Reads all of the category definitions from the commands extension point.
+	 *
+	 * @param configurationElements
+	 *            The configuration elements in the commands extension point;
+	 *            must not be <code>null</code>, but may be empty.
+	 * @param configurationElementCount
+	 *            The number of configuration elements that are really in the
+	 *            array.
+	 * @param commandManager
+	 *            The command service to which the categories should be added;
+	 *            must not be <code>null</code>.
+	 */
+	private static final void readCategoriesFromRegistry(
+			final IConfigurationElement[] configurationElements,
+			final int configurationElementCount, final CommandManager commandManager) {
+
+		Category undefCat = commandManager.getCategory(null);
+		if (!undefCat.isDefined()) {
+			// Define the uncategorized category.
+			commandManager.defineUncategorizedCategory(
+					WorkbenchMessages.get().CommandService_AutogeneratedCategoryName,
+					WorkbenchMessages.get().CommandService_AutogeneratedCategoryDescription);
+		}
+
+		final List warningsToLog = new ArrayList(1);
+
+		for (int i = 0; i < configurationElementCount; i++) {
+			final IConfigurationElement configurationElement = configurationElements[i];
+
+			// Read out the category identifier.
+			final String categoryId = readRequired(configurationElement,
+					ATT_ID, warningsToLog, "Categories need an id"); //$NON-NLS-1$
+			if (categoryId == null) {
+				continue;
+			}
+
+			// Read out the name.
+			final String name = readRequired(configurationElement, ATT_NAME,
+					warningsToLog, "Categories need a name", //$NON-NLS-1$
+					categoryId);
+			if (name == null) {
+				continue;
+			}
+
+			// Read out the description.
+			final String description = readOptional(configurationElement,
+					ATT_DESCRIPTION);
+
+			final Category category = commandManager.getCategory(categoryId);
+			if (!category.isDefined()) {
+				category.define(name, description);
+			}
+		}
+
+		// If there were any warnings, then log them now.
+		logWarnings(
+				warningsToLog,
+				"Warnings while parsing the commands from the 'org.eclipse.ui.commands' and 'org.eclipse.ui.actionDefinitions' extension points."); //$NON-NLS-1$
+	}
+
+	/**
+	 * Reads all of the command definitions from the commands extension point.
+	 *
+	 * @param configurationElements
+	 *            The configuration elements in the commands extension point;
+	 *            must not be <code>null</code>, but may be empty.
+	 * @param configurationElementCount
+	 *            The number of configuration elements that are really in the
+	 *            array.
+	 * @param commandManager
+	 *            The command service to which the commands should be added;
+	 *            must not be <code>null</code>.
+	 */
+	private final void readCommandsFromRegistry(
+			final IConfigurationElement[] configurationElements,
+			final int configurationElementCount, final CommandManager commandManager) {
+		final List warningsToLog = new ArrayList(1);
+
+		for (int i = 0; i < configurationElementCount; i++) {
+			final IConfigurationElement configurationElement = configurationElements[i];
+
+			// Read out the command identifier.
+			final String commandId = readRequired(configurationElement, ATT_ID,
+					warningsToLog, "Commands need an id"); //$NON-NLS-1$
+			if (commandId == null || commandId.startsWith("org.eclipse.ui.help")) {
+				continue;
+			}
+
+			// Read out the name.
+			final String name = readRequired(configurationElement, ATT_NAME,
+					warningsToLog, "Commands need a name"); //$NON-NLS-1$
+			if (name == null) {
+				continue;
+			}
+
+			// Read out the description.
+			final String description = readOptional(configurationElement,
+					ATT_DESCRIPTION);
+
+			// Read out the category id.
+			String categoryId = configurationElement
+					.getAttribute(ATT_CATEGORY_ID);
+			if ((categoryId == null) || (categoryId.length() == 0)) {
+				categoryId = configurationElement.getAttribute(ATT_CATEGORY);
+				if ((categoryId != null) && (categoryId.length() == 0)) {
+					categoryId = null;
+				}
+			}
+
+			// Read out the parameters.
+			final Parameter[] parameters = readParameters(configurationElement,
+					warningsToLog, commandManager);
+
+			// Read out the returnTypeId.
+			final String returnTypeId = readOptional(configurationElement,
+					ATT_RETURN_TYPE_ID);
+
+			// Read out the help context identifier.
+			final String helpContextId = readOptional(configurationElement,
+					ATT_HELP_CONTEXT_ID);
+
+			final Command command = commandManager.getCommand(commandId);
+			final Category category = commandManager.getCategory(categoryId);
+			if (!category.isDefined()) {
+				addWarning(
+						warningsToLog,
+						"Commands should really have a category", //$NON-NLS-1$
+						configurationElement, commandId,
+						"categoryId", categoryId); //$NON-NLS-1$
+			}
+
+			final ParameterType returnType;
+			if (returnTypeId == null) {
+				returnType = null;
+			} else {
+				returnType = commandManager.getParameterType(returnTypeId);
+			}
+
+			if (parameters != null && parameters.length > 0) {
+				command.undefine();
+			}
+			if (!command.isDefined()) {
+				command.define(name, description, category, parameters, returnType, helpContextId);
+				command.setHandler(HandlerServiceImpl.getHandler(commandId, context));
+			}
+			readState(configurationElement, warningsToLog, command);
+		}
+
+		// If there were any warnings, then log them now.
+		logWarnings(
+				warningsToLog,
+				"Warnings while parsing the commands from the 'org.eclipse.ui.commands' and 'org.eclipse.ui.actionDefinitions' extension points."); //$NON-NLS-1$
+	}
+
+	/**
+	 * Reads the parameters from a parent configuration element. This is used to
+	 * read the parameter sub-elements from a command element. Each parameter is
+	 * guaranteed to be valid. If invalid parameters are found, then a warning
+	 * status will be appended to the <code>warningsToLog</code> list.
+	 *
+	 * @param configurationElement
+	 *            The configuration element from which the parameters should be
+	 *            read; must not be <code>null</code>.
+	 * @param warningsToLog
+	 *            The list of warnings found during parsing. Warnings found
+	 *            while parsing the parameters will be appended to this list.
+	 *            This value must not be <code>null</code>.
+	 * @param commandManager
+	 *            The command service from which the parameter can get parameter
+	 *            types; must not be <code>null</code>.
+	 * @return The array of parameters found for this configuration element;
+	 *         <code>null</code> if none can be found.
+	 */
+	private static final Parameter[] readParameters(
+			final IConfigurationElement configurationElement, final List warningsToLog,
+			final CommandManager commandManager) {
+		final IConfigurationElement[] parameterElements = configurationElement
+				.getChildren(TAG_COMMAND_PARAMETER);
+		if ((parameterElements == null) || (parameterElements.length == 0)) {
+			return null;
+		}
+
+		int insertionIndex = 0;
+		Parameter[] parameters = new Parameter[parameterElements.length];
+		for (final IConfigurationElement parameterElement : parameterElements) {
+			// Read out the id
+			final String id = readRequired(parameterElement, ATT_ID,
+					warningsToLog, "Parameters need an id"); //$NON-NLS-1$
+			if (id == null) {
+				continue;
+			}
+
+			// Read out the name.
+			final String name = readRequired(parameterElement, ATT_NAME,
+					warningsToLog, "Parameters need a name"); //$NON-NLS-1$
+			if (name == null) {
+				continue;
+			}
+
+			/*
+			 * The IParameterValues will be initialized lazily as an
+			 * IExecutableExtension.
+			 */
+
+			// Read out the typeId attribute, if present.
+			final String typeId = readOptional(parameterElement, ATT_TYPE_ID);
+
+			// Read out the optional attribute, if present.
+			final boolean optional = readBoolean(parameterElement,
+					ATT_OPTIONAL, true);
+
+			final ParameterType type;
+			if (typeId == null) {
+				type = null;
+			} else {
+				type = commandManager.getParameterType(typeId);
+			}
+
+			final Parameter parameter = new Parameter(id, name,
+					parameterElement, type, optional);
+			parameters[insertionIndex++] = parameter;
+		}
+
+		if (insertionIndex != parameters.length) {
+			final Parameter[] compactedParameters = new Parameter[insertionIndex];
+			System.arraycopy(parameters, 0, compactedParameters, 0,
+					insertionIndex);
+			parameters = compactedParameters;
+		}
+
+		return parameters;
+	}
+
+	/**
+	 * Reads all of the commandParameterType definitions from the commands
+	 * extension point.
+	 *
+	 * @param configurationElements
+	 *            The configuration elements in the commands extension point;
+	 *            must not be <code>null</code>, but may be empty.
+	 * @param configurationElementCount
+	 *            The number of configuration elements that are really in the
+	 *            array.
+	 * @param commandManager
+	 *            The command service to which the commands should be added;
+	 *            must not be <code>null</code>.
+	 * @since 3.2
+	 */
+	private static final void readParameterTypesFromRegistry(
+			final IConfigurationElement[] configurationElements,
+			final int configurationElementCount, final CommandManager commandManager) {
+
+		final List warningsToLog = new ArrayList(1);
+
+		for (int i = 0; i < configurationElementCount; i++) {
+			final IConfigurationElement configurationElement = configurationElements[i];
+
+			// Read out the commandParameterType identifier.
+			final String parameterTypeId = readRequired(configurationElement,
+					ATT_ID, warningsToLog, "Command parameter types need an id"); //$NON-NLS-1$
+			if (parameterTypeId == null) {
+				continue;
+			}
+
+			// Read out the type.
+			final String type = readOptional(configurationElement, ATT_TYPE);
+
+			// Read out the converter.
+			final String converter = readOptional(configurationElement,
+					ATT_CONVERTER);
+
+			/*
+			 * if the converter attribute was given, create a proxy
+			 * AbstractParameterValueConverter for the ParameterType, otherwise
+			 * null indicates there is no converter
+			 */
+			final AbstractParameterValueConverter parameterValueConverter = (converter == null) ? null
+					: new ParameterValueConverterProxy(configurationElement);
+
+			final ParameterType parameterType = commandManager
+					.getParameterType(parameterTypeId);
+			if (!parameterType.isDefined()) {
+				parameterType.define(type, parameterValueConverter);
+			}
+		}
+
+		// If there were any warnings, then log them now.
+		logWarnings(
+				warningsToLog,
+				"Warnings while parsing the commandParameterTypes from the 'org.eclipse.ui.commands' extension point."); //$NON-NLS-1$
+
+	}
+
+	/**
+	 * Reads the states from a parent configuration element. This is used to
+	 * read the state sub-elements from a command element. Each state is
+	 * guaranteed to be valid. If invalid states are found, then a warning
+	 * status will be appended to the <code>warningsToLog</code> list.
+	 *
+	 * @param configurationElement
+	 *            The configuration element from which the states should be
+	 *            read; must not be <code>null</code>.
+	 * @param warningsToLog
+	 *            The list of warnings found during parsing. Warnings found
+	 *            while parsing the parameters will be appended to this list.
+	 *            This value must not be <code>null</code>.
+	 * @param command
+	 *            The command for which the state is being read; may be
+	 *            <code>null</code>.
+	 */
+	private static final void readState(
+			final IConfigurationElement configurationElement,
+			final List warningsToLog, final Command command) {
+		final IConfigurationElement[] stateElements = configurationElement
+				.getChildren(TAG_STATE);
+		if ((stateElements == null) || (stateElements.length == 0)) {
+			return;
+		}
+
+		for (final IConfigurationElement stateElement : stateElements) {
+			final String id = readRequired(stateElement, ATT_ID, warningsToLog, "State needs an id"); //$NON-NLS-1$
+			if (id == null) {
+				continue;
+			}
+
+			if (checkClass(stateElement, warningsToLog, "State must have an associated class", id)) { //$NON-NLS-1$
+				if (command.getState(id) == null) {
+					final State state = new CommandStateProxy(stateElement, ATT_CLASS,
+							PrefUtil.getInternalPreferenceStore(),
+							CommandService.createPreferenceKey(command, id));
+					command.addState(id, state);
+				}
+			}
+		}
+	}
+
+	/**
+	 * The command service with which this persistence class is associated;
+	 * never <code>null</code>.
+	 */
+	private final CommandManager commandManager;
+
+	/**
+	 * Constructs a new instance of <code>CommandPersistence</code>.
+	 *
+	 * @param commandService
+	 *            The command service which should be populated with the values
+	 *            from the registry; must not be <code>null</code>.
+	 */
+	public CommandPersistence(final CommandManager commandService) {
+		if (commandService == null) {
+			throw new NullPointerException("The command service cannot be null"); //$NON-NLS-1$
+		}
+		this.commandManager = commandService;
+	}
+
+	@Override
+	protected final boolean isChangeImportant(final IRegistryChangeEvent event) {
+		return false;
+	}
+
+	public boolean commandsNeedUpdating(final IRegistryChangeEvent event) {
+	    // RAP [bm]: 
+//      final IExtensionDelta[] commandDeltas = event.getExtensionDeltas(
+//              PlatformUI.PLUGIN_ID, IWorkbenchRegistryConstants.PL_COMMANDS);
+        final IExtensionDelta[] commandDeltas = event.getExtensionDeltas(
+                PlatformUI.PLUGIN_EXTENSION_NAME_SPACE, IWorkbenchRegistryConstants.PL_COMMANDS);
+        // RAPEND: [bm] 
+        if (commandDeltas.length == 0) {
+            // RAP [bm]: 
+//          final IExtensionDelta[] actionDefinitionDeltas = event
+//                  .getExtensionDeltas(PlatformUI.PLUGIN_ID,
+//                          IWorkbenchRegistryConstants.PL_ACTION_DEFINITIONS);
+            final IExtensionDelta[] actionDefinitionDeltas = event
+            .getExtensionDeltas(PlatformUI.PLUGIN_EXTENSION_NAME_SPACE,
+                    IWorkbenchRegistryConstants.PL_ACTION_DEFINITIONS);
+            // RAPEND: [bm] 
+            if (actionDefinitionDeltas.length == 0) {
+                return false;
+            }
+        }
+
+		return true;
+	}
+
+	/**
+	 * Reads all of the commands and categories from the registry,
+	 *
+	 * @param commandManager
+	 *            The command service which should be populated with the values
+	 *            from the registry; must not be <code>null</code>.
+	 */
+	@Override
+	protected final void read() {
+		super.read();
+		reRead();
+	}
+
+	public void reRead() {
+		// Create the extension registry mementos.
+		final IExtensionRegistry registry = Platform.getExtensionRegistry();
+		int commandDefinitionCount = 0;
+		int categoryDefinitionCount = 0;
+		int parameterTypeDefinitionCount = 0;
+		final IConfigurationElement[][] indexedConfigurationElements = new IConfigurationElement[3][];
+
+		// Sort the commands extension point based on element name.
+		final IConfigurationElement[] commandsExtensionPoint = registry
+				.getConfigurationElementsFor(EXTENSION_COMMANDS);
+		for (final IConfigurationElement configurationElement : commandsExtensionPoint) {
+			final String name = configurationElement.getName();
+
+			// Check if it is a binding definition.
+			if (TAG_COMMAND.equals(name)) {
+				addElementToIndexedArray(configurationElement,
+						indexedConfigurationElements,
+						INDEX_COMMAND_DEFINITIONS, commandDefinitionCount++);
+			} else if (TAG_CATEGORY.equals(name)) {
+				addElementToIndexedArray(configurationElement,
+						indexedConfigurationElements,
+						INDEX_CATEGORY_DEFINITIONS, categoryDefinitionCount++);
+			} else if (TAG_COMMAND_PARAMETER_TYPE.equals(name)) {
+				addElementToIndexedArray(configurationElement,
+						indexedConfigurationElements,
+						INDEX_PARAMETER_TYPE_DEFINITIONS,
+						parameterTypeDefinitionCount++);
+			}
+		}
+
+		final IConfigurationElement[] actionDefinitionsExtensionPoint = registry
+				.getConfigurationElementsFor(EXTENSION_ACTION_DEFINITIONS);
+		for (final IConfigurationElement configurationElement : actionDefinitionsExtensionPoint) {
+			final String name = configurationElement.getName();
+
+			if (TAG_ACTION_DEFINITION.equals(name)) {
+				addElementToIndexedArray(configurationElement,
+						indexedConfigurationElements,
+						INDEX_COMMAND_DEFINITIONS, commandDefinitionCount++);
+			}
+		}
+
+		readCategoriesFromRegistry(
+				indexedConfigurationElements[INDEX_CATEGORY_DEFINITIONS],
+				categoryDefinitionCount, commandManager);
+		readCommandsFromRegistry(
+				indexedConfigurationElements[INDEX_COMMAND_DEFINITIONS],
+				commandDefinitionCount, commandManager);
+		readParameterTypesFromRegistry(
+				indexedConfigurationElements[INDEX_PARAMETER_TYPE_DEFINITIONS],
+				parameterTypeDefinitionCount, commandManager);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/CommandService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/CommandService.java
new file mode 100644
index 0000000..25d7865
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/CommandService.java
@@ -0,0 +1,403 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.commands;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import org.eclipse.core.commands.Category;
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.CommandManager;
+import org.eclipse.core.commands.IExecutionListener;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.core.commands.ParameterType;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.commands.SerializationException;
+import org.eclipse.core.commands.State;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.e4.core.commands.internal.ICommandHelpService;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.ui.internal.workbench.renderers.swt.IUpdateService;
+import org.eclipse.e4.ui.model.application.ui.menu.MItem;
+import org.eclipse.e4.ui.workbench.IPresentationEngine;
+import org.eclipse.jface.commands.PersistentState;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.commands.IElementReference;
+import org.eclipse.ui.commands.IElementUpdater;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.menus.MenuHelper;
+import org.eclipse.ui.internal.util.PrefUtil;
+import org.eclipse.ui.menus.UIElement;
+
+/**
+ * <p>
+ * Provides services related to the command architecture within the workbench.
+ * This service can be used to access the set of commands and handlers.
+ * </p>
+ *
+ * @since 3.1
+ */
+public final class CommandService implements ICommandService, IUpdateService {
+
+	/**
+	 * The preference key prefix for all handler state.
+	 */
+	private static final String PREFERENCE_KEY_PREFIX = "org.eclipse.ui.commands/state"; //$NON-NLS-1$
+
+	/**
+	 * Creates a preference key for the given piece of state on the given
+	 * command.
+	 *
+	 * @param command
+	 *            The command for which the preference key should be created;
+	 *            must not be <code>null</code>.
+	 * @param stateId
+	 *            The identifier of the state for which the preference key
+	 *            should be created; must not be <code>null</code>.
+	 * @return A suitable preference key; never <code>null</code>.
+	 */
+	static final String createPreferenceKey(final Command command,
+			final String stateId) {
+		return PREFERENCE_KEY_PREFIX + '/' + command.getId() + '/' + stateId;
+	}
+
+	/**
+	 * The command manager that supports this service. This value is never
+	 * <code>null</code>.
+	 */
+	private final CommandManager commandManager;
+
+	/**
+	 * The persistence class for this command service.
+	 */
+	private final CommandPersistence commandPersistence;
+
+	private IEclipseContext context;
+
+	private ICommandHelpService commandHelpService;
+
+	/**
+	 * Constructs a new instance of <code>CommandService</code> using a
+	 * command manager.
+	 *
+	 * @param commandManager
+	 *            The command manager to use; must not be <code>null</code>.
+	 */
+	public CommandService(final CommandManager commandManager, IEclipseContext context) {
+		if (commandManager == null) {
+			throw new NullPointerException(
+					"Cannot create a command service with a null manager"); //$NON-NLS-1$
+		}
+		this.commandManager = commandManager;
+		this.commandPersistence = new CommandPersistence(commandManager);
+		this.context = context;
+		this.commandHelpService = context.get(ICommandHelpService.class);
+	}
+
+	@Override
+	public final void addExecutionListener(final IExecutionListener listener) {
+		commandManager.addExecutionListener(listener);
+	}
+
+	@Override
+	public final void defineUncategorizedCategory(final String name,
+			final String description) {
+		commandManager.defineUncategorizedCategory(name, description);
+	}
+
+	@Override
+	public final ParameterizedCommand deserialize(
+			final String serializedParameterizedCommand)
+			throws NotDefinedException, SerializationException {
+		return commandManager.deserialize(serializedParameterizedCommand);
+	}
+
+	@Override
+	public final void dispose() {
+		commandPersistence.dispose();
+
+		/*
+		 * All state on all commands neeeds to be disposed. This is so that the
+		 * state has a chance to persist any changes.
+		 */
+		final Command[] commands = commandManager.getAllCommands();
+		for (final Command command : commands) {
+			final String[] stateIds = command.getStateIds();
+			for (final String stateId : stateIds) {
+				final State state = command.getState(stateId);
+				if (state instanceof PersistentState) {
+					final PersistentState persistentState = (PersistentState) state;
+					if (persistentState.shouldPersist()) {
+						persistentState.save(PrefUtil
+								.getInternalPreferenceStore(),
+								createPreferenceKey(command, stateId));
+					}
+				}
+			}
+		}
+		commandCallbacks = null;
+	}
+
+	@Override
+	public final Category getCategory(final String categoryId) {
+		return commandManager.getCategory(categoryId);
+	}
+
+	@Override
+	public final Command getCommand(final String commandId) {
+		return commandManager.getCommand(commandId);
+	}
+
+	@Override
+	public final Category[] getDefinedCategories() {
+		return commandManager.getDefinedCategories();
+	}
+
+	@Override
+	public final Collection getDefinedCategoryIds() {
+		return commandManager.getDefinedCategoryIds();
+	}
+
+	@Override
+	public final Collection getDefinedCommandIds() {
+		return commandManager.getDefinedCommandIds();
+	}
+
+	@Override
+	public final Command[] getDefinedCommands() {
+		return commandManager.getDefinedCommands();
+	}
+
+	@Override
+	public Collection getDefinedParameterTypeIds() {
+		return commandManager.getDefinedParameterTypeIds();
+	}
+
+	@Override
+	public ParameterType[] getDefinedParameterTypes() {
+		return commandManager.getDefinedParameterTypes();
+	}
+
+	/**
+	 * @throws NotDefinedException
+	 *             if the given command is not defined
+	 */
+	@Override
+	public final String getHelpContextId(final Command command)
+			throws NotDefinedException {
+		return commandHelpService.getHelpContextId(command.getId(), context);
+	}
+
+	@Override
+	public final String getHelpContextId(final String commandId)
+			throws NotDefinedException {
+		final Command command = getCommand(commandId);
+		return getHelpContextId(command);
+	}
+
+	@Override
+	public ParameterType getParameterType(final String parameterTypeId) {
+		return commandManager.getParameterType(parameterTypeId);
+	}
+
+	@Override
+	public final void readRegistry() {
+		commandPersistence.reRead();
+	}
+
+	@Override
+	public final void removeExecutionListener(final IExecutionListener listener) {
+		commandManager.removeExecutionListener(listener);
+	}
+
+	@Override
+	public final void setHelpContextId(final IHandler handler, final String helpContextId) {
+		commandHelpService.setHelpContextId(handler, helpContextId);
+	}
+
+	/**
+	 * This is a map of commandIds to a list containing currently registered
+	 * callbacks, in the form of ICallbackReferences.
+	 */
+	private Map commandCallbacks = new HashMap();
+
+	@Override
+	public final void refreshElements(String commandId, Map filter) {
+		Command cmd = getCommand(commandId);
+
+		if (!cmd.isDefined() || !(cmd.getHandler() instanceof IElementUpdater)) {
+			return;
+		}
+		final IElementUpdater updater = (IElementUpdater) cmd.getHandler();
+
+		if (commandCallbacks == null) {
+			return;
+		}
+
+		List callbackRefs = (List) commandCallbacks.get(commandId);
+		if (callbackRefs == null) {
+			return;
+		}
+
+		for (Iterator i = callbackRefs.iterator(); i.hasNext();) {
+			final IElementReference callbackRef = (IElementReference) i.next();
+			final Map parms = Collections.unmodifiableMap(callbackRef
+					.getParameters());
+			ISafeRunnable run = new ISafeRunnable() {
+				@Override
+				public void handleException(Throwable exception) {
+					WorkbenchPlugin.log("Failed to update callback: "  //$NON-NLS-1$
+							+ callbackRef.getCommandId(), exception);
+				}
+
+				@Override
+				public void run() throws Exception {
+					updater.updateElement(callbackRef.getElement(), parms);
+				}
+			};
+			if (filter == null) {
+				SafeRunner.run(run);
+			} else {
+				boolean match = true;
+				for (Iterator j = filter.entrySet().iterator(); j.hasNext()
+						&& match;) {
+					Map.Entry parmEntry = (Map.Entry) j.next();
+					Object value = parms.get(parmEntry.getKey());
+					if (!parmEntry.getValue().equals(value)) {
+						match = false;
+					}
+				}
+				if (match) {
+					SafeRunner.run(run);
+				}
+			}
+		}
+	}
+
+	@Override
+	public final IElementReference registerElementForCommand(
+			ParameterizedCommand command, UIElement element)
+			throws NotDefinedException {
+		if (!command.getCommand().isDefined()) {
+			throw new NotDefinedException(
+					"Cannot define a callback for undefined command " //$NON-NLS-1$
+							+ command.getCommand().getId());
+		}
+		if (element == null) {
+			throw new NotDefinedException("No callback defined for command " //$NON-NLS-1$
+					+ command.getCommand().getId());
+		}
+
+		ElementReference ref = new ElementReference(command.getId(), element,
+				command.getParameterMap());
+		registerElement(ref);
+		return ref;
+	}
+
+	@Override
+	public void registerElement(IElementReference elementReference) {
+		List parameterizedCommands = (List) commandCallbacks
+				.get(elementReference.getCommandId());
+		if (parameterizedCommands == null) {
+			parameterizedCommands = new ArrayList();
+			commandCallbacks.put(elementReference.getCommandId(),
+					parameterizedCommands);
+		}
+		parameterizedCommands.add(elementReference);
+
+		// If the active handler wants to update the callback, it can do
+		// so now
+		Command command = getCommand(elementReference.getCommandId());
+		if (command.isDefined()) {
+			if (command.getHandler() instanceof IElementUpdater) {
+				((IElementUpdater) command.getHandler()).updateElement(
+						elementReference.getElement(), elementReference
+								.getParameters());
+			}
+		}
+	}
+
+	@Override
+	public void unregisterElement(IElementReference elementReference) {
+		if (commandCallbacks == null)
+			return;
+		List parameterizedCommands = (List) commandCallbacks
+				.get(elementReference.getCommandId());
+		if (parameterizedCommands != null) {
+			parameterizedCommands.remove(elementReference);
+			if (parameterizedCommands.isEmpty()) {
+				commandCallbacks.remove(elementReference.getCommandId());
+			}
+		}
+	}
+
+	/**
+	 * @return Returns the commandPersistence.
+	 */
+	public CommandPersistence getCommandPersistence() {
+		return commandPersistence;
+	}
+
+	@Override
+	public Runnable registerElementForUpdate(ParameterizedCommand parameterizedCommand,
+			final MItem item) {
+		UIElement element = new UIElement(context.get(IWorkbench.class)) {
+
+			@Override
+			public void setText(String text) {
+				item.setLabel(text);
+			}
+
+			@Override
+			public void setTooltip(String text) {
+				item.setTooltip(text);
+			}
+
+			@Override
+			public void setIcon(ImageDescriptor desc) {
+				item.setIconURI(MenuHelper.getIconURI(desc, context));
+			}
+
+			@Override
+			public void setDisabledIcon(ImageDescriptor desc) {
+				item.getTransientData().put(IPresentationEngine.DISABLED_ICON_IMAGE_KEY,
+						MenuHelper.getIconURI(desc, context));
+			}
+
+			@Override
+			public void setHoverIcon(ImageDescriptor desc) {
+				// ignored
+			}
+
+			@Override
+			public void setChecked(boolean checked) {
+				item.setSelected(checked);
+			}
+		};
+
+		try {
+			final IElementReference reference = registerElementForCommand(parameterizedCommand,
+					element);
+			return () -> unregisterElement(reference);
+		} catch (NotDefinedException e) {
+			WorkbenchPlugin.log(e);
+		}
+		return null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/CommandServiceFactory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/CommandServiceFactory.java
new file mode 100644
index 0000000..050d233
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/CommandServiceFactory.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ ******************************************************************************/
+
+package org.eclipse.ui.internal.commands;
+
+import org.eclipse.e4.ui.model.application.ui.MContext;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.internal.services.IWorkbenchLocationService;
+import org.eclipse.ui.services.AbstractServiceFactory;
+import org.eclipse.ui.services.IServiceLocator;
+import org.eclipse.ui.services.IServiceScopes;
+
+/**
+ * @since 3.4
+ *
+ */
+public class CommandServiceFactory extends AbstractServiceFactory {
+
+	@Override
+	public Object create(Class serviceInterface, IServiceLocator parentLocator,
+			IServiceLocator locator) {
+		if (!ICommandService.class.equals(serviceInterface)) {
+			return null;
+		}
+		IWorkbenchLocationService wls = locator
+				.getService(IWorkbenchLocationService.class);
+		final IWorkbench wb = wls.getWorkbench();
+		if (wb == null) {
+			return null;
+		}
+
+		Object parent = parentLocator.getService(serviceInterface);
+		if (parent == null) {
+			// we are registering the global services in the Workbench
+			return null;
+		}
+		final IWorkbenchWindow window = wls.getWorkbenchWindow();
+		final IWorkbenchPartSite site = wls.getPartSite();
+
+		if (site == null) {
+			return new SlaveCommandService((ICommandService) parent,
+					IServiceScopes.WINDOW_SCOPE, window);
+		}
+
+		if (parent instanceof SlaveCommandService) {
+			IServiceLocator pageSite = wls.getPageSite();
+			if (pageSite != null) {
+				MContext context = pageSite.getService(MContext.class);
+				if (context == null) {
+					return new SlaveCommandService((ICommandService) parent,
+							IServiceScopes.PAGESITE_SCOPE, pageSite);
+				}
+				return new SlaveCommandService((ICommandService) parent,
+						IServiceScopes.PAGESITE_SCOPE, pageSite, context.getContext());
+			}
+			IServiceLocator mpepSite = wls.getMultiPageEditorSite();
+			if (mpepSite != null) {
+				MContext context = mpepSite.getService(MContext.class);
+				if (context == null) {
+					return new SlaveCommandService((ICommandService) parent,
+							IServiceScopes.MPESITE_SCOPE, mpepSite);
+				}
+				return new SlaveCommandService((ICommandService) parent,
+						IServiceScopes.MPESITE_SCOPE, mpepSite, context.getContext());
+			}
+		}
+
+		return new SlaveCommandService((ICommandService) parent,
+				IServiceScopes.PARTSITE_SCOPE, site);
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/CommandStateProxy.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/CommandStateProxy.java
new file mode 100644
index 0000000..21fad9e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/CommandStateProxy.java
@@ -0,0 +1,279 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.commands;
+
+import org.eclipse.core.commands.IStateListener;
+import org.eclipse.core.commands.State;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.commands.PersistentState;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+
+/**
+ * <p>
+ * A proxy for handler state that has been defined in XML. This delays the class
+ * loading until the state is really asked for information. Asking a proxy for
+ * anything (except disposing, and adding and removing listeners) will cause the
+ * proxy to instantiate the proxied handler.
+ * </p>
+ * <p>
+ * Loading the proxied state will automatically cause it to load its value from
+ * the preference store. Disposing of the state will cause it to persist its
+ * value.
+ * </p>
+ * <p>
+ * This class is not intended for use outside of the
+ * <code>org.eclipse.ui.workbench</code> plug-in.
+ * </p>
+ *
+ * @since 3.2
+ */
+public final class CommandStateProxy extends PersistentState {
+
+	/**
+	 * The configuration element from which the state can be created. This value
+	 * will exist until the element is converted into a real class -- at which
+	 * point this value will be set to <code>null</code>.
+	 */
+	private IConfigurationElement configurationElement;
+
+	/**
+	 * The key in the preference store to locate the persisted state.
+	 */
+	private String preferenceKey;
+
+	/**
+	 * The preference store containing the persisted state, if any.
+	 */
+	private IPreferenceStore preferenceStore;
+
+	/**
+	 * The real state. This value is <code>null</code> until the proxy is
+	 * forced to load the real state. At this point, the configuration element
+	 * is converted, nulled out, and this state gains a reference.
+	 */
+	private State state = null;
+
+	/**
+	 * The name of the configuration element attribute which contains the
+	 * information necessary to instantiate the real state.
+	 */
+	private final String stateAttributeName;
+
+	/**
+	 * Constructs a new instance of <code>HandlerState</code> with all the
+	 * information it needs to create the real state later.
+	 *
+	 * @param configurationElement
+	 *            The configuration element from which the real class can be
+	 *            loaded at run-time; must not be <code>null</code>.
+	 * @param stateAttributeName
+	 *            The name of the attribute or element containing the state
+	 *            executable extension; must not be <code>null</code>.
+	 * @param preferenceStore
+	 *            The preference store to which any persistent data should be
+	 *            written, and from which it should be loaded; may be
+	 *            <code>null</code>.
+	 * @param preferenceKey
+	 *            The key at which the persistent data is located within the
+	 *            preference store.
+	 */
+	public CommandStateProxy(final IConfigurationElement configurationElement,
+			final String stateAttributeName,
+			final IPreferenceStore preferenceStore, final String preferenceKey) {
+
+		if (configurationElement == null) {
+			throw new NullPointerException(
+					"The configuration element backing a state proxy cannot be null"); //$NON-NLS-1$
+		}
+
+		if (stateAttributeName == null) {
+			throw new NullPointerException(
+					"The attribute containing the state class must be known"); //$NON-NLS-1$
+		}
+
+		this.configurationElement = configurationElement;
+		this.stateAttributeName = stateAttributeName;
+		this.preferenceKey = preferenceKey;
+		this.preferenceStore = preferenceStore;
+	}
+
+	@Override
+	public final void addListener(final IStateListener listener) {
+		if (state == null) {
+			addListenerObject(listener);
+		} else {
+			state.addListener(listener);
+		}
+	}
+
+	@Override
+	public final void dispose() {
+		if (state != null) {
+			state.dispose();
+			if (state instanceof PersistentState) {
+				final PersistentState persistableState = (PersistentState) state;
+				if (persistableState.shouldPersist() && preferenceStore != null
+						&& preferenceKey != null) {
+					persistableState.save(preferenceStore, preferenceKey);
+				}
+			}
+		}
+	}
+
+	@Override
+	public final Object getValue() {
+		if (loadState()) {
+			return state.getValue();
+		}
+
+		return null;
+	}
+
+	@Override
+	public final void load(final IPreferenceStore store,
+			final String preferenceKey) {
+		if (loadState() && state instanceof PersistentState) {
+			final PersistentState persistableState = (PersistentState) state;
+			if (persistableState.shouldPersist() && preferenceStore != null
+					&& preferenceKey != null) {
+				persistableState.load(preferenceStore, preferenceKey);
+			}
+		}
+	}
+
+	/**
+	 * Loads the state, if possible. If the state is loaded, then the member
+	 * variables are updated accordingly and the state is told to load its value
+	 * from the preference store.
+	 *
+	 * @return <code>true</code> if the state is now non-null;
+	 *         <code>false</code> otherwise.
+	 */
+	private final boolean loadState() {
+		return loadState(false);
+	}
+
+	/**
+	 * Loads the state, if possible. If the state is loaded, then the member
+	 * variables are updated accordingly and the state is told to load its value
+	 * from the preference store.
+	 *
+	 * @param readPersistence
+	 *            Whether the persistent state for this object should be read.
+	 * @return <code>true</code> if the state is now non-null;
+	 *         <code>false</code> otherwise.
+	 */
+	private final boolean loadState(final boolean readPersistence) {
+		if (state == null) {
+			try {
+				state = (State) configurationElement
+						.createExecutableExtension(stateAttributeName);
+				state.setId(getId());
+				configurationElement = null;
+
+				// Try to load the persistent state, if possible.
+				if (readPersistence && state instanceof PersistentState) {
+					final PersistentState persistentState = (PersistentState) state;
+					persistentState.setShouldPersist(true);
+				}
+				load(preferenceStore, preferenceKey);
+
+				// Transfer the local listeners to the real state.
+				final Object[] listenerArray = getListeners();
+				for (Object element : listenerArray) {
+					state.addListener((IStateListener) element);
+				}
+				clearListeners();
+
+				return true;
+
+			} catch (final ClassCastException e) {
+				final String message = "The proxied state was the wrong class"; //$NON-NLS-1$
+				final IStatus status = new Status(IStatus.ERROR,
+						WorkbenchPlugin.PI_WORKBENCH, 0, message, e);
+				WorkbenchPlugin.log(message, status);
+				return false;
+
+			} catch (final CoreException e) {
+				final String message = "The proxied state for '" + configurationElement.getAttribute(stateAttributeName) //$NON-NLS-1$
+						+ "' could not be loaded"; //$NON-NLS-1$
+				IStatus status = new Status(IStatus.ERROR,
+						WorkbenchPlugin.PI_WORKBENCH, 0, message, e);
+				WorkbenchPlugin.log(message, status);
+				return false;
+			}
+		}
+
+		return true;
+	}
+
+	@Override
+	public final void removeListener(final IStateListener listener) {
+		if (state == null) {
+			removeListenerObject(listener);
+		} else {
+			state.removeListener(listener);
+		}
+	}
+
+	@Override
+	public final void save(final IPreferenceStore store,
+			final String preferenceKey) {
+		if (loadState() && state instanceof PersistentState) {
+			((PersistentState) state).save(store, preferenceKey);
+		}
+	}
+
+	@Override
+	public final void setId(final String id) {
+		super.setId(id);
+		if (state != null) {
+			state.setId(id);
+		}
+	}
+
+	@Override
+	public final void setShouldPersist(final boolean persisted) {
+		if (loadState(persisted) && state instanceof PersistentState) {
+			((PersistentState) state).setShouldPersist(persisted);
+		}
+	}
+
+	@Override
+	public final void setValue(final Object value) {
+		if (loadState()) {
+			state.setValue(value);
+		}
+	}
+
+	@Override
+	public final boolean shouldPersist() {
+		if (loadState() && state instanceof PersistentState) {
+			return ((PersistentState) state).shouldPersist();
+		}
+
+		return false;
+	}
+
+	@Override
+	public final String toString() {
+		if (state == null) {
+			return configurationElement.getAttribute(stateAttributeName);
+		}
+
+		return state.toString();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/ElementReference.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/ElementReference.java
new file mode 100644
index 0000000..ce21506
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/ElementReference.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal.commands;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.ui.commands.IElementReference;
+import org.eclipse.ui.menus.UIElement;
+
+/**
+ * Our element reference that is used during element
+ * registration/unregistration.
+ *
+ * @since 3.3
+ */
+public class ElementReference implements IElementReference {
+
+	private String commandId;
+	private UIElement element;
+	private HashMap parameters;
+
+	/**
+	 * Construct the reference.
+	 *
+	 * @param id
+	 *            command id. Must not be <code>null</code>.
+	 * @param adapt
+	 *            the element. Must not be <code>null</code>.
+	 * @param parms.
+	 *            parameters used for filtering. Must not be <code>null</code>.
+	 */
+	public ElementReference(String id, UIElement adapt, Map parms) {
+		commandId = id;
+		element = adapt;
+		if (parms == null) {
+			parameters = new HashMap();
+		} else {
+			parameters = new HashMap(parms);
+		}
+	}
+
+	@Override
+	public UIElement getElement() {
+		return element;
+	}
+
+	@Override
+	public String getCommandId() {
+		return commandId;
+	}
+
+	@Override
+	public Map getParameters() {
+		return parameters;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/ICommandImageManagerListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/ICommandImageManagerListener.java
new file mode 100644
index 0000000..cdf4ad7
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/ICommandImageManagerListener.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.commands;
+
+/**
+ * <p>
+ * An instance of this interface can be used by clients to receive notification
+ * of changes to one or more instances of <code>CommandImageManager</code>.
+ * </p>
+ * <p>
+ * Clients may instantiate, but must not extend.
+ * </p>
+ * <p>
+ * <strong>PROVISIONAL</strong>. This class or interface has been added as
+ * part of a work in progress. There is a guarantee neither that this API will
+ * work nor that it will remain the same. Please do not use this API without
+ * consulting with the Platform/UI team.
+ * </p>
+ * <p>
+ * This class is eventually intended to exist in
+ * <code>org.eclipse.jface.commands</code>.
+ * </p>
+ *
+ * @since 3.2
+ */
+public interface ICommandImageManagerListener {
+
+	/**
+	 * Notifies that one or more properties of an instance of
+	 * <code>CommandImageManager</code> have changed. Specific details are
+	 * described in the <code>CommandImageManagerEvent</code>.
+	 *
+	 * @param event
+	 *            The event; never <code>null</code>.
+	 */
+	void commandImageManagerChanged(CommandImageManagerEvent event);
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/ILegacyAttributeNames.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/ILegacyAttributeNames.java
new file mode 100644
index 0000000..33709a5
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/ILegacyAttributeNames.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.commands;
+
+import org.eclipse.jface.action.IAction;
+
+/**
+ * This defines attribute names that were understood in Eclipse 3.0. This is
+ * used to provide legacy support for the attribute map property.
+ *
+ * @since 3.1
+ */
+public interface ILegacyAttributeNames {
+
+	/**
+	 * Whether the handler is capable of executing right now.
+	 */
+	public final String ENABLED = IAction.ENABLED;
+
+	/**
+	 * Whether the handler is capable of handling delegation of responsibilities
+	 * at this time.
+	 */
+	public final String HANDLED = IAction.HANDLED;
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/LegacyCommandListenerWrapper.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/LegacyCommandListenerWrapper.java
new file mode 100644
index 0000000..a89c088
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/LegacyCommandListenerWrapper.java
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.commands;
+
+import org.eclipse.core.commands.CommandEvent;
+import org.eclipse.core.commands.ICommandListener;
+import org.eclipse.jface.bindings.BindingManager;
+import org.eclipse.ui.commands.ICommand;
+
+/**
+ * Wraps a legacy listener in a new listener interface. This simply forwards
+ * incoming events through to the old interface.
+ *
+ * @since 3.1
+ */
+final class LegacyCommandListenerWrapper implements ICommandListener {
+
+	/**
+	 * The supporting binding manager; never <code>null</code>.
+	 */
+	private final BindingManager bindingManager;
+
+	/**
+	 * The listener which is being wrapped. This value should never be
+	 * <code>null</code>.
+	 */
+	private final org.eclipse.ui.commands.ICommandListener listener;
+
+	/**
+	 * Constructs a new instance of <code>CommandListenerWrapper</code> around
+	 * a legacy listener.
+	 *
+	 * @param listener
+	 *            The listener to be wrapped; must not be <code>null</code>.
+	 */
+	LegacyCommandListenerWrapper(
+			final org.eclipse.ui.commands.ICommandListener listener,
+			final BindingManager bindingManager) {
+		if (listener == null) {
+			throw new NullPointerException("Cannot wrap a null listener."); //$NON-NLS-1$
+		}
+
+		if (bindingManager == null) {
+			throw new NullPointerException(
+					"Cannot create a listener wrapper without a binding manager"); //$NON-NLS-1$
+		}
+
+		this.listener = listener;
+		this.bindingManager = bindingManager;
+	}
+
+	@Override
+	public final void commandChanged(final CommandEvent commandEvent) {
+		final ICommand command = new CommandLegacyWrapper(commandEvent.getCommand(),
+				bindingManager);
+		final boolean definedChanged = commandEvent.isDefinedChanged();
+		final boolean descriptionChanged = commandEvent.isDescriptionChanged();
+		final boolean handledChanged = commandEvent.isHandledChanged();
+		final boolean nameChanged = commandEvent.isNameChanged();
+
+		listener.commandChanged(new org.eclipse.ui.commands.CommandEvent(
+				command, false, false, definedChanged, descriptionChanged,
+				handledChanged, false, nameChanged, null));
+
+	}
+
+	@Override
+	public final boolean equals(final Object object) {
+		if (object instanceof LegacyCommandListenerWrapper) {
+			final LegacyCommandListenerWrapper wrapper = (LegacyCommandListenerWrapper) object;
+			return listener.equals(wrapper.listener);
+		}
+
+		if (object instanceof org.eclipse.ui.commands.ICommandListener) {
+			final org.eclipse.ui.commands.ICommandListener other = (org.eclipse.ui.commands.ICommandListener) object;
+			return listener.equals(other);
+		}
+
+		return false;
+	}
+
+	@Override
+	public final int hashCode() {
+		return listener.hashCode();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/ParameterValueConverterProxy.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/ParameterValueConverterProxy.java
new file mode 100644
index 0000000..22e9412
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/ParameterValueConverterProxy.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.commands;
+
+import org.eclipse.core.commands.AbstractParameterValueConverter;
+import org.eclipse.core.commands.ParameterValueConversionException;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+
+/**
+ * A proxy for a parameter value converter that has been defined in the regisry.
+ * This delays the class loading until the converter is really asked to do
+ * string/object conversions.
+ *
+ * @since 3.2
+ */
+public final class ParameterValueConverterProxy extends
+		AbstractParameterValueConverter {
+
+	/**
+	 * The configuration element providing the executable extension that will
+	 * extend <code>AbstractParameterValueConverter</code>. This value will
+	 * not be <code>null</code>.
+	 */
+	private final IConfigurationElement converterConfigurationElement;
+
+	/**
+	 * The real parameter value converter instance. This will be
+	 * <code>null</code> until one of the conversion methods are used.
+	 */
+	private AbstractParameterValueConverter parameterValueConverter;
+
+	/**
+	 * Constructs a <code>ParameterValueConverterProxy</code> to represent the
+	 * real converter until it is needed.
+	 *
+	 * @param converterConfigurationElement
+	 *            The configuration element from which the real converter can be
+	 *            loaded.
+	 */
+	public ParameterValueConverterProxy(
+			final IConfigurationElement converterConfigurationElement) {
+		if (converterConfigurationElement == null) {
+			throw new NullPointerException(
+					"converterConfigurationElement must not be null"); //$NON-NLS-1$
+		}
+
+		this.converterConfigurationElement = converterConfigurationElement;
+	}
+
+	@Override
+	public final Object convertToObject(final String parameterValue)
+			throws ParameterValueConversionException {
+		return getConverter().convertToObject(parameterValue);
+	}
+
+	@Override
+	public final String convertToString(final Object parameterValue)
+			throws ParameterValueConversionException {
+		return getConverter().convertToString(parameterValue);
+	}
+
+	/**
+	 * Returns the real parameter value converter for this proxy or throws an
+	 * exception indicating the converter could not be obtained.
+	 *
+	 * @return the real converter for this proxy; never <code>null</code>.
+	 * @throws ParameterValueConversionException
+	 *             if the converter could not be obtained
+	 */
+	private AbstractParameterValueConverter getConverter()
+			throws ParameterValueConversionException {
+		if (parameterValueConverter == null) {
+			try {
+				parameterValueConverter = (AbstractParameterValueConverter) converterConfigurationElement
+						.createExecutableExtension(IWorkbenchRegistryConstants.ATT_CONVERTER);
+			} catch (final CoreException e) {
+				throw new ParameterValueConversionException(
+						"Problem creating parameter value converter", e); //$NON-NLS-1$
+			} catch (final ClassCastException e) {
+				throw new ParameterValueConversionException(
+						"Parameter value converter was not a subclass of AbstractParameterValueConverter", e); //$NON-NLS-1$
+			}
+		}
+		return parameterValueConverter;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/SlaveCommandService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/SlaveCommandService.java
new file mode 100644
index 0000000..0ffbe07
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/SlaveCommandService.java
@@ -0,0 +1,298 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.commands;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import org.eclipse.core.commands.Category;
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.IExecutionListener;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.core.commands.ParameterType;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.commands.SerializationException;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.ui.internal.workbench.renderers.swt.IUpdateService;
+import org.eclipse.e4.ui.model.application.ui.menu.MItem;
+import org.eclipse.e4.ui.workbench.IPresentationEngine;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.commands.IElementReference;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.menus.MenuHelper;
+import org.eclipse.ui.menus.UIElement;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * A command service which delegates almost all responsibility to the parent
+ * service.
+ * <p>
+ * This class is not intended for use outside of the
+ * <code>org.eclipse.ui.workbench</code> plug-in.
+ * </p>
+ *
+ * @since 3.2
+ */
+public class SlaveCommandService implements ICommandService, IUpdateService {
+
+	private Collection fExecutionListeners = new ArrayList();
+
+	/**
+	 * The collection of ICallbackReferences added through this service.
+	 *
+	 * @since 3.3
+	 */
+	private Set fCallbackCache = new HashSet();
+
+	private ICommandService fParentService;
+
+	/**
+	 * The scoping constant added to callback registrations submitted through
+	 * this service.
+	 *
+	 * @since 3.3
+	 */
+	private String fScopingName;
+
+	/**
+	 * The object to scope. In theory, the service locator that would find this
+	 * service.
+	 *
+	 * @since 3.3
+	 */
+	private IServiceLocator fScopingValue;
+
+	private IEclipseContext fContext;
+
+	/**
+	 * Build the slave service.
+	 *
+	 * @param parent
+	 *            the parent service. This must not be <code>null</code>.
+	 */
+	public SlaveCommandService(ICommandService parent, String scopeName, IServiceLocator scopeValue) {
+		this(parent, scopeName, scopeValue, null);
+	}
+
+	public SlaveCommandService(ICommandService parent, String scopeName,
+			IServiceLocator scopeValue,
+			IEclipseContext context) {
+		if (parent == null) {
+			throw new NullPointerException(
+					"The parent command service must not be null"); //$NON-NLS-1$
+		}
+		fParentService = parent;
+		fScopingName = scopeName;
+		fScopingValue = scopeValue;
+		fContext = context;
+	}
+
+	@Override
+	public void addExecutionListener(IExecutionListener listener) {
+		if (!fExecutionListeners.contains(listener)) {
+			fExecutionListeners.add(listener);
+		}
+		fParentService.addExecutionListener(listener);
+	}
+
+	@Override
+	public void defineUncategorizedCategory(String name, String description) {
+		fParentService.defineUncategorizedCategory(name, description);
+	}
+
+	@Override
+	public ParameterizedCommand deserialize(
+			String serializedParameterizedCommand) throws NotDefinedException,
+			SerializationException {
+		return fParentService.deserialize(serializedParameterizedCommand);
+	}
+
+	@Override
+	public void dispose() {
+		if (!fExecutionListeners.isEmpty()) {
+			Object[] array = fExecutionListeners.toArray();
+			for (Object element : array) {
+				removeExecutionListener((IExecutionListener) element);
+			}
+			fExecutionListeners.clear();
+		}
+		if (!fCallbackCache.isEmpty()) {
+			Object[] array = fCallbackCache.toArray();
+			for (Object element : array) {
+				unregisterElement((IElementReference) element);
+			}
+		}
+	}
+
+	@Override
+	public Category getCategory(String categoryId) {
+		return fParentService.getCategory(categoryId);
+	}
+
+	@Override
+	public Command getCommand(String commandId) {
+		return fParentService.getCommand(commandId);
+	}
+
+	@Override
+	public Category[] getDefinedCategories() {
+		return fParentService.getDefinedCategories();
+	}
+
+	@Override
+	public Collection getDefinedCategoryIds() {
+		return fParentService.getDefinedCategoryIds();
+	}
+
+	@Override
+	public Collection getDefinedCommandIds() {
+		return fParentService.getDefinedCommandIds();
+	}
+
+	@Override
+	public Command[] getDefinedCommands() {
+		return fParentService.getDefinedCommands();
+	}
+
+	@Override
+	public Collection getDefinedParameterTypeIds() {
+		return fParentService.getDefinedParameterTypeIds();
+	}
+
+	@Override
+	public ParameterType[] getDefinedParameterTypes() {
+		return fParentService.getDefinedParameterTypes();
+	}
+
+	@Override
+	public final String getHelpContextId(final Command command)
+			throws NotDefinedException {
+		return fParentService.getHelpContextId(command);
+	}
+
+	@Override
+	public final String getHelpContextId(final String commandId)
+			throws NotDefinedException {
+		return fParentService.getHelpContextId(commandId);
+	}
+
+	@Override
+	public ParameterType getParameterType(String parameterTypeId) {
+		return fParentService.getParameterType(parameterTypeId);
+	}
+
+	@Override
+	public void readRegistry() {
+		fParentService.readRegistry();
+	}
+
+	@Override
+	public void removeExecutionListener(IExecutionListener listener) {
+		fExecutionListeners.remove(listener);
+		fParentService.removeExecutionListener(listener);
+	}
+
+	@Override
+	public final void setHelpContextId(final IHandler handler,
+			final String helpContextId) {
+		fParentService.setHelpContextId(handler, helpContextId);
+	}
+
+	@Override
+	public void refreshElements(String commandId, Map filter) {
+		fParentService.refreshElements(commandId, filter);
+	}
+
+	@Override
+	public IElementReference registerElementForCommand(
+			ParameterizedCommand command, UIElement element)
+			throws NotDefinedException {
+		if (!command.getCommand().isDefined()) {
+			throw new NotDefinedException(
+					"Cannot define a callback for undefined command " //$NON-NLS-1$
+							+ command.getCommand().getId());
+		}
+		if (element == null) {
+			throw new NotDefinedException("No callback defined for command " //$NON-NLS-1$
+					+ command.getCommand().getId());
+		}
+
+		ElementReference ref = new ElementReference(command.getId(), element,
+				command.getParameterMap());
+		registerElement(ref);
+		return ref;
+	}
+
+	@Override
+	public void registerElement(IElementReference elementReference) {
+		fCallbackCache.add(elementReference);
+		elementReference.getParameters().put(fScopingName, fScopingValue);
+		fParentService.registerElement(elementReference);
+	}
+
+	@Override
+	public void unregisterElement(IElementReference elementReference) {
+		fCallbackCache.remove(elementReference);
+		fParentService.unregisterElement(elementReference);
+	}
+
+	@Override
+	public Runnable registerElementForUpdate(ParameterizedCommand parameterizedCommand,
+			final MItem item) {
+		UIElement element = new UIElement(fScopingValue) {
+
+			@Override
+			public void setText(String text) {
+				item.setLabel(text);
+			}
+
+			@Override
+			public void setTooltip(String text) {
+				item.setTooltip(text);
+			}
+
+			@Override
+			public void setIcon(ImageDescriptor desc) {
+				item.setIconURI(MenuHelper.getIconURI(desc, fContext));
+			}
+
+			@Override
+			public void setDisabledIcon(ImageDescriptor desc) {
+				item.getTransientData().put(IPresentationEngine.DISABLED_ICON_IMAGE_KEY,
+						MenuHelper.getIconURI(desc, fContext));
+			}
+
+			@Override
+			public void setHoverIcon(ImageDescriptor desc) {
+				// ignored
+			}
+
+			@Override
+			public void setChecked(boolean checked) {
+				item.setSelected(checked);
+			}
+		};
+
+		try {
+			final IElementReference reference = registerElementForCommand(parameterizedCommand,
+					element);
+			return () -> unregisterElement(reference);
+		} catch (NotDefinedException e) {
+			WorkbenchPlugin.log(e);
+		}
+		return null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/WorkbenchCommandSupport.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/WorkbenchCommandSupport.java
new file mode 100644
index 0000000..526806d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/commands/WorkbenchCommandSupport.java
@@ -0,0 +1,139 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.internal.commands;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import org.eclipse.core.commands.CommandManager;
+import org.eclipse.core.commands.contexts.ContextManager;
+import org.eclipse.jface.bindings.BindingManager;
+import org.eclipse.ui.LegacyHandlerSubmissionExpression;
+import org.eclipse.ui.commands.HandlerSubmission;
+import org.eclipse.ui.commands.ICommandManager;
+import org.eclipse.ui.commands.IWorkbenchCommandSupport;
+import org.eclipse.ui.handlers.IHandlerActivation;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.internal.handlers.LegacyHandlerWrapper;
+
+/**
+ * Provides command support in terms of the workbench.
+ *
+ * @since 3.0
+ */
+public class WorkbenchCommandSupport implements IWorkbenchCommandSupport {
+
+	/**
+	 * The map of activations that have been given to the handler service (<code>IHandlerActivation</code>),
+	 * indexed by the submissions (<code>HandlerSubmission</code>). This map
+	 * should be <code>null</code> if there are no such activations.
+	 */
+	private Map activationsBySubmission = null;
+
+	/**
+	 * The mutable command manager that should be notified of changes to the
+	 * list of active handlers. This value is never <code>null</code>.
+	 */
+	private final CommandManagerLegacyWrapper commandManagerWrapper;
+
+	/**
+	 * The handler service for the workbench. This value is never
+	 * <code>null</code>.
+	 */
+	private final IHandlerService handlerService;
+
+	/**
+	 * Constructs a new instance of <code>WorkbenchCommandSupport</code>
+	 *
+	 * @param bindingManager
+	 *            The binding manager providing support for the command manager;
+	 *            must not be <code>null</code>.
+	 * @param commandManager
+	 *            The command manager for the workbench; must not be
+	 *            <code>null</code>.
+	 * @param contextManager
+	 *            The context manager providing support for the command manager
+	 *            and binding manager; must not be <code>null</code>.
+	 * @param handlerService
+	 *            The handler service for the workbench; must not be
+	 *            <code>null</code>.
+	 */
+	public WorkbenchCommandSupport(final BindingManager bindingManager,
+			final CommandManager commandManager,
+			final ContextManager contextManager,
+			final IHandlerService handlerService) {
+		if (handlerService == null) {
+			throw new NullPointerException("The handler service cannot be null"); //$NON-NLS-1$
+		}
+
+		this.handlerService = handlerService;
+
+		commandManagerWrapper = CommandManagerFactory.getCommandManagerWrapper(
+				bindingManager, commandManager, contextManager);
+
+		// Initialize the old key formatter settings.
+		org.eclipse.ui.keys.KeyFormatterFactory
+				.setDefault(org.eclipse.ui.keys.SWTKeySupport
+						.getKeyFormatterForPlatform());
+	}
+
+	@Override
+	public final void addHandlerSubmission(
+			final HandlerSubmission handlerSubmission) {
+		final IHandlerActivation activation = handlerService.activateHandler(
+				handlerSubmission.getCommandId(), new LegacyHandlerWrapper(
+						handlerSubmission.getHandler()),
+				new LegacyHandlerSubmissionExpression(handlerSubmission
+						.getActivePartId(), handlerSubmission.getActiveShell(),
+						handlerSubmission.getActiveWorkbenchPartSite()));
+		if (activationsBySubmission == null) {
+			activationsBySubmission = new HashMap();
+		}
+		activationsBySubmission.put(handlerSubmission, activation);
+	}
+
+	@Override
+	public final void addHandlerSubmissions(final Collection handlerSubmissions) {
+		final Iterator submissionItr = handlerSubmissions.iterator();
+		while (submissionItr.hasNext()) {
+			addHandlerSubmission((HandlerSubmission) submissionItr.next());
+		}
+	}
+
+	@Override
+	public ICommandManager getCommandManager() {
+		return commandManagerWrapper;
+	}
+
+	@Override
+	public final void removeHandlerSubmission(
+			final HandlerSubmission handlerSubmission) {
+		if (activationsBySubmission == null) {
+			return;
+		}
+
+		final Object value = activationsBySubmission.remove(handlerSubmission);
+		if (value instanceof IHandlerActivation) {
+			final IHandlerActivation activation = (IHandlerActivation) value;
+			handlerService.deactivateHandler(activation);
+		}
+	}
+
+	@Override
+	public final void removeHandlerSubmissions(
+			final Collection handlerSubmissions) {
+		final Iterator submissionItr = handlerSubmissions.iterator();
+		while (submissionItr.hasNext()) {
+			removeHandlerSubmission((HandlerSubmission) submissionItr.next());
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/ActiveContextSourceProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/ActiveContextSourceProvider.java
new file mode 100644
index 0000000..ebde264
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/ActiveContextSourceProvider.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.contexts;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.eclipse.core.commands.contexts.ContextManagerEvent;
+import org.eclipse.core.commands.contexts.IContextManagerListener;
+import org.eclipse.ui.AbstractSourceProvider;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.contexts.IContextService;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * <p>
+ * This listens to changes to the list of active contexts, and propagates them
+ * through the <code>ISourceProvider</code> framework (a common language in
+ * which events are communicated to services).
+ * </p>
+ *
+ * @since 3.2
+ */
+public final class ActiveContextSourceProvider extends AbstractSourceProvider
+		implements IContextManagerListener {
+
+	/**
+	 * The names of the sources supported by this source provider.
+	 */
+	private static final String[] PROVIDED_SOURCE_NAMES = new String[] { ISources.ACTIVE_CONTEXT_NAME };
+
+	/**
+	 * The context service with which this source provider should communicate.
+	 * This value is never <code>null</code>.
+	 */
+	private IContextService contextService;
+
+	@Override
+	public final void contextManagerChanged(final ContextManagerEvent event) {
+		if (event.isActiveContextsChanged()) {
+			final Map currentState = getCurrentState();
+
+			if (DEBUG) {
+				logDebuggingInfo("Contexts changed to " //$NON-NLS-1$
+						+ currentState.get(ISources.ACTIVE_CONTEXT_NAME));
+			}
+
+			fireSourceChanged(ISources.ACTIVE_CONTEXT, currentState);
+		}
+	}
+
+	@Override
+	public final void dispose() {
+		contextService.removeContextManagerListener(this);
+	}
+
+	@Override
+	public final Map getCurrentState() {
+		final Map currentState = new TreeMap();
+		final Collection activeContextIds = contextService
+				.getActiveContextIds();
+		currentState.put(ISources.ACTIVE_CONTEXT_NAME, activeContextIds);
+		return currentState;
+	}
+
+	@Override
+	public final String[] getProvidedSourceNames() {
+		return PROVIDED_SOURCE_NAMES;
+	}
+
+	@Override
+	public void initialize(IServiceLocator locator) {
+		contextService = locator
+				.getService(IContextService.class);
+		contextService.addContextManagerListener(this);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/ContextActivation.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/ContextActivation.java
new file mode 100644
index 0000000..1670145
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/ContextActivation.java
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.contexts;
+
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.contexts.IContextActivation;
+import org.eclipse.ui.contexts.IContextService;
+import org.eclipse.ui.internal.services.EvaluationResultCache;
+
+/**
+ * <p>
+ * A token representing the activation of a context. This token can later be
+ * used to cancel that activation. Without this token, then the context will
+ * only become inactive if the component in which the context was activated is
+ * destroyed.
+ * </p>
+ * <p>
+ * This caches the context id, so that they can later be identified.
+ * </p>
+ * <p>
+ * Note: this class has a natural ordering that is inconsistent with equals.
+ * </p>
+ *
+ * @since 3.1
+ */
+final class ContextActivation extends EvaluationResultCache implements
+		IContextActivation {
+
+	/**
+	 * The identifier for the context which should be active. This value is
+	 * never <code>null</code>.
+	 */
+	private final String contextId;
+
+	/**
+	 * The context service from which this context activation was requested.
+	 * This value is never <code>null</code>.
+	 */
+	private final IContextService contextService;
+
+	/**
+	 * Constructs a new instance of <code>ContextActivation</code>.
+	 *
+	 * @param contextId
+	 *            The identifier for the context which should be activated. This
+	 *            value must not be <code>null</code>.
+	 * @param expression
+	 *            The expression that must evaluate to <code>true</code>
+	 *            before this handler is active. This value may be
+	 *            <code>null</code> if it is always active.
+	 * @param contextService
+	 *            The context service from which the handler activation was
+	 *            requested; must not be <code>null</code>.
+	 * @see ISources
+	 */
+	public ContextActivation(final String contextId,
+			final Expression expression, final IContextService contextService) {
+		super(expression);
+
+		if (contextId == null) {
+			throw new NullPointerException(
+					"The context identifier for a context activation cannot be null"); //$NON-NLS-1$
+		}
+
+		if (contextService == null) {
+			throw new NullPointerException(
+					"The context service for an activation cannot be null"); //$NON-NLS-1$
+		}
+
+		this.contextId = contextId;
+		this.contextService = contextService;
+	}
+
+	@Override
+	public final void clearActive() {
+		clearResult();
+	}
+
+	@Override
+	public final String getContextId() {
+		return contextId;
+	}
+
+	@Override
+	public final IContextService getContextService() {
+		return contextService;
+	}
+
+	@Override
+	public final boolean isActive(final IEvaluationContext context) {
+		return evaluate(context);
+	}
+
+	@Override
+	public final String toString() {
+		final StringBuffer buffer = new StringBuffer();
+
+		buffer.append("ContextActivation(contextId="); //$NON-NLS-1$
+		buffer.append(contextId);
+		buffer.append(",sourcePriority="); //$NON-NLS-1$
+		buffer.append(getSourcePriority());
+		buffer.append(')');
+
+		return buffer.toString();
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/ContextAuthority.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/ContextAuthority.java
new file mode 100644
index 0000000..1caa321
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/ContextAuthority.java
@@ -0,0 +1,808 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.contexts;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
+
+import org.eclipse.core.commands.contexts.ContextManager;
+import org.eclipse.core.commands.util.Tracing;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.ActiveShellExpression;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.contexts.IContextActivation;
+import org.eclipse.ui.contexts.IContextService;
+import org.eclipse.ui.internal.misc.Policy;
+import org.eclipse.ui.internal.services.ExpressionAuthority;
+
+/**
+ * <p>
+ * A central authority for deciding activation of contexts. This authority
+ * listens to a variety of incoming sources, and updates the underlying context
+ * manager if changes occur.
+ * </p>
+ *
+ * @since 3.1
+ */
+public final class ContextAuthority extends ExpressionAuthority {
+
+
+	/**
+	 * The default size of the set containing the activations to recompute. This
+	 * is more than enough to cover the average case.
+	 */
+	private static final int ACTIVATIONS_TO_RECOMPUTE_SIZE = 4;
+
+	/**
+	 * Whether the context authority should kick into debugging mode. This
+	 * causes the unresolvable handler conflicts to be printed to the console.
+	 */
+	private static final boolean DEBUG = Policy.DEBUG_CONTEXTS;
+
+	/**
+	 * Whether the performance information should be printed about the
+	 * performance of the context authority.
+	 */
+	private static final boolean DEBUG_PERFORMANCE = Policy.DEBUG_CONTEXTS_PERFORMANCE;
+
+	/**
+	 * The name of the data tag containing the dispose listener information.
+	 */
+	private static final String DISPOSE_LISTENER = "org.eclipse.ui.internal.contexts.ContextAuthority"; //$NON-NLS-1$
+
+	/**
+	 * The component name to print when displaying tracing information.
+	 */
+	private static final String TRACING_COMPONENT = "CONTEXTS"; //$NON-NLS-1$
+
+	/**
+	 * A bucket sort of the context activations based on source priority. Each
+	 * activation will appear only once per set, but may appear in multiple
+	 * sets. If no activations are defined for a particular priority level, then
+	 * the array at that index will only contain <code>null</code>.
+	 */
+	private final Set[] activationsBySourcePriority = new Set[33];
+
+	/**
+	 * This is a map of context activations (<code>Collection</code> of
+	 * <code>IContextActivation</code>) sorted by context identifier (<code>String</code>).
+	 * If there is only one context activation for a context, then the
+	 * <code>Collection</code> is replaced by a
+	 * <code>IContextActivation</code>. If there is no activation, the entry
+	 * should be removed entirely.
+	 */
+	private final Map contextActivationsByContextId = new HashMap();
+
+	/**
+	 * The context manager that should be updated when the contexts are
+	 * changing.
+	 */
+	private final ContextManager contextManager;
+
+	/**
+	 * The context service that should be used for authority-managed
+	 * shell-related contexts. This value is never <code>null</code>.
+	 */
+	private final IContextService contextService;
+
+	/**
+	 * This is a map of shell to a list of activations. When a shell is
+	 * registered, it is added to this map with the list of activation that
+	 * should be submitted when the shell is active. When the shell is
+	 * deactivated, this same list should be withdrawn. A shell is removed from
+	 * this map using the {@link #unregisterShell(Shell)}method. This value may
+	 * be empty, but is never <code>null</code>. The <code>null</code> key
+	 * is reserved for active shells that have not been registered but have a
+	 * parent (i.e., default dialog service).
+	 */
+	private final Map registeredWindows = new WeakHashMap();
+
+	/**
+	 * Constructs a new instance of <code>ContextAuthority</code>.
+	 *
+	 * @param contextManager
+	 *            The context manager from which contexts can be retrieved (to
+	 *            update their active state); must not be <code>null</code>.
+	 * @param contextService
+	 *            The workbench context service for which this authority is
+	 *            acting. This allows the authority to manage shell-specific
+	 *            contexts. This value must not be <code>null</code>.
+	 */
+	ContextAuthority(final ContextManager contextManager,
+			final IContextService contextService) {
+		if (contextManager == null) {
+			throw new NullPointerException(
+					"The context authority needs a context manager"); //$NON-NLS-1$
+		}
+		if (contextService == null) {
+			throw new NullPointerException(
+					"The context authority needs an evaluation context"); //$NON-NLS-1$
+		}
+
+		this.contextManager = contextManager;
+		this.contextService = contextService;
+	}
+
+	/**
+	 * Activates a context on the workbench. This will add it to a master list.
+	 *
+	 * @param activation
+	 *            The activation; must not be <code>null</code>.
+	 */
+	final void activateContext(final IContextActivation activation) {
+		// First we update the contextActivationsByContextId map.
+		final String contextId = activation.getContextId();
+		final Object value = contextActivationsByContextId.get(contextId);
+		if (value instanceof Collection) {
+			final Collection contextActivations = (Collection) value;
+			if (!contextActivations.contains(activation)) {
+				contextActivations.add(activation);
+				updateContext(contextId, containsActive(contextActivations));
+			}
+		} else if (value instanceof IContextActivation) {
+			if (value != activation) {
+				final Collection contextActivations = new ArrayList(2);
+				contextActivations.add(value);
+				contextActivations.add(activation);
+				contextActivationsByContextId
+						.put(contextId, contextActivations);
+				updateContext(contextId, containsActive(contextActivations));
+			}
+		} else {
+			contextActivationsByContextId.put(contextId, activation);
+			updateContext(contextId, evaluate(activation));
+		}
+
+		// Next we update the source priority bucket sort of activations.
+		final int sourcePriority = activation.getSourcePriority();
+		for (int i = 1; i <= 32; i++) {
+			if ((sourcePriority & (1 << i)) != 0) {
+				Set activations = activationsBySourcePriority[i];
+				if (activations == null) {
+					activations = new HashSet(1);
+					activationsBySourcePriority[i] = activations;
+				}
+				activations.add(activation);
+			}
+		}
+	}
+
+	/**
+	 * Checks whether the new active shell is registered. If it is already
+	 * registered, then it does no work. If it is not registered, then it checks
+	 * what type of contexts the shell should have by default. This is
+	 * determined by parenting. A shell with no parent receives no contexts. A
+	 * shell with a parent, receives the dialog contexts.
+	 *
+	 * @param newShell
+	 *            The newly active shell; may be <code>null</code> or
+	 *            disposed.
+	 * @param oldShell
+	 *            The previously active shell; may be <code>null</code> or
+	 *            disposed.
+	 */
+	private final void checkWindowType(final Shell newShell,
+			final Shell oldShell) {
+		/*
+		 * If the previous active shell was recognized as a dialog by default,
+		 * then remove its submissions.
+		 */
+		Collection oldActivations = (Collection) registeredWindows
+				.get(oldShell);
+		if (oldActivations == null) {
+			/*
+			 * The old shell wasn't registered. So, we need to check if it was
+			 * considered a dialog by default.
+			 */
+			oldActivations = (Collection) registeredWindows.get(null);
+			if (oldActivations != null) {
+				final Iterator oldActivationItr = oldActivations.iterator();
+				while (oldActivationItr.hasNext()) {
+					final IContextActivation activation = (IContextActivation) oldActivationItr
+							.next();
+					deactivateContext(activation);
+				}
+			}
+		}
+
+		/*
+		 * If the new active shell is recognized as a dialog by default, then
+		 * create some submissions, remember them, and submit them for
+		 * processing.
+		 */
+		if ((newShell != null) && (!newShell.isDisposed())) {
+			final Collection newActivations;
+
+			if ((newShell.getParent() != null)
+					&& (registeredWindows.get(newShell) == null)) {
+				// This is a dialog by default.
+				newActivations = new ArrayList();
+				final Expression expression = new ActiveShellExpression(
+						newShell);
+				final IContextActivation dialogWindowActivation = new ContextActivation(
+						IContextService.CONTEXT_ID_DIALOG_AND_WINDOW,
+						expression, contextService);
+				activateContext(dialogWindowActivation);
+				newActivations.add(dialogWindowActivation);
+				final IContextActivation dialogActivation = new ContextActivation(
+						IContextService.CONTEXT_ID_DIALOG, expression,
+						contextService);
+				activateContext(dialogActivation);
+				newActivations.add(dialogActivation);
+				registeredWindows.put(null, newActivations);
+
+				/*
+				 * Make sure the submissions will be removed in event of
+				 * disposal. This is really just a paranoid check. The
+				 * "oldSubmissions" code above should take care of this.
+				 */
+				newShell.addDisposeListener(new DisposeListener() {
+
+					@Override
+					public void widgetDisposed(DisposeEvent e) {
+						registeredWindows.remove(null);
+						if (!newShell.isDisposed()) {
+							newShell.removeDisposeListener(this);
+						}
+
+						/*
+						 * In the case where a dispose has happened, we are
+						 * expecting an activation event to arrive at some point
+						 * in the future. If we process the submissions now,
+						 * then we will update the activeShell before
+						 * checkWindowType is called. This means that dialogs
+						 * won't be recognized as dialogs.
+						 */
+						final Iterator newActivationItr = newActivations
+								.iterator();
+						while (newActivationItr.hasNext()) {
+							deactivateContext((IContextActivation) newActivationItr
+									.next());
+						}
+					}
+				});
+
+			} else {
+				// Shells that are not dialogs by default must register.
+				newActivations = null;
+
+			}
+		}
+	}
+
+	/**
+	 * Returns a subset of the given <code>activations</code> containing only
+	 * those that are active
+	 *
+	 * @param activations
+	 *            The activations to trim; must not be <code>null</code>, but
+	 *            may be empty.
+	 * @return <code>true</code> if there is at least one active context;
+	 *         <code>false</code> otherwise.
+	 */
+	private final boolean containsActive(final Collection activations) {
+		final Iterator activationItr = activations.iterator();
+		while (activationItr.hasNext()) {
+			final IContextActivation activation = (IContextActivation) activationItr
+					.next();
+			if (evaluate(activation)) {
+				return true;
+			}
+		}
+
+		return false;
+	}
+
+	/**
+	 * Removes an activation for a context on the workbench. This will remove it
+	 * from the master list, and update the appropriate context, if necessary.
+	 *
+	 * @param activation
+	 *            The activation; must not be <code>null</code>.
+	 */
+	final void deactivateContext(final IContextActivation activation) {
+		// First we update the handlerActivationsByCommandId map.
+		final String contextId = activation.getContextId();
+		final Object value = contextActivationsByContextId.get(contextId);
+		if (value instanceof Collection) {
+			final Collection contextActivations = (Collection) value;
+			if (contextActivations.contains(activation)) {
+				contextActivations.remove(activation);
+				if (contextActivations.isEmpty()) {
+					contextActivationsByContextId.remove(contextId);
+					updateContext(contextId, false);
+
+				} else if (contextActivations.size() == 1) {
+					final IContextActivation remainingActivation = (IContextActivation) contextActivations
+							.iterator().next();
+					contextActivationsByContextId.put(contextId,
+							remainingActivation);
+					updateContext(contextId, evaluate(remainingActivation));
+
+				} else {
+					updateContext(contextId, containsActive(contextActivations));
+				}
+			}
+		} else if (value instanceof IContextActivation) {
+			if (value == activation) {
+				contextActivationsByContextId.remove(contextId);
+				updateContext(contextId, false);
+			}
+		}
+
+		// Next we update the source priority bucket sort of activations.
+		final int sourcePriority = activation.getSourcePriority();
+		for (int i = 1; i <= 32; i++) {
+			if ((sourcePriority & (1 << i)) != 0) {
+				final Set activations = activationsBySourcePriority[i];
+				if (activations == null) {
+					continue;
+				}
+				activations.remove(activation);
+				if (activations.isEmpty()) {
+					activationsBySourcePriority[i] = null;
+				}
+			}
+		}
+	}
+
+	/**
+	 * Returns the currently active shell.
+	 *
+	 * @return The currently active shell; may be <code>null</code>.
+	 */
+	final Shell getActiveShell() {
+		return (Shell) getVariable(ISources.ACTIVE_SHELL_NAME);
+	}
+
+	/**
+	 * Returns the shell type for the given shell.
+	 *
+	 * @param shell
+	 *            The shell for which the type should be determined. If this
+	 *            value is <code>null</code>, then
+	 *            <code>IWorkbenchContextSupport.TYPE_NONE</code> is returned.
+	 * @return <code>IWorkbenchContextSupport.TYPE_WINDOW</code>,
+	 *         <code>IWorkbenchContextSupport.TYPE_DIALOG</code>, or
+	 *         <code>IWorkbenchContextSupport.TYPE_NONE</code>.
+	 */
+	public final int getShellType(final Shell shell) {
+		// If the shell is null, then return none.
+		if (shell == null) {
+			return IContextService.TYPE_NONE;
+		}
+
+		final Collection activations = (Collection) registeredWindows
+				.get(shell);
+		if (activations != null) {
+			// The shell is registered, so check what type it was registered as.
+			if (activations.isEmpty()) {
+				// It was registered as none.
+				return IContextService.TYPE_NONE;
+			}
+
+			// Look for the right type of context id.
+			final Iterator activationItr = activations.iterator();
+			while (activationItr.hasNext()) {
+				final IContextActivation activation = (IContextActivation) activationItr
+						.next();
+				final String contextId = activation.getContextId();
+				if (contextId == IContextService.CONTEXT_ID_DIALOG) {
+					return IContextService.TYPE_DIALOG;
+				} else if (contextId == IContextService.CONTEXT_ID_WINDOW) {
+					return IContextService.TYPE_WINDOW;
+				}
+			}
+
+			// This shouldn't be possible.
+			Assert
+					.isTrue(
+							false,
+							"A registered shell should have at least one submission matching TYPE_WINDOW or TYPE_DIALOG"); //$NON-NLS-1$
+			return IContextService.TYPE_NONE; // not reachable
+
+		} else if (shell.getParent() != null) {
+			/*
+			 * The shell is not registered, but it has a parent. It is therefore
+			 * considered a dialog by default.
+			 */
+			return IContextService.TYPE_DIALOG;
+
+		} else {
+			/*
+			 * The shell is not registered, but has no parent. It gets no key
+			 * bindings.
+			 */
+			return IContextService.TYPE_NONE;
+		}
+	}
+
+	/**
+	 * <p>
+	 * Registers a shell to automatically promote or demote some basic types of
+	 * contexts. The "In Dialogs" and "In Windows" contexts are provided by the
+	 * system. This a convenience method to ensure that these contexts are
+	 * promoted when the given is shell is active.
+	 * </p>
+	 * <p>
+	 * If a shell is registered as a window, then the "In Windows" context is
+	 * enabled when that shell is active. If a shell is registered as a dialog --
+	 * or is not registered, but has a parent shell -- then the "In Dialogs"
+	 * context is enabled when that shell is active. If the shell is registered
+	 * as none -- or is not registered, but has no parent shell -- then the
+	 * neither of the contexts will be enabled (by us -- someone else can always
+	 * enabled them).
+	 * </p>
+	 * <p>
+	 * If the provided shell has already been registered, then this method will
+	 * change the registration.
+	 * </p>
+	 *
+	 * @param shell
+	 *            The shell to register for key bindings; must not be
+	 *            <code>null</code>.
+	 * @param type
+	 *            The type of shell being registered. This value must be one of
+	 *            the constants given in this interface.
+	 *
+	 * @return <code>true</code> if the shell had already been registered
+	 *         (i.e., the registration has changed); <code>false</code>
+	 *         otherwise.
+	 */
+	public final boolean registerShell(final Shell shell, final int type) {
+		// We do not allow null shell registration. It is reserved.
+		if (shell == null) {
+			throw new NullPointerException("The shell was null"); //$NON-NLS-1$
+		}
+
+		// Debugging output
+		if (DEBUG) {
+			final StringBuffer buffer = new StringBuffer("register shell '"); //$NON-NLS-1$
+			buffer.append(shell);
+			buffer.append("' as "); //$NON-NLS-1$
+			switch (type) {
+			case IContextService.TYPE_DIALOG:
+				buffer.append("dialog"); //$NON-NLS-1$
+				break;
+			case IContextService.TYPE_WINDOW:
+				buffer.append("window"); //$NON-NLS-1$
+				break;
+			case IContextService.TYPE_NONE:
+				buffer.append("none"); //$NON-NLS-1$
+				break;
+			default:
+				buffer.append("unknown"); //$NON-NLS-1$
+				break;
+			}
+			Tracing.printTrace(TRACING_COMPONENT, buffer.toString());
+		}
+
+		// Build the list of submissions.
+		final List activations = new ArrayList();
+		Expression expression;
+		IContextActivation dialogWindowActivation;
+		switch (type) {
+		case IContextService.TYPE_DIALOG:
+			expression = new ActiveShellExpression(shell);
+			dialogWindowActivation = new ContextActivation(
+					IContextService.CONTEXT_ID_DIALOG_AND_WINDOW, expression,
+					contextService);
+			activateContext(dialogWindowActivation);
+			activations.add(dialogWindowActivation);
+			final IContextActivation dialogActivation = new ContextActivation(
+					IContextService.CONTEXT_ID_DIALOG, expression,
+					contextService);
+			activateContext(dialogActivation);
+			activations.add(dialogActivation);
+			break;
+		case IContextService.TYPE_NONE:
+			break;
+		case IContextService.TYPE_WINDOW:
+			expression = new ActiveShellExpression(shell);
+			dialogWindowActivation = new ContextActivation(
+					IContextService.CONTEXT_ID_DIALOG_AND_WINDOW, expression,
+					contextService);
+			activateContext(dialogWindowActivation);
+			activations.add(dialogWindowActivation);
+			final IContextActivation windowActivation = new ContextActivation(
+					IContextService.CONTEXT_ID_WINDOW, expression,
+					contextService);
+			activateContext(windowActivation);
+			activations.add(windowActivation);
+			break;
+		default:
+			throw new IllegalArgumentException("The type is not recognized: " //$NON-NLS-1$
+					+ type);
+		}
+
+		// Check to see if the activations are already present.
+		boolean returnValue = false;
+		final Collection previousActivations = (Collection) registeredWindows
+				.get(shell);
+		if (previousActivations != null) {
+			returnValue = true;
+			final Iterator previousActivationItr = previousActivations
+					.iterator();
+			while (previousActivationItr.hasNext()) {
+				final IContextActivation activation = (IContextActivation) previousActivationItr
+						.next();
+				deactivateContext(activation);
+			}
+		}
+
+		// Add the new submissions, and force some reprocessing to occur.
+		registeredWindows.put(shell, activations);
+
+		/*
+		 * Remember the dispose listener so that we can remove it later if we
+		 * unregister the shell.
+		 */
+		final DisposeListener shellDisposeListener = new DisposeListener() {
+
+			@Override
+			public void widgetDisposed(DisposeEvent e) {
+				registeredWindows.remove(shell);
+				if (!shell.isDisposed()) {
+					shell.removeDisposeListener(this);
+				}
+
+				/*
+				 * In the case where a dispose has happened, we are expecting an
+				 * activation event to arrive at some point in the future. If we
+				 * process the submissions now, then we will update the
+				 * activeShell before checkWindowType is called. This means that
+				 * dialogs won't be recognized as dialogs.
+				 */
+				final Iterator activationItr = activations.iterator();
+				while (activationItr.hasNext()) {
+					deactivateContext((IContextActivation) activationItr.next());
+				}
+			}
+		};
+
+		// Make sure the submissions will be removed in event of disposal.
+		shell.addDisposeListener(shellDisposeListener);
+		shell.setData(DISPOSE_LISTENER, shellDisposeListener);
+
+		return returnValue;
+	}
+
+	/**
+	 * Carries out the actual source change notification. It assumed that by the
+	 * time this method is called, <code>context</code> is up-to-date with the
+	 * current state of the application.
+	 *
+	 * @param sourcePriority
+	 *            A bit mask of all the source priorities that have changed.
+	 */
+	@Override
+	protected final void sourceChanged(final int sourcePriority) {
+		// If tracing, then track how long it takes to process the activations.
+		long startTime = 0L;
+		if (DEBUG_PERFORMANCE) {
+			startTime = System.currentTimeMillis();
+		}
+
+		/*
+		 * In this first phase, we cycle through all of the activations that
+		 * could have potentially changed. Each such activation is added to a
+		 * set for future processing. We add it to a set so that we avoid
+		 * handling any individual activation more than once.
+		 */
+		final Set activationsToRecompute = new HashSet(
+				ACTIVATIONS_TO_RECOMPUTE_SIZE);
+		for (int i = 1; i <= 32; i++) {
+			if ((sourcePriority & (1 << i)) != 0) {
+				final Collection activations = activationsBySourcePriority[i];
+				if (activations != null) {
+					final Iterator activationItr = activations.iterator();
+					while (activationItr.hasNext()) {
+						activationsToRecompute.add(activationItr.next());
+					}
+				}
+			}
+		}
+
+		/*
+		 * For every activation, we recompute its active state, and check
+		 * whether it has changed. If it has changed, then we take note of the
+		 * context identifier so we can update the context later.
+		 */
+		final Collection changedContextIds = new ArrayList(
+				activationsToRecompute.size());
+		final Iterator activationItr = activationsToRecompute.iterator();
+		while (activationItr.hasNext()) {
+			final IContextActivation activation = (IContextActivation) activationItr
+					.next();
+			final boolean currentActive = evaluate(activation);
+			activation.clearResult();
+			final boolean newActive = evaluate(activation);
+			if (newActive != currentActive) {
+				changedContextIds.add(activation.getContextId());
+			}
+		}
+
+		try {
+			contextManager.deferUpdates(true);
+			/*
+			 * For every context identifier with a changed activation, we
+			 * resolve conflicts and trigger an update.
+			 */
+			final Iterator changedContextIdItr = changedContextIds.iterator();
+			while (changedContextIdItr.hasNext()) {
+				final String contextId = (String) changedContextIdItr.next();
+				final Object value = contextActivationsByContextId
+						.get(contextId);
+				if (value instanceof IContextActivation) {
+					final IContextActivation activation = (IContextActivation) value;
+					updateContext(contextId, evaluate(activation));
+				} else if (value instanceof Collection) {
+					updateContext(contextId, containsActive((Collection) value));
+				} else {
+					updateContext(contextId, false);
+				}
+			}
+		} finally {
+			contextManager.deferUpdates(false);
+		}
+
+		// If tracing performance, then print the results.
+		if (DEBUG_PERFORMANCE) {
+			final long elapsedTime = System.currentTimeMillis() - startTime;
+			final int size = activationsToRecompute.size();
+			if (size > 0) {
+				Tracing.printTrace(TRACING_COMPONENT, size
+						+ " activations recomputed in " + elapsedTime + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
+			}
+		}
+	}
+
+	/**
+	 * <p>
+	 * Unregisters a shell that was previously registered. After this method
+	 * completes, the shell will be treated as if it had never been registered
+	 * at all. If you have registered a shell, you should ensure that this
+	 * method is called when the shell is disposed. Otherwise, a potential
+	 * memory leak will exist.
+	 * </p>
+	 * <p>
+	 * If the shell was never registered, or if the shell is <code>null</code>,
+	 * then this method returns <code>false</code> and does nothing.
+	 *
+	 * @param shell
+	 *            The shell to be unregistered; does nothing if this value is
+	 *            <code>null</code>.
+	 *
+	 * @return <code>true</code> if the shell had been registered;
+	 *         <code>false</code> otherwise.
+	 */
+	public final boolean unregisterShell(final Shell shell) {
+		// Don't allow this method to play with the special null slot.
+		if (shell == null) {
+			return false;
+		}
+
+		/*
+		 * If we're unregistering the shell but we're not about to dispose it,
+		 * then we'll end up leaking the DisposeListener unless we remove it
+		 * here.
+		 */
+		if (!shell.isDisposed()) {
+			final DisposeListener oldListener = (DisposeListener) shell
+					.getData(DISPOSE_LISTENER);
+			if (oldListener != null) {
+				shell.removeDisposeListener(oldListener);
+			}
+		}
+
+		Collection previousActivations = (Collection) registeredWindows
+				.get(shell);
+		if (previousActivations != null) {
+			registeredWindows.remove(shell);
+
+			final Iterator previousActivationItr = previousActivations
+					.iterator();
+			while (previousActivationItr.hasNext()) {
+				final IContextActivation activation = (IContextActivation) previousActivationItr
+						.next();
+				deactivateContext(activation);
+			}
+			return true;
+		}
+
+		return false;
+	}
+
+	/**
+	 * Updates the context with the given context activation.
+	 *
+	 * @param contextId
+	 *            The identifier of the context which should be updated; must
+	 *            not be <code>null</code>.
+	 * @param active
+	 *            Whether the context should be active; <code>false</code>
+	 *            otherwise.
+	 */
+	private final void updateContext(final String contextId,
+			final boolean active) {
+		if (active) {
+			contextManager.addActiveContext(contextId);
+		} else {
+			contextManager.removeActiveContext(contextId);
+		}
+	}
+
+	/**
+	 * Updates this authority's evaluation context. If the changed variable is
+	 * the <code>ISources.ACTIVE_SHELL_NAME</code> variable, then this also
+	 * triggers an update of the shell-specific contexts. For example, if a
+	 * dialog becomes active, then the dialog context will be activated by this
+	 * method.
+	 *
+	 * @param name
+	 *            The name of the variable to update; must not be
+	 *            <code>null</code>.
+	 * @param value
+	 *            The new value of the variable. If this value is
+	 *            <code>null</code>, then the variable is removed.
+	 */
+	@Override
+	protected final void updateEvaluationContext(final String name,
+			final Object value) {
+		/*
+		 * Bug 84056. If we update the active workbench window, then we risk
+		 * falling back to that shell when the active shell has registered as
+		 * "none".
+		 */
+		if ((name != null)
+				&& (!ISources.ACTIVE_WORKBENCH_WINDOW_SHELL_NAME.equals(name))) {
+			/*
+			 * We need to track shell activation ourselves, as some special
+			 * contexts are automatically activated in response to different
+			 * types of shells becoming active.
+			 */
+			if (ISources.ACTIVE_SHELL_NAME.equals(name)) {
+				checkWindowType((Shell) value,
+						(Shell) getVariable(ISources.ACTIVE_SHELL_NAME));
+			}
+
+			// Update the evaluation context itself.
+			changeVariable(name, value);
+		}
+	}
+
+	/**
+	 * <p>
+	 * Bug 95792. A mechanism by which the key binding architecture can force an
+	 * update of the contexts (based on the active shell) before trying to
+	 * execute a command. This mechanism is required for GTK+ only.
+	 * </p>
+	 * <p>
+	 * DO NOT CALL THIS METHOD.
+	 * </p>
+	 */
+	final void updateShellKludge() {
+		updateCurrentState();
+		sourceChanged(ISources.ACTIVE_SHELL);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/ContextLegacyWrapper.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/ContextLegacyWrapper.java
new file mode 100644
index 0000000..7a7d210
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/ContextLegacyWrapper.java
@@ -0,0 +1,127 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.contexts;
+
+import org.eclipse.core.commands.contexts.Context;
+import org.eclipse.core.commands.contexts.ContextManager;
+import org.eclipse.ui.contexts.IContext;
+import org.eclipse.ui.contexts.IContextListener;
+import org.eclipse.ui.contexts.NotDefinedException;
+import org.eclipse.ui.internal.util.Util;
+
+/**
+ * This implements the old <code>IContext</code> interface based on the new
+ * context implementation in <code>org.eclipse.ui.contexts</code>. This is a
+ * wrapper.
+ *
+ * @since 3.1
+ */
+public class ContextLegacyWrapper implements IContext {
+
+	/**
+	 * The context manager that maintains the set of active contexts; must not
+	 * be <code>null</code>.
+	 */
+	private final ContextManager contextManager;
+
+	/**
+	 * The wrapped instance of context. This value will never be
+	 * <code>null</code>.
+	 */
+	private final Context wrappedContext;
+
+	/**
+	 * Constructs a new instance of <code>ContextWrapper</code>.
+	 *
+	 * @param context
+	 *            The context to wrapper; must not be <code>null</code>.
+	 * @param contextManager
+	 *            The context manager that maintains the set of active contexts;
+	 *            must not be <code>null</code>.
+	 */
+	public ContextLegacyWrapper(final Context context,
+			final ContextManager contextManager) {
+		if (context == null) {
+			throw new NullPointerException(
+					"A wrapper cannot be created on a null context"); //$NON-NLS-1$
+		}
+
+		if (contextManager == null) {
+			throw new NullPointerException(
+					"A wrapper cannot be created with a null manager"); //$NON-NLS-1$
+		}
+
+		wrappedContext = context;
+		this.contextManager = contextManager;
+	}
+
+	@Override
+	public void addContextListener(IContextListener contextListener) {
+		final LegacyContextListenerWrapper wrapper = new LegacyContextListenerWrapper(
+				contextListener, contextManager, this);
+		wrappedContext.addContextListener(wrapper);
+
+		/*
+		 * We need to add the listener to the context manager as well, as only
+		 * the manager advertises changes to the enabled state.
+		 */
+		contextManager.addContextManagerListener(wrapper);
+	}
+
+	@Override
+	public int compareTo(Object o) {
+		return Util
+				.compare(wrappedContext, ((ContextLegacyWrapper) o).wrappedContext);
+	}
+
+	@Override
+	public String getId() {
+		return wrappedContext.getId();
+	}
+
+	@Override
+	public String getName() throws NotDefinedException {
+		try {
+			return wrappedContext.getName();
+		} catch (final org.eclipse.core.commands.common.NotDefinedException e) {
+			throw new NotDefinedException(e);
+		}
+	}
+
+	@Override
+	public String getParentId() throws NotDefinedException {
+		try {
+			return wrappedContext.getParentId();
+		} catch (final org.eclipse.core.commands.common.NotDefinedException e) {
+			throw new NotDefinedException(e);
+		}
+	}
+
+	@Override
+	public boolean isDefined() {
+		return wrappedContext.isDefined();
+	}
+
+	@Override
+	public boolean isEnabled() {
+		return contextManager.getActiveContextIds().contains(
+				wrappedContext.getId());
+	}
+
+	@Override
+	public void removeContextListener(IContextListener contextListener) {
+		final LegacyContextListenerWrapper wrapper = new LegacyContextListenerWrapper(
+				contextListener, contextManager, this);
+		wrappedContext.removeContextListener(wrapper);
+		contextManager.removeContextManagerListener(wrapper);
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/ContextManagerFactory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/ContextManagerFactory.java
new file mode 100644
index 0000000..76e27c1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/ContextManagerFactory.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.contexts;
+
+import org.eclipse.core.commands.contexts.ContextManager;
+
+/**
+ * This class allows clients to broker instances of <code>IContextManager</code>.
+ * <p>
+ * This class is not intended to be extended by clients.
+ * </p>
+ *
+ * @since 3.0
+ */
+public final class ContextManagerFactory {
+
+	/**
+	 * Creates a new instance of <code>ContextManagerWrapper</code>.
+	 *
+	 * @param contextManager
+	 *            The context manager that this context manager wrapper should
+	 *            wrap; must not be <code>null</code>.
+	 * @return a new instance of <code>ContextManagerWrapper</code>. Clients
+	 *         should not make assumptions about the concrete implementation
+	 *         outside the contract of the interface. Guaranteed not to be
+	 *         <code>null</code>.
+	 */
+	public static final ContextManagerLegacyWrapper getContextManagerWrapper(
+			final ContextManager contextManager) {
+		return new ContextManagerLegacyWrapper(contextManager);
+	}
+
+	/**
+	 * This class should not be constructed.
+	 */
+	private ContextManagerFactory() {
+		// Should not be called.
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/ContextManagerLegacyWrapper.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/ContextManagerLegacyWrapper.java
new file mode 100644
index 0000000..834bd66
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/ContextManagerLegacyWrapper.java
@@ -0,0 +1,243 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.contexts;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.core.commands.contexts.Context;
+import org.eclipse.core.commands.contexts.ContextManager;
+import org.eclipse.ui.contexts.ContextManagerEvent;
+import org.eclipse.ui.contexts.IContext;
+import org.eclipse.ui.contexts.IContextManager;
+import org.eclipse.ui.contexts.IContextManagerListener;
+
+/**
+ * A wrapper around the new API that supports the old API. This manager also
+ * adds support for reading from the registry.
+ *
+ * @since 3.1
+ */
+public final class ContextManagerLegacyWrapper implements
+		org.eclipse.core.commands.contexts.IContextManagerListener,
+		IContextManager {
+
+	/**
+	 * A comparator between context identifiers, that sorts them based on depth
+	 * within the tree. Context identifiers representing deeper items (i.e.,
+	 * items with more ancestors), have lesser values (i.e., would appear
+	 * earlier in a set).
+	 *
+	 * @since 3.0
+	 */
+	private class ContextIdDepthComparator implements Comparator {
+
+		/**
+		 * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
+		 */
+		@Override
+		public final int compare(final Object object1, final Object object2) {
+			final String contextId1 = (String) object1;
+			final String contextId2 = (String) object2;
+			Context context;
+			String parentId;
+
+			// Get the depth of the first context.
+			int depth1 = 0;
+			context = contextManager.getContext(contextId1);
+			try {
+				parentId = context.getParentId();
+				while (parentId != null) {
+					depth1++;
+					context = contextManager.getContext(parentId);
+					parentId = context.getParentId();
+				}
+			} catch (final NotDefinedException e) {
+				// Do nothing. Stop ascending the ancestry.
+			}
+
+			// Get the depth of the second context.
+			int depth2 = 0;
+			context = contextManager.getContext(contextId2);
+			try {
+				parentId = context.getParentId();
+				while (parentId != null) {
+					depth2++;
+					context = contextManager.getContext(parentId);
+					parentId = context.getParentId();
+				}
+			} catch (final NotDefinedException e) {
+				// Do nothing. Stop ascending the ancestry.
+			}
+
+			// If the contexts are equal depth, then use their identifier.
+			int compare = depth2 - depth1;
+			if (compare == 0) {
+				compare = contextId1.compareTo(contextId2);
+			}
+
+			return compare;
+		}
+	}
+
+	/**
+	 * A set that contains context identifiers (strings). The set is sorted
+	 * based on how many ancestors the corresponding contexts have. Contexts
+	 * with no parents appear last, while contexts with the most ancestors
+	 * appear first.
+	 *
+	 * @since 3.0
+	 */
+	private class DepthSortedContextIdSet extends TreeSet {
+
+		/**
+		 * Generated serial version UID for this class.
+		 *
+		 * @since 3.1
+		 */
+		private static final long serialVersionUID = 3257291326872892465L;
+
+		/**
+		 * Constructs a new instance of <code>DepthSortedContextIdSet</code>
+		 * with the set to be sorted.
+		 *
+		 * @param contextIds
+		 *            A set of context identifiers (strings); this may contain
+		 *            <code>null</code> values. The set may not be
+		 *            <code>null</code>, but may be empty.
+		 */
+		private DepthSortedContextIdSet(final Set contextIds) {
+			super(new ContextIdDepthComparator());
+			addAll(contextIds);
+		}
+	}
+
+	private final ContextManager contextManager;
+
+	private List contextManagerListeners;
+
+	/**
+	 * Constructs a new instance of <code>MutableContextManager</code>. The
+	 * registry is created on the platform's extension registry.
+	 *
+	 * @param contextManager
+	 *            The manager which will provided the real support; must not be
+	 *            <code>null</code>.
+	 */
+	public ContextManagerLegacyWrapper(ContextManager contextManager) {
+
+		if (contextManager == null) {
+			throw new NullPointerException("The context manager cannot be null"); //$NON-NLS-1$
+		}
+
+		this.contextManager = contextManager;
+		this.contextManager.addContextManagerListener(this);
+	}
+
+	@Override
+	public void addContextManagerListener(
+			IContextManagerListener contextManagerListener) {
+		if (contextManagerListener == null) {
+			throw new NullPointerException();
+		}
+
+		if (contextManagerListeners == null) {
+			contextManagerListeners = new ArrayList();
+		}
+
+		if (!contextManagerListeners.contains(contextManagerListener)) {
+			contextManagerListeners.add(contextManagerListener);
+		}
+	}
+
+	@Override
+	public void contextManagerChanged(
+			org.eclipse.core.commands.contexts.ContextManagerEvent contextManagerEvent) {
+		final String contextId = contextManagerEvent.getContextId();
+		final boolean definedContextsChanged;
+		final Set previouslyDefinedContextIds;
+		if (contextId == null) {
+			definedContextsChanged = false;
+			previouslyDefinedContextIds = null;
+		} else {
+			definedContextsChanged = true;
+			previouslyDefinedContextIds = new HashSet();
+			previouslyDefinedContextIds.addAll(contextManager
+					.getDefinedContextIds());
+			if (contextManagerEvent.isContextDefined()) {
+				previouslyDefinedContextIds.remove(contextId);
+			} else {
+				previouslyDefinedContextIds.add(contextId);
+			}
+		}
+
+		fireContextManagerChanged(new ContextManagerEvent(this,
+				definedContextsChanged, contextManagerEvent
+						.isActiveContextsChanged(),
+				previouslyDefinedContextIds, contextManagerEvent
+						.getPreviouslyActiveContextIds()));
+
+	}
+
+	protected void fireContextManagerChanged(
+			ContextManagerEvent contextManagerEvent) {
+		if (contextManagerEvent == null) {
+			throw new NullPointerException();
+		}
+
+		if (contextManagerListeners != null) {
+			for (int i = 0; i < contextManagerListeners.size(); i++) {
+				((IContextManagerListener) contextManagerListeners.get(i))
+						.contextManagerChanged(contextManagerEvent);
+			}
+		}
+	}
+
+	@Override
+	public IContext getContext(String contextId) {
+		return new ContextLegacyWrapper(contextManager.getContext(contextId),
+				contextManager);
+	}
+
+	@Override
+	public SortedSet getDefinedContextIds() {
+		return new DepthSortedContextIdSet(contextManager
+				.getDefinedContextIds());
+	}
+
+	@Override
+	public SortedSet getEnabledContextIds() {
+		return new DepthSortedContextIdSet(contextManager.getActiveContextIds());
+	}
+
+	@Override
+	public void removeContextManagerListener(
+			IContextManagerListener contextManagerListener) {
+		if (contextManagerListener == null) {
+			throw new NullPointerException();
+		}
+
+		if (contextManagerListeners != null) {
+			contextManagerListeners.remove(contextManagerListener);
+		}
+	}
+
+	public void setEnabledContextIds(Set enabledContextIds) {
+		contextManager.setActiveContextIds(enabledContextIds);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/ContextPersistence.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/ContextPersistence.java
new file mode 100644
index 0000000..2df9707
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/ContextPersistence.java
@@ -0,0 +1,226 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.contexts;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.eclipse.core.commands.contexts.Context;
+import org.eclipse.core.commands.contexts.ContextManager;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionDelta;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.IRegistryChangeEvent;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.services.RegistryPersistence;
+
+/**
+ * <p>
+ * A static class for accessing the registry.
+ * </p>
+ *
+ * @since 3.1
+ */
+public final class ContextPersistence extends RegistryPersistence {
+
+	/**
+	 * The index of the context elements in the indexed array.
+	 *
+	 * @see ContextPersistence#read()
+	 */
+	private static final int INDEX_CONTEXT_DEFINITIONS = 0;
+
+	/**
+	 * Reads all of the command definitions from the commands extension point.
+	 *
+	 * @param configurationElements
+	 *            The configuration elements in the commands extension point;
+	 *            must not be <code>null</code>, but may be empty.
+	 * @param configurationElementCount
+	 *            The number of configuration elements that are really in the
+	 *            array.
+	 * @param contextManager
+	 *            The context manager to which the commands should be added;
+	 *            must not be <code>null</code>.
+	 */
+	private static final void readContextsFromRegistry(
+			final IConfigurationElement[] configurationElements,
+			final int configurationElementCount,
+			final ContextManager contextManager) {
+		final List warningsToLog = new ArrayList(1);
+
+		for (int i = 0; i < configurationElementCount; i++) {
+			final IConfigurationElement configurationElement = configurationElements[i];
+
+			// Read out the command identifier.
+			final String contextId = readRequired(configurationElement, ATT_ID,
+					warningsToLog, "Contexts need an id"); //$NON-NLS-1$
+			if (contextId == null) {
+				continue;
+			}
+
+			// Read out the name.
+			final String name = readRequired(configurationElement, ATT_NAME,
+					warningsToLog, "Contexts need a name", //$NON-NLS-1$
+					contextId);
+			if (name == null) {
+				continue;
+			}
+
+			// Read out the description.
+			final String description = readOptional(configurationElement,
+					ATT_DESCRIPTION);
+
+			// Read out the parent id.
+			String parentId = configurationElement.getAttribute(ATT_PARENT_ID);
+			if ((parentId == null) || (parentId.length() == 0)) {
+				parentId = configurationElement.getAttribute(ATT_PARENT);
+				if ((parentId == null) || (parentId.length() == 0)) {
+					parentId = configurationElement
+							.getAttribute(ATT_PARENT_SCOPE);
+				}
+			}
+			if ((parentId != null) && (parentId.length() == 0)) {
+				parentId = null;
+			}
+
+			final Context context = contextManager.getContext(contextId);
+			if (!context.isDefined()) {
+				context.define(name, description, parentId);
+			}
+		}
+
+		logWarnings(
+				warningsToLog,
+				"Warnings while parsing the contexts from the 'org.eclipse.ui.contexts', 'org.eclipse.ui.commands' and 'org.eclipse.ui.acceleratorScopes' extension points."); //$NON-NLS-1$
+	}
+
+	/**
+	 * The context manager for this instance; must not be <code>null</code>.
+	 */
+	private final ContextManager contextManager;
+
+	/**
+	 * Constructs a new instance of <code>ContextPersistence</code>.
+	 */
+	public ContextPersistence(final ContextManager contextManager) {
+		if (contextManager == null) {
+			throw new NullPointerException(
+					"The context manager must not be null"); //$NON-NLS-1$
+		}
+		this.contextManager = contextManager;
+	}
+
+	@Override
+	protected final boolean isChangeImportant(final IRegistryChangeEvent event) {
+		final IExtensionDelta[] acceleratorScopeDeltas = event
+				.getExtensionDeltas(PlatformUI.PLUGIN_EXTENSION_NAME_SPACE,
+						IWorkbenchRegistryConstants.PL_ACCELERATOR_SCOPES);
+		if (acceleratorScopeDeltas.length == 0) {
+			final IExtensionDelta[] contextDeltas = event.getExtensionDeltas(
+					PlatformUI.PLUGIN_EXTENSION_NAME_SPACE,
+					IWorkbenchRegistryConstants.PL_CONTEXTS);
+			if (contextDeltas.length == 0) {
+				final IExtensionDelta[] commandDeltas = event
+						.getExtensionDeltas(PlatformUI.PLUGIN_EXTENSION_NAME_SPACE,
+								IWorkbenchRegistryConstants.PL_COMMANDS);
+				if (commandDeltas.length == 0) {
+					return false;
+				}
+			}
+		}
+
+		return true;
+	}
+
+	/**
+	 * Reads all of the contexts from the registry,
+	 *
+	 * @param contextManager
+	 *            The context manager which should be populated with the values
+	 *            from the registry; must not be <code>null</code>.
+	 */
+	@Override
+	protected final void read() {
+		super.read();
+		reRead();
+	}
+
+	public void reRead() {
+
+		// Create the extension registry mementos.
+		final IExtensionRegistry registry = Platform.getExtensionRegistry();
+		int contextDefinitionCount = 0;
+		final IConfigurationElement[][] indexedConfigurationElements = new IConfigurationElement[1][];
+
+		/*
+		 * Retrieve the accelerator scopes from the accelerator scopes extension
+		 * point.
+		 */
+		final IConfigurationElement[] acceleratorScopesExtensionPoint = registry
+				.getConfigurationElementsFor(EXTENSION_ACCELERATOR_SCOPES);
+		for (final IConfigurationElement configurationElement : acceleratorScopesExtensionPoint) {
+			final String name = configurationElement.getName();
+
+			// Check if it is a binding definition.
+			if (TAG_ACCELERATOR_SCOPE.equals(name)) {
+				addElementToIndexedArray(configurationElement,
+						indexedConfigurationElements,
+						INDEX_CONTEXT_DEFINITIONS, contextDefinitionCount++);
+			}
+		}
+
+		/*
+		 * Retrieve the deprecated scopes and contexts from the commands
+		 * extension point.
+		 */
+		final IConfigurationElement[] commandsExtensionPoint = registry
+				.getConfigurationElementsFor(EXTENSION_COMMANDS);
+		for (final IConfigurationElement configurationElement : commandsExtensionPoint) {
+			final String name = configurationElement.getName();
+
+			// Check if it is a binding definition.
+			if (TAG_SCOPE.equals(name)) {
+				addElementToIndexedArray(configurationElement,
+						indexedConfigurationElements,
+						INDEX_CONTEXT_DEFINITIONS, contextDefinitionCount++);
+			} else if (TAG_CONTEXT.equals(name)) {
+				addElementToIndexedArray(configurationElement,
+						indexedConfigurationElements,
+						INDEX_CONTEXT_DEFINITIONS, contextDefinitionCount++);
+
+			}
+		}
+
+		/*
+		 * Retrieve the contexts from the contexts extension point.
+		 */
+		final IConfigurationElement[] contextsExtensionPoint = registry
+				.getConfigurationElementsFor(EXTENSION_CONTEXTS);
+		for (final IConfigurationElement configurationElement : contextsExtensionPoint) {
+			final String name = configurationElement.getName();
+
+			// Check if it is a binding definition.
+			if (TAG_CONTEXT.equals(name)) {
+				addElementToIndexedArray(configurationElement,
+						indexedConfigurationElements,
+						INDEX_CONTEXT_DEFINITIONS, contextDefinitionCount++);
+			}
+		}
+
+		readContextsFromRegistry(
+				indexedConfigurationElements[INDEX_CONTEXT_DEFINITIONS],
+				contextDefinitionCount, contextManager);
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/ContextService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/ContextService.java
new file mode 100644
index 0000000..7802de6
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/ContextService.java
@@ -0,0 +1,301 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ *******************************************************************************/
+package org.eclipse.ui.internal.contexts;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import javax.inject.Inject;
+import org.eclipse.core.commands.contexts.Context;
+import org.eclipse.core.commands.contexts.ContextManager;
+import org.eclipse.core.commands.contexts.IContextManagerListener;
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.e4.core.commands.ExpressionContext;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.contexts.RunAndTrack;
+import org.eclipse.e4.ui.services.EContextService;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.ISourceProvider;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.contexts.IContextActivation;
+import org.eclipse.ui.contexts.IContextService;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+
+/**
+ * <p>
+ * Provides services related to contexts in the Eclipse workbench. This provides
+ * access to contexts.
+ * </p>
+ *
+ * @since 3.1
+ */
+public final class ContextService implements IContextService {
+
+	private HashMap<IContextActivation, UpdateExpression> activationToRat = new HashMap<>();
+
+	/**
+	 * The central authority for determining which context we should use.
+	 */
+	private final ContextAuthority contextAuthority;
+
+	/**
+	 * The context manager that supports this service. This value is never
+	 * <code>null</code>.
+	 */
+	private ContextManager contextManager;
+
+	@Inject
+	private EContextService contextService;
+
+	@Inject
+	private IEclipseContext eclipseContext;
+
+	/**
+	 * The persistence class for this context service.
+	 */
+	private final ContextPersistence contextPersistence;
+
+	/**
+	 * Constructs a new instance of <code>ContextService</code> using a
+	 * context manager.
+	 *
+	 * @param contextManager
+	 *            The context manager to use; must not be <code>null</code>.
+	 */
+	@Inject
+	public ContextService(final ContextManager contextManager) {
+		if (contextManager == null) {
+			throw new NullPointerException(
+					"Cannot create a context service with a null manager"); //$NON-NLS-1$
+		}
+		this.contextManager = contextManager;
+		this.contextAuthority = new ContextAuthority(contextManager, this);
+		this.contextPersistence = new ContextPersistence(contextManager);
+	}
+
+	@Override
+	public void deferUpdates(boolean defer) {
+		contextManager.deferUpdates(defer);
+		contextService.deferUpdates(defer);
+	}
+
+	@Override
+	public final IContextActivation activateContext(final String contextId) {
+		return activateContext(contextId, null);
+	}
+
+	private class UpdateExpression extends RunAndTrack {
+		boolean updating = true;
+
+		private String contextId;
+		private Expression expression;
+
+		EvaluationResult cached = null;
+
+		public UpdateExpression(String contextId, Expression expression) {
+			this.contextId = contextId;
+			this.expression = expression;
+		}
+
+		@Override
+		public boolean changed(IEclipseContext context) {
+			if (!updating) {
+				return false;
+			}
+			ExpressionContext ctx = new ExpressionContext(eclipseContext);
+			try {
+				if (updating) {
+					EvaluationResult result = expression.evaluate(ctx);
+					if (cached != null
+							&& (cached == result || (cached != EvaluationResult.FALSE && result != EvaluationResult.FALSE))) {
+						return updating;
+					}
+					if (result != EvaluationResult.FALSE) {
+						runExternalCode(() -> contextService.activateContext(contextId));
+					} else if (cached != null) {
+						runExternalCode(() -> contextService.deactivateContext(contextId));
+					}
+					cached = result;
+				}
+			} catch (CoreException e) {
+				// contextService.deactivateContext(contextId);
+				WorkbenchPlugin.log("Failed to update " + contextId, e); //$NON-NLS-1$
+			}
+			return updating;
+		}
+	}
+
+	@Override
+	public final IContextActivation activateContext(final String contextId,
+			final Expression expression) {
+
+		final IContextActivation activation = new ContextActivation(contextId,
+				expression, this);
+		contextAuthority.activateContext(activation);
+		if (expression == null) {
+			contextService.activateContext(contextId);
+		} else {
+			final UpdateExpression runnable = new UpdateExpression(contextId, expression);
+			activationToRat.put(activation, runnable);
+			eclipseContext.runAndTrack(runnable);
+		}
+		return activation;
+	}
+
+	@Override
+	public IContextActivation activateContext(String contextId,
+			Expression expression, boolean global) {
+		return activateContext(contextId, expression);
+	}
+
+	@Override
+	public final IContextActivation activateContext(final String contextId,
+			final Expression expression, final int sourcePriority) {
+		return activateContext(contextId, expression);
+	}
+
+	@Override
+	public final void addContextManagerListener(
+			final IContextManagerListener listener) {
+		contextManager.addContextManagerListener(listener);
+	}
+
+	@Override
+	public final void addSourceProvider(final ISourceProvider provider) {
+		contextAuthority.addSourceProvider(provider);
+	}
+
+	@Override
+	public final void deactivateContext(final IContextActivation activation) {
+		if (activation != null && activation.getContextService() == this) {
+			final UpdateExpression rat = activationToRat.remove(activation);
+			if (rat != null) {
+				rat.updating = false;
+				if (rat.cached != null && rat.cached != EvaluationResult.FALSE) {
+					contextService.deactivateContext(activation.getContextId());
+				}
+			} else {
+				contextService.deactivateContext(activation.getContextId());
+			}
+			contextAuthority.deactivateContext(activation);
+		}
+	}
+
+	@Override
+	public final void deactivateContexts(final Collection activations) {
+		try {
+			deferUpdates(true);
+			final Iterator<?> activationItr = activations.iterator();
+			while (activationItr.hasNext()) {
+				final IContextActivation activation = (IContextActivation) activationItr.next();
+				deactivateContext(activation);
+			}
+		} finally {
+			deferUpdates(false);
+		}
+	}
+
+	@Override
+	public final void dispose() {
+		contextPersistence.dispose();
+		contextAuthority.dispose();
+	}
+
+	@Override
+	public final Collection getActiveContextIds() {
+		return contextService.getActiveContextIds();
+	}
+
+	@Override
+	public final Context getContext(final String contextId) {
+		return contextService.getContext(contextId);
+	}
+
+	@Override
+	public final Collection getDefinedContextIds() {
+		return contextManager.getDefinedContextIds();
+	}
+
+	@Override
+	public final Context[] getDefinedContexts() {
+		return contextManager.getDefinedContexts();
+	}
+
+	@Override
+	public final int getShellType(final Shell shell) {
+		return contextAuthority.getShellType(shell);
+	}
+
+	@Override
+	public final void readRegistry() {
+		// contextPersistence.read();
+	}
+
+	@Override
+	public final boolean registerShell(final Shell shell, final int type) {
+		return contextAuthority.registerShell(shell, type);
+	}
+
+	@Override
+	public final void removeContextManagerListener(
+			final IContextManagerListener listener) {
+		contextManager.removeContextManagerListener(listener);
+	}
+
+	@Override
+	public final void removeSourceProvider(final ISourceProvider provider) {
+		contextAuthority.removeSourceProvider(provider);
+	}
+
+	@Override
+	public final boolean unregisterShell(final Shell shell) {
+		return contextAuthority.unregisterShell(shell);
+	}
+
+	/**
+	 * <p>
+	 * Bug 95792. A mechanism by which the key binding architecture can force an
+	 * update of the contexts (based on the active shell) before trying to
+	 * execute a command. This mechanism is required for GTK+ only.
+	 * </p>
+	 * <p>
+	 * DO NOT CALL THIS METHOD.
+	 * </p>
+	 */
+	public final void updateShellKludge() {
+		contextAuthority.updateShellKludge();
+	}
+
+	/**
+	 * <p>
+	 * Bug 95792. A mechanism by which the key binding architecture can force an
+	 * update of the contexts (based on the active shell) before trying to
+	 * execute a command. This mechanism is required for GTK+ only.
+	 * </p>
+	 * <p>
+	 * DO NOT CALL THIS METHOD.
+	 * </p>
+	 *
+	 * @param shell
+	 *            The shell that should be considered active; must not be
+	 *            <code>null</code>.
+	 */
+	public final void updateShellKludge(final Shell shell) {
+		final Shell currentActiveShell = contextAuthority.getActiveShell();
+		if (currentActiveShell != shell) {
+			contextAuthority.sourceChanged(ISources.ACTIVE_SHELL,
+					ISources.ACTIVE_SHELL_NAME, shell);
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/ContextServiceFactory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/ContextServiceFactory.java
new file mode 100644
index 0000000..267266f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/ContextServiceFactory.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ ******************************************************************************/
+
+package org.eclipse.ui.internal.contexts;
+
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.contexts.IContextService;
+import org.eclipse.ui.internal.expressions.ActivePartExpression;
+import org.eclipse.ui.internal.expressions.WorkbenchWindowExpression;
+import org.eclipse.ui.internal.services.IWorkbenchLocationService;
+import org.eclipse.ui.services.AbstractServiceFactory;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * @since 3.4
+ *
+ */
+public class ContextServiceFactory extends AbstractServiceFactory {
+
+	@Override
+	public Object create(Class serviceInterface, IServiceLocator parentLocator,
+			IServiceLocator locator) {
+		if (!IContextService.class.equals(serviceInterface)) {
+			return null;
+		}
+		IWorkbenchLocationService wls = locator
+				.getService(IWorkbenchLocationService.class);
+		final IWorkbench wb = wls.getWorkbench();
+		if (wb == null) {
+			return null;
+		}
+
+		Object parent = parentLocator.getService(serviceInterface);
+		if (parent == null) {
+			// we are registering the global services in the Workbench
+			return null;
+		}
+		final IWorkbenchWindow window = wls.getWorkbenchWindow();
+		final IWorkbenchPartSite site = wls.getPartSite();
+		if (site == null) {
+			Expression exp = new WorkbenchWindowExpression(window);
+			return new SlaveContextService((IContextService) parent, exp);
+		}
+		if (parent instanceof SlaveContextService) {
+			Expression exp = ((SlaveContextService) parent).fDefaultExpression;
+			if (exp instanceof ActivePartExpression) {
+				return new NestableContextService((IContextService) parent, exp);
+			}
+		}
+		Expression exp = new ActivePartExpression(site.getPart());
+		return new SlaveContextService((IContextService) parent, exp);
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/LegacyContextListenerWrapper.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/LegacyContextListenerWrapper.java
new file mode 100644
index 0000000..171bc9a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/LegacyContextListenerWrapper.java
@@ -0,0 +1,144 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.contexts;
+
+import java.util.Set;
+
+import org.eclipse.core.commands.contexts.ContextEvent;
+import org.eclipse.core.commands.contexts.ContextManager;
+import org.eclipse.core.commands.contexts.ContextManagerEvent;
+import org.eclipse.core.commands.contexts.IContextListener;
+import org.eclipse.core.commands.contexts.IContextManagerListener;
+import org.eclipse.ui.contexts.IContext;
+
+/**
+ * <p>
+ * This wraps an old context listener so it supports the new API. This is used
+ * to support attaching old-style listens to the new context objects.
+ * </p>
+ *
+ * @since 3.1
+ */
+public class LegacyContextListenerWrapper implements IContextListener,
+		IContextManagerListener {
+
+	/**
+	 * The legacy context that this listener would previously have been attached
+	 * to. This value is never <code>null</code>.
+	 */
+	private final IContext context;
+
+	/**
+	 * The context manager used for constructing the context wrapper when an
+	 * event occurs; must not be <code>null</code>.
+	 */
+	private final ContextManager contextManager;
+
+	/**
+	 * The listener to be wrapped. This value is never <code>null</code>.
+	 */
+	private final org.eclipse.ui.contexts.IContextListener wrappedListener;
+
+	/**
+	 * Constructs a new instance of <code>ContextListenerWrapper</code>.
+	 *
+	 * @param listener
+	 *            The listener to be wrapped. Must not be <code>null</code>.
+	 * @param contextManager
+	 *            The context manager used for constructing the context wrapper
+	 *            when an event occurs; must not be <code>null</code>.
+	 * @param context
+	 *            The legacy context this listener will be listening to; must
+	 *            not be <code>null</code>.
+	 */
+	public LegacyContextListenerWrapper(
+			final org.eclipse.ui.contexts.IContextListener listener,
+			final ContextManager contextManager, final IContext context) {
+		if (listener == null) {
+			throw new NullPointerException(
+					"Cannot create a listener wrapper on a null listener"); //$NON-NLS-1$
+		}
+
+		if (contextManager == null) {
+			throw new NullPointerException(
+					"Cannot create a listener wrapper with a null context manager"); //$NON-NLS-1$
+		}
+
+		if (context == null) {
+			throw new NullPointerException(
+					"Cannot create a listener wrapper with a null context"); //$NON-NLS-1$
+		}
+
+		wrappedListener = listener;
+		this.contextManager = contextManager;
+		this.context = context;
+	}
+
+	@Override
+	public final void contextChanged(final ContextEvent contextEvent) {
+		wrappedListener
+				.contextChanged(new org.eclipse.ui.contexts.ContextEvent(
+						new ContextLegacyWrapper(contextEvent.getContext(),
+								contextManager), contextEvent
+								.isDefinedChanged(), false, contextEvent
+								.isNameChanged(), contextEvent
+								.isParentIdChanged()));
+	}
+
+	@Override
+	public final void contextManagerChanged(final ContextManagerEvent event) {
+		final String contextId = context.getId();
+		final boolean enabledChanged;
+		if (event.isActiveContextsChanged()) {
+			final Set previousContexts = event.getPreviouslyActiveContextIds();
+			final Set currentContexts = contextManager.getActiveContextIds();
+			if ((previousContexts != null)
+					&& (previousContexts.contains(contextId))
+					&& ((currentContexts == null) || (currentContexts
+							.contains(contextId)))) {
+				enabledChanged = true;
+			} else if ((currentContexts != null)
+					&& (currentContexts.contains(contextId))
+					&& ((previousContexts == null) || (previousContexts
+							.contains(contextId)))) {
+				enabledChanged = true;
+			} else {
+				enabledChanged = false;
+			}
+		} else {
+			enabledChanged = false;
+		}
+
+		wrappedListener
+				.contextChanged(new org.eclipse.ui.contexts.ContextEvent(
+						context, false, enabledChanged, false, false));
+	}
+
+	@Override
+	public final boolean equals(final Object object) {
+		if (object instanceof LegacyContextListenerWrapper) {
+			final LegacyContextListenerWrapper other = (LegacyContextListenerWrapper) object;
+			return wrappedListener.equals(other.wrappedListener);
+		}
+
+		if (object instanceof org.eclipse.ui.contexts.IContextListener) {
+			final org.eclipse.ui.contexts.IContextListener other = (org.eclipse.ui.contexts.IContextListener) object;
+			return wrappedListener.equals(other);
+		}
+
+		return false;
+	}
+
+	@Override
+	public final int hashCode() {
+		return wrappedListener.hashCode();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/NestableContextService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/NestableContextService.java
new file mode 100644
index 0000000..1a694ef
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/NestableContextService.java
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.contexts;
+
+import java.util.Iterator;
+
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.ui.contexts.IContextActivation;
+import org.eclipse.ui.contexts.IContextService;
+import org.eclipse.ui.internal.services.INestable;
+
+/**
+ * <p>
+ * A context service which delegates almost all responsibility to the parent
+ * service. This service is capable of being nested inside a component that is
+ * not recognized by the "source" event mechanism.
+ * </p>
+ * <p>
+ * This class is not intended for use outside of the
+ * <code>org.eclipse.ui.workbench</code> plug-in.
+ * </p>
+ *
+ * @since 3.2
+ */
+public class NestableContextService extends SlaveContextService implements
+		INestable {
+	/**
+	 * Maintain the state of the context service.
+	 */
+	private boolean fActive;
+
+	/**
+	 * Construct the new nested slave context.
+	 *
+	 * @param parentService
+	 *            the parent context service; must not be <code>null</code>.
+	 * @param defaultExpression
+	 *            A default expression to use to determine viability. It's
+	 *            mainly used for conflict resolution. It can be
+	 *            <code>null</code>.
+	 */
+	public NestableContextService(IContextService parentService,
+			Expression defaultExpression) {
+		super(parentService, defaultExpression);
+		fActive = false;
+	}
+
+	@Override
+	protected IContextActivation doActivateContext(IContextActivation activation) {
+		if (fActive) {
+			return super.doActivateContext(activation);
+		}
+		fLocalActivations.put(activation, null);
+		return activation;
+	}
+
+	@Override
+	public void activate() {
+		if (fActive) {
+			return;
+		}
+
+		Iterator c = fLocalActivations.keySet().iterator();
+		while (c.hasNext()) {
+			IContextActivation activation = (IContextActivation) c.next();
+			super.doActivateContext(activation);
+		}
+		fActive = true;
+	}
+
+	@Override
+	public void deactivate() {
+		if (!fActive) {
+			return;
+		}
+		deactivateContexts(fParentActivations);
+		fParentActivations.clear();
+
+		Iterator c = fLocalActivations.keySet().iterator();
+		while (c.hasNext()) {
+			fLocalActivations.put(c.next(), null);
+		}
+		fActive = false;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/SlaveContextService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/SlaveContextService.java
new file mode 100644
index 0000000..27ac81a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/SlaveContextService.java
@@ -0,0 +1,303 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.contexts;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import org.eclipse.core.commands.contexts.Context;
+import org.eclipse.core.commands.contexts.IContextManagerListener;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.ISourceProvider;
+import org.eclipse.ui.contexts.IContextActivation;
+import org.eclipse.ui.contexts.IContextService;
+import org.eclipse.ui.internal.expressions.AndExpression;
+
+/**
+ * A context service which delegates almost all responsibility to the parent
+ * service.
+ * <p>
+ * This class is not intended for use outside of the
+ * <code>org.eclipse.ui.workbench</code> plug-in.
+ * </p>
+ *
+ * @since 3.2
+ *
+ */
+public class SlaveContextService implements IContextService {
+
+	/**
+	 * The parent context service, which is never <code>null</code>.
+	 */
+	protected IContextService fParentService;
+
+	/**
+	 * The default expression used when {@link #activateContext(String) } is
+	 * called. Contexts contributed that use this expression will only be active
+	 * with this service is active.
+	 */
+	protected Expression fDefaultExpression;
+
+	/**
+	 * Our contexts that are currently active with the parent context service.
+	 */
+	protected Set fParentActivations;
+
+	/**
+	 * A map of the local activation to the parent activations. If this service
+	 * is inactive, then all parent activations are <code>null</code>.
+	 * Otherwise, they point to the corresponding activation in the parent
+	 * service.
+	 */
+	protected Map fLocalActivations;
+
+	/**
+	 * A collection of context manager listeners. The listeners are not
+	 * activated/deactivated, but they will be removed when this service is
+	 * disposed.
+	 */
+	private Collection fContextManagerListeners;
+
+	/**
+	 * A collection of source providers. The listeners are not
+	 * activated/deactivated, but they will be removed when this service is
+	 * disposed.
+	 */
+	private Collection fSourceProviders;
+
+	/**
+	 * A collection of shells registered through this service. The listeners are
+	 * not activated/deactivated, but they will be removed when this service is
+	 * disposed.
+	 */
+	private Collection fRegisteredShells;
+
+	/**
+	 * Construct the new slave.
+	 *
+	 * @param parentService
+	 *            the parent context service; must not be <code>null</code>.
+	 * @param defaultExpression
+	 *            A default expression to use to determine viability. It's
+	 *            mainly used for conflict resolution. It can be
+	 *            <code>null</code>.
+	 */
+	public SlaveContextService(IContextService parentService,
+			Expression defaultExpression) {
+		if (parentService == null) {
+			throw new NullPointerException(
+					"The parent context service must not be null"); //$NON-NLS-1$
+		}
+		fParentService = parentService;
+		fDefaultExpression = defaultExpression;
+		fParentActivations = new HashSet();
+		fLocalActivations = new HashMap();
+		fContextManagerListeners = new ArrayList();
+		fSourceProviders = new ArrayList();
+		fRegisteredShells = new ArrayList();
+	}
+
+	@Override
+	public void deferUpdates(boolean defer) {
+		fParentService.deferUpdates(defer);
+	}
+
+	@Override
+	public IContextActivation activateContext(String contextId) {
+
+		ContextActivation activation = new ContextActivation(contextId,
+				fDefaultExpression, this);
+		return doActivateContext(activation);
+	}
+
+	@Override
+	public IContextActivation activateContext(String contextId,
+			Expression expression) {
+		return activateContext(contextId, expression, false);
+	}
+
+	@Override
+	public IContextActivation activateContext(String contextId,
+			Expression expression, boolean global) {
+		if (global) {
+			IContextActivation activation = fParentService.activateContext(
+					contextId, expression, global);
+			fParentActivations.add(activation);
+			return activation;
+		}
+
+		Expression aExpression = fDefaultExpression;
+		if (expression != null && fDefaultExpression != null) {
+			final AndExpression andExpression = new AndExpression();
+			andExpression.add(expression);
+			andExpression.add(fDefaultExpression);
+			aExpression = andExpression;
+		} else if (expression != null) {
+			aExpression = expression;
+		}
+
+		ContextActivation activation = new ContextActivation(contextId,
+				aExpression, this);
+		return doActivateContext(activation);
+	}
+
+	@Override
+	public IContextActivation activateContext(String contextId,
+			Expression expression, int sourcePriorities) {
+		return activateContext(contextId, expression);
+	}
+
+	@Override
+	public void addContextManagerListener(IContextManagerListener listener) {
+		if (!fContextManagerListeners.contains(listener)) {
+			fContextManagerListeners.add(listener);
+		}
+		fParentService.addContextManagerListener(listener);
+	}
+
+	@Override
+	public void addSourceProvider(ISourceProvider provider) {
+		if (!fSourceProviders.contains(provider)) {
+			fSourceProviders.add(provider);
+		}
+		fParentService.addSourceProvider(provider);
+	}
+
+	@Override
+	public void deactivateContext(IContextActivation activation) {
+		IContextActivation parentActivation = null;
+		if (fLocalActivations.containsKey(activation)) {
+			parentActivation = (IContextActivation) fLocalActivations
+					.remove(activation);
+		} else {
+			parentActivation = activation;
+		}
+		if (parentActivation != null) {
+			fParentService.deactivateContext(parentActivation);
+			fParentActivations.remove(parentActivation);
+		}
+	}
+
+	@Override
+	public void deactivateContexts(Collection activations) {
+		Object[] array = activations.toArray();
+		for (int i = 0; i < array.length; i++) {
+			deactivateContext((IContextActivation) array[i]);
+			array[i] = null;
+		}
+	}
+
+	@Override
+	public void dispose() {
+		fParentService.deactivateContexts(fParentActivations);
+		fParentActivations.clear();
+		fLocalActivations.clear();
+
+		// Remove any "resource", like listeners, that were associated
+		// with this service.
+		if (!fContextManagerListeners.isEmpty()) {
+			for (Object element : fContextManagerListeners.toArray()) {
+				removeContextManagerListener((IContextManagerListener) element);
+			}
+			fContextManagerListeners.clear();
+		}
+		if (!fSourceProviders.isEmpty()) {
+			for (Object element : fSourceProviders.toArray()) {
+				removeSourceProvider((ISourceProvider) element);
+			}
+			fSourceProviders.clear();
+		}
+		if (!fRegisteredShells.isEmpty()) {
+			for (Object element : fRegisteredShells.toArray()) {
+				unregisterShell((Shell) element);
+			}
+			fRegisteredShells.clear();
+		}
+	}
+
+	/**
+	 * Activate the context with respect to this slave service.
+	 *
+	 * @param contextId
+	 *            the context id
+	 * @param expression
+	 *            the expression to use
+	 * @return the activated context
+	 */
+	protected IContextActivation doActivateContext(IContextActivation activation) {
+		IContextActivation parentActivation = fParentService.activateContext(
+				activation.getContextId(), activation.getExpression());
+		fParentActivations.add(parentActivation);
+		fLocalActivations.put(activation, parentActivation);
+		return activation;
+	}
+
+	@Override
+	public Collection getActiveContextIds() {
+		return fParentService.getActiveContextIds();
+	}
+
+	@Override
+	public Context getContext(String contextId) {
+		return fParentService.getContext(contextId);
+	}
+
+	@Override
+	public Collection getDefinedContextIds() {
+		return fParentService.getDefinedContextIds();
+	}
+
+	@Override
+	public Context[] getDefinedContexts() {
+		return fParentService.getDefinedContexts();
+	}
+
+	@Override
+	public int getShellType(Shell shell) {
+		return fParentService.getShellType(shell);
+	}
+
+	@Override
+	public void readRegistry() {
+		fParentService.readRegistry();
+	}
+
+	@Override
+	public boolean registerShell(Shell shell, int type) {
+		if (!fRegisteredShells.contains(shell)) {
+			fRegisteredShells.add(shell);
+		}
+		return fParentService.registerShell(shell, type);
+	}
+
+	@Override
+	public void removeContextManagerListener(IContextManagerListener listener) {
+		fContextManagerListeners.remove(listener);
+		fParentService.removeContextManagerListener(listener);
+	}
+
+	@Override
+	public void removeSourceProvider(ISourceProvider provider) {
+		fSourceProviders.remove(provider);
+		fParentService.removeSourceProvider(provider);
+	}
+
+	@Override
+	public boolean unregisterShell(Shell shell) {
+		fRegisteredShells.remove(shell);
+		return fParentService.unregisterShell(shell);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/WorkbenchContextSupport.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/WorkbenchContextSupport.java
new file mode 100644
index 0000000..c8463da
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/contexts/WorkbenchContextSupport.java
@@ -0,0 +1,166 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2016 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.ui.internal.contexts;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import org.eclipse.core.commands.contexts.ContextManager;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.LegacyHandlerSubmissionExpression;
+import org.eclipse.ui.contexts.EnabledSubmission;
+import org.eclipse.ui.contexts.IContextActivation;
+import org.eclipse.ui.contexts.IContextManager;
+import org.eclipse.ui.contexts.IContextService;
+import org.eclipse.ui.contexts.IWorkbenchContextSupport;
+import org.eclipse.ui.internal.Workbench;
+import org.eclipse.ui.keys.IBindingService;
+
+/**
+ * Provides support for contexts within the workbench -- including key bindings,
+ * and some default contexts for shell types.
+ *
+ * @since 3.0
+ */
+public class WorkbenchContextSupport implements IWorkbenchContextSupport {
+
+	/**
+	 * The map of activations that have been given to the handler service (<code>IHandlerActivation</code>),
+	 * indexed by the submissions (<code>HandlerSubmission</code>). This map
+	 * should be <code>null</code> if there are no such activations.
+	 */
+	private Map activationsBySubmission = null;
+
+	/**
+	 * The binding service for the workbench. This value is never
+	 * <code>null</code>.
+	 */
+	private IBindingService bindingService;
+
+	/**
+	 * The context service for the workbench. This value is never
+	 * <code>null</code>.
+	 */
+	private IContextService contextService;
+
+	/**
+	 * The legacy context manager supported by this application.
+	 */
+	private ContextManagerLegacyWrapper contextManagerWrapper;
+
+	/**
+	 * The workbench for which context support is being provided. This value
+	 * must not be <code>null</code>.
+	 */
+	private final Workbench workbench;
+
+	/**
+	 * Constructs a new instance of <code>WorkbenchCommandSupport</code>.
+	 * This attaches the key binding support, and adds a global shell activation
+	 * filter.
+	 *
+	 * @param workbenchToSupport
+	 *            The workbench that needs to be supported by this instance;
+	 *            must not be <code>null</code>.
+	 * @param contextManager
+	 *            The context manager to be wrappered; must not be
+	 *            <code>null</code>.
+	 */
+	public WorkbenchContextSupport(final Workbench workbenchToSupport,
+			final ContextManager contextManager) {
+		workbench = workbenchToSupport;
+		contextService = workbench.getService(IContextService.class);
+		bindingService = workbench.getService(IBindingService.class);
+		contextManagerWrapper = ContextManagerFactory
+				.getContextManagerWrapper(contextManager);
+	}
+
+	@Override
+	public final void addEnabledSubmission(
+			final EnabledSubmission enabledSubmission) {
+		final IContextActivation activation = contextService.activateContext(
+				enabledSubmission.getContextId(),
+				new LegacyHandlerSubmissionExpression(enabledSubmission
+						.getActivePartId(), enabledSubmission.getActiveShell(),
+						enabledSubmission.getActiveWorkbenchPartSite()));
+		if (activationsBySubmission == null) {
+			activationsBySubmission = new HashMap();
+		}
+		activationsBySubmission.put(enabledSubmission, activation);
+	}
+
+	@Override
+	public final void addEnabledSubmissions(final Collection enabledSubmissions) {
+		final Iterator submissionItr = enabledSubmissions.iterator();
+		while (submissionItr.hasNext()) {
+			addEnabledSubmission((EnabledSubmission) submissionItr.next());
+		}
+	}
+
+	@Override
+	public final IContextManager getContextManager() {
+		return contextManagerWrapper;
+	}
+
+	@Override
+	public final int getShellType(Shell shell) {
+		return contextService.getShellType(shell);
+	}
+
+	@Override
+	public final boolean isKeyFilterEnabled() {
+		return bindingService.isKeyFilterEnabled();
+	}
+
+	@Override
+	public final void openKeyAssistDialog() {
+		bindingService.openKeyAssistDialog();
+	}
+
+	@Override
+	public final boolean registerShell(final Shell shell, final int type) {
+		return contextService.registerShell(shell, type);
+	}
+
+	@Override
+	public final void removeEnabledSubmission(
+			final EnabledSubmission enabledSubmission) {
+		if (activationsBySubmission == null) {
+			return;
+		}
+
+		final Object value = activationsBySubmission.remove(enabledSubmission);
+		if (value instanceof IContextActivation) {
+			final IContextActivation activation = (IContextActivation) value;
+			contextService.deactivateContext(activation);
+		}
+	}
+
+	@Override
+	public final void removeEnabledSubmissions(
+			final Collection enabledSubmissions) {
+		final Iterator submissionItr = enabledSubmissions.iterator();
+		while (submissionItr.hasNext()) {
+			removeEnabledSubmission((EnabledSubmission) submissionItr.next());
+		}
+	}
+
+	@Override
+	public final void setKeyFilterEnabled(final boolean enabled) {
+		bindingService.setKeyFilterEnabled(enabled);
+	}
+
+	@Override
+	public final boolean unregisterShell(final Shell shell) {
+		return contextService.unregisterShell(shell);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/DeclarativeDecorator.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/DeclarativeDecorator.java
new file mode 100644
index 0000000..ff0c85c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/DeclarativeDecorator.java
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.decorators;
+
+import java.net.URL;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.IDecoration;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.ILightweightLabelDecorator;
+import org.eclipse.ui.internal.util.BundleUtility;
+
+/**
+ * The DeclarativeDecorator is a decorator that is made entirely from an XML
+ * specification.
+ */
+public class DeclarativeDecorator implements ILightweightLabelDecorator {
+
+	private String iconLocation;
+
+    private IConfigurationElement configElement;
+
+    private ImageDescriptor descriptor;
+
+    DeclarativeDecorator(IConfigurationElement definingElement, String iconPath) {
+        this.iconLocation = iconPath;
+        this.configElement = definingElement;
+    }
+
+    /**
+     * @see org.eclipse.jface.viewers.IBaseLabelProvider#addListener(org.eclipse.jface.viewers.ILabelProviderListener)
+     */
+    @Override
+	public void addListener(ILabelProviderListener listener) {
+    }
+
+    /**
+     * @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose()
+     */
+    @Override
+	public void dispose() {
+    	//Nothing to do here
+    }
+
+	/**
+     * @see org.eclipse.jface.viewers.IBaseLabelProvider#isLabelProperty(java.lang.Object,
+     *      java.lang.String)
+     */
+    @Override
+	public boolean isLabelProperty(Object element, String property) {
+        return false;
+    }
+
+    /**
+     * @see org.eclipse.jface.viewers.IBaseLabelProvider#removeListener(org.eclipse.jface.viewers.ILabelProviderListener)
+     */
+    @Override
+	public void removeListener(ILabelProviderListener listener) {
+    }
+
+    /**
+     * @see org.eclipse.jface.viewers.ILightweightLabelDecorator#decorate(java.lang.Object,
+     *      org.eclipse.jface.viewers.IDecoration)
+     */
+    @Override
+	public void decorate(Object element, IDecoration decoration) {
+        if (descriptor == null) {
+            URL url = BundleUtility.find(configElement.getDeclaringExtension()
+                    .getNamespace(), iconLocation);
+            if (url == null) {
+				return;
+			}
+            descriptor = ImageDescriptor.createFromURL(url);
+        }
+        decoration.addOverlay(descriptor);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/DecorationBuilder.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/DecorationBuilder.java
new file mode 100644
index 0000000..d654d9d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/DecorationBuilder.java
@@ -0,0 +1,215 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Sascha Zelzer <zelzer@mathi.uni-heidelberg.de> -
+ *     	Fix for Bug 152927 [Decorators] ArrayOutOfBoundsException in DecorationBuilder.java
+ *******************************************************************************/
+package org.eclipse.ui.internal.decorators;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.DecorationContext;
+import org.eclipse.jface.viewers.IDecoration;
+import org.eclipse.jface.viewers.IDecorationContext;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+
+/**
+ * The Decoration builder is the object that builds a decoration.
+ */
+public class DecorationBuilder implements IDecoration {
+
+	private static int DECORATOR_ARRAY_SIZE = 6;
+
+	private List prefixes = new ArrayList();
+
+	private List suffixes = new ArrayList();
+
+	private ImageDescriptor[] descriptors = new ImageDescriptor[DECORATOR_ARRAY_SIZE];
+
+	private Color foregroundColor;
+
+	private Color backgroundColor;
+
+	private Font font;
+
+	LightweightDecoratorDefinition currentDefinition;
+
+	// A flag set if a value has been added
+	private boolean valueSet = false;
+
+	private final IDecorationContext context;
+
+	/**
+	 * Default constructor.
+	 */
+	DecorationBuilder() {
+		this(DecorationContext.DEFAULT_CONTEXT);
+	}
+
+	/**
+	 * Create a decoration builder for the given context
+	 *
+	 * @param context
+	 *            a decoration context
+	 */
+	public DecorationBuilder(IDecorationContext context) {
+		this.context = context;
+	}
+
+	/**
+	 * Set the value of the definition we are currently working on.
+	 *
+	 * @param definition
+	 */
+	void setCurrentDefinition(LightweightDecoratorDefinition definition) {
+		this.currentDefinition = definition;
+	}
+
+	/**
+	 * @see org.eclipse.jface.viewers.IDecoration#addOverlay(org.eclipse.jface.resource.ImageDescriptor)
+	 */
+	@Override
+	public void addOverlay(ImageDescriptor overlay) {
+		int quadrant = currentDefinition.getQuadrant();
+		if (descriptors[quadrant] == null) {
+			descriptors[quadrant] = overlay;
+		}
+		valueSet = true;
+	}
+
+	/**
+	 * @see org.eclipse.jface.viewers.IDecoration#addOverlay(org.eclipse.jface.resource.ImageDescriptor)
+	 */
+	@Override
+	public void addOverlay(ImageDescriptor overlay, int quadrant) {
+		if (quadrant >= 0 && quadrant < DECORATOR_ARRAY_SIZE) {
+			if (descriptors[quadrant] == null) {
+				descriptors[quadrant] = overlay;
+			}
+			valueSet = true;
+		} else {
+			WorkbenchPlugin
+					.log("Unable to apply decoration for " + currentDefinition.getId() + " invalid quadrant: " + quadrant); //$NON-NLS-1$ //$NON-NLS-2$
+		}
+	}
+
+	/**
+	 * @see org.eclipse.jface.viewers.IDecoration#addPrefix(java.lang.String)
+	 */
+	@Override
+	public void addPrefix(String prefixString) {
+		prefixes.add(prefixString);
+		valueSet = true;
+	}
+
+	/**
+	 * @see org.eclipse.jface.viewers.IDecoration#addSuffix(java.lang.String)
+	 */
+	@Override
+	public void addSuffix(String suffixString) {
+		suffixes.add(suffixString);
+		valueSet = true;
+	}
+
+	/**
+	 * Clear the current values and return a DecorationResult.
+	 *
+	 * @return DecorationResult
+	 */
+	DecorationResult createResult() {
+		// check whether the context says that replacement should happen
+		boolean clearReplacementImage = true;
+		if (context != null) {
+			Object propertyValue = context.getProperty(IDecoration.ENABLE_REPLACE);
+			if (propertyValue instanceof Boolean) {
+				if (((Boolean) propertyValue).booleanValue()) {
+					clearReplacementImage = false;
+				}
+			}
+		}
+		if (clearReplacementImage) {
+			descriptors[IDecoration.REPLACE] = null;
+		}
+		DecorationResult newResult = new DecorationResult(new ArrayList(
+				prefixes), new ArrayList(suffixes), descriptors,
+				foregroundColor, backgroundColor, font);
+
+		return newResult;
+	}
+
+	/**
+	 * Clear the contents of the result so it can be reused.
+	 */
+	void clearContents() {
+		this.prefixes.clear();
+		this.suffixes.clear();
+		this.descriptors = new ImageDescriptor[DECORATOR_ARRAY_SIZE];
+		valueSet = false;
+	}
+
+	/**
+	 * Return whether or not a value has been set.
+	 *
+	 * @return boolean
+	 */
+	boolean hasValue() {
+		return valueSet;
+	}
+
+	/**
+	 * Apply the previously calculates result to the receiver.
+	 *
+	 * @param result
+	 */
+	void applyResult(DecorationResult result) {
+		prefixes.addAll(result.getPrefixes());
+		suffixes.addAll(result.getSuffixes());
+		ImageDescriptor[] resultDescriptors = result.getDescriptors();
+		if (resultDescriptors != null) {
+			for (int i = 0; i < descriptors.length; i++) {
+				if (resultDescriptors[i] != null) {
+					descriptors[i] = resultDescriptors[i];
+				}
+			}
+		}
+
+		setForegroundColor(result.getForegroundColor());
+		setBackgroundColor(result.getBackgroundColor());
+		setFont(result.getFont());
+		valueSet = true;
+	}
+
+
+	@Override
+	public void setBackgroundColor(Color bgColor) {
+		this.backgroundColor = bgColor;
+		valueSet = true;
+	}
+
+	@Override
+	public void setFont(Font newFont) {
+		this.font = newFont;
+		valueSet = true;
+	}
+
+	@Override
+	public void setForegroundColor(Color fgColor) {
+		this.foregroundColor = fgColor;
+		valueSet = true;
+	}
+
+	@Override
+	public IDecorationContext getDecorationContext() {
+		return context;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/DecorationReference.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/DecorationReference.java
new file mode 100644
index 0000000..40ae0ea
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/DecorationReference.java
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.decorators;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.viewers.IDecorationContext;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.internal.WorkbenchMessages;
+
+/**
+ * A DecorationReference is a class that holds onto the starting
+ * text and image of a decoration.
+ */
+class DecorationReference {
+    Object element;
+
+    Object adaptedElement;
+
+    String undecoratedText;
+
+    boolean forceUpdate = false;
+
+	IDecorationContext[] contexts;
+
+    DecorationReference(Object object, Object adaptedObject, IDecorationContext context) {
+        this.contexts = new IDecorationContext[] { context} ;
+		Assert.isNotNull(object);
+        element = object;
+        this.adaptedElement = adaptedObject;
+    }
+
+    /**
+     * Returns the adaptedElement.
+     * @return Object
+     */
+    Object getAdaptedElement() {
+        return adaptedElement;
+    }
+
+    /**
+     * Returns the element.
+     * @return Object
+     */
+    Object getElement() {
+        return element;
+    }
+
+    /**
+     * Return true if an update should occur whether or
+     * not there is a result.
+     * @return boolean
+     */
+    boolean shouldForceUpdate() {
+        return forceUpdate;
+    }
+
+    /**
+     * Sets the forceUpdate flag. If true an update
+     * occurs whether or not a decoration has resulted.
+     * @param forceUpdate The forceUpdate to set
+     */
+    void setForceUpdate(boolean forceUpdate) {
+        this.forceUpdate = forceUpdate;
+    }
+
+    /**
+     * Set the text that will be used to label the decoration
+     * calculation.
+     * @param text
+     */
+    void setUndecoratedText(String text) {
+        undecoratedText = text;
+    }
+
+    /**
+     * Return the string for the subtask for this element.
+     * @return String
+     */
+    String getSubTask() {
+        if (undecoratedText == null) {
+			return WorkbenchMessages.get().DecorationReference_EmptyReference;
+		}
+	return NLS.bind(WorkbenchMessages.get().DecorationScheduler_DecoratingSubtask, undecoratedText );
+    }
+
+    /**
+     * Returns the decoration context associated with the element
+     * being decorated
+     * @return the decoration context
+     */
+	IDecorationContext[] getContexts() {
+		return contexts;
+	}
+
+	void addContext(IDecorationContext context) {
+		IDecorationContext[] newContexts = new IDecorationContext[contexts.length + 1];
+		System.arraycopy(contexts, 0, newContexts, 0, contexts.length);
+		newContexts[contexts.length] = context;
+		contexts = newContexts;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/DecorationResult.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/DecorationResult.java
new file mode 100644
index 0000000..ff9aa16
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/DecorationResult.java
@@ -0,0 +1,178 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.decorators;
+
+import java.util.List;
+import java.util.ListIterator;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.ResourceManager;
+import org.eclipse.jface.viewers.DecorationOverlayIcon;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+
+/**
+ * The Decoration Result is the result of a decoration.
+ */
+public class DecorationResult {
+
+	private List prefixes;
+
+	private List suffixes;
+
+	private ImageDescriptor[] descriptors;
+
+	private Color foregroundColor;
+
+	private Color backgroundColor;
+
+	private Font font;
+
+	DecorationResult(List prefixList, List suffixList,
+			ImageDescriptor[] imageDescriptors, Color resultForegroundColor,
+			Color resultBackgroundColor, Font resultFont) {
+		prefixes = prefixList;
+		suffixes = suffixList;
+
+		// Don't set the field if there are no entries
+		if (hasOverlays(imageDescriptors)) {
+			descriptors = imageDescriptors;
+		}
+		foregroundColor = resultForegroundColor;
+		backgroundColor = resultBackgroundColor;
+		font = resultFont;
+	}
+
+	/**
+	 * Return whether or not any of the imageDescriptors are non-null.
+	 *
+	 * @param imageDescriptors
+	 * @return <code>true</code> if there are some non-null overlays
+	 */
+	private boolean hasOverlays(ImageDescriptor[] imageDescriptors) {
+		for (ImageDescriptor imageDescriptor : imageDescriptors) {
+			if (imageDescriptor != null) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Decorate the Image supplied with the overlays.
+	 *
+	 * @param image
+	 * @param manager
+	 * @return Image
+	 */
+	Image decorateWithOverlays(Image image, ResourceManager manager) {
+
+		// Do not try to do anything if there is no source or overlays
+		if (image == null || descriptors == null) {
+			return image;
+		}
+
+		Rectangle bounds = image.getBounds();
+		Point size = new Point(bounds.width, bounds.height);
+		DecorationOverlayIcon icon = new DecorationOverlayIcon(image, descriptors, size);
+		return manager.createImage(icon);
+	}
+
+	/**
+	 * Decorate the String supplied with the prefixes and suffixes. This method
+	 * is public for use by the test suites and is not intended to be referenced
+	 * by other workbench internals.
+	 *
+	 * @param text
+	 * @return String
+	 */
+	public String decorateWithText(String text) {
+
+		if (prefixes.isEmpty() && suffixes.isEmpty()) {
+			return text;
+		}
+
+		StringBuffer result = new StringBuffer();
+
+		ListIterator prefixIterator = prefixes.listIterator();
+
+		while (prefixIterator.hasNext()) {
+			result.append(prefixIterator.next());
+		}
+
+		result.append(text);
+
+		ListIterator suffixIterator = suffixes.listIterator();
+
+		while (suffixIterator.hasNext()) {
+			result.append(suffixIterator.next());
+		}
+
+		return result.toString();
+	}
+
+	/**
+	 * Get the descriptor array for the receiver.
+	 *
+	 * @return ImageDescriptor[] or <code>null</code>
+	 */
+	ImageDescriptor[] getDescriptors() {
+		return descriptors;
+	}
+
+	/**
+	 * Get the prefixes for the receiver.
+	 *
+	 * @return List
+	 */
+	List getPrefixes() {
+		return prefixes;
+	}
+
+	/**
+	 * Get the suffixes for the receiver.
+	 *
+	 * @return List
+	 */
+	List getSuffixes() {
+		return suffixes;
+	}
+
+	/**
+	 * Return the background Color for the result.
+	 *
+	 * @return Color
+	 */
+	Color getBackgroundColor() {
+		return backgroundColor;
+	}
+
+	/**
+	 * Return the font for the result.
+	 *
+	 * @return Font
+	 */
+	Font getFont() {
+		return font;
+	}
+
+	/**
+	 * Return the foreground color for the result.
+	 *
+	 * @return Color
+	 */
+	Color getForegroundColor() {
+		return foregroundColor;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/DecorationScheduler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/DecorationScheduler.java
new file mode 100644
index 0000000..a1933a3
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/DecorationScheduler.java
@@ -0,0 +1,659 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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
+ *     Francis Upton <francisu@ieee.org> -
+ *     		Fix for Bug 216667 [Decorators] DecorationScheduler hangs onto objects forever sometimes
+ *******************************************************************************/
+package org.eclipse.ui.internal.decorators;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.resource.ResourceManager;
+import org.eclipse.jface.viewers.DecorationContext;
+import org.eclipse.jface.viewers.IDecorationContext;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.LabelProviderChangedEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.progress.UIJob;
+import org.eclipse.ui.progress.WorkbenchJob;
+
+/**
+ * The DecorationScheduler is the class that handles the decoration of elements
+ * using a background thread.
+ */
+public class DecorationScheduler {
+
+	static final ILabelProviderListener[] EMPTY_LISTENER_LIST = new ILabelProviderListener[0];
+
+	// When decorations are computed they are added to this cache via
+	// decorated() method
+	Map resultCache = new HashMap();
+
+	// Objects that need an icon and text computed for display to the user
+	List awaitingDecoration = new ArrayList();
+
+	// Objects that are awaiting a label update.
+	Set pendingUpdate = new HashSet();
+
+	// Key to lock write access to the pending update set
+	Object pendingKey = new Object();
+
+	Map awaitingDecorationValues = new HashMap();
+
+	DecoratorManager decoratorManager;
+
+	boolean shutdown = false;
+
+	Job decorationJob;
+
+	UIJob updateJob;
+
+	private Collection removedListeners = Collections.synchronizedSet(new HashSet());
+
+	private Job clearJob;
+
+	// Static used for the updates to indicate an update is required
+	static final int NEEDS_INIT = -1;
+
+	/** Amount of time to delay the update notification when max reached. */
+	static final int UPDATE_DELAY = 100;
+
+	/**
+	 * Return a new instance of the receiver configured for the supplied
+	 * DecoratorManager.
+	 *
+	 * @param manager
+	 */
+	DecorationScheduler(DecoratorManager manager) {
+		decoratorManager = manager;
+		createDecorationJob();
+	}
+
+	/**
+	 * Decorate the text for the receiver. If it has already been done then
+	 * return the result, otherwise queue it for decoration.
+	 *
+	 * @return String
+	 * @param text
+	 * @param element
+	 * @param adaptedElement
+	 *            The adapted value of element. May be null.
+	 * @param context
+	 *            the decoration context
+	 */
+
+	public String decorateWithText(String text, Object element, Object adaptedElement, IDecorationContext context) {
+
+		DecorationResult decoration = getResult(element, adaptedElement, context);
+
+		if (decoration == null) {
+			return text;
+		}
+
+		return decoration.decorateWithText(text);
+
+	}
+
+	/**
+	 * Queue the element and its adapted value if it has not been already.
+	 *
+	 * @param element
+	 * @param adaptedElement
+	 *            The adapted value of element. May be null.
+	 * @param forceUpdate
+	 *            If true then a labelProviderChanged is fired whether
+	 *            decoration occurred or not.
+	 * @param undecoratedText
+	 *            The original text for the element if it is known.
+	 * @param context
+	 *            The decoration context
+	 */
+
+	synchronized void queueForDecoration(Object element, Object adaptedElement, boolean forceUpdate,
+			String undecoratedText, IDecorationContext context) {
+
+		Assert.isNotNull(context);
+		DecorationReference reference = (DecorationReference) awaitingDecorationValues.get(element);
+		if (reference != null) {
+			if (forceUpdate) {// Make sure we don't loose a force
+				reference.setForceUpdate(forceUpdate);
+			}
+			reference.addContext(context);
+		} else {
+			reference = new DecorationReference(element, adaptedElement, context);
+			reference.setForceUpdate(forceUpdate);
+			reference.setUndecoratedText(undecoratedText);
+			awaitingDecorationValues.put(element, reference);
+			awaitingDecoration.add(element);
+			if (shutdown) {
+				return;
+			}
+			decorationJob.schedule();
+		}
+
+	}
+
+	/**
+	 * Decorate the supplied image, element and its adapted value.
+	 *
+	 * @return Image
+	 * @param image
+	 * @param element
+	 * @param adaptedElement
+	 *            The adapted value of element. May be null.
+	 * @param context
+	 *            the decoration context
+	 * @param manager
+	 *
+	 */
+	public Image decorateWithOverlays(Image image, Object element, Object adaptedElement, IDecorationContext context,
+			ResourceManager manager) {
+
+		DecorationResult decoration = getResult(element, adaptedElement, context);
+
+		if (decoration == null) {
+			return image;
+		}
+		return decoration.decorateWithOverlays(image, manager);
+	}
+
+	/**
+	 * Return the DecorationResult for element. If there isn't one queue for
+	 * decoration and return <code>null</code>.
+	 *
+	 * @param element
+	 *            The element to be decorated. If it is <code>null</code>
+	 *            return <code>null</code>.
+	 * @param adaptedElement
+	 *            It's adapted value.
+	 * @param context
+	 *            The deocration context
+	 * @return DecorationResult or <code>null</code>
+	 */
+	private DecorationResult getResult(Object element, Object adaptedElement, IDecorationContext context) {
+
+		// We do not support decoration of null
+		if (element == null) {
+			return null;
+		}
+
+		DecorationResult decoration = internalGetResult(element, context);
+
+		if (decoration == null) {
+			queueForDecoration(element, adaptedElement, false, null, context);
+			return null;
+		}
+		return decoration;
+
+	}
+
+	private DecorationResult internalGetResult(Object element,
+			IDecorationContext context) {
+		Map results = (Map) resultCache.get(context);
+		if (results != null) {
+			return (DecorationResult) results.get(element);
+		}
+		return null;
+	}
+
+	protected void internalPutResult(Object element,
+			IDecorationContext context, DecorationResult result) {
+		Map results = (Map) resultCache.get(context);
+		if (results == null) {
+			results = new HashMap();
+			resultCache.put(context, results);
+		}
+		results.put(element, result);
+	}
+
+	/**
+	 * Execute a label update using the pending decorations.
+	 */
+	synchronized void decorated() {
+
+		// Don't bother if we are shutdown now
+		if (shutdown) {
+			return;
+		}
+
+		// Lazy initialize the job
+		if (updateJob == null) {
+			updateJob = getUpdateJob();
+		}
+
+		// Give it a bit of a lag for other updates to occur
+		updateJob.schedule(UPDATE_DELAY);
+	}
+
+	/**
+	 * Shutdown the decoration.
+	 */
+	synchronized void shutdown() {
+		shutdown = true;
+	}
+
+	/**
+	 * Get the next resource to be decorated.
+	 *
+	 * @return IResource
+	 */
+	synchronized DecorationReference nextElement() {
+
+		if (shutdown || awaitingDecoration.isEmpty()) {
+			return null;
+		}
+		Object element = awaitingDecoration.remove(0);
+
+		return (DecorationReference) awaitingDecorationValues.remove(element);
+	}
+
+	/**
+	 * Create the Thread used for running decoration.
+	 */
+	private void createDecorationJob() {
+		decorationJob = new Job(WorkbenchMessages.get().DecorationScheduler_CalculationJobName) {
+			@Override
+			public IStatus run(IProgressMonitor monitor) {
+
+				synchronized (DecorationScheduler.this) {
+					if (shutdown) {
+						return Status.CANCEL_STATUS;
+					}
+				}
+
+				while (updatesPending()) {
+
+					try {
+						Thread.sleep(100);
+					} catch (InterruptedException e) {
+						// Cancel and try again if there was an error
+						schedule();
+						return Status.CANCEL_STATUS;
+					}
+				}
+
+				SubMonitor subMonitor = SubMonitor.convert(monitor,
+						WorkbenchMessages.get().DecorationScheduler_CalculatingTask, awaitingDecoration.size());
+				// will block if there are no resources to be decorated
+				DecorationReference reference;
+
+				while ((reference = nextElement()) != null) {
+
+					subMonitor.split(1);
+
+					monitor.subTask(reference.getSubTask());
+					Object element = reference.getElement();
+					boolean force = reference.shouldForceUpdate();
+					IDecorationContext[] contexts = reference.getContexts();
+					for (IDecorationContext context : contexts) {
+						ensureResultCached(element, force, context);
+					}
+					// Only notify listeners when we have exhausted the
+					// queue of decoration requests.
+					synchronized (DecorationScheduler.this) {
+						if (awaitingDecoration.isEmpty()) {
+							decorated();
+						}
+					}
+				}
+				return Status.OK_STATUS;
+			}
+
+			/**
+			 * Ensure that a result is cached for the given element and context
+			 *
+			 * @param element
+			 *            the elements
+			 * @param force
+			 *            whether an update should be forced
+			 * @param context
+			 *            the decoration context
+			 */
+			private void ensureResultCached(Object element, boolean force,
+					IDecorationContext context) {
+				boolean elementIsCached = internalGetResult(element, context) != null;
+				if (elementIsCached) {
+					synchronized (pendingKey) {
+						pendingUpdate.add(element);
+					}
+
+				}
+
+				if (!elementIsCached) {
+					DecorationBuilder cacheResult = new DecorationBuilder(context);
+					// Calculate the decoration
+					decoratorManager.getLightweightManager().getDecorations(element, cacheResult);
+
+					// If we should update regardless then put a result
+					// anyways
+					if (cacheResult.hasValue() || force) {
+
+						// Synchronize on the result lock as we want to
+						// be sure that we do not try and decorate during
+						// label update servicing.
+						// Note: resultCache and pendingUpdate modifications
+						// must be done atomically.
+
+						// Add the decoration even if it's empty in
+						// order to indicate that the decoration is
+						// ready
+						internalPutResult(element, context, cacheResult.createResult());
+
+						// Add an update for only the original element
+						// to
+						// prevent multiple updates and clear the cache.
+						synchronized (pendingKey) {
+							pendingUpdate.add(element);
+						}
+
+
+					}
+				}
+			}
+
+			@Override
+			public boolean belongsTo(Object family) {
+				return DecoratorManager.FAMILY_DECORATE == family;
+			}
+
+			@Override
+			public boolean shouldRun() {
+				return PlatformUI.isWorkbenchRunning();
+			}
+		};
+
+		decorationJob.setSystem(true);
+		decorationJob.setPriority(Job.DECORATE);
+		decorationJob.schedule();
+	}
+
+	/**
+	 * Return whether or not we are waiting on updated
+	 *
+	 * @return <code>true</code> if there are updates waiting to be served
+	 */
+	protected boolean updatesPending() {
+		if (updateJob != null && updateJob.getState() != Job.NONE) {
+			return true;
+		}
+		if (clearJob != null && clearJob.getState() != Job.NONE) {
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * An external update request has been made. Clear the results as they are
+	 * likely obsolete now.
+	 */
+	void clearResults() {
+		if (clearJob == null) {
+			clearJob = getClearJob();
+		}
+		clearJob.schedule();
+	}
+
+	private Job getClearJob() {
+		Job clear = new Job(WorkbenchMessages.get().DecorationScheduler_ClearResultsJob) {
+
+			@Override
+			protected IStatus run(IProgressMonitor monitor) {
+				resultCache.clear();
+				return Status.OK_STATUS;
+			}
+
+			@Override
+			public boolean shouldRun() {
+				return PlatformUI.isWorkbenchRunning();
+			}
+
+		};
+		clear.setSystem(true);
+
+		return clear;
+	}
+
+	/**
+	 * Get the update WorkbenchJob.
+	 *
+	 * @return WorkbenchJob
+	 */
+	private WorkbenchJob getUpdateJob() {
+		WorkbenchJob job = new WorkbenchJob(WorkbenchMessages.get().DecorationScheduler_UpdateJobName) {
+
+			int currentIndex = NEEDS_INIT;
+
+			LabelProviderChangedEvent labelProviderChangedEvent;
+
+			ILabelProviderListener[] listeners;
+
+			@Override
+			public IStatus runInUIThread(IProgressMonitor monitor) {
+
+				synchronized (DecorationScheduler.this) {
+					if (shutdown) {
+						return Status.CANCEL_STATUS;
+					}
+				}
+
+				// If this is the first one check again in case
+				// someone has already cleared it out.
+				if (currentIndex == NEEDS_INIT) {
+					if (hasPendingUpdates()) {
+					    resetState();
+						return Status.OK_STATUS;
+					}
+					setUpUpdates();
+				}
+
+				if (listeners.length == 0) {
+				    resetState();
+				    return Status.OK_STATUS;
+				}
+
+				monitor.beginTask(WorkbenchMessages.get().DecorationScheduler_UpdatingTask, IProgressMonitor.UNKNOWN);
+
+				long startTime = System.currentTimeMillis();
+				while (currentIndex < listeners.length) {
+					ILabelProviderListener listener = listeners[currentIndex];
+					currentIndex++;
+
+					// If it was removed in the meantime then skip it.
+					if (!removedListeners.contains(listener)) {
+						decoratorManager.fireListener(
+								labelProviderChangedEvent, listener);
+					}
+
+					// If it is taking long enough for the user to notice then
+					// cancel the updates.
+					if ((System.currentTimeMillis() - startTime) >= UPDATE_DELAY / 2) {
+						break;
+					}
+				}
+
+				monitor.done();
+
+				if (currentIndex >= listeners.length) {
+				    resetState();
+					if (!hasPendingUpdates()) {
+						decorated();
+					}
+					labelProviderChangedEvent = null;
+					listeners = EMPTY_LISTENER_LIST;
+				} else {
+					schedule(UPDATE_DELAY);// Reschedule if we are not done
+				}
+				return Status.OK_STATUS;
+			}
+
+            /**
+             * Clear any cached information.
+             */
+            private void resetState() {
+                currentIndex = NEEDS_INIT;// Reset
+                removedListeners.clear();
+                // Other decoration requests may have occurred due to
+                // updates or we may have timed out updating listeners.
+                // Only clear the results if there are none pending.
+                if (awaitingDecoration.isEmpty()) {
+                    resultCache.clear();
+                }
+            }
+
+			private void setUpUpdates() {
+				// Get the elements awaiting update and then
+				// clear the list
+				removedListeners.clear();
+				currentIndex = 0;
+				synchronized (pendingKey) {
+					Object[] elements = pendingUpdate.toArray(new Object[pendingUpdate.size()]);
+					pendingUpdate.clear();
+					labelProviderChangedEvent = new LabelProviderChangedEvent(decoratorManager, elements);
+				}
+				listeners = decoratorManager.getListeners();
+			}
+
+			@Override
+			public boolean belongsTo(Object family) {
+				return DecoratorManager.FAMILY_DECORATE == family;
+			}
+
+			@Override
+			public boolean shouldRun() {
+				return PlatformUI.isWorkbenchRunning();
+			}
+		};
+
+		job.setSystem(true);
+		return job;
+	}
+
+	/**
+	 * Return whether or not there is a decoration for this element ready.
+	 *
+	 * @param element
+	 * @param context
+	 *            The decoration context
+	 * @return boolean true if the element is ready.
+	 */
+	public boolean isDecorationReady(Object element, IDecorationContext context) {
+		return internalGetResult(element, context) != null;
+	}
+
+	/**
+	 * Return the background Color for element. If there is no result cue for
+	 * decoration and return null, otherwise return the value in the result.
+	 *
+	 * @param element
+	 *            The Object to be decorated
+	 * @param adaptedElement
+	 * @return Color or <code>null</code> if there is no value or if it is has
+	 *         not been decorated yet.
+	 */
+	public Color getBackgroundColor(Object element, Object adaptedElement) {
+		DecorationResult decoration = getResult(element, adaptedElement, DecorationContext.DEFAULT_CONTEXT);
+
+		if (decoration == null) {
+			return null;
+		}
+		return decoration.getBackgroundColor();
+	}
+
+	/**
+	 * Return the font for element. If there is no result cue for decoration and
+	 * return null, otherwise return the value in the result.
+	 *
+	 * @param element
+	 *            The Object to be decorated
+	 * @param adaptedElement
+	 * @return Font or <code>null</code> if there is no value or if it is has
+	 *         not been decorated yet.
+	 */
+	public Font getFont(Object element, Object adaptedElement) {
+		DecorationResult decoration = getResult(element, adaptedElement, DecorationContext.DEFAULT_CONTEXT);
+
+		if (decoration == null) {
+			return null;
+		}
+		return decoration.getFont();
+	}
+
+	/**
+	 * Return the foreground Color for element. If there is no result cue for
+	 * decoration and return null, otherwise return the value in the result.
+	 *
+	 * @param element
+	 *            The Object to be decorated
+	 * @param adaptedElement
+	 * @return Color or <code>null</code> if there is no value or if it is has
+	 *         not been decorated yet.
+	 */
+	public Color getForegroundColor(Object element, Object adaptedElement) {
+		DecorationResult decoration = getResult(element, adaptedElement, DecorationContext.DEFAULT_CONTEXT);
+
+		if (decoration == null) {
+			return null;
+		}
+		return decoration.getForegroundColor();
+	}
+
+	/**
+	 * Return whether or not any updates are being processed/
+	 *
+	 * @return boolean
+	 */
+	public boolean processingUpdates() {
+		return !hasPendingUpdates() && !awaitingDecoration.isEmpty();
+	}
+
+	/**
+	 * A listener has been removed. If we are updating then skip it.
+	 *
+	 * @param listener
+	 */
+	void listenerRemoved(ILabelProviderListener listener) {
+		if (updatesPending()) {// Only keep track of them if there are updates
+			// pending
+			removedListeners.add(listener);
+		}
+		if (!updatesPending()) {
+			removedListeners.remove(listener);
+		}
+
+	}
+
+	/**
+	 * Return whether or not there are any updates pending.
+	 *
+	 * @return boolean <code>true</code> if the updates are empty
+	 */
+	boolean hasPendingUpdates() {
+		synchronized (pendingKey) {
+			return pendingUpdate.isEmpty();
+		}
+
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/DecoratorDefinition.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/DecoratorDefinition.java
new file mode 100644
index 0000000..2880dbe
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/DecoratorDefinition.java
@@ -0,0 +1,325 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.decorators;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.ui.IPluginContribution;
+import org.eclipse.ui.internal.ActionExpression;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.registry.RegistryReader;
+
+/**
+ * The DecoratorDefinition is the class that holds onto
+ * the label decorator, the name and the name of the
+ * class a decorator definition applies to,
+ */
+
+public abstract class DecoratorDefinition implements IPluginContribution {
+
+    private static final String ATT_LABEL = "label"; //$NON-NLS-1$
+
+    private static final String ATT_OBJECT_CLASS = "objectClass"; //$NON-NLS-1$
+
+    static final String CHILD_ENABLEMENT = "enablement"; //$NON-NLS-1$
+
+    private static final String ATT_ADAPTABLE = "adaptable"; //$NON-NLS-1$
+
+    private static final String ATT_ENABLED = "state"; //$NON-NLS-1$
+
+    private ActionExpression enablement;
+
+    protected boolean enabled;
+
+    private boolean defaultEnabled;
+
+    private String id;
+
+    protected IConfigurationElement definingElement;
+
+    //A flag that is set if there is an error creating the decorator
+    protected boolean labelProviderCreationFailed = false;
+
+	private boolean hasReadEnablement;
+
+	static final String ATT_CLASS = "class";//$NON-NLS-1$
+
+    /**
+     * Create a new instance of the receiver with the
+     * supplied values.
+     */
+
+    DecoratorDefinition(String identifier, IConfigurationElement element) {
+
+        this.id = identifier;
+        this.definingElement = element;
+
+        this.enabled = this.defaultEnabled = Boolean.valueOf(element.getAttribute(ATT_ENABLED)).booleanValue();
+    }
+
+    /**
+	 * Gets the name.
+	 *
+	 * @return Returns the label attribute from the decorator contribution, or
+	 *         null if the underlined definition is not valid anymore
+	 */
+    public String getName() {
+		if (!definingElement.isValid()) {
+			crashDisable();
+			return null;
+		}
+        return definingElement.getAttribute(ATT_LABEL);
+    }
+
+    /**
+	 * Returns the description
+	 *
+	 * @return Returns the label attribute from the decorator contribution, or
+	 *         null if the underlined definition is not valid anymore
+	 */
+    public String getDescription() {
+		if (!definingElement.isValid()) {
+			crashDisable();
+			return null;
+		}
+        return RegistryReader.getDescription(definingElement);
+    }
+
+    /**
+     * Gets the enabled.
+     * @return Returns a boolean
+     */
+    public boolean isEnabled() {
+        return enabled;
+    }
+
+    /**
+     * Sets the enabled flag and adds or removes the decorator
+     * manager as a listener as appropriate.
+     * @param newState The enabled to set
+     */
+    public void setEnabled(boolean newState) {
+
+        //Only refresh if there has been a change
+        if (this.enabled != newState) {
+            this.enabled = newState;
+            try {
+                refreshDecorator();
+            } catch (CoreException exception) {
+                handleCoreException(exception);
+            }
+
+        }
+    }
+
+    /**
+     * Refresh the current decorator based on our enable
+     * state.
+     */
+    protected abstract void refreshDecorator() throws CoreException;
+
+    /**
+     * Dispose the decorator instance and remove listeners
+     * as appropirate.
+     * @param disposedDecorator
+     */
+    protected void disposeCachedDecorator(IBaseLabelProvider disposedDecorator) {
+        disposedDecorator.removeListener(WorkbenchPlugin.getDefault()
+                .getDecoratorManager());
+        disposedDecorator.dispose();
+
+    }
+
+    /**
+     * Return whether or not this decorator should be
+     * applied to adapted types.
+     *
+     * @return whether or not this decorator should be
+     * applied to adapted types
+     */
+    public boolean isAdaptable() {
+		if (!definingElement.isValid()) {
+			crashDisable();
+			return false;
+		}
+    	return Boolean.valueOf(definingElement.getAttribute(ATT_ADAPTABLE)).booleanValue();
+    }
+
+    /**
+     * Gets the id.
+     * @return Returns a String
+     */
+    public String getId() {
+        return id;
+    }
+
+    /**
+     * Return the default value for this type - this value
+     * is the value read from the element description.
+     *
+     * @return the default value for this type - this value
+     * is the value read from the element description
+     */
+    public boolean getDefaultValue() {
+        return defaultEnabled;
+    }
+
+    /**
+     * Returns the enablement.
+     * @return ActionExpression
+     */
+    protected ActionExpression getEnablement() {
+    	if (!hasReadEnablement) {
+    		hasReadEnablement = true;
+    		initializeEnablement();
+    	}
+        return enablement;
+    }
+
+    /**
+     * Initialize the enablement expression for this decorator
+     */
+    protected void initializeEnablement() {
+		if (!definingElement.isValid()) {
+			crashDisable();
+			return;
+		}
+        IConfigurationElement[] elements = definingElement.getChildren(CHILD_ENABLEMENT);
+        if (elements.length == 0) {
+            String className = definingElement.getAttribute(ATT_OBJECT_CLASS);
+            if (className != null) {
+				enablement = new ActionExpression(ATT_OBJECT_CLASS,
+                        className);
+			}
+        } else {
+			enablement = new ActionExpression(elements[0]);
+		}
+    }
+
+    /**
+     * Add a listener for the decorator.If there is an exception
+     * then inform the user and disable the receiver.
+     * This method should not be called unless a check for
+     * isEnabled() has been done first.
+     */
+    void addListener(ILabelProviderListener listener) {
+        try {
+            //Internal decorator might be null so be prepared
+            IBaseLabelProvider currentDecorator = internalGetLabelProvider();
+            if (currentDecorator != null) {
+				currentDecorator.addListener(listener);
+			}
+        } catch (CoreException exception) {
+            handleCoreException(exception);
+        }
+    }
+
+    /**
+     * Return whether or not the decorator registered for element
+     * has a label property called property name. If there is an
+     * exception disable the receiver and return false.
+     * This method should not be called unless a check for
+     * isEnabled() has been done first.
+     */
+    boolean isLabelProperty(Object element, String property) {
+        try { //Internal decorator might be null so be prepared
+            IBaseLabelProvider currentDecorator = internalGetLabelProvider();
+            if (currentDecorator != null) {
+				return currentDecorator.isLabelProperty(element, property);
+			}
+        } catch (CoreException exception) {
+            handleCoreException(exception);
+            return false;
+        }
+        return false;
+    }
+
+    /**
+     * Gets the label provider and creates it if it does not exist yet.
+     * Throws a CoreException if there is a problem
+     * creating the labelProvider.
+     * This method should not be called unless a check for
+     * enabled to be true is done first.
+     * @return Returns a ILabelDecorator
+     */
+    protected abstract IBaseLabelProvider internalGetLabelProvider()
+            throws CoreException;
+
+    /**
+     * A CoreException has occured. Inform the user and disable
+     * the receiver.
+     */
+
+    protected void handleCoreException(CoreException exception) {
+
+        //If there is an error then reset the enabling to false
+        WorkbenchPlugin.log(exception);
+        crashDisable();
+    }
+
+    /**
+     * A crash has occured. Disable the receiver without notification.
+     */
+    public void crashDisable() {
+        this.enabled = false;
+    }
+
+    /**
+     * Return whether or not this is a full or lightweight definition.
+     * @return <code>true</code> if this is not a lightweight decorator.
+     */
+    public abstract boolean isFull();
+
+	/**
+	 * Return the configuration element.
+	 *
+	 * @return the configuration element
+	 * @since 3.1
+	 */
+	public IConfigurationElement getConfigurationElement() {
+		return definingElement;
+	}
+
+    /**
+     * Return whether the decorator is applicable to the given element
+     * @param element the element to be decorated
+     * @return whether the decorator w=should be applied to the element
+     */
+    public boolean isEnabledFor(Object element) {
+    	if(isEnabled()){
+    		ActionExpression expression =  getEnablement();
+    		if(expression != null) {
+				return expression.isEnabledFor(element);
+			}
+			// Always on if no expression and is still enabled
+			return isEnabled();
+    	}
+    	return false;
+
+    }
+
+	@Override
+	public String getPluginId() {
+		IConfigurationElement element = getConfigurationElement();
+		if (!element.isValid()) {
+			crashDisable();
+			return null;
+		}
+		return element.getContributor().getName();
+	}
+
+	@Override
+	public String getLocalId() {
+		return getId();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/DecoratorManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/DecoratorManager.java
new file mode 100644
index 0000000..1196c10
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/DecoratorManager.java
@@ -0,0 +1,1152 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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.ui.internal.decorators;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.StringTokenizer;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.dynamichelpers.ExtensionTracker;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.jface.resource.ResourceManager;
+import org.eclipse.jface.util.SafeRunnable;
+import org.eclipse.jface.viewers.DecorationContext;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.jface.viewers.IColorDecorator;
+import org.eclipse.jface.viewers.IDecorationContext;
+import org.eclipse.jface.viewers.IDelayedLabelDecorator;
+import org.eclipse.jface.viewers.IFontDecorator;
+import org.eclipse.jface.viewers.ILabelDecorator;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.ILightweightLabelDecorator;
+import org.eclipse.jface.viewers.LabelDecorator;
+import org.eclipse.jface.viewers.LabelProviderChangedEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.IDecoratorManager;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.IPreferenceConstants;
+import org.eclipse.ui.internal.LegacyResourceSupport;
+import org.eclipse.ui.internal.Workbench;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.util.PrefUtil;
+import org.eclipse.ui.internal.util.Util;
+import org.eclipse.ui.progress.WorkbenchJob;
+
+/**
+ * The DecoratorManager is the class that handles all of the decorators defined
+ * in the image.
+ *
+ * @since 2.0
+ */
+public class DecoratorManager implements ILabelProviderListener,
+		IDecoratorManager, IExtensionChangeHandler {
+
+ // RAP [rh] extension point namespace (see bug 293379)
+//  private static String EXTENSIONPOINT_UNIQUE_ID = WorkbenchPlugin.PI_WORKBENCH
+//          + "." + IWorkbenchRegistryConstants.PL_DECORATORS; //$NON-NLS-1$
+    private static String EXTENSIONPOINT_UNIQUE_ID
+      = PlatformUI.PLUGIN_EXTENSION_NAME_SPACE
+      + "." 
+      + IWorkbenchRegistryConstants.PL_DECORATORS; //$NON-NLS-1$
+
+	/**
+	 * The family for the decorate job.
+	 */
+	public static final Object FAMILY_DECORATE = new Object();
+
+	private DecorationScheduler scheduler;
+
+	private LightweightDecoratorManager lightweightManager;
+
+	// Hold onto the list of listeners to be told if a change has occured
+	private ListenerList<ILabelProviderListener> listeners = new ListenerList<>();
+
+	// The full definitions read from the registry.
+	// Initalize to an empty collection as this is rarely used now.
+	private FullDecoratorDefinition[] fullDefinitions;
+
+	private FullTextDecoratorRunnable fullTextRunnable = new FullTextDecoratorRunnable();
+
+	private FullImageDecoratorRunnable fullImageRunnable = new FullImageDecoratorRunnable();
+
+	private static final FullDecoratorDefinition[] EMPTY_FULL_DEF = new FullDecoratorDefinition[0];
+
+	private final String PREFERENCE_SEPARATOR = ","; //$NON-NLS-1$
+
+	private final String VALUE_SEPARATOR = ":"; //$NON-NLS-1$
+
+	private final String P_TRUE = "true"; //$NON-NLS-1$
+
+	private final String P_FALSE = "false"; //$NON-NLS-1$
+
+	private LocalResourceManager resourceManager;
+
+
+	/**
+	 * ManagedWorkbenchLabelDecorator is the internal LabelDecorator
+	 * passed as result of calls to {@link IDecoratorManager#getLabelDecorator()}
+	 * @since 3.4
+	 *
+	 */
+	private static class ManagedWorkbenchLabelDecorator extends LabelDecorator
+			implements ILabelDecorator, IDelayedLabelDecorator,
+			IColorDecorator, IFontDecorator {
+
+		private final DecoratorManager decoratorManager;
+		private LocalResourceManager resourceManager;
+
+		/**
+		 * Create a new instance of the receiver that supports decoratorManager
+		 * @param decoratorManager
+		 */
+		public ManagedWorkbenchLabelDecorator(DecoratorManager decoratorManager) {
+			this.decoratorManager = decoratorManager;
+			this.resourceManager = null;
+		}
+
+		/**
+		 * Return a resource manager local to the receiver.
+		 * @return {@link LocalResourceManager}
+		 */
+		private LocalResourceManager getResourceManager() {
+			if (resourceManager == null) {
+				resourceManager = new LocalResourceManager(decoratorManager
+						.getResourceManager());
+			}
+			return resourceManager;
+		}
+
+		@Override
+		public Image decorateImage(Image image, Object element,
+				IDecorationContext context) {
+			return decoratorManager.decorateImage(image, element, context,
+					getResourceManager());
+		}
+
+		@Override
+		public String decorateText(String text, Object element,
+				IDecorationContext context) {
+			return decoratorManager.decorateText(text, element, context);
+		}
+
+		@Override
+		public boolean prepareDecoration(Object element, String originalText,
+				IDecorationContext context) {
+			return decoratorManager.prepareDecoration(element, originalText,
+					context);
+		}
+
+		@Override
+		public boolean prepareDecoration(Object element, String originalText) {
+			return prepareDecoration(element, originalText,
+					DecorationContext.DEFAULT_CONTEXT);
+		}
+
+		@Override
+		public Font decorateFont(Object element) {
+			return decoratorManager.decorateFont(element);
+		}
+
+		@Override
+		public Color decorateBackground(Object element) {
+			return decoratorManager.decorateBackground(element);
+		}
+
+		@Override
+		public Color decorateForeground(Object element) {
+			return decoratorManager.decorateForeground(element);
+		}
+
+		@Override
+		public Image decorateImage(Image image, Object element) {
+			return decorateImage(image, element,
+					DecorationContext.DEFAULT_CONTEXT);
+		}
+
+		@Override
+		public String decorateText(String text, Object element) {
+			return decorateText(text, element,
+					DecorationContext.DEFAULT_CONTEXT);
+		}
+
+		@Override
+		public void addListener(ILabelProviderListener listener) {
+			decoratorManager.addListener(listener);
+		}
+
+		@Override
+		public void dispose() {
+			if (resourceManager != null) {
+				resourceManager.dispose();
+				resourceManager = null;
+			}
+		}
+
+		@Override
+		public boolean isLabelProperty(Object element, String property) {
+			return decoratorManager.isLabelProperty(element, property);
+		}
+
+		@Override
+		public void removeListener(ILabelProviderListener listener) {
+			decoratorManager.removeListener(listener);
+		}
+
+	}
+
+	/**
+	 * Create a new instance of the receiver and load the settings from the
+	 * installed plug-ins.
+	 */
+	public DecoratorManager() {
+
+		scheduler = new DecorationScheduler(this);
+		IExtensionTracker tracker = PlatformUI.getWorkbench()
+				.getExtensionTracker();
+		tracker.registerHandler(this, ExtensionTracker
+				.createExtensionPointFilter(getExtensionPointFilter()));
+
+		resourceManager = null;
+	}
+
+	/**
+	 * Initalize the decorator definitions.
+	 */
+	private void initializeDecoratorDefinitions() {
+		DecoratorRegistryReader reader = new DecoratorRegistryReader();
+		Collection values = reader
+				.readRegistry(Platform.getExtensionRegistry());
+
+		ArrayList full = new ArrayList();
+		ArrayList lightweight = new ArrayList();
+		Iterator allDefinitions = values.iterator();
+		IExtensionTracker configurationElementTracker = PlatformUI
+				.getWorkbench().getExtensionTracker();
+		while (allDefinitions.hasNext()) {
+			DecoratorDefinition nextDefinition = (DecoratorDefinition) allDefinitions
+					.next();
+			if (nextDefinition.isFull()) {
+				full.add(nextDefinition);
+			} else {
+				lightweight.add(nextDefinition);
+			}
+
+			configurationElementTracker.registerObject(nextDefinition
+					.getConfigurationElement().getDeclaringExtension(),
+					nextDefinition, IExtensionTracker.REF_WEAK);
+		}
+
+		fullDefinitions = new FullDecoratorDefinition[full.size()];
+		full.toArray(fullDefinitions);
+
+		LightweightDecoratorDefinition[] lightweightDefinitions = new LightweightDecoratorDefinition[lightweight
+				.size()];
+		lightweight.toArray(lightweightDefinitions);
+
+		lightweightManager = new LightweightDecoratorManager(
+				lightweightDefinitions);
+
+		applyDecoratorsPreference();
+	}
+
+	/**
+	 * For dynamic UI
+	 *
+	 * @param definition
+	 *            the definition to add
+	 * @since 3.0
+	 */
+	public void addDecorator(DecoratorDefinition definition) {
+		if (definition.isFull()) {
+			if (getFullDecoratorDefinition(definition.getId()) == null) {
+				FullDecoratorDefinition[] oldDefs = getFullDefinitions();
+				fullDefinitions = new FullDecoratorDefinition[fullDefinitions.length + 1];
+				System
+						.arraycopy(oldDefs, 0, fullDefinitions, 0,
+								oldDefs.length);
+				fullDefinitions[oldDefs.length] = (FullDecoratorDefinition) definition;
+				clearCaches();
+				updateForEnablementChange();
+			}
+		} else {
+			if (getLightweightManager().addDecorator(
+					(LightweightDecoratorDefinition) definition)) {
+				clearCaches();
+				updateForEnablementChange();
+			}
+		}
+		((Workbench) PlatformUI.getWorkbench()).getExtensionTracker()
+				.registerObject(
+						definition.getConfigurationElement()
+								.getDeclaringExtension(), definition,
+						IExtensionTracker.REF_WEAK);
+	}
+
+	/**
+	 * See if the supplied decorator cache has a value for the element. If not
+	 * calculate it from the enabledDefinitions and update the cache.
+	 *
+	 * @return Collection of DecoratorDefinition.
+	 * @param element
+	 *            The element being tested.
+	 * @param enabledDefinitions
+	 *            The definitions currently defined for this decorator.
+	 */
+	static Collection getDecoratorsFor(Object element,
+			DecoratorDefinition[] enabledDefinitions) {
+
+		ArrayList decorators = new ArrayList();
+
+		for (DecoratorDefinition enabledDefinition : enabledDefinitions) {
+			if (enabledDefinition.isEnabledFor(element)) {
+				decorators.add(enabledDefinition);
+			}
+		}
+
+		return decorators;
+
+	}
+
+	/**
+	 * Add the listener to the list of listeners.
+	 */
+	@Override
+	public void addListener(ILabelProviderListener listener) {
+		listeners.add(listener);
+	}
+
+	/**
+	 * Remove the listener from the list.
+	 */
+	@Override
+	public void removeListener(ILabelProviderListener listener) {
+		listeners.remove(listener);
+		scheduler.listenerRemoved(listener);
+	}
+
+	/**
+	 * Get the list of elements listening to the receiver.
+	 *
+	 * @return ILabelProviderListener []
+	 */
+	ILabelProviderListener[] getListeners() {
+		Object[] array = listeners.getListeners();
+		ILabelProviderListener[] listenerArray = new ILabelProviderListener[array.length];
+		System.arraycopy(array, 0, listenerArray, 0, listenerArray.length);
+		return listenerArray;
+	}
+
+	/**
+	 * Inform all of the listeners that require an update
+	 *
+	 * @param listener
+	 *            The listener we are updating.
+	 * @param event
+	 *            the event with the update details
+	 */
+	void fireListener(final LabelProviderChangedEvent event,
+			final ILabelProviderListener listener) {
+		SafeRunner.run(new SafeRunnable() {
+			@Override
+			public void run() {
+				listener.labelProviderChanged(event);
+			}
+		});
+
+	}
+
+	/**
+	 * Inform all of the listeners that require an update
+	 *
+	 * @param event
+	 *            the event with the update details
+	 */
+	void fireListeners(final LabelProviderChangedEvent event) {
+		for (final ILabelProviderListener l : listeners) {
+			SafeRunner.run(new SafeRunnable() {
+				@Override
+				public void run() {
+					l.labelProviderChanged(event);
+				}
+			});
+		}
+	}
+
+	/**
+	 * Fire any listeners from the UIThread. Used for cases where this may be
+	 * invoked outside of the UI by the public API.
+	 *
+	 * @param event
+	 *            the event with the update details
+	 */
+	void fireListenersInUIThread(final LabelProviderChangedEvent event) {
+
+		// No updates if there is no UI
+		if (!PlatformUI.isWorkbenchRunning()) {
+			return;
+		}
+
+		// Only bother with the job if in the UI Thread
+		if (Thread.currentThread() == PlatformUI.getWorkbench().getDisplay()
+				.getThread()) {
+			fireListeners(event);
+			return;
+		}
+
+		WorkbenchJob updateJob = new WorkbenchJob(
+				WorkbenchMessages.get().DecorationScheduler_UpdateJobName) {
+			@Override
+			public IStatus runInUIThread(IProgressMonitor monitor) {
+				fireListeners(event);
+				return Status.OK_STATUS;
+			}
+
+			@Override
+			public boolean belongsTo(Object family) {
+				return FAMILY_DECORATE == family;
+			}
+		};
+		updateJob.setSystem(true);
+		updateJob.schedule();
+
+	}
+
+
+	/**
+	 * Decorate the text in the reciever using the context.
+	 * @param text
+	 * @param element
+	 * @param context
+	 * @return String
+	 * @see LabelDecorator#decorateText(String, Object, IDecorationContext)
+	 */
+	public String decorateText(String text, Object element,
+			IDecorationContext context) {
+		// Get any adaptations to IResource
+		Object adapted = getResourceAdapter(element);
+		String result = scheduler.decorateWithText(text, element, adapted,
+				context);
+		for (FullDecoratorDefinition decorator : getDecoratorsFor(element)) {
+			if (decorator.isEnabledFor(element)) {
+				String newResult = safeDecorateText(element, result,
+						decorator);
+				if (newResult != null) {
+					result = newResult;
+				}
+			}
+		}
+
+		if (adapted != null) {
+			for (FullDecoratorDefinition decorator : getDecoratorsFor(adapted)) {
+				if (decorator.isAdaptable()
+						&& decorator.isEnabledFor(adapted)) {
+					String newResult = safeDecorateText(adapted, result,
+							decorator);
+					if (newResult != null) {
+						result = newResult;
+					}
+				}
+			}
+		}
+
+		return result;
+	}
+
+
+	@Override
+	public String decorateText(String text, Object element) {
+		return decorateText(text, element, DecorationContext.DEFAULT_CONTEXT);
+	}
+
+	/**
+	 * Decorate the text in a SafeRunnable.
+	 *
+	 * @param element
+	 *            The element we are decorating
+	 * @param start
+	 *            The currently decorated String
+	 * @param decorator
+	 *            The decorator to run.
+	 * @return String
+	 */
+	private String safeDecorateText(Object element, String start,
+			FullDecoratorDefinition decorator) {
+		fullTextRunnable.setValues(start, element, decorator);
+		SafeRunner.run(fullTextRunnable);
+		String newResult = fullTextRunnable.getResult();
+		return newResult;
+	}
+
+	/**
+	 * Decorate the image within the context. Allocate any new images in
+	 * localResourceManager
+	 * @param image
+	 * @param element
+	 * @param context
+	 * @param localResourceManager
+	 * @return Image
+	 * @see LabelDecorator#decorateImage(Image, Object, IDecorationContext)
+	 */
+	public Image decorateImage(Image image, Object element,
+			IDecorationContext context, ResourceManager localResourceManager) {
+		Object adapted = getResourceAdapter(element);
+		Image result = scheduler.decorateWithOverlays(image, element, adapted,
+				context, localResourceManager);
+
+		for (FullDecoratorDefinition decorator : getDecoratorsFor(element)) {
+			if (decorator.isEnabledFor(element)) {
+				Image newResult = safeDecorateImage(element, result,
+						decorator);
+				if (newResult != null) {
+					result = newResult;
+				}
+			}
+		}
+
+		// Get any adaptations to IResource
+
+		if (adapted != null) {
+			for (FullDecoratorDefinition decorator : getDecoratorsFor(adapted)) {
+				if (decorator.isAdaptable()
+						&& decorator.isEnabledFor(adapted)) {
+					Image newResult = safeDecorateImage(adapted, result,
+							decorator);
+					if (newResult != null) {
+						result = newResult;
+					}
+				}
+			}
+		}
+
+		return result;
+	}
+
+	@Override
+	public Image decorateImage(Image image, Object element) {
+		return decorateImage(image, element, DecorationContext.DEFAULT_CONTEXT,
+				getResourceManager());
+	}
+
+	/**
+	 * Decorate the image in a SafeRunnable.
+	 *
+	 * @param element
+	 *            The element we are decorating
+	 * @param start
+	 *            The currently decorated Image
+	 * @param decorator
+	 *            The decorator to run.
+	 * @return Image
+	 */
+	private Image safeDecorateImage(Object element, Image start,
+			FullDecoratorDefinition decorator) {
+		fullImageRunnable.setValues(start, element, decorator);
+		SafeRunner.run(fullImageRunnable);
+		Image newResult = fullImageRunnable.getResult();
+		return newResult;
+	}
+
+	/**
+	 * Get the resource adapted object for the supplied element. Return
+	 * <code>null</code>. if there isn't one.
+	 *
+	 * @param element
+	 * @return Object or <code>null</code>.
+	 */
+	private Object getResourceAdapter(Object element) {
+		Object adapted = LegacyResourceSupport
+				.getAdaptedContributorResource(element);
+		if (adapted != element) {
+			return adapted; // Avoid applying decorator twice
+		}
+		return null;
+	}
+
+	/**
+	 * Return whether or not the decorator registered for element has a label
+	 * property called property name.
+	 */
+	@Override
+	public boolean isLabelProperty(Object element, String property) {
+		return isLabelProperty(element, property, true);
+	}
+
+	/**
+	 * Return whether or not the decorator registered for element has a label
+	 * property called property name. Check for an adapted resource if
+	 * checkAdapted is true.
+	 *
+	 * @param element
+	 * @param property
+	 * @param checkAdapted
+	 * @return boolean <code>true</code> if there is a label property for
+	 *         element or its adapted value
+	 */
+	public boolean isLabelProperty(Object element, String property,
+			boolean checkAdapted) {
+		boolean fullCheck = isLabelProperty(element, property,
+				getDecoratorsFor(element));
+
+		if (fullCheck) {
+			return fullCheck;
+		}
+
+		boolean lightweightCheck = isLabelProperty(element, property,
+				getLightweightManager().getDecoratorsFor(element));
+
+		if (lightweightCheck) {
+			return true;
+		}
+
+		if (checkAdapted) {
+			// Get any adaptions to IResource
+			Object adapted = getResourceAdapter(element);
+			if (adapted == null || adapted == element) {
+				return false;
+			}
+
+			fullCheck = isLabelProperty(adapted, property,
+					getDecoratorsFor(adapted));
+			if (fullCheck) {
+				return fullCheck;
+			}
+
+			return isLabelProperty(adapted, property, lightweightManager
+					.getDecoratorsFor(adapted));
+		}
+		return false;
+	}
+
+	private boolean isLabelProperty(Object element, String property,
+			DecoratorDefinition[] decorators) {
+		for (DecoratorDefinition decorator : decorators) {
+			if (decorator.isEnabledFor(element)
+					&& decorator.isLabelProperty(element, property)) {
+				return true;
+			}
+		}
+
+		return false;
+	}
+
+	/**
+	 * Return the enabled full decorator definitions.
+	 *
+	 * @return FullDecoratorDefinition[]
+	 */
+	private FullDecoratorDefinition[] enabledFullDefinitions() {
+
+		FullDecoratorDefinition[] fullDefinitions = getFullDefinitions();
+		// As this are a deprecated data type optimize for
+		// the undefined case.
+		if (fullDefinitions.length == 0) {
+			return fullDefinitions;
+		}
+		ArrayList result = new ArrayList();
+		for (FullDecoratorDefinition element : fullDefinitions) {
+			if (element.isEnabled()) {
+				result.add(element);
+			}
+		}
+		FullDecoratorDefinition[] returnArray = new FullDecoratorDefinition[result
+				.size()];
+		result.toArray(returnArray);
+		return returnArray;
+	}
+
+	/*
+	 * @see IBaseLabelProvider#dispose()
+	 */
+	@Override
+	public void dispose() {
+		// do nothing
+	}
+
+	/**
+	 * Clear the caches in the manager. This is required to avoid updates that
+	 * may occur due to changes in enablement.
+	 */
+	public void clearCaches() {
+		getLightweightManager().reset();
+		fullTextRunnable.clearReferences();
+		fullImageRunnable.clearReferences();
+	}
+
+	/**
+	 * Enablement had changed. Fire the listeners and write the preference.
+	 */
+	public void updateForEnablementChange() {
+		// Clear any results that may be around as all labels have changed
+		scheduler.clearResults();
+		fireListenersInUIThread(new LabelProviderChangedEvent(this));
+		writeDecoratorsPreference();
+	}
+
+	/**
+	 * Get the DecoratorDefinitions defined on the receiver.
+	 *
+	 * @return DecoratorDefinition[]
+	 */
+	public DecoratorDefinition[] getAllDecoratorDefinitions() {
+		LightweightDecoratorDefinition[] lightweightDefinitions = getLightweightManager()
+				.getDefinitions();
+		DecoratorDefinition[] returnValue = new DecoratorDefinition[fullDefinitions.length
+				+ lightweightDefinitions.length];
+		System.arraycopy(fullDefinitions, 0, returnValue, 0,
+				fullDefinitions.length);
+		System.arraycopy(lightweightDefinitions, 0, returnValue,
+				fullDefinitions.length, lightweightDefinitions.length);
+		return returnValue;
+	}
+
+	/*
+	 * @see ILabelProviderListener#labelProviderChanged(LabelProviderChangedEvent)
+	 */
+	@Override
+	public void labelProviderChanged(LabelProviderChangedEvent event) {
+		Object[] elements = event.getElements();
+		scheduler.clearResults();
+		// If the elements are not specified send out a general update
+		if (elements == null) {
+			fireListeners(event);
+		} else {
+			// Assume that someone is going to care about the
+			// decoration result and just start it right away
+			for (Object element : elements) {
+				Object adapted = getResourceAdapter(element);
+				// Force an update in case full decorators are the only ones
+				// enabled
+				scheduler.queueForDecoration(element, adapted, true, null,
+						DecorationContext.DEFAULT_CONTEXT);
+			}
+		}
+	}
+
+	/**
+	 * Store the currently enabled decorators in preference store.
+	 */
+	private void writeDecoratorsPreference() {
+		StringBuffer enabledIds = new StringBuffer();
+		writeDecoratorsPreference(enabledIds, getFullDefinitions());
+		writeDecoratorsPreference(enabledIds, getLightweightManager()
+				.getDefinitions());
+
+		WorkbenchPlugin.getDefault().getPreferenceStore().setValue(
+				IPreferenceConstants.ENABLED_DECORATORS, enabledIds.toString());
+		PrefUtil.savePrefs();
+	}
+
+	private void writeDecoratorsPreference(StringBuffer enabledIds,
+			DecoratorDefinition[] definitions) {
+		for (DecoratorDefinition definition : definitions) {
+			enabledIds.append(definition.getId());
+			enabledIds.append(VALUE_SEPARATOR);
+			if (definition.isEnabled()) {
+				enabledIds.append(P_TRUE);
+			} else {
+				enabledIds.append(P_FALSE);
+			}
+
+			enabledIds.append(PREFERENCE_SEPARATOR);
+		}
+	}
+
+	/**
+	 * Get the currently enabled decorators in preference store and set the
+	 * state of the current definitions accordingly.
+	 */
+	public void applyDecoratorsPreference() {
+
+		String preferenceValue = WorkbenchPlugin.getDefault()
+				.getPreferenceStore().getString(
+						IPreferenceConstants.ENABLED_DECORATORS);
+
+		StringTokenizer tokenizer = new StringTokenizer(preferenceValue,
+				PREFERENCE_SEPARATOR);
+		Set enabledIds = new HashSet();
+		Set disabledIds = new HashSet();
+		while (tokenizer.hasMoreTokens()) {
+			String nextValuePair = tokenizer.nextToken();
+
+			// Strip out the true or false to get the id
+			String id = nextValuePair.substring(0, nextValuePair
+					.indexOf(VALUE_SEPARATOR));
+			if (nextValuePair.endsWith(P_TRUE)) {
+				enabledIds.add(id);
+			} else {
+				disabledIds.add(id);
+			}
+		}
+
+		for (FullDecoratorDefinition element : getFullDefinitions()) {
+			String id = element.getId();
+			if (enabledIds.contains(id)) {
+				element.setEnabled(true);
+			} else {
+				if (disabledIds.contains(id)) {
+					element.setEnabled(false);
+				}
+			}
+		}
+
+		LightweightDecoratorDefinition[] lightweightDefinitions = getLightweightManager()
+				.getDefinitions();
+		for (LightweightDecoratorDefinition lightweightDefinition : lightweightDefinitions) {
+			String id = lightweightDefinition.getId();
+			if (enabledIds.contains(id)) {
+				lightweightDefinition.setEnabled(true);
+			} else {
+				if (disabledIds.contains(id)) {
+					lightweightDefinition.setEnabled(false);
+				}
+			}
+		}
+
+	}
+
+	/**
+	 * Shutdown the decorator manager by disabling all of the decorators so that
+	 * dispose() will be called on them.
+	 */
+	public void shutdown() {
+		// Disable all of the enabled decorators
+		// so as to force a dispose of thier decorators
+		FullDecoratorDefinition[] full = getFullDefinitions();
+		for (FullDecoratorDefinition element : full) {
+			if (element.isEnabled()) {
+				element.setEnabled(false);
+			}
+		}
+		if (lightweightManager != null) {
+			getLightweightManager().shutdown();
+		}
+		scheduler.shutdown();
+		dispose();
+	}
+
+	@Override
+	public boolean getEnabled(String decoratorId) {
+		DecoratorDefinition definition = getDecoratorDefinition(decoratorId);
+		if (definition == null) {
+			return false;
+		}
+		return definition.isEnabled();
+	}
+
+	/**
+	 * @see IDecoratorManager#getLabelDecorator()
+	 */
+	@Override
+	public ILabelDecorator getLabelDecorator() {
+		return new ManagedWorkbenchLabelDecorator(this);
+	}
+
+	/**
+	 * Returns the resource manager used to created images for the light weight
+	 * decorator.
+	 *
+	 * @return the resource manager
+	 */
+	public ResourceManager getResourceManager() {
+		if (resourceManager == null) {
+			resourceManager = new LocalResourceManager(JFaceResources
+					.getResources(PlatformUI.getWorkbench().getDisplay()));
+		}
+		return resourceManager;
+	}
+
+	/**
+	 * @see IDecoratorManager#setEnabled(String, boolean)
+	 */
+	@Override
+	public void setEnabled(String decoratorId, boolean enabled) {
+		DecoratorDefinition definition = getDecoratorDefinition(decoratorId);
+		if (definition != null) {
+			definition.setEnabled(enabled);
+			clearCaches();
+			updateForEnablementChange();
+		}
+	}
+
+	/*
+	 * @see IDecoratorManager#getBaseLabelProvider(String)
+	 */
+	@Override
+	public IBaseLabelProvider getBaseLabelProvider(String decoratorId) {
+		IBaseLabelProvider fullProvider = getLabelDecorator(decoratorId);
+		if (fullProvider == null) {
+			return getLightweightLabelDecorator(decoratorId);
+		}
+		return fullProvider;
+	}
+
+	/*
+	 * @see IDecoratorManager#getLabelDecorator(String)
+	 */
+	@Override
+	public ILabelDecorator getLabelDecorator(String decoratorId) {
+		FullDecoratorDefinition definition = getFullDecoratorDefinition(decoratorId);
+
+		// Do not return for a disabled decorator
+		if (definition != null && definition.isEnabled()) {
+			ILabelDecorator result = definition.getDecorator();
+			if (result == null) {
+				try {
+					result = definition.internalGetDecorator();
+				} catch (CoreException e) {
+					WorkbenchPlugin.log(e);
+				}
+			}
+			return result;
+		}
+		return null;
+	}
+
+	/*
+	 * @see IDecoratorManager#getLightweightLabelDecorator(String)
+	 */
+	@Override
+	public ILightweightLabelDecorator getLightweightLabelDecorator(
+			String decoratorId) {
+		LightweightDecoratorDefinition definition = getLightweightManager()
+				.getDecoratorDefinition(decoratorId);
+		// Do not return for a disabled decorator
+		if (definition != null && definition.isEnabled()) {
+			return definition.getDecorator();
+		}
+		return null;
+	}
+
+	/**
+	 * Get the DecoratorDefinition with the supplied id
+	 *
+	 * @return DecoratorDefinition or <code>null</code> if it is not found
+	 * @param decoratorId
+	 *            String
+	 */
+	private DecoratorDefinition getDecoratorDefinition(String decoratorId) {
+		DecoratorDefinition returnValue = getFullDecoratorDefinition(decoratorId);
+		if (returnValue == null) {
+			return getLightweightManager().getDecoratorDefinition(decoratorId);
+		}
+		return returnValue;
+	}
+
+	/**
+	 * Get the FullDecoratorDefinition with the supplied id
+	 *
+	 * @return FullDecoratorDefinition or <code>null</code> if it is not found
+	 * @param decoratorId
+	 *            the id
+	 */
+	private FullDecoratorDefinition getFullDecoratorDefinition(
+			String decoratorId) {
+		int idx = getFullDecoratorDefinitionIdx(decoratorId);
+		if (idx != -1) {
+			return getFullDefinitions()[idx];
+		}
+		return null;
+	}
+
+	/**
+	 * Return the index of the definition in the array.
+	 *
+	 * @param decoratorId
+	 *            the id
+	 * @return the index of the definition in the array or <code>-1</code>
+	 * @since 3.1
+	 */
+	private int getFullDecoratorDefinitionIdx(String decoratorId) {
+		FullDecoratorDefinition[] full = getFullDefinitions();
+		for (int i = 0; i < full.length; i++) {
+			if (full[i].getId().equals(decoratorId)) {
+				return i;
+			}
+		}
+		return -1;
+	}
+
+	/**
+	 * Get the full decorator definitions registered for elements of this type.
+	 *
+	 * @param element
+	 *            The element to look up
+	 * @return FullDecoratorDefinition[]
+	 */
+	private FullDecoratorDefinition[] getDecoratorsFor(Object element) {
+
+		if (element == null) {
+			return EMPTY_FULL_DEF;
+		}
+
+		Collection decorators = getDecoratorsFor(element,
+				enabledFullDefinitions());
+		FullDecoratorDefinition[] decoratorArray = EMPTY_FULL_DEF;
+		if (decorators.size() > 0) {
+			decoratorArray = new FullDecoratorDefinition[decorators.size()];
+			decorators.toArray(decoratorArray);
+		}
+
+		return decoratorArray;
+	}
+
+	/**
+	 * Returns the lightweightManager. This method is public for use by test
+	 * cases. No other classes outside of this package should use this method.
+	 *
+	 * @return LightweightDecoratorManager
+	 */
+	public LightweightDecoratorManager getLightweightManager() {
+		if (lightweightManager == null) {
+			initializeDecoratorDefinitions();
+		}
+		return lightweightManager;
+	}
+
+	/**
+	 * @see org.eclipse.ui.IDecoratorManager#update(java.lang.String)
+	 */
+	@Override
+	public void update(String decoratorId) {
+
+		IBaseLabelProvider provider = getBaseLabelProvider(decoratorId);
+		if (provider != null) {
+			scheduler.clearResults();
+			fireListeners(new LabelProviderChangedEvent(provider));
+		}
+
+	}
+
+	public boolean prepareDecoration(Object element, String originalText,
+			IDecorationContext context) {
+		// Check if there is a decoration ready or if there is no lightweight
+		// decorators to be applied
+		if (scheduler.isDecorationReady(element, context)
+				|| !getLightweightManager().hasEnabledDefinitions()) {
+			return true;
+		}
+
+		// Force an update if there is a text already
+		boolean force = true;
+		// If not then do not force as the undecorated value is fine
+		if (originalText == null || originalText.length() == 0) {
+			force = false;
+		}
+
+		// Queue the decoration.
+		scheduler.queueForDecoration(element, getResourceAdapter(element),
+				force, originalText, context);
+
+		// If we are going to force an update just let that happen later.
+		return !force;
+	}
+
+	@Override
+	public boolean prepareDecoration(Object element, String originalText) {
+		return prepareDecoration(element, originalText,
+				DecorationContext.DEFAULT_CONTEXT);
+	}
+
+	public Font decorateFont(Object element) {
+		return scheduler.getFont(element, getResourceAdapter(element));
+	}
+
+	public Color decorateBackground(Object element) {
+		return scheduler.getBackgroundColor(element,
+				getResourceAdapter(element));
+	}
+
+	public Color decorateForeground(Object element) {
+		return scheduler.getForegroundColor(element,
+				getResourceAdapter(element));
+	}
+
+	/**
+	 * Get all of the defined fullDefinitions. Initalize if required
+	 *
+	 * @return FullDecoratorDefinition[]
+	 */
+	private FullDecoratorDefinition[] getFullDefinitions() {
+		if (fullDefinitions == null) {
+			initializeDecoratorDefinitions();
+		}
+		return fullDefinitions;
+	}
+
+	private IExtensionPoint getExtensionPointFilter() {
+		return Platform.getExtensionRegistry().getExtensionPoint(
+				EXTENSIONPOINT_UNIQUE_ID);
+	}
+
+	@Override
+	public void addExtension(IExtensionTracker tracker,
+			IExtension addedExtension) {
+		for (IConfigurationElement addedElement : addedExtension.getConfigurationElements()) {
+			DecoratorRegistryReader reader = new DecoratorRegistryReader();
+			reader.readElement(addedElement);
+			for (Iterator j = reader.getValues().iterator(); j.hasNext();) {
+				addDecorator((DecoratorDefinition) j.next());
+			}
+		}
+	}
+
+	@Override
+	public void removeExtension(IExtension source, Object[] objects) {
+
+		boolean shouldClear = false;
+		for (Object object : objects) {
+			if (object instanceof DecoratorDefinition) {
+				DecoratorDefinition definition = (DecoratorDefinition) object;
+				if (definition.isFull()) {
+					int idx = getFullDecoratorDefinitionIdx(definition.getId());
+					if (idx != -1) {
+						FullDecoratorDefinition[] oldDefs = getFullDefinitions();
+						Util
+								.arrayCopyWithRemoval(
+										oldDefs,
+										fullDefinitions = new FullDecoratorDefinition[fullDefinitions.length - 1],
+										idx);
+						shouldClear = true;
+					}
+				} else {
+					shouldClear |= getLightweightManager().removeDecorator(
+							(LightweightDecoratorDefinition) definition);
+				}
+			}
+		}
+
+		if (shouldClear) {
+			clearCaches();
+			updateForEnablementChange();
+		}
+
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/DecoratorRegistryReader.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/DecoratorRegistryReader.java
new file mode 100644
index 0000000..e78b39e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/DecoratorRegistryReader.java
@@ -0,0 +1,123 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.decorators;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.registry.RegistryReader;
+
+/**
+ * The DecoratorRegistryReader is the class that reads the
+ * decorator descriptions from the registry
+ */
+public class DecoratorRegistryReader extends RegistryReader {
+
+    //The registry values are the ones read from the registry
+    private Collection values = new ArrayList();
+
+    private Collection ids = new HashSet();
+
+    /**
+     * Constructor for DecoratorRegistryReader.
+     */
+    public DecoratorRegistryReader() {
+        super();
+    }
+
+    /*
+     * @see RegistryReader#readElement(IConfigurationElement)
+     */
+    @Override
+	public boolean readElement(IConfigurationElement element) {
+
+    	DecoratorDefinition desc = getDecoratorDefinition(element);
+
+    	if (desc == null) {
+			return false;
+		}
+
+        values.add(desc);
+
+        return true;
+
+    }
+
+    /**
+     * Return the DecoratorDefinition defined by element or <code>null</code>
+     * if it cannot be determined.
+     * @param element
+     * @return DecoratorDefinition
+     */
+    DecoratorDefinition getDecoratorDefinition(IConfigurationElement element){
+
+        String id = element.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+        if (ids.contains(id)) {
+            logDuplicateId(element);
+            return null;
+        }
+        ids.add(id);
+
+        boolean noClass = element.getAttribute(DecoratorDefinition.ATT_CLASS) == null;
+
+        //Lightweight or Full? It is lightweight if it is declared lightweight or if there is no class
+        if (Boolean.valueOf(element.getAttribute(IWorkbenchRegistryConstants.ATT_LIGHTWEIGHT)).booleanValue() || noClass) {
+
+            String iconPath = element.getAttribute(LightweightDecoratorDefinition.ATT_ICON);
+
+            if (noClass && iconPath == null) {
+                logMissingElement(element, LightweightDecoratorDefinition.ATT_ICON);
+                return null;
+            }
+
+            return new LightweightDecoratorDefinition(id, element);
+        }
+        return new FullDecoratorDefinition(id, element);
+
+    }
+
+    /**
+     * Read the decorator extensions within a registry and set
+     * up the registry values.
+     */
+    Collection readRegistry(IExtensionRegistry in) {
+        values.clear();
+        ids.clear();
+        // RAP [bm]: 
+//      readRegistry(in, PlatformUI.PLUGIN_ID,
+//              IWorkbenchRegistryConstants.PL_DECORATORS);
+    readRegistry(in, PlatformUI.PLUGIN_EXTENSION_NAME_SPACE,
+                IWorkbenchRegistryConstants.PL_DECORATORS);
+        return values;
+    }
+
+    /**
+     * Return the values.
+     *
+     * @return the values
+     */
+    public Collection getValues() {
+        return values;
+    }
+
+    /**
+     * Logs a registry error when the configuration element is unknown.
+     */
+    protected void logDuplicateId(IConfigurationElement element) {
+        logError(element, "Duplicate id found: " + element.getAttribute(IWorkbenchRegistryConstants.ATT_ID));//$NON-NLS-1$
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/FullDecoratorDefinition.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/FullDecoratorDefinition.java
new file mode 100644
index 0000000..0381653
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/FullDecoratorDefinition.java
@@ -0,0 +1,161 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.decorators;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.util.SafeRunnable;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.jface.viewers.ILabelDecorator;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+
+/**
+ * The RunnableDecoratorDefinition is the definition for
+ * decorators that have an ILabelDecorator class to instantiate.
+ */
+
+class FullDecoratorDefinition extends DecoratorDefinition {
+
+	ILabelDecorator decorator;
+
+    /**
+     * Create a new instance of the receiver with the
+     * supplied values.
+     */
+
+    FullDecoratorDefinition(String identifier, IConfigurationElement element) {
+        super(identifier, element);
+    }
+
+    /**
+     * Gets the decorator and creates it if it does
+     * not exist yet. Throws a CoreException if there is a problem
+     * creating the decorator.
+     * This method should not be called unless a check for
+     * enabled to be true is done first.
+     * @return Returns a ILabelDecorator
+     */
+    protected ILabelDecorator internalGetDecorator() throws CoreException {
+        if (labelProviderCreationFailed) {
+			return null;
+		}
+
+        final CoreException[] exceptions = new CoreException[1];
+
+        if (decorator == null) {
+            Platform
+                    .run(new SafeRunnable(
+                            NLS.bind(WorkbenchMessages.get().DecoratorManager_ErrorActivatingDecorator, getName() )) {
+                        @Override
+						public void run() {
+                            try {
+                                decorator = (ILabelDecorator) WorkbenchPlugin
+                                        .createExtension(
+                                                definingElement,
+                                                DecoratorDefinition.ATT_CLASS);
+                                decorator.addListener(WorkbenchPlugin
+                                        .getDefault().getDecoratorManager());
+                            } catch (CoreException exception) {
+                                exceptions[0] = exception;
+                            }
+                        }
+                    });
+        } else {
+			return decorator;
+		}
+
+        if (decorator == null) {
+            this.labelProviderCreationFailed = true;
+            setEnabled(false);
+        }
+
+        if (exceptions[0] != null) {
+			throw exceptions[0];
+		}
+
+        return decorator;
+    }
+
+    @Override
+	protected void refreshDecorator() {
+        //Only do something if disabled so as to prevent
+        //gratutitous activation
+        if (!this.enabled && decorator != null) {
+            IBaseLabelProvider cached = decorator;
+            decorator = null;
+            disposeCachedDecorator(cached);
+        }
+    }
+
+    /**
+     * Decorate the image provided for the element type.
+     * This method should not be called unless a check for
+     * isEnabled() has been done first.
+     * Return null if there is no image or if an error occurs.
+     */
+    Image decorateImage(Image image, Object element) {
+        try {
+            //Internal decorator might be null so be prepared
+            ILabelDecorator currentDecorator = internalGetDecorator();
+            if (currentDecorator != null) {
+				return currentDecorator.decorateImage(image, element);
+			}
+
+        } catch (CoreException exception) {
+            handleCoreException(exception);
+        }
+        return null;
+    }
+
+    /**
+     * Decorate the text provided for the element type.
+     * This method should not be called unless a check for
+     * isEnabled() has been done first.
+     * Return null if there is no text or if there is an exception.
+     */
+    String decorateText(String text, Object element) {
+        try {
+            //Internal decorator might be null so be prepared
+            ILabelDecorator currentDecorator = internalGetDecorator();
+            if (currentDecorator != null) {
+				return currentDecorator.decorateText(text, element);
+			}
+        } catch (CoreException exception) {
+            handleCoreException(exception);
+        }
+        return null;
+    }
+
+    /**
+     * Returns the decorator, or <code>null</code> if not enabled.
+     *
+     * @return the decorator, or <code>null</code> if not enabled
+     */
+    public ILabelDecorator getDecorator() {
+        return decorator;
+    }
+
+    @Override
+	protected IBaseLabelProvider internalGetLabelProvider()
+            throws CoreException {
+        return internalGetDecorator();
+    }
+
+    @Override
+	public boolean isFull() {
+        return true;
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/FullDecoratorRunnable.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/FullDecoratorRunnable.java
new file mode 100644
index 0000000..448b846
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/FullDecoratorRunnable.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2014 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.ui.internal.decorators;
+
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.misc.StatusUtil;
+
+/**
+ * The FullDecoratorRunnable is the ISafeRunnable that runs
+ * the full decorators
+ */
+abstract class FullDecoratorRunnable implements ISafeRunnable {
+    protected Object element;
+
+    protected FullDecoratorDefinition decorator;
+
+    /**
+     * Set the values for the element and the decorator.
+     * @param object
+     * @param definition
+     */
+    protected void setValues(Object object, FullDecoratorDefinition definition) {
+        element = object;
+        decorator = definition;
+
+    }
+
+    /*
+     * @see ISafeRunnable.handleException(Throwable).
+     */
+    @Override
+	public void handleException(Throwable exception) {
+        IStatus status = StatusUtil.newStatus(IStatus.ERROR, exception
+                .getMessage(), exception);
+		String message = NLS.bind(WorkbenchMessages.get().DecoratorWillBeDisabled,
+				decorator.getName());
+        WorkbenchPlugin.log(message, status);
+        decorator.crashDisable();
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/FullImageDecoratorRunnable.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/FullImageDecoratorRunnable.java
new file mode 100644
index 0000000..dd6dc1b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/FullImageDecoratorRunnable.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.decorators;
+
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * The FullImageDecoratorRunnable is the runnable for decorating
+ * images
+ */
+class FullImageDecoratorRunnable extends FullDecoratorRunnable {
+    Image result = null;
+
+    Image start;
+
+    @Override
+	public void run() throws Exception {
+        result = decorator.decorateImage(start, element);
+    }
+
+    /**
+     * Get the result of the decoration or <code>null</code>
+     * if there was a failure.
+     * @return Image
+     */
+    Image getResult() {
+        return result;
+    }
+
+    /**
+     * Set the values of the initialString and the decorator
+     * and object that are going to be used to determine the
+     * result.
+     * @param initialImage
+     * @param object
+     * @param definition
+     */
+    void setValues(Image initialImage, Object object,
+            FullDecoratorDefinition definition) {
+        setValues(object, definition);
+        start = initialImage;
+        result = null;
+    }
+
+
+	/**
+	 * Clear decorator references.
+	 * @since 3.1
+	 */
+	void clearReferences() {
+		decorator = null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/FullTextDecoratorRunnable.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/FullTextDecoratorRunnable.java
new file mode 100644
index 0000000..08f2740
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/FullTextDecoratorRunnable.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.decorators;
+
+/**
+ * FullTextDecoratorRunnable is the decorator that runs the text
+ * decoration.
+ */
+public class FullTextDecoratorRunnable extends FullDecoratorRunnable {
+    String result = null;
+
+    String start;
+
+    @Override
+	public void run() throws Exception {
+        result = decorator.decorateText(start, element);
+    }
+
+    /**
+     * Get the result of the decoration or <code>null</code>
+     * if there was a failure.
+     * @return the result
+     */
+    String getResult() {
+        return result;
+    }
+
+    /**
+     * Set the values of the initialString and the decorator
+     * and object that are going to be used to determine the
+     * result.
+     * @param initialString
+     * @param object
+     * @param definition
+     */
+    void setValues(String initialString, Object object,
+            FullDecoratorDefinition definition) {
+        setValues(object, definition);
+        start = initialString;
+        result = null;
+    }
+
+	/**
+	 * Clear decorator references.
+	 * @since 3.1
+	 */
+	void clearReferences() {
+		decorator = null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/LightweightActionDescriptor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/LightweightActionDescriptor.java
new file mode 100644
index 0000000..eefefff
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/LightweightActionDescriptor.java
@@ -0,0 +1,142 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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.ui.internal.decorators;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.internal.dialogs.DialogUtil;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.model.IWorkbenchAdapter;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+/**
+ * Represent the description of an action within
+ * an action set. It does not create an action.
+ *
+ * [Issue: This class overlaps with ActionDescriptor
+ *		and should be reviewed to determine if code
+ *		reuse if possible.]
+ */
+public class LightweightActionDescriptor implements IAdaptable,
+        IWorkbenchAdapter {
+    private static final Object[] NO_CHILDREN = new Object[0];
+
+    private String id;
+
+    private String label;
+
+    private String description;
+
+    private ImageDescriptor image;
+
+    /**
+     * Create a new instance of <code>LightweightActionDescriptor</code>.
+     *
+     * @param actionElement the configuration element
+     */
+    public LightweightActionDescriptor(IConfigurationElement actionElement) {
+        super();
+
+        this.id = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+        this.label = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_LABEL);
+        this.description = actionElement
+                .getAttribute(IWorkbenchRegistryConstants.TAG_DESCRIPTION);
+
+        String iconName = actionElement.getAttribute(IWorkbenchRegistryConstants.ATT_ICON);
+        if (iconName != null) {
+            IExtension extension = actionElement.getDeclaringExtension();
+            this.image = AbstractUIPlugin.imageDescriptorFromPlugin(extension
+                    .getNamespace(), iconName);
+        }
+    }
+
+    /**
+     * Returns an object which is an instance of the given class
+     * associated with this object. Returns <code>null</code> if
+     * no such object can be found.
+     */
+	@Override
+	public <T> T getAdapter(Class<T> adapter) {
+        if (adapter == IWorkbenchAdapter.class) {
+			return adapter.cast(this);
+		}
+        return null;
+    }
+
+    /**
+     * Returns the action's description.
+     *
+     * @return the description
+     */
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     * Returns the action's id.
+     *
+     * @return the id
+     */
+    public String getId() {
+        return id;
+    }
+
+    /**
+     * Returns the action's image descriptor.
+     *
+     * @return the image descriptor
+     */
+    public ImageDescriptor getImageDescriptor() {
+        return image;
+    }
+
+    @Override
+	public ImageDescriptor getImageDescriptor(Object o) {
+        if (o == this) {
+			return getImageDescriptor();
+		}
+        return null;
+    }
+
+    /**
+     * Returns the action's label.
+     *
+     * @return the label
+     */
+    public String getLabel() {
+        return label;
+    }
+
+    @Override
+	public String getLabel(Object o) {
+        if (o == this) {
+            String text = getLabel();
+            int end = text.lastIndexOf('@');
+            if (end >= 0) {
+				text = text.substring(0, end);
+			}
+            return DialogUtil.removeAccel(text);
+        }
+        return o == null ? "" : o.toString();//$NON-NLS-1$
+    }
+
+    @Override
+	public Object[] getChildren(Object o) {
+        return NO_CHILDREN;
+    }
+
+    @Override
+	public Object getParent(Object o) {
+        return null;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/LightweightDecoratorDefinition.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/LightweightDecoratorDefinition.java
new file mode 100644
index 0000000..4247114
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/LightweightDecoratorDefinition.java
@@ -0,0 +1,325 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.decorators;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.jface.viewers.IDecoration;
+import org.eclipse.jface.viewers.ILightweightLabelDecorator;
+import org.eclipse.ui.internal.ActionExpression;
+import org.eclipse.ui.internal.IObjectContributor;
+import org.eclipse.ui.internal.LegacyResourceSupport;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+
+/**
+ * The DeclarativeDecoratorDefinition is a decorator definition that is defined
+ * entirely from xml and will not require the activation of its defining
+ * plug-in.
+ */
+class LightweightDecoratorDefinition extends DecoratorDefinition implements
+		IObjectContributor {
+
+	private static final String ATT_LOCATION = "location"; //$NON-NLS-1$
+
+	static final String ATT_ICON = "icon"; //$NON-NLS-1$
+
+	// Constants for quadrants
+	/**
+	 * Position <code>TOP_LEFT</code>. Value <code>0</code>
+	 */
+	public static final int TOP_LEFT = 0;
+
+	/**
+	 * Position <code>TOP_RIGHT</code>. Value <code>1</code>
+	 */
+	public static final int TOP_RIGHT = 1;
+
+	/**
+	 * Position <code>BOTTOM_LEFT</code>. Value <code>2</code>
+	 */
+	public static final int BOTTOM_LEFT = 2;
+
+	/**
+	 * Position <code>BOTTOM_RIGHT</code>. Value <code>3</code>
+	 */
+	public static final int BOTTOM_RIGHT = 3;
+
+	/**
+	 * Position <code>UNDERLAY</code>. Value <code>4</code>
+	 */
+	public static final int UNDERLAY = 4;
+
+	private static final String UNDERLAY_STRING = "UNDERLAY"; //$NON-NLS-1$
+
+	/**
+	 * Position <code>REPLACE</code>. Value <code>5</code>
+	 */
+	public static final int REPLACE = 5;
+
+	private static final String REPLACE_STRING = "REPLACE"; //$NON-NLS-1$
+
+	private static final String ATT_QUADRANT = "quadrant"; //$NON-NLS-1$
+
+	// Constants for quadrants
+	private static final String TOP_LEFT_STRING = "TOP_LEFT"; //$NON-NLS-1$
+
+	private static final String TOP_RIGHT_STRING = "TOP_RIGHT"; //$NON-NLS-1$
+
+	private static final String BOTTOM_LEFT_STRING = "BOTTOM_LEFT"; //$NON-NLS-1$
+
+	/**
+	 * The DeclarativeDecorator is the internal decorator supplied by the
+	 * decorator definition.
+	 */
+	private ILightweightLabelDecorator decorator;
+
+	private int quadrant;
+
+	private boolean hasReadQuadrant;
+
+	private String[] objectClasses;
+
+	LightweightDecoratorDefinition(String identifier,
+			IConfigurationElement element) {
+		super(identifier, element);
+	}
+
+	/**
+	 * Gets the decorator and creates it if it does not exist yet. Throws a
+	 * CoreException if there is a problem creating the decorator. This method
+	 * should not be called unless a check for enabled to be true is done first.
+	 *
+	 * @return Returns a ILabelDecorator
+	 */
+	protected ILightweightLabelDecorator internalGetDecorator()
+			throws CoreException {
+		if (labelProviderCreationFailed) {
+			return null;
+		}
+
+		final CoreException[] exceptions = new CoreException[1];
+
+		if (decorator == null) {
+
+			if (isDeclarative()) {
+				decorator = new DeclarativeDecorator(definingElement,
+						getIconLocation());
+			} else {
+
+				SafeRunner.run(new ISafeRunnable() {
+					@Override
+					public void run() {
+						try {
+							decorator = (ILightweightLabelDecorator) WorkbenchPlugin
+									.createExtension(definingElement,
+											DecoratorDefinition.ATT_CLASS);
+							decorator.addListener(WorkbenchPlugin.getDefault()
+									.getDecoratorManager());
+						} catch (CoreException exception) {
+							exceptions[0] = exception;
+						}
+					}
+
+					@Override
+					public void handleException(Throwable e) {
+						// Do nothing as Core will handle the logging
+					}
+				});
+			}
+		} else {
+			return decorator;
+		}
+
+		if (decorator == null) {
+			this.labelProviderCreationFailed = true;
+			setEnabled(false);
+		}
+
+		if (exceptions[0] != null) {
+			throw exceptions[0];
+		}
+
+		return decorator;
+	}
+
+	/**
+	 * Return whether or not this represents a declarative decorator.
+	 *
+	 * @return boolean <code>true</code> if this is declarative
+	 */
+	private boolean isDeclarative() {
+		return definingElement.getAttribute(DecoratorDefinition.ATT_CLASS) == null;
+	}
+
+	/**
+	 * Return the icon location.
+	 *
+	 * @return the icon location
+	 */
+	private String getIconLocation() {
+		return definingElement.getAttribute(ATT_ICON);
+	}
+
+	@Override
+	protected IBaseLabelProvider internalGetLabelProvider()
+			throws CoreException {
+		return internalGetDecorator();
+	}
+
+	@Override
+	public boolean isFull() {
+		return false;
+	}
+
+	/**
+	 * Returns the quadrant.One of the following constants in
+	 * DecoratorRegistryReader: TOP_LEFT TOP_RIGHT BOTTOM_LEFT BOTTOM_RIGHT
+	 * UNDERLAY REPLACE
+	 *
+	 * @return int
+	 */
+	public int getQuadrant() {
+		if (!hasReadQuadrant) {
+			hasReadQuadrant = true;
+			quadrant = getLocationConstant(definingElement
+					.getAttribute(ATT_LOCATION), definingElement);
+		}
+		return quadrant;
+	}
+
+	/**
+	 * Get the constant value based on the location supplied. Default to bottom
+	 * right.
+	 *
+	 * @since 3.1
+	 */
+	private int getLocationConstant(String locationDefinition,
+			IConfigurationElement element) {
+
+		// Backwards compatibility
+		if (locationDefinition == null) {
+			locationDefinition = element.getAttribute(ATT_QUADRANT);
+		}
+
+		if (TOP_RIGHT_STRING.equals(locationDefinition)) {
+			return TOP_RIGHT;
+		}
+		if (TOP_LEFT_STRING.equals(locationDefinition)) {
+			return TOP_LEFT;
+		}
+		if (BOTTOM_LEFT_STRING.equals(locationDefinition)) {
+			return BOTTOM_LEFT;
+		}
+		if (UNDERLAY_STRING.equals(locationDefinition)) {
+			return UNDERLAY;
+		}
+		if (REPLACE_STRING.equals(locationDefinition)) {
+			return REPLACE;
+		}
+		return BOTTOM_RIGHT;
+
+	}
+
+	/**
+	 * Decorate the element using the decoration to store the result.
+	 * @param element
+	 * @param decoration
+	 */
+	public void decorate(Object element, IDecoration decoration) {
+		try {
+			// Internal decorator might be null so be prepared
+			ILightweightLabelDecorator currentDecorator = internalGetDecorator();
+			if(currentDecorator == null) {
+				return;
+			}
+
+			if (isAdaptable()) {
+				String[] classes = getObjectClasses();
+				for (String className : classes) {
+					Object adapted = LegacyResourceSupport.getAdapter(element,
+							className);
+					if (adapted != null) {
+						currentDecorator.decorate(adapted, decoration);
+					}
+				}
+			}
+			else{
+				if (currentDecorator != null && element != null) {
+					currentDecorator.decorate(element, decoration);
+				}
+			}
+		} catch (CoreException exception) {
+			handleCoreException(exception);
+		}
+
+	}
+
+	/**
+	 * Returns the lightweight decorator, or <code>null</code> if not enabled.
+	 *
+	 * @return the lightweight decorator, or <code>null</code> if not enabled
+	 */
+	public ILightweightLabelDecorator getDecorator() {
+		return decorator;
+	}
+
+	@Override
+	protected void refreshDecorator() {
+		// Only do something if disabled so as to prevent
+		// gratutitous activation
+		if (!this.enabled && decorator != null) {
+			IBaseLabelProvider cached = decorator;
+			decorator = null;
+			disposeCachedDecorator(cached);
+		}
+	}
+
+	@Override
+	public boolean isApplicableTo(Object object) {
+		return isEnabledFor(object);
+	}
+
+	@Override
+	public boolean canAdapt() {
+		return isAdaptable();
+	}
+
+	/**
+	 * Get the object classes to which this decorator is registered.
+	 *
+	 * @return String [] the object classes to which this decorator is
+	 *         registered
+	 */
+	public String[] getObjectClasses() {
+		if (objectClasses == null) {
+			getEnablement();
+		}
+		return objectClasses;
+	}
+
+	@Override
+	protected void initializeEnablement() {
+		super.initializeEnablement();
+		ActionExpression expression = getEnablement();
+		if (expression != null) {
+			objectClasses = expression.extractObjectClasses();
+		}
+
+		// If the class is null set it to Object
+		if (objectClasses == null) {
+			objectClasses = new String[] {Object.class.getName()};
+		}
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/LightweightDecoratorManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/LightweightDecoratorManager.java
new file mode 100644
index 0000000..b859ddc
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/decorators/LightweightDecoratorManager.java
@@ -0,0 +1,402 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.decorators;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.internal.ObjectContributorManager;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.internal.util.Util;
+
+/**
+ * The LightweightDecoratorManager is a decorator manager that encapsulates the
+ * behavior for the lightweight decorators.
+ */
+public class LightweightDecoratorManager extends ObjectContributorManager {
+
+	/**
+	 * The runnable is the object used to run the decorations so that an error
+	 * in someones decorator will not kill the thread. It is implemented here to
+	 * prevent aborting of decoration i.e. successful decorations will still be
+	 * applied.
+	 */
+
+	private static class LightweightRunnable implements ISafeRunnable {
+
+		static class RunnableData {
+
+			final DecorationBuilder builder;
+
+			final LightweightDecoratorDefinition decorator;
+
+			final Object element;
+
+			public RunnableData(Object object, DecorationBuilder builder, LightweightDecoratorDefinition definition) {
+				this.element = object;
+				this.builder = builder;
+				this.decorator = definition;
+			}
+
+			boolean isConsistent() {
+				return builder != null && decorator != null && element != null;
+			}
+		}
+
+		private volatile RunnableData data = new RunnableData(null, null, null);
+
+		void setValues(Object object, DecorationBuilder builder,
+				LightweightDecoratorDefinition definition) {
+			data = new RunnableData(object, builder, definition);
+		}
+
+		/*
+		 * @see ISafeRunnable.handleException(Throwable).
+		 */
+		@Override
+		public void handleException(Throwable exception) {
+			IStatus status = StatusUtil.newStatus(IStatus.ERROR, exception
+					.getMessage(), exception);
+			LightweightDecoratorDefinition decorator = data.decorator;
+			String message;
+			if (decorator == null) {
+				message = WorkbenchMessages.get().DecoratorError;
+			} else {
+				String name = decorator.getName();
+				if (name == null) {
+					// decorator definition is not accessible anymore
+					name = decorator.getId();
+				}
+				message = NLS.bind(WorkbenchMessages.get().DecoratorWillBeDisabled, name);
+			}
+			WorkbenchPlugin.log(message, status);
+			if (decorator != null) {
+				decorator.crashDisable();
+			}
+			clearReferences();
+		}
+
+		/*
+		 * @see ISafeRunnable.run
+		 */
+		@Override
+		public void run() throws Exception {
+			// Copy to local variables, see
+			// https://bugs.eclipse.org/bugs/show_bug.cgi?id=300358
+			RunnableData data = this.data;
+			if (data.isConsistent()) {
+				data.decorator.decorate(data.element, data.builder);
+			}
+			clearReferences();
+		}
+
+		/**
+		 * Clear all of the references in the receiver.
+		 *
+		 * @since 3.1
+		 */
+		void clearReferences() {
+			data = new RunnableData(null, null, null);
+		}
+	}
+
+	private LightweightRunnable runnable = new LightweightRunnable();
+
+	// The lightweight definitions read from the registry
+	private LightweightDecoratorDefinition[] lightweightDefinitions;
+
+	private static final LightweightDecoratorDefinition[] EMPTY_LIGHTWEIGHT_DEF = new LightweightDecoratorDefinition[0];
+
+	LightweightDecoratorManager(LightweightDecoratorDefinition[] definitions) {
+		super();
+		lightweightDefinitions = definitions;
+		buildContributors();
+	}
+
+	/**
+	 * Get the lightweight definitions for the receiver.
+	 *
+	 * @return LightweightDecoratorDefinition[]
+	 */
+	LightweightDecoratorDefinition[] getDefinitions() {
+		return lightweightDefinitions;
+	}
+
+	/**
+	 * Register the decorators as object contributions so that adaptable lookup
+	 * can occur.
+	 */
+	private void buildContributors() {
+		for (LightweightDecoratorDefinition decorator : lightweightDefinitions) {
+			for (String type : getTargetTypes(decorator)) {
+				registerContributor(decorator, type);
+			}
+		}
+	}
+
+	/**
+	 * For dynamic UI
+	 *
+	 * @param decorator
+	 *            the definition to add
+	 * @return whether the definition was added
+	 * @since 3.0
+	 */
+	public boolean addDecorator(LightweightDecoratorDefinition decorator) {
+		if (getLightweightDecoratorDefinition(decorator.getId()) == null) {
+			LightweightDecoratorDefinition[] oldDefs = lightweightDefinitions;
+			lightweightDefinitions = new LightweightDecoratorDefinition[lightweightDefinitions.length + 1];
+			System.arraycopy(oldDefs, 0, lightweightDefinitions, 0,
+					oldDefs.length);
+			lightweightDefinitions[oldDefs.length] = decorator;
+			// no reset - handled in the DecoratorManager
+			String[] types = getTargetTypes(decorator);
+			for (String type : types) {
+				registerContributor(decorator, type);
+			}
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Get the name of the types that a decorator is registered for.
+	 *
+	 * @param decorator
+	 * @return String[]
+	 */
+	private String[] getTargetTypes(LightweightDecoratorDefinition decorator) {
+		return decorator.getObjectClasses();
+	}
+
+	/**
+	 * For dynamic-ui
+	 *
+	 * @param decorator
+	 *            the definition to remove
+	 * @return whether the definition was removed
+	 * @since 3.1
+	 */
+	public boolean removeDecorator(LightweightDecoratorDefinition decorator) {
+		int idx = getLightweightDecoratorDefinitionIdx(decorator.getId());
+		if (idx != -1) {
+			LightweightDecoratorDefinition[] oldDefs = lightweightDefinitions;
+			Util.arrayCopyWithRemoval(
+							oldDefs,
+							lightweightDefinitions = new LightweightDecoratorDefinition[lightweightDefinitions.length - 1],
+							idx);
+			// no reset - handled in the DecoratorManager
+			for (String type : getTargetTypes(decorator)) {
+				unregisterContributor(decorator, type);
+
+			}
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Get the LightweightDecoratorDefinition with the supplied id
+	 *
+	 * @return LightweightDecoratorDefinition or <code>null</code> if it is
+	 *         not found
+	 * @param decoratorId
+	 *            String
+	 * @since 3.0
+	 */
+	private LightweightDecoratorDefinition getLightweightDecoratorDefinition(
+			String decoratorId) {
+		int idx = getLightweightDecoratorDefinitionIdx(decoratorId);
+		if (idx != -1) {
+			return lightweightDefinitions[idx];
+		}
+		return null;
+	}
+
+	/**
+	 * Return the index of the definition in the array.
+	 *
+	 * @param decoratorId
+	 *            the id
+	 * @return the index of the definition in the array or <code>-1</code>
+	 * @since 3.1
+	 */
+	private int getLightweightDecoratorDefinitionIdx(String decoratorId) {
+		for (int i = 0; i < lightweightDefinitions.length; i++) {
+			if (lightweightDefinitions[i].getId().equals(decoratorId)) {
+				return i;
+			}
+		}
+		return -1;
+	}
+
+	/**
+	 * Return the enabled lightweight decorator definitions.
+	 *
+	 * @return LightweightDecoratorDefinition[]
+	 */
+	LightweightDecoratorDefinition[] enabledDefinitions() {
+		ArrayList result = new ArrayList();
+		for (LightweightDecoratorDefinition lightweightDefinition : lightweightDefinitions) {
+			if (lightweightDefinition.isEnabled()) {
+				result.add(lightweightDefinition);
+			}
+		}
+		LightweightDecoratorDefinition[] returnArray = new LightweightDecoratorDefinition[result
+				.size()];
+		result.toArray(returnArray);
+		return returnArray;
+	}
+
+	/**
+	 * Return whether there are enabled lightwieght decorators
+	 *
+	 * @return boolean
+	 */
+	boolean hasEnabledDefinitions() {
+		for (LightweightDecoratorDefinition lightweightDefinition : lightweightDefinitions) {
+			if (lightweightDefinition.isEnabled()) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Reset any cached values.
+	 */
+	void reset() {
+		runnable.clearReferences();
+	}
+
+	/**
+	 * Shutdown the decorator manager by disabling all of the decorators so that
+	 * dispose() will be called on them.
+	 */
+	void shutdown() {
+		// Disable all fo the enabled decorators
+		// so as to force a dispose of thier decorators
+		for (LightweightDecoratorDefinition lightweightDefinition : lightweightDefinitions) {
+			if (lightweightDefinition.isEnabled()) {
+				lightweightDefinition.setEnabled(false);
+			}
+		}
+	}
+
+	/**
+	 * Get the LightweightDecoratorDefinition with the supplied id
+	 *
+	 * @return LightweightDecoratorDefinition or <code>null</code> if it is
+	 *         not found
+	 * @param decoratorId
+	 *            String
+	 */
+	LightweightDecoratorDefinition getDecoratorDefinition(String decoratorId) {
+		for (LightweightDecoratorDefinition lightweightDefinition : lightweightDefinitions) {
+			if (lightweightDefinition.getId().equals(decoratorId)) {
+				return lightweightDefinition;
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Get the lightweight registered for elements of this type.
+	 */
+	LightweightDecoratorDefinition[] getDecoratorsFor(Object element) {
+
+		if (element == null) {
+			return EMPTY_LIGHTWEIGHT_DEF;
+		}
+
+		List elements = new ArrayList(1);
+		elements.add(element);
+		LightweightDecoratorDefinition[] decoratorArray = EMPTY_LIGHTWEIGHT_DEF;
+		List contributors = getContributors(elements);
+		if (!contributors.isEmpty()) {
+			Collection decorators = DecoratorManager.getDecoratorsFor(element,
+					(DecoratorDefinition[]) contributors
+							.toArray(new DecoratorDefinition[contributors
+									.size()]));
+			if (decorators.size() > 0) {
+				decoratorArray = new LightweightDecoratorDefinition[decorators
+						.size()];
+				decorators.toArray(decoratorArray);
+			}
+		}
+
+		return decoratorArray;
+	}
+
+	/**
+	 * Fill the decoration with all of the results of the decorators.
+	 *
+	 * @param element
+	 *            The source element
+	 * @param decoration
+	 *            The DecorationResult we are working on. where adaptable is
+	 *            true.
+	 */
+	public void getDecorations(Object element, DecorationBuilder decoration) {
+		for (LightweightDecoratorDefinition decorator : getDecoratorsFor(element)) {
+			decoration.setCurrentDefinition(decorator);
+			decorate(element, decoration, decorator);
+		}
+	}
+
+	/**
+	 * Decorate the element receiver in a SafeRunnable.
+	 *
+	 * @param element
+	 *            The Object to be decorated
+	 * @param decoration
+	 *            The object building decorations.
+	 * @param decorator
+	 *            The decorator being applied.
+	 */
+	private void decorate(Object element, DecorationBuilder decoration,
+			LightweightDecoratorDefinition decorator) {
+
+		runnable.setValues(element, decoration, decorator);
+		SafeRunner.run(runnable);
+	}
+
+
+	/**
+	 * Method for use by test cases
+	 *
+	 * @param object
+	 *            the object to be decorated
+	 * @return the decoration result
+	 */
+	public DecorationResult getDecorationResult(Object object) {
+		DecorationBuilder builder = new DecorationBuilder();
+		getDecorations(object, builder);
+		return builder.createResult();
+
+	}
+
+	@Override
+	public void addExtension(IExtensionTracker tracker, IExtension extension) {
+		// Do nothing as this is handled by the DecoratorManager
+		// This is not called as canHandleExtensionTracking returns
+		// false.
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/AboutPluginsDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/AboutPluginsDialog.java
new file mode 100644
index 0000000..ea5daea
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/AboutPluginsDialog.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *  	Sebastian Davids <sdavids@gmx.de> - Fix for bug 19346 - Dialog
+ * 		font should be activated and used by other components.
+ *******************************************************************************/
+package org.eclipse.ui.internal.dialogs;
+
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.about.AboutPluginsPage;
+import org.osgi.framework.Bundle;
+import org.eclipse.ui.internal.about.ProductInfoDialog;
+
+/**
+ * Displays information about the product plugins.
+ *
+ * PRIVATE this class is internal to the ide
+ */
+public class AboutPluginsDialog extends ProductInfoDialog {
+    public AboutPluginsDialog(Shell parentShell, String productName,
+            Bundle[] bundles, String title, String message, String helpContextId) {
+    	super(parentShell);
+    	AboutPluginsPage page = new AboutPluginsPage();
+    	page.setHelpContextId(helpContextId);
+    	page.setBundles(bundles);
+    	page.setMessage(message);
+    	if (title == null && page.getProductName() != null)
+            title = NLS.bind(WorkbenchMessages.get().AboutPluginsDialog_shellTitle, productName);
+    	initializeDialog(page, title, helpContextId);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/AbstractWorkingSetDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/AbstractWorkingSetDialog.java
new file mode 100644
index 0000000..241708e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/AbstractWorkingSetDialog.java
@@ -0,0 +1,437 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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
+ * 		Sebastian Davids <sdavids@gmx.de> - Bug 19346
+ *      Lars Vogel <Lars.Vogel@vogella.com> - Bug 481473
+ *******************************************************************************/
+package org.eclipse.ui.internal.dialogs;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.window.Window;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkingSet;
+import org.eclipse.ui.IWorkingSetManager;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.dialogs.IWorkingSetEditWizard;
+import org.eclipse.ui.dialogs.IWorkingSetNewWizard;
+import org.eclipse.ui.dialogs.IWorkingSetSelectionDialog;
+import org.eclipse.ui.dialogs.SelectionDialog;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.WorkingSet;
+import org.eclipse.ui.internal.registry.WorkingSetRegistry;
+
+/**
+ * Abstract baseclass for various working set dialogs.
+ *
+ * @since 3.2
+ */
+public abstract class AbstractWorkingSetDialog extends SelectionDialog implements IWorkingSetSelectionDialog {
+
+	private static final int ID_NEW = IDialogConstants.CLIENT_ID + 1;
+	private static final int ID_DETAILS = ID_NEW + 1;
+	private static final int ID_REMOVE = ID_DETAILS + 1;
+	private static final int ID_SELECTALL = ID_REMOVE + 1;
+	private static final int ID_DESELECTALL = ID_SELECTALL + 1;
+
+	private Button newButton;
+
+	private Button detailsButton;
+
+	private Button removeButton;
+
+	private Button selectAllButton;
+
+	private Button deselectAllButton;
+
+	private IWorkingSet[] result;
+
+	private List<IWorkingSet> addedWorkingSets;
+
+	private List<IWorkingSet> removedWorkingSets;
+
+	private Map<IWorkingSet, IWorkingSet> editedWorkingSets;
+
+	private List<IWorkingSet> removedMRUWorkingSets;
+
+	private Set<String> workingSetIds;
+
+	private boolean canEdit;
+
+	protected AbstractWorkingSetDialog(Shell parentShell, String[] workingSetIds, boolean canEdit) {
+		super(parentShell);
+		if (workingSetIds != null) {
+			this.workingSetIds = new HashSet<>();
+			for (String workingSetId : workingSetIds) {
+				this.workingSetIds.add(workingSetId);
+			}
+		}
+		this.canEdit = canEdit;
+	}
+
+	/**
+	 * Return the set of supported working set types.
+	 *
+	 * @return the supported working set types
+	 */
+	protected Set<String> getSupportedWorkingSetIds() {
+		return workingSetIds;
+	}
+
+	/**
+	 * Adds the modify buttons to the dialog.
+	 *
+	 * @param composite
+	 *            Composite to add the buttons to
+	 */
+	protected void addModifyButtons(Composite composite) {
+		Composite buttonComposite = new Composite(composite, SWT.RIGHT);
+		GridLayout layout = new GridLayout();
+		layout.marginHeight = layout.marginWidth = 0;
+		layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
+		buttonComposite.setLayout(layout);
+		GridData data = new GridData(GridData.VERTICAL_ALIGN_BEGINNING | GridData.GRAB_VERTICAL);
+		buttonComposite.setLayoutData(data);
+
+		newButton = createButton(buttonComposite, ID_NEW, WorkbenchMessages.get().WorkingSetSelectionDialog_newButton_label,
+				false);
+		newButton.addSelectionListener(new SelectionAdapter()
+        {
+		    /** {@inheritDoc} */
+		    @Override
+		    public void widgetSelected(SelectionEvent e)
+		    {
+		        createWorkingSet();
+		    }
+        });
+
+		if (canEdit) {
+			detailsButton = createButton(buttonComposite, ID_DETAILS,
+					WorkbenchMessages.get().WorkingSetSelectionDialog_detailsButton_label, false);
+			detailsButton.setEnabled(false);
+			detailsButton.addSelectionListener(new SelectionAdapter()
+	        {
+	            /** {@inheritDoc} */
+	            @Override
+	            public void widgetSelected(SelectionEvent e)
+	            {
+	                editSelectedWorkingSet();
+	            }
+	        });
+
+			removeButton = createButton(buttonComposite, ID_REMOVE,
+					WorkbenchMessages.get().WorkingSetSelectionDialog_removeButton_label, false);
+			removeButton.setEnabled(false);
+			removeButton.addSelectionListener(new SelectionAdapter()
+            {
+                /** {@inheritDoc} */
+                @Override
+                public void widgetSelected(SelectionEvent e)
+                { 
+                    removeSelectedWorkingSets();
+                }
+            });
+		}
+
+		layout.numColumns = 1; // must manually reset the number of columns
+								// because createButton increments it - we want
+								// these buttons to be laid out vertically.
+	}
+
+	/**
+	 * Add the select/deselect buttons.
+	 *
+	 * @param composite
+	 *            Composite to add the buttons to
+	 */
+	protected void addSelectionButtons(Composite composite) {
+		Composite buttonComposite = new Composite(composite, SWT.NONE);
+		GridLayout layout = new GridLayout(2, false);
+		layout.marginHeight = layout.marginWidth = 0;
+		layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
+		buttonComposite.setLayout(layout);
+		GridData data = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
+		buttonComposite.setLayoutData(data);
+
+		selectAllButton = createButton(buttonComposite, ID_SELECTALL, WorkbenchMessages.get().SelectionDialog_selectLabel,
+				false);
+		selectAllButton.addSelectionListener(new SelectionAdapter()
+        {
+            /** {@inheritDoc} */
+            @Override
+            public void widgetSelected(SelectionEvent e)
+            {
+                selectAllSets();
+            }
+        });
+
+		deselectAllButton = createButton(buttonComposite, ID_DESELECTALL,
+				WorkbenchMessages.get().SelectionDialog_deselectLabel, false);
+		deselectAllButton.addSelectionListener(new SelectionAdapter()
+        {
+            /** {@inheritDoc} */
+            @Override
+            public void widgetSelected(SelectionEvent e)
+            {
+                deselectAllSets();
+            }
+        });
+	}
+
+	/**
+	 * Select all working sets.
+	 */
+	protected abstract void selectAllSets();
+
+	/**
+	 * Deselect all working sets.
+	 */
+	protected abstract void deselectAllSets();
+
+	/**
+	 * Opens a working set wizard for editing the currently selected working
+	 * set.
+	 *
+	 * @see org.eclipse.ui.dialogs.IWorkingSetPage
+	 */
+	void editSelectedWorkingSet() {
+		IWorkingSetManager manager = WorkbenchPlugin.getDefault().getWorkingSetManager();
+		IWorkingSet editWorkingSet = getSelectedWorkingSets().get(0);
+		IWorkingSetEditWizard wizard = manager.createWorkingSetEditWizard(editWorkingSet);
+		WizardDialog dialog = new WizardDialog(getShell(), wizard);
+		IWorkingSet originalWorkingSet = editedWorkingSets.get(editWorkingSet);
+		boolean firstEdit = originalWorkingSet == null;
+
+		// save the original working set values for restoration when selection
+		// dialog is cancelled.
+		if (firstEdit) {
+			originalWorkingSet = new WorkingSet(editWorkingSet.getName(), editWorkingSet.getLabel(),
+					editWorkingSet.getElements());
+		} else {
+			editedWorkingSets.remove(editWorkingSet);
+		}
+		dialog.create();
+		PlatformUI.getWorkbench().getHelpSystem().setHelp(dialog.getShell(),
+				IWorkbenchHelpContextIds.WORKING_SET_EDIT_WIZARD);
+		if (dialog.open() == Window.OK) {
+			editWorkingSet = wizard.getSelection();
+			availableWorkingSetsChanged();
+			// make sure ok button is enabled when the selected working set
+			// is edited. Fixes bug 33386.
+			updateButtonAvailability();
+		}
+		editedWorkingSets.put(editWorkingSet, originalWorkingSet);
+	}
+
+	/**
+	 * Opens a working set wizard for creating a new working set.
+	 */
+	void createWorkingSet() {
+		IWorkingSetManager manager = WorkbenchPlugin.getDefault().getWorkingSetManager();
+		String ids[] = null;
+		if (workingSetIds != null) {
+			ids = workingSetIds.toArray(new String[workingSetIds.size()]);
+		}
+		IWorkingSetNewWizard wizard = manager.createWorkingSetNewWizard(ids);
+		// the wizard can never be null since we have at least a resource
+		// working set
+		// creation page
+		WizardDialog dialog = new WizardDialog(getShell(), wizard);
+
+		dialog.create();
+		PlatformUI.getWorkbench().getHelpSystem().setHelp(dialog.getShell(),
+				IWorkbenchHelpContextIds.WORKING_SET_NEW_WIZARD);
+		if (dialog.open() == Window.OK) {
+			IWorkingSet workingSet = wizard.getSelection();
+			manager.addWorkingSet(workingSet);
+			addedWorkingSets.add(workingSet);
+			availableWorkingSetsChanged();
+			workingSetAdded(workingSet);
+		}
+	}
+
+	protected abstract List<IWorkingSet> getSelectedWorkingSets();
+
+	/**
+	 * Notifies the dialog that there has been a change to the sets available
+	 * for use. In other words, the user has either added, deleted or renamed a
+	 * set.
+	 * <p>
+	 * Subclasses should override, but should call
+	 * <code>super.availableWorkingSetsChanged</code> to update the selection
+	 * button enablements.
+	 * </p>
+	 */
+	protected void availableWorkingSetsChanged() {
+		boolean enable = PlatformUI.getWorkbench().getWorkingSetManager().getWorkingSets().length > 0;
+		if (!(selectAllButton == null || selectAllButton.isDisposed())) {
+			selectAllButton.setEnabled(enable);
+		}
+		if (!(deselectAllButton == null || deselectAllButton.isDisposed())) {
+			deselectAllButton.setEnabled(enable);
+		}
+	}
+
+	/**
+	 * Notifies the dialog that the given working set was added to the sets
+	 * available for use. In other words, the user has just added the given
+	 * working set.
+	 *
+	 * <p>
+	 * This implementation doesn't do anything. Subclasses can override it to
+	 * auto-select the added working set.
+	 * </p>
+	 *
+	 * @param addedSet
+	 *            the added working set.
+	 */
+	protected void workingSetAdded(IWorkingSet addedSet) {
+	}
+
+	@Override
+	public IWorkingSet[] getSelection() {
+		return result;
+	}
+
+	@Override
+	public void setSelection(IWorkingSet[] selection) {
+		result = selection;
+	}
+
+	@Override
+	public int open() {
+		addedWorkingSets = new ArrayList<>();
+		removedWorkingSets = new ArrayList<>();
+		editedWorkingSets = new HashMap<>();
+		removedMRUWorkingSets = new ArrayList<>();
+		return super.open();
+	}
+
+	/**
+	 * Return the list of working sets that were added during the life of this
+	 * dialog.
+	 *
+	 * @return the working sets
+	 */
+	protected final List<IWorkingSet> getAddedWorkingSets() {
+		return addedWorkingSets;
+	}
+
+	/**
+	 * Return the map of working sets that were edited during the life of this
+	 * dialog.
+	 *
+	 * @return the working sets
+	 */
+	protected final Map<IWorkingSet, IWorkingSet> getEditedWorkingSets() {
+		return editedWorkingSets;
+	}
+
+	/**
+	 * Return the list of working sets that were removed from the MRU list
+	 * during the life of this dialog.
+	 *
+	 * @return the working sets
+	 */
+	protected final List<IWorkingSet> getRemovedMRUWorkingSets() {
+		return removedMRUWorkingSets;
+	}
+
+	/**
+	 * Return the list of working sets that were removed during the life of this
+	 * dialog.
+	 *
+	 * @return the working sets
+	 */
+	protected final List<IWorkingSet> getRemovedWorkingSets() {
+		return removedWorkingSets;
+	}
+
+	/**
+	 * Updates the modify buttons' enabled state based on the current seleciton.
+	 */
+	protected void updateButtonAvailability() {
+		List<IWorkingSet> selection = getSelectedWorkingSets();
+		boolean hasSelection = !selection.isEmpty();
+		boolean hasSingleSelection = hasSelection;
+		WorkingSetRegistry registry = WorkbenchPlugin.getDefault().getWorkingSetRegistry();
+
+		newButton.setEnabled(registry.hasNewPageWorkingSetDescriptor());
+
+		if (canEdit)
+			removeButton.setEnabled(hasSelection);
+
+		IWorkingSet selectedWorkingSet = null;
+		if (hasSelection) {
+			hasSingleSelection = selection.size() == 1;
+			if (hasSingleSelection) {
+				selectedWorkingSet = selection.get(0);
+			}
+		}
+		if (canEdit) {
+			detailsButton.setEnabled(hasSingleSelection && selectedWorkingSet.isEditable());
+		}
+
+		getOkButton().setEnabled(true);
+	}
+
+	/**
+	 * Removes the selected working sets from the workbench.
+	 */
+	protected void removeSelectedWorkingSets() {
+		List<IWorkingSet> selection = getSelectedWorkingSets();
+		removeSelectedWorkingSets(selection);
+	}
+
+	/**
+	 * Remove the working sets contained in the provided selection from the
+	 * working set manager.
+	 *
+	 * @param selection
+	 *            the sets
+	 */
+	protected void removeSelectedWorkingSets(List<IWorkingSet> selection) {
+		IWorkingSetManager manager = WorkbenchPlugin.getDefault().getWorkingSetManager();
+		Iterator iter = selection.iterator();
+		while (iter.hasNext()) {
+			IWorkingSet workingSet = (IWorkingSet) iter.next();
+			if (getAddedWorkingSets().contains(workingSet)) {
+				getAddedWorkingSets().remove(workingSet);
+			} else {
+				IWorkingSet[] recentWorkingSets = manager.getRecentWorkingSets();
+				for (IWorkingSet recentWorkingSet : recentWorkingSets) {
+					if (workingSet.equals(recentWorkingSet)) {
+						getRemovedMRUWorkingSets().add(workingSet);
+						break;
+					}
+				}
+				getRemovedWorkingSets().add(workingSet);
+			}
+			manager.removeWorkingSet(workingSet);
+		}
+		availableWorkingSetsChanged();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ActionSetComparator.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ActionSetComparator.java
new file mode 100644
index 0000000..f0d0caf
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ActionSetComparator.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2014 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.ui.internal.dialogs;
+
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.ui.internal.registry.IActionSetDescriptor;
+
+/**
+ * This is used to sort action sets in the perspective customization dialog.
+ */
+public class ActionSetComparator extends ViewerComparator {
+
+    /**
+     * Creates a new sorter.
+     */
+    public ActionSetComparator() {
+    }
+
+    /**
+     * Returns a negative, zero, or positive number depending on whether
+     * the first element is less than, equal to, or greater than
+     * the second element.
+     */
+    @Override
+	public int compare(Viewer viewer, Object e1, Object e2) {
+        if (e1 instanceof IActionSetDescriptor) {
+            String str1 = DialogUtil.removeAccel(((IActionSetDescriptor) e1)
+                    .getLabel());
+            String str2 = DialogUtil.removeAccel(((IActionSetDescriptor) e2)
+                    .getLabel());
+            return getComparator().compare(str1, str2);
+        }
+        return 0;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/AdaptableForwarder.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/AdaptableForwarder.java
new file mode 100644
index 0000000..dbe12a3
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/AdaptableForwarder.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.dialogs;
+
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.core.runtime.IAdaptable;
+
+/**
+ * Class that wraps an object and forwards adapter calls if possible, otherwise
+ * returns the object. This is used to maintain API compatibility with methods that
+ * need an IAdaptable but when the operation supports a broader type.
+ *
+ * @since 3.2
+ */
+public class AdaptableForwarder implements IAdaptable {
+
+	private Object element;
+
+	/**
+	 * Create a new instance of the receiver.
+	 * @param element
+	 */
+	public AdaptableForwarder(Object element) {
+		this.element = element;
+	}
+
+	@Override
+	public <T> T getAdapter(Class<T> adapter) {
+		return Adapters.adapt(element, adapter);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/CapabilityFilter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/CapabilityFilter.java
new file mode 100644
index 0000000..5f13eeb
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/CapabilityFilter.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.dialogs;
+
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.ui.activities.WorkbenchActivityHelper;
+
+/**
+ * The CapabilityFilter is a filter that uses the capabilities
+ * support as filter for items.
+ */
+public class CapabilityFilter extends ViewerFilter {
+
+	/**
+	 * Create a new instance of a capability filter.
+	 */
+	public CapabilityFilter() {
+		super();
+
+	}
+
+	@Override
+	public boolean select(Viewer viewer, Object parentElement, Object element) {
+		return ! WorkbenchActivityHelper.filterItem(element);
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ContentTypesPreferencePage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ContentTypesPreferencePage.java
new file mode 100644
index 0000000..3166fbc
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ContentTypesPreferencePage.java
@@ -0,0 +1,700 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2016 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.ui.internal.dialogs;
+
+import java.nio.charset.Charset;
+import java.nio.charset.IllegalCharsetNameException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.content.IContentType;
+import org.eclipse.core.runtime.content.IContentTypeManager;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.ListViewer;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.jface.window.Window;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.osgi.util.TextProcessor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.dialogs.PreferenceLinkArea;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.internal.util.Util;
+import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+/**
+ * Preference page that allows manipulation of core content types. Unlike most
+ * preference pages, it does not work on the preference store itself but rather
+ * the content type manager. As such, there are no apply/default buttons and all
+ * changes made take effect immediately.
+ *
+ * @since 3.1
+ */
+public class ContentTypesPreferencePage extends PreferencePage implements
+		IWorkbenchPreferencePage {
+
+	private ListViewer fileAssociationViewer;
+
+	private Button removeButton;
+
+	private TreeViewer contentTypesViewer;
+
+	private Button addButton;
+
+	private Button editButton;
+
+	private Text charsetField;
+
+	private Button setButton;
+
+	private IWorkbench workbench;
+
+	private Button removeContentTypeButton;
+
+	private Button addChildContentTypeButton;
+
+	private class Spec {
+		String name;
+
+		String ext;
+
+		boolean isPredefined;
+
+		int sortValue;
+
+		@Override
+		public String toString() {
+			String toString;
+			if (name != null) {
+				toString = name;
+			} else {
+				toString = "*." + ext; //$NON-NLS-1$
+			}
+
+			if (isPredefined) {
+				toString = NLS.bind(
+						WorkbenchMessages.get().get().ContentTypes_lockedFormat, toString);
+			}
+
+			return toString;
+		}
+	}
+
+	private class FileSpecComparator extends ViewerComparator {
+		@Override
+		public int category(Object element) {
+			// only Spec objects in here - unchecked cast
+			return ((Spec) element).sortValue;
+		}
+	}
+
+	private class FileSpecLabelProvider extends LabelProvider {
+		@Override
+		public String getText(Object element) {
+			String label = super.getText(element);
+			return TextProcessor.process(label, "*."); //$NON-NLS-1$
+		}
+	}
+
+	private class FileSpecContentProvider implements IStructuredContentProvider {
+
+        @Override
+        public void dispose(){           
+        }
+        
+        @Override
+        public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+        }
+
+        @Override
+        public Object[] getElements(Object inputElement) {
+			IContentType contentType = (IContentType) inputElement;
+			String[] userextfileSpecs = contentType
+					.getFileSpecs(IContentType.FILE_EXTENSION_SPEC | IContentType.IGNORE_PRE_DEFINED);
+			String[] usernamefileSpecs = contentType
+					.getFileSpecs(IContentType.FILE_NAME_SPEC | IContentType.IGNORE_PRE_DEFINED);
+			String[] preextfileSpecs = contentType
+					.getFileSpecs(IContentType.FILE_EXTENSION_SPEC | IContentType.IGNORE_USER_DEFINED);
+			String[] prenamefileSpecs = contentType
+					.getFileSpecs(IContentType.FILE_NAME_SPEC | IContentType.IGNORE_USER_DEFINED);
+
+			return createSpecs(userextfileSpecs, usernamefileSpecs,
+					preextfileSpecs, prenamefileSpecs);
+		}
+
+		private Object[] createSpecs(String[] userextfileSpecs,
+				String[] usernamefileSpecs, String[] preextfileSpecs,
+				String[] prenamefileSpecs) {
+			List returnValues = new ArrayList();
+			for (String usernamefileSpec : usernamefileSpecs) {
+				Spec spec = new Spec();
+				spec.name = usernamefileSpec;
+				spec.isPredefined = false;
+				spec.sortValue = 0;
+				returnValues.add(spec);
+			}
+
+			for (String prenamefileSpec : prenamefileSpecs) {
+				Spec spec = new Spec();
+				spec.name = prenamefileSpec;
+				spec.isPredefined = true;
+				spec.sortValue = 1;
+				returnValues.add(spec);
+			}
+
+			for (String userextfileSpec : userextfileSpecs) {
+				Spec spec = new Spec();
+				spec.ext = userextfileSpec;
+				spec.isPredefined = false;
+				spec.sortValue = 2;
+				returnValues.add(spec);
+			}
+
+			for (String preextfileSpec : preextfileSpecs) {
+				Spec spec = new Spec();
+				spec.ext = preextfileSpec;
+				spec.isPredefined = true;
+				spec.sortValue = 3;
+				returnValues.add(spec);
+			}
+
+			return returnValues.toArray();
+		}
+	}
+
+	private class ContentTypesLabelProvider extends LabelProvider {
+		@Override
+		public String getText(Object element) {
+			IContentType contentType = (IContentType) element;
+			return contentType.getName();
+		}
+	}
+
+	private class ContentTypesContentProvider implements ITreeContentProvider {
+
+		private IContentTypeManager manager;
+
+		@Override
+		public Object[] getChildren(Object parentElement) {
+			List elements = new ArrayList();
+			IContentType baseType = (IContentType) parentElement;
+			for (IContentType contentType : manager.getAllContentTypes()) {
+				if (Util.equals(contentType.getBaseType(), baseType)) {
+					elements.add(contentType);
+				}
+			}
+			return elements.toArray();
+		}
+
+		@Override
+		public Object getParent(Object element) {
+			IContentType contentType = (IContentType) element;
+			return contentType.getBaseType();
+		}
+
+		@Override
+		public boolean hasChildren(Object element) {
+			return getChildren(element).length > 0;
+		}
+
+		@Override
+		public Object[] getElements(Object inputElement) {
+			return getChildren(null);
+		}
+
+        @Override
+        public void dispose()
+        {
+
+        }
+		
+		@Override
+		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+			manager = (IContentTypeManager) newInput;
+		}
+	}
+
+	@Override
+	protected Control createContents(Composite parent) {
+		Composite composite = new Composite(parent, SWT.NONE);
+		GridLayout layout = new GridLayout(2, false);
+		layout.marginHeight = layout.marginWidth = 0;
+		composite.setLayout(layout);
+
+		PreferenceLinkArea contentTypeArea = new PreferenceLinkArea(
+				composite,
+				SWT.NONE,
+				"org.eclipse.ui.preferencePages.FileEditors", WorkbenchMessages.get().ContentTypes_FileEditorsRelatedLink,//$NON-NLS-1$
+				(IWorkbenchPreferenceContainer) getContainer(), null);
+
+		GridData data = new GridData(GridData.FILL_HORIZONTAL
+				| GridData.GRAB_HORIZONTAL);
+		contentTypeArea.getControl().setLayoutData(data);
+
+		createContentTypesTree(composite);
+		createFileAssociations(composite);
+		createCharset(composite);
+
+		workbench.getHelpSystem().setHelp(parent,
+				IWorkbenchHelpContextIds.CONTENT_TYPES_PREFERENCE_PAGE);
+
+		applyDialogFont(composite);
+		return composite;
+	}
+
+	private void createCharset(final Composite parent) {
+		Composite composite = new Composite(parent, SWT.NONE);
+		GridLayout layout = new GridLayout(3, false);
+		layout.marginHeight = layout.marginWidth = 0;
+		GridData compositeData = new GridData(GridData.FILL_HORIZONTAL);
+		compositeData.horizontalSpan = 2;
+		composite.setLayoutData(compositeData);
+		composite.setLayout(layout);
+
+		Label label = new Label(composite, SWT.NONE);
+		label.setFont(parent.getFont());
+		label.setText(WorkbenchMessages.get().get().ContentTypes_characterSetLabel);
+		charsetField = new Text(composite, SWT.SINGLE | SWT.BORDER);
+		charsetField.setFont(parent.getFont());
+		charsetField.setEnabled(false);
+		GridData data = new GridData(GridData.FILL_HORIZONTAL);
+		charsetField.setLayoutData(data);
+		setButton = new Button(composite, SWT.PUSH);
+		setButton.setFont(parent.getFont());
+		setButton
+				.setText(WorkbenchMessages.get().ContentTypes_characterSetUpdateLabel);
+		setButton.setEnabled(false);
+		setButtonLayoutData(setButton);
+		setButton.addSelectionListener(new SelectionAdapter()
+        {
+            /** {@inheritDoc} */
+            @Override
+            public void widgetSelected(SelectionEvent e)
+            {            
+                try {
+                    String text = charsetField.getText().trim();
+                    if (text.length() == 0) {
+                        text = null;
+                    }
+                    getSelectedContentType().setDefaultCharset(text);
+                    setButton.setEnabled(false);
+                } catch (CoreException e1) {
+                    StatusUtil.handleStatus(e1.getStatus(), StatusManager.SHOW,
+                                            parent.getShell());
+                }
+            }
+		});
+
+		charsetField.addKeyListener(new KeyAdapter() {
+			@Override
+			public void keyReleased(KeyEvent e) {
+				IContentType contentType = getSelectedContentType();
+				String charset = contentType.getDefaultCharset();
+				if (charset == null) {
+					charset = ""; //$NON-NLS-1$
+				}
+				setButton.setEnabled(!charset.equals(charsetField.getText())
+						&& getErrorMessage() == null);
+			}
+		});
+
+		charsetField.addModifyListener(e -> {
+			String errorMessage = null;
+			String text = charsetField.getText();
+			try {
+				if (text.length() != 0 && !Charset.isSupported(text))
+					errorMessage = WorkbenchMessages.get().ContentTypes_unsupportedEncoding;
+			} catch (IllegalCharsetNameException ex) {
+				errorMessage = WorkbenchMessages.get().ContentTypes_unsupportedEncoding;
+			}
+			setErrorMessage(errorMessage);
+		});
+
+	}
+
+	/**
+	 * @param composite
+	 */
+	private void createFileAssociations(final Composite composite) {
+		{
+			Label label = new Label(composite, SWT.NONE);
+			label.setText(WorkbenchMessages.get().get().ContentTypes_fileAssociationsLabel);
+			GridData data = new GridData();
+			data.horizontalSpan = 2;
+			label.setLayoutData(data);
+		}
+		{
+			fileAssociationViewer = new ListViewer(composite);
+			fileAssociationViewer.setComparator(new FileSpecComparator());
+			fileAssociationViewer.getControl().setFont(composite.getFont());
+			fileAssociationViewer
+					.setContentProvider(new FileSpecContentProvider());
+			fileAssociationViewer.setLabelProvider(new FileSpecLabelProvider());
+			GridData data = new GridData(GridData.FILL_BOTH);
+			data.horizontalSpan = 1;
+			fileAssociationViewer.getControl().setLayoutData(data);
+			fileAssociationViewer
+					.addSelectionChangedListener(event -> {
+						IStructuredSelection selection = (IStructuredSelection) event
+								.getSelection();
+						if (selection.isEmpty()) {
+							editButton.setEnabled(false);
+							removeButton.setEnabled(false);
+							return;
+						}
+						boolean enabled = true;
+						List elements = selection.toList();
+						for (Iterator i = elements.iterator(); i.hasNext();) {
+							Spec spec = (Spec) i.next();
+							if (spec.isPredefined) {
+								enabled = false;
+							}
+						}
+						editButton.setEnabled(enabled && selection.size() == 1);
+						removeButton.setEnabled(enabled);
+					});
+		}
+		{
+			Composite buttonArea = new Composite(composite, SWT.NONE);
+			GridLayout layout = new GridLayout(1, false);
+			buttonArea.setLayout(layout);
+			GridData data = new GridData(SWT.DEFAULT, SWT.TOP, false, false);
+			buttonArea.setLayoutData(data);
+
+			addButton = new Button(buttonArea, SWT.PUSH);
+			addButton.setFont(composite.getFont());
+			addButton
+					.setText(WorkbenchMessages.get().ContentTypes_fileAssociationsAddLabel);
+			addButton.setEnabled(false);
+			setButtonLayoutData(addButton);
+			addButton.addSelectionListener(new SelectionAdapter()
+            {
+                /** {@inheritDoc} */
+                @Override
+                public void widgetSelected(SelectionEvent e)
+                {
+    				Shell shell = composite.getShell();
+    				IContentType selectedContentType = getSelectedContentType();
+    				FileExtensionDialog dialog = new FileExtensionDialog(
+    						shell,
+    						WorkbenchMessages.get().ContentTypes_addDialog_title,
+    						IWorkbenchHelpContextIds.FILE_EXTENSION_DIALOG,
+    						WorkbenchMessages.get().ContentTypes_addDialog_messageHeader,
+    						WorkbenchMessages.get().ContentTypes_addDialog_message,
+    						WorkbenchMessages.get().ContentTypes_addDialog_label);
+    				if (dialog.open() == Window.OK) {
+    					String name = dialog.getName();
+    					String extension = dialog.getExtension();
+    					try {
+    						if (name.equals("*")) { //$NON-NLS-1$
+    							selectedContentType.addFileSpec(extension,
+    									IContentType.FILE_EXTENSION_SPEC);
+    						} else {
+    							selectedContentType
+    									.addFileSpec(
+    											name
+    													+ (extension.length() > 0 ? ('.' + extension)
+    															: ""), //$NON-NLS-1$
+    											IContentType.FILE_NAME_SPEC);
+    						}
+    					} catch (CoreException ex) {
+    						StatusUtil.handleStatus(ex.getStatus(),
+    								StatusManager.SHOW, shell);
+    						WorkbenchPlugin.log(ex);
+    					} finally {
+    						fileAssociationViewer.refresh(false);
+    					}
+    				
+                    }
+                }
+			});
+
+			editButton = new Button(buttonArea, SWT.PUSH);
+			editButton.setFont(composite.getFont());
+			editButton
+					.setText(WorkbenchMessages.get().ContentTypes_fileAssociationsEditLabel);
+			editButton.setEnabled(false);
+			setButtonLayoutData(editButton);
+			editButton.addSelectionListener(new SelectionAdapter()
+            {
+                /** {@inheritDoc} */
+                @Override
+                public void widgetSelected(SelectionEvent e)
+                {
+    				Shell shell = composite.getShell();
+    				IContentType selectedContentType = getSelectedContentType();
+    				Spec spec = getSelectedSpecs()[0];
+    				FileExtensionDialog dialog = new FileExtensionDialog(
+    						shell,
+    						WorkbenchMessages.get().ContentTypes_editDialog_title,
+    						IWorkbenchHelpContextIds.FILE_EXTENSION_DIALOG,
+    						WorkbenchMessages.get().ContentTypes_editDialog_messageHeader,
+    						WorkbenchMessages.get().ContentTypes_editDialog_message,
+    						WorkbenchMessages.get().ContentTypes_editDialog_label);
+    				if (spec.name == null) {
+    					dialog.setInitialValue("*." + spec.ext); //$NON-NLS-1$
+    				} else {
+    					dialog.setInitialValue(spec.name);
+    				}
+    				if (dialog.open() == Window.OK) {
+    					String name = dialog.getName();
+    					String extension = dialog.getExtension();
+    					try {
+    						// remove the original spec
+    						if (spec.name != null) {
+    							selectedContentType.removeFileSpec(spec.name,
+    									IContentType.FILE_NAME_SPEC);
+    						} else if (spec.ext != null) {
+    							selectedContentType.removeFileSpec(spec.ext,
+    									IContentType.FILE_EXTENSION_SPEC);
+    						}
+    
+    						// add the new one
+    						if (name.equals("*")) { //$NON-NLS-1$
+    							selectedContentType.addFileSpec(extension,
+    									IContentType.FILE_EXTENSION_SPEC);
+    						} else {
+    							selectedContentType
+    									.addFileSpec(
+    											name
+    													+ (extension.length() > 0 ? ('.' + extension)
+    															: ""), //$NON-NLS-1$
+    											IContentType.FILE_NAME_SPEC);
+    						}
+    					} catch (CoreException ex) {
+    						StatusUtil.handleStatus(ex.getStatus(),
+    								StatusManager.SHOW, shell);
+    						WorkbenchPlugin.log(ex);
+    					} finally {
+    						fileAssociationViewer.refresh(false);
+    					}
+    				}
+                }
+			});
+
+			removeButton = new Button(buttonArea, SWT.PUSH);
+			removeButton.setEnabled(false);
+			removeButton
+					.setText(WorkbenchMessages.get().ContentTypes_fileAssociationsRemoveLabel);
+			setButtonLayoutData(removeButton);
+			removeButton.addSelectionListener(new SelectionAdapter()
+            {
+                /** {@inheritDoc} */
+                @Override
+                public void widgetSelected(SelectionEvent e)
+                {
+                    IContentType contentType = getSelectedContentType();
+                    Spec[] specs = getSelectedSpecs();
+                    MultiStatus result = new MultiStatus(PlatformUI.PLUGIN_ID,
+                                                         0, new IStatus[0],
+                                                         WorkbenchMessages.get().ContentTypes_errorDialogMessage,
+                                                         null);
+                    for (Spec spec : specs) {
+                        try {
+                            if (spec.name != null) {
+                                contentType.removeFileSpec(spec.name,
+                                                           IContentType.FILE_NAME_SPEC);
+                            } else if (spec.ext != null) {
+                                contentType.removeFileSpec(spec.ext,
+                                                           IContentType.FILE_EXTENSION_SPEC);
+                            }
+                        } catch (CoreException e2) {
+                            result.add(e2.getStatus());
+                        }
+                    }
+                    if (!result.isOK()) {
+                        StatusUtil.handleStatus(result, StatusManager.SHOW,
+                                                composite.getShell());
+                    }
+                    fileAssociationViewer.refresh(false);
+                }
+			});
+		}
+	}
+
+	protected Spec[] getSelectedSpecs() {
+		List<Spec> list = fileAssociationViewer.getStructuredSelection().toList();
+		return list.toArray(new Spec[list.size()]);
+	}
+
+	protected IContentType getSelectedContentType() {
+		return (IContentType) contentTypesViewer.getStructuredSelection().getFirstElement();
+	}
+
+	/**
+	 * @param composite
+	 */
+	private void createContentTypesTree(Composite composite) {
+		{
+			Label label = new Label(composite, SWT.NONE);
+			label.setFont(composite.getFont());
+			label.setText(WorkbenchMessages.get().ContentTypes_contentTypesLabel);
+			GridData data = new GridData();
+			data.horizontalSpan = 2;
+			label.setLayoutData(data);
+		}
+		{
+			contentTypesViewer = new TreeViewer(composite, SWT.SINGLE
+					| SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
+			contentTypesViewer.getControl().setFont(composite.getFont());
+			contentTypesViewer
+					.setContentProvider(new ContentTypesContentProvider());
+			contentTypesViewer
+					.setLabelProvider(new ContentTypesLabelProvider());
+			contentTypesViewer.setComparator(new ViewerComparator());
+			contentTypesViewer.setInput(Platform.getContentTypeManager());
+			GridData data = new GridData(GridData.FILL_BOTH);
+			contentTypesViewer.getControl().setLayoutData(data);
+
+			contentTypesViewer
+					.addSelectionChangedListener(event -> {
+						IContentType contentType = (IContentType) ((IStructuredSelection) event
+								.getSelection()).getFirstElement();
+						fileAssociationViewer.setInput(contentType);
+						editButton.setEnabled(false);
+						removeButton.setEnabled(false);
+
+						if (contentType != null) {
+							String charset = contentType
+									.getDefaultCharset();
+							if (charset == null) {
+								charset = ""; //$NON-NLS-1$
+							}
+							charsetField.setText(charset);
+						} else {
+							charsetField.setText(""); //$NON-NLS-1$
+						}
+
+						charsetField.setEnabled(contentType != null);
+						addButton.setEnabled(contentType != null);
+						setButton.setEnabled(false);
+
+						addChildContentTypeButton.setEnabled(contentType != null);
+						removeContentTypeButton.setEnabled(contentType != null && contentType.isUserDefined());
+					});
+		}
+		Composite buttonsComposite = new Composite(composite, SWT.NONE);
+		buttonsComposite.setLayoutData(new GridData(SWT.DEFAULT, SWT.TOP, false, false));
+		buttonsComposite.setLayout(new GridLayout(1, false));
+		Button addRootContentTypeButton = new Button(buttonsComposite, SWT.PUSH);
+		setButtonLayoutData(addRootContentTypeButton);
+		addRootContentTypeButton.setText(WorkbenchMessages.get().ContentTypes_addRootContentTypeButton);
+		addRootContentTypeButton.addSelectionListener(new SelectionAdapter()
+        {
+            /** {@inheritDoc} */
+            @Override
+            public void widgetSelected(SelectionEvent e)
+            {
+                String id = "userCreated" + System.currentTimeMillis(); //$NON-NLS-1$
+                IContentTypeManager manager = (IContentTypeManager) contentTypesViewer.getInput();
+                NewContentTypeDialog dialog = new NewContentTypeDialog(ContentTypesPreferencePage.this.getShell(),
+                                                                       manager, null);
+                if (dialog.open() == IDialogConstants.OK_ID) {
+                    try {
+                        IContentType newContentType = manager.addContentType(id, dialog.getName(), null);
+                        contentTypesViewer.refresh();
+                        contentTypesViewer.setSelection(new StructuredSelection(newContentType));
+                    } catch (CoreException e1) {
+                        MessageDialog.openError(getShell(), WorkbenchMessages.get().ContentTypes_failedAtEditingContentTypes,
+                                                e1.getMessage());
+                    }
+                }
+            }
+		});
+		addChildContentTypeButton = new Button(buttonsComposite, SWT.PUSH);
+		setButtonLayoutData(addChildContentTypeButton);
+		addChildContentTypeButton.setText(WorkbenchMessages.get().ContentTypes_addChildContentTypeButton);
+		addChildContentTypeButton.addSelectionListener(new SelectionAdapter()
+        {
+            /** {@inheritDoc} */
+            @Override
+            public void widgetSelected(SelectionEvent e)
+            {
+                String id = "userCreated" + System.currentTimeMillis(); //$NON-NLS-1$
+                IContentTypeManager manager = (IContentTypeManager) contentTypesViewer.getInput();
+                NewContentTypeDialog dialog = new NewContentTypeDialog(ContentTypesPreferencePage.this.getShell(),
+                                                                       manager,
+                                                                       getSelectedContentType());
+                if (dialog.open() == IDialogConstants.OK_ID) {
+                    try {
+                        IContentType newContentType = manager.addContentType(id, dialog.getName(),
+                                                                             getSelectedContentType());
+                        contentTypesViewer.refresh(getSelectedContentType());
+                        contentTypesViewer.setSelection(new StructuredSelection(newContentType));
+                    } catch (CoreException e1) {
+                        MessageDialog.openError(getShell(), WorkbenchMessages.get().ContentTypes_failedAtEditingContentTypes,
+                                                e1.getMessage());
+                    }
+                }
+            }
+		});
+		addChildContentTypeButton.setEnabled(getSelectedContentType() != null);
+		removeContentTypeButton = new Button(buttonsComposite, SWT.PUSH);
+		setButtonLayoutData(removeContentTypeButton);
+		removeContentTypeButton.setText(WorkbenchMessages.get().ContentTypes_removeContentTypeButton);
+		removeContentTypeButton.addSelectionListener(new SelectionAdapter()
+        {
+            /** {@inheritDoc} */
+            @Override
+            public void widgetSelected(SelectionEvent e)
+            {
+                IContentType selectedContentType = getSelectedContentType();
+                try {
+                    Platform.getContentTypeManager().removeContentType(selectedContentType.getId());
+                    contentTypesViewer.refresh();
+                } catch (CoreException e1) {
+                    MessageDialog.openError(getShell(), WorkbenchMessages.get().ContentTypes_failedAtEditingContentTypes,
+                                            e1.getMessage());
+                }
+            }
+		});
+		removeContentTypeButton
+				.setEnabled(getSelectedContentType() != null && getSelectedContentType().isUserDefined());
+	}
+
+	@Override
+	public void init(IWorkbench workbench) {
+		this.workbench = workbench;
+		noDefaultAndApplyButton();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/DataTransferWizardCollectionComparator.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/DataTransferWizardCollectionComparator.java
new file mode 100644
index 0000000..0ae8ad1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/DataTransferWizardCollectionComparator.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.dialogs;
+
+import org.eclipse.jface.viewers.IBasicPropertyConstants;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.ui.internal.registry.WizardsRegistryReader;
+
+/**
+ *	A Viewer element sorter that sorts Elements by their name attribute.
+ *	Note that capitalization differences are not considered by this
+ *	sorter, so a < B < c.
+ *
+ *	NOTE exceptions to the above: an element with the system's reserved
+ *	category for Other Wizards will always be sorted such that it will
+ *	ultimately be placed at the end of the sorted result, and an elemen
+ *  with the reserved category name for General wizards will always be
+ *  placed at the beginning of the sorted result.
+ *
+ *  @since 3.2
+ */
+class DataTransferWizardCollectionComparator extends ViewerComparator {
+	/**
+	 * Static instance of this class.
+	 */
+    public final static DataTransferWizardCollectionComparator INSTANCE = new DataTransferWizardCollectionComparator();
+
+    /**
+     * Creates an instance of <code>DataTransferWizardCollectionSorter</code>.  Since this
+     * is a stateless sorter, it is only accessible as a singleton; the private
+     * visibility of this constructor ensures this.
+     */
+    private DataTransferWizardCollectionComparator() {
+        super();
+    }
+
+    @Override
+	public int category(Object element) {
+		if (element instanceof WizardCollectionElement){
+			String id = ((WizardCollectionElement)element).getId();
+    		if (WizardsRegistryReader.GENERAL_WIZARD_CATEGORY.equals(id)) {
+				return 1;
+			}
+    		if (WizardsRegistryReader.UNCATEGORIZED_WIZARD_CATEGORY.equals(id)) {
+				return 3;
+			}
+    		return 2;
+		}
+		return super.category(element);
+	}
+
+	/**
+     *	Return true if this sorter is affected by a property
+     *	change of propertyName on the specified element.
+     */
+    @Override
+	public boolean isSorterProperty(Object object, String propertyId) {
+        return propertyId.equals(IBasicPropertyConstants.P_TEXT);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/DecoratorsPreferencePage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/DecoratorsPreferencePage.java
new file mode 100644
index 0000000..f5d9d84
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/DecoratorsPreferencePage.java
@@ -0,0 +1,290 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.dialogs;
+
+import com.ibm.icu.text.Collator;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import org.eclipse.jface.preference.IPreferencePage;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.jface.viewers.CheckboxTableViewer;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.decorators.DecoratorDefinition;
+import org.eclipse.ui.internal.decorators.DecoratorManager;
+
+/**
+ * The DecoratorsPreferencePage is the preference page for enabling and disabling
+ * the decorators in the image and for giving the user a description of the decorator.
+ */
+public class DecoratorsPreferencePage extends PreferencePage implements
+        IWorkbenchPreferencePage {
+
+    private Text descriptionText;
+
+    private CheckboxTableViewer checkboxViewer;
+
+    /**
+     * @see PreferencePage#createContents(Composite)
+     */
+    @Override
+	protected Control createContents(Composite parent) {
+
+        Font font = parent.getFont();
+
+        PlatformUI.getWorkbench().getHelpSystem().setHelp(parent,
+				IWorkbenchHelpContextIds.DECORATORS_PREFERENCE_PAGE);
+
+        Composite mainComposite = new Composite(parent, SWT.NONE);
+        mainComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+        mainComposite.setFont(font);
+
+        GridLayout layout = new GridLayout();
+        layout.marginWidth = 0;
+        layout.marginHeight = 0;
+        layout.verticalSpacing = 10;
+        mainComposite.setLayout(layout);
+
+        Label topLabel = new Label(mainComposite, SWT.NONE);
+        topLabel.setText(WorkbenchMessages.get().DecoratorsPreferencePage_explanation);
+        topLabel.setFont(font);
+
+        createDecoratorsArea(mainComposite);
+        createDescriptionArea(mainComposite);
+        populateDecorators();
+
+        return mainComposite;
+    }
+
+    /**
+     * Creates the widgets for the list of decorators.
+     */
+    private void createDecoratorsArea(Composite mainComposite) {
+
+        Font mainFont = mainComposite.getFont();
+        Composite decoratorsComposite = new Composite(mainComposite, SWT.NONE);
+        decoratorsComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
+        GridLayout decoratorsLayout = new GridLayout();
+        decoratorsLayout.marginWidth = 0;
+        decoratorsLayout.marginHeight = 0;
+        decoratorsComposite.setLayout(decoratorsLayout);
+        decoratorsComposite.setFont(mainFont);
+
+        Label decoratorsLabel = new Label(decoratorsComposite, SWT.NONE);
+        decoratorsLabel.setText(WorkbenchMessages.get().DecoratorsPreferencePage_decoratorsLabel);
+        decoratorsLabel.setFont(mainFont);
+
+        // Checkbox table viewer of decorators
+        checkboxViewer = CheckboxTableViewer.newCheckList(decoratorsComposite,
+                SWT.SINGLE | SWT.TOP | SWT.BORDER);
+        checkboxViewer.getTable().setLayoutData(
+                new GridData(GridData.FILL_BOTH));
+        checkboxViewer.getTable().setFont(decoratorsComposite.getFont());
+        checkboxViewer.setLabelProvider(new LabelProvider() {
+            @Override
+			public String getText(Object element) {
+                return ((DecoratorDefinition) element).getName();
+            }
+        });
+        checkboxViewer.getTable().setFont(mainFont);
+
+        checkboxViewer.setContentProvider(new IStructuredContentProvider() {
+            private final Comparator comparer = new Comparator() {
+                private Collator collator = Collator.getInstance();
+
+                @Override
+				public int compare(Object arg0, Object arg1) {
+                    String s1 = ((DecoratorDefinition) arg0).getName();
+                    String s2 = ((DecoratorDefinition) arg1).getName();
+                    return collator.compare(s1, s2);
+                }
+            };
+
+            @Override
+			public void dispose() {
+                //Nothing to do on dispose
+            }
+
+            @Override
+			public void inputChanged(Viewer viewer, Object oldInput,
+                    Object newInput) {
+            }
+
+            @Override
+			public Object[] getElements(Object inputElement) {
+                //Make an entry for each decorator definition
+                Object[] elements = (Object[]) inputElement;
+                Object[] results = new Object[elements.length];
+                System.arraycopy(elements, 0, results, 0, elements.length);
+                Collections.sort(Arrays.asList(results), comparer);
+                return results;
+            }
+
+        });
+
+        checkboxViewer
+                .addSelectionChangedListener(event -> {
+				    if (event.getSelection() instanceof IStructuredSelection) {
+				        IStructuredSelection sel = (IStructuredSelection) event
+				                .getSelection();
+				        DecoratorDefinition definition = (DecoratorDefinition) sel
+				                .getFirstElement();
+				        if (definition == null) {
+							clearDescription();
+						} else {
+							showDescription(definition);
+						}
+				    }
+				});
+
+        checkboxViewer.addCheckStateListener(event -> checkboxViewer.setSelection(new StructuredSelection(event
+		        .getElement())));
+    }
+
+    /**
+     * Creates the widgets for the description.
+     */
+    private void createDescriptionArea(Composite mainComposite) {
+
+        Font mainFont = mainComposite.getFont();
+        Composite textComposite = new Composite(mainComposite, SWT.NONE);
+        textComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
+        GridLayout textLayout = new GridLayout();
+        textLayout.marginWidth = 0;
+        textLayout.marginHeight = 0;
+        textComposite.setLayout(textLayout);
+        textComposite.setFont(mainFont);
+
+        Label descriptionLabel = new Label(textComposite, SWT.NONE);
+        descriptionLabel.setText(WorkbenchMessages.get().DecoratorsPreferencePage_description);
+        descriptionLabel.setFont(mainFont);
+
+        descriptionText = new Text(textComposite, SWT.MULTI | SWT.WRAP
+                | SWT.READ_ONLY | SWT.BORDER | SWT.H_SCROLL);
+        descriptionText.setLayoutData(new GridData(GridData.FILL_BOTH));
+        descriptionText.setFont(mainFont);
+    }
+
+    /**
+     * Populates the list of decorators.
+     */
+    private void populateDecorators() {
+        DecoratorDefinition[] definitions = getAllDefinitions();
+        checkboxViewer.setInput(definitions);
+        for (DecoratorDefinition definition : definitions) {
+            checkboxViewer.setChecked(definition, definition
+                    .isEnabled());
+        }
+    }
+
+    /**
+     * Show the selected description in the text.
+     */
+    private void showDescription(DecoratorDefinition definition) {
+        if (descriptionText == null || descriptionText.isDisposed()) {
+            return;
+        }
+        String text = definition.getDescription();
+        if (text == null || text.length() == 0) {
+			descriptionText.setText(WorkbenchMessages.get().PreferencePage_noDescription);
+		} else {
+			descriptionText.setText(text);
+		}
+    }
+
+    /**
+     * Clear the selected description in the text.
+     */
+    private void clearDescription() {
+        if (descriptionText == null || descriptionText.isDisposed()) {
+            return;
+        }
+        descriptionText.setText(""); //$NON-NLS-1$
+    }
+
+    /**
+     * @see PreferencePage#performDefaults()
+     */
+    @Override
+	protected void performDefaults() {
+        super.performDefaults();
+		DecoratorManager manager = WorkbenchPlugin.getDefault().getDecoratorManager();
+		for (DecoratorDefinition definition : manager.getAllDecoratorDefinitions()) {
+            checkboxViewer.setChecked(definition, definition
+                    .getDefaultValue());
+        }
+    }
+
+    /**
+     * @see IPreferencePage#performOk()
+     */
+    @Override
+	public boolean performOk() {
+        if (super.performOk()) {
+            DecoratorManager manager = getDecoratorManager();
+            //Clear the caches first to avoid unneccessary updates
+            manager.clearCaches();
+			for (DecoratorDefinition definition : manager.getAllDecoratorDefinitions()) {
+                boolean checked = checkboxViewer.getChecked(definition);
+                definition.setEnabled(checked);
+
+            }
+            //Have the manager clear again as there may have been
+            //extra updates fired by the enablement changes.
+            manager.clearCaches();
+            manager.updateForEnablementChange();
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * @see IWorkbenchPreferencePage#init(IWorkbench)
+     */
+    @Override
+	public void init(IWorkbench workbench) {
+    }
+
+    /**
+     * Get the decorator definitions for the workbench.
+     */
+    private DecoratorDefinition[] getAllDefinitions() {
+        return getDecoratorManager().getAllDecoratorDefinitions();
+    }
+
+    /**
+     * Get the DecoratorManager being used for this page.
+     *
+     * @return the decorator manager
+     */
+    private DecoratorManager getDecoratorManager() {
+        return WorkbenchPlugin.getDefault().getDecoratorManager();
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/DialogUtil.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/DialogUtil.java
new file mode 100644
index 0000000..9357bac
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/DialogUtil.java
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.dialogs;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+/**
+ * Utility class to help with dialogs.
+ * <p>
+ * Note that a copy of this class exists in the
+ * org.eclipse.ui.internal.ide package.
+ * </p>
+ */
+public class DialogUtil {
+
+    /**
+     * Prevent instantiation.
+     */
+    private DialogUtil() {
+    }
+
+    /**
+     * Open an error style dialog for PartInitException by
+     * including any extra information from the nested
+     * CoreException if present.
+     */
+    public static void openError(Shell parent, String title, String message,
+            PartInitException exception) {
+        // Check for a nested CoreException
+        CoreException nestedException = null;
+        IStatus status = exception.getStatus();
+        if (status != null && status.getException() instanceof CoreException) {
+			nestedException = (CoreException) status.getException();
+		}
+
+        IStatus errorStatus = null;
+
+		if (nestedException != null) {
+			// Open an error dialog and include the extra
+			// status information from the nested CoreException
+			errorStatus = StatusUtil.newStatus(nestedException.getStatus(),
+					message);
+		} else {
+			// Open a regular error dialog since there is no
+			// extra information to displa
+			errorStatus = new Status(IStatus.ERROR,
+					WorkbenchPlugin.PI_WORKBENCH, message);
+		}
+
+		StatusUtil.handleStatus(errorStatus, StatusManager.SHOW, parent);
+    }
+
+    /**
+	 * Removes the '&' accelerator indicator from a label, if any. Also removes
+	 * the () accelerators which are used in Asian languages.
+	 */
+    public static String removeAccel(String label) {
+
+        int startBracket = label.indexOf("(&"); //$NON-NLS-1$
+        //Non latin accelerator?
+        if (startBracket >= 0) {
+            int endBracket = label.indexOf(')');
+
+            //If there is more than one character it is not an accelerator
+            if ((endBracket - startBracket) == 3) {
+				return label.substring(0, startBracket)
+                        + label.substring(endBracket + 1);
+			}
+        }
+
+        int i = label.indexOf('&');
+        if (i >= 0) {
+			label = label.substring(0, i) + label.substring(i + 1);
+		}
+
+        return label;
+    }
+
+    /**
+     * Return the number of rows available in the current display using the
+     * current font.
+     * @param parent The Composite whose Font will be queried.
+     * @return int The result of the display size divided by the font size.
+     */
+    public static int availableRows(Composite parent) {
+
+        int fontHeight = (parent.getFont().getFontData())[0].getHeight();
+        int displayHeight = parent.getDisplay().getClientArea().height;
+
+        return displayHeight / fontHeight;
+    }
+
+    /**
+     * Return whether or not the font in the parent is the size of a result
+     * font (i.e. smaller than the High Contrast Font). This method is used to
+     * make layout decisions based on screen space.
+     * @param parent The Composite whose Font will be queried.
+     * @return boolean. True if there are more than 50 lines of possible
+     * text in the display.
+     */
+    public static boolean inRegularFontMode(Composite parent) {
+
+        return availableRows(parent) > 50;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/EditorsPreferencePage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/EditorsPreferencePage.java
new file mode 100644
index 0000000..d6a69a2
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/EditorsPreferencePage.java
@@ -0,0 +1,332 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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
+ *     Sebastian Davids <sdavids@gmx.de> - bug 97667 [Preferences] Pref Page General/Editors - problems
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 489891
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.dialogs;
+
+import org.eclipse.jface.preference.FieldEditor;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.IntegerFieldEditor;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.jface.preference.StringFieldEditor;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferenceConstants;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.EditorHistory;
+import org.eclipse.ui.internal.IPreferenceConstants;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.util.PrefUtil;
+
+/**
+ * The Editors preference page of the workbench.
+ */
+public class EditorsPreferencePage extends PreferencePage implements
+        IWorkbenchPreferencePage {
+	private static final int REUSE_INDENT = 20;
+
+    protected Composite editorReuseGroup;
+
+    private Button reuseEditors;
+
+    protected Button showMultipleEditorTabs;
+
+    protected Button useIPersistableEditor;
+
+    private Composite editorReuseIndentGroup;
+
+    private Composite editorReuseThresholdGroup;
+
+    private IntegerFieldEditor reuseEditorsThreshold;
+
+
+    private IntegerFieldEditor recentFilesEditor;
+
+    private IPropertyChangeListener validityChangeListener = event -> {
+	    if (event.getProperty().equals(FieldEditor.IS_VALID)) {
+			updateValidState();
+		}
+	};
+
+	private Button promptWhenStillOpenEditor;
+
+	private Button allowInplaceEditor;
+
+	@Override
+	protected Control createContents(Composite parent) {
+        Composite composite = createComposite(parent);
+
+        createEditorHistoryGroup(composite);
+
+//        createSpace(composite);
+        createShowMultipleEditorTabsPref(composite);
+        createAllowInplaceEditorPref(composite);
+        createUseIPersistablePref(composite);
+        createPromptWhenStillOpenPref(composite);
+		createEditorReuseGroup(composite);
+		// ((TabBehaviour)Tweaklets.get(TabBehaviour.KEY)).setPreferenceVisibility(editorReuseGroup,
+		// showMultipleEditorTabs);
+
+        updateValidState();
+
+        applyDialogFont(composite);
+
+        setHelpContext(parent);
+
+        return composite;
+    }
+
+	protected void setHelpContext(Composite parent) {
+		// @issue the IDE subclasses this, but should provide its own help
+        PlatformUI.getWorkbench().getHelpSystem().setHelp(parent,
+				IWorkbenchHelpContextIds.WORKBENCH_EDITOR_PREFERENCE_PAGE);
+	}
+
+//    protected void createSpace(Composite parent) {
+//        WorkbenchPreferencePage.createSpace(parent);
+//    }
+
+    protected void createShowMultipleEditorTabsPref(Composite composite) {
+        showMultipleEditorTabs = new Button(composite, SWT.CHECK);
+        showMultipleEditorTabs.setText(WorkbenchMessages.get().WorkbenchPreference_showMultipleEditorTabsButton);
+        showMultipleEditorTabs.setSelection(getAPIPreferenceStore().getBoolean(
+                IWorkbenchPreferenceConstants.SHOW_MULTIPLE_EDITOR_TABS));
+        setButtonLayoutData(showMultipleEditorTabs);
+    }
+
+    protected void createAllowInplaceEditorPref(Composite composite) {
+    	allowInplaceEditor = new Button(composite, SWT.CHECK);
+    	allowInplaceEditor.setText(WorkbenchMessages.get().WorkbenchPreference_allowInplaceEditingButton);
+    	allowInplaceEditor.setSelection(!getAPIPreferenceStore().getBoolean(
+    			IWorkbenchPreferenceConstants.DISABLE_OPEN_EDITOR_IN_PLACE));
+    	setButtonLayoutData(allowInplaceEditor);
+    }
+
+    protected void createUseIPersistablePref(Composite composite) {
+        useIPersistableEditor = new Button(composite, SWT.CHECK);
+        useIPersistableEditor.setText(WorkbenchMessages.get().WorkbenchPreference_useIPersistableEditorButton);
+        useIPersistableEditor.setSelection(getPreferenceStore().getBoolean(
+                IPreferenceConstants.USE_IPERSISTABLE_EDITORS));
+        setButtonLayoutData(useIPersistableEditor);
+    }
+
+    protected void createPromptWhenStillOpenPref(Composite composite) {
+    	promptWhenStillOpenEditor = new Button(composite, SWT.CHECK);
+    	promptWhenStillOpenEditor.setText(WorkbenchMessages.get().WorkbenchPreference_promptWhenStillOpenButton);
+    	promptWhenStillOpenEditor.setSelection(getAPIPreferenceStore().getBoolean(
+    			IWorkbenchPreferenceConstants.PROMPT_WHEN_SAVEABLE_STILL_OPEN));
+    	setButtonLayoutData(promptWhenStillOpenEditor);
+    }
+
+    protected Composite createComposite(Composite parent) {
+        Composite composite = new Composite(parent, SWT.NULL);
+        GridLayout layout = new GridLayout();
+        layout.marginWidth = 0;
+        layout.marginHeight = 0;
+        composite.setLayout(layout);
+        composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
+        return composite;
+    }
+
+    @Override
+	public void init(IWorkbench workbench) {
+        // do nothing
+    }
+
+    @Override
+	protected void performDefaults() {
+        IPreferenceStore store = getPreferenceStore();
+        showMultipleEditorTabs
+				.setSelection(getAPIPreferenceStore()
+						.getDefaultBoolean(IWorkbenchPreferenceConstants.SHOW_MULTIPLE_EDITOR_TABS));
+        allowInplaceEditor
+        		.setSelection(!getAPIPreferenceStore()
+        				.getDefaultBoolean(IWorkbenchPreferenceConstants.DISABLE_OPEN_EDITOR_IN_PLACE));
+		useIPersistableEditor
+				.setSelection(store
+						.getDefaultBoolean(IPreferenceConstants.USE_IPERSISTABLE_EDITORS));
+		promptWhenStillOpenEditor
+				.setSelection(getAPIPreferenceStore()
+						.getDefaultBoolean(IWorkbenchPreferenceConstants.PROMPT_WHEN_SAVEABLE_STILL_OPEN));
+        reuseEditors.setSelection(store
+                .getDefaultBoolean(IPreferenceConstants.REUSE_EDITORS_BOOLEAN));
+        reuseEditorsThreshold.loadDefault();
+        reuseEditorsThreshold.getLabelControl(editorReuseThresholdGroup)
+                .setEnabled(reuseEditors.getSelection());
+        reuseEditorsThreshold.getTextControl(editorReuseThresholdGroup)
+                .setEnabled(reuseEditors.getSelection());
+        recentFilesEditor.loadDefault();
+    }
+
+    @Override
+	public boolean performOk() {
+        IPreferenceStore store = getPreferenceStore();
+        getAPIPreferenceStore().setValue(IWorkbenchPreferenceConstants.SHOW_MULTIPLE_EDITOR_TABS,
+                showMultipleEditorTabs.getSelection());
+        getAPIPreferenceStore().setValue(IWorkbenchPreferenceConstants.DISABLE_OPEN_EDITOR_IN_PLACE,
+        		!allowInplaceEditor.getSelection());
+        store.setValue(IPreferenceConstants.USE_IPERSISTABLE_EDITORS,
+                useIPersistableEditor.getSelection());
+        getAPIPreferenceStore().setValue(IWorkbenchPreferenceConstants.PROMPT_WHEN_SAVEABLE_STILL_OPEN,
+        		promptWhenStillOpenEditor.getSelection());
+
+        // store the reuse editors setting
+        store.setValue(IPreferenceConstants.REUSE_EDITORS_BOOLEAN, reuseEditors
+                .getSelection());
+        reuseEditorsThreshold.store();
+
+        // store the recent files setting
+        recentFilesEditor.store();
+
+        PrefUtil.savePrefs();
+        return super.performOk();
+    }
+
+    /**
+     * Returns preference store that belongs to the our plugin.
+     *
+     * @return the preference store for this plugin
+     */
+    @Override
+	protected IPreferenceStore doGetPreferenceStore() {
+        return WorkbenchPlugin.getDefault().getPreferenceStore();
+    }
+
+    protected IPreferenceStore getAPIPreferenceStore() {
+    	return PrefUtil.getAPIPreferenceStore();
+    }
+
+    protected void updateValidState() {
+        if (!recentFilesEditor.isValid()) {
+            setErrorMessage(recentFilesEditor.getErrorMessage());
+            setValid(false);
+        } else if (!reuseEditorsThreshold.isValid()) {
+            setErrorMessage(reuseEditorsThreshold.getErrorMessage());
+            setValid(false);
+        } else {
+            setErrorMessage(null);
+            setValid(true);
+        }
+    }
+
+    /**
+     * Create a composite that contains entry fields specifying editor reuse preferences.
+     */
+    protected void createEditorReuseGroup(Composite composite) {
+        editorReuseGroup = new Composite(composite, SWT.LEFT);
+        GridLayout layout = new GridLayout();
+        // Line up with other entries in preference page
+        layout.marginWidth = 0;
+        layout.marginHeight = 0;
+        editorReuseGroup.setLayout(layout);
+        editorReuseGroup.setLayoutData(new GridData(
+                GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL));
+
+        reuseEditors = new Button(editorReuseGroup, SWT.CHECK);
+        reuseEditors.setText(WorkbenchMessages.get().WorkbenchPreference_reuseEditors);
+        reuseEditors.setLayoutData(new GridData());
+
+        IPreferenceStore store = WorkbenchPlugin.getDefault()
+                .getPreferenceStore();
+        reuseEditors.setSelection(store
+                .getBoolean(IPreferenceConstants.REUSE_EDITORS_BOOLEAN));
+        reuseEditors.addSelectionListener(new SelectionAdapter()
+        {
+            /** {@inheritDoc} */
+            @Override
+            public void widgetSelected(SelectionEvent e)
+            {
+                reuseEditorsThreshold.getLabelControl(editorReuseThresholdGroup).setEnabled(reuseEditors.getSelection());
+                reuseEditorsThreshold.getTextControl(editorReuseThresholdGroup).setEnabled(reuseEditors.getSelection());
+            }
+		});
+
+        editorReuseIndentGroup = new Composite(editorReuseGroup, SWT.LEFT);
+        GridLayout indentLayout = new GridLayout();
+        indentLayout.marginLeft = REUSE_INDENT;
+        indentLayout.marginWidth = 0;
+        editorReuseIndentGroup.setLayout(indentLayout);
+        editorReuseIndentGroup.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+        editorReuseThresholdGroup = new Composite(editorReuseIndentGroup,
+                SWT.LEFT);
+        layout = new GridLayout();
+		layout.marginWidth = 0;
+        editorReuseThresholdGroup.setLayout(layout);
+        editorReuseThresholdGroup.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+        reuseEditorsThreshold = new IntegerFieldEditor(
+                IPreferenceConstants.REUSE_EDITORS,
+                WorkbenchMessages.get().WorkbenchPreference_reuseEditorsThreshold, editorReuseThresholdGroup);
+
+        reuseEditorsThreshold.setPreferenceStore(WorkbenchPlugin.getDefault()
+                .getPreferenceStore());
+        reuseEditorsThreshold.setPage(this);
+        reuseEditorsThreshold.setTextLimit(2);
+        reuseEditorsThreshold.setErrorMessage(WorkbenchMessages.get().WorkbenchPreference_reuseEditorsThresholdError);
+        reuseEditorsThreshold
+                .setValidateStrategy(StringFieldEditor.VALIDATE_ON_KEY_STROKE);
+        reuseEditorsThreshold.setValidRange(1, 99);
+        reuseEditorsThreshold.load();
+        reuseEditorsThreshold.getLabelControl(editorReuseThresholdGroup)
+                .setEnabled(reuseEditors.getSelection());
+        reuseEditorsThreshold.getTextControl(editorReuseThresholdGroup)
+                .setEnabled(reuseEditors.getSelection());
+        reuseEditorsThreshold.setPropertyChangeListener(validityChangeListener);
+
+    }
+
+    /**
+     * Create a composite that contains entry fields specifying editor history preferences.
+     */
+    protected void createEditorHistoryGroup(Composite composite) {
+        Composite groupComposite = new Composite(composite, SWT.LEFT);
+        GridLayout layout = new GridLayout();
+        layout.numColumns = 2;
+        groupComposite.setLayout(layout);
+        GridData gd = new GridData();
+        gd.horizontalAlignment = GridData.FILL;
+        gd.grabExcessHorizontalSpace = true;
+        groupComposite.setLayoutData(gd);
+
+        recentFilesEditor = new IntegerFieldEditor(
+                IPreferenceConstants.RECENT_FILES,
+                WorkbenchMessages.get().WorkbenchPreference_recentFiles, groupComposite);
+
+        recentFilesEditor.setPreferenceStore(WorkbenchPlugin.getDefault()
+                .getPreferenceStore());
+        recentFilesEditor.setPage(this);
+        recentFilesEditor.setTextLimit(Integer.toString(EditorHistory.MAX_SIZE)
+                .length());
+        recentFilesEditor
+				.setErrorMessage(NLS.bind(WorkbenchMessages.get().WorkbenchPreference_recentFilesError,
+						Integer.valueOf(EditorHistory.MAX_SIZE)));
+        recentFilesEditor
+                .setValidateStrategy(StringFieldEditor.VALIDATE_ON_KEY_STROKE);
+        recentFilesEditor.setValidRange(0, EditorHistory.MAX_SIZE);
+        recentFilesEditor.load();
+        recentFilesEditor.setPropertyChangeListener(validityChangeListener);
+    }
+}
+
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/EmptyPreferencePage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/EmptyPreferencePage.java
new file mode 100644
index 0000000..2f5c09b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/EmptyPreferencePage.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2014 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.ui.internal.dialogs;
+
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+
+/*
+ * A page used as a filler for nodes in the preference tree
+ * for which no page is suppplied.
+ */
+public class EmptyPreferencePage extends PreferencePage implements
+        IWorkbenchPreferencePage {
+    @Override
+	protected Control createContents(Composite parent) {
+        return new Composite(parent, SWT.NULL);
+    }
+
+    /**
+     * Hook method to get a page specific preference store. Reimplement this
+     * method if a page don't want to use its parent's preference store.
+     */
+    @Override
+	protected IPreferenceStore doGetPreferenceStore() {
+        return WorkbenchPlugin.getDefault().getPreferenceStore();
+    }
+
+    /**
+     * @see IWorkbenchPreferencePage
+     */
+    @Override
+	public void init(IWorkbench workbench) {
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/EmptyPropertyPage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/EmptyPropertyPage.java
new file mode 100644
index 0000000..36ed42a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/EmptyPropertyPage.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2014 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.ui.internal.dialogs;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.dialogs.PropertyPage;
+
+/*
+ * A page used as a filler for nodes in the property page dialog
+ * for which no page is suppplied.
+ */
+public class EmptyPropertyPage extends PropertyPage {
+    /**
+     * Creates empty composite for this page content.
+     */
+
+    @Override
+	protected Control createContents(Composite parent) {
+        return new Composite(parent, SWT.NULL);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ErrorPreferencePage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ErrorPreferencePage.java
new file mode 100644
index 0000000..028d442
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ErrorPreferencePage.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.internal.dialogs;
+
+import org.eclipse.jface.resource.JFaceColors;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.internal.WorkbenchMessages;
+
+/**
+ * A page that is used to indicate an error in loading a page within the
+ * workbench.
+ *
+ * @since 3.0
+ */
+public class ErrorPreferencePage extends EmptyPreferencePage {
+
+    @Override
+	protected Control createContents(Composite parent) {
+        Text text = new Text(parent, SWT.MULTI | SWT.READ_ONLY | SWT.WRAP);
+        text.setForeground(JFaceColors.getErrorText(text.getDisplay()));
+        text.setBackground(text.getDisplay().getSystemColor(
+                SWT.COLOR_WIDGET_BACKGROUND));
+        text.setText(WorkbenchMessages.get().ErrorPreferencePage_errorMessage);
+        return text;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/EventLoopProgressMonitor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/EventLoopProgressMonitor.java
new file mode 100644
index 0000000..a46e9b5
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/EventLoopProgressMonitor.java
@@ -0,0 +1,196 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.dialogs;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IProgressMonitorWithBlocking;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.ProgressMonitorWrapper;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.internal.ExceptionHandler;
+
+/**
+ * Used to run an event loop whenever progress monitor methods
+ * are invoked.  <p>
+ * This is needed since editor save operations are done in the UI thread.
+ * Although save operations should be written to do the work in the non-UI thread,
+ * this was not done for 1.0, so this was added to keep the UI live
+ * (including allowing the cancel button to work).
+ */
+public class EventLoopProgressMonitor extends ProgressMonitorWrapper implements
+        IProgressMonitorWithBlocking {
+    /**
+     * Threshold for how often the event loop is spun, in ms.
+     */
+    private static int T_THRESH = 100;
+
+    /**
+     * Maximum amount of time to spend processing events, in ms.
+     */
+    private static int T_MAX = 50;
+
+    /**
+     * Last time the event loop was spun.
+     */
+    private long lastTime = System.currentTimeMillis();
+
+    /**
+     * The task name is the name of the current task
+     * in the event loop.
+     */
+    private String taskName;
+
+    /**
+     * Constructs a new instance of the receiver and forwards to monitor.
+     * @param monitor
+     */
+    public EventLoopProgressMonitor(IProgressMonitor monitor) {
+        super(monitor);
+    }
+
+    /**
+     * @see IProgressMonitor#beginTask
+     */
+    @Override
+	public void beginTask(String name, int totalWork) {
+        super.beginTask(name, totalWork);
+        taskName = name;
+        runEventLoop();
+    }
+
+    @Override
+	public void clearBlocked() {
+        Dialog.getBlockedHandler().clearBlocked();
+    }
+
+    /**
+     * @see IProgressMonitor#done
+     */
+    @Override
+	public void done() {
+        super.done();
+        taskName = null;
+        runEventLoop();
+    }
+
+    /**
+     * @see IProgressMonitor#internalWorked
+     */
+    @Override
+	public void internalWorked(double work) {
+        super.internalWorked(work);
+        runEventLoop();
+    }
+
+    /**
+     * @see IProgressMonitor#isCanceled
+     */
+    @Override
+	public boolean isCanceled() {
+        runEventLoop();
+        return super.isCanceled();
+    }
+
+    /**
+     * Runs an event loop.
+     */
+    private void runEventLoop() {
+        // Only run the event loop so often, as it is expensive on some platforms
+        // (namely Motif).
+        long t = System.currentTimeMillis();
+        if (t - lastTime < T_THRESH) {
+            return;
+        }
+        lastTime = t;
+        // Run the event loop.
+        Display disp = Display.getDefault();
+        if (disp == null) {
+            return;
+        }
+
+        //Initialize an exception handler from the window class.
+        ExceptionHandler handler = ExceptionHandler.getInstance();
+
+        for (;;) {
+            try {
+                if (!disp.readAndDispatch()) {
+					break;
+				}
+            } catch (Throwable e) {//Handle the exception the same way as the workbench
+                handler.handleException(e);
+                break;
+            }
+
+            // Only run the event loop for so long.
+            // Otherwise, this would never return if some other thread was
+            // constantly generating events.
+            if (System.currentTimeMillis() - t > T_MAX) {
+                break;
+            }
+        }
+    }
+
+    @Override
+	public void setBlocked(IStatus reason) {
+        Dialog.getBlockedHandler().showBlocked(this, reason, taskName);
+    }
+
+    /**
+     * @see IProgressMonitor#setCanceled
+     */
+    @Override
+	public void setCanceled(boolean b) {
+        super.setCanceled(b);
+        taskName = null;
+        runEventLoop();
+    }
+
+    /**
+     * @see IProgressMonitor#setTaskName
+     */
+    @Override
+	public void setTaskName(String name) {
+        super.setTaskName(name);
+        taskName = name;
+        runEventLoop();
+    }
+
+    /**
+     * @see IProgressMonitor#subTask
+     */
+    @Override
+	public void subTask(String name) {
+        //Be prepared in case the first task was null
+        if (taskName == null) {
+			taskName = name;
+		}
+        super.subTask(name);
+        runEventLoop();
+    }
+
+    /**
+     * @see IProgressMonitor#worked
+     */
+    @Override
+	public void worked(int work) {
+        super.worked(work);
+        runEventLoop();
+    }
+
+    /**
+     * Return the name of the current task.
+     * @return Returns the taskName.
+     */
+    protected String getTaskName() {
+        return taskName;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ExportPage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ExportPage.java
new file mode 100644
index 0000000..dc5679e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ExportPage.java
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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
+ *     Alain Bernard <alain.bernard1224@gmail.com> - Bug 281490
+ *******************************************************************************/
+package org.eclipse.ui.internal.dialogs;
+
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.activities.ITriggerPoint;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.activities.ws.WorkbenchTriggerPoints;
+import org.eclipse.ui.wizards.IWizardCategory;
+
+/**
+ * Wizard page class from which an export wizard is selected.
+ *
+ * @since 3.2
+ *
+ */
+public class ExportPage extends ImportExportPage {
+	private static final String STORE_SELECTED_EXPORT_WIZARD_ID = DIALOG_SETTING_SECTION_NAME
+		+ "STORE_SELECTED_EXPORT_WIZARD_ID"; //$NON-NLS-1$
+
+	private static final String STORE_EXPANDED_EXPORT_CATEGORIES = DIALOG_SETTING_SECTION_NAME
+		+ "STORE_EXPANDED_EXPORT_CATEGORIES";	//$NON-NLS-1$
+
+	CategorizedWizardSelectionTree exportTree;
+
+	/**
+	 * Constructor for export wizard selection page.
+	 *
+	 * @param aWorkbench
+	 * @param currentSelection
+	 */
+	public ExportPage(IWorkbench aWorkbench,
+			IStructuredSelection currentSelection) {
+		super(aWorkbench, currentSelection);
+	}
+
+	@Override
+	protected void initialize() {
+		workbench.getHelpSystem().setHelp(getControl(),
+                IWorkbenchHelpContextIds.EXPORT_WIZARD_SELECTION_WIZARD_PAGE);
+	}
+
+	@Override
+	protected Composite createTreeViewer(Composite parent) {
+		IWizardCategory root = WorkbenchPlugin.getDefault()
+			.getExportWizardRegistry().getRootCategory();
+		exportTree = new CategorizedWizardSelectionTree(
+				root, WorkbenchMessages.get().ExportWizard_selectWizard);
+		Composite exportComp = exportTree.createControl(parent);
+		exportTree.getViewer().addSelectionChangedListener(event -> listSelectionChanged(event.getSelection()));
+		exportTree.getViewer().addDoubleClickListener(event -> treeDoubleClicked(event));
+		setTreeViewer(exportTree.getViewer());
+	    return exportComp;
+	}
+
+	@Override
+	public void saveWidgetValues(){
+    	storeExpandedCategories(STORE_EXPANDED_EXPORT_CATEGORIES, exportTree.getViewer());
+        storeSelectedCategoryAndWizard(STORE_SELECTED_EXPORT_WIZARD_ID, exportTree.getViewer());
+        super.saveWidgetValues();
+	}
+
+	@Override
+	protected void restoreWidgetValues(){
+        IWizardCategory exportRoot = WorkbenchPlugin.getDefault().getExportWizardRegistry().getRootCategory();
+        expandPreviouslyExpandedCategories(STORE_EXPANDED_EXPORT_CATEGORIES, exportRoot, exportTree.getViewer());
+        selectPreviouslySelected(STORE_SELECTED_EXPORT_WIZARD_ID, exportRoot, exportTree.getViewer());
+        super.restoreWidgetValues();
+	}
+
+	@Override
+	protected ITriggerPoint getTriggerPoint(){
+		return getWorkbench().getActivitySupport()
+    		.getTriggerPointManager().getTriggerPoint(WorkbenchTriggerPoints.EXPORT_WIZARDS);
+	}
+
+	@Override
+	protected void updateMessage(){
+		setMessage(WorkbenchMessages.get().ImportExportPage_chooseExportWizard);
+		super.updateMessage();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ExportWizard.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ExportWizard.java
new file mode 100644
index 0000000..ab10868
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ExportWizard.java
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Alain Bernard <alain.bernard1224@gmail.com> - Bug 281490
+ *******************************************************************************/
+package org.eclipse.ui.internal.dialogs;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.IWizardNode;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchWizard;
+import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.activities.ws.WorkbenchTriggerPoints;
+import org.eclipse.ui.internal.registry.WizardsRegistryReader;
+import org.eclipse.ui.model.AdaptableList;
+import org.eclipse.ui.wizards.IWizardCategory;
+
+/**
+ * The export wizard allows the user to choose which nested export wizard to run.
+ * The set of available wizards comes from the export wizard extension point.
+ */
+public class ExportWizard extends Wizard {
+    private IWorkbench theWorkbench;
+
+    private IStructuredSelection selection;
+
+    //the list selection page
+    class SelectionPage extends WorkbenchWizardListSelectionPage {
+        SelectionPage(IWorkbench w, IStructuredSelection ss, AdaptableList e,
+                String s) {
+            super(w, ss, e, s, WorkbenchTriggerPoints.EXPORT_WIZARDS);
+        }
+
+        @Override
+		public void createControl(Composite parent) {
+            super.createControl(parent);
+            workbench.getHelpSystem().setHelp(getControl(),
+                    IWorkbenchHelpContextIds.EXPORT_WIZARD_SELECTION_WIZARD_PAGE);
+        }
+
+        @Override
+		protected IWizardNode createWizardNode(WorkbenchWizardElement element) {
+            return new WorkbenchWizardNode(this, element) {
+                @Override
+				public IWorkbenchWizard createWizard() throws CoreException {
+                    return wizardElement.createWizard();
+                }
+            };
+        }
+    }
+
+    /**
+     * Creates the wizard's pages lazily.
+     */
+    @Override
+	public void addPages() {
+        addPage(new SelectionPage(this.theWorkbench, this.selection,
+                getAvailableExportWizards(), WorkbenchMessages.get().ExportWizard_selectWizard));
+    }
+
+    /**
+     * Returns the export wizards that are available for invocation.
+     */
+    protected AdaptableList getAvailableExportWizards() {
+       	// TODO: exports are still flat - we need to get at the flat list. All
+		// wizards will be in the "other" category.
+		IWizardCategory root = WorkbenchPlugin.getDefault()
+				.getExportWizardRegistry().getRootCategory();
+		WizardCollectionElement otherCategory = (WizardCollectionElement) root
+				.findCategory(new Path(
+						WizardsRegistryReader.UNCATEGORIZED_WIZARD_CATEGORY));
+		if (otherCategory == null) {
+			return new AdaptableList();
+		}
+		return otherCategory.getWizardAdaptableList();
+	}
+
+    /**
+     * Initializes the wizard.
+     *
+     * @param aWorkbench the workbench
+     * @param currentSelection the current selectio
+     */
+    public void init(IWorkbench aWorkbench,
+            IStructuredSelection currentSelection) {
+        this.theWorkbench = aWorkbench;
+        this.selection = currentSelection;
+
+        setWindowTitle(WorkbenchMessages.get().ExportWizard_title);
+        setDefaultPageImageDescriptor(WorkbenchImages
+                .getImageDescriptor(IWorkbenchGraphicConstants.IMG_WIZBAN_EXPORT_WIZ));
+        setNeedsProgressMonitor(true);
+    }
+
+    /**
+     * Subclasses must implement this <code>IWizard</code> method
+     * to perform any special finish processing for their wizard.
+     */
+    @Override
+	public boolean performFinish() {
+        ((SelectionPage) getPages()[0]).saveWidgetValues();
+        return true;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/FileEditorsPreferencePage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/FileEditorsPreferencePage.java
new file mode 100644
index 0000000..977442a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/FileEditorsPreferencePage.java
@@ -0,0 +1,694 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Benjamin Muskalla -	Bug 29633 [EditorMgmt] "Open" menu should
+ *     						have Open With-->Other
+ *******************************************************************************/
+package org.eclipse.ui.internal.dialogs;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.content.IContentType;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.jface.window.Window;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.ui.IEditorDescriptor;
+import org.eclipse.ui.IFileEditorMapping;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.ui.dialogs.EditorSelectionDialog;
+import org.eclipse.ui.dialogs.PreferenceLinkArea;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.registry.EditorDescriptor;
+import org.eclipse.ui.internal.registry.EditorRegistry;
+import org.eclipse.ui.internal.registry.FileEditorMapping;
+import org.eclipse.ui.internal.util.PrefUtil;
+import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer;
+
+/**
+ * The file editors page presents the collection of file names and extensions
+ * for which the user has registered editors. It also lets the user add new
+ * internal or external (program) editors for a given file name and extension.
+ *
+ * The user can add an editor for either a specific file name and extension
+ * (e.g. report.doc), or for all file names of a given extension (e.g. *.doc)
+ *
+ * The set of registered editors is tracked by the EditorRegistery
+ * available from the workbench plugin.
+ */
+public class FileEditorsPreferencePage extends PreferencePage implements
+        IWorkbenchPreferencePage, Listener {
+
+    private static final String DATA_EDITOR = "editor"; //$NON-NLS-1$
+
+    private static final String DATA_FROM_CONTENT_TYPE = "type"; //$NON-NLS-1$
+
+	protected Table resourceTypeTable;
+
+    protected Button addResourceTypeButton;
+
+    protected Button removeResourceTypeButton;
+
+    protected Table editorTable;
+
+    protected Button addEditorButton;
+
+    protected Button removeEditorButton;
+
+    protected Button defaultEditorButton;
+
+    protected Label editorLabel;
+
+    protected IWorkbench workbench;
+
+    protected List imagesToDispose;
+
+    protected Map editorsToImages;
+
+    /**
+     * Add a new resource type to the collection shown in the top of the page.
+     * This is typically called after the extension dialog is shown to the user.
+     *
+     * @param newName the new name
+     * @param newExtension the new extension
+     */
+    public void addResourceType(String newName, String newExtension) {
+        // Either a file name or extension must be provided
+        Assert.isTrue((newName != null && newName.length() != 0)
+                || (newExtension != null && newExtension.length() != 0));
+
+        // Wild card only valid by itself (i.e. rep* is not valid)
+        // And must have an extension
+        int index = newName.indexOf('*');
+        if (index > -1) {
+            Assert.isTrue(index == 0 && newName.length() == 1);
+            Assert.isTrue(newExtension != null && newExtension.length() != 0);
+        }
+
+        // Find the index at which to insert the new entry.
+        String newFilename = (newName + (newExtension == null
+                || newExtension.length() == 0 ? "" : "." + newExtension)).toUpperCase();//$NON-NLS-1$ //$NON-NLS-2$
+        IFileEditorMapping resourceType;
+        TableItem[] items = resourceTypeTable.getItems();
+        boolean found = false;
+        int i = 0;
+
+        while (i < items.length && !found) {
+            resourceType = (IFileEditorMapping) items[i].getData();
+            int result = newFilename.compareToIgnoreCase(resourceType
+                    .getLabel());
+            if (result == 0) {
+                // Same resource type not allowed!
+                MessageDialog
+                        .openInformation(
+                                getControl().getShell(),
+                                WorkbenchMessages.get().FileEditorPreference_existsTitle,
+                                WorkbenchMessages.get().FileEditorPreference_existsMessage);
+                return;
+            }
+
+            if (result < 0) {
+				found = true;
+			} else {
+				i++;
+			}
+        }
+
+        // Create the new type and insert it
+        resourceType = new FileEditorMapping(newName, newExtension);
+        TableItem item = newResourceTableItem(resourceType, i, true);
+        resourceTypeTable.setFocus();
+        resourceTypeTable.showItem(item);
+        fillEditorTable();
+    }
+
+    /**
+     * Creates the page's UI content.
+     */
+    @Override
+	protected Control createContents(Composite parent) {
+        imagesToDispose = new ArrayList();
+        editorsToImages = new HashMap(50);
+
+        // define container & its gridding
+        Composite pageComponent = new Composite(parent, SWT.NULL);
+        GridLayout layout = new GridLayout();
+        layout.numColumns = 2;
+        layout.marginWidth = 0;
+        layout.marginHeight = 0;
+        pageComponent.setLayout(layout);
+        GridData data = new GridData();
+        data.verticalAlignment = GridData.FILL;
+        data.horizontalAlignment = GridData.FILL;
+        pageComponent.setLayoutData(data);
+
+        //layout the contents
+
+        PreferenceLinkArea contentTypeArea = new PreferenceLinkArea(pageComponent, SWT.NONE,
+                "org.eclipse.ui.preferencePages.ContentTypes", WorkbenchMessages.get().FileEditorPreference_contentTypesRelatedLink,//$NON-NLS-1$
+                (IWorkbenchPreferenceContainer) getContainer(),null);
+
+        data = new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL);
+        contentTypeArea.getControl().setLayoutData(data);
+
+        //layout the top table & its buttons
+        Label label = new Label(pageComponent, SWT.LEFT);
+        label.setText(WorkbenchMessages.get().FileEditorPreference_fileTypes);
+        data = new GridData();
+        data.horizontalAlignment = GridData.FILL;
+        data.horizontalSpan = 2;
+        label.setLayoutData(data);
+
+        resourceTypeTable = new Table(pageComponent, SWT.MULTI | SWT.BORDER
+                | SWT.FULL_SELECTION);
+        resourceTypeTable.addListener(SWT.Selection, this);
+        resourceTypeTable.addListener(SWT.DefaultSelection, this);
+        data = new GridData(GridData.FILL_HORIZONTAL);
+
+        int availableRows = DialogUtil.availableRows(pageComponent);
+
+        data.heightHint = resourceTypeTable.getItemHeight()
+                * (availableRows / 8);
+        resourceTypeTable.setLayoutData(data);
+
+        Composite groupComponent = new Composite(pageComponent, SWT.NULL);
+        GridLayout groupLayout = new GridLayout();
+        groupLayout.marginWidth = 0;
+        groupLayout.marginHeight = 0;
+        groupComponent.setLayout(groupLayout);
+        data = new GridData();
+        data.verticalAlignment = GridData.FILL;
+        data.horizontalAlignment = GridData.FILL;
+        groupComponent.setLayoutData(data);
+
+        addResourceTypeButton = new Button(groupComponent, SWT.PUSH);
+        addResourceTypeButton.setText(WorkbenchMessages.get().FileEditorPreference_add);
+        addResourceTypeButton.addListener(SWT.Selection, this);
+        setButtonLayoutData(addResourceTypeButton);
+
+        removeResourceTypeButton = new Button(groupComponent, SWT.PUSH);
+        removeResourceTypeButton.setText(WorkbenchMessages.get().FileEditorPreference_remove);
+        removeResourceTypeButton.addListener(SWT.Selection, this);
+        setButtonLayoutData(removeResourceTypeButton);
+
+        //Spacer
+        label = new Label(pageComponent, SWT.LEFT);
+        data = new GridData();
+        data.horizontalAlignment = GridData.FILL;
+        data.horizontalSpan = 2;
+        label.setLayoutData(data);
+
+        // layout the bottom table & its buttons
+        editorLabel = new Label(pageComponent, SWT.LEFT);
+        editorLabel.setText(WorkbenchMessages.get().FileEditorPreference_associatedEditors);
+        data = new GridData();
+        data.horizontalAlignment = GridData.FILL;
+        data.horizontalSpan = 2;
+        editorLabel.setLayoutData(data);
+
+        editorTable = new Table(pageComponent, SWT.MULTI | SWT.BORDER);
+        editorTable.addListener(SWT.Selection, this);
+        editorTable.addListener(SWT.DefaultSelection, this);
+        data = new GridData(GridData.FILL_BOTH);
+        data.heightHint = editorTable.getItemHeight() * 7;
+        editorTable.setLayoutData(data);
+
+        groupComponent = new Composite(pageComponent, SWT.NULL);
+        groupLayout = new GridLayout();
+        groupLayout.marginWidth = 0;
+        groupLayout.marginHeight = 0;
+        groupComponent.setLayout(groupLayout);
+        data = new GridData();
+        data.verticalAlignment = GridData.FILL;
+        data.horizontalAlignment = GridData.FILL;
+        groupComponent.setLayoutData(data);
+
+        addEditorButton = new Button(groupComponent, SWT.PUSH);
+        addEditorButton.setText(WorkbenchMessages.get().FileEditorPreference_addEditor);
+        addEditorButton.addListener(SWT.Selection, this);
+        addEditorButton.setLayoutData(data);
+        setButtonLayoutData(addEditorButton);
+
+        removeEditorButton = new Button(groupComponent, SWT.PUSH);
+        removeEditorButton.setText(WorkbenchMessages.get().FileEditorPreference_removeEditor);
+        removeEditorButton.addListener(SWT.Selection, this);
+        setButtonLayoutData(removeEditorButton);
+
+        defaultEditorButton = new Button(groupComponent, SWT.PUSH);
+        defaultEditorButton.setText(WorkbenchMessages.get().FileEditorPreference_default);
+        defaultEditorButton.addListener(SWT.Selection, this);
+        setButtonLayoutData(defaultEditorButton);
+
+        fillResourceTypeTable();
+        if (resourceTypeTable.getItemCount() > 0) {
+            resourceTypeTable.setSelection(0);
+        }
+        fillEditorTable();
+        updateEnabledState();
+
+        workbench.getHelpSystem().setHelp(parent,
+				IWorkbenchHelpContextIds.FILE_EDITORS_PREFERENCE_PAGE);
+        applyDialogFont(pageComponent);
+
+        return pageComponent;
+    }
+
+    /**
+     * The preference page is going to be disposed. So deallocate all allocated
+     * SWT resources that aren't disposed automatically by disposing the page
+     * (i.e fonts, cursors, etc). Subclasses should reimplement this method to
+     * release their own allocated SWT resources.
+     */
+    @Override
+	public void dispose() {
+        super.dispose();
+        if (imagesToDispose != null) {
+            for (Iterator e = imagesToDispose.iterator(); e.hasNext();) {
+                ((Image) e.next()).dispose();
+            }
+            imagesToDispose = null;
+        }
+        if (editorsToImages != null) {
+            for (Iterator e = editorsToImages.values().iterator(); e.hasNext();) {
+                ((Image) e.next()).dispose();
+            }
+            editorsToImages = null;
+        }
+    }
+
+    /**
+     * Hook method to get a page specific preference store. Reimplement this
+     * method if a page don't want to use its parent's preference store.
+     */
+    @Override
+	protected IPreferenceStore doGetPreferenceStore() {
+        return WorkbenchPlugin.getDefault().getPreferenceStore();
+    }
+
+    protected void fillEditorTable() {
+        editorTable.removeAll();
+        FileEditorMapping resourceType = getSelectedResourceType();
+        if (resourceType != null) {
+			for (IEditorDescriptor editor : resourceType.getEditors()) {
+                TableItem item = new TableItem(editorTable, SWT.NULL);
+                item.setData(DATA_EDITOR, editor);
+                // Check if it is the default editor
+                String defaultString = null;
+                if (resourceType != null) {
+                    if (resourceType.getDefaultEditor() == editor && resourceType.isDeclaredDefaultEditor(editor)) {
+						defaultString = WorkbenchMessages.get().FileEditorPreference_defaultLabel;
+					}
+                }
+
+                if (defaultString != null) {
+                    item.setText(editor.getLabel() + " " + defaultString); //$NON-NLS-1$
+                } else {
+                    item.setText(editor.getLabel());
+                }
+                item.setImage(getImage(editor));
+            }
+
+            // now add any content type editors
+			EditorRegistry registry = (EditorRegistry) WorkbenchPlugin
+					.getDefault().getEditorRegistry();
+			IContentType[] contentTypes = Platform.getContentTypeManager()
+					.findContentTypesFor(resourceType.getLabel());
+			for (IContentType contentType : contentTypes) {
+				for (IEditorDescriptor editor : registry.getEditorsForContentType(contentType)) {
+					// don't add duplicates
+					TableItem[] items = editorTable.getItems();
+					TableItem foundItem = null;
+					for (TableItem item : items) {
+						if (item.getData(DATA_EDITOR).equals(editor)) {
+							foundItem = item;
+							break;
+						}
+					}
+					if (foundItem == null) {
+						TableItem item = new TableItem(editorTable, SWT.NULL);
+						item.setData(DATA_EDITOR, editor);
+						item.setData(DATA_FROM_CONTENT_TYPE, contentType);
+						setLockedItemText(item, editor.getLabel());
+						item.setImage(getImage(editor));
+					} else { // update the item to reflect its origin
+						foundItem.setData(DATA_FROM_CONTENT_TYPE, contentType);
+						setLockedItemText(foundItem, foundItem.getText());
+					}
+				}
+			}
+
+        }
+    }
+
+    /**
+	 * Set the locked message on the item. Assumes the item has an instance of
+	 * IContentType in the data map.
+	 *
+	 * @param item the item to set
+	 * @param baseLabel the base label
+	 */
+	private void setLockedItemText(TableItem item, String baseLabel) {
+		item.setText(NLS
+				.bind(WorkbenchMessages.get().FileEditorPreference_isLocked,
+						baseLabel, ((IContentType) item
+								.getData(DATA_FROM_CONTENT_TYPE)).getName()));
+	}
+
+    /**
+	 * Place the existing resource types in the table
+	 */
+    protected void fillResourceTypeTable() {
+        // Populate the table with the items
+        IFileEditorMapping[] array = WorkbenchPlugin.getDefault()
+                .getEditorRegistry().getFileEditorMappings();
+        for (int i = 0; i < array.length; i++) {
+            FileEditorMapping mapping = (FileEditorMapping) array[i];
+            mapping = (FileEditorMapping) mapping.clone(); // want a copy
+            newResourceTableItem(mapping, i, false);
+        }
+    }
+
+    /**
+     * Returns the image associated with the given editor.
+     */
+    protected Image getImage(IEditorDescriptor editor) {
+        Image image = (Image) editorsToImages.get(editor);
+        if (image == null) {
+            image = editor.getImageDescriptor().createImage();
+            editorsToImages.put(editor, image);
+        }
+        return image;
+    }
+
+    protected FileEditorMapping getSelectedResourceType() {
+        TableItem[] items = resourceTypeTable.getSelection();
+        if (items.length == 1) {
+            return (FileEditorMapping) items[0].getData();
+        }
+        return null;
+    }
+
+    protected IEditorDescriptor[] getAssociatedEditors() {
+        if (getSelectedResourceType() == null) {
+			return null;
+		}
+        if (editorTable.getItemCount() > 0) {
+            ArrayList editorList = new ArrayList();
+            for (int i = 0; i < editorTable.getItemCount(); i++) {
+				editorList.add(editorTable.getItem(i).getData(DATA_EDITOR));
+			}
+
+            return (IEditorDescriptor[]) editorList
+                    .toArray(new IEditorDescriptor[editorList.size()]);
+        }
+        return null;
+    }
+
+    @Override
+	public void handleEvent(Event event) {
+        if (event.widget == addResourceTypeButton) {
+            promptForResourceType();
+        } else if (event.widget == removeResourceTypeButton) {
+            removeSelectedResourceType();
+        } else if (event.widget == addEditorButton) {
+            promptForEditor();
+        } else if (event.widget == removeEditorButton) {
+            removeSelectedEditor();
+        } else if (event.widget == defaultEditorButton) {
+            setSelectedEditorAsDefault();
+        } else if (event.widget == resourceTypeTable) {
+            fillEditorTable();
+        }
+
+        updateEnabledState();
+
+    }
+
+    /**
+     * @see IWorkbenchPreferencePage
+     */
+    @Override
+	public void init(IWorkbench aWorkbench) {
+        this.workbench = aWorkbench;
+        noDefaultAndApplyButton();
+    }
+
+    /*
+     * Create a new <code>TableItem</code> to represent the resource
+     * type editor description supplied.
+     */
+    protected TableItem newResourceTableItem(IFileEditorMapping mapping,
+            int index, boolean selected) {
+        Image image = mapping.getImageDescriptor().createImage(false);
+        if (image != null) {
+			imagesToDispose.add(image);
+		}
+
+        TableItem item = new TableItem(resourceTypeTable, SWT.NULL, index);
+        if (image != null) {
+            item.setImage(image);
+        }
+        item.setText(mapping.getLabel());
+        item.setData(mapping);
+        if (selected) {
+            resourceTypeTable.setSelection(index);
+        }
+
+        return item;
+    }
+
+    /**
+     * This is a hook for sublcasses to do special things when the ok
+     * button is pressed.
+     * For example reimplement this method if you want to save the
+     * page's data into the preference bundle.
+     */
+    @Override
+	public boolean performOk() {
+        TableItem[] items = resourceTypeTable.getItems();
+        FileEditorMapping[] resourceTypes = new FileEditorMapping[items.length];
+        for (int i = 0; i < items.length; i++) {
+            resourceTypes[i] = (FileEditorMapping) (items[i].getData());
+        }
+        EditorRegistry registry = (EditorRegistry) WorkbenchPlugin.getDefault()
+                .getEditorRegistry(); // cast to allow save to be called
+        registry.setFileEditorMappings(resourceTypes);
+        registry.saveAssociations();
+
+        PrefUtil.savePrefs();
+        return true;
+    }
+
+    /**
+     * Prompt for editor.
+     */
+    public void promptForEditor() {
+        EditorSelectionDialog dialog = new EditorSelectionDialog(getControl()
+                .getShell());
+        dialog.setEditorsToFilter(getAssociatedEditors());
+        dialog
+                .setMessage(NLS.bind(WorkbenchMessages.get().Choose_the_editor_for_file,getSelectedResourceType().getLabel() ));
+        if (dialog.open() == Window.OK) {
+            EditorDescriptor editor = (EditorDescriptor) dialog
+                    .getSelectedEditor();
+            if (editor != null) {
+                int i = editorTable.getItemCount();
+                boolean isEmpty = i < 1;
+                TableItem item = new TableItem(editorTable, SWT.NULL, i);
+                item.setData(DATA_EDITOR, editor);
+                if (isEmpty) {
+					item
+                            .setText(editor.getLabel()
+                                    + " " + WorkbenchMessages.get().FileEditorPreference_defaultLabel); //$NON-NLS-1$
+				} else {
+					item.setText(editor.getLabel());
+				}
+                item.setImage(getImage(editor));
+                editorTable.setSelection(i);
+                editorTable.setFocus();
+                getSelectedResourceType().addEditor(editor);
+				if (isEmpty) {
+					getSelectedResourceType().setDefaultEditor(editor);
+				}
+                updateSelectedResourceType(); //in case of new default
+            }
+        }
+    }
+
+    /**
+     * Prompt for resource type.
+     */
+    public void promptForResourceType() {
+        FileExtensionDialog dialog = new FileExtensionDialog(getControl()
+				.getShell(), WorkbenchMessages.get().FileExtension_shellTitle,
+				IWorkbenchHelpContextIds.FILE_EXTENSION_DIALOG,
+				WorkbenchMessages.get().FileExtension_dialogTitle,
+				WorkbenchMessages.get().FileExtension_fileTypeMessage,
+				WorkbenchMessages.get().FileExtension_fileTypeLabel);
+        if (dialog.open() == Window.OK) {
+            String name = dialog.getName();
+            String extension = dialog.getExtension();
+            addResourceType(name, extension);
+        }
+    }
+
+    /**
+     * Remove the editor from the table
+     */
+    public void removeSelectedEditor() {
+        TableItem[] items = editorTable.getSelection();
+        boolean defaultEditor = editorTable.getSelectionIndex() == 0;
+        if (items.length > 0) {
+        	for (TableItem item : items) {
+                getSelectedResourceType().removeEditor(
+                        (EditorDescriptor) item.getData(DATA_EDITOR));
+                item.dispose();
+        	}
+        }
+        if (defaultEditor && editorTable.getItemCount() > 0) {
+            TableItem item = editorTable.getItem(0);
+            // explicitly set the first editor as the default
+            getSelectedResourceType().setDefaultEditor(
+					(EditorDescriptor) item.getData(DATA_EDITOR));
+			item.setText(((EditorDescriptor) (item.getData(DATA_EDITOR))).getLabel()
+					+ " " + WorkbenchMessages.get().FileEditorPreference_defaultLabel); //$NON-NLS-1$
+			if (!isEditorRemovable(item)) {
+				setLockedItemText(item, item.getText());
+			}
+		}
+
+    }
+
+    /**
+     * Remove the type from the table
+     */
+    public void removeSelectedResourceType() {
+		for (TableItem item : resourceTypeTable.getSelection()) {
+        	item.dispose();
+        }
+        //Clear out the editors too
+        editorTable.removeAll();
+    }
+
+    /**
+     * Add the selected editor to the default list.
+     */
+    public void setSelectedEditorAsDefault() {
+        TableItem[] items = editorTable.getSelection();
+        if (items.length > 0) {
+            // First change the label of the old default
+            TableItem oldDefaultItem = editorTable.getItem(0);
+            oldDefaultItem
+                    .setText(((EditorDescriptor) oldDefaultItem.getData(DATA_EDITOR))
+                            .getLabel());
+            // update the label to reflect the locked state
+            if (!isEditorRemovable(oldDefaultItem)) {
+				setLockedItemText(oldDefaultItem, oldDefaultItem.getText());
+			}
+            // Now set the new default
+            EditorDescriptor editor = (EditorDescriptor) items[0].getData(DATA_EDITOR);
+            getSelectedResourceType().setDefaultEditor(editor);
+            IContentType fromContentType = (IContentType) items[0].getData(DATA_FROM_CONTENT_TYPE);
+            items[0].dispose(); //Table is single selection
+            TableItem item = new TableItem(editorTable, SWT.NULL, 0);
+            item.setData(DATA_EDITOR, editor);
+            if (fromContentType != null) {
+				item.setData(DATA_FROM_CONTENT_TYPE, fromContentType);
+			}
+            item
+                    .setText(editor.getLabel()
+                            + " " + WorkbenchMessages.get().FileEditorPreference_defaultLabel); //$NON-NLS-1$
+            item.setImage(getImage(editor));
+            if (!isEditorRemovable(item)) {
+				setLockedItemText(item, item.getText());
+			}
+			editorTable.setSelection(new TableItem[] { item });
+        }
+    }
+
+    /**
+     * Update the enabled state.
+     */
+    public void updateEnabledState() {
+        //Update enabled state
+    	int selectedResources = resourceTypeTable.getSelectionCount();
+        int selectedEditors = editorTable.getSelectionCount();
+
+        removeResourceTypeButton.setEnabled(selectedResources != 0);
+		editorLabel.setEnabled(selectedResources == 1);
+        addEditorButton.setEnabled(selectedResources == 1);
+		removeEditorButton.setEnabled(areEditorsRemovable());
+        defaultEditorButton.setEnabled(selectedEditors == 1);
+    }
+
+    /**
+	 * Return whether the selected editors are removable. An editor is removable
+	 * if it was not submitted via a content-type binding.
+	 *
+	 * @return whether all the selected editors are removable or not
+	 * @since 3.1
+	 */
+	private boolean areEditorsRemovable() {
+		TableItem[] items = editorTable.getSelection();
+		if (items.length == 0) {
+			return false;
+		}
+
+		for (int i = 0; i < items.length; i++) {
+			if (!isEditorRemovable(items[i])) {
+				return false;
+			}
+		}
+		return true;
+	}
+
+    /**
+	 * Return whether the given editor is removable. An editor is removable
+	 * if it is not submitted via a content-type binding.
+	 *
+	 * @param item the item to test
+	 * @return whether the selected editor is removable
+	 * @since 3.1
+	 */
+    private boolean isEditorRemovable(TableItem item) {
+		IContentType fromContentType = (IContentType) item.getData(DATA_FROM_CONTENT_TYPE);
+		return fromContentType == null;
+	}
+
+	/**
+	 * Update the selected type.
+	 */
+    public void updateSelectedResourceType() {
+        // TableItem item = resourceTypeTable.getSelection()[0]; //Single select
+        //  Image image = ((IFileEditorMapping)item.getData()).getImageDescriptor().getImage();
+        //  imagesToDispose.addElement(image);
+        //  item.setImage(image);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/FileExtensionDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/FileExtensionDialog.java
new file mode 100644
index 0000000..459a263
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/FileExtensionDialog.java
@@ -0,0 +1,249 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.dialogs;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.dialogs.TitleAreaDialog;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.jface.layout.LayoutConstants;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+
+/**
+ * This class is used to prompt the user for a file name & extension.
+ */
+public class FileExtensionDialog extends TitleAreaDialog {
+
+	private static final String DIALOG_SETTINGS_SECTION = "FileExtensionDialogSettings"; //$NON-NLS-1$
+
+    private String filename = ""; //$NON-NLS-1$
+
+    private String initialValue;
+
+    private Text filenameField;
+
+    private Button okButton;
+
+	private String title;
+
+	private String helpContextId;
+
+	private final String headerTitle;
+
+	private final String message2;
+
+	private final String label;
+
+    /**
+     * Constructs a new file extension dialog.
+     * @param parentShell the parent shell
+     */
+    public FileExtensionDialog(Shell parentShell) {
+		this(parentShell, WorkbenchMessages.get().FileExtension_shellTitle,
+				IWorkbenchHelpContextIds.FILE_EXTENSION_DIALOG,
+				WorkbenchMessages.get().FileExtension_dialogTitle,
+				WorkbenchMessages.get().FileExtension_fileTypeMessage,
+				WorkbenchMessages.get().FileExtension_fileTypeLabel);
+		setShellStyle(getShellStyle() | SWT.SHEET);
+	}
+
+    /**
+     * Constructs a new file extension dialog.
+     *
+     * @param parentShell the parent shell
+     * @param title the dialog title
+     * @param helpContextId the help context for this dialog
+     * @param headerTitle the dialog header
+     * @param message the dialog message
+     * @param label the label for the "file type" field
+     * @since 3.4
+     */
+    public FileExtensionDialog(Shell parentShell, String title, String helpContextId, String headerTitle, String message, String label) {
+    	super(parentShell);
+    	this.title = title;
+    	this.helpContextId = helpContextId;
+		this.headerTitle = headerTitle;
+		message2 = message;
+		this.label = label;
+
+		setShellStyle(getShellStyle() | SWT.SHEET);
+    }
+
+    @Override
+	protected void configureShell(Shell shell) {
+        super.configureShell(shell);
+        shell.setText(title);
+        PlatformUI.getWorkbench().getHelpSystem().setHelp(shell, helpContextId);
+    }
+
+
+    @Override
+	protected Control createDialogArea(Composite parent) {
+		Composite parentComposite = (Composite) super.createDialogArea(parent);
+
+		Composite contents = new Composite(parentComposite, SWT.NONE);
+		contents.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+		setTitle(headerTitle);
+		setMessage(message2);
+
+		new Label(contents, SWT.LEFT)
+				.setText(label);
+
+		filenameField = new Text(contents, SWT.SINGLE | SWT.BORDER);
+		if (initialValue != null) {
+			filenameField.setText(initialValue);
+		}
+		filenameField.addModifyListener(event -> {
+			if (event.widget == filenameField) {
+				filename = filenameField.getText().trim();
+				okButton.setEnabled(validateFileType());
+			}
+		});
+		filenameField.setFocus();
+
+		Dialog.applyDialogFont(parentComposite);
+
+		Point defaultMargins = LayoutConstants.getMargins();
+		GridLayoutFactory.fillDefaults().numColumns(2).margins(
+				defaultMargins.x, defaultMargins.y).generateLayout(contents);
+
+		return contents;
+	}
+
+
+    @Override
+	protected void createButtonsForButtonBar(Composite parent) {
+        okButton = createButton(parent, IDialogConstants.OK_ID,
+                IDialogConstants.get().OK_LABEL, true);
+        okButton.setEnabled(false);
+        createButton(parent, IDialogConstants.CANCEL_ID,
+                IDialogConstants.get().CANCEL_LABEL, false);
+    }
+
+    /**
+     * Validate the user input for a file type
+     */
+    private boolean validateFileType() {
+        // We need kernel api to validate the extension or a filename
+
+        // check for empty name and extension
+        if (filename.length() == 0) {
+            setErrorMessage(null);
+            return false;
+        }
+
+        // check for empty extension if there is no name
+        int index = filename.lastIndexOf('.');
+        if (index == filename.length() - 1) {
+            if (index == 0 || (index == 1 && filename.charAt(0) == '*')) {
+                setErrorMessage(WorkbenchMessages.get().FileExtension_extensionEmptyMessage);
+                return false;
+            }
+        }
+
+        // check for characters before *
+        // or no other characters
+        // or next chatacter not '.'
+        // or another *
+        index = filename.indexOf('*');
+        if (index > -1) {
+            if (filename.length() == 1) {
+                setErrorMessage(WorkbenchMessages.get().FileExtension_extensionEmptyMessage);
+                return false;
+            }
+            if (index != 0 || filename.charAt(1) != '.') {
+                setErrorMessage(WorkbenchMessages.get().FileExtension_fileNameInvalidMessage);
+                return false;
+            }
+            if (filename.length() > index && filename.indexOf('*', index + 1) != -1) {
+            	setErrorMessage(WorkbenchMessages.get().FileExtension_fileNameInvalidMessage);
+            	return false;
+            }
+        }
+
+        setErrorMessage(null);
+        return true;
+    }
+
+    /**
+     * Get the extension.
+     *
+     * @return the extension
+     */
+    public String getExtension() {
+        // We need kernel api to validate the extension or a filename
+
+        int index = filename.lastIndexOf('.');
+        if (index == -1) {
+			return ""; //$NON-NLS-1$
+		}
+        if (index == filename.length()) {
+			return ""; //$NON-NLS-1$
+		}
+        return filename.substring(index + 1, filename.length());
+    }
+
+    /**
+     * Get the name.
+     *
+     * @return the name
+     */
+    public String getName() {
+        // We need kernel api to validate the extension or a filename
+
+        int index = filename.lastIndexOf('.');
+        if (index == -1) {
+			return filename;
+		}
+        if (index == 0) {
+			return "*"; //$NON-NLS-1$
+		}
+        return filename.substring(0, index);
+    }
+
+    /**
+	 * Sets the initial value that should be prepopulated in this dialog.
+	 *
+	 * @param initialValue
+	 *            the value to be displayed to the user
+	 * @since 3.4
+	 */
+    public void setInitialValue(String initialValue) {
+    	this.initialValue = initialValue;
+    }
+
+    @Override
+	protected IDialogSettings getDialogBoundsSettings() {
+        IDialogSettings settings = WorkbenchPlugin.getDefault().getDialogSettings();
+        IDialogSettings section = settings.getSection(DIALOG_SETTINGS_SECTION);
+        if (section == null) section = settings.addNewSection(DIALOG_SETTINGS_SECTION);
+        return section;
+    }
+
+    @Override
+	protected boolean isResizable() {
+    	return true;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/FilteredPreferenceDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/FilteredPreferenceDialog.java
new file mode 100644
index 0000000..eb4cb41
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/FilteredPreferenceDialog.java
@@ -0,0 +1,693 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2014, 2015 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
+ *     Oakland Software (Francis Upton) <francisu@ieee.org> - bug 219273
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *     Stefan Xenos <sxenos@google.com> - Bug 466793
+ *******************************************************************************/
+package org.eclipse.ui.internal.dialogs;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.ToolBarManager;
+import org.eclipse.jface.commands.ActionHandler;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.preference.IPreferenceNode;
+import org.eclipse.jface.preference.IPreferencePage;
+import org.eclipse.jface.preference.PreferenceContentProvider;
+import org.eclipse.jface.preference.PreferenceDialog;
+import org.eclipse.jface.preference.PreferenceLabelProvider;
+import org.eclipse.jface.preference.PreferenceManager;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.ScrolledComposite;
+import org.eclipse.swt.events.FocusAdapter;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.Sash;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.ActiveShellExpression;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.activities.WorkbenchActivityHelper;
+import org.eclipse.ui.dialogs.FilteredTree;
+import org.eclipse.ui.dialogs.PatternFilter;
+import org.eclipse.ui.handlers.IHandlerActivation;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.model.IContributionService;
+import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer;
+import org.eclipse.ui.preferences.IWorkingCopyManager;
+import org.eclipse.ui.preferences.WorkingCopyManager;
+import org.eclipse.ui.statushandlers.StatusManager;
+import org.osgi.service.prefs.BackingStoreException;
+
+
+/**
+ * Baseclass for preference dialogs that will show two tabs of preferences -
+ * filtered and unfiltered.
+ *
+ * @since 3.0
+ */
+public abstract class FilteredPreferenceDialog extends PreferenceDialog
+		implements IWorkbenchPreferenceContainer {
+
+	/**
+	 *
+	 */
+	private static final int PAGE_MULTIPLIER = 9;
+
+	/**
+	 *
+	 */
+	private static final int INCREMENT = 10;
+
+	protected class PreferenceFilteredTree extends FilteredTree {
+		/**
+		 * An (optional) additional filter on the TreeViewer.
+		 */
+		private ViewerFilter viewerFilter;
+
+		/**
+		 * Initial title of dialog. This is only used if the additional filter
+		 * provided by the addFilter(ViewerFilter) method is utilized.
+		 */
+		private String cachedTitle;
+
+		/**
+		 * Constructor.
+		 *
+		 * @param parent
+		 *            parent Composite
+		 * @param treeStyle
+		 *            SWT style bits for Tree
+		 * @param filter
+		 *            the PatternFilter to use for the TreeViewer
+		 */
+		PreferenceFilteredTree(Composite parent, int treeStyle,
+				PatternFilter filter) {
+			super(parent, treeStyle, filter, true);
+		}
+
+		/**
+		 * Add an additional, optional filter to the viewer. If the filter text
+		 * is cleared, this filter will be removed from the TreeViewer.
+		 *
+		 * @param filter
+		 */
+		protected void addFilter(ViewerFilter filter) {
+			viewerFilter = filter;
+			getViewer().addFilter(filter);
+
+			if (filterText != null) {
+				setFilterText(WorkbenchMessages.get().FilteredTree_FilterMessage);
+				textChanged();
+			}
+
+			cachedTitle = getShell().getText();
+			getShell().setText(
+					NLS.bind(
+							WorkbenchMessages.get().FilteredTree_FilteredDialogTitle,
+							cachedTitle));
+		}
+
+		@Override
+		protected void updateToolbar(boolean visible) {
+			super.updateToolbar(viewerFilter != null || visible);
+		}
+
+		@Override
+		protected void clearText() {
+			setFilterText(""); //$NON-NLS-1$
+			// remove the filter if text is cleared
+			if (!locked && viewerFilter != null) {
+				getViewer().removeFilter(viewerFilter);
+				viewerFilter = null;
+				getShell().setText(cachedTitle);
+			}
+			textChanged();
+		}
+	}
+
+	protected PreferenceFilteredTree filteredTree;
+
+	private Object pageData;
+
+	IWorkingCopyManager workingCopyManager;
+
+	private Collection updateJobs = new ArrayList();
+
+	/**
+	 * The preference page history.
+	 *
+	 * @since 3.1
+	 */
+	PreferencePageHistory history;
+
+	private Sash sash;
+
+	private IHandlerActivation showViewHandler;
+
+	private boolean locked;
+
+	/**
+	 * Creates a new preference dialog under the control of the given preference
+	 * manager.
+	 *
+	 * @param parentShell
+	 *            the parent shell
+	 * @param manager
+	 *            the preference manager
+	 */
+	public FilteredPreferenceDialog(Shell parentShell, PreferenceManager manager) {
+		super(parentShell, manager);
+		history = new PreferencePageHistory(this);
+	}
+
+	/**
+	 * Differs from super implementation in that if the node is found but should
+	 * be filtered based on a call to
+	 * <code>WorkbenchActivityHelper.filterItem()</code> then
+	 * <code>null</code> is returned.
+	 *
+	 * @see org.eclipse.jface.preference.PreferenceDialog#findNodeMatching(java.lang.String)
+	 */
+	@Override
+	protected IPreferenceNode findNodeMatching(String nodeId) {
+		IPreferenceNode node = super.findNodeMatching(nodeId);
+		if (WorkbenchActivityHelper.filterItem(node)) {
+			return null;
+		}
+		return node;
+	}
+
+	@Override
+	protected TreeViewer createTreeViewer(Composite parent) {
+		int styleBits = SWT.SINGLE;
+		TreeViewer tree;
+		if (!hasAtMostOnePage()) {
+			filteredTree= new PreferenceFilteredTree(parent, styleBits, new PreferencePatternFilter());
+			filteredTree.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
+
+			tree= filteredTree.getViewer();
+		} else
+			tree= new TreeViewer(parent, styleBits);
+
+		setContentAndLabelProviders(tree);
+		tree.setInput(getPreferenceManager());
+
+
+		tree.addFilter(new CapabilityFilter());
+
+		tree.addSelectionChangedListener(event -> handleTreeSelectionChanged(event));
+
+		super.addListeners(tree);
+		return tree;
+	}
+
+	/**
+	 * Return whether or not there are less than two pages.
+	 *
+	 * @return <code>true</code> if there are less than two pages.
+	 */
+	private boolean hasAtMostOnePage() {
+		ITreeContentProvider contentProvider= new PreferenceContentProvider();
+		try {
+			Object[] children= contentProvider.getElements(getPreferenceManager());
+			return children.length == 0 || children.length == 1 && !contentProvider.hasChildren(children[0]);
+		} finally {
+			contentProvider.dispose();
+		}
+	}
+
+	/**
+	 * Set the content and label providers for the treeViewer
+	 *
+	 * @param treeViewer
+	 */
+	protected void setContentAndLabelProviders(TreeViewer treeViewer) {
+		if (hasAtMostOnePage()) {
+			treeViewer.setLabelProvider(new PreferenceLabelProvider());
+		} else {
+			treeViewer.setLabelProvider(new PreferenceBoldLabelProvider(filteredTree));
+		}
+		IContributionService cs = PlatformUI
+				.getWorkbench().getActiveWorkbenchWindow().getService(
+						IContributionService.class);
+		treeViewer.setComparator(cs.getComparatorFor(getContributionType()));
+		treeViewer.setContentProvider(new PreferenceContentProvider());
+	}
+
+	/**
+	 * Return the contributionType (used by the IContributionService).
+	 *
+	 * Override this with a more specific contribution type as required.
+	 *
+	 * @return a string, the contributionType
+	 */
+	protected String getContributionType() {
+		return IContributionService.TYPE_PREFERENCE;
+	}
+
+	/**
+	 * A selection has been made in the tree.
+	 *
+	 * @param event
+	 *            SelectionChangedEvent
+	 */
+	protected void handleTreeSelectionChanged(SelectionChangedEvent event) {
+		// Do nothing by default
+	}
+
+	@Override
+	protected Control createTreeAreaContents(Composite parent) {
+		Composite leftArea = new Composite(parent, SWT.NONE);
+		leftArea.setBackground(parent.getDisplay().getSystemColor(
+				SWT.COLOR_LIST_BACKGROUND));
+		leftArea.setFont(parent.getFont());
+		GridLayout leftLayout = new GridLayout();
+		leftLayout.numColumns = 1;
+		leftLayout.marginHeight = 0;
+		leftLayout.marginTop = IDialogConstants.VERTICAL_MARGIN;
+		leftLayout.marginWidth = IDialogConstants.HORIZONTAL_MARGIN;
+		leftLayout.horizontalSpacing = 0;
+		leftLayout.verticalSpacing = 0;
+		leftArea.setLayout(leftLayout);
+
+		// Build the tree an put it into the composite.
+		TreeViewer viewer = createTreeViewer(leftArea);
+		setTreeViewer(viewer);
+
+		updateTreeFont(JFaceResources.getDialogFont());
+		GridData viewerData = new GridData(GridData.FILL_BOTH
+				| GridData.GRAB_VERTICAL);
+		viewer.getControl().getParent().setLayoutData(viewerData);
+
+		layoutTreeAreaControl(leftArea);
+
+		return leftArea;
+	}
+
+	/**
+	 * Show only the supplied ids.
+	 *
+	 * @param filteredIds
+	 */
+	public void showOnly(String[] filteredIds) {
+		if (!hasAtMostOnePage()) {
+			filteredTree.addFilter(new PreferenceNodeFilter(filteredIds));
+		}
+	}
+
+	/**
+	 * Set the data to be applied to a page after it is created.
+	 *
+	 * @param pageData
+	 *            Object
+	 */
+	public void setPageData(Object pageData) {
+		this.pageData = pageData;
+	}
+
+	@Override
+	protected void createPage(IPreferenceNode node) {
+
+		super.createPage(node);
+		if (this.pageData == null) {
+			return;
+		}
+		// Apply the data if it has been set.
+		IPreferencePage page = node.getPage();
+		if (page instanceof PreferencePage) {
+			((PreferencePage) page).applyData(this.pageData);
+		}
+
+	}
+
+	@Override
+	public IPreferencePage getCurrentPage() {
+		return super.getCurrentPage();
+	}
+
+	@Override
+	public boolean openPage(String pageId, Object data) {
+		setPageData(data);
+		setCurrentPageId(pageId);
+		IPreferencePage page = getCurrentPage();
+		if (page instanceof PreferencePage) {
+			((PreferencePage) page).applyData(data);
+		}
+		return true;
+	}
+
+	/**
+	 * Selects the current page based on the given preference page identifier.
+	 * If no node can be found, then nothing will change.
+	 *
+	 * @param preferencePageId
+	 *            The preference page identifier to select; should not be
+	 *            <code>null</code>.
+	 */
+	public final void setCurrentPageId(final String preferencePageId) {
+		final IPreferenceNode node = findNodeMatching(preferencePageId);
+		if (node != null) {
+			getTreeViewer().setSelection(new StructuredSelection(node));
+			showPage(node);
+		}
+	}
+
+	@Override
+	public IWorkingCopyManager getWorkingCopyManager() {
+		if (workingCopyManager == null) {
+			workingCopyManager = new WorkingCopyManager();
+		}
+		return workingCopyManager;
+	}
+
+	@Override
+	protected void okPressed() {
+		super.okPressed();
+
+		if (getReturnCode() == FAILED) {
+			return;
+		}
+
+		if (workingCopyManager != null) {
+			try {
+				workingCopyManager.applyChanges();
+			} catch (BackingStoreException e) {
+				String msg = e.getMessage();
+				if (msg == null) {
+					msg = WorkbenchMessages.get().FilteredPreferenceDialog_PreferenceSaveFailed;
+				}
+				StatusUtil
+						.handleStatus(
+								WorkbenchMessages.get().PreferencesExportDialog_ErrorDialogTitle
+										+ ": " + msg, e, StatusManager.SHOW, //$NON-NLS-1$
+								getShell());
+			}
+		}
+
+		// Run the update jobs
+		Iterator updateIterator = updateJobs.iterator();
+		while (updateIterator.hasNext()) {
+			((Job) updateIterator.next()).schedule();
+		}
+	}
+
+	@Override
+	public void registerUpdateJob(Job job) {
+		updateJobs.add(job);
+	}
+
+	/**
+	 * Get the toolbar for the container
+	 *
+	 * @return Control
+	 */
+	Control getContainerToolBar(Composite composite) {
+
+		final ToolBarManager historyManager = new ToolBarManager(SWT.HORIZONTAL
+				| SWT.FLAT);
+		historyManager.createControl(composite);
+
+		history.createHistoryControls(historyManager.getControl(),
+				historyManager);
+
+		Action popupMenuAction = new Action() {
+			@Override
+			public ImageDescriptor getImageDescriptor() {
+				return WorkbenchImages
+						.getImageDescriptor(IWorkbenchGraphicConstants.IMG_LCL_VIEW_MENU);
+			}
+
+			@Override
+			public void run() {
+				MenuManager manager = new MenuManager();
+				manager.add(new Action() {
+					@Override
+					public void run() {
+
+						sash.addFocusListener(new FocusAdapter() {
+							@Override
+							public void focusGained(FocusEvent e) {
+								sash.setBackground(sash.getDisplay()
+										.getSystemColor(
+												SWT.COLOR_LIST_SELECTION));
+							}
+
+							@Override
+							public void focusLost(FocusEvent e) {
+								sash.setBackground(sash.getDisplay()
+										.getSystemColor(SWT.COLOR_LIST_BACKGROUND));
+							}
+						});
+						sash.setFocus();
+					}
+
+					@Override
+					public String getText() {
+						return WorkbenchMessages.get().FilteredPreferenceDialog_Resize;
+					}
+				});
+				manager.add(new Action() {
+					@Override
+					public void run() {
+						activeKeyScrolling();
+					}
+
+					@Override
+					public String getText() {
+						return WorkbenchMessages.get().FilteredPreferenceDialog_Key_Scrolling;
+					}
+				});
+				Menu menu = manager.createContextMenu(getShell());
+				Rectangle bounds = historyManager.getControl().getBounds();
+				Point topLeft = new Point(bounds.x + bounds.width, bounds.y + bounds.height);
+				topLeft = historyManager.getControl().toDisplay(topLeft);
+				menu.setLocation(topLeft.x, topLeft.y);
+				menu.setVisible(true);
+			}
+		};
+		popupMenuAction.setToolTipText(WorkbenchMessages.get().FilteredPreferenceDialog_FilterToolTip);
+		historyManager.add(popupMenuAction);
+		IHandlerService service = PlatformUI.getWorkbench()
+				.getService(IHandlerService.class);
+		showViewHandler = service
+				.activateHandler(
+						IWorkbenchCommandConstants.WINDOW_SHOW_VIEW_MENU,
+						new ActionHandler(popupMenuAction),
+						new ActiveShellExpression(getShell()));
+
+		historyManager.update(false);
+
+		return historyManager.getControl();
+	}
+
+	private boolean keyScrollingEnabled = false;
+	private Listener keyScrollingFilter = null;
+
+	void activeKeyScrolling() {
+		if (keyScrollingFilter == null) {
+			Composite pageParent = getPageContainer().getParent();
+			if (!(pageParent instanceof ScrolledComposite)) {
+				return;
+			}
+			final ScrolledComposite sc = (ScrolledComposite) pageParent;
+			keyScrollingFilter = event -> {
+				if (!keyScrollingEnabled || sc.isDisposed()) {
+					return;
+				}
+				switch (event.keyCode) {
+				case SWT.ARROW_DOWN:
+					sc.setOrigin(sc.getOrigin().x, sc.getOrigin().y
+							+ INCREMENT);
+					break;
+				case SWT.ARROW_UP:
+					sc.setOrigin(sc.getOrigin().x, sc.getOrigin().y
+							- INCREMENT);
+					break;
+				case SWT.ARROW_LEFT:
+					sc.setOrigin(sc.getOrigin().x - INCREMENT, sc
+							.getOrigin().y);
+					break;
+				case SWT.ARROW_RIGHT:
+					sc.setOrigin(sc.getOrigin().x + INCREMENT, sc
+							.getOrigin().y);
+					break;
+				case SWT.PAGE_DOWN:
+					sc.setOrigin(sc.getOrigin().x, sc.getOrigin().y
+							+ PAGE_MULTIPLIER * INCREMENT);
+					break;
+				case SWT.PAGE_UP:
+					sc.setOrigin(sc.getOrigin().x, sc.getOrigin().y
+							- PAGE_MULTIPLIER * INCREMENT);
+					break;
+				case SWT.HOME:
+					sc.setOrigin(0, 0);
+					break;
+				case SWT.END:
+					sc.setOrigin(0, sc.getSize().y);
+					break;
+				default:
+					keyScrollingEnabled = false;
+				}
+				event.type = SWT.None;
+				event.doit = false;
+			};
+			Display display = PlatformUI.getWorkbench().getDisplay();
+			display.addFilter(SWT.KeyDown, keyScrollingFilter);
+			display.addFilter(SWT.Traverse, keyScrollingFilter);
+			sc.addDisposeListener(e -> removeKeyScrolling());
+		}
+		keyScrollingEnabled = true;
+	}
+
+	void removeKeyScrolling() {
+		if (keyScrollingFilter != null) {
+			keyScrollingEnabled = false;
+			Display display = PlatformUI.getWorkbench().getDisplay();
+			if (display != null) {
+				display.removeFilter(SWT.KeyDown, keyScrollingFilter);
+				display.removeFilter(SWT.Traverse, keyScrollingFilter);
+			}
+			keyScrollingFilter = null;
+		}
+	}
+
+	@Override
+	protected boolean showPage(IPreferenceNode node) {
+		final boolean success = super.showPage(node);
+		if (success) {
+			history.addHistoryEntry(new PreferenceHistoryEntry(node.getId(),
+					node.getLabelText(), null));
+		}
+		return success;
+	}
+
+	@Override
+	public boolean close() {
+		if (showViewHandler != null) {
+			IHandlerService service = PlatformUI
+					.getWorkbench().getService(IHandlerService.class);
+			service.deactivateHandler(showViewHandler);
+			showViewHandler.getHandler().dispose();
+			showViewHandler = null;
+		}
+		removeKeyScrolling();
+		history.dispose();
+		return super.close();
+	}
+
+	@Override
+	protected Composite createTitleArea(Composite parent) {
+
+		GridLayout parentLayout = (GridLayout) parent.getLayout();
+		parentLayout.numColumns = 2;
+		parentLayout.marginHeight = 0;
+		parentLayout.marginTop = IDialogConstants.VERTICAL_MARGIN;
+		parent.setLayout(parentLayout);
+
+		Composite titleComposite = super.createTitleArea(parent);
+
+		Composite toolbarArea = new Composite(parent, SWT.NONE);
+		GridLayout toolbarLayout = new GridLayout();
+		toolbarLayout.marginHeight = 0;
+		toolbarLayout.verticalSpacing = 0;
+		toolbarArea.setLayout(toolbarLayout);
+		toolbarArea.setLayoutData(new GridData(SWT.END, SWT.FILL, false, true));
+		Control topBar = getContainerToolBar(toolbarArea);
+		topBar.setLayoutData(new GridData(SWT.END, SWT.FILL, false, true));
+
+		return titleComposite;
+	}
+
+	@Override
+	protected void selectSavedItem() {
+		getTreeViewer().setInput(getPreferenceManager());
+		super.selectSavedItem();
+		if (getTreeViewer().getTree().getItemCount() > 1) {
+			// unfortunately super will force focus to the list but we want the
+			// type ahead combo to get it.
+			Text filterText = filteredTree.getFilterControl();
+			if (filterText != null) {
+				filterText.setFocus();
+			}
+		}
+	}
+
+	@Override
+	protected void updateTreeFont(Font dialogFont) {
+		if (hasAtMostOnePage()) {
+			Composite composite= getTreeViewer().getTree();
+			applyDialogFont(composite, dialogFont);
+			composite.layout(true);
+		} else {
+			applyDialogFont(filteredTree, dialogFont);
+			filteredTree.layout(true);
+		}
+	}
+
+	/**
+	 * Apply the dialog font to the given control and it's children.
+	 *
+	 * @param control the control
+	 * @param dialogFont the dialog font
+	 */
+	private void applyDialogFont(Control control, Font dialogFont) {
+		control.setFont(dialogFont);
+		if (control instanceof Composite) {
+			Control[] children = ((Composite) control).getChildren();
+			for (Control element : children) {
+				applyDialogFont(element, dialogFont);
+			}
+		}
+	}
+
+	@Override
+	protected Sash createSash(Composite composite, Control rightControl) {
+		sash = super.createSash(composite, rightControl);
+		return sash;
+	}
+
+	/**
+	 * <code>true</code> if upon clearing the filter field, the list of pages
+	 * should not be reset to all property or preference pages.
+	 *
+	 * @param b
+	 */
+	public void setLocked(boolean b) {
+		this.locked = b;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/IPropertyPageContributor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/IPropertyPageContributor.java
new file mode 100644
index 0000000..a497023
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/IPropertyPageContributor.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Oakland Software (Francis Upton) <francisu@ieee.org> - bug 223808
+ *******************************************************************************/
+package org.eclipse.ui.internal.dialogs;
+
+import org.eclipse.jface.preference.PreferenceNode;
+import org.eclipse.ui.internal.IObjectContributor;
+
+/**
+ * Implement this interface in order to register property
+ * pages for a given object. During property dialog building
+ * sequence, all property page contributors for a given object
+ * are given a chance to add their pages.
+ */
+public interface IPropertyPageContributor extends IObjectContributor {
+    /**
+     * Implement this method to add an instance of PropertyPage class to the
+     * property page manager.
+     * @param manager the contributor manager onto which to contribute the
+     * property page.
+     * @param object the type for which page should be contributed.
+     * @return true the page that was added, <code>null</code> if no page was added.
+     */
+    public PreferenceNode contributePropertyPage(PropertyPageManager manager,
+            Object object);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ImportExportPage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ImportExportPage.java
new file mode 100644
index 0000000..e9069e3
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ImportExportPage.java
@@ -0,0 +1,465 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.dialogs;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.wizard.IWizardNode;
+import org.eclipse.jface.wizard.IWizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchWizard;
+import org.eclipse.ui.activities.ITriggerPoint;
+import org.eclipse.ui.activities.WorkbenchActivityHelper;
+import org.eclipse.ui.dialogs.FilteredTree;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.model.AdaptableList;
+import org.eclipse.ui.model.WorkbenchLabelProvider;
+import org.eclipse.ui.wizards.IWizardCategory;
+import org.eclipse.ui.wizards.IWizardDescriptor;
+
+/**
+ * Abstract wizard page class from which an import or export wizard can be chosen.
+ *
+ * @since 3.2
+ *
+ */
+public abstract class ImportExportPage extends WorkbenchWizardSelectionPage{
+    protected static final String DIALOG_SETTING_SECTION_NAME = "ImportExportPage."; //$NON-NLS-1$
+
+    // tree viewer of wizard selections
+    private TreeViewer treeViewer;
+
+	/*
+	 * Class to create a control that shows a categorized tree of wizard types.
+	 */
+	protected class CategorizedWizardSelectionTree {
+		private final static int SIZING_LISTS_HEIGHT = 200;
+
+		private IWizardCategory wizardCategories;
+		private String message;
+		private TreeViewer viewer;
+
+		/**
+		 * Constructor for CategorizedWizardSelectionTree
+		 *
+		 * @param categories root wizard category for the wizard type
+		 * @param msg message describing what the user should choose from the tree.
+		 */
+		protected CategorizedWizardSelectionTree(IWizardCategory categories, String msg){
+			this.wizardCategories = categories;
+			this.message = msg;
+		}
+
+		/**
+		 * Create the tree viewer and a message describing what the user should choose
+		 * from the tree.
+		 *
+		 * @param parent Composite on which the tree viewer is to be created
+		 * @return Comoposite with all widgets
+		 */
+		protected Composite createControl(Composite parent){
+	        Font font = parent.getFont();
+
+	        // create composite for page.
+	        Composite outerContainer = new Composite(parent, SWT.NONE);
+	        outerContainer.setLayout(new GridLayout());
+	        outerContainer.setLayoutData(new GridData(GridData.FILL_BOTH));
+	        outerContainer.setFont(font);
+
+	        Label messageLabel = new Label(outerContainer, SWT.NONE);
+	        if (message != null) {
+				messageLabel.setText(message);
+			}
+	        messageLabel.setFont(font);
+
+	        createFilteredTree(outerContainer);
+	        layoutTopControl(viewer.getControl());
+
+	        return outerContainer;
+		}
+
+		/**
+		 * Create the categorized tree viewer.
+		 *
+		 * @param parent
+		 */
+		private void createFilteredTree(Composite parent){
+			// Create a FilteredTree for the categories and wizards
+			FilteredTree filteredTree = new FilteredTree(parent, SWT.SINGLE | SWT.H_SCROLL
+	                | SWT.V_SCROLL | SWT.BORDER, new WizardPatternFilter(), true);
+	        viewer = filteredTree.getViewer();
+	        filteredTree.setFont(parent.getFont());
+			filteredTree.setQuickSelectionMode(true);
+
+	        viewer.setContentProvider(new WizardContentProvider());
+			viewer.setLabelProvider(new WorkbenchLabelProvider());
+	        viewer.setComparator(DataTransferWizardCollectionComparator.INSTANCE);
+
+	        ArrayList inputArray = new ArrayList();
+	        boolean expandTop = false;
+
+	        if (wizardCategories != null) {
+	            if (wizardCategories.getParent() == null) {
+					for (IWizardCategory wizardCategory : wizardCategories.getCategories()) {
+						inputArray.add(wizardCategory);
+	                }
+	            } else {
+	                expandTop = true;
+	                inputArray.add(wizardCategories);
+	            }
+	        }
+
+	        // ensure the category is expanded.  If there is a remembered expansion it will be set later.
+	        if (expandTop) {
+				viewer.setAutoExpandLevel(2);
+			}
+
+	        AdaptableList input = new AdaptableList(inputArray);
+
+	        // filter wizard list according to capabilities that are enabled
+	        viewer.addFilter(new WizardActivityFilter());
+
+	        viewer.setInput(input);
+		}
+
+		/**
+		 *
+		 * @return the categorized tree viewer
+		 */
+		protected TreeViewer getViewer(){
+			return viewer;
+		}
+
+		/**
+		 * Layout for the given control.
+		 *
+		 * @param control
+		 */
+	    private void layoutTopControl(Control control) {
+	        GridData data = new GridData(GridData.FILL_BOTH);
+
+	        int availableRows = DialogUtil.availableRows(control.getParent());
+
+	        //Only give a height hint if the dialog is going to be too small
+	        if (availableRows > 50) {
+	            data.heightHint = SIZING_LISTS_HEIGHT;
+	        } else {
+	            data.heightHint = availableRows * 3;
+	        }
+
+	        control.setLayoutData(data);
+	    }
+	}
+
+	/**
+	 * Constructor for import/export wizard page.
+	 *
+	 * @param aWorkbench current workbench
+	 * @param currentSelection current selection
+	 */
+	protected ImportExportPage(IWorkbench aWorkbench, IStructuredSelection currentSelection){
+		super("importExportPage", aWorkbench, currentSelection, null, null);	//$NON-NLS-1$
+		setTitle(WorkbenchMessages.get().Select);
+	}
+
+	@Override
+	public void createControl(Composite parent) {
+	    Font font = parent.getFont();
+
+	    // create composite for page.
+	    Composite outerContainer = new Composite(parent, SWT.NONE);
+	    outerContainer.setLayout(new GridLayout());
+	    outerContainer.setLayoutData(new GridData(GridData.FILL_BOTH));
+	    outerContainer.setFont(font);
+
+	    Composite comp = createTreeViewer(outerContainer);
+
+		Dialog.applyDialogFont(comp);
+
+	    restoreWidgetValues();
+
+	    setControl(outerContainer);
+
+	   initialize();
+	}
+
+	/**
+	 * Create the tree viewer from which a wizard is selected.
+	 */
+    protected abstract Composite createTreeViewer(Composite parent);
+
+    /**
+     * Method to call when an item in one of the lists is double-clicked.
+     * Shows the first page of the selected wizard or expands a collapsed
+     * tree.
+     * @param event
+     */
+    protected void treeDoubleClicked(DoubleClickEvent event){
+    	ISelection selection = event.getViewer().getSelection();
+	    IStructuredSelection ss = (IStructuredSelection) selection;
+    	listSelectionChanged(ss);
+
+		Object element = ss.getFirstElement();
+		TreeViewer v = (TreeViewer)event.getViewer();
+		if (v.isExpandable(element)) {
+		    v.setExpandedState(element, !v.getExpandedState(element));
+		} else if (element instanceof WorkbenchWizardElement) {
+			if (canFlipToNextPage()) {
+				getContainer().showPage(getNextPage());
+				return;
+			}
+		}
+        getContainer().showPage(getNextPage());
+    }
+
+    /*
+     * Update the wizard's message based on the given (selected) wizard element.
+     */
+    private void updateSelectedNode(WorkbenchWizardElement wizardElement){
+        setErrorMessage(null);
+        if (wizardElement == null) {
+        	updateMessage();
+            setSelectedNode(null);
+            return;
+        }
+
+        setSelectedNode(createWizardNode(wizardElement));
+        setMessage(wizardElement.getDescription());
+    }
+
+    /*
+     * Update the wizard's message based on the currently selected tab
+     * and the selected wizard on that tab.
+     */
+    protected void updateMessage(){
+    	TreeViewer viewer = getTreeViewer();
+    	if (viewer != null){
+    		ISelection selection = viewer.getSelection();
+            IStructuredSelection ss = (IStructuredSelection) selection;
+            Object sel = ss.getFirstElement();
+            if (sel instanceof WorkbenchWizardElement){
+               	updateSelectedNode((WorkbenchWizardElement)sel);
+            }
+            else{
+            	setSelectedNode(null);
+            }
+    	} else {
+			setMessage(null);
+		}
+    }
+
+    /*
+     * Method to call whenever the selection in one of the lists has changed.
+     * Updates the wizard's message to relect the description of the currently
+     * selected wizard.
+     */
+    protected void listSelectionChanged(ISelection selection){
+        setErrorMessage(null);
+        IStructuredSelection ss = (IStructuredSelection) selection;
+        Object sel = ss.getFirstElement();
+        if (sel instanceof WorkbenchWizardElement){
+	        WorkbenchWizardElement currentWizardSelection = (WorkbenchWizardElement) sel;
+	        updateSelectedNode(currentWizardSelection);
+        } else {
+			updateSelectedNode(null);
+		}
+    }
+
+    /*
+     * Create a wizard node given a wizard's descriptor.
+     */
+	private IWizardNode createWizardNode(IWizardDescriptor element) {
+        return new WorkbenchWizardNode(this, element) {
+            @Override
+			public IWorkbenchWizard createWizard() throws CoreException {
+                return wizardElement.createWizard();
+            }
+        };
+    }
+
+    /**
+     * Uses the dialog store to restore widget values to the values that they
+     * held last time this wizard was used to completion.
+     */
+    protected void restoreWidgetValues() {
+        updateMessage();
+    }
+
+    /**
+     * Expands the wizard categories in this page's category viewer that were
+     * expanded last time this page was used. If a category that was previously
+     * expanded no longer exists then it is ignored.
+     */
+    protected void expandPreviouslyExpandedCategories(String setting, IWizardCategory wizardCategories, TreeViewer viewer) {
+        String[] expandedCategoryPaths =  getDialogSettings()
+                .getArray(setting);
+        if (expandedCategoryPaths == null || expandedCategoryPaths.length == 0) {
+			return;
+		}
+
+        List categoriesToExpand = new ArrayList(expandedCategoryPaths.length);
+
+        if (wizardCategories != null) {
+            for (String expandedCategoryPath : expandedCategoryPaths) {
+                IWizardCategory category = wizardCategories
+                        .findCategory(new Path(expandedCategoryPath));
+                if (category != null) {
+					categoriesToExpand.add(category);
+				}
+            }
+        }
+
+        if (!categoriesToExpand.isEmpty()) {
+			viewer.setExpandedElements(categoriesToExpand.toArray());
+		}
+
+    }
+
+    /**
+     * Selects the wizard category and wizard in this page that were selected
+     * last time this page was used. If a category or wizard that was
+     * previously selected no longer exists then it is ignored.
+     */
+    protected void selectPreviouslySelected(String setting, IWizardCategory wizardCategories, final TreeViewer viewer) {
+        String selectedId = getDialogSettings().get(setting);
+        if (selectedId == null) {
+			return;
+		}
+
+        if (wizardCategories == null) {
+			return;
+		}
+
+        Object selected = wizardCategories.findCategory(new Path(
+                selectedId));
+
+        if (selected == null) {
+            selected = wizardCategories.findWizard(selectedId);
+
+            if (selected == null) {
+				// if we cant find either a category or a wizard, abort.
+                return;
+			}
+        }
+
+        viewer.setSelection(new StructuredSelection(selected), true);
+    }
+
+    /**
+     * Stores the collection of currently-expanded categories in this page's
+     * dialog store, in order to recreate this page's state in the next
+     * instance of this page.
+     */
+    protected void storeExpandedCategories(String setting, TreeViewer viewer) {
+        Object[] expandedElements = viewer.getExpandedElements();
+        List expandedElementPaths = new ArrayList(expandedElements.length);
+        for (Object expandedElement : expandedElements) {
+            if (expandedElement instanceof IWizardCategory) {
+				expandedElementPaths
+                        .add(((IWizardCategory) expandedElement)
+                                .getPath().toString());
+			}
+        }
+        getDialogSettings().put(setting,
+                (String[]) expandedElementPaths
+                        .toArray(new String[expandedElementPaths.size()]));
+    }
+
+    /**
+     * Stores the currently-selected element in this page's dialog store, in
+     * order to recreate this page's state in the next instance of this page.
+     */
+    protected void storeSelectedCategoryAndWizard(String setting, TreeViewer viewer) {
+        Object selected = ((IStructuredSelection) viewer
+                .getSelection()).getFirstElement();
+
+        if (selected != null) {
+            if (selected instanceof IWizardCategory) {
+				getDialogSettings().put(setting,
+                        ((IWizardCategory) selected).getPath()
+                                .toString());
+			} else {
+				// else its a wizard
+            	getDialogSettings().put(setting,
+                        ((IWizardDescriptor) selected).getId());
+			}
+        }
+    }
+
+    /**
+     * When Finish is pressed, write widget values to the dialog store so
+     * that they will persist into the next invocation of the wizard page.
+     *
+     */
+    public void saveWidgetValues(){
+    	// do nothing by default - subclasses should override
+    }
+
+    @Override
+	public IWizardPage getNextPage() {
+    	ITriggerPoint triggerPoint = getTriggerPoint();
+
+        if (triggerPoint == null || WorkbenchActivityHelper.allowUseOf(triggerPoint, getSelectedNode())) {
+			return super.getNextPage();
+		}
+        return null;
+    }
+
+    /**
+     * Get the trigger point for the wizard type, if one exists.
+     *
+     * @return the wizard's trigger point
+     */
+    protected ITriggerPoint getTriggerPoint(){
+    	return null;	// default implementation
+    }
+
+    /**
+     * Set the tree viewer that is used for this wizard selection page.
+     *
+     * @param viewer
+     */
+    protected void setTreeViewer(TreeViewer viewer){
+    	treeViewer = viewer;
+    }
+
+    /**
+     * Get the tree viewer that is used for this wizard selection page.
+     *
+     * @return tree viewer used for this wizard's selection page
+     */
+    protected TreeViewer getTreeViewer(){
+    	return treeViewer;
+    }
+
+    /**
+     * Perform any initialization of the wizard page that needs to be done
+     * after widgets are created and main control is set.
+     */
+    protected void initialize(){
+    	// do nothing by default
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ImportExportWizard.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ImportExportWizard.java
new file mode 100644
index 0000000..68e252a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ImportExportWizard.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.dialogs;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.internal.WorkbenchMessages;
+
+/**
+ * The import/export wizard allows users to choose whether to
+ * show the import wizard or the export wizard.
+ *
+ * @since 3.2
+ *
+ */
+public class ImportExportWizard extends Wizard {
+	/**
+	 * Constant used to to specify to the import/export wizard
+	 * which page should initially be shown.
+	 */
+	public static final String IMPORT = "import";	//$NON-NLS-1$
+	/**
+	 * Constant used to to specify to the import/export wizard
+	 * which page should initially be shown.
+	 */
+	public static final String EXPORT = "export";	//$NON-NLS-1$
+
+    private IWorkbench workbench;
+    private IStructuredSelection selection;
+    private ImportExportPage importExportPage;
+    private String page = null;
+
+    /**
+     * Create an import/export wizard and show the page
+     * with the given id.
+     *
+     * @param pageId
+     */
+    public ImportExportWizard(String pageId){
+    	page = pageId;
+    }
+
+    /**
+     * Subclasses must implement this <code>IWizard</code> method
+     * to perform any special finish processing for their wizard.
+     */
+    @Override
+	public boolean performFinish() {
+    	importExportPage.saveWidgetValues();
+        return true;
+    }
+
+    /**
+     * Creates the wizard's pages lazily.
+     */
+    @Override
+	public void addPages() {
+    	if (page.equals(IMPORT)) {
+			importExportPage = new ImportPage(this.workbench, this.selection);
+		} else if (page.equals(EXPORT)) {
+			importExportPage = new ExportPage(this.workbench, this.selection);
+		}
+        if (importExportPage != null) {
+			addPage(importExportPage);
+		}
+    }
+
+    /**
+     * Initializes the wizard.
+     *
+     * @param aWorkbench the workbench
+     * @param currentSelection the current selectio
+     */
+    public void init(IWorkbench aWorkbench,
+            IStructuredSelection currentSelection) {
+        this.workbench = aWorkbench;
+        this.selection = currentSelection;
+
+        ImageDescriptor wizardBannerImage = null;
+        if (IMPORT.equals(page)){
+        	wizardBannerImage = WorkbenchImages
+                .getImageDescriptor(IWorkbenchGraphicConstants.IMG_WIZBAN_IMPORT_WIZ);
+        	setWindowTitle(WorkbenchMessages.get().ImportWizard_title);
+        }
+        else if (EXPORT.equals(page)){
+        	wizardBannerImage = WorkbenchImages
+                    .getImageDescriptor(IWorkbenchGraphicConstants.IMG_WIZBAN_EXPORT_WIZ);
+        	setWindowTitle(WorkbenchMessages.get().ExportWizard_title);
+        }
+        if (wizardBannerImage != null) {
+			setDefaultPageImageDescriptor(wizardBannerImage);
+		}
+        setNeedsProgressMonitor(true);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ImportPage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ImportPage.java
new file mode 100644
index 0000000..d6abaf9
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ImportPage.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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
+ *     Alain Bernard <alain.bernard1224@gmail.com> - Bug 281490
+ *******************************************************************************/
+package org.eclipse.ui.internal.dialogs;
+
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.activities.ITriggerPoint;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.activities.ws.WorkbenchTriggerPoints;
+import org.eclipse.ui.wizards.IWizardCategory;
+
+/**
+ * Wizard page class from which an import wizard is selected.
+ *
+ * @since 3.2
+ *
+ */
+public class ImportPage extends ImportExportPage {
+    private static final String STORE_SELECTED_IMPORT_WIZARD_ID = DIALOG_SETTING_SECTION_NAME
+    		+ "STORE_SELECTED_IMPORT_WIZARD_ID"; //$NON-NLS-1$
+
+    private static final String STORE_EXPANDED_IMPORT_CATEGORIES = DIALOG_SETTING_SECTION_NAME
+			+ "STORE_EXPANDED_IMPORT_CATEGORIES";	//$NON-NLS-1$
+
+    protected CategorizedWizardSelectionTree importTree;
+
+    /**
+     * Constructor for import wizard selection page.
+     *
+     * @param aWorkbench
+     * @param currentSelection
+     */
+	public ImportPage(IWorkbench aWorkbench,
+			IStructuredSelection currentSelection) {
+		super(aWorkbench, currentSelection);
+	}
+
+	@Override
+	protected void initialize() {
+        workbench.getHelpSystem().setHelp(
+				getControl(),
+				IWorkbenchHelpContextIds.IMPORT_WIZARD_SELECTION_WIZARD_PAGE);
+	}
+
+	@Override
+	protected Composite createTreeViewer(Composite parent) {
+		IWizardCategory root = WorkbenchPlugin.getDefault()
+			.getImportWizardRegistry().getRootCategory();
+		importTree = new CategorizedWizardSelectionTree(
+				root, WorkbenchMessages.get().ImportWizard_selectWizard);
+		Composite importComp = importTree.createControl(parent);
+		importTree.getViewer().addSelectionChangedListener(event -> listSelectionChanged(event.getSelection()));
+		importTree.getViewer().addDoubleClickListener(event -> treeDoubleClicked(event));
+		setTreeViewer(importTree.getViewer());
+		return importComp;
+	}
+
+	@Override
+	public void saveWidgetValues(){
+    	storeExpandedCategories(STORE_EXPANDED_IMPORT_CATEGORIES, importTree.getViewer());
+        storeSelectedCategoryAndWizard(STORE_SELECTED_IMPORT_WIZARD_ID, importTree.getViewer());
+        super.saveWidgetValues();
+	}
+
+	@Override
+	protected void restoreWidgetValues(){
+    	IWizardCategory importRoot = WorkbenchPlugin.getDefault().getImportWizardRegistry().getRootCategory();
+        expandPreviouslyExpandedCategories(STORE_EXPANDED_IMPORT_CATEGORIES, importRoot,importTree.getViewer());
+        selectPreviouslySelected(STORE_SELECTED_IMPORT_WIZARD_ID, importRoot, importTree.getViewer());
+        super.restoreWidgetValues();
+	}
+
+	@Override
+	protected ITriggerPoint getTriggerPoint(){
+		return getWorkbench().getActivitySupport()
+    		.getTriggerPointManager().getTriggerPoint(WorkbenchTriggerPoints.IMPORT_WIZARDS);
+	}
+
+	@Override
+	protected void updateMessage(){
+		setMessage(WorkbenchMessages.get().ImportExportPage_chooseImportWizard);
+		super.updateMessage();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ImportWizard.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ImportWizard.java
new file mode 100644
index 0000000..0a9930f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ImportWizard.java
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Alain Bernard <alain.bernard1224@gmail.com> - Bug 281490
+ *******************************************************************************/
+package org.eclipse.ui.internal.dialogs;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.IWizardNode;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchWizard;
+import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.activities.ws.WorkbenchTriggerPoints;
+import org.eclipse.ui.internal.registry.WizardsRegistryReader;
+import org.eclipse.ui.model.AdaptableList;
+import org.eclipse.ui.wizards.IWizardCategory;
+
+/**
+ * The import wizard allows the user to choose which nested import wizard to
+ * run. The set of available wizards comes from the import wizard extension
+ * point.
+ */
+public class ImportWizard extends Wizard {
+
+    //the list selection page
+    class SelectionPage extends WorkbenchWizardListSelectionPage {
+        SelectionPage(IWorkbench w, IStructuredSelection ss, AdaptableList e,
+                String s) {
+            super(w, ss, e, s, WorkbenchTriggerPoints.IMPORT_WIZARDS);
+        }
+
+        @Override
+		public void createControl(Composite parent) {
+            super.createControl(parent);
+            getWorkbench()
+					.getHelpSystem()
+					.setHelp(
+							getControl(),
+							IWorkbenchHelpContextIds.IMPORT_WIZARD_SELECTION_WIZARD_PAGE);
+        }
+
+        @Override
+		public IWizardNode createWizardNode(WorkbenchWizardElement element) {
+            return new WorkbenchWizardNode(this, element) {
+                @Override
+				public IWorkbenchWizard createWizard() throws CoreException {
+                    return wizardElement.createWizard();
+                }
+            };
+        }
+
+
+    }
+
+    private IStructuredSelection selection;
+
+    private IWorkbench workbench;
+
+    /**
+     * Creates the wizard's pages lazily.
+     */
+    @Override
+	public void addPages() {
+        addPage(new SelectionPage(this.workbench, this.selection,
+                getAvailableImportWizards(), WorkbenchMessages.get().ImportWizard_selectWizard));
+    }
+
+    /**
+     * Returns the import wizards that are available for invocation.
+     */
+    protected AdaptableList getAvailableImportWizards() {
+       	// TODO: imports are still flat - we need to get at the flat list. All
+		// wizards will be in the "other" category.
+		IWizardCategory root = WorkbenchPlugin.getDefault()
+				.getImportWizardRegistry().getRootCategory();
+		WizardCollectionElement otherCategory = (WizardCollectionElement) root
+				.findCategory(new Path(
+						WizardsRegistryReader.UNCATEGORIZED_WIZARD_CATEGORY));
+		if (otherCategory == null) {
+			return new AdaptableList();
+		}
+		return otherCategory.getWizardAdaptableList();
+    }
+
+    /**
+     * Initializes the wizard.
+     *
+     * @param aWorkbench the workbench
+     * @param currentSelection the current selection
+     */
+    public void init(IWorkbench aWorkbench,
+            IStructuredSelection currentSelection) {
+        this.workbench = aWorkbench;
+        this.selection = currentSelection;
+
+        setWindowTitle(WorkbenchMessages.get().ImportWizard_title);
+        setDefaultPageImageDescriptor(WorkbenchImages
+                .getImageDescriptor(IWorkbenchGraphicConstants.IMG_WIZBAN_IMPORT_WIZ));
+        setNeedsProgressMonitor(true);
+    }
+
+    @Override
+	public boolean performFinish() {
+        ((SelectionPage) getPages()[0]).saveWidgetValues();
+        return true;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/NewContentTypeDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/NewContentTypeDialog.java
new file mode 100644
index 0000000..4a7061c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/NewContentTypeDialog.java
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Red Hat Inc. 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:
+ *   Mickael Istria (Red Hat Inc.) - initial implementation
+ *******************************************************************************/
+package org.eclipse.ui.internal.dialogs;
+
+import org.eclipse.core.runtime.content.IContentType;
+import org.eclipse.core.runtime.content.IContentTypeManager;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.TitleAreaDialog;
+import org.eclipse.jface.fieldassist.ControlDecoration;
+import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.jface.layout.LayoutConstants;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.internal.WorkbenchMessages;
+
+/**
+ * A dialog that asks for initial values to create a new content-type.
+ *
+ * @since 3.109
+ */
+public class NewContentTypeDialog extends TitleAreaDialog {
+
+	private String name;
+	private IContentTypeManager manager;
+	private ControlDecoration decorator;
+
+	/**
+	 * @param parentShell
+	 */
+	protected NewContentTypeDialog(Shell parentShell, IContentTypeManager manager, IContentType parent) {
+		super(parentShell);
+		this.manager = manager;
+		String baseName = name = WorkbenchMessages.get().ContentTypes_newContentTypeDialog_defaultNameNoParent;
+		if (parent != null) {
+			baseName = name = NLS.bind(WorkbenchMessages.get().ContentTypes_newContentTypeDialog_defaultNameWithParent,
+					parent.getName());
+		}
+		int suffix = 2;
+		while (manager.getContentType(name) != null) {
+			name = baseName + " (" + suffix + ')'; //$NON-NLS-1$
+			suffix++;
+		}
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see
+	 * org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets.
+	 * Shell)
+	 */
+	@Override
+	protected void configureShell(Shell shell) {
+		super.configureShell(shell);
+		shell.setText(WorkbenchMessages.get().ContentTypes_newContentTypeDialog_title);
+	}
+
+	@Override
+	protected Control createDialogArea(Composite parent) {
+		Composite parentComposite = (Composite) super.createDialogArea(parent);
+		Composite contents = new Composite(parentComposite, SWT.NONE);
+		contents.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+		Label nameLabel = new Label(contents, SWT.LEFT);
+		nameLabel.setText(WorkbenchMessages.get().ContentTypes_newContentTypeDialog_nameLabel);
+		Text nameText = new Text(contents, SWT.SINGLE | SWT.BORDER);
+		nameText.setText(name);
+		nameText.addModifyListener(event -> {
+			name = nameText.getText();
+			if (validateName()) {
+				getButton(IDialogConstants.OK_ID).setEnabled(true);
+				decorator.hide();
+			} else {
+				getButton(IDialogConstants.OK_ID).setEnabled(false);
+				decorator.show();
+			}
+		});
+		decorator = new ControlDecoration(nameText, SWT.TOP | SWT.LEFT);
+		decorator.setImage(FieldDecorationRegistry.getDefault().getFieldDecoration(FieldDecorationRegistry.DEC_ERROR)
+				.getImage());
+		decorator.setDescriptionText(WorkbenchMessages.get().ContentTypes_newContentTypeDialog_invalidContentTypeName);
+		decorator.hide();
+		setTitle(WorkbenchMessages.get().ContentTypes_newContentTypeDialog_title);
+		setMessage(WorkbenchMessages.get().ContentTypes_newContentTypeDialog_descritption);
+
+		Dialog.applyDialogFont(parentComposite);
+
+		Point defaultMargins = LayoutConstants.getMargins();
+		GridLayoutFactory.fillDefaults().numColumns(2).margins(defaultMargins.x, defaultMargins.y)
+				.generateLayout(contents);
+
+		return contents;
+	}
+
+	private boolean validateName() {
+		return name.length() > 0 && manager.getContentType(name) == null;
+	}
+
+	public String getName() {
+		return name;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/NewWizard.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/NewWizard.java
new file mode 100644
index 0000000..38f38f2
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/NewWizard.java
@@ -0,0 +1,171 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.dialogs;
+
+import java.util.StringTokenizer;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.IWizard;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.wizards.IWizardCategory;
+import org.eclipse.ui.wizards.IWizardDescriptor;
+
+/**
+ * The new wizard is responsible for allowing the user to choose which new
+ * (nested) wizard to run. The set of available new wizards comes from the new
+ * extension point.
+ */
+public class NewWizard extends Wizard {
+    private static final String CATEGORY_SEPARATOR = "/"; //$NON-NLS-1$
+
+    private String categoryId = null;
+
+    private NewWizardSelectionPage mainPage;
+
+    private boolean projectsOnly = false;
+
+    private IStructuredSelection selection;
+
+    private IWorkbench workbench;
+
+    /**
+     * Create the wizard pages
+     */
+    @Override
+	public void addPages() {
+        IWizardCategory root = WorkbenchPlugin.getDefault().getNewWizardRegistry().getRootCategory();
+        IWizardDescriptor [] primary = WorkbenchPlugin.getDefault().getNewWizardRegistry().getPrimaryWizards();
+
+        if (categoryId != null) {
+            IWizardCategory categories = root;
+            StringTokenizer familyTokenizer = new StringTokenizer(categoryId,
+                    CATEGORY_SEPARATOR);
+            while (familyTokenizer.hasMoreElements()) {
+                categories = getChildWithID(categories, familyTokenizer
+                        .nextToken());
+                if (categories == null) {
+					break;
+				}
+            }
+            if (categories != null) {
+				root = categories;
+			}
+        }
+
+        mainPage = new NewWizardSelectionPage(workbench, selection, root,
+				primary, projectsOnly);
+        addPage(mainPage);
+    }
+
+    /**
+     * Returns the id of the category of wizards to show or <code>null</code>
+     * to show all categories. If no entries can be found with this id then all
+     * categories are shown.
+     *
+     * @return String or <code>null</code>.
+     */
+    public String getCategoryId() {
+        return categoryId;
+    }
+
+    /**
+     * Returns the child collection element for the given id
+     */
+    private IWizardCategory getChildWithID(
+            IWizardCategory parent, String id) {
+		for (IWizardCategory wizardCategory : parent.getCategories()) {
+			if (wizardCategory.getId().equals(id)) {
+				return wizardCategory;
+			}
+        }
+        return null;
+    }
+
+    /**
+     * Lazily create the wizards pages
+     * @param aWorkbench the workbench
+     * @param currentSelection the current selection
+     */
+    public void init(IWorkbench aWorkbench,
+            IStructuredSelection currentSelection) {
+        this.workbench = aWorkbench;
+        this.selection = currentSelection;
+
+		if (getWindowTitle() == null) {
+			// No title supplied. Set the default title
+			if (projectsOnly) {
+				setWindowTitle(WorkbenchMessages.get().NewProject_title);
+			} else {
+				setWindowTitle(WorkbenchMessages.get().NewWizard_title);
+			}
+		}
+        setDefaultPageImageDescriptor(WorkbenchImages
+                .getImageDescriptor(IWorkbenchGraphicConstants.IMG_WIZBAN_NEW_WIZ));
+        setNeedsProgressMonitor(true);
+    }
+
+    /**
+     * The user has pressed Finish. Instruct self's pages to finish, and answer
+     * a boolean indicating success.
+     *
+     * @return boolean
+     */
+    @Override
+	public boolean performFinish() {
+        //save our selection state
+        mainPage.saveWidgetValues();
+        // if we're finishing from the main page then perform finish on the selected wizard.
+        if (getContainer().getCurrentPage() == mainPage) {
+			if (mainPage.canFinishEarly()) {
+				IWizard wizard = mainPage.getSelectedNode().getWizard();
+				wizard.setContainer(getContainer());
+				return wizard.performFinish();
+			}
+		}
+        return true;
+    }
+
+    /**
+     * Sets the id of the category of wizards to show or <code>null</code> to
+     * show all categories. If no entries can be found with this id then all
+     * categories are shown.
+     *
+     * @param id may be <code>null</code>.
+     */
+    public void setCategoryId(String id) {
+        categoryId = id;
+    }
+
+    /**
+     * Sets the projects only flag. If <code>true</code> only projects will
+     * be shown in this wizard.
+     * @param b if only projects should be shown
+     */
+    public void setProjectsOnly(boolean b) {
+        projectsOnly = b;
+    }
+
+    @Override
+	public boolean canFinish() {
+         // we can finish if the first page is current and the the page can finish early.
+	    	if (getContainer().getCurrentPage() == mainPage) {
+	    		if (mainPage.canFinishEarly()) {
+					return true;
+				}
+	    	}
+	    	return super.canFinish();
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/NewWizardCollectionComparator.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/NewWizardCollectionComparator.java
new file mode 100644
index 0000000..c138ce0
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/NewWizardCollectionComparator.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.dialogs;
+
+import org.eclipse.jface.viewers.IBasicPropertyConstants;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.ui.internal.registry.WizardsRegistryReader;
+
+/**
+ *	A Viewer element sorter that sorts Elements by their name attribute.
+ *	Note that capitalization differences are not considered by this
+ *	sorter, so a < B < c.
+ *
+ *	NOTE one exception to the above: an element with the system's reserved
+ *	name for base Wizards will always be sorted such that it will
+ *	ultimately be placed at the beginning of the sorted result.
+ */
+class NewWizardCollectionComparator extends ViewerComparator {
+	/**
+	 * Static instance of this class.
+	 */
+    public final static NewWizardCollectionComparator INSTANCE = new NewWizardCollectionComparator();
+
+
+    /**
+     * Creates an instance of <code>NewWizardCollectionSorter</code>.  Since this
+     * is a stateless sorter, it is only accessible as a singleton; the private
+     * visibility of this constructor ensures this.
+     */
+    private NewWizardCollectionComparator() {
+        super();
+    }
+
+    @Override
+	public int category(Object element) {
+    	if (element instanceof WorkbenchWizardElement) {
+			return -1;
+		}
+    	if (element instanceof WizardCollectionElement){
+    		String id = ((WizardCollectionElement)element).getId();
+    		if (WizardsRegistryReader.GENERAL_WIZARD_CATEGORY.equals(id)) {
+				return 1;
+			}
+    		if (WizardsRegistryReader.UNCATEGORIZED_WIZARD_CATEGORY.equals(id)) {
+				return 3;
+			}
+    		if (WizardsRegistryReader.FULL_EXAMPLES_WIZARD_CATEGORY.equals(id)) {
+				return 4;
+			}
+    		return 2;
+    	}
+    	return super.category(element);
+	}
+
+	/**
+     *	Return true if this sorter is affected by a property
+     *	change of propertyName on the specified element.
+     */
+    @Override
+	public boolean isSorterProperty(Object object, String propertyId) {
+        return propertyId.equals(IBasicPropertyConstants.P_TEXT);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/NewWizardNewPage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/NewWizardNewPage.java
new file mode 100644
index 0000000..e828b08
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/NewWizardNewPage.java
@@ -0,0 +1,726 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.dialogs;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.jface.wizard.IWizard;
+import org.eclipse.jface.wizard.IWizardContainer;
+import org.eclipse.jface.wizard.IWizardContainer2;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CLabel;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.ui.IWorkbenchWizard;
+import org.eclipse.ui.activities.WorkbenchActivityHelper;
+import org.eclipse.ui.dialogs.FilteredTree;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.registry.WizardsRegistryReader;
+import org.eclipse.ui.model.AdaptableList;
+import org.eclipse.ui.model.WorkbenchLabelProvider;
+import org.eclipse.ui.wizards.IWizardCategory;
+import org.eclipse.ui.wizards.IWizardDescriptor;
+
+/**
+ * New wizard selection tab that allows the user to select a registered 'New'
+ * wizard to be launched.
+ */
+class NewWizardNewPage implements ISelectionChangedListener {
+
+    // id constants
+    private static final String DIALOG_SETTING_SECTION_NAME = "NewWizardSelectionPage."; //$NON-NLS-1$
+
+    private final static int SIZING_LISTS_HEIGHT = 200;
+
+    private final static int SIZING_VIEWER_WIDTH = 300;
+
+    private final static String STORE_EXPANDED_CATEGORIES_ID = DIALOG_SETTING_SECTION_NAME
+            + "STORE_EXPANDED_CATEGORIES_ID"; //$NON-NLS-1$
+
+    private final static String STORE_SELECTED_ID = DIALOG_SETTING_SECTION_NAME
+            + "STORE_SELECTED_ID"; //$NON-NLS-1$
+
+    private NewWizardSelectionPage page;
+
+    private FilteredTree filteredTree;
+
+    private WizardPatternFilter filteredTreeFilter;
+
+    //Keep track of the wizards we have previously selected
+    private Hashtable selectedWizards = new Hashtable();
+
+    private IDialogSettings settings;
+
+    private Button showAllCheck;
+
+    private IWizardCategory wizardCategories;
+
+    private IWizardDescriptor [] primaryWizards;
+
+    private CLabel descImageCanvas;
+
+    private Map imageTable = new HashMap();
+
+    private IWizardDescriptor selectedElement;
+
+    private WizardActivityFilter filter = new WizardActivityFilter();
+
+    private boolean needShowAll;
+
+	private boolean projectsOnly;
+
+	private ViewerFilter projectFilter = new WizardTagFilter(new String[] {WorkbenchWizardElement.TAG_PROJECT});
+
+    /**
+     * Create an instance of this class
+     * @param mainPage
+     * @param wizardCategories
+     * @param primaryWizards
+     * @param projectsOnly
+     */
+    public NewWizardNewPage(NewWizardSelectionPage mainPage,
+			IWizardCategory wizardCategories,
+			IWizardDescriptor[] primaryWizards, boolean projectsOnly) {
+        this.page = mainPage;
+        this.wizardCategories = wizardCategories;
+        this.primaryWizards = primaryWizards;
+        this.projectsOnly = projectsOnly;
+
+        trimPrimaryWizards();
+
+        if (this.primaryWizards.length > 0) {
+            if (allPrimary(wizardCategories)) {
+                this.wizardCategories = null; // dont bother considering the categories as all wizards are primary
+                needShowAll = false;
+            } else {
+                needShowAll = !allActivityEnabled(wizardCategories);
+            }
+        } else {
+            needShowAll = !allActivityEnabled(wizardCategories);
+        }
+
+		IWizard wizard = mainPage.getWizard();
+		if (wizard instanceof NewWizard) {
+			if (WizardsRegistryReader.FULL_EXAMPLES_WIZARD_CATEGORY.equals(((NewWizard) wizard)
+					.getCategoryId())) {
+				filter.setFilterPrimaryWizards(true);
+			}
+		}
+    }
+
+    /**
+     * @param category the wizard category
+     * @return whether all of the wizards in the category are enabled via activity filtering
+     */
+    private boolean allActivityEnabled(IWizardCategory category) {
+		for (IWizardDescriptor wizard : category.getWizards()) {
+            if (WorkbenchActivityHelper.filterItem(wizard)) {
+				return false;
+			}
+        }
+
+		for (IWizardCategory wizard : category.getCategories()) {
+			if (!allActivityEnabled(wizard)) {
+				return false;
+			}
+		}
+
+        return true;
+    }
+
+    /**
+     * Remove all primary wizards that are not in the wizard collection
+     */
+    private void trimPrimaryWizards() {
+        ArrayList newPrimaryWizards = new ArrayList(primaryWizards.length);
+
+        if (wizardCategories == null) {
+			return;//No categories so nothing to trim
+		}
+
+        for (IWizardDescriptor primaryWizard : primaryWizards) {
+            if (wizardCategories.findWizard(primaryWizard.getId()) != null) {
+				newPrimaryWizards.add(primaryWizard);
+			}
+        }
+
+        primaryWizards = (WorkbenchWizardElement[]) newPrimaryWizards
+                .toArray(new WorkbenchWizardElement[newPrimaryWizards.size()]);
+    }
+
+    /**
+     * @param category the wizard category
+     * @return whether all wizards in the category are considered primary
+     */
+    private boolean allPrimary(IWizardCategory category) {
+		for (IWizardDescriptor wizard : category.getWizards()) {
+            if (!isPrimary(wizard)) {
+				return false;
+			}
+        }
+
+		for (IWizardCategory wizard : category.getCategories()) {
+			if (!allPrimary(wizard)) {
+				return false;
+			}
+		}
+
+        return true;
+    }
+
+    /**
+     * @param wizard
+     * @return whether the given wizard is primary
+     */
+    private boolean isPrimary(IWizardDescriptor wizard) {
+        for (IWizardDescriptor primaryWizard : primaryWizards) {
+            if (primaryWizard.equals(wizard)) {
+				return true;
+			}
+        }
+
+        return false;
+    }
+
+    /**
+     * @since 3.0
+     */
+    public void activate() {
+        page.setDescription(WorkbenchMessages.get().NewWizardNewPage_description);
+    }
+
+    /**
+     * Create this tab's visual components
+     *
+     * @param parent Composite
+     * @return Control
+     */
+    protected Control createControl(Composite parent) {
+
+        Font wizardFont = parent.getFont();
+        // top level group
+        Composite outerContainer = new Composite(parent, SWT.NONE);
+        GridLayout layout = new GridLayout();
+        outerContainer.setLayout(layout);
+
+        Label wizardLabel = new Label(outerContainer, SWT.NONE);
+        GridData data = new GridData(SWT.BEGINNING, SWT.FILL, false, true);
+        outerContainer.setLayoutData(data);
+        wizardLabel.setFont(wizardFont);
+        wizardLabel.setText(WorkbenchMessages.get().NewWizardNewPage_wizardsLabel);
+
+        Composite innerContainer = new Composite(outerContainer, SWT.NONE);
+        layout = new GridLayout(2, false);
+        layout.marginHeight = 0;
+        layout.marginWidth = 0;
+        innerContainer.setLayout(layout);
+        innerContainer.setFont(wizardFont);
+        data = new GridData(SWT.FILL, SWT.FILL, true, true);
+        innerContainer.setLayoutData(data);
+
+        filteredTree = createFilteredTree(innerContainer);
+        createOptionsButtons(innerContainer);
+
+        createImage(innerContainer);
+
+        updateDescription(null);
+
+        // wizard actions pane...create SWT table directly to
+        // get single selection mode instead of multi selection.
+        restoreWidgetValues();
+
+        return outerContainer;
+    }
+
+    /**
+     * Create a new FilteredTree in the parent.
+     *
+     * @param parent the parent <code>Composite</code>.
+     * @since 3.0
+     */
+    protected FilteredTree createFilteredTree(Composite parent){
+        Composite composite = new Composite(parent, SWT.NONE);
+        GridLayout layout = new GridLayout();
+        layout.marginHeight = 0;
+        layout.marginWidth = 0;
+        composite.setLayout(layout);
+
+        GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
+        data.widthHint = SIZING_VIEWER_WIDTH;
+        data.horizontalSpan = 2;
+        data.grabExcessHorizontalSpace = true;
+        data.grabExcessVerticalSpace = true;
+
+        boolean needsHint = DialogUtil.inRegularFontMode(parent);
+
+        //Only give a height hint if the dialog is going to be too small
+        if (needsHint) {
+            data.heightHint = SIZING_LISTS_HEIGHT;
+        }
+        composite.setLayoutData(data);
+
+        filteredTreeFilter = new WizardPatternFilter();
+    	FilteredTree filterTree = new FilteredTree(composite,
+    			SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER, filteredTreeFilter, true);
+		filterTree.setQuickSelectionMode(true);
+
+		final TreeViewer treeViewer = filterTree.getViewer();
+		treeViewer.setContentProvider(new WizardContentProvider());
+		treeViewer.setLabelProvider(new WorkbenchLabelProvider());
+		treeViewer.setComparator(NewWizardCollectionComparator.INSTANCE);
+		treeViewer.addSelectionChangedListener(this);
+
+        ArrayList inputArray = new ArrayList();
+
+        for (IWizardDescriptor primaryWizard : primaryWizards) {
+            inputArray.add(primaryWizard);
+        }
+
+        boolean expandTop = false;
+
+        if (wizardCategories != null) {
+            if (wizardCategories.getParent() == null) {
+				for (IWizardCategory wizardCategory : wizardCategories.getCategories()) {
+					inputArray.add(wizardCategory);
+                }
+            } else {
+                expandTop = true;
+                inputArray.add(wizardCategories);
+            }
+        }
+
+        // ensure the category is expanded.  If there is a remembered expansion it will be set later.
+        if (expandTop) {
+			treeViewer.setAutoExpandLevel(2);
+		}
+
+        AdaptableList input = new AdaptableList(inputArray);
+
+        treeViewer.setInput(input);
+
+		filterTree.setBackground(parent.getDisplay().getSystemColor(
+				SWT.COLOR_WIDGET_BACKGROUND));
+
+        treeViewer.getTree().setFont(parent.getFont());
+
+        treeViewer.addDoubleClickListener(event -> {
+			    IStructuredSelection s = (IStructuredSelection) event
+					.getSelection();
+			selectionChanged(new SelectionChangedEvent(event.getViewer(), s));
+
+			Object element = s.getFirstElement();
+		    if (treeViewer.isExpandable(element)) {
+		    	treeViewer.setExpandedState(element, !treeViewer
+		                .getExpandedState(element));
+		    } else if (element instanceof WorkbenchWizardElement) {
+		        page.advanceToNextPageOrFinish();
+		    }
+		});
+
+        treeViewer.addFilter(filter);
+
+        if (projectsOnly) {
+			treeViewer.addFilter(projectFilter);
+		}
+
+		Dialog.applyDialogFont(filterTree);
+		return filterTree;
+    }
+
+    /**
+     * Create the Show All and help buttons at the bottom of the page.
+     *
+     * @param parent the parent composite on which to create the widgets
+     */
+    private void createOptionsButtons(Composite parent){
+        if (needShowAll) {
+            showAllCheck = new Button(parent, SWT.CHECK);
+            GridData data = new GridData();
+            showAllCheck.setLayoutData(data);
+            showAllCheck.setFont(parent.getFont());
+            showAllCheck.setText(WorkbenchMessages.get().NewWizardNewPage_showAll);
+            showAllCheck.setSelection(false);
+
+            // flipping tabs updates the selected node
+            showAllCheck.addSelectionListener(new SelectionAdapter() {
+
+                // the delta of expanded elements between the last 'show all'
+                // and the current 'no show all'
+                private Object[] delta = new Object[0];
+
+                @Override
+				public void widgetSelected(SelectionEvent e) {
+                    boolean showAll = showAllCheck.getSelection();
+
+                    if (showAll) {
+                    	filteredTree.getViewer().getControl().setRedraw(false);
+                    } else {
+                        // get the inital expanded elements when going from show
+                        // all-> no show all.
+                        // this isnt really the delta yet, we're just reusing
+                        // the variable.
+                        delta = filteredTree.getViewer().getExpandedElements();
+                    }
+
+                    try {
+                        if (showAll) {
+                        	filteredTree.getViewer().resetFilters();
+                        	filteredTree.getViewer().addFilter(filteredTreeFilter);
+                            if (projectsOnly) {
+								filteredTree.getViewer().addFilter(projectFilter);
+							}
+
+                            // restore the expanded elements that were present
+                            // in the last show all state but not in the 'no
+                            // show all' state.
+                            Object[] currentExpanded = filteredTree.getViewer()
+                                    .getExpandedElements();
+                            Object[] expanded = new Object[delta.length
+                                    + currentExpanded.length];
+                            System.arraycopy(currentExpanded, 0, expanded, 0,
+                                    currentExpanded.length);
+                            System.arraycopy(delta, 0, expanded,
+                                    currentExpanded.length, delta.length);
+                            filteredTree.getViewer().setExpandedElements(expanded);
+                        } else {
+                        	filteredTree.getViewer().addFilter(filter);
+                            if (projectsOnly) {
+								filteredTree.getViewer().addFilter(projectFilter);
+							}
+                        }
+                        filteredTree.getViewer().refresh(false);
+
+                        if (!showAll) {
+                            // if we're going from show all -> no show all
+                            // record the elements that were expanded in the
+                            // 'show all' state but not the 'no show all' state
+                            // (because they didnt exist).
+                            Object[] newExpanded = filteredTree.getViewer().getExpandedElements();
+                            List deltaList = new ArrayList(Arrays.asList(delta));
+                            deltaList.removeAll(Arrays.asList(newExpanded));
+                        }
+                    } finally {
+                        if (showAll) {
+							filteredTree.getViewer().getControl().setRedraw(true);
+						}
+                    }
+                }
+            });
+        }
+    }
+
+    /**
+     * Create the image controls.
+     *
+     * @param parent the parent <code>Composite</code>.
+     * @since 3.0
+     */
+    private void createImage(Composite parent) {
+        descImageCanvas = new CLabel(parent, SWT.NONE);
+        GridData data = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING
+                | GridData.VERTICAL_ALIGN_BEGINNING);
+        data.widthHint = 0;
+        data.heightHint = 0;
+        descImageCanvas.setLayoutData(data);
+
+        // hook a listener to get rid of cached images.
+        descImageCanvas.addDisposeListener(e -> {
+		    for (Iterator i = imageTable.values().iterator(); i.hasNext();) {
+		        ((Image) i.next()).dispose();
+		    }
+		    imageTable.clear();
+		});
+    }
+
+    /**
+     * Expands the wizard categories in this page's category viewer that were
+     * expanded last time this page was used. If a category that was previously
+     * expanded no longer exists then it is ignored.
+     */
+    protected void expandPreviouslyExpandedCategories() {
+        String[] expandedCategoryPaths = settings
+                .getArray(STORE_EXPANDED_CATEGORIES_ID);
+        if (expandedCategoryPaths == null || expandedCategoryPaths.length == 0) {
+			return;
+		}
+
+        List categoriesToExpand = new ArrayList(expandedCategoryPaths.length);
+
+        if (wizardCategories != null) {
+            for (String expandedCategoryPath : expandedCategoryPaths) {
+                IWizardCategory category = wizardCategories
+                        .findCategory(new Path(expandedCategoryPath));
+                if (category != null) {
+					categoriesToExpand.add(category);
+				}
+            }
+        }
+
+        if (!categoriesToExpand.isEmpty()) {
+			filteredTree.getViewer().setExpandedElements(categoriesToExpand.toArray());
+		}
+
+    }
+
+    /**
+     * Returns the single selected object contained in the passed
+     * selectionEvent, or <code>null</code> if the selectionEvent contains
+     * either 0 or 2+ selected objects.
+     */
+    protected Object getSingleSelection(IStructuredSelection selection) {
+        return selection.size() == 1 ? selection.getFirstElement() : null;
+    }
+
+    /**
+     * Set self's widgets to the values that they held last time this page was
+     * open
+     *
+     */
+    protected void restoreWidgetValues() {
+        expandPreviouslyExpandedCategories();
+        selectPreviouslySelected();
+    }
+
+    /**
+     * Store the current values of self's widgets so that they can be restored
+     * in the next instance of self
+     *
+     */
+    public void saveWidgetValues() {
+        storeExpandedCategories();
+        storeSelectedCategoryAndWizard();
+    }
+
+    /**
+     * The user selected either new wizard category(s) or wizard element(s).
+     * Proceed accordingly.
+     *
+     * @param selectionEvent ISelection
+     */
+    @Override
+	public void selectionChanged(SelectionChangedEvent selectionEvent) {
+        page.setErrorMessage(null);
+        page.setMessage(null);
+
+        Object selectedObject = getSingleSelection((IStructuredSelection) selectionEvent
+                .getSelection());
+
+        if (selectedObject instanceof IWizardDescriptor) {
+            if (selectedObject == selectedElement) {
+				return;
+			}
+            updateWizardSelection((IWizardDescriptor) selectedObject);
+        } else {
+            selectedElement = null;
+            page.setHasPages(false);
+            page.setCanFinishEarly(false);
+            page.selectWizardNode(null);
+            updateDescription(null);
+        }
+    }
+
+    /**
+     * Selects the wizard category and wizard in this page that were selected
+     * last time this page was used. If a category or wizard that was
+     * previously selected no longer exists then it is ignored.
+     */
+    protected void selectPreviouslySelected() {
+        String selectedId = settings.get(STORE_SELECTED_ID);
+        if (selectedId == null) {
+			return;
+		}
+
+        if (wizardCategories == null) {
+			return;
+		}
+
+        Object selected = wizardCategories.findCategory(new Path(
+                selectedId));
+
+        if (selected == null) {
+            selected = wizardCategories.findWizard(selectedId);
+
+            if (selected == null) {
+				// if we cant find either a category or a wizard, abort.
+                return;
+			}
+        }
+
+        //work around for 62039
+        final StructuredSelection selection = new StructuredSelection(selected);
+        filteredTree.getViewer().getControl().getDisplay().asyncExec(() -> filteredTree.getViewer().setSelection(selection, true));
+    }
+
+    /**
+     * Set the dialog store to use for widget value storage and retrieval
+     *
+     * @param settings IDialogSettings
+     */
+    public void setDialogSettings(IDialogSettings settings) {
+        this.settings = settings;
+    }
+
+    /**
+     * Stores the collection of currently-expanded categories in this page's
+     * dialog store, in order to recreate this page's state in the next
+     * instance of this page.
+     */
+    protected void storeExpandedCategories() {
+        Object[] expandedElements = filteredTree.getViewer().getExpandedElements();
+        List expandedElementPaths = new ArrayList(expandedElements.length);
+        for (Object expandedElement : expandedElements) {
+            if (expandedElement instanceof IWizardCategory) {
+				expandedElementPaths
+                        .add(((IWizardCategory) expandedElement)
+                                .getPath().toString());
+			}
+        }
+        settings.put(STORE_EXPANDED_CATEGORIES_ID,
+                (String[]) expandedElementPaths
+                        .toArray(new String[expandedElementPaths.size()]));
+    }
+
+    /**
+     * Stores the currently-selected element in this page's dialog store, in
+     * order to recreate this page's state in the next instance of this page.
+     */
+    protected void storeSelectedCategoryAndWizard() {
+        Object selected = getSingleSelection((IStructuredSelection) filteredTree
+        		.getViewer().getSelection());
+
+        if (selected != null) {
+            if (selected instanceof IWizardCategory) {
+				settings.put(STORE_SELECTED_ID,
+                        ((IWizardCategory) selected).getPath()
+                                .toString());
+			} else {
+				// else its a wizard
+                settings.put(STORE_SELECTED_ID,
+                        ((IWizardDescriptor) selected).getId());
+			}
+        }
+    }
+
+    /**
+     * Update the current description controls.
+     *
+     * @param selectedObject the new wizard
+     * @since 3.0
+     */
+    private void updateDescription(IWizardDescriptor selectedObject) {
+        String string = ""; //$NON-NLS-1$
+        if (selectedObject != null) {
+			string = selectedObject.getDescription();
+		}
+
+        page.setDescription(string);
+
+        if (hasImage(selectedObject)) {
+            ImageDescriptor descriptor = null;
+            if (selectedObject != null) {
+                descriptor = selectedObject.getDescriptionImage();
+            }
+
+            if (descriptor != null) {
+            	GridData data = (GridData)descImageCanvas.getLayoutData();
+            	data.widthHint = SWT.DEFAULT;
+            	data.heightHint = SWT.DEFAULT;
+                Image image = (Image) imageTable.get(descriptor);
+                if (image == null) {
+                    image = descriptor.createImage(false);
+                    imageTable.put(descriptor, image);
+                }
+                descImageCanvas.setImage(image);
+            }
+        } else {
+        	GridData data = (GridData)descImageCanvas.getLayoutData();
+        	data.widthHint = 0;
+        	data.heightHint = 0;
+            descImageCanvas.setImage(null);
+        }
+
+        descImageCanvas.getParent().layout(true);
+        filteredTree.getViewer().getTree().showSelection();
+
+        IWizardContainer container = page.getWizard().getContainer();
+        if (container instanceof IWizardContainer2) {
+            ((IWizardContainer2) container).updateSize();
+        }
+    }
+
+    /**
+     * Tests whether the given wizard has an associated image.
+     *
+     * @param selectedObject the wizard to test
+     * @return whether the given wizard has an associated image
+     */
+    private boolean hasImage(IWizardDescriptor selectedObject) {
+        if (selectedObject == null) {
+			return false;
+		}
+
+        if (selectedObject.getDescriptionImage() != null) {
+			return true;
+		}
+
+        return false;
+    }
+
+    /**
+     * @param selectedObject
+     */
+    private void updateWizardSelection(IWizardDescriptor selectedObject) {
+        selectedElement = selectedObject;
+        WorkbenchWizardNode selectedNode;
+        if (selectedWizards.containsKey(selectedObject)) {
+            selectedNode = (WorkbenchWizardNode) selectedWizards
+                    .get(selectedObject);
+        } else {
+            selectedNode = new WorkbenchWizardNode(page, selectedObject) {
+                @Override
+				public IWorkbenchWizard createWizard() throws CoreException {
+                    return wizardElement.createWizard();
+                }
+            };
+            selectedWizards.put(selectedObject, selectedNode);
+        }
+
+        page.setCanFinishEarly(selectedObject.canFinishEarly());
+        page.setHasPages(selectedObject.hasPages());
+        page.selectWizardNode(selectedNode);
+
+        updateDescription(selectedObject);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/NewWizardSelectionPage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/NewWizardSelectionPage.java
new file mode 100644
index 0000000..1cb0cf6
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/NewWizardSelectionPage.java
@@ -0,0 +1,138 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.dialogs;
+
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.activities.ws.WorkbenchTriggerPoints;
+import org.eclipse.ui.wizards.IWizardCategory;
+import org.eclipse.ui.wizards.IWizardDescriptor;
+
+/**
+ *	New wizard selection tab that allows the user to either select a
+ *	registered 'New' wizard to be launched, or to select a solution or
+ *	projects to be retrieved from an available server.  This page
+ *	contains two visual tabs that allow the user to perform these tasks.
+ *
+ *  Temporarily has two inner pages.  The new format page is used if the system
+ *  is currently aware of activity categories.
+ */
+class NewWizardSelectionPage extends WorkbenchWizardSelectionPage {
+    private IWizardCategory wizardCategories;
+
+    // widgets
+    private NewWizardNewPage newResourcePage;
+
+    private IWizardDescriptor [] primaryWizards;
+
+	private boolean projectsOnly;
+
+	private boolean canFinishEarly = false, hasPages = true;
+
+    /**
+     * Create an instance of this class.
+     *
+     * @param workbench the workbench
+     * @param selection the current selection
+     * @param root the wizard root element
+     * @param primary the primary wizard elements
+     * @param projectsOnly if only projects should be shown
+     */
+    public NewWizardSelectionPage(IWorkbench workbench,
+			IStructuredSelection selection, IWizardCategory root,
+			IWizardDescriptor[] primary, boolean projectsOnly) {
+        super("newWizardSelectionPage", workbench, selection, null, WorkbenchTriggerPoints.NEW_WIZARDS);//$NON-NLS-1$
+
+        setTitle(WorkbenchMessages.get().NewWizardSelectionPage_description);
+        wizardCategories = root;
+        primaryWizards = primary;
+        this.projectsOnly = projectsOnly;
+	}
+
+    /**
+     * Makes the next page visible.
+     */
+    public void advanceToNextPageOrFinish() {
+    		if (canFlipToNextPage()) {
+				getContainer().showPage(getNextPage());
+			} else if (canFinishEarly()) {
+    			if (getWizard().performFinish()) {
+					((WizardDialog)getContainer()).close();
+				}
+    		}
+    }
+
+    @Override
+	public void createControl(Composite parent) {
+        IDialogSettings settings = getDialogSettings();
+        newResourcePage = new NewWizardNewPage(this, wizardCategories,
+				primaryWizards, projectsOnly);
+        newResourcePage.setDialogSettings(settings);
+
+        Control control = newResourcePage.createControl(parent);
+        getWorkbench().getHelpSystem().setHelp(control,
+				IWorkbenchHelpContextIds.NEW_WIZARD_SELECTION_WIZARD_PAGE);
+        setControl(control);
+    }
+
+    /**
+     * Since Finish was pressed, write widget values to the dialog store so that they
+     *will persist into the next invocation of this wizard page
+     */
+    protected void saveWidgetValues() {
+        newResourcePage.saveWidgetValues();
+    }
+
+    @Override
+	public boolean canFlipToNextPage() {
+        // if the current page advertises that it does have pages then ask it via the super call
+    		if (hasPages) {
+				return super.canFlipToNextPage();
+			}
+    		return false;
+    }
+
+    /**
+     * Sets whether the selected wizard advertises that it does provide pages.
+     *
+     * @param newValue whether the selected wizard has pages
+     * @since 3.1
+     */
+	public void setHasPages(boolean newValue) {
+		hasPages = newValue;
+	}
+
+	/**
+	 * Sets whether the selected wizard advertises that it can finish early.
+	 *
+	 * @param newValue whether the selected wizard can finish early
+	 * @since 3.1
+	 */
+	public void setCanFinishEarly(boolean newValue) {
+		canFinishEarly = newValue;
+	}
+
+	/**
+	 * Answers whether the currently selected page, if any, advertises that it may finish early.
+	 *
+	 * @return whether the page can finish early
+	 * @since 3.1
+	 */
+	public boolean canFinishEarly() {
+		return canFinishEarly;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/PerspContentProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/PerspContentProvider.java
new file mode 100644
index 0000000..e41923a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/PerspContentProvider.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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.ui.internal.dialogs;
+
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.ui.IPerspectiveRegistry;
+
+public class PerspContentProvider implements IStructuredContentProvider {
+    @Override
+	public Object[] getElements(Object element) {
+        if (element instanceof IPerspectiveRegistry) {
+            return ((IPerspectiveRegistry) element).getPerspectives();
+        }
+        return null;
+    }
+    
+    @Override
+    public void dispose() {
+        //no-op
+    }
+    
+    @Override
+    public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+        //no-op
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/PerspectivesPreferencePage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/PerspectivesPreferencePage.java
new file mode 100644
index 0000000..d24eb43
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/PerspectivesPreferencePage.java
@@ -0,0 +1,607 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Semion Chichelnitsky (semion@il.ibm.com) - bug 278064
+ *     Denis Zygann <d.zygann@web.de> - Bug 330453
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.dialogs;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective;
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Widget;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPreferenceConstants;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.IPreferenceConstants;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.Workbench;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.registry.PerspectiveDescriptor;
+import org.eclipse.ui.internal.registry.PerspectiveRegistry;
+import org.eclipse.ui.internal.util.Descriptors;
+import org.eclipse.ui.internal.util.PrefUtil;
+import org.eclipse.ui.internal.util.Util;
+
+import com.ibm.icu.text.Collator;
+
+/**
+ * The Workbench / Perspectives preference page.
+ */
+public class PerspectivesPreferencePage extends PreferencePage implements
+		IWorkbenchPreferencePage {
+	private IWorkbench workbench;
+
+	private PerspectiveRegistry perspectiveRegistry;
+
+	// List of perspectives to populate preference page
+	private ArrayList<IPerspectiveDescriptor> perspectives;
+
+	private String defaultPerspectiveId;
+
+	private ArrayList<IPerspectiveDescriptor> perspToDelete = new ArrayList<>();
+
+	private ArrayList<IPerspectiveDescriptor> perspToRevert = new ArrayList<>();
+
+	private Table perspectivesTable;
+
+	private Button revertButton;
+
+	private Button deleteButton;
+
+	private Button setDefaultButton;
+
+	// widgets for open perspective mode;
+	private Button openSameWindowButton;
+
+	private Button openNewWindowButton;
+
+	private int openPerspMode;
+
+	// labels
+	private final String OPM_TITLE = WorkbenchMessages.get().OpenPerspectiveMode_optionsTitle;
+
+	private final String OPM_SAME_WINDOW = WorkbenchMessages.get().OpenPerspectiveMode_sameWindow;
+
+	private final String OPM_NEW_WINDOW = WorkbenchMessages.get().OpenPerspectiveMode_newWindow;
+
+	/**
+	 * <code>Comparator</code> to compare two perspective descriptors
+	 */
+	private Comparator<IPerspectiveDescriptor> comparator = new Comparator<IPerspectiveDescriptor>() {
+        private Collator collator = Collator.getInstance();
+
+		@Override
+		public int compare(IPerspectiveDescriptor ob1, IPerspectiveDescriptor ob2) {
+			IPerspectiveDescriptor d1 = ob1;
+			IPerspectiveDescriptor d2 = ob2;
+            return collator.compare(d1.getLabel(), d2.getLabel());
+        }
+    };
+
+	/**
+	 * Creates the page's UI content.
+	 */
+	@Override
+	protected Control createContents(Composite parent) {
+		// @issue if the product subclasses this page, then it should provide
+		// the help content
+		PlatformUI.getWorkbench().getHelpSystem().setHelp(parent,
+				IWorkbenchHelpContextIds.PERSPECTIVES_PREFERENCE_PAGE);
+
+		Composite composite = createComposite(parent);
+
+		createOpenPerspButtonGroup(composite);
+		createCustomizePerspective(composite);
+
+		return composite;
+	}
+
+	/**
+	 * Creates the composite which will contain all the preference controls for
+	 * this page.
+	 *
+	 * @param parent
+	 *            the parent composite
+	 * @return the composite for this page
+	 */
+	protected Composite createComposite(Composite parent) {
+		Composite composite = new Composite(parent, SWT.NONE);
+		GridData data = new GridData(GridData.FILL_BOTH);
+		composite.setLayoutData(data);
+		composite.setFont(parent.getFont());
+		GridLayout layout = new GridLayout();
+		layout.marginWidth = 0;
+		layout.marginHeight = 0;
+		layout.verticalSpacing = 10;
+		composite.setLayout(layout);
+		return composite;
+	}
+
+	/**
+	 * Create a composite that contains buttons for selecting the open
+	 * perspective mode.
+	 *
+	 * @param composite
+	 *            the parent composite
+	 */
+	protected void createOpenPerspButtonGroup(Composite composite) {
+
+		Font font = composite.getFont();
+
+		Group buttonComposite = new Group(composite, SWT.LEFT);
+		buttonComposite.setText(OPM_TITLE);
+		buttonComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+		buttonComposite.setFont(composite.getFont());
+		GridLayout layout = new GridLayout();
+		layout.numColumns = 2;
+		buttonComposite.setLayout(layout);
+
+		openSameWindowButton = new Button(buttonComposite, SWT.RADIO);
+		openSameWindowButton.setText(OPM_SAME_WINDOW);
+		openSameWindowButton
+				.setSelection(IPreferenceConstants.OPM_ACTIVE_PAGE == openPerspMode);
+		openSameWindowButton.setFont(font);
+		openSameWindowButton.addSelectionListener(new SelectionAdapter()
+        {
+            public void widgetSelected(SelectionEvent e) 
+            {
+                openPerspMode = IPreferenceConstants.OPM_ACTIVE_PAGE;
+            }
+        });
+		openNewWindowButton = new Button(buttonComposite, SWT.RADIO);
+		openNewWindowButton.setText(OPM_NEW_WINDOW);
+		openNewWindowButton
+				.setSelection(IPreferenceConstants.OPM_NEW_WINDOW == openPerspMode);
+		openNewWindowButton.setFont(font);
+		openNewWindowButton.addSelectionListener(new SelectionAdapter()
+        {
+            public void widgetSelected(SelectionEvent e) 
+            {
+                openPerspMode = IPreferenceConstants.OPM_NEW_WINDOW;
+            }
+        });
+	}
+
+	/**
+	 * Create a table of 3 buttons to enable the user to manage customized
+	 * perspectives.
+	 *
+	 * @param parent
+	 *            the parent for the button parent
+	 * @return Composite that the buttons are created in.
+	 */
+	protected Composite createCustomizePerspective(Composite parent) {
+
+		Font font = parent.getFont();
+
+		// define container & its gridding
+		Composite perspectivesComponent = new Composite(parent, SWT.NONE);
+		perspectivesComponent.setLayoutData(new GridData(GridData.FILL_BOTH));
+		perspectivesComponent.setFont(parent.getFont());
+
+		GridLayout layout = new GridLayout();
+		layout.numColumns = 2;
+		layout.marginWidth = 0;
+		layout.marginHeight = 0;
+		perspectivesComponent.setLayout(layout);
+
+		// Add the label
+		Label label = new Label(perspectivesComponent, SWT.LEFT);
+		label.setText(WorkbenchMessages.get().PerspectivesPreference_available);
+		GridData data = new GridData();
+		data.horizontalSpan = 2;
+		label.setLayoutData(data);
+		label.setFont(font);
+
+		// Add perspectivesTable.
+		perspectivesTable = new Table(perspectivesComponent, SWT.H_SCROLL | SWT.V_SCROLL
+				| SWT.BORDER);
+	    perspectivesTable.addSelectionListener(new SelectionAdapter()
+        {
+            public void widgetSelected(SelectionEvent e) 
+            {
+                updateButtons();
+            }
+        });
+        perspectivesTable.setFont(font);
+
+		data = new GridData(GridData.FILL_BOTH);
+		data.grabExcessHorizontalSpace = true;
+		data.grabExcessVerticalSpace = true;
+		perspectivesTable.setLayoutData(data);
+
+		// Populate the perspectivesTable
+		IPerspectiveDescriptor[] persps = perspectiveRegistry.getPerspectives();
+		perspectives = new ArrayList<>(persps.length);
+		for (int i = 0; i < persps.length; i++) {
+			perspectives.add(i, persps[i]);
+		}
+		Collections.sort(perspectives, comparator);
+		defaultPerspectiveId = perspectiveRegistry.getDefaultPerspective();
+		updatePerspectivesTable();
+
+		// Create vertical button bar.
+		Composite buttonBar = (Composite) createVerticalButtonBar(perspectivesComponent);
+		data = new GridData(GridData.FILL_VERTICAL);
+		buttonBar.setLayoutData(data);
+
+		//Add note label
+		String NOTE_LABEL = WorkbenchMessages.get().Preference_note;
+		String REVERT_NOTE = WorkbenchMessages.get().RevertPerspective_note;
+		Composite noteComposite = createNoteComposite(font, parent,
+                NOTE_LABEL, REVERT_NOTE);
+        GridData noteData = new GridData();
+        noteData.horizontalSpan = 2;
+        noteComposite.setLayoutData(noteData);
+		return perspectivesComponent;
+	}
+
+	/**
+	 * Creates a new vertical button with the given id.
+	 * <p>
+	 * The default implementation of this framework method creates a standard
+	 * push button, registers for selection events including button presses and
+	 * help requests, and registers default buttons with its shell. The button
+	 * id is stored as the buttons client data.
+	 * </p>
+	 *
+	 * @param parent
+	 *            the parent composite
+	 * @param label
+	 *            the label from the button
+	 * @param defaultButton
+	 *            <code>true</code> if the button is to be the default button,
+	 *            and <code>false</code> otherwise
+	 * @return Button The created button.
+	 */
+	protected Button createVerticalButton(Composite parent, String label,
+			boolean defaultButton) {
+		Button button = new Button(parent, SWT.PUSH);
+
+		button.setText(label);
+
+		GridData data = setButtonLayoutData(button);
+		data.horizontalAlignment = GridData.FILL;
+
+		button.addSelectionListener(new SelectionAdapter()
+        {
+            public void widgetSelected(SelectionEvent event) 
+            {
+                verticalButtonPressed(event.widget);
+            }
+        });
+		button.setToolTipText(label);
+		if (defaultButton) {
+			Shell shell = parent.getShell();
+			if (shell != null) {
+				shell.setDefaultButton(button);
+			}
+		}
+		button.setFont(parent.getFont());
+		return button;
+	}
+
+	/**
+	 * Creates and returns the vertical button bar.
+	 *
+	 * @param parent
+	 *            the parent composite to contain the button bar
+	 * @return the button bar control
+	 */
+	protected Control createVerticalButtonBar(Composite parent) {
+		// Create composite.
+		Composite composite = new Composite(parent, SWT.NULL);
+
+		// create a layout with spacing and margins appropriate for the font
+		// size.
+		GridLayout layout = new GridLayout();
+		layout.numColumns = 1;
+		layout.marginWidth = 5;
+		layout.marginHeight = 0;
+		layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
+		layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
+		composite.setLayout(layout);
+		composite.setFont(parent.getFont());
+
+		// Add the buttons to the button bar.
+		setDefaultButton = createVerticalButton(composite, WorkbenchMessages.get().PerspectivesPreference_MakeDefault, false);
+		setDefaultButton.setToolTipText(WorkbenchMessages.get().PerspectivesPreference_MakeDefaultTip);
+
+		revertButton = createVerticalButton(composite, WorkbenchMessages.get().PerspectivesPreference_Reset, false);
+		revertButton.setToolTipText(WorkbenchMessages.get().PerspectivesPreference_ResetTip);
+
+		deleteButton = createVerticalButton(composite, WorkbenchMessages.get().PerspectivesPreference_Delete, false);
+		deleteButton.setToolTipText(WorkbenchMessages.get().PerspectivesPreference_DeleteTip);
+		updateButtons();
+
+		return composite;
+	}
+
+	/**
+	 * @see IWorkbenchPreferencePage
+	 */
+	@Override
+	public void init(IWorkbench aWorkbench) {
+		this.workbench = aWorkbench;
+		this.perspectiveRegistry = (PerspectiveRegistry) workbench
+				.getPerspectiveRegistry();
+		IPreferenceStore store = WorkbenchPlugin.getDefault()
+				.getPreferenceStore();
+		setPreferenceStore(store);
+
+		openPerspMode = store.getInt(IPreferenceConstants.OPEN_PERSP_MODE);
+	}
+
+	/**
+	 * The default button has been pressed.
+	 */
+	@Override
+	protected void performDefaults() {
+		//Project perspective preferences
+		IPreferenceStore store = WorkbenchPlugin.getDefault()
+				.getPreferenceStore();
+
+		openPerspMode = store
+				.getDefaultInt(IPreferenceConstants.OPEN_PERSP_MODE);
+		openSameWindowButton
+				.setSelection(IPreferenceConstants.OPM_ACTIVE_PAGE == openPerspMode);
+		openNewWindowButton
+				.setSelection(IPreferenceConstants.OPM_NEW_WINDOW == openPerspMode);
+
+		String currentDefault = perspectiveRegistry.getDefaultPerspective();
+
+		int index = indexOf(currentDefault);
+		if (index >= 0){
+			defaultPerspectiveId = currentDefault;
+			updatePerspectivesTable();
+			perspectivesTable.setSelection(index);
+		}
+
+		String newDefault = PrefUtil.getAPIPreferenceStore().getDefaultString(
+                IWorkbenchPreferenceConstants.DEFAULT_PERSPECTIVE_ID);
+
+		IPerspectiveDescriptor desc = null;
+        if (newDefault != null) {
+			desc = workbench.getPerspectiveRegistry().findPerspectiveWithId(newDefault);
+		}
+        if (desc == null) {
+        	newDefault = workbench.getPerspectiveRegistry().getDefaultPerspective();
+        }
+
+        defaultPerspectiveId = newDefault;
+        updatePerspectivesTable();
+
+	}
+
+	/**
+	 * Look up the index of the perpective with the given if.
+	 * @param perspectiveId or <code>null</code>
+	 * @return int -1 if it cannot be found
+	 */
+	private int indexOf(String perspectiveId) {
+		if (perspectiveId == null) {
+			return -1;
+		}
+		PerspectiveDescriptor[] descriptors =
+			new PerspectiveDescriptor[perspectives.size()];
+		perspectives.toArray(descriptors);
+		for (int i = 0; i < descriptors.length; i++) {
+			PerspectiveDescriptor descriptor = descriptors[i];
+			if(descriptor.getId().equals(perspectiveId)) {
+				return i;
+			}
+		}
+		return -1;
+	}
+
+	/**
+	 * Return true if there are no open instances of the perspective.  If there are open
+	 * instances of the perspective prompt the user and return true if the user answers "yes"
+	 * to the delete prompt.
+	 *
+	 * @return boolean <code>true</code> if it is OK to delete the perspective
+	 *         either because there are no open instances or the user has
+	 *         confirmed the deletion.
+	 */
+	private boolean canDeletePerspective(IPerspectiveDescriptor desc) {
+
+		MApplication application = ((Workbench) workbench).getApplication();
+		EModelService modelService = application.getContext().get(EModelService.class);
+
+		if (modelService.findElements(application, desc.getId(), MPerspective.class, null)
+				.isEmpty())
+			return true;
+
+		return MessageDialog.openQuestion(
+				getShell(),
+				WorkbenchMessages.get().PerspectivesPreference_perspectiveopen_title,
+				NLS.bind(WorkbenchMessages.get().PerspectivesPreference_perspectiveopen_message,
+						desc.getLabel()));
+	}
+
+	/**
+	 * Apply the user's changes if any
+	 */
+	@Override
+	public boolean performOk() {
+		// Set the default perspective
+		if (!Util.equals(defaultPerspectiveId, perspectiveRegistry.getDefaultPerspective())) {
+			perspectiveRegistry.setDefaultPerspective(defaultPerspectiveId);
+		}
+
+		// Don't bother figuring out which window a perspective may be open in,
+		// the number of windows will be small.
+
+		for (IPerspectiveDescriptor perspective : perspToDelete) {
+			IWorkbenchWindow[] windows = workbench.getWorkbenchWindows();
+			for (IWorkbenchWindow window : windows) {
+				IWorkbenchPage[] pages = window.getPages();
+				for (IWorkbenchPage page : pages) {
+					page.closePerspective(perspective, true, false);
+				}
+			}
+			perspectiveRegistry.deletePerspectives(perspToDelete);
+		}
+
+        // Revert perspectives
+		for (IPerspectiveDescriptor perspective : perspToRevert) {
+			perspectiveRegistry.revertPerspective(perspective);
+		}
+
+		IPreferenceStore store = getPreferenceStore();
+
+		// store the open perspective mode setting
+		store.setValue(IPreferenceConstants.OPEN_PERSP_MODE, openPerspMode);
+
+		// save both the API prefs and the internal prefs
+		// the API prefs are modified by
+		// PerspectiveRegistry.setDefaultPerspective
+		PrefUtil.savePrefs();
+
+		return true;
+	}
+
+	/**
+	 * Update the button enablement state.
+	 */
+	protected void updateButtons() {
+		// Get selection.
+		int index = perspectivesTable.getSelectionIndex();
+
+		// Map it to the perspective descriptor
+		PerspectiveDescriptor desc = null;
+		if (index > -1) {
+			desc = (PerspectiveDescriptor) perspectives.get(index);
+		}
+
+		// Do enable.
+		if (desc != null) {
+			revertButton.setEnabled(desc.isPredefined() && desc.hasCustomDefinition()
+					&& !perspToRevert.contains(desc));
+			deleteButton.setEnabled(!desc.isPredefined());
+			setDefaultButton.setEnabled(true);
+		} else {
+			revertButton.setEnabled(false);
+			deleteButton.setEnabled(false);
+			setDefaultButton.setEnabled(false);
+		}
+	}
+
+	/**
+	 * Update the perspectivesTable.
+	 */
+	protected void updatePerspectivesTable() {
+        // Populate the table with the items
+		perspectivesTable.removeAll();
+		for (int i = 0; i < perspectives.size(); i++) {
+        	PerspectiveDescriptor persp = (PerspectiveDescriptor) perspectives.get(i);
+        	newPerspectivesTableItem(persp, i, false);
+        }
+    }
+
+	/**
+	 * Create a new tableItem using given perspective, and set image for the new item.
+	 */
+	protected TableItem newPerspectivesTableItem(IPerspectiveDescriptor persp,
+            int index, boolean selected) {
+
+        ImageDescriptor image = persp.getImageDescriptor();
+
+        TableItem item = new TableItem(perspectivesTable, SWT.NULL, index);
+        if (image != null) {
+            Descriptors.setImage(item, image);
+        }
+        String label=persp.getLabel();
+        if (persp.getId().equals(defaultPerspectiveId)){
+			label = NLS.bind(WorkbenchMessages.get().PerspectivesPreference_defaultLabel, label );
+
+		}
+        item.setText(label);
+        item.setData(persp);
+        if (selected) {
+        	perspectivesTable.setSelection(index);
+        }
+
+        return item;
+    }
+
+    /**
+	 * Notifies that this page's button with the given id has been pressed.
+	 *
+	 * @param button
+	 *            the button that was pressed
+	 */
+	protected void verticalButtonPressed(Widget button) {
+		// Get selection.
+		int index = perspectivesTable.getSelectionIndex();
+
+		// Map it to the perspective descriptor
+		PerspectiveDescriptor desc = null;
+		if (index > -1) {
+			desc = (PerspectiveDescriptor) perspectives.get(index);
+		} else {
+			return;
+		}
+
+		// Take action.
+		if (button == revertButton) {
+			if (!perspToRevert.contains(desc)) {
+				perspToRevert.add(desc);
+			}
+		} else if (button == deleteButton) {
+			if (!perspToDelete.contains(desc)) {
+				if (canDeletePerspective(desc)) {
+					perspToDelete.add(desc);
+					perspToRevert.remove(desc);
+					perspectives.remove(desc);
+					updatePerspectivesTable();
+				}
+
+			}
+		} else if (button == setDefaultButton) {
+			defaultPerspectiveId = desc.getId();
+			updatePerspectivesTable();
+			perspectivesTable.setSelection(index);
+		}
+
+		updateButtons();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/PreferenceBoldLabelProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/PreferenceBoldLabelProvider.java
new file mode 100644
index 0000000..bb7ade1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/PreferenceBoldLabelProvider.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.dialogs;
+
+import org.eclipse.jface.preference.PreferenceLabelProvider;
+import org.eclipse.jface.viewers.IFontProvider;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.ui.dialogs.FilteredTree;
+import org.eclipse.ui.dialogs.PatternFilter;
+
+/**
+ * This PreferenceBoldLabelProvider will bold those elements which really match
+ * the search contents
+ */
+public class PreferenceBoldLabelProvider extends PreferenceLabelProvider implements IFontProvider {
+
+	private FilteredTree filterTree;
+
+	private PatternFilter filterForBoldElements;
+
+	PreferenceBoldLabelProvider(FilteredTree filterTree) {
+		this.filterTree = filterTree;
+		this.filterForBoldElements= filterTree.getPatternFilter();
+	}
+
+	@Override
+	public Font getFont(Object element) {
+		return FilteredTree.getBoldFont(element, filterTree,
+				filterForBoldElements);
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/PreferenceHistoryEntry.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/PreferenceHistoryEntry.java
new file mode 100644
index 0000000..098d1e8
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/PreferenceHistoryEntry.java
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.dialogs;
+
+import org.eclipse.core.runtime.Assert;
+
+/**
+ * A preference history entry.
+ *
+ * @since 3.1
+ */
+final class PreferenceHistoryEntry {
+	private String id;
+	private String label;
+	private Object argument;
+
+	/**
+	 * Creates a new entry.
+	 *
+	 * @param id the preference page id
+	 * @param label the label to display, usually the preference page label
+	 * @param argument an argument to pass to the preference page, may be
+	 *        <code>null</code>
+	 */
+	public PreferenceHistoryEntry(String id, String label, Object argument) {
+		Assert.isLegal(id != null);
+		Assert.isLegal(label != null);
+		this.id= id;
+		this.label= label;
+		this.argument= argument;
+	}
+	/**
+	 * Returns the preference page id.
+	 *
+	 * @return the preference page id
+	 */
+	public String getId() {
+		return id;
+	}
+	/**
+	 * Returns the preference page argument.
+	 *
+	 * @return the preference page argument
+	 */
+	public Object getArgument() {
+		return argument;
+	}
+	/**
+	 * Returns the preference page label.
+	 *
+	 * @return the preference page label
+	 */
+	public String getLabel() {
+		return label;
+	}
+	/*
+	 * @see java.lang.Object#toString()
+	 */
+	@Override
+	public String toString() {
+		if (argument == null) {
+			return id;
+		}
+		return id + "(" + argument + ")"; //$NON-NLS-1$ //$NON-NLS-2$
+	}
+	/*
+	 * @see java.lang.Object#equals(java.lang.Object)
+	 */
+	@Override
+	public boolean equals(Object obj) {
+		if (obj instanceof PreferenceHistoryEntry) {
+			PreferenceHistoryEntry other= (PreferenceHistoryEntry) obj;
+			return id.equals(other.id)
+					&& (argument == null && other.argument == null
+							|| argument.equals(other.argument));
+		}
+		return super.equals(obj);
+	}
+	/*
+	 * @see java.lang.Object#hashCode()
+	 */
+	@Override
+	public int hashCode() {
+		int argHash= argument == null ? 0 : argument.hashCode() & 0x0000ffff;
+		return id.hashCode() << 16 | argHash;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/PreferenceNodeFilter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/PreferenceNodeFilter.java
new file mode 100644
index 0000000..391df70
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/PreferenceNodeFilter.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.dialogs;
+
+import java.util.Collection;
+import java.util.HashSet;
+import org.eclipse.jface.preference.IPreferenceNode;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+
+/**
+ * The PreferenceNodeFilter is a filter that only matches
+ * a set of ids.
+ */
+public class PreferenceNodeFilter extends ViewerFilter {
+
+	Collection ids = new HashSet();
+
+	/**
+	 * Create a new instance of the receiver on a
+	 * list of filteredIds.
+	 * @param filteredIds The collection of ids that
+	 * will be shown.
+	 */
+	public PreferenceNodeFilter(String[] filteredIds) {
+		super();
+		for (String filteredId : filteredIds) {
+			ids.add(filteredId);
+		}
+	}
+
+	@Override
+	public boolean select(Viewer viewer, Object parentElement, Object element) {
+		return checkNodeAndChildren((IPreferenceNode) element);
+	}
+
+	/**
+	 * Check to see if the node or any of its children
+	 * have an id in the ids.
+	 * @param node WorkbenchPreferenceNode
+	 * @return boolean <code>true</code> if node or oe of its children
+	 * has an id in the ids.
+	 */
+	private boolean checkNodeAndChildren(IPreferenceNode node) {
+		if(ids.contains(node.getId())) {
+			return true;
+		}
+
+		for (IPreferenceNode subNode : node.getSubNodes()) {
+			if(checkNodeAndChildren(subNode)) {
+				return true;
+			}
+
+		}
+		return false;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/PreferencePageHistory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/PreferencePageHistory.java
new file mode 100644
index 0000000..8f77cbb
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/PreferencePageHistory.java
@@ -0,0 +1,335 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *     Robert Roth <robert.roth.off@gmail.com> - Bug 337788
+ *******************************************************************************/
+package org.eclipse.ui.internal.dialogs;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.ActionContributionItem;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.IMenuCreator;
+import org.eclipse.jface.action.ToolBarManager;
+import org.eclipse.jface.commands.ActionHandler;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.ui.ActiveShellExpression;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.handlers.IHandlerActivation;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+
+/**
+ * History for navigating preference pages.
+ *
+ * @since 3.1
+ */
+class PreferencePageHistory {
+
+	/**
+	 * The history toolbar.
+	 */
+	private ToolBarManager historyToolbar;
+
+	/**
+	 * A list of preference history domain elements that stores the history of
+	 * the visited preference pages.
+	 */
+	private List history = new ArrayList();
+
+	/**
+	 * Stores the current entry into <code>history</code> and
+	 * <code>historyLabels</code>.
+	 */
+	private int historyIndex = -1;
+
+	/**
+	 * The preference dialog we implement the history for.
+	 */
+	private final FilteredPreferenceDialog dialog;
+
+	/**
+	 * The handler submission for these controls.
+	 */
+	private Set activations = new HashSet();
+
+	/**
+	 * Creates a new history for the given dialog.
+	 *
+	 * @param dialog
+	 *            the preference dialog to create a history for
+	 */
+	public PreferencePageHistory(FilteredPreferenceDialog dialog) {
+		this.dialog = dialog;
+	}
+
+	/**
+	 * Returns the preference page path (for now: its id) for the history at
+	 * <code>index</code>.
+	 *
+	 * @param index
+	 *            the index into the history
+	 * @return the preference page path at <code>index</code> or
+	 *         <code>null</code> if <code>index</code> is not a valid
+	 *         history index
+	 */
+	private PreferenceHistoryEntry getHistoryEntry(int index) {
+		if (index >= 0 && index < history.size()) {
+			return (PreferenceHistoryEntry) history.get(index);
+		}
+		return null;
+	}
+
+	/**
+	 * Adds the preference page path and its label to the page history.
+	 *
+	 * @param entry
+	 *            the preference page history entry
+	 */
+	public void addHistoryEntry(PreferenceHistoryEntry entry) {
+		if (historyIndex == -1 || !history.get(historyIndex).equals(entry)) {
+			history.subList(historyIndex + 1, history.size()).clear();
+			history.add(entry);
+			historyIndex++;
+			updateHistoryControls();
+		}
+	}
+
+	/**
+	 * Sets the current page to be the one corresponding to the given index in
+	 * the page history.
+	 *
+	 * @param index
+	 *            the index into the page history
+	 */
+	private void jumpToHistory(int index) {
+		if (index >= 0 && index < history.size()) {
+			historyIndex = index;
+			dialog.setCurrentPageId(getHistoryEntry(index).getId());
+		}
+		updateHistoryControls();
+	}
+
+	/**
+	 * Updates the history controls.
+	 *
+	 */
+	private void updateHistoryControls() {
+		historyToolbar.update(false);
+		for (IContributionItem item : historyToolbar.getItems()) {
+			item.update(IAction.ENABLED);
+			item.update(IAction.TOOL_TIP_TEXT);
+		}
+	}
+
+	/**
+	 * Creates the history toolbar and initializes <code>historyToolbar</code>.
+	 *
+	 * @param historyBar
+	 * @param manager
+	 * @return the control of the history toolbar
+	 */
+	public ToolBar createHistoryControls(ToolBar historyBar,
+			ToolBarManager manager) {
+
+		historyToolbar = manager;
+		/**
+		 * Superclass of the two for-/backward actions for the history.
+		 */
+		abstract class HistoryNavigationAction extends Action implements
+				IMenuCreator {
+			private Menu lastMenu;
+
+			protected final static int MAX_ENTRIES = 5;
+
+			HistoryNavigationAction() {
+				super("", IAction.AS_DROP_DOWN_MENU); //$NON-NLS-1$
+			}
+
+			@Override
+			public IMenuCreator getMenuCreator() {
+				return this;
+			}
+
+			@Override
+			public void dispose() {
+				if (lastMenu != null) {
+					lastMenu.dispose();
+					lastMenu = null;
+				}
+			}
+
+			@Override
+			public Menu getMenu(Control parent) {
+				if (lastMenu != null) {
+					lastMenu.dispose();
+				}
+				lastMenu = new Menu(parent);
+				createEntries(lastMenu);
+				return lastMenu;
+
+			}
+
+			@Override
+			public Menu getMenu(Menu parent) {
+				return null;
+			}
+
+			protected void addActionToMenu(Menu parent, IAction action) {
+				ActionContributionItem item = new ActionContributionItem(action);
+				item.fill(parent, -1);
+			}
+
+			protected abstract void createEntries(Menu menu);
+		}
+
+		/**
+		 * Menu entry for the toolbar dropdowns. Instances are direct-jump
+		 * entries in the navigation history.
+		 */
+		class HistoryItemAction extends Action {
+
+			private final int index;
+
+			HistoryItemAction(int index, String label) {
+				super(label, IAction.AS_PUSH_BUTTON);
+				this.index = index;
+			}
+
+			@Override
+			public void run() {
+				jumpToHistory(index);
+			}
+		}
+
+		HistoryNavigationAction backward = new HistoryNavigationAction() {
+			@Override
+			public void run() {
+				jumpToHistory(historyIndex - 1);
+			}
+
+			@Override
+			public boolean isEnabled() {
+				boolean enabled = historyIndex > 0;
+				if (enabled) {
+					setToolTipText(NLS.bind(WorkbenchMessages.get().NavigationHistoryAction_backward_toolTipName,getHistoryEntry(historyIndex - 1).getLabel() ));
+				} else {
+					setToolTipText(WorkbenchMessages.get().NavigationHistoryAction_backward_toolTip);
+				}
+				return enabled;
+			}
+
+			@Override
+			protected void createEntries(Menu menu) {
+				int limit = Math.max(0, historyIndex - MAX_ENTRIES);
+				for (int i = historyIndex - 1; i >= limit; i--) {
+					IAction action = new HistoryItemAction(i,
+							getHistoryEntry(i).getLabel());
+					addActionToMenu(menu, action);
+				}
+			}
+		};
+		backward.setText(WorkbenchMessages.get().NavigationHistoryAction_backward_text);
+		backward
+				.setActionDefinitionId(IWorkbenchCommandConstants.NAVIGATE_BACKWARD_HISTORY);
+		backward.setImageDescriptor(WorkbenchPlugin.getDefault()
+				.getSharedImages().getImageDescriptor(
+						ISharedImages.IMG_TOOL_BACK));
+		backward.setDisabledImageDescriptor(WorkbenchPlugin.getDefault()
+				.getSharedImages().getImageDescriptor(
+						ISharedImages.IMG_TOOL_BACK_DISABLED));
+		registerKeybindings(backward);
+		historyToolbar.add(backward);
+
+		HistoryNavigationAction forward = new HistoryNavigationAction() {
+			@Override
+			public void run() {
+				jumpToHistory(historyIndex + 1);
+			}
+
+			@Override
+			public boolean isEnabled() {
+				boolean enabled = historyIndex < history.size() - 1;
+				if (enabled) {
+					setToolTipText(NLS.bind(WorkbenchMessages.get().NavigationHistoryAction_forward_toolTipName, getHistoryEntry(historyIndex + 1).getLabel() ));
+				} else {
+					setToolTipText(WorkbenchMessages.get().NavigationHistoryAction_forward_toolTip);
+				}
+				return enabled;
+			}
+
+			@Override
+			protected void createEntries(Menu menu) {
+				int limit = Math.min(history.size(), historyIndex + MAX_ENTRIES
+						+ 1);
+				for (int i = historyIndex + 1; i < limit; i++) {
+					IAction action = new HistoryItemAction(i,
+							getHistoryEntry(i).getLabel());
+					addActionToMenu(menu, action);
+				}
+			}
+		};
+		forward.setText(WorkbenchMessages.get().NavigationHistoryAction_forward_text);
+		forward.setActionDefinitionId(IWorkbenchCommandConstants.NAVIGATE_FORWARD_HISTORY);
+		forward.setImageDescriptor(WorkbenchPlugin.getDefault()
+				.getSharedImages().getImageDescriptor(
+						ISharedImages.IMG_TOOL_FORWARD));
+		forward.setDisabledImageDescriptor(WorkbenchPlugin.getDefault()
+				.getSharedImages().getImageDescriptor(
+						ISharedImages.IMG_TOOL_FORWARD_DISABLED));
+		registerKeybindings(forward);
+		historyToolbar.add(forward);
+
+		return historyBar;
+	}
+
+	/**
+	 * Registers the given action with the workbench command support.
+	 *
+	 * @param action
+	 *            the action to register.
+	 */
+	private void registerKeybindings(IAction action) {
+		final IHandler handler = new ActionHandler(action);
+		final IHandlerService handlerService = PlatformUI.getWorkbench().getService(IHandlerService.class);
+		final IHandlerActivation activation = handlerService.activateHandler(
+				action.getActionDefinitionId(), handler,
+				new ActiveShellExpression(dialog.getShell()));
+		activations.add(activation);
+	}
+
+	/**
+	 * Dispose the receiver and clear out the references.
+	 *
+	 */
+	public void dispose() {
+		final IHandlerService handlerService = PlatformUI.getWorkbench().getService(IHandlerService.class);
+		final Iterator iterator = activations.iterator();
+		while (iterator.hasNext()) {
+			handlerService.deactivateHandler((IHandlerActivation) iterator
+					.next());
+		}
+		activations.clear();
+
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/PreferencePatternFilter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/PreferencePatternFilter.java
new file mode 100644
index 0000000..e88c712
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/PreferencePatternFilter.java
@@ -0,0 +1,125 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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
+ *     Jan-Hendrik Diederich, Bredex GmbH - bug 201052
+ *******************************************************************************/
+package org.eclipse.ui.internal.dialogs;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import org.eclipse.jface.preference.IPreferenceNode;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.ui.activities.WorkbenchActivityHelper;
+import org.eclipse.ui.dialogs.PatternFilter;
+import org.eclipse.ui.internal.preferences.WorkbenchPreferenceExtensionNode;
+
+/**
+ * A class that handles filtering preference node items based on a supplied
+ * matching string.
+ *
+ * @since 3.2
+ *
+ */
+public class PreferencePatternFilter extends PatternFilter {
+
+	/**
+	 * this cache is needed because
+	 * WorkbenchPreferenceExtensionNode.getKeywordLabels() is expensive. When it
+	 * tracks keyword changes effectivly than this cache can be removed.
+	 */
+	private Map keywordCache = new HashMap();
+
+	/**
+	 * Create a new instance of a PreferencePatternFilter
+	 *
+	 * @param isMatchItem
+	 */
+	public PreferencePatternFilter() {
+		super();
+	}
+
+	/*
+	 * Return true if the given Object matches with any possible keywords that
+	 * have been provided. Currently this is only applicable for preference and
+	 * property pages.
+	 */
+	private String[] getKeywords(Object element) {
+		List keywordList = new ArrayList();
+		if (element instanceof WorkbenchPreferenceExtensionNode) {
+			WorkbenchPreferenceExtensionNode workbenchNode = (WorkbenchPreferenceExtensionNode) element;
+
+			Collection keywordCollection = (Collection) keywordCache
+					.get(element);
+			if (keywordCollection == null) {
+				keywordCollection = workbenchNode.getKeywordLabels();
+				keywordCache.put(element, keywordCollection);
+			}
+			if (!keywordCollection.isEmpty()){
+				Iterator keywords = keywordCollection.iterator();
+				while (keywords.hasNext()) {
+					keywordList.add(keywords.next());
+				}
+			}
+		}
+		return (String[]) keywordList.toArray(new String[keywordList.size()]);
+	}
+
+	@Override
+	public boolean isElementSelectable(Object element) {
+		return element instanceof WorkbenchPreferenceExtensionNode;
+	}
+
+	@Override
+	public boolean isElementVisible(Viewer viewer, Object element) {
+	    if (WorkbenchActivityHelper.restrictUseOf(
+	            element))
+	        return false;
+
+		// Preference nodes are not differentiated based on category since
+		// categories are selectable nodes.
+		if (isLeafMatch(viewer, element)) {
+			return true;
+		}
+
+		ITreeContentProvider contentProvider = (ITreeContentProvider) ((TreeViewer) viewer)
+				.getContentProvider();
+		IPreferenceNode node = (IPreferenceNode) element;
+		Object[] children = contentProvider.getChildren(node);
+		// Will return true if any subnode of the element matches the search
+		if (filter(viewer, element, children).length > 0) {
+			return true;
+		}
+		return false;
+	}
+
+	@Override
+	protected boolean isLeafMatch(Viewer viewer, Object element) {
+		IPreferenceNode node = (IPreferenceNode) element;
+		String text = node.getLabelText();
+
+		if (wordMatches(text)) {
+			return true;
+		}
+
+		// Also need to check the keywords
+		for (String keyword : getKeywords(node)) {
+			if (wordMatches(keyword)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/PropertyDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/PropertyDialog.java
new file mode 100644
index 0000000..322bc06
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/PropertyDialog.java
@@ -0,0 +1,187 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     James Blackburn (Broadcom Corp.) - Bug 294628 multiple selection
+ *******************************************************************************/
+package org.eclipse.ui.internal.dialogs;
+
+import java.util.Iterator;
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.preference.PreferenceManager;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.model.IContributionService;
+import org.eclipse.ui.model.IWorkbenchAdapter;
+
+/**
+ * This dialog is created and shown when 'Properties' action is performed while
+ * an object is selected. It shows one or more pages registered for object's
+ * type.
+ */
+public class PropertyDialog extends FilteredPreferenceDialog {
+	private ISelection selection;
+
+	// The id of the last page that was selected
+	private static String lastPropertyId = null;
+
+	/**
+	 * Create a new property dialog.
+	 *
+	 * @param shell
+	 *            the parent shell
+	 * @param propertyPageId
+	 *            the property page id
+	 * @param element
+	 *            the adaptable element
+	 * @return the property dialog
+	 */
+	public static PropertyDialog createDialogOn(Shell shell,
+			final String propertyPageId, Object element) {
+
+		PropertyPageManager pageManager = new PropertyPageManager();
+		String title = "";//$NON-NLS-1$
+
+		if (element == null) {
+			return null;
+		}
+		// load pages for the selection
+		// fill the manager with contributions from the matching contributors
+		PropertyPageContributorManager.getManager().contribute(pageManager,
+				element);
+		// testing if there are pages in the manager
+		Iterator pages = pageManager.getElements(PreferenceManager.PRE_ORDER)
+				.iterator();
+		String name = getName(element);
+		if (!pages.hasNext()) {
+			MessageDialog.openInformation(shell,
+					WorkbenchMessages.get().PropertyDialog_messageTitle, NLS.bind(
+							WorkbenchMessages.get().PropertyDialog_noPropertyMessage,
+							name));
+			return null;
+		}
+		title = NLS
+				.bind(WorkbenchMessages.get().PropertyDialog_propertyMessage, name);
+		PropertyDialog propertyDialog = new PropertyDialog(shell, pageManager,
+				new StructuredSelection(element));
+
+		if (propertyPageId != null) {
+			propertyDialog.setSelectedNode(propertyPageId);
+		}
+		propertyDialog.create();
+
+		propertyDialog.getShell().setText(title);
+		PlatformUI.getWorkbench().getHelpSystem().setHelp(
+				propertyDialog.getShell(),
+				IWorkbenchHelpContextIds.PROPERTY_DIALOG);
+
+		return propertyDialog;
+
+	}
+
+	/**
+	 * Returns the name of the given element(s). Prints at most 3 names.
+	 *
+	 * @param element
+	 *            the element / IStructuredSelection
+	 * @return the name of the element
+	 */
+	private static String getName(Object element) {
+		Object[] elements;
+		if (element instanceof IStructuredSelection)
+			elements = ((IStructuredSelection) element).toArray();
+		else
+			elements = new Object[] { element };
+		StringBuffer sb = new StringBuffer();
+		// Print at most 3 entries...
+		for (int i = 0; i < elements.length; i++) {
+			element = elements[i];
+			if (i > 2) {
+				sb.append(" ..."); //$NON-NLS-1$
+				break;
+			}
+			IWorkbenchAdapter adapter = Adapters.adapt(element, IWorkbenchAdapter.class);
+			if (adapter != null) {
+				if (sb.length() > 0)
+					sb.append(", "); //$NON-NLS-1$
+				sb.append(adapter.getLabel(element));
+			}
+		}
+		return sb.toString();
+	}
+
+	/**
+	 * Create an instance of the receiver.
+	 *
+	 * @param parentShell
+	 * @param mng
+	 * @param selection
+	 */
+	public PropertyDialog(Shell parentShell, PreferenceManager mng,
+			ISelection selection) {
+		super(parentShell, mng);
+		setSelection(selection);
+	}
+
+	/**
+	 * Returns selection in the "Properties" action context.
+	 *
+	 * @return the selection
+	 */
+	public ISelection getSelection() {
+		return selection;
+	}
+
+	/**
+	 * Sets the selection that will be used to determine target object.
+	 *
+	 * @param newSelection
+	 *            the new selection
+	 */
+	public void setSelection(ISelection newSelection) {
+		selection = newSelection;
+	}
+
+	/**
+	 * Get the name of the selected item preference
+	 */
+	@Override
+	protected String getSelectedNodePreference() {
+		return lastPropertyId;
+	}
+
+	/**
+	 * Get the name of the selected item preference
+	 */
+	@Override
+	protected void setSelectedNodePreference(String pageId) {
+		lastPropertyId = pageId;
+	}
+
+	/**
+	 * Return the contributionType (used by the IContributionService).
+	 *
+	 * Override this with a more specific contribution type as required.
+	 *
+	 * @return a string, the contributionType
+	 */
+	@Override
+	protected String getContributionType() {
+		return IContributionService.TYPE_PROPERTY;
+	}
+
+
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/PropertyPageContributorManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/PropertyPageContributorManager.java
new file mode 100644
index 0000000..83ef276
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/PropertyPageContributorManager.java
@@ -0,0 +1,257 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Oakland Software (Francis Upton) <francisu@ieee.org> - bug 219273
+ *     James Blackburn (Broadcom Corp.) - Bug 294628 multiple selection
+ *******************************************************************************/
+package org.eclipse.ui.internal.dialogs;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
+import org.eclipse.jface.preference.PreferenceNode;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.internal.ObjectContributorManager;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.registry.PropertyPagesRegistryReader;
+
+/**
+ * Extends generic object contributor manager by loading property page
+ * contributors from the registry.
+ */
+
+public class PropertyPageContributorManager extends ObjectContributorManager {
+	private static PropertyPageContributorManager sharedInstance = null;
+
+	private class CategorizedPageNode {
+		RegistryPageContributor contributor;
+
+		CategorizedPageNode parent;
+
+		CategorizedPageNode(RegistryPageContributor page) {
+			contributor = page;
+		}
+
+		void setParent(CategorizedPageNode node) {
+			parent = node;
+		}
+
+	}
+
+	/**
+	 * The constructor.
+	 */
+	public PropertyPageContributorManager() {
+		super();
+		// load contributions on startup so that getContributors() returns the
+		// proper content
+		loadContributors();
+	}
+
+	/**
+	 * Given the object class, this method will find all the registered matching
+	 * contributors and sequentially invoke them to contribute to the property
+	 * page manager. Matching algorithm will also check subclasses and
+	 * implemented interfaces.
+	 *
+	 * If object is an IStructuredSelection then attempt to match all the
+	 * contained objects.
+	 *
+	 * @param manager
+	 * @param object
+	 * @return true if contribution took place, false otherwise.
+	 */
+	public boolean contribute(PropertyPageManager manager, Object object) {
+
+		Collection result = null;
+		if (object instanceof IStructuredSelection) {
+			Object[] objs = ((IStructuredSelection) object).toArray();
+			for (Object obj : objs) {
+				List contribs = getContributors(obj);
+				if (result == null)
+					result = new LinkedHashSet(contribs);
+				else
+					result.retainAll(contribs);
+			}
+		} else
+			result = getContributors(object);
+
+		if (result == null || result.size() == 0) {
+			return false;
+		}
+
+		// Build the category nodes
+		List catNodes = buildNodeList(result);
+		Iterator resultIterator = catNodes.iterator();
+
+		// K(CategorizedPageNode) V(PreferenceNode - property page)
+		Map catPageNodeToPages = new HashMap();
+
+		// Allow each contributor to add its page to the manager.
+		boolean actualContributions = false;
+		while (resultIterator.hasNext()) {
+			CategorizedPageNode next = (CategorizedPageNode) resultIterator
+					.next();
+			IPropertyPageContributor ppcont = next.contributor;
+			if (!ppcont.isApplicableTo(object)) {
+				continue;
+			}
+			PreferenceNode page = ppcont.contributePropertyPage(manager, object);
+			if (page != null) {
+				catPageNodeToPages.put(next, page);
+				actualContributions = true;
+			}
+		}
+
+		// Fixup the parents in each page
+		if (actualContributions) {
+			resultIterator = catNodes.iterator();
+			while (resultIterator.hasNext()) {
+				CategorizedPageNode next = (CategorizedPageNode) resultIterator
+						.next();
+				PreferenceNode child = (PreferenceNode) catPageNodeToPages.get(next);
+				if (child == null)
+					continue;
+				PreferenceNode parent = null;
+				if (next.parent != null)
+					parent = (PreferenceNode) catPageNodeToPages.get(next.parent);
+
+				if (parent == null) {
+					manager.addToRoot(child);
+				} else {
+					parent.add(child);
+				}
+			}
+		}
+		return actualContributions;
+	}
+
+	/**
+	 * Build the list of nodes to be sorted.
+	 * @param nodes
+	 * @return List of CategorizedPageNode
+	 */
+	private List buildNodeList(Collection nodes) {
+		Hashtable mapping = new Hashtable();
+
+		Iterator nodesIterator = nodes.iterator();
+		while(nodesIterator.hasNext()){
+			RegistryPageContributor page = (RegistryPageContributor) nodesIterator.next();
+			mapping.put(page.getPageId(),new CategorizedPageNode(page));
+		}
+
+		Iterator values = mapping.values().iterator();
+		List returnValue = new ArrayList();
+		while(values.hasNext()){
+			CategorizedPageNode next = (CategorizedPageNode) values.next();
+			returnValue.add(next);
+			if(next.contributor.getCategory() == null) {
+				continue;
+			}
+			Object parent = mapping.get(next.contributor.getCategory());
+			if(parent != null) {
+				next.setParent((CategorizedPageNode) parent);
+			}
+		}
+		return returnValue;
+	}
+
+	/**
+	 * Ideally, shared instance should not be used and manager should be located
+	 * in the workbench class.
+	 * @return PropertyPageContributorManager
+	 */
+	public static PropertyPageContributorManager getManager() {
+		if (sharedInstance == null) {
+			sharedInstance = new PropertyPageContributorManager();
+		}
+		return sharedInstance;
+	}
+
+	/**
+	 * Loads property page contributors from the registry.
+	 */
+	private void loadContributors() {
+		PropertyPagesRegistryReader reader = new PropertyPagesRegistryReader(
+				this);
+		reader.registerPropertyPages(Platform.getExtensionRegistry());
+	}
+
+    @Override
+	public void addExtension(IExtensionTracker tracker, IExtension extension) {
+		for (IConfigurationElement addedElement : extension.getConfigurationElements()) {
+            PropertyPagesRegistryReader reader = new PropertyPagesRegistryReader(this);
+            reader.readElement(addedElement);
+        }
+    }
+
+	/**
+	 * Return the contributors for element filters on the enablement.
+	 * @param element
+	 * @return Collection of PropertyPageContribution
+	 */
+	public Collection getApplicableContributors(Object element) {
+		if (element instanceof IStructuredSelection)
+			return getApplicableContributors((IStructuredSelection) element);
+		Collection contributors = getContributors(element);
+		Collection result = new ArrayList();
+		for (Iterator iter = contributors.iterator(); iter.hasNext();) {
+			RegistryPageContributor contributor = (RegistryPageContributor) iter.next();
+			if(contributor.isApplicableTo(element))
+				result.add(contributor);
+
+		}
+		return result;
+	}
+
+	/**
+	 * Get applicable contributors for multiple selection
+	 *
+	 * @param selection
+	 * @return Collection of applicable property page contributors
+	 * @since 3.7
+	 */
+	public Collection getApplicableContributors(IStructuredSelection selection) {
+		Iterator it = selection.iterator();
+		Collection result = null;
+		while (it.hasNext()) {
+			Object element = it.next();
+			Collection collection = getApplicableContributors(element);
+			if (result == null)
+				result = new LinkedHashSet(collection);
+			else
+				result.retainAll(collection);
+		}
+		if (result != null && !result.isEmpty() && selection.size() > 1) {
+			// only add contributors which can handle multi selection
+			it = result.iterator();
+			while (it.hasNext()) {
+				RegistryPageContributor contrib = (RegistryPageContributor) it
+						.next();
+				if (!contrib.supportsMultipleSelection())
+					it.remove();
+			}
+		}
+		return result;
+	}
+
+	@Override
+	protected String getExtensionPointFilter() {
+		return IWorkbenchRegistryConstants.PL_PROPERTY_PAGES;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/PropertyPageManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/PropertyPageManager.java
new file mode 100644
index 0000000..9341860
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/PropertyPageManager.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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
+ *     Jan-Hendrik Diederich, Bredex GmbH - bug 201052
+ *     Oakland Software (Francis Upton) <francisu@ieee.org> - bug 219273
+ *******************************************************************************/
+package org.eclipse.ui.internal.dialogs;
+
+import org.eclipse.jface.preference.PreferenceManager;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.preferences.WorkbenchPreferenceExpressionNode;
+
+/**
+ * This class is created to avoid mentioning preferences
+ * in this context. Ideally, JFace preference classes should be
+ * renamed into something more generic (for example,
+ * 'TreeNavigationDialog').
+ */
+
+public class PropertyPageManager extends PreferenceManager {
+	/**
+	 * The constructor.
+	 */
+	public PropertyPageManager() {
+		super(WorkbenchPlugin.PREFERENCE_PAGE_CATEGORY_SEPARATOR,
+				new WorkbenchPreferenceExpressionNode("")); //$NON-NLS-1$
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/PropertyPageNode.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/PropertyPageNode.java
new file mode 100644
index 0000000..565da2d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/PropertyPageNode.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.dialogs;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.preference.IPreferencePage;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.internal.preferences.WorkbenchPreferenceExtensionNode;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+/**
+ * Property page node allows us to achieve presence in the property page dialog
+ * without loading the page itself, thus loading the contributing plugin.
+ * Only when the user selects the page will it be loaded.
+ */
+public class PropertyPageNode extends WorkbenchPreferenceExtensionNode {
+    private RegistryPageContributor contributor;
+
+	private IPreferencePage page;
+
+    private Image icon;
+
+    private Object element;
+
+    /**
+     * Create a new instance of the receiver.
+     * @param contributor
+     * @param element
+     */
+    public PropertyPageNode(RegistryPageContributor contributor,
+            Object element) {
+        super(contributor.getPageId(), contributor.getConfigurationElement());
+        this.contributor = contributor;
+        this.element = element;
+    }
+
+    /**
+     * Creates the preference page this node stands for. If the page is null,
+     * it will be created by loading the class. If loading fails,
+     * empty filler page will be created instead.
+     */
+    @Override
+	public void createPage() {
+        try {
+            page = contributor.createPage(element);
+        } catch (CoreException e) {
+            // Just inform the user about the error. The details are
+            // written to the log by now.
+            IStatus errStatus = StatusUtil.newStatus(e.getStatus(), WorkbenchMessages.get().PropertyPageNode_errorMessage);
+            StatusManager.getManager().handle(errStatus, StatusManager.SHOW);
+            page = new EmptyPropertyPage();
+        }
+        setPage(page);
+    }
+
+    @Override
+	public void disposeResources() {
+
+        if (page != null) {
+            page.dispose();
+            page = null;
+        }
+        if (icon != null) {
+            icon.dispose();
+            icon = null;
+        }
+    }
+
+    /**
+     * Returns page icon, if defined.
+     */
+    @Override
+	public Image getLabelImage() {
+        if (icon == null) {
+            ImageDescriptor desc = contributor.getPageIcon();
+            if (desc != null) {
+                icon = desc.createImage();
+            }
+        }
+        return icon;
+    }
+
+    /**
+     * Returns page label as defined in the registry.
+     */
+    @Override
+	public String getLabelText() {
+        return contributor.getPageName();
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/RegistryPageContributor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/RegistryPageContributor.java
new file mode 100644
index 0000000..739f95a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/RegistryPageContributor.java
@@ -0,0 +1,486 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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
+ *     Jan-Hendrik Diederich, Bredex GmbH - bug 201052
+ *     Oakland Software (Francis Upton) <francisu@ieee.org> - bug 223808
+ *     James Blackburn (Broadcom Corp.) - Bug 294628 multiple selection
+ *******************************************************************************/
+package org.eclipse.ui.internal.dialogs;
+
+import java.lang.ref.SoftReference;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import org.eclipse.core.expressions.EvaluationContext;
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.ExpressionConverter;
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.preference.IPreferencePage;
+import org.eclipse.jface.preference.PreferenceNode;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.IActionFilter;
+import org.eclipse.ui.IPluginContribution;
+import org.eclipse.ui.IWorkbenchPropertyPage;
+import org.eclipse.ui.IWorkbenchPropertyPageMulti;
+import org.eclipse.ui.SelectionEnabler;
+import org.eclipse.ui.internal.IWorkbenchConstants;
+import org.eclipse.ui.internal.LegacyResourceSupport;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.registry.CategorizedPageRegistryReader;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.registry.PropertyPagesRegistryReader;
+import org.eclipse.ui.model.IWorkbenchAdapter;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+/**
+ * This property page contributor is created from page entry in the registry.
+ * Since instances of this class are created by the workbench, there is no
+ * danger of premature loading of plugins.
+ */
+
+public class RegistryPageContributor implements IPropertyPageContributor,
+		IAdaptable,
+		IPluginContribution
+		{
+	private static final String CHILD_ENABLED_WHEN = "enabledWhen"; //$NON-NLS-1$
+
+	private String pageId;
+
+	/**
+	 * The list of subpages (immediate children) of this node (element type:
+	 * <code>RegistryPageContributor</code>).
+	 */
+	private Collection subPages = new ArrayList();
+
+	private boolean adaptable = false;
+
+	/**
+	 * Flag which indicates if this property page supports multiple selection
+	 */
+	private final boolean supportsMultiSelect;
+
+	private IConfigurationElement pageElement;
+
+	private SoftReference<Map<String, String>> filterProperties;
+
+	private Expression enablementExpression;
+
+	/**
+	 * PropertyPageContributor constructor.
+	 *
+	 * @param pageId
+	 *            the id
+	 * @param element
+	 *            the element
+	 */
+	public RegistryPageContributor(String pageId, IConfigurationElement element) {
+		this.pageId = pageId;
+		this.pageElement = element;
+		adaptable = Boolean
+				.valueOf(
+						pageElement
+								.getAttribute(PropertyPagesRegistryReader.ATT_ADAPTABLE))
+				.booleanValue();
+		supportsMultiSelect = PropertyPagesRegistryReader.ATT_SELECTION_FILTER_MULTI
+				.equals(pageElement.getAttribute(PropertyPagesRegistryReader.ATT_SELECTION_FILTER));
+		initializeEnablement(element);
+	}
+
+	@Override
+	public PreferenceNode contributePropertyPage(PropertyPageManager mng,
+			Object element) {
+		PropertyPageNode node = new PropertyPageNode(this, element);
+		if (IWorkbenchConstants.WORKBENCH_PROPERTIES_PAGE_INFO.equals(node.getId()))
+			node.setPriority(-1);
+		return node;
+	}
+
+	/**
+	 * Creates the page based on the information in the configuration element.
+	 *
+	 * @param element
+	 *            the adaptable element
+	 * @return the property page
+	 * @throws CoreException
+	 *             thrown if there is a problem creating the apge
+	 */
+	public IPreferencePage createPage(Object element)
+			throws CoreException {
+		IPreferencePage ppage = null;
+		ppage = (IPreferencePage) WorkbenchPlugin.createExtension(
+				pageElement, IWorkbenchRegistryConstants.ATT_CLASS);
+
+		ppage.setTitle(getPageName());
+
+		Object[] elements = getObjects(element);
+		IAdaptable[] adapt = new IAdaptable[elements.length];
+
+		for (int i = 0; i < elements.length; i++) {
+			Object adapted = elements[i];
+			if (adaptable) {
+				adapted = getAdaptedElement(adapted);
+				if (adapted == null) {
+					String message = "Error adapting selection to Property page " + pageId + " is being ignored"; //$NON-NLS-1$ //$NON-NLS-2$
+					throw new CoreException(new Status(IStatus.ERROR,
+							WorkbenchPlugin.PI_WORKBENCH, IStatus.ERROR,
+							message, null));
+				}
+			}
+			adapt[i] = (IAdaptable) ((adapted instanceof IAdaptable) ? adapted
+					: new AdaptableForwarder(adapted));
+		}
+
+		if (supportsMultiSelect) {
+			if ((ppage instanceof IWorkbenchPropertyPageMulti))
+				((IWorkbenchPropertyPageMulti) ppage).setElements(adapt);
+			else
+				throw new CoreException(
+						new Status(
+								IStatus.ERROR,
+								WorkbenchPlugin.PI_WORKBENCH,
+								IStatus.ERROR,
+								"Property page must implement IWorkbenchPropertyPageMulti: " + getPageName(), //$NON-NLS-1$
+								null));
+		} else
+			((IWorkbenchPropertyPage) ppage).setElement(adapt[0]);
+
+		return ppage;
+	}
+
+	/**
+	 * Find an adapted element from the receiver.
+	 *
+	 * @param element
+	 * @return the adapted element or <code>null</code> if it could not be
+	 *         found.
+	 */
+	private Object getAdaptedElement(Object element) {
+		Object adapted = LegacyResourceSupport.getAdapter(element,
+				getObjectClass());
+		if (adapted != null)
+			return adapted;
+
+		return null;
+	}
+
+	/**
+	 * Return the object class name
+	 *
+	 * @return the object class name
+	 */
+	public String getObjectClass() {
+		return pageElement
+				.getAttribute(PropertyPagesRegistryReader.ATT_OBJECTCLASS);
+	}
+
+	/**
+	 * Returns page icon as defined in the registry.
+	 *
+	 * @return the page icon
+	 */
+	public ImageDescriptor getPageIcon() {
+		String iconName = pageElement
+				.getAttribute(IWorkbenchRegistryConstants.ATT_ICON);
+		if (iconName == null)
+			return null;
+		return AbstractUIPlugin.imageDescriptorFromPlugin(pageElement
+				.getNamespaceIdentifier(), iconName);
+	}
+
+	/**
+	 * Returns page ID as defined in the registry.
+	 *
+	 * @return the page id
+	 */
+
+	public String getPageId() {
+		return pageId;
+	}
+
+	/**
+	 * Returns page name as defined in the registry.
+	 *
+	 * @return the page name
+	 */
+	public String getPageName() {
+		return pageElement.getAttribute(IWorkbenchRegistryConstants.ATT_NAME);
+	}
+
+	/**
+	 * Calculate whether the Property page is applicable to the current
+	 * selection. Checks:
+	 * <ul>
+	 * <li>multiSelect</li>
+	 * <li>enabledWhen enablement expression/li>
+	 * <li>nameFilter</li>
+	 * <li>custom Filter</li>
+	 * <li>checks legacy resource support</li>
+	 * </ul>
+	 * <p>
+	 * For multipleSelection pages, considers all elements in the selection for
+	 * enablement.
+	 */
+	@Override
+	public boolean isApplicableTo(Object object) {
+		Object[] objs = getObjects(object);
+
+		// If not a multi-select page not applicable to multiple selection
+		if (objs.length > 1 && !supportsMultiSelect)
+			return false;
+
+		if (failsEnablement(objs))
+			return false;
+
+		// Test name filter
+		String nameFilter = pageElement
+				.getAttribute(PropertyPagesRegistryReader.ATT_NAME_FILTER);
+
+		for (Object obj : objs) {
+			object = obj;
+			// Name filter
+			if (nameFilter != null) {
+				String objectName = object.toString();
+				IWorkbenchAdapter adapter = Adapters.adapt(object, IWorkbenchAdapter.class);
+				if (adapter != null) {
+					String elementName = adapter.getLabel(object);
+					if (elementName != null) {
+						objectName = elementName;
+					}
+				}
+				if (!SelectionEnabler.verifyNameMatch(objectName, nameFilter))
+					return false;
+			}
+
+			// Test custom filter
+			if (getFilterProperties() == null)
+				return true;
+			IActionFilter filter = null;
+
+			// Do the free IResource adapting
+			Object adaptedObject = LegacyResourceSupport
+					.getAdaptedResource(object);
+			if (adaptedObject != null) {
+				object = adaptedObject;
+			}
+
+			filter = Adapters.adapt(object, IActionFilter.class);
+
+			if (filter != null && !testCustom(object, filter))
+				return false;
+		}
+
+		return true;
+	}
+
+	/**
+	 * Return whether or not object fails the enabledWhen enablement criterea.
+	 * For multi-select pages, evaluate the enabledWhen expression using the
+	 * structured selection as a Collection (which should be iterated over).
+	 * @return boolean <code>true</code> if it fails the enablement test
+	 */
+	private boolean failsEnablement(Object[] objs) {
+		if (enablementExpression == null)
+			return false;
+		try {
+			// If multi-select property page, always pass a collection for iteration
+			Object object = (supportsMultiSelect) ? Arrays.asList(objs) : objs[0];
+			EvaluationContext context = new EvaluationContext(null, object);
+			context.setAllowPluginActivation(true);
+			return enablementExpression.evaluate(
+					context).equals(
+					EvaluationResult.FALSE);
+		} catch (CoreException e) {
+			WorkbenchPlugin.log(e);
+			return false;
+		}
+	}
+
+	/**
+	 * Returns an object array for the passed in object. If the object is an
+	 * IStructuredSelection, then return its array otherwise return a 1 element
+	 * Object[] containing the passed in object
+	 *
+	 * @param obj
+	 * @return an object array representing the passed in object
+	 */
+	private Object[] getObjects(Object obj) {
+		if (obj instanceof IStructuredSelection)
+			return ((IStructuredSelection) obj).toArray();
+		return new Object[] { obj };
+	}
+
+	/**
+	 * Initialize the enablement expression for this decorator
+	 */
+	protected void initializeEnablement(IConfigurationElement definingElement) {
+		IConfigurationElement[] elements = definingElement
+				.getChildren(CHILD_ENABLED_WHEN);
+
+		if (elements.length == 0)
+			return;
+
+		try {
+			IConfigurationElement[] enablement = elements[0].getChildren();
+			if (enablement.length == 0)
+				return;
+			enablementExpression = ExpressionConverter.getDefault().perform(
+					enablement[0]);
+		} catch (CoreException e) {
+			WorkbenchPlugin.log(e);
+		}
+
+	}
+
+	/**
+	 * Returns whether the object passes a custom key value filter implemented
+	 * by a matcher.
+	 */
+	private boolean testCustom(Object object, IActionFilter filter) {
+		Map<String, String> filterProperties = getFilterProperties();
+
+		if (filterProperties == null)
+			return false;
+		for (Entry<String, String> entry : filterProperties.entrySet()) {
+			String key = entry.getKey();
+			String value = entry.getValue();
+			if (!filter.testAttribute(object, key, value))
+				return false;
+		}
+		return true;
+	}
+
+	/*
+	 * @see IObjectContributor#canAdapt()
+	 */
+	@Override
+	public boolean canAdapt() {
+		return adaptable;
+	}
+
+	/**
+	 * Get the id of the category.
+	 *
+	 * @return String
+	 * @since 3.1
+	 */
+	public String getCategory() {
+		return pageElement
+				.getAttribute(CategorizedPageRegistryReader.ATT_CATEGORY);
+	}
+
+	/**
+	 * Return the children of the receiver.
+	 *
+	 * @return Collection
+	 */
+	public Collection getSubPages() {
+		return subPages;
+	}
+
+	/**
+	 * Add child to the list of children.
+	 *
+	 * @param child
+	 */
+	public void addSubPage(RegistryPageContributor child) {
+		subPages.add(child);
+	}
+
+	private Map<String, String> getFilterProperties() {
+		if (filterProperties == null || filterProperties.get() == null) {
+			Map<String, String> map = new HashMap<>();
+			filterProperties = new SoftReference<>(map);
+			IConfigurationElement[] children = pageElement.getChildren();
+			for (IConfigurationElement element : children) {
+				processChildElement(map, element);
+			}
+		}
+		return filterProperties.get();
+	}
+
+	/**
+	 * Get the child with the given id.
+	 *
+	 * @param id
+	 * @return RegistryPageContributor
+	 */
+	public Object getChild(String id) {
+		Iterator iterator = subPages.iterator();
+		while (iterator.hasNext()) {
+			RegistryPageContributor next = (RegistryPageContributor) iterator
+					.next();
+			if (next.getPageId().equals(id))
+				return next;
+		}
+		return null;
+	}
+
+	/**
+	 * Parses child element and processes it.
+	 *
+	 * @since 3.1
+	 */
+	private void processChildElement(Map<String, String> map, IConfigurationElement element) {
+		String tag = element.getName();
+		if (tag.equals(PropertyPagesRegistryReader.TAG_FILTER)) {
+			String key = element
+					.getAttribute(PropertyPagesRegistryReader.ATT_FILTER_NAME);
+			String value = element
+					.getAttribute(PropertyPagesRegistryReader.ATT_FILTER_VALUE);
+			if (key == null || value == null)
+				return;
+			map.put(key, value);
+		}
+	}
+
+	@Override
+	public <T> T getAdapter(Class<T> adapter) {
+		if (adapter.equals(IConfigurationElement.class)) {
+			return adapter.cast(getConfigurationElement());
+		}
+		return null;
+	}
+
+	/**
+	 * @return boolean indicating if this page supports multiple selection
+	 * @since 3.7
+	 */
+	boolean supportsMultipleSelection() {
+		return supportsMultiSelect;
+	}
+
+	/**
+	 * @return the configuration element
+	 * @since 3.1
+	 */
+	IConfigurationElement getConfigurationElement() {
+		return pageElement;
+	}
+
+	@Override
+	public String getLocalId() {
+		return pageId;
+	}
+
+    @Override
+	public String getPluginId() {
+    	return pageElement.getContributor().getName();
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/SavePerspectiveDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/SavePerspectiveDialog.java
new file mode 100644
index 0000000..060d79a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/SavePerspectiveDialog.java
@@ -0,0 +1,321 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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
+ *     Patrik Suzzi <psuzzi@gmail.com> - Bug 490700
+ *******************************************************************************/
+package org.eclipse.ui.internal.dialogs;
+
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.activities.ws.ActivityViewerFilter;
+import org.eclipse.ui.internal.registry.PerspectiveRegistry;
+import org.eclipse.ui.model.PerspectiveLabelProvider;
+
+/**
+ * The SavePerspectiveDialog can be used to get the name of a new
+ * perspective or the descriptor of an old perspective.  The results
+ * are returned by <code>getNewPerspName</code> and
+ * <code>getOldPersp</code>.
+ */
+public class SavePerspectiveDialog extends org.eclipse.jface.dialogs.Dialog
+        implements ISelectionChangedListener, ModifyListener {
+    private Text text;
+
+    private TableViewer list;
+
+    private Button okButton;
+
+    private PerspectiveRegistry perspReg;
+
+    private String perspName;
+
+    private IPerspectiveDescriptor persp;
+
+    private IPerspectiveDescriptor initialSelection;
+
+    private boolean ignoreSelection = false;
+
+    final private static int LIST_WIDTH = 40;
+
+    final private static int TEXT_WIDTH = 40;
+
+    final private static int LIST_HEIGHT = 14;
+
+    /**
+     * PerspectiveDialog constructor comment.
+     * @param parentShell the parent shell
+     * @param perspReg the perspective registry
+     */
+    public SavePerspectiveDialog(Shell parentShell, PerspectiveRegistry perspReg) {
+        super(parentShell);
+        this.perspReg = perspReg;
+		setShellStyle(getShellStyle() | SWT.SHEET);
+    }
+
+    @Override
+	protected void configureShell(Shell shell) {
+        super.configureShell(shell);
+        shell
+                .setText(WorkbenchMessages.get().SavePerspective_shellTitle);
+        PlatformUI.getWorkbench().getHelpSystem().setHelp(shell,
+				IWorkbenchHelpContextIds.SAVE_PERSPECTIVE_DIALOG);
+    }
+
+    /**
+     * Add buttons to the dialog's button bar.
+     *
+     * @param parent the button bar composite
+     */
+    @Override
+	protected void createButtonsForButtonBar(Composite parent) {
+		okButton = createButton(parent, IDialogConstants.OK_ID, WorkbenchMessages.get().SavePerspective_saveButtonLabel,
+				true);
+		createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.get().CANCEL_LABEL, false);
+		updateButtons();
+		text.setFocus();
+    }
+
+    /**
+     * Creates and returns the contents of the upper part
+     * of this dialog (above the button bar).
+     *
+     * @param parent the parent composite to contain the dialog area
+     * @return the dialog area control
+     */
+    @Override
+	protected Control createDialogArea(Composite parent) {
+        Font font = parent.getFont();
+        // Run super.
+        Composite composite = (Composite) super.createDialogArea(parent);
+
+        // description
+        Label descLabel = new Label(composite, SWT.WRAP);
+        descLabel.setText(WorkbenchMessages.get().SavePerspectiveDialog_description);
+        descLabel.setFont(parent.getFont());
+
+        // Spacer.
+        Label label = new Label(composite, SWT.NONE);
+        GridData data = new GridData();
+        data.heightHint = 8;
+        label.setLayoutData(data);
+
+        // Create name group.
+        Composite nameGroup = new Composite(composite, SWT.NONE);
+        nameGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+        GridLayout layout = new GridLayout();
+        layout.numColumns = 2;
+        layout.marginWidth = layout.marginHeight = 0;
+        nameGroup.setLayout(layout);
+
+        // Create name label.
+        label = new Label(nameGroup, SWT.NONE);
+        label.setText(WorkbenchMessages.get().SavePerspective_name);
+        label.setFont(font);
+
+        // Add text field.
+        text = new Text(nameGroup, SWT.BORDER);
+        text.setFocus();
+        data = new GridData(GridData.FILL_HORIZONTAL);
+        data.widthHint = convertWidthInCharsToPixels(TEXT_WIDTH);
+        text.setLayoutData(data);
+        text.setFont(font);
+        text.addModifyListener(this);
+
+        // Spacer.
+        label = new Label(composite, SWT.NONE);
+        data = new GridData();
+        data.heightHint = 5;
+        label.setLayoutData(data);
+
+        // Another label.
+        label = new Label(composite, SWT.NONE);
+        label.setText(WorkbenchMessages.get().SavePerspective_existing);
+        label.setFont(font);
+
+        // Add perspective list.
+        list = new TableViewer(composite, SWT.H_SCROLL | SWT.V_SCROLL
+                | SWT.BORDER);
+        list.setLabelProvider(new PerspectiveLabelProvider());
+        list.setContentProvider(new PerspContentProvider());
+        list.addFilter(new ActivityViewerFilter());
+        list.setComparator(new ViewerComparator());
+        list.setInput(perspReg);
+        list.addSelectionChangedListener(this);
+        list.getTable().setFont(font);
+
+        // Set perspective list size.
+        Control ctrl = list.getControl();
+        GridData spec = new GridData(GridData.FILL_BOTH);
+        spec.widthHint = convertWidthInCharsToPixels(LIST_WIDTH);
+        spec.heightHint = convertHeightInCharsToPixels(LIST_HEIGHT);
+        ctrl.setLayoutData(spec);
+
+        // Set the initial selection
+        if (initialSelection != null) {
+            StructuredSelection sel = new StructuredSelection(initialSelection);
+            list.setSelection(sel, true);
+        }
+        text.selectAll();
+
+        // Return results.
+        return composite;
+    }
+
+    /**
+     * Returns the target name.
+     *
+     * @return the target name
+     */
+    public IPerspectiveDescriptor getPersp() {
+        return persp;
+    }
+
+    /**
+     * Returns the target name.
+     *
+     * @return the target name
+     */
+    public String getPerspName() {
+        return perspName;
+    }
+
+    /**
+     * The user has typed some text.
+     */
+    @Override
+	public void modifyText(org.eclipse.swt.events.ModifyEvent e) {
+        // Get text.
+        perspName = text.getText();
+
+        // Transfer text to persp list.
+        ignoreSelection = true;
+        persp = perspReg.findPerspectiveWithLabel(perspName);
+        if (persp == null) {
+            StructuredSelection sel = new StructuredSelection();
+            list.setSelection(sel);
+        } else {
+            StructuredSelection sel = new StructuredSelection(persp);
+            list.setSelection(sel);
+        }
+        ignoreSelection = false;
+
+        updateButtons();
+    }
+
+    /**
+     * Notifies that the ok button of this dialog has been pressed.
+     * <p>
+     * The default implementation of this framework method sets
+     * this dialog's return code to <code>Window.OK</code>
+     * and closes the dialog. Subclasses may override.
+     * </p>
+     */
+    @Override
+	protected void okPressed() {
+        perspName = text.getText();
+        persp = perspReg.findPerspectiveWithLabel(perspName);
+        if (persp != null) {
+            // Confirm ok to overwrite
+            String message = NLS.bind(WorkbenchMessages.get().SavePerspective_overwriteQuestion,perspName );
+            String[] buttons = new String[] { IDialogConstants.get().YES_LABEL,
+                    IDialogConstants.get().NO_LABEL, IDialogConstants.get().CANCEL_LABEL };
+			MessageDialog d = new MessageDialog(this.getShell(),
+					WorkbenchMessages.get().SavePerspective_overwriteTitle, null,
+					message, MessageDialog.QUESTION, buttons, 0) {
+				@Override
+				protected int getShellStyle() {
+					return super.getShellStyle() | SWT.SHEET;
+				}
+			};
+
+            switch (d.open()) {
+            case 0: //yes
+                break;
+            case 1: //no
+                return;
+            case 2: //cancel
+                cancelPressed();
+                return;
+            default:
+                return;
+            }
+        }
+
+        super.okPressed();
+    }
+
+    /**
+     * Notifies that the selection has changed.
+     *
+     * @param event event object describing the change
+     */
+    @Override
+	public void selectionChanged(SelectionChangedEvent event) {
+        // If a selection is caused by modifyText ignore it.
+        if (ignoreSelection) {
+			return;
+		}
+
+        // Get selection.
+        IStructuredSelection sel = (IStructuredSelection) list.getSelection();
+        persp = null;
+        if (!sel.isEmpty()) {
+			persp = (IPerspectiveDescriptor) sel.getFirstElement();
+		}
+
+        // Transfer selection to text field.
+        if (persp != null) {
+            perspName = persp.getLabel();
+            text.setText(perspName);
+        }
+
+        updateButtons();
+    }
+
+    /**
+     * Sets the initial selection in this dialog.
+     *
+     * @param selectedElement the perspective descriptor to select
+     */
+    public void setInitialSelection(IPerspectiveDescriptor selectedElement) {
+        initialSelection = selectedElement;
+    }
+
+    /**
+     * Update the OK button.
+     */
+    private void updateButtons() {
+        if (okButton != null) {
+            String label = text.getText();
+            okButton.setEnabled(perspReg.validateLabel(label));
+        }
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/SelectPerspectiveDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/SelectPerspectiveDialog.java
new file mode 100644
index 0000000..4f22af9
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/SelectPerspectiveDialog.java
@@ -0,0 +1,351 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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
+ *     Sebastian Davids <sdavids@gmx.de> - Fix for bug 19346 - Dialog font should be
+ *     activated and used by other components.
+ *     Martin Karpisek <martin.karpisek@gmail.com> - Bug 106954
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.dialogs;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.PopupDialog;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusAdapter;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.IPerspectiveRegistry;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.activities.ITriggerPoint;
+import org.eclipse.ui.activities.WorkbenchActivityHelper;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.activities.ws.ActivityMessages;
+import org.eclipse.ui.internal.activities.ws.ActivityViewerFilter;
+import org.eclipse.ui.internal.activities.ws.WorkbenchTriggerPoints;
+import org.eclipse.ui.model.PerspectiveLabelProvider;
+
+/**
+ * A dialog for perspective creation
+ */
+public class SelectPerspectiveDialog extends Dialog implements
+        ISelectionChangedListener {
+
+    final private static int LIST_HEIGHT = 300;
+
+    final private static int LIST_WIDTH = 300;
+
+    private TableViewer list;
+
+    private Button okButton;
+
+    private IPerspectiveDescriptor perspDesc;
+
+    private IPerspectiveRegistry perspReg;
+
+    private ActivityViewerFilter activityViewerFilter = new ActivityViewerFilter();
+
+	private Label descriptionHint;
+
+    private Button showAllButton;
+
+	private PopupDialog perspDescPopupDialog;
+
+    /**
+     * PerspectiveDialog constructor comment.
+     *
+     * @param parentShell the parent shell
+     * @param perspReg the perspective registry
+     */
+    public SelectPerspectiveDialog(Shell parentShell,
+            IPerspectiveRegistry perspReg) {
+        super(parentShell);
+        this.perspReg = perspReg;
+		setShellStyle(getShellStyle() | SWT.SHEET);
+    }
+
+    @Override
+	protected void cancelPressed() {
+        perspDesc = null;
+        super.cancelPressed();
+    }
+
+    @Override
+	protected void configureShell(Shell shell) {
+        super.configureShell(shell);
+        shell.setText(WorkbenchMessages.get().SelectPerspective_shellTitle);
+        PlatformUI.getWorkbench().getHelpSystem().setHelp(shell,
+				IWorkbenchHelpContextIds.SELECT_PERSPECTIVE_DIALOG);
+    }
+
+    /**
+     * Adds buttons to this dialog's button bar.
+     * <p>
+     * The default implementation of this framework method adds standard ok and
+     * cancel buttons using the <code>createButton</code> framework method.
+     * Subclasses may override.
+     * </p>
+     *
+     * @param parent the button bar composite
+     */
+    @Override
+	protected void createButtonsForButtonBar(Composite parent) {
+        okButton = createButton(parent, IDialogConstants.OK_ID,
+				WorkbenchMessages.get().SelectPerspective_open_button_label, true);
+        createButton(parent, IDialogConstants.CANCEL_ID,
+                IDialogConstants.get().CANCEL_LABEL, false);
+        updateButtons();
+    }
+
+    /**
+     * Creates and returns the contents of the upper part of this dialog (above
+     * the button bar).
+     *
+     * @param parent the parent composite to contain the dialog area
+     * @return the dialog area control
+     */
+    @Override
+	protected Control createDialogArea(Composite parent) {
+        // Run super.
+        Composite composite = (Composite) super.createDialogArea(parent);
+        composite.setFont(parent.getFont());
+
+        createViewer(composite);
+        layoutTopControl(list.getControl());
+
+		// Use F2... label
+		descriptionHint = new Label(composite, SWT.WRAP);
+		descriptionHint.setText(WorkbenchMessages.get().SelectPerspective_selectPerspectiveHelp);
+		descriptionHint.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+		descriptionHint.setVisible(false);
+
+        if (needsShowAllButton()) {
+            createShowAllButton(composite);
+        }
+        // Return results.
+        return composite;
+    }
+
+    /**
+     * @return whether a show-all button is needed.  A show all button is needed only if the list contains filtered items.
+     */
+    private boolean needsShowAllButton() {
+        return activityViewerFilter.getHasEncounteredFilteredItem();
+    }
+
+    /**
+     * Create a show all button in the parent.
+     *
+     * @param parent the parent <code>Composite</code>.
+     */
+    private void createShowAllButton(Composite parent) {
+        showAllButton = new Button(parent, SWT.CHECK);
+        showAllButton
+                .setText(ActivityMessages.Perspective_showAll);
+        showAllButton.addSelectionListener(new SelectionAdapter() {
+
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+    		    if (showAllButton.getSelection()) {
+    		        list.resetFilters();
+    		    } else {
+    		        list.addFilter(activityViewerFilter);
+    		    }
+            }
+		});
+
+    }
+
+    /**
+     * Create a new viewer in the parent.
+     *
+     * @param parent the parent <code>Composite</code>.
+     */
+    private void createViewer(Composite parent) {
+        // Add perspective list.
+        list = new TableViewer(parent, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL
+                | SWT.BORDER);
+        list.getTable().setFont(parent.getFont());
+		list.setLabelProvider(new PerspectiveLabelProvider());
+        list.setContentProvider(new PerspContentProvider());
+        list.addFilter(activityViewerFilter);
+        list.setComparator(new ViewerComparator());
+        list.setInput(perspReg);
+        list.addSelectionChangedListener(this);
+        list.addDoubleClickListener(event -> handleDoubleClickEvent());
+		list.getControl().addKeyListener(new KeyAdapter() {
+			@Override
+			public void keyPressed(KeyEvent e) {
+				handleTableViewerKeyPressed(e);
+			}
+		});
+    }
+
+    /**
+     * Returns the current selection.
+     *
+     * @return the current selection
+     */
+    public IPerspectiveDescriptor getSelection() {
+        return perspDesc;
+    }
+
+    /**
+     * Handle a double click event on the list
+     */
+    protected void handleDoubleClickEvent() {
+        okPressed();
+    }
+
+    /**
+     * Layout the top control.
+     *
+     * @param control the control.
+     */
+    private void layoutTopControl(Control control) {
+        GridData spec = new GridData(GridData.FILL_BOTH);
+        spec.widthHint = LIST_WIDTH;
+        spec.heightHint = LIST_HEIGHT;
+        control.setLayoutData(spec);
+    }
+
+    /**
+     * Notifies that the selection has changed.
+     *
+     * @param event event object describing the change
+     */
+    @Override
+	public void selectionChanged(SelectionChangedEvent event) {
+        updateSelection(event);
+        updateButtons();
+		updateTooltip();
+    }
+
+    /**
+     * Update the button enablement state.
+     */
+    protected void updateButtons() {
+        okButton.setEnabled(getSelection() != null);
+    }
+
+    /**
+     * Update the selection object.
+     */
+    protected void updateSelection(SelectionChangedEvent event) {
+        perspDesc = null;
+        IStructuredSelection sel = (IStructuredSelection) event.getSelection();
+        if (!sel.isEmpty()) {
+            Object obj = sel.getFirstElement();
+            if (obj instanceof IPerspectiveDescriptor) {
+				perspDesc = (IPerspectiveDescriptor) obj;
+			}
+        }
+    }
+
+    private void updateTooltip() {
+		String tooltip = ""; //$NON-NLS-1$
+		if (perspDesc != null) {
+			tooltip = perspDesc.getDescription();
+		}
+
+		boolean hasTooltip = tooltip != null && tooltip.length() > 0;
+		descriptionHint.setVisible(hasTooltip);
+
+		if (perspDescPopupDialog != null) {
+			perspDescPopupDialog.close();
+			perspDescPopupDialog = null;
+		}
+	}
+
+	@Override
+	protected void okPressed() {
+        ITriggerPoint triggerPoint = PlatformUI.getWorkbench()
+                .getActivitySupport().getTriggerPointManager().getTriggerPoint(
+                        WorkbenchTriggerPoints.OPEN_PERSPECITVE_DIALOG);
+        if (WorkbenchActivityHelper.allowUseOf(triggerPoint, getSelection())) {
+			super.okPressed();
+		}
+    }
+
+    @Override
+	protected boolean isResizable() {
+    	return true;
+    }
+
+	private void handleTableViewerKeyPressed(KeyEvent event) {
+		// popup the description for the selected perspective
+		if (event.keyCode == SWT.F2 && event.stateMask == 0) {
+			IStructuredSelection selection = list.getStructuredSelection();
+			// only show description if one perspective is selected
+			if (selection.size() == 1) {
+				Object o = selection.getFirstElement();
+				if (o instanceof IPerspectiveDescriptor) {
+					String description = ((IPerspectiveDescriptor) o).getDescription();
+					if (description.length() == 0) {
+						description = WorkbenchMessages.get().SelectPerspective_noDesc;
+					}
+					popUp(description);
+				}
+			}
+		}
+	}
+
+	private void popUp(final String description) {
+		perspDescPopupDialog = new PopupDialog(getShell(), PopupDialog.HOVER_SHELLSTYLE, true, false, false, false, false, null, null) {
+			private static final int CURSOR_SIZE = 15;
+
+			@Override
+			protected Point getInitialLocation(Point initialSize) {
+				// show popup relative to cursor
+				Display display = getShell().getDisplay();
+				Point location = display.getCursorLocation();
+				location.x += CURSOR_SIZE;
+				location.y += CURSOR_SIZE;
+				return location;
+			}
+
+			@Override
+			protected Control createDialogArea(Composite parent) {
+				Label label = new Label(parent, SWT.WRAP);
+				label.setText(description);
+				label.addFocusListener(new FocusAdapter() {
+					@Override
+					public void focusLost(FocusEvent event) {
+						close();
+					}
+				});
+				// Use the compact margins employed by PopupDialog.
+				GridData gd = new GridData(GridData.BEGINNING | GridData.FILL_BOTH);
+				gd.horizontalIndent = PopupDialog.POPUP_HORIZONTALSPACING;
+				gd.verticalIndent = PopupDialog.POPUP_VERTICALSPACING;
+				label.setLayoutData(gd);
+				return label;
+			}
+		};
+		perspDescPopupDialog.open();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ShowViewDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ShowViewDialog.java
new file mode 100644
index 0000000..586e0eb
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ShowViewDialog.java
@@ -0,0 +1,484 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Sebastian Davids - bug 128526, bug 128529
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 430988, 457434, 472654
+ *     Simon Scholz <simon.scholz@vogella.com> - Bug 455527
+ *******************************************************************************/
+package org.eclipse.ui.internal.dialogs;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.ui.internal.workbench.swt.WorkbenchSWTActivator;
+import org.eclipse.e4.ui.model.LocalizationHelper;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.descriptor.basic.MPartDescriptor;
+import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
+import org.eclipse.e4.ui.services.help.EHelpService;
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+import org.eclipse.e4.ui.workbench.modeling.EPartService;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.IDialogLabelKeys;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.dialogs.PopupDialog;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.ITreeSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusAdapter;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.dialogs.FilteredTree;
+import org.eclipse.ui.dialogs.PatternFilter;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchMessages;
+
+public class ShowViewDialog extends Dialog implements ISelectionChangedListener, IDoubleClickListener {
+
+	private static final String DIALOG_SETTING_SECTION_NAME = "ShowViewDialog"; //$NON-NLS-1$
+
+	private static final int LIST_HEIGHT = 300;
+
+	private static final int LIST_WIDTH = 250;
+
+	private static final String STORE_EXPANDED_CATEGORIES_ID = DIALOG_SETTING_SECTION_NAME
+			+ ".STORE_EXPANDED_CATEGORIES_ID"; //$NON-NLS-1$
+
+	private static final String STORE_SELECTED_VIEW_ID = DIALOG_SETTING_SECTION_NAME
+			+ ".STORE_SELECTED_VIEW_ID"; //$NON-NLS-1$
+
+	private FilteredTree filteredTree;
+
+	private Color dimmedForeground;
+
+	private Button okButton;
+
+	private MApplication application;
+
+	private MPartDescriptor[] viewDescs = new MPartDescriptor[0];
+
+	private Label descriptionHint;
+
+	private IEclipseContext context;
+
+	private EModelService modelService;
+
+	private MWindow window;
+
+	private EPartService partService;
+
+	/**
+	 * Constructs a new ShowViewDialog.
+	 *
+	 * @param shell
+	 * @param application
+	 * @param window
+	 * @param modelService
+	 * @param partService
+	 * @param context
+	 *
+	 */
+	public ShowViewDialog(Shell shell, MApplication application, MWindow window, EModelService modelService,
+			EPartService partService, IEclipseContext context) {
+		super(shell);
+		this.application = application;
+		this.window = window;
+		this.modelService = modelService;
+		this.partService = partService;
+		this.context = context;
+	}
+
+	/**
+	 * This method is called if a button has been pressed.
+	 */
+	@Override
+	protected void buttonPressed(int buttonId) {
+		if (buttonId == IDialogConstants.OK_ID) {
+			saveWidgetValues();
+		}
+		super.buttonPressed(buttonId);
+	}
+
+	/**
+	 * Notifies that the cancel button of this dialog has been pressed.
+	 */
+	@Override
+	protected void cancelPressed() {
+		viewDescs = new MPartDescriptor[0];
+		super.cancelPressed();
+	}
+
+	@Override
+	protected void configureShell(Shell shell) {
+		super.configureShell(shell);
+		shell.setText(WorkbenchMessages.get().ShowView_shellTitle);
+		EHelpService helpService = context.get(EHelpService.class);
+		if (helpService != null) {
+			helpService.setHelp(shell, IWorkbenchHelpContextIds.SHOW_VIEW_DIALOG);
+		}
+	}
+
+	@Override
+	protected void createButtonsForButtonBar(Composite parent) {
+		okButton = createButton(parent, IDialogConstants.OK_ID, WorkbenchMessages.get().ShowView_open_button_label,
+				true);
+		createButton(parent, IDialogConstants.CANCEL_ID, JFaceResources.getString(IDialogLabelKeys.CANCEL_LABEL_KEY),
+				false);
+		updateButtons();
+	}
+
+	@Override
+	protected Control createDialogArea(Composite parent) {
+		// Run super.
+		Composite composite = (Composite) super.createDialogArea(parent);
+		composite.setFont(parent.getFont());
+
+		createFilteredTreeViewer(composite);
+
+		layoutTopControl(filteredTree);
+
+		// Use F2... label
+		descriptionHint = new Label(composite, SWT.WRAP);
+		descriptionHint.setText(WorkbenchMessages.get().ShowView_selectViewHelp);
+		descriptionHint.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+		descriptionHint.setVisible(false);
+
+		// Restore the last state
+		restoreWidgetValues();
+
+		applyDialogFont(composite);
+
+		// Return results.
+		return composite;
+	}
+
+	/**
+	 * Blends c1 and c2 based in the provided ratio.
+	 *
+	 * @param c1
+	 *            first color
+	 * @param c2
+	 *            second color
+	 * @param ratio
+	 *            percentage of the first color in the blend (0-100)
+	 * @return the RGB value of the blended color
+	 *
+	 *         copied from FormColors.java
+	 */
+	private static RGB blend(RGB c1, RGB c2, int ratio) {
+		int r = blend(c1.red, c2.red, ratio);
+		int g = blend(c1.green, c2.green, ratio);
+		int b = blend(c1.blue, c2.blue, ratio);
+		return new RGB(r, g, b);
+	}
+
+	private static int blend(int v1, int v2, int ratio) {
+		int b = (ratio * v1 + (100 - ratio) * v2) / 100;
+		return Math.min(255, b);
+	}
+
+	/**
+	 * Create a new filtered tree viewer in the parent.
+	 *
+	 * @param parent
+	 *            the parent <code>Composite</code>.
+	 */
+	private void createFilteredTreeViewer(Composite parent) {
+		PatternFilter filter = new ViewPatternFilter();
+		int styleBits = SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER;
+		filteredTree = new FilteredTree(parent, styleBits, filter, true);
+		filteredTree.setQuickSelectionMode(true);
+		filteredTree.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
+
+		TreeViewer treeViewer = filteredTree.getViewer();
+		Control treeControl = treeViewer.getControl();
+		RGB dimmedRGB = blend(treeControl.getForeground().getRGB(), treeControl.getBackground()
+				.getRGB(), 60);
+		dimmedForeground = new Color(treeControl.getDisplay(), dimmedRGB);
+		treeControl.addDisposeListener(e -> dimmedForeground.dispose());
+
+		treeViewer.setLabelProvider(new ViewLabelProvider(context, modelService, partService, window,dimmedForeground));
+		treeViewer.setContentProvider(new ViewContentProvider(application));
+		treeViewer.setComparator(new ViewComparator());
+		treeViewer.setInput(application);
+		treeViewer.addSelectionChangedListener(this);
+		treeViewer.addDoubleClickListener(this);
+		treeViewer.getControl().addKeyListener(new KeyAdapter() {
+			@Override
+			public void keyPressed(KeyEvent e) {
+				handleTreeViewerKeyPressed(e);
+			}
+		});
+
+		// if the tree has only one or zero views, disable the filter text
+		// control
+		if (hasAtMostOneView(filteredTree.getViewer())) {
+			Text filterText = filteredTree.getFilterControl();
+			if (filterText != null) {
+				filterText.setEnabled(false);
+			}
+		}
+	}
+
+	/**
+	 * Return whether or not there are less than two views in the list.
+	 *
+	 * @param tree
+	 * @return <code>true</code> if there are less than two views in the list.
+	 */
+	private boolean hasAtMostOneView(TreeViewer tree) {
+		ITreeContentProvider contentProvider = (ITreeContentProvider) tree.getContentProvider();
+		Object[] children = contentProvider.getElements(tree.getInput());
+
+		if (children.length <= 1) {
+			if (children.length == 0) {
+				return true;
+			}
+			return !contentProvider.hasChildren(children[0]);
+		}
+		return false;
+	}
+
+	@Override
+	public void doubleClick(DoubleClickEvent event) {
+		IStructuredSelection s = (IStructuredSelection) event.getSelection();
+		Object element = s.getFirstElement();
+		if (filteredTree.getViewer().isExpandable(element)) {
+			filteredTree.getViewer().setExpandedState(element,
+					!filteredTree.getViewer().getExpandedState(element));
+		} else if (viewDescs.length > 0) {
+			saveWidgetValues();
+			setReturnCode(OK);
+			close();
+		}
+	}
+
+	/**
+	 * Return the dialog store to cache values into
+	 */
+	protected IDialogSettings getDialogSettings() {
+		IDialogSettings workbenchSettings = WorkbenchSWTActivator.getDefault().getDialogSettings();
+		IDialogSettings section = workbenchSettings.getSection(DIALOG_SETTING_SECTION_NAME);
+		if (section == null) {
+			section = workbenchSettings.addNewSection(DIALOG_SETTING_SECTION_NAME);
+		}
+		return section;
+	}
+
+	/**
+	 * Returns the descriptors for the selected views.
+	 *
+	 * @return the descriptors for the selected views
+	 */
+	public MPartDescriptor[] getSelection() {
+		return viewDescs;
+	}
+
+	/**
+	 * Layout the top control.
+	 *
+	 * @param control
+	 *            the control.
+	 */
+	private void layoutTopControl(Control control) {
+		GridData spec = new GridData(GridData.FILL_BOTH);
+		spec.widthHint = LIST_WIDTH;
+		spec.heightHint = LIST_HEIGHT;
+		control.setLayoutData(spec);
+	}
+
+	/**
+	 * Use the dialog store to restore widget values to the values that they
+	 * held last time this dialog was used to completion.
+	 */
+	protected void restoreWidgetValues() {
+		IDialogSettings settings = getDialogSettings();
+
+		String[] expandedCategoryIds = settings.getArray(STORE_EXPANDED_CATEGORIES_ID);
+		if (expandedCategoryIds == null)
+			return;
+
+		if (expandedCategoryIds.length > 0)
+			filteredTree.getViewer().setExpandedElements(expandedCategoryIds);
+
+		String selectedPartId = settings.get(STORE_SELECTED_VIEW_ID);
+		if (selectedPartId != null) {
+			List<MPartDescriptor> descriptors = application.getDescriptors();
+			for (MPartDescriptor descriptor : descriptors) {
+				if (selectedPartId.equals(descriptor.getElementId())) {
+					filteredTree.getViewer()
+							.setSelection(new StructuredSelection(descriptor), true);
+					break;
+				}
+			}
+		}
+	}
+
+	/**
+	 * Since OK was pressed, write widget values to the dialog store so that
+	 * they will persist into the next invocation of this dialog
+	 */
+	protected void saveWidgetValues() {
+		IDialogSettings settings = getDialogSettings();
+
+		// Collect the ids of the all expanded categories
+		Object[] expandedElements = filteredTree.getViewer().getExpandedElements();
+		String[] expandedCategoryIds = new String[expandedElements.length];
+		for (int i = 0; i < expandedElements.length; ++i) {
+			if (expandedElements[i] instanceof MPartDescriptor)
+				expandedCategoryIds[i] = ((MPartDescriptor) expandedElements[i]).getElementId();
+			else
+				expandedCategoryIds[i] = expandedElements[i].toString();
+		}
+
+		// Save them for next time.
+		settings.put(STORE_EXPANDED_CATEGORIES_ID, expandedCategoryIds);
+
+		String selectedViewId = ""; //$NON-NLS-1$
+		if (viewDescs.length > 0) {
+			// in the case of a multi-selection, it's probably less confusing
+			// to store just the first rather than the whole multi-selection
+			selectedViewId = viewDescs[0].getElementId();
+		}
+		settings.put(STORE_SELECTED_VIEW_ID, selectedViewId);
+	}
+
+	/**
+	 * Notifies that the selection has changed.
+	 *
+	 * @param event
+	 *            event object describing the change
+	 */
+	@Override
+	public void selectionChanged(SelectionChangedEvent event) {
+		updateSelection(event);
+		updateButtons();
+		String tooltip = ""; //$NON-NLS-1$
+		if (viewDescs.length > 0) {
+			tooltip = viewDescs[0].getTooltip();
+			tooltip = LocalizationHelper.getLocalized(tooltip, viewDescs[0], context);
+		}
+
+		boolean hasTooltip = tooltip != null && tooltip.length() > 0;
+		descriptionHint.setVisible(viewDescs.length == 1 && hasTooltip);
+	}
+
+	/**
+	 * Update the button enablement state.
+	 */
+	protected void updateButtons() {
+		if (okButton != null) {
+			okButton.setEnabled(getSelection().length > 0);
+		}
+	}
+
+	/**
+	 * Update the selection object.
+	 */
+	protected void updateSelection(SelectionChangedEvent event) {
+		ArrayList<MPartDescriptor> descs = new ArrayList<>();
+		IStructuredSelection sel = (IStructuredSelection) event.getSelection();
+		for (Iterator<?> i = sel.iterator(); i.hasNext();) {
+			Object o = i.next();
+			if (o instanceof MPartDescriptor) {
+				descs.add((MPartDescriptor) o);
+			}
+		}
+
+		viewDescs = new MPartDescriptor[descs.size()];
+		descs.toArray(viewDescs);
+	}
+
+	@Override
+	protected IDialogSettings getDialogBoundsSettings() {
+		return getDialogSettings();
+	}
+
+	void handleTreeViewerKeyPressed(KeyEvent event) {
+		// popup the description for the selected view
+		if (descriptionHint.isVisible() && event.keyCode == SWT.F2 && event.stateMask == 0) {
+			ITreeSelection selection = (ITreeSelection) filteredTree.getViewer().getSelection();
+			// only show description if one view is selected
+			if (selection.size() == 1) {
+				Object o = selection.getFirstElement();
+				if (o instanceof MPartDescriptor) {
+					String description = ((MPartDescriptor) o).getTooltip();
+					description = LocalizationHelper.getLocalized(description, (MPartDescriptor) o,
+							context);
+					if (description != null && description.length() == 0)
+						description = WorkbenchMessages.get().ShowView_noDesc;
+					popUp(description);
+				}
+			}
+		}
+	}
+
+	private void popUp(final String description) {
+		new PopupDialog(filteredTree.getShell(), PopupDialog.HOVER_SHELLSTYLE, true, false, false,
+				false, false, null, null) {
+			private static final int CURSOR_SIZE = 15;
+
+			@Override
+			protected Point getInitialLocation(Point initialSize) {
+				// show popup relative to cursor
+				Display display = getShell().getDisplay();
+				Point location = display.getCursorLocation();
+				location.x += CURSOR_SIZE;
+				location.y += CURSOR_SIZE;
+				return location;
+			}
+
+			@Override
+			protected Control createDialogArea(Composite parent) {
+				Label label = new Label(parent, SWT.WRAP);
+				label.setText(description);
+				label.addFocusListener(new FocusAdapter() {
+					@Override
+					public void focusLost(FocusEvent event) {
+						close();
+					}
+				});
+				// Use the compact margins employed by PopupDialog.
+				GridData gd = new GridData(GridData.BEGINNING | GridData.FILL_BOTH);
+				gd.horizontalIndent = PopupDialog.POPUP_HORIZONTALSPACING;
+				gd.verticalIndent = PopupDialog.POPUP_VERTICALSPACING;
+				label.setLayoutData(gd);
+				return label;
+			}
+		}.open();
+	}
+
+	@Override
+	protected boolean isResizable() {
+		return true;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/SimpleWorkingSetSelectionDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/SimpleWorkingSetSelectionDialog.java
new file mode 100644
index 0000000..6be108b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/SimpleWorkingSetSelectionDialog.java
@@ -0,0 +1,198 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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
+ *     Jan-Ove Weichel <janove.weichel@vogella.com> - Bug 481490
+ ******************************************************************************/
+
+package org.eclipse.ui.internal.dialogs;
+
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.CheckboxTableViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkingSet;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchMessages;
+
+/**
+ * Base implementation for a simple working set dialog that doesn't contain
+ * references to non-editable/non-visible working sets.
+ *
+ * @since 3.4
+ *
+ */
+public class SimpleWorkingSetSelectionDialog extends AbstractWorkingSetDialog {
+
+	private class Filter extends ViewerFilter {
+
+		@Override
+		public boolean select(Viewer viewer, Object parentElement,
+				Object element) {
+			return isCompatible((IWorkingSet) element);
+		}
+
+		private boolean isCompatible(IWorkingSet set) {
+			if (set.isAggregateWorkingSet())
+				return false;
+
+			// original JDT code had the catch for self-updating sets that no
+			// one can explain. There doesn't seem to
+			// be a good reason to exclude these sets so the clause has been
+			// removed.
+
+			// if (set.isAggregateWorkingSet() || !set.isSelfUpdating())
+			// return false;
+
+			if (!set.isVisible())
+				return false;
+
+			if (!set.isEditable())
+				return false;
+
+			Set<String> workingSetTypeIds = getSupportedWorkingSetIds();
+			if (workingSetTypeIds == null)
+				return true;
+			for (String workingSetTypeId : workingSetTypeIds) {
+				if (workingSetTypeId.equals(set.getId())) {
+					return true;
+				}
+			}
+
+			return false;
+		}
+	}
+
+	private CheckboxTableViewer viewer;
+
+	private IWorkingSet[] initialSelection;
+
+	/**
+	 * Create a new instance of this class.
+	 *
+	 * @param shell
+	 *            the shell to parent this dialog on
+	 * @param workingSetTypeIds
+	 *            the types of working set IDs that will be shown in this dialog
+	 * @param selectedWorkingSets
+	 *            the currently selected working sets (if any)
+	 * @param canEdit
+	 *            whether or not this dialog will display edit controls
+	 */
+	public SimpleWorkingSetSelectionDialog(Shell shell, String[] workingSetTypeIds, IWorkingSet[] selectedWorkingSets,
+			boolean canEdit) {
+		super(shell, workingSetTypeIds, canEdit);
+		this.initialSelection = selectedWorkingSets;
+		setTitle(WorkbenchMessages.get().WorkingSetSelectionDialog_title_multiSelect);
+		setMessage(WorkbenchMessages.get().WorkingSetSelectionDialog_message_multiSelect);
+	}
+
+	@Override
+	protected Control createDialogArea(Composite parent) {
+		initializeDialogUnits(parent);
+
+		Composite composite = (Composite) super.createDialogArea(parent);
+
+		Composite viewerComposite = new Composite(composite, SWT.NONE);
+		GridLayout layout = new GridLayout(2, false);
+		layout.marginHeight = layout.marginWidth = 0;
+		layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
+		layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
+		viewerComposite.setLayout(layout);
+		viewerComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+		viewer = CheckboxTableViewer.newCheckList(viewerComposite, SWT.BORDER);
+		viewer.getControl().setLayoutData(new GridData(GridData.FILL_BOTH));
+		viewer.setLabelProvider(new WorkingSetLabelProvider());
+		viewer.setContentProvider(new ArrayContentProvider());
+		viewer.addFilter(new WorkingSetFilter(null));
+		IWorkingSet[] workingSets = PlatformUI.getWorkbench().getWorkingSetManager()
+				.getWorkingSets();
+		viewer.setInput(workingSets);
+		viewer.setFilters(new ViewerFilter[] {new Filter()});
+
+		viewer.addSelectionChangedListener(event -> handleSelectionChanged());
+		viewer.setCheckedElements(initialSelection);
+
+		GridData viewerData = new GridData(GridData.FILL_BOTH);
+		viewerData.widthHint = convertWidthInCharsToPixels(50);
+		viewer.getControl().setLayoutData(viewerData);
+
+		addModifyButtons(viewerComposite);
+
+		addSelectionButtons(composite);
+
+		availableWorkingSetsChanged();
+
+		Dialog.applyDialogFont(composite);
+
+		viewerData.heightHint = viewer.getTable().getItemHeight()
+				* Math.min(30, Math.max(10, workingSets.length));
+
+		return composite;
+	}
+
+	@Override
+	protected void okPressed() {
+		Object[] checked = viewer.getCheckedElements();
+		IWorkingSet[] workingSets = new IWorkingSet[checked.length];
+		System.arraycopy(checked, 0, workingSets, 0, checked.length);
+		setSelection(workingSets);
+		super.okPressed();
+	}
+
+	@Override
+	protected List getSelectedWorkingSets() {
+		return viewer.getStructuredSelection().toList();
+	}
+
+	@Override
+	protected void availableWorkingSetsChanged() {
+		viewer.setInput(PlatformUI.getWorkbench().getWorkingSetManager()
+				.getWorkingSets());
+		super.availableWorkingSetsChanged();
+	}
+
+	@Override
+	protected void workingSetAdded(IWorkingSet addedSet) {
+		viewer.setChecked(addedSet, true);
+		updateButtonAvailability();
+	}
+
+	/**
+	 * Called when the selection has changed.
+	 */
+	void handleSelectionChanged() {
+		updateButtonAvailability();
+	}
+
+	@Override
+	protected void selectAllSets() {
+		viewer.setCheckedElements(PlatformUI.getWorkbench()
+				.getWorkingSetManager().getWorkingSets());
+		updateButtonAvailability();
+	}
+
+	@Override
+	protected void deselectAllSets() {
+		viewer.setCheckedElements(new Object[0]);
+		updateButtonAvailability();
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/StartupPreferencePage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/StartupPreferencePage.java
new file mode 100644
index 0000000..fa8ee1a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/StartupPreferencePage.java
@@ -0,0 +1,149 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.dialogs;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.IPreferenceConstants;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.Workbench;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.util.PrefUtil;
+import org.eclipse.ui.testing.ContributionInfo;
+import org.osgi.framework.Constants;
+
+/**
+ * The Startup preference page.
+ */
+public class StartupPreferencePage extends PreferencePage implements
+        IWorkbenchPreferencePage {
+    private Table pluginsList;
+
+    private Workbench workbench;
+
+    /**
+     * @see PreferencePage#createContents(Composite)
+     */
+    @Override
+	protected Control createContents(Composite parent) {
+    	PlatformUI.getWorkbench().getHelpSystem().setHelp(parent,
+				IWorkbenchHelpContextIds.STARTUP_PREFERENCE_PAGE);
+
+        Composite composite = createComposite(parent);
+
+        createEarlyStartupSelection(composite);
+
+        return composite;
+    }
+
+    protected Composite createComposite(Composite parent) {
+        Composite composite = new Composite(parent, SWT.NULL);
+        GridLayout layout = new GridLayout();
+        layout.marginWidth = 0;
+        layout.marginHeight = 0;
+        composite.setLayout(layout);
+        GridData data = new GridData(GridData.FILL_BOTH
+                | GridData.VERTICAL_ALIGN_FILL | GridData.HORIZONTAL_ALIGN_FILL);
+        composite.setLayoutData(data);
+        composite.setFont(parent.getFont());
+
+        return composite;
+    }
+
+    protected void createEarlyStartupSelection(Composite parent) {
+        Label label = new Label(parent, SWT.NONE);
+        label.setText(WorkbenchMessages.get().StartupPreferencePage_label);
+        label.setFont(parent.getFont());
+        GridData data = new GridData(GridData.FILL_HORIZONTAL);
+        label.setLayoutData(data);
+        pluginsList = new Table(parent, SWT.BORDER | SWT.CHECK | SWT.H_SCROLL
+                | SWT.V_SCROLL);
+        data = new GridData(GridData.FILL_BOTH);
+        pluginsList.setFont(parent.getFont());
+        pluginsList.setLayoutData(data);
+		TableViewer viewer = new TableViewer(pluginsList);
+		viewer.setLabelProvider(new LabelProvider() {
+			@Override
+			public String getText(Object element) {
+				return Platform.getBundle(((ContributionInfo) element).getBundleId())
+						.getHeaders().get(
+						Constants.BUNDLE_NAME);
+			}
+		});
+		viewer.setContentProvider(ArrayContentProvider.getInstance());
+		viewer.setInput(workbench.getEarlyActivatedPlugins());
+		updateCheckState();
+    }
+
+	private void updateCheckState() {
+        HashSet disabledPlugins = new HashSet(Arrays.asList(workbench.getDisabledEarlyActivatedPlugins()));
+		for (int i = 0; i < pluginsList.getItemCount(); i++) {
+			TableItem item = pluginsList.getItem(i);
+			String pluginId = ((ContributionInfo) item.getData()).getBundleId();
+            item.setChecked(!disabledPlugins.contains(pluginId));
+        }
+    }
+
+    /**
+     * @see IWorkbenchPreferencePage
+     */
+    @Override
+	public void init(IWorkbench workbench) {
+        this.workbench = (Workbench) workbench;
+    }
+
+    /**
+     * @see PreferencePage
+     */
+    @Override
+	protected void performDefaults() {
+		IPreferenceStore store = PrefUtil.getInternalPreferenceStore();
+		store.setToDefault(IPreferenceConstants.PLUGINS_NOT_ACTIVATED_ON_STARTUP);
+		updateCheckState();
+    }
+
+    /**
+     * @see PreferencePage
+     */
+    @Override
+	public boolean performOk() {
+        StringBuffer preference = new StringBuffer();
+        TableItem items[] = pluginsList.getItems();
+        for (int i = 0; i < items.length; i++) {
+            if (!items[i].getChecked()) {
+				preference.append(((ContributionInfo) items[i].getData()).getBundleId());
+                preference.append(IPreferenceConstants.SEPARATOR);
+            }
+        }
+        String pref = preference.toString();
+        IPreferenceStore store = PrefUtil.getInternalPreferenceStore();
+		store.setValue(IPreferenceConstants.PLUGINS_NOT_ACTIVATED_ON_STARTUP, pref);
+        PrefUtil.savePrefs();
+        return true;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ViewComparator.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ViewComparator.java
new file mode 100644
index 0000000..4e33fe2
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ViewComparator.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2014 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 430603
+ *******************************************************************************/
+package org.eclipse.ui.internal.dialogs;
+
+import org.eclipse.e4.ui.model.application.descriptor.basic.MPartDescriptor;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.ui.internal.WorkbenchMessages;
+
+/**
+ * This is used to sort views in a ShowViewDialog.
+ */
+public class ViewComparator extends ViewerComparator {
+
+	private final static String EMPTY_STRING = ""; //$NON-NLS-1$
+
+	/**
+	 * Returns a negative, zero, or positive number depending on whether the
+	 * first element is less than, equal to, or greater than the second element.
+	 */
+	@Override
+	public int compare(Viewer viewer, Object e1, Object e2) {
+		// place "General" category first
+		if (WorkbenchMessages.get().ICategory_other.equals(e1)) {
+			return -1;
+		}
+		if (WorkbenchMessages.get().ICategory_general.equals(e2)) {
+			return 1;
+		}
+
+		String str1;
+		if (e1 instanceof MPartDescriptor) {
+			str1 = ((MPartDescriptor) e1).getLocalizedLabel();
+		} else {
+			str1 = e1.toString();
+		}
+
+		String str2;
+		if (e2 instanceof MPartDescriptor) {
+			str2 = ((MPartDescriptor) e2).getLocalizedLabel();
+		} else {
+			str2 = e2.toString();
+		}
+		if (str1 == null) {
+			str1 = EMPTY_STRING;
+		}
+		if (str2 == null) {
+			str2 = EMPTY_STRING;
+		}
+		String s1 = DialogUtil.removeAccel(str1);
+		String s2 = DialogUtil.removeAccel(str2);
+		return getComparator().compare(s1, s2);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ViewContentProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ViewContentProvider.java
new file mode 100644
index 0000000..527cee6
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ViewContentProvider.java
@@ -0,0 +1,190 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 430603, 450817, 472654
+ *******************************************************************************/
+package org.eclipse.ui.internal.dialogs;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.descriptor.basic.MPartDescriptor;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.ui.activities.WorkbenchActivityHelper;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.intro.IIntroConstants;
+import org.eclipse.ui.views.IViewDescriptor;
+import org.eclipse.ui.views.IViewRegistry;
+
+/**
+ * Provides content for viewers that wish to show Views.
+ */
+public class ViewContentProvider implements ITreeContentProvider {
+
+	/**
+	 * Child cache. Map from Object->Object[]. Our hasChildren() method is
+	 * expensive so it's better to cache the results of getChildren().
+	 */
+	private Map<Object, Object[]> childMap = new HashMap<>();
+
+	private MApplication application;
+	private IViewRegistry viewRegistry;
+
+	public ViewContentProvider(MApplication application) {
+		this.application = application;
+		viewRegistry = WorkbenchPlugin.getDefault().getViewRegistry();
+	}
+
+	@Override
+	public void dispose() {
+		childMap.clear();
+	}
+
+	@Override
+	public Object getParent(Object element) {
+		return null;
+	}
+
+	@Override
+	public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+		childMap.clear();
+		application = (MApplication) newInput;
+	}
+
+	@Override
+	public Object[] getElements(Object element) {
+		return getChildren(element);
+	}
+
+	@Override
+	public boolean hasChildren(Object element) {
+		if (element instanceof MApplication) {
+			return true;
+		} else if (element instanceof String) {
+			return true;
+		}
+		return false;
+	}
+
+	@Override
+	public Object[] getChildren(Object element) {
+		Object[] children = childMap.get(element);
+		if (children == null) {
+			children = createChildren(element);
+			childMap.put(element, children);
+		}
+		return children;
+	}
+
+	/**
+	 * Determines the categories and views
+	 *
+	 * Views are identified as PartDescriptors which have the tag "View"
+	 *
+	 */
+	private Object[] createChildren(Object element) {
+		if (element instanceof MApplication) {
+			return determineTopLevelElements(element).toArray();
+		} else if (element instanceof String) {
+			return determineViewsInCategory((String) element).toArray();
+		}
+		return new Object[0];
+	}
+
+	/**
+	 * @param categoryDescription
+	 * @return views with the category tag
+	 */
+	private Set<MPartDescriptor> determineViewsInCategory(String categoryDescription) {
+		List<MPartDescriptor> descriptors = application.getDescriptors();
+		Set<MPartDescriptor> categoryDescriptors = new HashSet<>();
+		for (MPartDescriptor descriptor : descriptors) {
+			if (isFilteredByActivity(descriptor.getElementId()) || isIntroView(descriptor.getElementId())) {
+				continue;
+			}
+			String category = descriptor.getCategory();
+			if (categoryDescription.equals(category)) {
+				categoryDescriptors.add(descriptor);
+			}
+		}
+		return categoryDescriptors;
+	}
+
+	/**
+	 * Determines the views and categories for the top level
+	 */
+	private Set<Object> determineTopLevelElements(Object element) {
+		List<MPartDescriptor> descriptors = ((MApplication) element).getDescriptors();
+		Set<String> categories = new HashSet<>();
+		Set<MPartDescriptor> visibleViews = new HashSet<>();
+		for (MPartDescriptor descriptor : descriptors) {
+			// only process views and hide views which are filtered by
+			// activities
+			if (!isView(descriptor) || isFilteredByActivity(descriptor.getElementId())) {
+				continue;
+			}
+
+			// determine the categories
+			String category = descriptor.getCategory();
+
+			// if view has not category show it directly
+			if (category == null) {
+				visibleViews.add(descriptor);
+				// otherwise just show the category
+			} else {
+				categories.add(category);
+			}
+		}
+
+		Set<Object> combinedTopElements = new HashSet<>();
+		combinedTopElements.addAll(categories);
+		combinedTopElements.addAll(visibleViews);
+		return combinedTopElements;
+	}
+
+
+	/**
+	 * Determines if the part is a view or and editor
+	 *
+	 * @param descriptor
+	 *
+	 * @return true if part is tagged as view
+	 */
+	private boolean isView(MPartDescriptor descriptor) {
+		return descriptor.getTags().contains("View"); //$NON-NLS-1$
+	}
+
+	/**
+	 * Remove Eclipse introview from this list, as it opened via the Help ->
+	 * Welcome menu
+	 */
+	private boolean isIntroView(String id) {
+		return (id.equals(IIntroConstants.INTRO_VIEW_ID));
+	}
+
+	/**
+	 * Evaluates if the view is filtered by an activity
+	 *
+	 * @param elementId
+	 * @return result of the check
+	 */
+	private boolean isFilteredByActivity(String elementId) {
+		IViewDescriptor[] views = viewRegistry.getViews();
+		for (IViewDescriptor descriptor : views) {
+			if (descriptor.getId().equals(elementId) && WorkbenchActivityHelper.filterItem(descriptor)) {
+				return true;
+			}
+		}
+		return false;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ViewLabelProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ViewLabelProvider.java
new file mode 100644
index 0000000..f06f520
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ViewLabelProvider.java
@@ -0,0 +1,135 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Benjamin Muskalla  - bug 77710
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 430603, 472654
+ *     Simon Scholz <simon.scholz@vogella.com> - Bug 455527
+ *******************************************************************************/
+package org.eclipse.ui.internal.dialogs;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.ui.model.application.MApplicationElement;
+import org.eclipse.e4.ui.model.application.descriptor.basic.MPartDescriptor;
+import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective;
+import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
+import org.eclipse.e4.ui.workbench.IResourceUtilities;
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+import org.eclipse.e4.ui.workbench.modeling.EPartService;
+import org.eclipse.e4.ui.workbench.swt.util.ISWTResourceUtilities;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.internal.WorkbenchMessages;
+
+/**
+ * Provides labels for view children.
+ */
+public class ViewLabelProvider extends ColumnLabelProvider {
+
+	/**
+	 * Image descriptor for enabled clear button.
+	 */
+	private static final String FOLDER_ICON = "org.eclipse.e4.descriptor.folder"; //$NON-NLS-1$
+
+	private Map<String, Image> imageMap = new HashMap<>();
+	private IEclipseContext context;
+	private final Color dimmedForeground;
+
+	private EModelService modelService;
+
+	private MWindow window;
+
+	private EPartService partService;
+
+	/**
+	 * @param context
+	 * @param modelService
+	 * @param partService
+	 * @param window
+	 *            the workbench window
+	 * @param dimmedForeground
+	 *            the dimmed foreground color to use for views that are already
+	 *            open
+	 */
+	public ViewLabelProvider(IEclipseContext context, EModelService modelService, EPartService partService,
+			MWindow window,
+			Color dimmedForeground) {
+		this.context = context;
+		this.modelService = modelService;
+		this.partService = partService;
+		this.window = window;
+		this.dimmedForeground = dimmedForeground;
+	}
+
+	@Override
+	public void dispose() {
+		for (Image image : imageMap.values()) {
+			image.dispose();
+		}
+		super.dispose();
+	}
+
+	@Override
+	public Image getImage(Object element) {
+		if (element instanceof MPartDescriptor) {
+			String iconURI = ((MPartDescriptor) element).getIconURI();
+			if (iconURI != null && iconURI.length() > 0) {
+				Image image = imageMap.get(iconURI);
+				if (image == null) {
+					ISWTResourceUtilities resUtils = (ISWTResourceUtilities) context
+							.get(IResourceUtilities.class.getName());
+					image = resUtils.imageDescriptorFromURI(URI.createURI(iconURI)).createImage();
+					imageMap.put(iconURI, image);
+				}
+				return image;
+			}
+			return null;
+		} else if (element instanceof String) {
+			Image image = imageMap.get(FOLDER_ICON);
+			if (image == null) {
+				ImageDescriptor desc = WorkbenchImages
+						.getImageDescriptor(ISharedImages.IMG_OBJ_FOLDER);
+				image = desc.createImage();
+				imageMap.put(FOLDER_ICON, desc.createImage());
+			}
+			return image;
+		}
+		return null;
+	}
+
+	@Override
+	public String getText(Object element) {
+		String label = WorkbenchMessages.get().ViewLabel_unknown;
+		if (element instanceof String) {
+			label = (String) element;
+		} else if (element instanceof MPartDescriptor) {
+			label = ((MPartDescriptor) element).getLocalizedLabel();
+		}
+		return label;
+	}
+
+	@Override
+	public Color getForeground(Object element) {
+		if (element instanceof MApplicationElement) {
+			String elementId = ((MApplicationElement) element).getElementId();
+			MPerspective activePerspective = modelService.getActivePerspective(window);
+			if(partService.isPartOrPlaceholderInPerspective(elementId, activePerspective)){
+				return dimmedForeground;
+			}
+		}
+
+		return null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ViewPatternFilter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ViewPatternFilter.java
new file mode 100644
index 0000000..8a4488f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/ViewPatternFilter.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2014 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 430603
+ *******************************************************************************/
+package org.eclipse.ui.internal.dialogs;
+
+import org.eclipse.e4.ui.model.LocalizationHelper;
+import org.eclipse.e4.ui.model.application.descriptor.basic.MPartDescriptor;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.ui.dialogs.PatternFilter;
+
+/**
+ * A class that handles filtering view node items based on a supplied matching
+ * string.
+ *
+ * @since 3.2
+ *
+ */
+public class ViewPatternFilter extends PatternFilter {
+
+
+	@Override
+	public boolean isElementSelectable(Object element) {
+		return element instanceof MPartDescriptor;
+	}
+
+	@Override
+	protected boolean isLeafMatch(Viewer viewer, Object element) {
+		if (element instanceof String) {
+			return false;
+		}
+
+		String text = null;
+		if (element instanceof MPartDescriptor) {
+			MPartDescriptor desc = (MPartDescriptor) element;
+			text = LocalizationHelper.getLocalized(desc.getLabel(), desc);
+			if (wordMatches(text)) {
+				return true;
+			}
+		}
+
+		return false;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WizardActivityFilter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WizardActivityFilter.java
new file mode 100644
index 0000000..5dac2b9
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WizardActivityFilter.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ *******************************************************************************/
+package org.eclipse.ui.internal.dialogs;
+
+import java.util.ArrayList;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.ui.activities.WorkbenchActivityHelper;
+import org.eclipse.ui.model.AdaptableList;
+
+/**
+ * Viewer filter designed to work with the new wizard page (and its input/content provider).
+ * This will filter all non-primary wizards that are not enabled by activity.
+ *
+ * @since 3.0
+ */
+public class WizardActivityFilter extends ViewerFilter {
+	private boolean filterPrimaryWizards = false;
+
+	public void setFilterPrimaryWizards(boolean filter) {
+		filterPrimaryWizards = filter;
+	}
+
+    @Override
+	public boolean select(Viewer viewer, Object parentElement, Object element) {
+		if (parentElement.getClass().equals(AdaptableList.class) && !filterPrimaryWizards) {
+			return true; //top-level ("primary") wizards should always be returned
+		}
+
+        if (WorkbenchActivityHelper.filterItem(element)) {
+			return false;
+		}
+
+        return true;
+    }
+
+	@Override
+	public Object[] filter(Viewer viewer, Object parent, Object[] elements) {
+		int size = elements.length;
+		ArrayList<Object> out = new ArrayList<>(size);
+
+		for (int i = 0; i < size; ++i) {
+			Object element = elements[i];
+			if (element instanceof WizardCollectionElement) {
+				Object wizardCollection = WizardCollectionElement.filter(viewer, this,
+						(WizardCollectionElement) element);
+				if (wizardCollection != null) {
+					out.add(wizardCollection);
+				}
+			} else if (select(viewer, parent, element)) {
+				out.add(element);
+			}
+		}
+		return out.toArray();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WizardCollectionElement.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WizardCollectionElement.java
new file mode 100644
index 0000000..1f500ec
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WizardCollectionElement.java
@@ -0,0 +1,449 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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
+ *     Jan-Hendrik Diederich, Bredex GmbH - bug 201052
+ *******************************************************************************/
+package org.eclipse.ui.internal.dialogs;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.ui.IPluginContribution;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.activities.WorkbenchActivityHelper;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.model.AdaptableList;
+import org.eclipse.ui.model.IWorkbenchAdapter;
+import org.eclipse.ui.wizards.IWizardCategory;
+import org.eclipse.ui.wizards.IWizardDescriptor;
+
+/**
+ * Instances of this class are a collection of WizardCollectionElements,
+ * thereby facilitating the definition of tree structures composed of these
+ * elements. Instances also store a list of wizards.
+ */
+public class WizardCollectionElement extends AdaptableList implements IPluginContribution,
+		IWizardCategory {
+    private String id;
+
+    private String pluginId;
+
+    private String name;
+
+    private WizardCollectionElement parent;
+
+    private AdaptableList wizards = new AdaptableList();
+
+	private IConfigurationElement configElement;
+
+    /**
+     * Creates a new <code>WizardCollectionElement</code>. Parent can be
+     * null.
+     * @param id the id
+     * @param pluginId the plugin
+     * @param name the name
+     * @param parent the parent
+     */
+    public WizardCollectionElement(String id, String pluginId, String name,
+            WizardCollectionElement parent) {
+        this.name = name;
+        this.id = id;
+        this.pluginId = pluginId;
+        this.parent = parent;
+    }
+
+    /**
+     * Creates a new <code>WizardCollectionElement</code>. Parent can be
+     * null.
+     *
+     * @param element
+     * @param parent
+     * @since 3.1
+     */
+    public WizardCollectionElement(IConfigurationElement element, WizardCollectionElement parent) {
+		configElement = element;
+		id = configElement.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+		this.parent = parent;
+	}
+
+	private WizardCollectionElement(WizardCollectionElement input, AdaptableList wizards) {
+		this(input.id, input.pluginId, input.name, input.parent);
+		this.configElement = input.configElement;
+		this.wizards = wizards;
+
+		for (Object child : input.children) {
+			children.add(child);
+		}
+	}
+
+	/**
+     * Adds a wizard collection to this collection.
+     */
+    @Override
+	public AdaptableList add(IAdaptable a) {
+        if (a instanceof WorkbenchWizardElement) {
+            wizards.add(a);
+        } else {
+            super.add(a);
+        }
+        return this;
+    }
+
+
+    /**
+     * Remove a wizard from this collection.
+     */
+    @Override
+	public void remove(IAdaptable a) {
+        if (a instanceof WorkbenchWizardElement) {
+            wizards.remove(a);
+        } else {
+            super.remove(a);
+        }
+	}
+
+	/**
+     * Returns the wizard collection child object corresponding to the passed
+     * path (relative to this object), or <code>null</code> if such an object
+     * could not be found.
+     *
+     * @param searchPath
+     *            org.eclipse.core.runtime.IPath
+     * @return WizardCollectionElement
+     */
+    public WizardCollectionElement findChildCollection(IPath searchPath) {
+        String searchString = searchPath.segment(0);
+		for (Object element : getChildren(null)) {
+            WizardCollectionElement currentCategory = (WizardCollectionElement) element;
+            if (currentCategory.getId().equals(searchString)) {
+                if (searchPath.segmentCount() == 1) {
+					return currentCategory;
+				}
+
+                return currentCategory.findChildCollection(searchPath
+                        .removeFirstSegments(1));
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns the wizard category corresponding to the passed
+     * id, or <code>null</code> if such an object could not be found.
+     * This recurses through child categories.
+     *
+     * @param id the id for the child category
+     * @return the category, or <code>null</code> if not found
+     * @since 3.1
+     */
+    public WizardCollectionElement findCategory(String id) {
+		for (Object element : getChildren(null)) {
+            WizardCollectionElement currentCategory = (WizardCollectionElement) element;
+            if (id.equals(currentCategory.getId())) {
+                    return currentCategory;
+            }
+            WizardCollectionElement childCategory = currentCategory.findCategory(id);
+            if (childCategory != null) {
+                return childCategory;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns this collection's associated wizard object corresponding to the
+     * passed id, or <code>null</code> if such an object could not be found.
+     *
+     * @param searchId the id to search on
+     * @param recursive whether to search recursivly
+     * @return the element
+     */
+    public WorkbenchWizardElement findWizard(String searchId, boolean recursive) {
+		for (Object wizard : getWizards()) {
+            WorkbenchWizardElement currentWizard = (WorkbenchWizardElement) wizard;
+            if (currentWizard.getId().equals(searchId)) {
+				return currentWizard;
+			}
+        }
+        if (!recursive) {
+			return null;
+		}
+        for (Iterator iterator = children.iterator(); iterator.hasNext();) {
+            WizardCollectionElement child = (WizardCollectionElement) iterator
+                    .next();
+            WorkbenchWizardElement result = child.findWizard(searchId, true);
+            if (result != null) {
+				return result;
+			}
+        }
+        return null;
+    }
+
+    /**
+     * Returns an object which is an instance of the given class associated
+     * with this object. Returns <code>null</code> if no such object can be
+     * found.
+     */
+	@Override
+	public <T> T getAdapter(Class<T> adapter) {
+        if (adapter == IWorkbenchAdapter.class) {
+			return adapter.cast(this);
+        }
+        return Platform.getAdapterManager().getAdapter(this, adapter);
+    }
+
+    /**
+     * Returns the unique ID of this element.
+     */
+    @Override
+	public String getId() {
+        return id;
+    }
+
+    /**
+     * Returns the label for this collection.
+     */
+    @Override
+	public String getLabel(Object o) {
+    	return configElement != null ? configElement
+				.getAttribute(IWorkbenchRegistryConstants.ATT_NAME) : name;
+    }
+
+    /**
+     * Returns the logical parent of the given object in its tree.
+     */
+    @Override
+	public Object getParent(Object o) {
+        return parent;
+    }
+
+    @Override
+	public IPath getPath() {
+        if (parent == null) {
+			return new Path(""); //$NON-NLS-1$
+		}
+
+        return parent.getPath().append(getId());
+    }
+
+
+    @Override
+	public IWizardDescriptor [] getWizards() {
+		return getWizardsExpression((IWizardDescriptor[]) wizards
+				.getTypedChildren(IWizardDescriptor.class));
+	}
+
+    /**
+     * Takes an array of <code>IWizardDescriptor</code> and removes all
+     * entries which fail the Expressions check.
+     *
+     * @param wizardDescriptors Array of <code>IWizardDescriptor</code>.
+     * @return The array minus the elements which faled the Expressions check.
+     */
+    private IWizardDescriptor[] getWizardsExpression(IWizardDescriptor[] wizardDescriptors) {
+        int size = wizardDescriptors.length;
+        List result = new ArrayList(size);
+        for (int i = 0; i < size; i++) {
+            if (!WorkbenchActivityHelper.restrictUseOf(wizardDescriptors[i]))
+                result.add(wizardDescriptors[i]);
+        }
+        return (IWizardDescriptor[])result
+                    .toArray(new IWizardDescriptor[result.size()]);
+    }
+
+    /**
+     * Return the wizards minus the wizards which failed the expressions check.
+     *
+     * @return the wizards
+     * @since 3.1
+     */
+    public WorkbenchWizardElement [] getWorkbenchWizardElements() {
+    	return getWorkbenchWizardElementsExpression(
+    	    (WorkbenchWizardElement[]) wizards
+				.getTypedChildren(WorkbenchWizardElement.class));
+    }
+
+    /**
+     * Takes an array of <code>WorkbenchWizardElement</code> and removes all
+     * entries which fail the Expressions check.
+     *
+     * @param workbenchWizardElements Array of <code>WorkbenchWizardElement</code>.
+     * @return The array minus the elements which faled the Expressions check.
+     */
+    private WorkbenchWizardElement[] getWorkbenchWizardElementsExpression(
+        WorkbenchWizardElement[] workbenchWizardElements) {
+        int size = workbenchWizardElements.length;
+        List result = new ArrayList(size);
+        for (int i=0; i<size; i++) {
+            WorkbenchWizardElement element = workbenchWizardElements[i];
+            if (!WorkbenchActivityHelper.restrictUseOf(element))
+                result.add(element);
+        }
+        return (WorkbenchWizardElement[])result.toArray(new WorkbenchWizardElement[result.size()]);
+    }
+
+
+    /**
+     * Returns true if this element has no children and no wizards.
+     *
+     * @return whether it is empty
+     */
+    public boolean isEmpty() {
+        return size() == 0 && wizards.size() == 0;
+    }
+
+    /**
+     * For debugging purposes.
+     */
+    @Override
+	public String toString() {
+        StringBuffer buf = new StringBuffer("WizardCollection, "); //$NON-NLS-1$
+        buf.append(children.size());
+        buf.append(" children, "); //$NON-NLS-1$
+        buf.append(wizards.size());
+        buf.append(" wizards"); //$NON-NLS-1$
+        return buf.toString();
+    }
+
+    @Override
+	public ImageDescriptor getImageDescriptor(Object object) {
+        return WorkbenchImages.getImageDescriptor(ISharedImages.IMG_OBJ_FOLDER);
+    }
+
+    @Override
+	public String getLocalId() {
+        return getId();
+    }
+
+    @Override
+	public String getPluginId() {
+        return configElement != null ? configElement.getNamespace() : pluginId;
+    }
+
+
+    @Override
+	public IWizardCategory getParent() {
+		return parent;
+	}
+
+    @Override
+	public IWizardCategory[] getCategories() {
+		return (IWizardCategory []) getTypedChildren(IWizardCategory.class);
+	}
+
+    /**
+     * Return the collection elements.
+     *
+     * @return the collection elements
+     * @since 3.1
+     */
+    public WizardCollectionElement [] getCollectionElements() {
+    	return (WizardCollectionElement[]) getTypedChildren(WizardCollectionElement.class);
+    }
+
+    /**
+     * Return the raw adapted list of wizards.
+     *
+     * @return the list of wizards
+     * @since 3.1
+     */
+    public AdaptableList getWizardAdaptableList() {
+    	return wizards;
+    }
+
+    @Override
+	public String getLabel() {
+		return getLabel(this);
+	}
+
+    /**
+     * Return the configuration element.
+     *
+     * @return the configuration element
+     * @since 3.1
+     */
+    public IConfigurationElement getConfigurationElement() {
+    	return configElement;
+    }
+
+    /**
+     * Return the parent collection element.
+     *
+     * @return the parent
+     * @since 3.1
+     */
+	public WizardCollectionElement getParentCollection() {
+		return parent;
+	}
+
+	@Override
+	public IWizardDescriptor findWizard(String id) {
+		return findWizard(id, true);
+	}
+
+	@Override
+	public IWizardCategory findCategory(IPath path) {
+		return findChildCollection(path);
+	}
+
+	/**
+	 * The helper method used to filter <code>WizardCollectionElement</code>
+	 * using <code>ViewerFilter</code>.<br>
+	 * It returns the result in the following way:<br>
+	 * - if some of the wizards from the input collection is skipped by the
+	 * viewerFilter then the modified copy of the collection (without skipped
+	 * wizards) is returned<br>
+	 * - when all wizards are skipped then null will be returned<br>
+	 * - if none of the wizards is skipped during filtering then the original
+	 * input collection is returned
+	 *
+	 * @param viewer
+	 *            the Viewer used by <code>ViewerFilter.select</code> method
+	 * @param viewerFilter
+	 *            the ViewerFilter
+	 * @param inputCollection
+	 *            collection to filter
+	 * @return inputCollection, modified copy of inputCollection or null
+	 *
+	 */
+	static WizardCollectionElement filter(Viewer viewer, ViewerFilter viewerFilter,
+			WizardCollectionElement inputCollection) {
+		AdaptableList wizards = null;
+		for (Object child : inputCollection.getWizardAdaptableList().getChildren()) {
+			if (viewerFilter.select(viewer, inputCollection, child)) {
+				if (wizards == null) {
+					wizards = new AdaptableList();
+				}
+				wizards.add((IAdaptable) child);
+			}
+		}
+
+		if (wizards == null) {
+			if (inputCollection.getChildren().length > 0) {
+				return new WizardCollectionElement(inputCollection, new AdaptableList());
+			}
+			return null;
+		}
+
+		if (inputCollection.getWizardAdaptableList().size() == wizards.size()) {
+			return inputCollection;
+		}
+		return new WizardCollectionElement(inputCollection, wizards);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WizardContentProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WizardContentProvider.java
new file mode 100644
index 0000000..ad72545
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WizardContentProvider.java
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.internal.dialogs;
+
+import java.util.ArrayList;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.ui.model.AdaptableList;
+
+/**
+ * Provider used by the NewWizardNewPage.
+ *
+ * @since 3.0
+ */
+public class WizardContentProvider implements ITreeContentProvider {
+
+    private AdaptableList input;
+
+    @Override
+	public void dispose() {
+        input = null;
+    }
+
+    @Override
+	public Object[] getChildren(Object parentElement) {
+        if (parentElement instanceof WizardCollectionElement) {
+            ArrayList list = new ArrayList();
+            WizardCollectionElement element = (WizardCollectionElement) parentElement;
+
+			for (Object childCollection : element.getChildren()) {
+                handleChild(childCollection, list);
+            }
+
+			for (Object childWizard : element.getWizards()) {
+                handleChild(childWizard, list);
+            }
+
+            // flatten lists with only one category
+            if (list.size() == 1
+                    && list.get(0) instanceof WizardCollectionElement) {
+                return getChildren(list.get(0));
+            }
+
+            return list.toArray();
+        } else if (parentElement instanceof AdaptableList) {
+            AdaptableList aList = (AdaptableList) parentElement;
+            Object[] children = aList.getChildren();
+            ArrayList list = new ArrayList(children.length);
+            for (Object element : children) {
+                handleChild(element, list);
+            }
+            // if there is only one category, return it's children directly (flatten list)
+            if (list.size() == 1
+            		&& list.get(0) instanceof WizardCollectionElement) {
+                return getChildren(list.get(0));
+            }
+
+            return list.toArray();
+        } else {
+			return new Object[0];
+		}
+    }
+
+    @Override
+	public Object[] getElements(Object inputElement) {
+        return getChildren(inputElement);
+    }
+
+    @Override
+	public Object getParent(Object element) {
+        if (element instanceof WizardCollectionElement) {
+			for (Object child : input.getChildren()) {
+                if (child.equals(element)) {
+					return input;
+				}
+            }
+            return ((WizardCollectionElement) element).getParent(element);
+        }
+        return null;
+    }
+
+    /**
+     * Adds the item to the list, unless it's a collection element without any children.
+     *
+     * @param element the element to test and add
+     * @param list the <code>Collection</code> to add to.
+     * @since 3.0
+     */
+    private void handleChild(Object element, ArrayList list) {
+        if (element instanceof WizardCollectionElement) {
+            if (hasChildren(element)) {
+				list.add(element);
+			}
+        } else {
+            list.add(element);
+        }
+    }
+
+    @Override
+	public boolean hasChildren(Object element) {
+        if (element instanceof WizardCollectionElement) {
+            if (getChildren(element).length > 0) {
+				return true;
+			}
+        }
+        return false;
+    }
+
+    @Override
+	public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+        input = (AdaptableList) newInput;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WizardPatternFilter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WizardPatternFilter.java
new file mode 100644
index 0000000..fe9907b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WizardPatternFilter.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ *******************************************************************************/
+package org.eclipse.ui.internal.dialogs;
+
+import java.util.ArrayList;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.ui.dialogs.PatternFilter;
+
+/**
+ * A class that handles filtering wizard node items based on a supplied matching
+ * string and keywords
+ *
+ * @since 3.2
+ *
+ */
+public class WizardPatternFilter extends PatternFilter {
+	/**
+	 * Create a new instance of a WizardPatternFilter
+	 * @param isMatchItem
+	 */
+	public WizardPatternFilter() {
+		super();
+	}
+
+	@Override
+	public boolean isElementSelectable(Object element) {
+		return element instanceof WorkbenchWizardElement;
+	}
+
+	@Override
+	protected boolean isLeafMatch(Viewer viewer, Object element) {
+		if (element instanceof WizardCollectionElement) {
+			return false;
+		}
+
+		if (element instanceof WorkbenchWizardElement) {
+			WorkbenchWizardElement desc = (WorkbenchWizardElement) element;
+			String text = desc.getLabel();
+			if (wordMatches(text)) {
+				return true;
+			}
+			String wizDesc = desc.getDescription();
+			if (wordMatches(wizDesc)) {
+				return true;
+			}
+
+			for (String keywordLabel : desc.getKeywordLabels()) {
+				if (wordMatches(keywordLabel))
+					return true;
+			}
+		}
+		return false;
+	}
+
+	@Override
+	public Object[] filter(Viewer viewer, Object parent, Object[] elements) {
+		ArrayList<Object> result = new ArrayList<>();
+
+		for (Object elem : super.filter(viewer, parent, elements)) {
+			if (elem instanceof WizardCollectionElement) {
+				Object wizardCollection = WizardCollectionElement.filter(viewer, this,
+						(WizardCollectionElement) elem);
+				if (wizardCollection != null) {
+					result.add(wizardCollection);
+				}
+			} else {
+				result.add(elem);
+			}
+		}
+
+		return result.toArray();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WizardTagFilter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WizardTagFilter.java
new file mode 100644
index 0000000..66c65df
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WizardTagFilter.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.dialogs;
+
+import org.eclipse.jface.viewers.AbstractTreeViewer;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.ui.wizards.IWizardDescriptor;
+
+/**
+ * A viewer filter that will exclude all IWizardDescriptors that do not have at
+ * least one tag in a provided set.
+ *
+ * @since 3.1
+ */
+public class WizardTagFilter extends ViewerFilter {
+
+	private String [] myTags;
+
+	/**
+	 * Create a new instance of this filter
+	 * @param tags the wizard tags to allow
+	 */
+	public WizardTagFilter(String [] tags) {
+		myTags = tags;
+	}
+
+	@Override
+	public boolean select(Viewer viewer, Object parentElement, Object element) {
+		if (element instanceof IWizardDescriptor) {
+			IWizardDescriptor desc = (IWizardDescriptor)element;
+			for (String tag : desc.getTags()) {
+				for (String myTag : myTags) {
+					if (tag.equals(myTag)) {
+						return true;
+					}
+				}
+			}
+			return false;
+		}
+        Object[] children = ((ITreeContentProvider) ((AbstractTreeViewer) viewer)
+                .getContentProvider()).getChildren(element);
+        if (children.length > 0) {
+			return filter(viewer, element, children).length > 0;
+		}
+
+		return false;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkbenchDialogBlockedHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkbenchDialogBlockedHandler.java
new file mode 100644
index 0000000..430ba0a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkbenchDialogBlockedHandler.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2014 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.ui.internal.dialogs;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.dialogs.IDialogBlockedHandler;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.internal.progress.BlockedJobsDialog;
+
+/**
+ * The WorkbenchWizardBlockedHandler is the class that implements the blocked
+ * handler for the workbench.
+ */
+public class WorkbenchDialogBlockedHandler implements IDialogBlockedHandler {
+    IProgressMonitor outerMonitor;
+
+    int nestingDepth = 0;
+
+    /**
+     * Create a new instance of the receiver.
+     */
+    public WorkbenchDialogBlockedHandler() {
+        //No default behavior
+    }
+
+    @Override
+	public void clearBlocked() {
+        if (nestingDepth == 0) {
+			return;
+		}
+
+        nestingDepth--;
+
+        if (nestingDepth <= 0) {
+            BlockedJobsDialog.clear(outerMonitor);
+            outerMonitor = null;
+            nestingDepth = 0;
+        }
+
+    }
+
+    @Override
+	public void showBlocked(Shell parentShell,
+            IProgressMonitor blockingMonitor, IStatus blockingStatus,
+            String blockedName) {
+
+        nestingDepth++;
+        if (outerMonitor == null) {
+            outerMonitor = blockingMonitor;
+            //Try to get a name as best as possible
+            if (blockedName == null && parentShell != null) {
+				blockedName = parentShell.getText();
+			}
+            BlockedJobsDialog.createBlockedDialog(parentShell, blockingMonitor,
+                    blockingStatus, blockedName);
+        }
+
+    }
+
+    @Override
+	public void showBlocked(IProgressMonitor blocking, IStatus blockingStatus,
+            String blockedName) {
+        showBlocked(null, blocking, blockingStatus, blockedName);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkbenchEditorsDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkbenchEditorsDialog.java
new file mode 100644
index 0000000..7c65c49
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkbenchEditorsDialog.java
@@ -0,0 +1,842 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.dialogs;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.dialogs.ProgressMonitorDialog;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.osgi.util.TextProcessor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Layout;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.ui.IEditorDescriptor;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorReference;
+import org.eclipse.ui.IEditorRegistry;
+import org.eclipse.ui.ISaveablesLifecycleListener;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.dialogs.SelectionDialog;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.SaveablesList;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPage;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.layout.CellData;
+import org.eclipse.ui.internal.layout.CellLayout;
+import org.eclipse.ui.internal.layout.Row;
+import org.eclipse.ui.internal.progress.ProgressMonitorJobsDialog;
+
+import com.ibm.icu.text.Collator;
+
+/**
+ * Implements a dialog showing all opened editors in the workbench
+ * and the recent closed editors
+ */
+public class WorkbenchEditorsDialog extends SelectionDialog {
+
+    private IWorkbenchWindow window;
+
+    private Table editorsTable;
+
+    private Button saveSelected;
+
+    private Button closeSelected;
+
+    private Button selectClean;
+
+    private Button invertSelection;
+
+    private Button allSelection;
+
+    private boolean showAllPersp = false;
+
+    private int sortColumn;
+
+    private List elements = new ArrayList();
+
+    private HashMap imageCache = new HashMap(11);
+
+    private HashMap disabledImageCache = new HashMap(11);
+
+    private boolean reverse = false;
+
+    private Collator collator = Collator.getInstance();
+
+    private Rectangle bounds;
+
+    private int columnsWidth[];
+
+    private static final String SORT = "sort"; //$NON-NLS-1$
+
+    private static final String ALLPERSP = "allPersp"; //$NON-NLS-1$
+
+    private static final String BOUNDS = "bounds"; //$NON-NLS-1$
+
+    private static final String COLUMNS = "columns"; //$NON-NLS-1$
+
+    private SelectionListener headerListener = new SelectionAdapter()
+    {
+        /** {@inheritDoc} */
+        @Override
+        public void widgetSelected(SelectionEvent e)
+        {
+            TableColumn column = (TableColumn) e.widget;
+            int index = editorsTable.indexOf(column);
+            if (index == sortColumn) {
+                reverse = !reverse;
+            } else {
+                sortColumn = index;
+            }
+            editorsTable.setSortDirection(reverse ? SWT.DOWN : SWT.UP);
+            editorsTable.setSortColumn(column);
+            updateItems();
+        }
+	};
+
+    /**
+     * Constructor for WorkbenchEditorsDialog.
+     *
+     * @param window the window
+     */
+    public WorkbenchEditorsDialog(IWorkbenchWindow window) {
+        super(window.getShell());
+        this.window = window;
+        setTitle(WorkbenchMessages.get().WorkbenchEditorsDialog_title);
+
+        IDialogSettings s = getDialogSettings();
+        if (s.get(ALLPERSP) == null) {
+            sortColumn = 0;
+        } else {
+            showAllPersp = s.getBoolean(ALLPERSP);
+            sortColumn = s.getInt(SORT);
+            String[] array = s.getArray(BOUNDS);
+            if (array != null) {
+                bounds = new Rectangle(0, 0, 0, 0);
+                bounds.x = Integer.valueOf(array[0]).intValue();
+                bounds.y = Integer.valueOf(array[1]).intValue();
+                bounds.width = Integer.valueOf(array[2]).intValue();
+                bounds.height = Integer.valueOf(array[3]).intValue();
+            }
+            array = s.getArray(COLUMNS);
+            if (array != null) {
+                columnsWidth = new int[array.length];
+                for (int i = 0; i < columnsWidth.length; i++) {
+					columnsWidth[i] = Integer.valueOf(array[i]).intValue();
+				}
+            }
+        }
+		setShellStyle(getShellStyle() | SWT.SHEET);
+    }
+
+    @Override
+	protected void configureShell(Shell newShell) {
+        super.configureShell(newShell);
+        PlatformUI.getWorkbench().getHelpSystem().setHelp(newShell,
+				IWorkbenchHelpContextIds.WORKBENCH_EDITORS_DIALOG);
+    }
+
+    @Override
+	protected void createButtonsForButtonBar(Composite parent) {
+        // Typically we would use the parent's createButtonsForButtonBar.
+        // However, we only want a Cancel button and not an OK button.  The
+        // OK button will be used later (in createDialogArea) to activate
+        // the selected editor.
+        createButton(parent, IDialogConstants.CANCEL_ID,
+                IDialogConstants.get().CANCEL_LABEL, false);
+        Button button = getButton(IDialogConstants.CANCEL_ID);
+        if (button != null) {
+			button.setText(WorkbenchMessages.get().WorkbenchEditorsDialog_close);
+		}
+
+    }
+
+    /**
+     * Initialize the dialog bounds with the bounds saved
+     * from the settings.
+     */
+    @Override
+	protected void initializeBounds() {
+        if (bounds != null) {
+            getShell().setBounds(bounds);
+        } else {
+            super.initializeBounds();
+        }
+    }
+
+    /**
+     * Creates the contents of this dialog, initializes the
+     * listener and the update thread.
+     */
+    @Override
+	protected Control createDialogArea(Composite parent) {
+
+        initializeDialogUnits(parent);
+
+        Font font = parent.getFont();
+
+        Composite dialogArea = new Composite(parent, SWT.NONE);
+        CellLayout dialogAreaLayout = new CellLayout(1)
+                .setMargins(
+                        convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN),
+                        convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN))
+                .setSpacing(
+                        convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING),
+                        convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING))
+                .setRow(1, Row.growing());
+        dialogArea.setLayout(dialogAreaLayout);
+        dialogArea.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+        //Label over the table
+        Label l = new Label(dialogArea, SWT.NONE);
+        l.setText(WorkbenchMessages.get().WorkbenchEditorsDialog_label);
+        l.setFont(font);
+        l.setLayoutData(new CellData().align(SWT.FILL, SWT.CENTER));
+        //Table showing the editors name, full path and perspective
+        editorsTable = new Table(dialogArea, SWT.MULTI | SWT.BORDER
+                | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION);
+        editorsTable.setLinesVisible(true);
+        editorsTable.setHeaderVisible(true);
+        editorsTable.setFont(font);
+
+        final int height = 16 * editorsTable.getItemHeight();
+        final int width = (int) (2.5 * height);
+
+        CellData tableData = new CellData().align(SWT.FILL, SWT.FILL).setHint(
+                CellData.OVERRIDE, width, height);
+
+        editorsTable.setLayoutData(tableData);
+        editorsTable.setLayout(new Layout() {
+            @Override
+			protected Point computeSize(Composite composite, int wHint,
+                    int hHint, boolean flushCache) {
+                return new Point(width, height);
+            }
+
+            @Override
+			protected void layout(Composite composite, boolean flushCache) {
+                TableColumn c[] = editorsTable.getColumns();
+                if (columnsWidth == null) {
+                    int w = editorsTable.getClientArea().width;
+                    c[0].setWidth(w * 1 / 3);
+                    c[1].setWidth(w - c[0].getWidth());
+                } else {
+                    c[0].setWidth(columnsWidth[0]);
+                    c[1].setWidth(columnsWidth[1]);
+                }
+                editorsTable.setLayout(null);
+            }
+        });
+        //Name column
+        TableColumn tc = new TableColumn(editorsTable, SWT.NONE);
+        tc.setResizable(true);
+        tc.setText(WorkbenchMessages.get().WorkbenchEditorsDialog_name);
+        tc.addSelectionListener(headerListener);
+        //Full path column
+        tc = new TableColumn(editorsTable, SWT.NONE);
+        tc.setResizable(true);
+        tc.setText(WorkbenchMessages.get().WorkbenchEditorsDialog_path);
+        tc.addSelectionListener(headerListener);
+
+        // A composite for selection option buttons
+        Composite selectionButtons = new Composite(dialogArea, SWT.NULL);
+        Label compLabel = new Label(selectionButtons, SWT.NULL);
+        compLabel.setFont(font);
+        GridLayout layout = new GridLayout();
+        layout.numColumns = 4;
+        selectionButtons.setLayout(layout);
+
+        //Select clean editors button
+        selectClean = new Button(selectionButtons, SWT.PUSH);
+        selectClean.setText(WorkbenchMessages.get().WorkbenchEditorsDialog_selectClean);
+        selectClean.addSelectionListener(new SelectionAdapter()
+        {
+            /** {@inheritDoc} */
+            @Override
+            public void widgetSelected(SelectionEvent e)
+            {
+    		    editorsTable.setSelection(selectClean(editorsTable.getItems()));
+    		    updateButtons();
+            }
+		});
+        selectClean.setFont(font);
+        setButtonLayoutData(selectClean);
+
+        //Invert selection button
+        invertSelection = new Button(selectionButtons, SWT.PUSH);
+        invertSelection.setText(WorkbenchMessages.get().WorkbenchEditorsDialog_invertSelection);
+        invertSelection.addSelectionListener(new SelectionAdapter()
+        {
+            /** {@inheritDoc} */
+            @Override
+            public void widgetSelected(SelectionEvent e)
+            {
+                editorsTable.setSelection(invertedSelection(editorsTable.getItems(), editorsTable.getSelection()));
+                updateButtons();
+            }
+		});
+        invertSelection.setFont(font);
+        setButtonLayoutData(invertSelection);
+
+        //Select all button
+        allSelection = new Button(selectionButtons, SWT.PUSH);
+        allSelection.setText(WorkbenchMessages.get().WorkbenchEditorsDialog_allSelection);
+        allSelection.addSelectionListener(new SelectionAdapter()
+        {
+            /** {@inheritDoc} */
+            @Override
+            public void widgetSelected(SelectionEvent e)
+            {
+    		    editorsTable.setSelection(editorsTable.getItems());
+    		    updateButtons();
+            }
+		});
+        allSelection.setFont(font);
+        setButtonLayoutData(allSelection);
+
+        // A composite for selected editor action buttons
+        Composite actionButtons = new Composite(dialogArea, SWT.NULL);
+        Label actLabel = new Label(actionButtons, SWT.NULL);
+        actLabel.setFont(font);
+        GridLayout actLayout = new GridLayout();
+        actLayout.numColumns = 4;
+        actionButtons.setLayout(actLayout);
+
+        // Activate selected editor button
+        createButton(actionButtons, IDialogConstants.OK_ID, WorkbenchMessages.get().WorkbenchEditorsDialog_activate,
+                true);
+
+        //Close selected editors button
+        closeSelected = new Button(actionButtons, SWT.PUSH);
+        closeSelected.setText(WorkbenchMessages.get().WorkbenchEditorsDialog_closeSelected);
+        closeSelected.addSelectionListener(new SelectionAdapter()
+        {
+            /** {@inheritDoc} */
+            @Override
+            public void widgetSelected(SelectionEvent e)
+            {
+                closeItems(editorsTable.getSelection());
+            }
+        });
+        closeSelected.setFont(font);
+        setButtonLayoutData(closeSelected);
+
+        //Save selected editors button
+        saveSelected = new Button(actionButtons, SWT.PUSH);
+        saveSelected.setText(WorkbenchMessages.get().WorkbenchEditorsDialog_saveSelected);
+        saveSelected.addSelectionListener(new SelectionAdapter()
+        {
+            /** {@inheritDoc} */
+            @Override
+            public void widgetSelected(SelectionEvent e)
+            {
+                saveItems(editorsTable.getSelection());
+            }
+        });
+        saveSelected.setFont(font);
+        setButtonLayoutData(saveSelected);
+
+        //Show only active perspective button
+        final Button showAllPerspButton = new Button(dialogArea, SWT.CHECK);
+        showAllPerspButton.setText(WorkbenchMessages.get().WorkbenchEditorsDialog_showAllPersp);
+        showAllPerspButton.setSelection(showAllPersp);
+        showAllPerspButton.setFont(font);
+        setButtonLayoutData(showAllPerspButton);
+        showAllPerspButton.addSelectionListener(new SelectionAdapter()
+        {
+            /** {@inheritDoc} */
+            @Override
+            public void widgetSelected(SelectionEvent e)
+            {
+    		    showAllPersp = showAllPerspButton.getSelection();
+    		    updateItems();
+            }
+		});
+        //Create the items and update buttons state
+        updateItems();
+        updateButtons();
+
+        editorsTable.addSelectionListener(new SelectionAdapter() {
+            @Override
+			public void widgetSelected(SelectionEvent e) {
+                updateButtons();
+            }
+
+            @Override
+			public void widgetDefaultSelected(SelectionEvent e) {
+                okPressed();
+            }
+        });
+        editorsTable.addDisposeListener(e -> {
+		    for (Iterator images1 = imageCache.values().iterator(); images1
+		            .hasNext();) {
+		        Image i1 = (Image) images1.next();
+		        i1.dispose();
+		    }
+		    for (Iterator images2 = disabledImageCache.values().iterator(); images2
+		            .hasNext();) {
+		        Image i2 = (Image) images2.next();
+		        i2.dispose();
+		    }
+		});
+        editorsTable.setFocus();
+        applyDialogFont(dialogArea);
+        return dialogArea;
+    }
+
+    /**
+     * Updates the button state (enabled/disabled)
+     */
+    private void updateButtons() {
+        TableItem selectedItems[] = editorsTable.getSelection();
+        boolean hasDirty = false;
+        for (TableItem selectedItem : selectedItems) {
+            Adapter editor = (Adapter) selectedItem.getData();
+            if (editor.isDirty()) {
+                hasDirty = true;
+                break;
+            }
+        }
+        saveSelected.setEnabled(hasDirty);
+
+        TableItem allItems[] = editorsTable.getItems();
+        boolean hasClean = false;
+        for (TableItem tableItem : allItems) {
+            Adapter editor = (Adapter) tableItem.getData();
+            if (!editor.isDirty()) {
+                hasClean = true;
+                break;
+            }
+        }
+        selectClean.setEnabled(hasClean);
+        invertSelection.setEnabled(allItems.length > 0);
+        closeSelected.setEnabled(selectedItems.length > 0);
+
+        Button ok = getOkButton();
+        if (ok != null) {
+			ok.setEnabled(selectedItems.length == 1);
+		}
+    }
+
+    /**
+     * Closes the specified editors
+     */
+    private void closeItems(TableItem items[]) {
+        if (items.length == 0) {
+			return;
+		}
+
+        // collect all instantiated editors that have been selected
+		List selectedEditors = new ArrayList();
+        for (TableItem item : items) {
+            Adapter e = (Adapter) item.getData();
+			if (e.editorRef != null) {
+				IWorkbenchPart part = e.editorRef.getPart(false);
+				if (part != null) {
+					selectedEditors.add(part);
+				}
+			}
+		}
+
+		SaveablesList saveablesList = (SaveablesList) window
+				.getService(ISaveablesLifecycleListener.class);
+		// prompt for save
+		if (saveablesList.preCloseParts(selectedEditors, true, this, window) != null) {
+			// close all editors
+			for (TableItem item : items) {
+				Adapter e = (Adapter) item.getData();
+				e.close();
+			}
+			// update the list
+			updateItems();
+        }
+    }
+
+    /**
+     * Saves the specified editors
+     */
+    private void saveItems(TableItem items[]) {
+        if (items.length == 0) {
+			return;
+		}
+        ProgressMonitorDialog pmd = new ProgressMonitorJobsDialog(getShell());
+        pmd.open();
+        for (TableItem item : items) {
+            Adapter editor = (Adapter) item.getData();
+            editor.save(pmd.getProgressMonitor());
+            updateItem(item, editor);
+        }
+        pmd.close();
+        updateItems();
+    }
+
+    /**
+     * Returns all clean editors from items[];
+     */
+    private TableItem[] selectClean(TableItem items[]) {
+        if (items.length == 0) {
+			return new TableItem[0];
+		}
+        ArrayList cleanItems = new ArrayList(items.length);
+        for (TableItem item : items) {
+            Adapter editor = (Adapter) item.getData();
+            if (!editor.isDirty()) {
+				cleanItems.add(item);
+			}
+        }
+        TableItem result[] = new TableItem[cleanItems.size()];
+        cleanItems.toArray(result);
+        return result;
+    }
+
+    /**
+     * Returns all clean editors from items[];
+     */
+    private TableItem[] invertedSelection(TableItem allItems[],
+            TableItem selectedItems[]) {
+        if (allItems.length == 0) {
+			return allItems;
+		}
+        ArrayList invertedSelection = new ArrayList(allItems.length
+                - selectedItems.length);
+        outerLoop: for (int i = 0; i < allItems.length; i++) {
+            for (int j = 0; j < selectedItems.length; j++) {
+                if (allItems[i] == selectedItems[j]) {
+					continue outerLoop;
+				}
+            }
+            invertedSelection.add(allItems[i]);
+        }
+        TableItem result[] = new TableItem[invertedSelection.size()];
+        invertedSelection.toArray(result);
+        return result;
+    }
+
+    /**
+     * Updates the specified item
+     */
+    private void updateItem(TableItem item, Adapter editor) {
+        item.setData(editor);
+        item.setText(editor.getText());
+        Image image = editor.getImage();
+        if (image != null)
+        	item.setImage(0, image);
+    }
+
+    /**
+     * Adds all editors to elements
+     */
+    private void updateEditors(IWorkbenchPage[] pages) {
+        for (IWorkbenchPage page : pages) {
+			for (IEditorReference editor : page.getEditorReferences()) {
+                elements.add(new Adapter(editor));
+            }
+        }
+    }
+
+    /**
+     * Updates all items in the table
+     */
+    private void updateItems() {
+    	// record what the user has selected
+		TableItem[] selectedItems = editorsTable.getSelection();
+		Adapter[] selectedAdapters = new Adapter[selectedItems.length];
+		for (int i = 0; i < selectedItems.length; i++) {
+			selectedAdapters[i] = (Adapter) selectedItems[i].getData();
+		}
+
+		// remove all the items
+        editorsTable.removeAll();
+        elements = new ArrayList();
+        if (showAllPersp) {
+			for (IWorkbenchWindow workbenchWindow : window.getWorkbench().getWorkbenchWindows()) {
+				updateEditors(workbenchWindow.getPages());
+			}
+        } else {
+            IWorkbenchPage page = window.getActivePage();
+            if (page != null) {
+                updateEditors(new IWorkbenchPage[] { page });
+            }
+        }
+
+        // sort the items
+        sort();
+
+		List selection = new ArrayList(selectedItems.length);
+        for (Iterator iterator = elements.iterator(); iterator.hasNext();) {
+            Adapter e = (Adapter) iterator.next();
+            TableItem item = new TableItem(editorsTable, SWT.NULL);
+            updateItem(item, e);
+
+            // try to match this item's editor to one that was previously selected
+			for (Adapter selectedAdapter : selectedAdapters) {
+				if (selectedAdapter.editorRef == e.editorRef) {
+					selection.add(item);
+				}
+			}
+        }
+
+        // set the selection back to the table
+		editorsTable.setSelection((TableItem[]) selection.toArray(new TableItem[selection.size()]));
+
+        // update the buttons, because the selection may have changed
+        updateButtons();
+    }
+
+    /**
+     * Sorts all the editors according to the table header
+     */
+    private void sort() {
+        //Backward compatible. Table used to have 3 columns.
+        if (sortColumn > (editorsTable.getColumnCount() - 1)) {
+			sortColumn = 0;
+		}
+        Adapter a[] = new Adapter[elements.size()];
+        elements.toArray(a);
+        Arrays.sort(a);
+        elements = Arrays.asList(a);
+    }
+
+    /**
+     * The user has selected a resource and the dialog is closing.
+     */
+    @Override
+	protected void okPressed() {
+        TableItem items[] = editorsTable.getSelection();
+        if (items.length != 1) {
+            super.okPressed();
+            return;
+        }
+
+        Adapter selection = (Adapter) items[0].getData();
+        //It would be better to activate before closing the
+        //dialog but it does not work when the editor is in other
+        //window. Must investigate.
+        super.okPressed();
+        selection.activate();
+    }
+
+	@Override
+	public boolean close() {
+		saveDialogSettings();
+		return super.close();
+	}
+
+    /**
+     * Saves the dialog settings.
+     */
+    private void saveDialogSettings() {
+        IDialogSettings s = getDialogSettings();
+        s.put(ALLPERSP, showAllPersp);
+        s.put(SORT, sortColumn);
+        bounds = getShell().getBounds();
+        String array[] = new String[4];
+        array[0] = String.valueOf(bounds.x);
+        array[1] = String.valueOf(bounds.y);
+        array[2] = String.valueOf(bounds.width);
+        array[3] = String.valueOf(bounds.height);
+        s.put(BOUNDS, array);
+        array = new String[editorsTable.getColumnCount()];
+        for (int i = 0; i < array.length; i++) {
+			array[i] = String.valueOf(editorsTable.getColumn(i).getWidth());
+		}
+        s.put(COLUMNS, array);
+    }
+
+    /**
+     * Return a dialog setting section for this dialog
+     */
+    private IDialogSettings getDialogSettings() {
+        IDialogSettings settings = WorkbenchPlugin.getDefault()
+                .getDialogSettings();
+        IDialogSettings thisSettings = settings
+                .getSection(getClass().getName());
+        if (thisSettings == null) {
+			thisSettings = settings.addNewSection(getClass().getName());
+		}
+        return thisSettings;
+    }
+
+    /**
+     * A helper inner class to adapt EditorHistoryItem and IEditorPart
+     * in the same type.
+     */
+    private class Adapter implements Comparable {
+        IEditorReference editorRef;
+
+        IEditorInput input;
+
+        IEditorDescriptor desc;
+
+        String text[];
+
+        Image image;
+
+        Adapter(IEditorReference ref) {
+            editorRef = ref;
+        }
+
+        boolean isDirty() {
+            if (editorRef == null) {
+				return false;
+			}
+            return editorRef.isDirty();
+        }
+
+        void close() {
+            if (editorRef == null) {
+				return;
+			}
+			WorkbenchPage p = (WorkbenchPage) editorRef.getPage();
+            // already saved when the i
+            p.closeEditor(editorRef, false);
+        }
+
+        void save(IProgressMonitor monitor) {
+            if (editorRef == null) {
+				return;
+			}
+            IEditorPart editor = (IEditorPart) editorRef.getPart(true);
+            if (editor != null) {
+				editor.doSave(monitor);
+			}
+        }
+
+        String[] getText() {
+            if (text != null) {
+				return text;
+			}
+            text = new String[2];
+            if (editorRef != null) {
+                if (editorRef.isDirty()) {
+					text[0] = "*" + editorRef.getTitle(); //$NON-NLS-1$
+				} else {
+					text[0] = editorRef.getTitle();
+				}
+                text[1] = editorRef.getTitleToolTip();
+            } else {
+                text[0] = input.getName();
+                text[1] = input.getToolTipText();
+            }
+			if (text[0] != null) {
+				text[0] = TextProcessor.process(text[0]);
+			}
+			if (text[1] != null) {
+				text[1] = TextProcessor.process(text[1]);
+			}
+            return text;
+        }
+
+        Image getImage() {
+            if (image != null) {
+				return image;
+			}
+            if (editorRef != null) {
+                image = editorRef.getTitleImage();
+            } else {
+                ImageDescriptor imageDesc = null;
+                if (desc != null) {
+                	imageDesc = desc.getImageDescriptor();
+				}
+                if (imageDesc == null) {
+                    IEditorRegistry registry = WorkbenchPlugin.getDefault()
+                            .getEditorRegistry();
+                    imageDesc = registry.getImageDescriptor(input.getName());
+					//TODO: how can this honour content types?  Guessing at the content type perhaps?
+
+                    if (imageDesc == null) {
+                        // @issue what should be the default image?
+                        // image = registry.getDefaultEditor().getImageDescriptor();
+                    }
+                }
+                if (imageDesc != null) {
+                    image = (Image) disabledImageCache.get(imageDesc);
+                    if (image == null) {
+                        Image enabled = imageDesc.createImage();
+                        Image disabled = new Image(editorsTable.getDisplay(),
+                                enabled, SWT.IMAGE_DISABLE);
+                        enabled.dispose();
+                        disabledImageCache.put(imageDesc, disabled);
+                        image = disabled;
+                    }
+                }
+            }
+            return image;
+        }
+
+        private void activate() {
+            if (editorRef != null) {
+                IEditorPart editor = editorRef.getEditor(true);
+                WorkbenchPage p = (WorkbenchPage) editor.getEditorSite()
+                        .getPage();
+                Shell s = p.getWorkbenchWindow().getShell();
+                if (s.getMinimized()) {
+					s.setMinimized(false);
+				}
+                s.moveAbove(null);
+                p.getWorkbenchWindow().setActivePage(p);
+                p.activate(editor);
+            } else {
+                IWorkbenchPage p = window.getActivePage();
+                if (p != null) {
+                    try {
+                        p.openEditor(input, desc.getId(), true);
+                    } catch (PartInitException e) {
+                    }
+                }
+            }
+        }
+
+        @Override
+		public int compareTo(Object another) {
+            Adapter adapter = (Adapter) another;
+            int result = collator.compare(getText()[sortColumn], adapter
+                    .getText()[sortColumn]);
+            if (result == 0) {
+                int column = sortColumn == 0 ? 1 : 0;
+                result = collator.compare(getText()[column],
+                        adapter.getText()[column]);
+            }
+            if (reverse) {
+				return result * -1;
+			}
+            return result;
+        }
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkbenchPreferenceDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkbenchPreferenceDialog.java
new file mode 100644
index 0000000..c79645b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkbenchPreferenceDialog.java
@@ -0,0 +1,223 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.dialogs;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.preference.IPreferenceNode;
+import org.eclipse.jface.preference.IPreferencePage;
+import org.eclipse.jface.preference.PreferenceManager;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.activities.WorkbenchActivityHelper;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.dnd.SwtUtil;
+
+/**
+ * Prefence dialog for the workbench including the ability to load/save
+ * preferences.
+ */
+public class WorkbenchPreferenceDialog extends FilteredPreferenceDialog {
+	/**
+	 * There can only ever be one instance of the workbench's preference dialog.
+	 * This keeps a handle on this instance, so that attempts to create a second
+	 * dialog should just fail (or return the original instance).
+	 *
+	 * @since 3.1
+	 */
+	private static WorkbenchPreferenceDialog instance = null;
+
+	/**
+	 * The bounds of this dialog will be persisted in the dialog settings.
+	 * This is defined at the most concrete level of the hierarchy so that
+	 * different concrete implementations don't necessarily store their bounds
+	 * in the same settings.
+	 *
+	 * @since 3.2
+	 */
+	private static final String DIALOG_SETTINGS_SECTION = "WorkbenchPreferenceDialogSettings"; //$NON-NLS-1$
+
+	private String initialPageId;
+
+
+	/**
+	 * Creates a workbench preference dialog to a particular preference page. It
+	 * is the responsibility of the caller to then call <code>open()</code>.
+	 * The call to <code>open()</code> will not return until the dialog
+	 * closes, so this is the last chance to manipulate the dialog.
+	 *
+	 * @param shell
+	 * 			The Shell to parent the dialog off of if it is not
+	 * 			already created. May be <code>null</code>
+	 * 			in which case the active workbench window will be used
+	 * 			if available.
+	 * @param preferencePageId
+	 *            The identifier of the preference page to open; may be
+	 *            <code>null</code>. If it is <code>null</code>, then the
+	 *            preference page is not selected or modified in any way.
+	 * @return The selected preference page.
+	 * @since 3.1
+	 */
+	public static final WorkbenchPreferenceDialog createDialogOn(Shell shell, final String preferencePageId) {
+		final WorkbenchPreferenceDialog dialog;
+
+		if (instance == null) {
+			/*
+			 * There is no existing preference dialog, so open a new one with
+			 * the given selected page.
+			 */
+
+			Shell parentShell = shell;
+			if (parentShell == null) {
+				// Determine a decent parent shell.
+				final IWorkbench workbench = PlatformUI.getWorkbench();
+				final IWorkbenchWindow workbenchWindow = workbench.getActiveWorkbenchWindow();
+				if (workbenchWindow != null) {
+					parentShell = workbenchWindow.getShell();
+				} else {
+					parentShell = null;
+				}
+			}
+
+			// Create the dialog
+			final PreferenceManager preferenceManager = PlatformUI.getWorkbench()
+					.getPreferenceManager();
+			dialog = new WorkbenchPreferenceDialog(parentShell, preferenceManager);
+			if (preferencePageId != null) {
+				dialog.setSelectedNode(preferencePageId);
+				dialog.setInitialPage(preferencePageId);
+			}
+			dialog.create();
+			PlatformUI.getWorkbench().getHelpSystem().setHelp(
+					dialog.getShell(),
+					IWorkbenchHelpContextIds.PREFERENCE_DIALOG);
+
+		} else {
+			/*
+			 * There is an existing preference dialog, so let's just select the
+			 * given preference page.
+			 */
+			dialog = instance;
+			if (preferencePageId != null) {
+				dialog.setCurrentPageId(preferencePageId);
+				dialog.setInitialPage(preferencePageId);
+			}
+
+		}
+
+		// Get the selected node, and return it.
+		return dialog;
+	}
+
+	/**
+	 * Creates a new preference dialog under the control of the given preference
+	 * manager.
+	 *
+	 * @param parentShell
+	 *            the parent shell
+	 * @param manager
+	 *            the preference manager
+	 */
+	public WorkbenchPreferenceDialog(Shell parentShell, PreferenceManager manager) {
+		super(parentShell, manager);
+		Assert.isTrue((instance == null),
+				"There cannot be two preference dialogs at once in the workbench."); //$NON-NLS-1$
+		instance = this;
+
+	}
+
+
+	@Override
+	public boolean close() {
+		instance = null;
+		return super.close();
+	}
+
+
+	/**
+	 * Differs from super implementation in that if the node is found but should
+	 * be filtered based on a call to
+	 * <code>WorkbenchActivityHelper.filterItem()</code> then
+	 * <code>null</code> is returned.
+	 *
+	 * @see org.eclipse.jface.preference.PreferenceDialog#findNodeMatching(java.lang.String)
+	 */
+	@Override
+	protected IPreferenceNode findNodeMatching(String nodeId) {
+		IPreferenceNode node = super.findNodeMatching(nodeId);
+		if (WorkbenchActivityHelper.filterItem(node)) {
+			return null;
+		}
+		return node;
+	}
+
+	@Override
+	protected void okPressed() {
+		super.okPressed();
+	}
+
+	@Override
+	protected IDialogSettings getDialogBoundsSettings() {
+        IDialogSettings settings = WorkbenchPlugin.getDefault().getDialogSettings();
+        IDialogSettings section = settings.getSection(DIALOG_SETTINGS_SECTION);
+        if (section == null) {
+            section = settings.addNewSection(DIALOG_SETTINGS_SECTION);
+        }
+        return section;
+	}
+
+	/**
+	 * Overridden to persist only the location, not the size, since the current
+	 * page dictates the most appropriate size for the dialog.
+	 *
+	 * @since 3.2
+	 */
+	@Override
+	protected int getDialogBoundsStrategy() {
+		return DIALOG_PERSISTLOCATION;
+	}
+
+	/**
+	 *
+	 * Overrides to set focus to the specific page if it a specific page was
+	 * requested.
+	 *
+	 * @since 3.5
+	 */
+	@Override
+	public int open() {
+		IPreferencePage selectedPage = getCurrentPage();
+		if ((initialPageId != null) && (selectedPage != null)) {
+			Shell shell = getShell();
+			if ((shell != null) && (!shell.isDisposed())) {
+				shell.open(); // make the dialog visible to properly set the focus
+				Control control = selectedPage.getControl();
+				if (!SwtUtil.isFocusAncestor(control))
+					control.setFocus();
+			}
+		}
+		return super.open();
+	}
+
+	/**
+	 * Remembers the initial page ID
+	 * @param pageId ID of the initial page to display
+	 * @since 3.5
+	 */
+	public void setInitialPage(String pageId) {
+		initialPageId = pageId;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkbenchPreferenceManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkbenchPreferenceManager.java
new file mode 100644
index 0000000..74b14a8
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkbenchPreferenceManager.java
@@ -0,0 +1,183 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Jan-Hendrik Diederich, Bredex GmbH - bug 201052
+ *******************************************************************************/
+package org.eclipse.ui.internal.dialogs;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.dynamichelpers.ExtensionTracker;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
+import org.eclipse.jface.preference.IPreferenceNode;
+import org.eclipse.jface.preference.PreferenceManager;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.internal.preferences.WorkbenchPreferenceExpressionNode;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.registry.PreferencePageRegistryReader;
+
+/**
+ * The WorkbenchPreferenceManager is the manager that can handle categories and
+ * preference nodes.
+ */
+public class WorkbenchPreferenceManager extends PreferenceManager implements
+		IExtensionChangeHandler {
+
+	/**
+	 * Create a new instance of the receiver with the specified seperatorChar
+	 *
+	 * @param separatorChar
+	 */
+	public WorkbenchPreferenceManager(char separatorChar) {
+		super(separatorChar, new WorkbenchPreferenceExpressionNode("")); //$NON-NLS-1$
+
+		IExtensionTracker tracker = PlatformUI.getWorkbench().getExtensionTracker();
+		tracker.registerHandler(this, ExtensionTracker.createExtensionPointFilter(getExtensionPointFilter()));
+
+		// add a listener for keyword deltas. If any occur clear all page caches
+		Platform.getExtensionRegistry().addRegistryChangeListener(
+				event -> {
+				    // RAP [DM] namespace
+					if (event.getExtensionDeltas(PlatformUI.PLUGIN_EXTENSION_NAME_SPACE,
+							IWorkbenchRegistryConstants.PL_KEYWORDS).length > 0) {
+						for (Object element : getElements(PreferenceManager.POST_ORDER)) {
+							((WorkbenchPreferenceNode) element).clearKeywords();
+						}
+					}
+				});
+	}
+
+	/**
+	 * Add the pages and the groups to the receiver.
+	 *
+	 * @param pageContributions
+	 */
+	public void addPages(Collection pageContributions) {
+
+		// Add the contributions to the manager
+		Iterator iterator = pageContributions.iterator();
+		while (iterator.hasNext()) {
+			Object next = iterator.next();
+			if (next instanceof WorkbenchPreferenceNode) {
+				WorkbenchPreferenceNode wNode = (WorkbenchPreferenceNode) next;
+				addToRoot(wNode);
+				registerNode(wNode);
+			}
+		}
+
+	}
+
+	/**
+	 * Register a node with the extension tracker.
+	 *
+	 * @param node
+	 *            register the given node and its subnodes with the extension
+	 *            tracker
+	 */
+	private void registerNode(WorkbenchPreferenceNode node) {
+		PlatformUI.getWorkbench().getExtensionTracker().registerObject(
+				node.getConfigurationElement().getDeclaringExtension(), node,
+				IExtensionTracker.REF_WEAK);
+		for (IPreferenceNode subNode : node.getSubNodes()) {
+			registerNode((WorkbenchPreferenceNode) subNode);
+		}
+
+	}
+
+	@Override
+	public void addExtension(IExtensionTracker tracker, IExtension extension) {
+		for (IConfigurationElement configElement : extension.getConfigurationElements()) {
+			WorkbenchPreferenceNode node = PreferencePageRegistryReader
+					.createNode(configElement);
+			if (node == null) {
+				continue;
+			}
+			registerNode(node);
+			String category = node.getCategory();
+			if (category == null) {
+				addToRoot(node);
+			} else {
+				IPreferenceNode parent = null;
+				for (Iterator j = getElements(PreferenceManager.POST_ORDER)
+                        .iterator(); j.hasNext();) {
+				    IPreferenceNode element = (IPreferenceNode) j
+                            .next();
+					if (category.equals(element.getId())) {
+						parent = element;
+						break;
+					}
+				}
+				if (parent == null) {
+					// Could not find the parent - log
+					String message = "Invalid preference category path: " + category + " (bundle: " + node.getPluginId() + ", page: " + node.getId() + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+					WorkbenchPlugin.log(StatusUtil.newStatus(IStatus.WARNING, message, null));
+					addToRoot(node);
+				} else {
+					parent.add(node);
+				}
+			}
+		}
+	}
+
+	private IExtensionPoint getExtensionPointFilter() {
+	    // RAP [bm]: namespace
+		return Platform.getExtensionRegistry().getExtensionPoint(
+				PlatformUI.PLUGIN_EXTENSION_NAME_SPACE, IWorkbenchRegistryConstants.PL_PREFERENCES);
+	}
+
+	@Override
+	public void removeExtension(IExtension extension, Object[] objects) {
+		for (Object object : objects) {
+			if (object instanceof IPreferenceNode) {
+				IPreferenceNode wNode = (IPreferenceNode) object;
+				wNode.disposeResources();
+				deepRemove(getRoot(), wNode);
+			}
+		}
+	}
+
+	/**
+	 * Removes the node from the manager, searching through all subnodes.
+	 *
+	 * @param parent
+	 *            the node to search
+	 * @param nodeToRemove
+	 *            the node to remove
+	 * @return whether the node was removed
+	 */
+	private boolean deepRemove(IPreferenceNode parent,
+			IPreferenceNode nodeToRemove) {
+		if (parent == nodeToRemove) {
+			if (parent == getRoot()) {
+				removeAll(); // we're removing the root
+				return true;
+			}
+		}
+
+		if (parent.remove(nodeToRemove)) {
+			return true;
+		}
+
+		for (IPreferenceNode subNode : parent.getSubNodes()) {
+			if (deepRemove(subNode, nodeToRemove)) {
+				return true;
+			}
+		}
+		return false;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkbenchPreferenceNode.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkbenchPreferenceNode.java
new file mode 100644
index 0000000..8bbe4e7
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkbenchPreferenceNode.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.dialogs;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.internal.preferences.WorkbenchPreferenceExtensionNode;
+import org.eclipse.ui.internal.registry.CategorizedPageRegistryReader;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+/**
+ * A proxy for a preference page to avoid creation of preference page just to
+ * show a node in the preference dialog tree.
+ */
+public class WorkbenchPreferenceNode extends WorkbenchPreferenceExtensionNode {
+
+	/**
+	 * Create a new instance of the receiver.
+	 * @param nodeId
+	 * @param element
+	 */
+	public WorkbenchPreferenceNode(String nodeId, IConfigurationElement element) {
+		super(nodeId, element);
+	}
+
+	/**
+	 * Creates the preference page this node stands for.
+	 */
+	@Override
+	public void createPage() {
+		IWorkbenchPreferencePage page;
+		try {
+			page = (IWorkbenchPreferencePage) WorkbenchPlugin.createExtension(
+					getConfigurationElement(), IWorkbenchRegistryConstants.ATT_CLASS);
+		} catch (CoreException e) {
+			// Just inform the user about the error. The details are
+			// written to the log by now.
+			IStatus errStatus = StatusUtil.newStatus(e.getStatus(), WorkbenchMessages.get().PreferenceNode_errorMessage);
+			StatusManager.getManager().handle(errStatus, StatusManager.SHOW | StatusManager.LOG);
+			page = new ErrorPreferencePage();
+		}
+
+		page.init(PlatformUI.getWorkbench());
+		if (getLabelImage() != null) {
+			page.setImageDescriptor(getImageDescriptor());
+		}
+		page.setTitle(getLabelText());
+		setPage(page);
+	}
+
+	/**
+	 * Return the category name for the node.
+	 * @return java.lang.String
+	 */
+	public String getCategory() {
+		return getConfigurationElement().getAttribute(
+				CategorizedPageRegistryReader.ATT_CATEGORY);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkbenchPreferencePage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkbenchPreferencePage.java
new file mode 100644
index 0000000..1264c78
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkbenchPreferencePage.java
@@ -0,0 +1,406 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Tristan Hume - <trishume@gmail.com> -
+ *     		Fix for Bug 2369 [Workbench] Would like to be able to save workspace without exiting
+ *     		Implemented workbench auto-save to correctly restore state in case of crash.
+ *******************************************************************************/
+package org.eclipse.ui.internal.dialogs;
+
+
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.jface.util.OpenStrategy;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.IPreferenceConstants;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.util.PrefUtil;
+
+/**
+ * Generic workbench main preference page.
+ */
+public class WorkbenchPreferencePage extends PreferencePage implements
+        IWorkbenchPreferencePage {
+    private Button stickyCycleButton;
+
+    private Button doubleClickButton;
+
+    private Button singleClickButton;
+
+    private Button selectOnHoverButton;
+
+    private Button openAfterDelayButton;
+
+    private Button showUserDialogButton;
+
+    private boolean openOnSingleClick;
+
+    private boolean selectOnHover;
+
+    private boolean openAfterDelay;
+
+    // RAP [bm]: 
+//  private Button showHeapStatusButton;
+
+	protected static int MAX_SAVE_INTERVAL = 9999;
+
+    @Override
+	protected Control createContents(Composite parent) {
+
+        // @issue if the product subclasses this page, then it should provide
+        // the help content
+    	PlatformUI.getWorkbench().getHelpSystem().setHelp(parent,
+				IWorkbenchHelpContextIds.WORKBENCH_PREFERENCE_PAGE);
+
+        Composite composite = createComposite(parent);
+
+        createButtons(composite);
+
+        createSpace(composite);
+        createOpenModeGroup(composite);
+
+        applyDialogFont(composite);
+
+        return composite;
+    }
+
+    /**
+     * Create the buttons at the top of the preference page.
+     * @param composite
+     */
+	protected void createButtons(Composite composite) {
+		createShowUserDialogPref(composite);
+        createStickyCyclePref(composite);
+        // RAP [bm]: 
+//      createHeapStatusPref(composite);
+	}
+
+    /**
+     * Create the widget for the user dialog preference.
+     *
+     * @param composite
+     */
+    protected void createShowUserDialogPref(Composite composite) {
+        showUserDialogButton = new Button(composite, SWT.CHECK);
+        showUserDialogButton.setText(WorkbenchMessages.get().WorkbenchPreference_RunInBackgroundButton);
+        showUserDialogButton.setToolTipText(WorkbenchMessages.get().WorkbenchPreference_RunInBackgroundToolTip);
+        showUserDialogButton.setSelection(WorkbenchPlugin.getDefault()
+                .getPreferenceStore().getBoolean(
+                        IPreferenceConstants.RUN_IN_BACKGROUND));
+    }
+    // RAP [bm]: 
+//    /**
+//     * Create the widget for the heap status preference.
+//     *
+//     * @param composite
+//     */
+//    protected void createHeapStatusPref(Composite composite) {
+//        showHeapStatusButton = new Button(composite, SWT.CHECK);
+//        showHeapStatusButton.setText(WorkbenchMessages.get().WorkbenchPreference_HeapStatusButton);
+//        showHeapStatusButton.setToolTipText(WorkbenchMessages.get().WorkbenchPreference_HeapStatusButtonToolTip);
+//
+//        showHeapStatusButton.setSelection(PrefUtil.getAPIPreferenceStore().getBoolean(
+//                        IWorkbenchPreferenceConstants.SHOW_MEMORY_MONITOR));
+//    }
+
+    /**
+     * Creates the composite which will contain all the preference controls for
+     * this page.
+     *
+     * @param parent
+     *            the parent composite
+     * @return the composite for this page
+     */
+    protected Composite createComposite(Composite parent) {
+        Composite composite = new Composite(parent, SWT.NONE);
+        GridLayout layout = new GridLayout();
+        layout.marginWidth = 0;
+        layout.marginHeight = 0;
+        composite.setLayout(layout);
+        composite.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_FILL
+                | GridData.HORIZONTAL_ALIGN_FILL));
+        return composite;
+    }
+
+    protected void createStickyCyclePref(Composite composite) {
+        stickyCycleButton = new Button(composite, SWT.CHECK);
+        stickyCycleButton.setText(WorkbenchMessages.get().WorkbenchPreference_stickyCycleButton);
+        stickyCycleButton.setSelection(getPreferenceStore().getBoolean(
+                IPreferenceConstants.STICKY_CYCLE));
+    }	
+
+    protected void createOpenModeGroup(Composite composite) {
+
+        Font font = composite.getFont();
+
+        Group buttonComposite = new Group(composite, SWT.LEFT);
+        GridLayout layout = new GridLayout();
+        buttonComposite.setLayout(layout);
+        GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL
+                | GridData.GRAB_HORIZONTAL);
+        buttonComposite.setLayoutData(data);
+        buttonComposite.setText(WorkbenchMessages.get().WorkbenchPreference_openMode);
+
+        String label = WorkbenchMessages.get().WorkbenchPreference_doubleClick;
+        doubleClickButton = createRadioButton(buttonComposite, label);
+        doubleClickButton.addSelectionListener(new SelectionAdapter() {
+
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                selectClickMode(singleClickButton.getSelection());
+            }
+        });
+        doubleClickButton.setSelection(!openOnSingleClick);
+
+        label = WorkbenchMessages.get().WorkbenchPreference_singleClick;
+        singleClickButton = createRadioButton(buttonComposite, label);
+        singleClickButton.addSelectionListener(new SelectionAdapter() {
+
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                
+                selectClickMode(singleClickButton.getSelection());
+            }
+        });
+        singleClickButton.setSelection(openOnSingleClick);
+
+        label = WorkbenchMessages.get().WorkbenchPreference_singleClick_SelectOnHover;
+        selectOnHoverButton = new Button(buttonComposite, SWT.CHECK | SWT.LEFT);
+        selectOnHoverButton.setText(label);
+        selectOnHoverButton.setEnabled(openOnSingleClick);
+        selectOnHoverButton.setSelection(selectOnHover);
+        selectOnHoverButton.addSelectionListener(new SelectionAdapter() {
+
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                
+                selectOnHover = selectOnHoverButton.getSelection();
+            }
+        });
+        data = new GridData();
+		data.horizontalIndent = 20;
+        selectOnHoverButton.setLayoutData(data);
+
+        label = WorkbenchMessages.get().WorkbenchPreference_singleClick_OpenAfterDelay;
+        openAfterDelayButton = new Button(buttonComposite, SWT.CHECK | SWT.LEFT);
+        openAfterDelayButton.setText(label);
+        openAfterDelayButton.setEnabled(openOnSingleClick);
+        openAfterDelayButton.setSelection(openAfterDelay);
+        openAfterDelayButton.addSelectionListener(new SelectionAdapter() {
+
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                openAfterDelay = openAfterDelayButton.getSelection();
+            }
+        });
+        data = new GridData();
+		data.horizontalIndent = 20;
+        openAfterDelayButton.setLayoutData(data);
+
+        createNoteComposite(font, buttonComposite, WorkbenchMessages.get().Preference_note,
+                WorkbenchMessages.get().WorkbenchPreference_noEffectOnAllViews);
+    }
+
+    private void selectClickMode(boolean singleClick) {
+        openOnSingleClick = singleClick;
+        selectOnHoverButton.setEnabled(openOnSingleClick);
+        openAfterDelayButton.setEnabled(openOnSingleClick);
+    }
+
+    /**
+     * Utility method that creates a radio button instance and sets the default
+     * layout data.
+     *
+     * @param parent
+     *            the parent for the new button
+     * @param label
+     *            the label for the new button
+     * @return the newly-created button
+     */
+    protected static Button createRadioButton(Composite parent, String label) {
+        Button button = new Button(parent, SWT.RADIO | SWT.LEFT);
+        button.setText(label);
+        return button;
+    }
+
+    /**
+     * Utility method that creates a combo box
+     *
+     * @param parent
+     *            the parent for the new label
+     * @return the new widget
+     */
+    protected static Combo createCombo(Composite parent) {
+        Combo combo = new Combo(parent, SWT.READ_ONLY);
+        GridData data = new GridData(GridData.FILL_HORIZONTAL);
+        data.widthHint = IDialogConstants.ENTRY_FIELD_WIDTH;
+        combo.setLayoutData(data);
+        return combo;
+    }
+
+    /**
+     * Utility method that creates a label instance and sets the default layout
+     * data.
+     *
+     * @param parent
+     *            the parent for the new label
+     * @param text
+     *            the text for the new label
+     * @return the new label
+     */
+    protected static Label createLabel(Composite parent, String text) {
+        Label label = new Label(parent, SWT.LEFT);
+        label.setText(text);
+        GridData data = new GridData();
+        data.horizontalSpan = 1;
+        data.horizontalAlignment = GridData.FILL;
+        label.setLayoutData(data);
+        return label;
+    }
+
+    /**
+     * Creates a tab of one horizontal spans.
+     *
+     * @param parent
+     *            the parent in which the tab should be created
+     */
+    protected static void createSpace(Composite parent) {
+        Label vfiller = new Label(parent, SWT.LEFT);
+        GridData gridData = new GridData();
+        gridData = new GridData();
+        gridData.horizontalAlignment = GridData.BEGINNING;
+        gridData.grabExcessHorizontalSpace = false;
+        gridData.verticalAlignment = GridData.CENTER;
+        gridData.grabExcessVerticalSpace = false;
+        vfiller.setLayoutData(gridData);
+    }
+
+    /**
+     * Returns preference store that belongs to the our plugin.
+     *
+     * @return the preference store for this plugin
+     */
+    @Override
+	protected IPreferenceStore doGetPreferenceStore() {
+        return WorkbenchPlugin.getDefault().getPreferenceStore();
+    }
+
+    /**
+     * @see IWorkbenchPreferencePage
+     */
+    @Override
+	public void init(IWorkbench aWorkbench) {
+        IPreferenceStore store = getPreferenceStore();
+        openOnSingleClick = store
+                .getBoolean(IPreferenceConstants.OPEN_ON_SINGLE_CLICK);
+        selectOnHover = store.getBoolean(IPreferenceConstants.SELECT_ON_HOVER);
+        openAfterDelay = store
+                .getBoolean(IPreferenceConstants.OPEN_AFTER_DELAY);
+    }
+
+    /**
+     * The default button has been pressed.
+     */
+    @Override
+	protected void performDefaults() {
+        IPreferenceStore store = getPreferenceStore();
+        stickyCycleButton.setSelection(store
+                .getBoolean(IPreferenceConstants.STICKY_CYCLE));
+        openOnSingleClick = store
+                .getDefaultBoolean(IPreferenceConstants.OPEN_ON_SINGLE_CLICK);
+        selectOnHover = store
+                .getDefaultBoolean(IPreferenceConstants.SELECT_ON_HOVER);
+        openAfterDelay = store
+                .getDefaultBoolean(IPreferenceConstants.OPEN_AFTER_DELAY);
+        singleClickButton.setSelection(openOnSingleClick);
+        doubleClickButton.setSelection(!openOnSingleClick);
+        selectOnHoverButton.setSelection(selectOnHover);
+        openAfterDelayButton.setSelection(openAfterDelay);
+        selectOnHoverButton.setEnabled(openOnSingleClick);
+        openAfterDelayButton.setEnabled(openOnSingleClick);
+        stickyCycleButton.setSelection(store
+                .getDefaultBoolean(IPreferenceConstants.STICKY_CYCLE));
+        showUserDialogButton.setSelection(store.getDefaultBoolean(
+                IPreferenceConstants.RUN_IN_BACKGROUND));
+        // RAP [bm]: 
+//        showHeapStatusButton.setSelection(PrefUtil.getAPIPreferenceStore().getDefaultBoolean(
+//                IWorkbenchPreferenceConstants.SHOW_MEMORY_MONITOR));
+
+        super.performDefaults();
+    }
+
+    /**
+     * The user has pressed Ok. Store/apply this page's values appropriately.
+     */
+    @Override
+	public boolean performOk() {
+        IPreferenceStore store = getPreferenceStore();
+
+        // store the keep cycle part dialogs sticky preference
+        store.setValue(IPreferenceConstants.STICKY_CYCLE, stickyCycleButton
+                .getSelection());
+        store.setValue(IPreferenceConstants.OPEN_ON_SINGLE_CLICK,
+                openOnSingleClick);
+        store.setValue(IPreferenceConstants.SELECT_ON_HOVER, selectOnHover);
+        store.setValue(IPreferenceConstants.OPEN_AFTER_DELAY, openAfterDelay);
+        store.setValue(IPreferenceConstants.RUN_IN_BACKGROUND,
+                showUserDialogButton.getSelection());
+        // RAP [bm]: 
+//		store.setValue(IPreferenceConstants.WORKBENCH_SAVE_INTERVAL, saveInterval.getIntValue());
+//        PrefUtil.getAPIPreferenceStore().setValue(IWorkbenchPreferenceConstants.SHOW_MEMORY_MONITOR, showHeapStatusButton.getSelection());
+//        updateHeapStatus(showHeapStatusButton.getSelection());
+
+        int singleClickMethod = openOnSingleClick ? OpenStrategy.SINGLE_CLICK
+                : OpenStrategy.DOUBLE_CLICK;
+        if (openOnSingleClick) {
+            if (selectOnHover) {
+                singleClickMethod |= OpenStrategy.SELECT_ON_HOVER;
+            }
+            if (openAfterDelay) {
+                singleClickMethod |= OpenStrategy.ARROW_KEYS_OPEN;
+            }
+        }
+        OpenStrategy.setOpenMethod(singleClickMethod);
+
+        PrefUtil.savePrefs();
+        return true;
+    }
+
+	/**
+	 * Show or hide the heap status based on selection.
+	 * @param selection
+	 */
+    // RAP [bm]: disabled heap status
+//	private void updateHeapStatus(boolean selection) {
+//		IWorkbenchWindow[] windows = PlatformUI.getWorkbench().getWorkbenchWindows();
+//		for (IWorkbenchWindow window : windows) {
+//			if(window instanceof WorkbenchWindow){
+//				((WorkbenchWindow) window).showHeapStatus(selection);
+//			}
+//		}
+//
+//	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkbenchWizardElement.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkbenchWizardElement.java
new file mode 100644
index 0000000..ddd1107
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkbenchWizardElement.java
@@ -0,0 +1,345 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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
+ *     Fair Isaac Corporation <Hemant.Singh@Gmail.com> - Bug 326695
+ *******************************************************************************/
+package org.eclipse.ui.internal.dialogs;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.ui.IPluginContribution;
+import org.eclipse.ui.IWorkbenchWizard;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.SelectionEnabler;
+import org.eclipse.ui.internal.ISelectionConversionService;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.registry.KeywordRegistry;
+import org.eclipse.ui.internal.registry.RegistryReader;
+import org.eclipse.ui.model.IWorkbenchAdapter;
+import org.eclipse.ui.model.IWorkbenchAdapter2;
+import org.eclipse.ui.model.IWorkbenchAdapter3;
+import org.eclipse.ui.model.WorkbenchAdapter;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.eclipse.ui.wizards.IWizardCategory;
+import org.eclipse.ui.wizards.IWizardDescriptor;
+
+/**
+ * Instances represent registered wizards.
+ */
+public class WorkbenchWizardElement extends WorkbenchAdapter implements
+        IAdaptable, IPluginContribution, IWizardDescriptor {
+    private String id;
+
+    private ImageDescriptor imageDescriptor;
+
+    private SelectionEnabler selectionEnabler;
+
+    private IConfigurationElement configurationElement;
+
+    private ImageDescriptor descriptionImage;
+
+    private WizardCollectionElement parentCategory;
+
+	/**
+	 * TODO: DO we need to  make this API?
+	 */
+	public static final String TAG_PROJECT = "project"; //$NON-NLS-1$
+
+	private static final String [] EMPTY_TAGS = new String[0];
+
+	private static final String [] PROJECT_TAGS = new String[] {TAG_PROJECT};
+
+	private String[] keywordLabels;
+
+
+    /**
+     * Create a new instance of this class
+     *
+     * @param configurationElement
+     * @since 3.1
+     */
+    public WorkbenchWizardElement(IConfigurationElement configurationElement) {
+        this.configurationElement = configurationElement;
+        id = configurationElement.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+    }
+
+    /**
+     * Answer a boolean indicating whether the receiver is able to handle the
+     * passed selection
+     *
+     * @return boolean
+     * @param selection
+     *            IStructuredSelection
+     */
+    public boolean canHandleSelection(IStructuredSelection selection) {
+        return getSelectionEnabler().isEnabledForSelection(selection);
+    }
+
+    /**
+     * Answer the selection for the reciever based on whether the it can handle
+     * the selection. If it can return the selection. If it can handle the
+     * adapted to IResource value of the selection. If it satisfies neither of
+     * these conditions return an empty IStructuredSelection.
+     *
+     * @return IStructuredSelection
+     * @param selection
+     *            IStructuredSelection
+     */
+    @Override
+	public IStructuredSelection adaptedSelection(IStructuredSelection selection) {
+        if (canHandleSelection(selection)) {
+			return selection;
+		}
+
+        IStructuredSelection adaptedSelection = convertToResources(selection);
+        if (canHandleSelection(adaptedSelection)) {
+			return adaptedSelection;
+		}
+
+        //Couldn't find one that works so just return
+        return StructuredSelection.EMPTY;
+    }
+
+    /**
+     * Create an the instance of the object described by the configuration
+     * element. That is, create the instance of the class the isv supplied in
+     * the extension point.
+     * @return the new object
+     * @throws CoreException
+     */
+    public Object createExecutableExtension() throws CoreException {
+        return WorkbenchPlugin.createExtension(configurationElement,
+                IWorkbenchRegistryConstants.ATT_CLASS);
+    }
+
+    /**
+     * Returns an object which is an instance of the given class associated
+     * with this object. Returns <code>null</code> if no such object can be
+     * found.
+     */
+	@Override
+	public <T> T getAdapter(Class<T> adapter) {
+        if (adapter == IWorkbenchAdapter.class
+                || adapter == IWorkbenchAdapter2.class
+                || adapter == IWorkbenchAdapter3.class) {
+			return adapter.cast(this);
+        }
+        else if (adapter == IPluginContribution.class) {
+			return adapter.cast(this);
+        }
+        else if (adapter == IConfigurationElement.class) {
+			return adapter.cast(configurationElement);
+        }
+        return Platform.getAdapterManager().getAdapter(this, adapter);
+    }
+
+    /**
+     * @return IConfigurationElement
+     */
+    public IConfigurationElement getConfigurationElement() {
+        return configurationElement;
+    }
+
+    /**
+     * Answer the description parameter of this element
+     *
+     * @return java.lang.String
+     */
+    @Override
+	public String getDescription() {
+        return RegistryReader.getDescription(configurationElement);
+    }
+
+    /**
+     * Answer the icon of this element.
+     */
+    @Override
+	public ImageDescriptor getImageDescriptor() {
+    	if (imageDescriptor == null) {
+    		String iconName = configurationElement
+                    .getAttribute(IWorkbenchRegistryConstants.ATT_ICON);
+	        if (iconName == null) {
+				return null;
+			}
+            imageDescriptor = AbstractUIPlugin.imageDescriptorFromPlugin(
+                    configurationElement.getNamespaceIdentifier(), iconName);
+    	}
+        return imageDescriptor;
+    }
+
+    /**
+     * Returns the name of this wizard element.
+     */
+    @Override
+	public ImageDescriptor getImageDescriptor(Object element) {
+        return getImageDescriptor();
+    }
+
+    /**
+     * Returns the name of this wizard element.
+     */
+    @Override
+	public String getLabel(Object element) {
+        return configurationElement.getAttribute(IWorkbenchRegistryConstants.ATT_NAME);
+    }
+
+    /**
+     * Answer self's action enabler, creating it first iff necessary
+     */
+    protected SelectionEnabler getSelectionEnabler() {
+        if (selectionEnabler == null) {
+			selectionEnabler = new SelectionEnabler(configurationElement);
+		}
+
+        return selectionEnabler;
+    }
+
+    /**
+     * Attempt to convert the elements in the passed selection into resources
+     * by asking each for its IResource property (iff it isn't already a
+     * resource). If all elements in the initial selection can be converted to
+     * resources then answer a new selection containing these resources;
+     * otherwise answer an empty selection.
+     *
+     * @param originalSelection the original selection
+     * @return the converted selection or an empty selection
+     */
+	private IStructuredSelection convertToResources(
+			IStructuredSelection originalSelection) {
+		Object selectionService = PlatformUI.getWorkbench().getService(
+				ISelectionConversionService.class);
+		if (selectionService == null || originalSelection == null) {
+			return StructuredSelection.EMPTY;
+		}
+		return ((ISelectionConversionService) selectionService)
+				.convertToResources(originalSelection);
+    }
+
+    @Override
+	public String getLocalId() {
+        return getId();
+    }
+
+    @Override
+	public String getPluginId() {
+        return (configurationElement != null) ? configurationElement
+                .getNamespaceIdentifier() : null;
+    }
+
+    @Override
+	public ImageDescriptor getDescriptionImage() {
+    	if (descriptionImage == null) {
+    		String descImage = configurationElement.getAttribute(IWorkbenchRegistryConstants.ATT_DESCRIPTION_IMAGE);
+    		if (descImage == null) {
+				return null;
+			}
+            descriptionImage = AbstractUIPlugin.imageDescriptorFromPlugin(
+                    configurationElement.getNamespaceIdentifier(), descImage);
+    	}
+        return descriptionImage;
+    }
+
+    @Override
+	public String getHelpHref() {
+        return configurationElement.getAttribute(IWorkbenchRegistryConstants.ATT_HELP_HREF);
+    }
+
+	@Override
+	public IWorkbenchWizard createWizard() throws CoreException {
+		return (IWorkbenchWizard) createExecutableExtension();
+	}
+
+	@Override
+	public String getId() {
+		return id;
+	}
+
+	@Override
+	public String getLabel() {
+		return getLabel(this);
+	}
+
+	@Override
+	public IWizardCategory getCategory() {
+		return (IWizardCategory) getParent(this);
+	}
+
+	/**
+	 * Return the collection.
+	 *
+	 * @return the collection
+	 * @since 3.1
+	 */
+	public WizardCollectionElement getCollectionElement() {
+		return (WizardCollectionElement) getParent(this);
+	}
+
+	@Override
+	public String [] getTags() {
+
+        String flag = configurationElement.getAttribute(IWorkbenchRegistryConstants.ATT_PROJECT);
+        if (Boolean.valueOf(flag).booleanValue()) {
+        	return PROJECT_TAGS;
+        }
+
+        return EMPTY_TAGS;
+	}
+
+	@Override
+	public Object getParent(Object object) {
+		return parentCategory;
+	}
+
+	/**
+	 * Set the parent category.
+	 *
+	 * @param parent the parent category
+	 * @since 3.1
+	 */
+	public void setParent(WizardCollectionElement parent) {
+		parentCategory = parent;
+	}
+
+	@Override
+	public boolean canFinishEarly() {
+		return Boolean.valueOf(configurationElement.getAttribute(IWorkbenchRegistryConstants.ATT_CAN_FINISH_EARLY)).booleanValue();
+	}
+
+	@Override
+	public boolean hasPages() {
+		String hasPagesString = configurationElement.getAttribute(IWorkbenchRegistryConstants.ATT_HAS_PAGES);
+		// default value is true
+		if (hasPagesString == null) {
+			return true;
+		}
+		return Boolean.valueOf(hasPagesString).booleanValue();
+	}
+
+	public String[] getKeywordLabels() {
+		if (keywordLabels == null) {
+
+			IConfigurationElement[] children = configurationElement
+					.getChildren(IWorkbenchRegistryConstants.TAG_KEYWORD_REFERENCE);
+			keywordLabels = new String[children.length];
+			KeywordRegistry registry = KeywordRegistry.getInstance();
+			for (int i = 0; i < children.length; i++) {
+				String id = children[i]
+						.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+				keywordLabels[i] = registry.getKeywordLabel(id);
+			}
+		}
+		return keywordLabels;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkbenchWizardListSelectionPage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkbenchWizardListSelectionPage.java
new file mode 100644
index 0000000..6e7f64d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkbenchWizardListSelectionPage.java
@@ -0,0 +1,222 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.dialogs;
+
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.wizard.IWizardNode;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.model.AdaptableList;
+import org.eclipse.ui.model.WorkbenchLabelProvider;
+import org.eclipse.ui.model.WorkbenchViewerComparator;
+
+/**
+ * Abstract implementation of a wizard selection page which simply displays a
+ * list of specified wizard elements and allows the user to select one to be
+ * launched. Subclasses just need to provide a method which creates an
+ * appropriate wizard node based upon a user selection.
+ */
+public abstract class WorkbenchWizardListSelectionPage extends
+        WorkbenchWizardSelectionPage implements ISelectionChangedListener,
+        IDoubleClickListener {
+
+    // id constants
+    private static final String DIALOG_SETTING_SECTION_NAME = "WizardListSelectionPage."; //$NON-NLS-1$
+
+    private final static int SIZING_LISTS_HEIGHT = 200;
+
+    private static final String STORE_SELECTED_WIZARD_ID = DIALOG_SETTING_SECTION_NAME
+            + "STORE_SELECTED_WIZARD_ID"; //$NON-NLS-1$
+
+    private TableViewer viewer;
+
+    private String message;
+
+    /**
+     * Creates a <code>WorkbenchWizardListSelectionPage</code>.
+     *
+     * @param aWorkbench the current workbench
+     * @param currentSelection the workbench's current resource selection
+     * @param wizardElements the collection of <code>WorkbenchWizardElements</code>
+     *            to display for selection
+     * @param message the message to display above the selection list
+     * @param triggerPointId the trigger point id
+     */
+    protected WorkbenchWizardListSelectionPage(IWorkbench aWorkbench,
+            IStructuredSelection currentSelection,
+            AdaptableList wizardElements, String message, String triggerPointId) {
+        super(
+                "singleWizardSelectionPage", aWorkbench, currentSelection, wizardElements, triggerPointId); //$NON-NLS-1$
+        setDescription(WorkbenchMessages.get().WizardList_description);
+        this.message = message;
+    }
+
+    @Override
+	public void createControl(Composite parent) {
+
+        Font font = parent.getFont();
+
+        // create composite for page.
+        Composite outerContainer = new Composite(parent, SWT.NONE);
+        outerContainer.setLayout(new GridLayout());
+        outerContainer.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_FILL
+                | GridData.HORIZONTAL_ALIGN_FILL));
+        outerContainer.setFont(font);
+
+        Label messageLabel = new Label(outerContainer, SWT.NONE);
+        messageLabel.setText(message);
+        messageLabel.setFont(font);
+
+        createViewer(outerContainer);
+        layoutTopControl(viewer.getControl());
+
+        restoreWidgetValues();
+
+        setControl(outerContainer);
+    }
+
+    /**
+     * Create a new viewer in the parent.
+     *
+     * @param parent the parent <code>Composite</code>.
+     */
+    private void createViewer(Composite parent) {
+        //Create a table for the list
+        Table table = new Table(parent, SWT.BORDER);
+        table.setFont(parent.getFont());
+
+        // the list viewer
+        viewer = new TableViewer(table);
+        viewer.setContentProvider(new WizardContentProvider());
+        viewer.setLabelProvider(new WorkbenchLabelProvider());
+        viewer.setComparator(new WorkbenchViewerComparator());
+        viewer.addSelectionChangedListener(this);
+        viewer.addDoubleClickListener(this);
+        viewer.setInput(wizardElements);
+    }
+
+    /**
+     * Returns an <code>IWizardNode</code> representing the specified
+     * workbench wizard which has been selected by the user. <b>Subclasses
+     * </b> must override this abstract implementation.
+     *
+     * @param element the wizard element that an <code>IWizardNode</code> is
+     *            needed for
+     * @return org.eclipse.jface.wizards.IWizardNode
+     */
+    protected abstract IWizardNode createWizardNode(
+            WorkbenchWizardElement element);
+
+    /**
+     * An item in a viewer has been double-clicked.
+     */
+    @Override
+	public void doubleClick(DoubleClickEvent event) {
+        selectionChanged(new SelectionChangedEvent(event.getViewer(), event
+                .getViewer().getSelection()));
+        getContainer().showPage(getNextPage());
+    }
+
+    /**
+     * Layout the top control.
+     *
+     * @param control the control.
+     * @since 3.0
+     */
+    private void layoutTopControl(Control control) {
+        GridData data = new GridData(GridData.FILL_BOTH);
+
+        int availableRows = DialogUtil.availableRows(control.getParent());
+
+        //Only give a height hint if the dialog is going to be too small
+        if (availableRows > 50) {
+            data.heightHint = SIZING_LISTS_HEIGHT;
+        } else {
+            data.heightHint = availableRows * 3;
+        }
+
+        control.setLayoutData(data);
+
+    }
+
+    /**
+     * Uses the dialog store to restore widget values to the values that they
+     * held last time this wizard was used to completion.
+     */
+    private void restoreWidgetValues() {
+
+        IDialogSettings settings = getDialogSettings();
+        if (settings == null) {
+			return;
+		}
+
+        String wizardId = settings.get(STORE_SELECTED_WIZARD_ID);
+        WorkbenchWizardElement wizard = findWizard(wizardId);
+        if (wizard == null) {
+			return;
+		}
+
+        StructuredSelection selection = new StructuredSelection(wizard);
+        viewer.setSelection(selection);
+    }
+
+    /**
+     * Since Finish was pressed, write widget values to the dialog store so
+     * that they will persist into the next invocation of this wizard page
+     */
+    public void saveWidgetValues() {
+		IStructuredSelection sel = viewer.getStructuredSelection();
+        if (sel.size() > 0) {
+            WorkbenchWizardElement selectedWizard = (WorkbenchWizardElement) sel
+                    .getFirstElement();
+            getDialogSettings().put(STORE_SELECTED_WIZARD_ID,
+                    selectedWizard.getId());
+        }
+    }
+
+    /**
+     * Notes the newly-selected wizard element and updates the page
+     * accordingly.
+     *
+     * @param event the selection changed event
+     */
+    @Override
+	public void selectionChanged(SelectionChangedEvent event) {
+        setErrorMessage(null);
+        IStructuredSelection selection = (IStructuredSelection) event
+                .getSelection();
+        WorkbenchWizardElement currentWizardSelection = (WorkbenchWizardElement) selection
+                .getFirstElement();
+        if (currentWizardSelection == null) {
+            setMessage(null);
+            setSelectedNode(null);
+            return;
+        }
+
+        setSelectedNode(createWizardNode(currentWizardSelection));
+        setMessage(currentWizardSelection.getDescription());
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkbenchWizardNode.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkbenchWizardNode.java
new file mode 100644
index 0000000..f242ce9
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkbenchWizardNode.java
@@ -0,0 +1,197 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.dialogs;
+
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.util.SafeRunnable;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.IWizard;
+import org.eclipse.jface.wizard.IWizardNode;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IPluginContribution;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchWizard;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.statushandlers.StatusAdapter;
+import org.eclipse.ui.statushandlers.StatusManager;
+import org.eclipse.ui.wizards.IWizardDescriptor;
+
+/**
+ * A wizard node represents a "potential" wizard. Wizard nodes
+ * are used by wizard selection pages to allow the user to pick
+ * from several available nested wizards.
+ * <p>
+ * <b>Subclasses</b> simply need to override method <code>createWizard()</code>,
+ * which is responsible for creating an instance of the wizard it represents
+ * AND ensuring that this wizard is the "right" type of wizard (e.g.-
+ * New, Import, etc.).</p>
+ */
+public abstract class WorkbenchWizardNode implements IWizardNode,
+        IPluginContribution {
+    protected WorkbenchWizardSelectionPage parentWizardPage;
+
+    protected IWizard wizard;
+
+    protected IWizardDescriptor wizardElement;
+
+    /**
+     * Creates a <code>WorkbenchWizardNode</code> that holds onto a wizard
+     * element.  The wizard element provides information on how to create
+     * the wizard supplied by the ISV's extension.
+     *
+     * @param aWizardPage the wizard page
+     * @param element the wizard descriptor
+     */
+    public WorkbenchWizardNode(WorkbenchWizardSelectionPage aWizardPage,
+    		IWizardDescriptor element) {
+        super();
+        this.parentWizardPage = aWizardPage;
+        this.wizardElement = element;
+    }
+
+    /**
+     * Returns the wizard represented by this wizard node.  <b>Subclasses</b>
+     * must override this method.
+     *
+     * @return the wizard object
+     * @throws CoreException
+     */
+    public abstract IWorkbenchWizard createWizard() throws CoreException;
+
+    @Override
+	public void dispose() {
+        // Do nothing since the wizard wasn't created via reflection.
+    }
+
+    /**
+     * Returns the current resource selection that is being given to the wizard.
+     */
+    protected IStructuredSelection getCurrentResourceSelection() {
+        return parentWizardPage.getCurrentResourceSelection();
+    }
+
+    @Override
+	public Point getExtent() {
+        return new Point(-1, -1);
+    }
+
+    @Override
+	public String getLocalId() {
+    	IPluginContribution contribution = Adapters.adapt(wizardElement, IPluginContribution.class);
+		if (contribution != null) {
+			return contribution.getLocalId();
+		}
+		return wizardElement.getId();
+    }
+
+    @Override
+	public String getPluginId() {
+       	IPluginContribution contribution = Adapters.adapt(wizardElement, IPluginContribution.class);
+		if (contribution != null) {
+			return contribution.getPluginId();
+		}
+		return null;
+    }
+
+    @Override
+	public IWizard getWizard() {
+        if (wizard != null) {
+			return wizard; // we've already created it
+		}
+
+        final IWorkbenchWizard[] workbenchWizard = new IWorkbenchWizard[1];
+        final IStatus statuses[] = new IStatus[1];
+        // Start busy indicator.
+        BusyIndicator.showWhile(parentWizardPage.getShell().getDisplay(),
+                () -> SafeRunner.run(new SafeRunnable() {
+				    /**
+				     * Add the exception details to status is one happens.
+				     */
+				    @Override
+					public void handleException(Throwable e) {
+				       	IPluginContribution contribution = Adapters.adapt(wizardElement, IPluginContribution.class);
+				        statuses[0] = new Status(
+				                IStatus.ERROR,
+				                contribution != null ? contribution.getPluginId() : WorkbenchPlugin.PI_WORKBENCH,
+				                IStatus.OK,
+				                WorkbenchMessages.get().WorkbenchWizard_errorMessage,
+				                e);
+				    }
+
+				    @Override
+					public void run() {
+				        try {
+				            workbenchWizard[0] = createWizard();
+				            // create instance of target wizard
+				        } catch (CoreException e) {
+				        	IPluginContribution contribution = Adapters.adapt(wizardElement, IPluginContribution.class);
+				        	statuses[0] = new Status(
+				                    IStatus.ERROR,
+				                    contribution != null ? contribution.getPluginId() : WorkbenchPlugin.PI_WORKBENCH,
+				                    IStatus.OK,
+				                    WorkbenchMessages.get().WorkbenchWizard_errorMessage,
+				                    e);
+				        }
+				    }
+				}));
+
+        if (statuses[0] != null) {
+            parentWizardPage
+					.setErrorMessage(WorkbenchMessages.get().WorkbenchWizard_errorMessage);
+			StatusAdapter statusAdapter = new StatusAdapter(statuses[0]);
+			statusAdapter.addAdapter(Shell.class, parentWizardPage.getShell());
+			statusAdapter.setProperty(StatusAdapter.TITLE_PROPERTY,
+					WorkbenchMessages.get().WorkbenchWizard_errorTitle);
+			StatusManager.getManager()
+					.handle(statusAdapter, StatusManager.SHOW);
+			return null;
+        }
+
+        IStructuredSelection currentSelection = getCurrentResourceSelection();
+
+        //Get the adapted version of the selection that works for the
+        //wizard node
+        currentSelection = wizardElement.adaptedSelection(currentSelection);
+
+        workbenchWizard[0].init(getWorkbench(), currentSelection);
+
+        wizard = workbenchWizard[0];
+        return wizard;
+    }
+
+    /**
+     * Returns the wizard element.
+     *
+     * @return the wizard descriptor
+     */
+    public IWizardDescriptor getWizardElement() {
+        return wizardElement;
+    }
+
+    /**
+     * Returns the current workbench.
+     */
+    protected IWorkbench getWorkbench() {
+        return parentWizardPage.getWorkbench();
+    }
+
+    @Override
+	public boolean isContentCreated() {
+        return wizard != null;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkbenchWizardSelectionPage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkbenchWizardSelectionPage.java
new file mode 100644
index 0000000..f2861ae
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkbenchWizardSelectionPage.java
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.dialogs;
+
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.wizard.IWizardNode;
+import org.eclipse.jface.wizard.IWizardPage;
+import org.eclipse.jface.wizard.WizardSelectionPage;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.activities.ITriggerPoint;
+import org.eclipse.ui.activities.WorkbenchActivityHelper;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.model.AdaptableList;
+
+/**
+ * Page for selecting a wizard from a group of available wizards.
+ */
+public abstract class WorkbenchWizardSelectionPage extends WizardSelectionPage {
+
+    // variables
+    protected IWorkbench workbench;
+
+    protected AdaptableList wizardElements;
+
+    public TableViewer wizardSelectionViewer;
+
+    protected IStructuredSelection currentResourceSelection;
+
+    protected String triggerPointId;
+
+    /**
+     *	Create an instance of this class
+     */
+    public WorkbenchWizardSelectionPage(String name, IWorkbench aWorkbench,
+            IStructuredSelection currentSelection, AdaptableList elements,
+            String triggerPointId) {
+        super(name);
+        this.wizardElements = elements;
+        this.currentResourceSelection = currentSelection;
+        this.workbench = aWorkbench;
+        this.triggerPointId = triggerPointId;
+        setTitle(WorkbenchMessages.get().Select);
+    }
+
+    /**
+     *	Answer the wizard object corresponding to the passed id, or null
+     *	if such an object could not be found
+     *
+     *	@return WizardElement
+     *	@param searchId the id to search on
+     */
+    protected WorkbenchWizardElement findWizard(String searchId) {
+		for (Object element : wizardElements.getChildren()) {
+            WorkbenchWizardElement currentWizard = (WorkbenchWizardElement) element;
+            if (currentWizard.getId().equals(searchId)) {
+				return currentWizard;
+			}
+        }
+
+        return null;
+    }
+
+    public IStructuredSelection getCurrentResourceSelection() {
+        return currentResourceSelection;
+    }
+
+    public IWorkbench getWorkbench() {
+        return this.workbench;
+    }
+
+    /**
+     *	Specify the passed wizard node as being selected, meaning that if
+     *	it's non-null then the wizard to be displayed when the user next
+     *	presses the Next button should be determined by asking the passed
+     *	node.
+     *
+     *	@param node org.eclipse.jface.wizards.IWizardNode
+     */
+    public void selectWizardNode(IWizardNode node) {
+        setSelectedNode(node);
+    }
+
+    @Override
+	public IWizardPage getNextPage() {
+        ITriggerPoint triggerPoint = getWorkbench().getActivitySupport()
+        .getTriggerPointManager().getTriggerPoint(triggerPointId);
+        if (triggerPoint == null || WorkbenchActivityHelper.allowUseOf(triggerPoint, getSelectedNode())) {
+			return super.getNextPage();
+		}
+        return null;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkingSetEditWizard.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkingSetEditWizard.java
new file mode 100644
index 0000000..310aca9
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkingSetEditWizard.java
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.dialogs;
+
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.ui.IWorkingSet;
+import org.eclipse.ui.dialogs.IWorkingSetEditWizard;
+import org.eclipse.ui.dialogs.IWorkingSetPage;
+import org.eclipse.ui.internal.WorkbenchMessages;
+
+/**
+ * A working set edit wizard allows the user to edit a
+ * working set using a plugin specified working set page.
+ *
+ * @since 2.0
+ * @see org.eclipse.ui.dialog.IWorkingSetPage
+ */
+public class WorkingSetEditWizard extends Wizard implements
+        IWorkingSetEditWizard {
+    private IWorkingSetPage workingSetEditPage;
+
+    private IWorkingSet workingSet;
+
+    /**
+     * Creates a new instance of the receiver.
+     *
+     * @param editPage the working set page that is going to
+     * 	be used for editing a working set.
+     */
+    public WorkingSetEditWizard(IWorkingSetPage editPage) {
+        super();
+        workingSetEditPage = editPage;
+        workingSetEditPage.setWizard(this);
+        setWindowTitle(WorkbenchMessages.get().WorkingSetEditWizard_title);
+    }
+
+    /**
+     * Overrides Wizard.
+     *
+     * @see org.eclipse.jface.wizard.Wizard#addPages
+     */
+    @Override
+	public void addPages() {
+        super.addPages();
+        addPage(workingSetEditPage);
+    }
+
+    /**
+     * Overrides Wizard.
+     *
+     * @see org.eclipse.jface.wizard.Wizard#canFinish()
+     */
+    @Override
+	public boolean canFinish() {
+        return workingSetEditPage.isPageComplete();
+    }
+
+    /**
+     * Returns the working set that is being edited.
+     *
+     * @return the working set that is being edited.
+     */
+    @Override
+	public IWorkingSet getSelection() {
+        return workingSet;
+    }
+
+    /**
+     * Overrides Wizard.
+     * Notifies the IWorkingSetPage that the wizard is being closed.
+     *
+     * @see org.eclipse.jface.wizard.Wizard#performFinish
+     */
+    @Override
+	public boolean performFinish() {
+        workingSetEditPage.finish();
+        return true;
+    }
+
+    /**
+     * Sets the working set that should be edited.
+     *
+     * @param workingSet the working set that should be edited.
+     */
+    public void setSelection(IWorkingSet workingSet) {
+        this.workingSet = workingSet;
+        workingSetEditPage.setSelection(workingSet);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkingSetFilter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkingSetFilter.java
new file mode 100644
index 0000000..34b1358
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkingSetFilter.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.dialogs;
+
+import java.util.Set;
+
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.ui.IWorkingSet;
+
+public class WorkingSetFilter extends ViewerFilter {
+		Set workingSetIds;
+
+		public WorkingSetFilter(Set workingSetIds) {
+			this.workingSetIds = workingSetIds;
+		}
+
+    @Override
+	public boolean select(Viewer viewer, Object parentElement, Object element) {
+        if (element instanceof IWorkingSet) {
+            IWorkingSet workingSet = (IWorkingSet) element;
+			String id = workingSet.getId();
+            //if (!workingSet.isVisible())
+            //	return false;
+            if (workingSetIds != null && id != null) {
+                return workingSetIds.contains(id);
+            }
+        }
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkingSetLabelProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkingSetLabelProvider.java
new file mode 100644
index 0000000..bd40202
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkingSetLabelProvider.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2014 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.ui.internal.dialogs;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.jface.resource.ResourceManager;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.IWorkingSet;
+
+public class WorkingSetLabelProvider extends LabelProvider {
+    private ResourceManager images;
+
+    /**
+     * Create a new instance of the receiver.
+     */
+    public WorkingSetLabelProvider() {
+        images = new LocalResourceManager(JFaceResources.getResources());
+    }
+
+    @Override
+	public void dispose() {
+        images.dispose();
+
+        super.dispose();
+    }
+
+    @Override
+	public Image getImage(Object object) {
+        Assert.isTrue(object instanceof IWorkingSet);
+        IWorkingSet workingSet = (IWorkingSet) object;
+        ImageDescriptor imageDescriptor = workingSet.getImageDescriptor();
+
+        if (imageDescriptor == null) {
+			return null;
+		}
+
+        Image icon = (Image) images.get(imageDescriptor);
+        return icon;
+    }
+
+    @Override
+	public String getText(Object object) {
+        Assert.isTrue(object instanceof IWorkingSet);
+        IWorkingSet workingSet = (IWorkingSet) object;
+        return workingSet.getLabel();
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkingSetNewWizard.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkingSetNewWizard.java
new file mode 100644
index 0000000..ea852c9
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkingSetNewWizard.java
@@ -0,0 +1,143 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.dialogs;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.wizard.IWizardPage;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.ui.IWorkingSet;
+import org.eclipse.ui.dialogs.IWorkingSetNewWizard;
+import org.eclipse.ui.dialogs.IWorkingSetPage;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.registry.WorkingSetDescriptor;
+import org.eclipse.ui.internal.registry.WorkingSetRegistry;
+
+/**
+ * A new working set wizard allows the user to create a
+ * new working set using a plugin specified working set page.
+ *
+ * @since 2.0
+ * @see org.eclipse.ui.dialog.IWorkingSetPage
+ */
+public class WorkingSetNewWizard extends Wizard implements IWorkingSetNewWizard {
+    private WorkingSetTypePage workingSetTypePage;
+
+    private IWorkingSetPage workingSetEditPage;
+
+    private String editPageId;
+
+    private IWorkingSet workingSet;
+
+    private WorkingSetDescriptor[] descriptors;
+
+    /**
+     * Creates a new instance of the receiver.
+     *
+     * @param descriptors the choice of descriptors
+     */
+    public WorkingSetNewWizard(WorkingSetDescriptor[] descriptors) {
+        super();
+        Assert.isTrue(descriptors != null && descriptors.length > 0);
+        this.descriptors= descriptors;
+        setWindowTitle(WorkbenchMessages.get().WorkingSetNewWizard_title);
+    }
+
+    /**
+     * Overrides method in Wizard.
+     * Adds a page listing the available kinds of working sets.
+     * The second wizard page will depend on the selected working set
+     * type.
+     *
+     * @see org.eclipse.jface.wizard.Wizard#addPages()
+     */
+    @Override
+	public void addPages() {
+        super.addPages();
+
+        IWizardPage page;
+        WorkingSetRegistry registry = WorkbenchPlugin.getDefault().getWorkingSetRegistry();
+
+        if (descriptors.length > 1) {
+            page = workingSetTypePage = new WorkingSetTypePage(this.descriptors);
+        } else {
+            editPageId = descriptors[0].getId();
+            page = workingSetEditPage = registry.getWorkingSetPage(editPageId);
+        }
+        page.setWizard(this);
+        addPage(page);
+        setForcePreviousAndNextButtons(descriptors.length > 1);
+    }
+
+	/**
+     * Overrides method in Wizard.
+     *
+     * @see org.eclipse.jface.wizard.Wizard#canFinish()
+     */
+    @Override
+	public boolean canFinish() {
+        return (workingSetEditPage != null && workingSetEditPage
+                .isPageComplete());
+    }
+
+    /**
+     * Overrides method in Wizard.
+     * Returns a working set page for creating the new working set.
+     * This second page is loaded from the plugin that defined the
+     * selected working set type.
+     *
+     * @see org.eclipse.jface.wizard.Wizard#getNextPage(IWizardPage)
+     */
+    @Override
+	public IWizardPage getNextPage(IWizardPage page) {
+        if (workingSetTypePage != null && page == workingSetTypePage) {
+            String pageId = workingSetTypePage.getSelection();
+            if (pageId != null) {
+                if (workingSetEditPage == null || pageId != editPageId) {
+                    WorkingSetRegistry registry = WorkbenchPlugin.getDefault()
+                            .getWorkingSetRegistry();
+                    workingSetEditPage = registry.getWorkingSetPage(pageId);
+                    addPage(workingSetEditPage);
+                    editPageId = pageId;
+                }
+                return workingSetEditPage;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns the new working set. Returns null if the wizard has
+     * been cancelled.
+     *
+     * @return the new working set or null if the wizard has been
+     * 	cancelled.
+     */
+    @Override
+	public IWorkingSet getSelection() {
+        return workingSet;
+    }
+
+    /**
+     * Overrides method in Wizard.
+     * Stores the newly created working set and the id of the page
+     * used to create it.
+     *
+     * @see org.eclipse.jface.wizard.Wizard#performFinish()
+     */
+    @Override
+	public boolean performFinish() {
+        workingSetEditPage.finish();
+        workingSet = workingSetEditPage.getSelection();
+        workingSet.setId(editPageId);
+        return true;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkingSetSelectionDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkingSetSelectionDialog.java
new file mode 100644
index 0000000..15b3a1f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkingSetSelectionDialog.java
@@ -0,0 +1,466 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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
+ * 		Sebastian Davids <sdavids@gmx.de> - Fix for bug 19346 - Dialog font
+ *   	should be activated and used by other components.
+ *******************************************************************************/
+package org.eclipse.ui.internal.dialogs;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.CheckboxTableViewer;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.IWorkingSet;
+import org.eclipse.ui.IWorkingSetManager;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.dialogs.IWorkingSetSelectionDialog;
+import org.eclipse.ui.internal.AggregateWorkingSet;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.util.Util;
+import org.eclipse.ui.model.WorkbenchViewerComparator;
+
+/**
+ * A working set selection dialog displays a list of working
+ * sets available in the workbench.
+ *
+ * @see IWorkingSetSelectionDialog
+ * @since 2.0
+ */
+public class WorkingSetSelectionDialog extends AbstractWorkingSetDialog {
+    private final static int SIZING_SELECTION_WIDGET_HEIGHT = 200;
+
+    private final static int SIZING_SELECTION_WIDGET_WIDTH = 50;
+
+    private ILabelProvider labelProvider;
+
+    private IStructuredContentProvider contentProvider;
+
+    private CheckboxTableViewer listViewer;
+
+    private boolean multiSelect;
+
+    private IWorkbenchWindow workbenchWindow;
+
+	private Button buttonWindowSet;
+
+	private Button buttonNoSet;
+
+	private Button buttonSelectedSets;
+
+    /**
+     * Creates a working set selection dialog.
+     *
+     * @param parentShell the parent shell
+     * @param multi decides how the results are returned with
+     *  <code>WorkingSetSelectionDialog#getSelection()</code> or
+     *  <code>WorkingSetSelectionDialog#getResult()</code>. true= working sets
+     *  chosen in the dialog are returned as an array of working set.false= returns
+     *  an array having a single aggregate working set of all working sets selected
+     *  in the dialog.
+     * @param workingSetIds a list of working set ids which are valid workings sets
+     *  to be selected, created, removed or edited, or <code>null</code> if all currently
+     *  available working set types are valid
+     */
+    public WorkingSetSelectionDialog(Shell parentShell, boolean multi, String[] workingSetIds) {
+        super(parentShell, workingSetIds, true);
+        initWorkbenchWindow();
+
+        contentProvider = new ArrayContentProvider();
+        labelProvider = new WorkingSetLabelProvider();
+        multiSelect = multi;
+        if (multiSelect) {
+            setTitle(WorkbenchMessages.get().WorkingSetSelectionDialog_title_multiSelect);
+            setMessage(WorkbenchMessages.get().WorkingSetSelectionDialog_message_multiSelect);
+        } else {
+            setTitle(WorkbenchMessages.get().WorkingSetSelectionDialog_title);
+            setMessage(WorkbenchMessages.get().WorkingSetSelectionDialog_message);
+        }
+
+    }
+
+    /**
+	 * Determine what window this dialog is being opened on. This impacts the
+	 * returned working set in the case where the user chooses the window set.
+	 *
+	 * @since 3.2
+	 */
+    private void initWorkbenchWindow() {
+		Shell shellToCheck = getShell();
+
+		workbenchWindow = Util.getWorkbenchWindowForShell(shellToCheck);
+	}
+
+    /**
+     * Overrides method from Dialog.
+     *
+     * @see org.eclipse.jface.dialogs.Dialog#cancelPressed()
+     */
+    @Override
+	protected void cancelPressed() {
+        restoreAddedWorkingSets();
+        restoreChangedWorkingSets();
+        restoreRemovedWorkingSets();
+        setSelection(null);
+        super.cancelPressed();
+    }
+
+    /**
+     * Overrides method from Window.
+     *
+     * @see org.eclipse.jface.window.Window#configureShell(Shell)
+     */
+    @Override
+	protected void configureShell(Shell shell) {
+        super.configureShell(shell);
+        PlatformUI.getWorkbench().getHelpSystem().setHelp(shell,
+				IWorkbenchHelpContextIds.WORKING_SET_SELECTION_DIALOG);
+    }
+
+    /**
+     * Overrides method from Dialog.
+     * Create the dialog widgets.
+     *
+     * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(Composite)
+     */
+    @Override
+	protected Control createDialogArea(Composite parent) {
+    	initializeDialogUnits(parent);
+
+        Composite composite = (Composite) super.createDialogArea(parent);
+
+		createMessageArea(composite);
+
+		SelectionListener listener = new SelectionAdapter()
+        {
+            /** {@inheritDoc} */
+            @Override
+            public void widgetSelected(SelectionEvent e)
+            {
+                updateButtonAvailability();
+            }
+        };
+
+		buttonWindowSet = new Button(composite, SWT.RADIO);
+		buttonWindowSet.setText(WorkbenchMessages.get().WindowWorkingSets);
+		buttonWindowSet.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+		buttonWindowSet.addSelectionListener(listener);
+
+		buttonNoSet = new Button(composite, SWT.RADIO);
+		buttonNoSet.setText(WorkbenchMessages.get().NoWorkingSet);
+		buttonNoSet.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+		buttonNoSet.addSelectionListener(listener);
+
+		buttonSelectedSets = new Button(composite, SWT.RADIO);
+		buttonSelectedSets.setText(WorkbenchMessages.get().SelectedWorkingSets);
+		buttonSelectedSets.addSelectionListener(listener);
+
+		switch (getInitialRadioSelection()) {
+		case 0:
+			buttonWindowSet.setSelection(true);
+			break;
+		case 1:
+			buttonNoSet.setSelection(true);
+			break;
+		case 2:
+			buttonSelectedSets.setSelection(true);
+			break;
+		}
+		buttonSelectedSets
+				.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+		Composite viewerComposite = new Composite(composite, SWT.NONE);
+		GridLayout layout = new GridLayout(2, false);
+		layout.marginHeight = layout.marginWidth = 0;
+		layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
+		layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
+		viewerComposite.setLayout(layout);
+
+		GridData data = new GridData(GridData.FILL_BOTH);
+		data.heightHint = SIZING_SELECTION_WIDGET_HEIGHT;
+		data.widthHint = SIZING_SELECTION_WIDGET_WIDTH + 300;  // fudge?  I like fudge.
+		viewerComposite.setLayoutData(data);
+
+		listViewer = CheckboxTableViewer.newCheckList(viewerComposite,
+				SWT.BORDER | SWT.MULTI);
+		data = new GridData(GridData.FILL_BOTH);
+		data.heightHint = SIZING_SELECTION_WIDGET_HEIGHT;
+		data.widthHint = SIZING_SELECTION_WIDGET_WIDTH;
+		listViewer.getTable().setLayoutData(data);
+
+        listViewer.setLabelProvider(labelProvider);
+        listViewer.setContentProvider(contentProvider);
+        listViewer.setComparator(new WorkbenchViewerComparator());
+
+        listViewer.addFilter(new WorkingSetFilter(getSupportedWorkingSetIds()));
+
+        listViewer.addSelectionChangedListener(event -> handleSelectionChanged());
+        listViewer.addDoubleClickListener(event -> {
+			Object obj = listViewer.getStructuredSelection().getFirstElement();
+			listViewer.setCheckedElements(new Object[] {obj});
+			buttonWindowSet.setSelection(false);
+			buttonNoSet.setSelection(false);
+			buttonSelectedSets.setSelection(true);
+			okPressed();
+		});
+        listViewer.addCheckStateListener(event -> {
+			// implicitly select the third radio button
+			buttonWindowSet.setSelection(false);
+			buttonNoSet.setSelection(false);
+			buttonSelectedSets.setSelection(true);
+		});
+
+        addModifyButtons(viewerComposite);
+
+        addSelectionButtons(composite);
+
+
+		listViewer.setInput(Arrays.asList(WorkbenchPlugin.getDefault()
+				.getWorkingSetManager().getWorkingSets()));
+        List initialElementSelections = getInitialElementSelections();
+		if (multiSelect) {
+			listViewer.setCheckedElements(initialElementSelections.toArray());
+		} else if (!initialElementSelections.isEmpty()) {
+			IWorkingSet set = (IWorkingSet) initialElementSelections.get(0);
+			if (set instanceof AggregateWorkingSet) {
+				AggregateWorkingSet aggregate = (AggregateWorkingSet) set;
+				listViewer.setCheckedElements(aggregate.getComponents());
+			}
+			else {
+				listViewer.setCheckedElements(initialElementSelections.toArray());
+			}
+		}
+
+		availableWorkingSetsChanged();
+		Dialog.applyDialogFont(composite);
+
+		return composite;
+    }
+
+    private int getInitialRadioSelection() {
+    		IWorkingSet windowSet = workbenchWindow.getActivePage().getAggregateWorkingSet();
+
+    		int selectionIndex;
+    		if (getSelection() != null && getSelection().length > 0) {
+    			if (windowSet.equals(getSelection()[0])) {
+    				selectionIndex = 0;
+    			}
+    			else {
+    				selectionIndex = 2;
+    			}
+    		}
+    		else {
+    			selectionIndex = 1;
+    		}
+
+		return selectionIndex;
+	}
+
+	/**
+     * Overrides method from Dialog.
+     * Sets the initial selection, if any.
+     *
+     * @see org.eclipse.jface.dialogs.Dialog#createContents(Composite)
+     */
+    @Override
+	protected Control createContents(Composite parent) {
+        Control control = super.createContents(parent);
+        List selections = getInitialElementSelections();
+        if (!selections.isEmpty()) {
+            listViewer.setSelection(new StructuredSelection(selections), true);
+        }
+        updateButtonAvailability();
+        return control;
+    }
+
+    /**
+     * Returns the selected working sets.
+     *
+     * @return the selected working sets
+     */
+    @Override
+	protected List getSelectedWorkingSets() {
+		return listViewer.getStructuredSelection().toList();
+    }
+
+    /**
+     * Called when the selection has changed.
+     */
+    void handleSelectionChanged() {
+        updateButtonAvailability();
+    }
+
+    /**
+     * Sets the selected working sets as the dialog result.
+     * Overrides method from Dialog
+     *
+     * @see org.eclipse.jface.dialogs.Dialog#okPressed()
+     */
+    @Override
+	protected void okPressed() {
+    		if (buttonWindowSet.getSelection()) {
+    			IWorkingSet [] windowSet = new IWorkingSet[] {workbenchWindow.getActivePage().getAggregateWorkingSet()};
+    			setSelection(windowSet);
+    			setResult(Arrays.asList(getSelection()));
+    		}
+    		else if (buttonNoSet.getSelection()) {
+			setSelection(new IWorkingSet[0]);
+			setResult(Arrays.asList(getSelection()));
+    		}
+    		else if (buttonSelectedSets.getSelection()) {
+			Object[] untypedResult = listViewer.getCheckedElements();
+			IWorkingSet[] typedResult = new IWorkingSet[untypedResult.length];
+			System.arraycopy(untypedResult, 0, typedResult, 0,
+					untypedResult.length);
+			// if multiselect is allowed or there was only one selected then dont create
+			// an aggregate
+			if (multiSelect || typedResult.length <= 1) {
+				setSelection(typedResult);
+				setResult(Arrays.asList(typedResult));
+			} else {
+				String setId = getAggregateIdForSets(typedResult);
+				IWorkingSetManager workingSetManager = workbenchWindow.getWorkbench()
+						.getWorkingSetManager();
+				IWorkingSet aggregate = workingSetManager.getWorkingSet(setId);
+				if (aggregate != null) {
+					workingSetManager.removeWorkingSet(aggregate);
+				}
+				aggregate = workingSetManager.createAggregateWorkingSet(setId,
+						WorkbenchMessages.get().WorkbenchPage_workingSet_multi_label, typedResult);
+				workingSetManager.addWorkingSet(aggregate);
+				setSelection(new IWorkingSet[] { aggregate });
+				setResult(Collections.singletonList(aggregate));
+			}
+    		}
+
+        super.okPressed();
+    }
+
+    /**
+	 * Create a string that represents the name of the aggregate set composed of
+	 * the supplied working sets. It's very long and not printworthy.
+	 *
+	 * @param typedResult the sets
+	 * @return the name
+	 */
+    private String getAggregateIdForSets(IWorkingSet[] typedResult) {
+    		StringBuffer buffer = new StringBuffer();
+    		buffer.append("Aggregate:"); //$NON-NLS-1$
+    		for (IWorkingSet element : typedResult) {
+			buffer.append(element.getName()).append(':');
+		}
+		return buffer.toString();
+	}
+
+	/**
+     * Removes newly created working sets from the working set manager.
+     */
+    private void restoreAddedWorkingSets() {
+        IWorkingSetManager manager = WorkbenchPlugin.getDefault()
+                .getWorkingSetManager();
+        Iterator iterator = getAddedWorkingSets().iterator();
+
+        while (iterator.hasNext()) {
+            manager.removeWorkingSet(((IWorkingSet) iterator.next()));
+        }
+    }
+
+    /**
+     * Rolls back changes to working sets.
+     */
+    private void restoreChangedWorkingSets() {
+        Iterator iterator = getEditedWorkingSets().keySet().iterator();
+
+        while (iterator.hasNext()) {
+            IWorkingSet editedWorkingSet = (IWorkingSet) iterator.next();
+			IWorkingSet originalWorkingSet = getEditedWorkingSets().get(editedWorkingSet);
+
+            if (editedWorkingSet.getName().equals(originalWorkingSet.getName()) == false) {
+                editedWorkingSet.setName(originalWorkingSet.getName());
+            }
+			if (!Arrays.equals(editedWorkingSet.getElements(), originalWorkingSet.getElements())) {
+                editedWorkingSet.setElements(originalWorkingSet.getElements());
+            }
+        }
+    }
+
+    /**
+     * Adds back removed working sets to the working set manager.
+     */
+    private void restoreRemovedWorkingSets() {
+        IWorkingSetManager manager = WorkbenchPlugin.getDefault()
+                .getWorkingSetManager();
+        Iterator iterator = getRemovedWorkingSets().iterator();
+
+        while (iterator.hasNext()) {
+            manager.addWorkingSet(((IWorkingSet) iterator.next()));
+        }
+        iterator = getRemovedMRUWorkingSets().iterator();
+        while (iterator.hasNext()) {
+            manager.addRecentWorkingSet(((IWorkingSet) iterator.next()));
+        }
+    }
+
+    /**
+     * Implements IWorkingSetSelectionDialog.
+     *
+     * @see org.eclipse.ui.dialogs.IWorkingSetSelectionDialog#setSelection(IWorkingSet[])
+     */
+    @Override
+	public void setSelection(IWorkingSet[] workingSets) {
+        super.setSelection(workingSets);
+        setInitialSelections(workingSets == null ? new Object[0] : workingSets);
+    }
+
+	@Override
+	protected void availableWorkingSetsChanged() {
+		listViewer.setInput(PlatformUI.getWorkbench().getWorkingSetManager().getWorkingSets());
+		super.availableWorkingSetsChanged();
+	}
+
+	@Override
+	protected void selectAllSets() {
+		listViewer.setCheckedElements(PlatformUI.getWorkbench().getWorkingSetManager().getWorkingSets());
+		// implicitly select the third radio button
+		buttonWindowSet.setSelection(false);
+		buttonNoSet.setSelection(false);
+		buttonSelectedSets.setSelection(true);
+		updateButtonAvailability();
+	}
+
+	@Override
+	protected void deselectAllSets() {
+		listViewer.setCheckedElements(new Object[0]);
+		// implicitly select the third radio button
+		buttonWindowSet.setSelection(false);
+		buttonNoSet.setSelection(false);
+		buttonSelectedSets.setSelection(true);
+		updateButtonAvailability();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkingSetTypePage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkingSetTypePage.java
new file mode 100644
index 0000000..9e28ac8
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/WorkingSetTypePage.java
@@ -0,0 +1,192 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ * 		  Sebastian Davids <sdavids@gmx.de> - Fix for bug 19346 - Dialog font should be
+ *        activated and used by other components.
+ *******************************************************************************/
+package org.eclipse.ui.internal.dialogs;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.jface.resource.ResourceManager;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.registry.WorkingSetDescriptor;
+
+/**
+ * The working set type page is used in the new working set
+ * wizard to select from a list of plugin defined working set
+ * types.
+ *
+ * @since 2.0
+ */
+public class WorkingSetTypePage extends WizardPage {
+    private final static int SIZING_SELECTION_WIDGET_WIDTH = 50;
+
+    private final static int SIZING_SELECTION_WIDGET_HEIGHT = 200;
+
+    private TableViewer typesListViewer;
+
+	private WorkingSetDescriptor[] descriptors;
+
+    /**
+     * Creates a new instance of the receiver
+     */
+    public WorkingSetTypePage() {
+        this(WorkbenchPlugin.getDefault().getWorkingSetRegistry().getNewPageWorkingSetDescriptors());
+    }
+
+    /**
+	 * @param descriptors a set of working set descriptors which can be selected on the page
+	 */
+	public WorkingSetTypePage(WorkingSetDescriptor[] descriptors) {
+		super(
+				"workingSetTypeSelectionPage", WorkbenchMessages.get().WorkingSetTypePage_description, WorkbenchImages.getImageDescriptor(IWorkbenchGraphicConstants.IMG_WIZBAN_WORKINGSET_WIZ)); //$NON-NLS-1$
+		this.descriptors = descriptors;
+	}
+
+    /**
+	 * Overrides method in WizardPage
+	 *
+	 * @see org.eclipse.jface.wizard.IWizardPage#canFlipToNextPage()
+	 */
+    @Override
+	public boolean canFlipToNextPage() {
+        return isPageComplete();
+    }
+
+    /**
+     * Implements IDialogPage
+     *
+     * @see org.eclipse.jface.dialogs.IDialogPage#createControl(Composite)
+     */
+    @Override
+	public void createControl(Composite parent) {
+        Font font = parent.getFont();
+        Composite composite = new Composite(parent, SWT.NULL);
+        composite.setLayout(new GridLayout());
+        composite.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL));
+        setControl(composite);
+
+        PlatformUI.getWorkbench().getHelpSystem().setHelp(composite,
+				IWorkbenchHelpContextIds.WORKING_SET_TYPE_PAGE);
+        Label typesLabel = new Label(composite, SWT.NONE);
+        typesLabel.setText(WorkbenchMessages.get().WorkingSetTypePage_typesLabel);
+        GridData data = new GridData(GridData.FILL_HORIZONTAL);
+        typesLabel.setLayoutData(data);
+        typesLabel.setFont(font);
+
+        typesListViewer = new TableViewer(composite, SWT.BORDER | SWT.SINGLE);
+        data = new GridData(GridData.FILL_BOTH);
+        data.heightHint = SIZING_SELECTION_WIDGET_HEIGHT;
+        data.widthHint = SIZING_SELECTION_WIDGET_WIDTH;
+        typesListViewer.getTable().setLayoutData(data);
+        typesListViewer.getTable().setFont(font);
+        typesListViewer
+                .addSelectionChangedListener(event -> handleSelectionChanged());
+        typesListViewer.addDoubleClickListener(event -> handleDoubleClick());
+        typesListViewer.setContentProvider(new ArrayContentProvider());
+        typesListViewer.setLabelProvider(new LabelProvider() {
+        	private ResourceManager images = new LocalResourceManager(
+					JFaceResources.getResources());
+			@Override
+			public String getText(Object element) {
+				return ((WorkingSetDescriptor)element).getName();
+			}
+
+			@Override
+			public void dispose() {
+				images.dispose();
+				super.dispose();
+			}
+
+			@Override
+			public Image getImage(Object element) {
+				ImageDescriptor imageDescriptor = ((WorkingSetDescriptor) element)
+						.getIcon();
+				return imageDescriptor == null ? null : (Image) images
+						.get(imageDescriptor);
+			}
+		});
+        typesListViewer.setInput(descriptors);
+        setPageComplete(false);
+    }
+
+    /**
+     * Overrides method in DialogPage
+     *
+     * @see org.eclipse.jface.dialogs.IDialogPage#dispose()
+     */
+    @Override
+	public void dispose() {
+        super.dispose();
+    }
+
+    /**
+     * Returns the page id of the selected working set type.
+     *
+     * @return the page id of the selected working set type.
+     */
+    public String getSelection() {
+        WorkingSetDescriptor descriptor = getSelectedWorkingSet();
+        if (descriptor != null)
+        	return descriptor.getId();
+
+        return null;
+    }
+
+	/**
+     * Return the selected working set.
+     *
+	 * @return the selected working set or <code>null</code>
+     * @since 3.4
+	 */
+	private WorkingSetDescriptor getSelectedWorkingSet() {
+		return (WorkingSetDescriptor) typesListViewer.getStructuredSelection().getFirstElement();
+	}
+
+    /**
+     * Called when a working set type is double clicked.
+     */
+    private void handleDoubleClick() {
+        handleSelectionChanged();
+        getContainer().showPage(getNextPage());
+    }
+
+    /**
+     * Called when the selection has changed.
+     */
+    private void handleSelectionChanged() {
+		IStructuredSelection selection = typesListViewer.getStructuredSelection();
+        boolean hasSelection = selection != null
+                && selection.isEmpty() == false;
+
+        WorkingSetDescriptor descriptor = getSelectedWorkingSet();
+		setDescription(descriptor == null ? "" : descriptor.getDescription()); //$NON-NLS-1$
+
+        setPageComplete(hasSelection);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/ActionSetFilter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/ActionSetFilter.java
new file mode 100644
index 0000000..162a446
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/ActionSetFilter.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.dialogs.cpd;
+
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.ui.internal.dialogs.cpd.CustomizePerspectiveDialog.ActionSet;
+import org.eclipse.ui.internal.dialogs.cpd.CustomizePerspectiveDialog.DisplayItem;
+
+/**
+ * Filters out contribution items which are not in a given action set.
+ *
+ * @since 3.5
+ */
+class ActionSetFilter extends ViewerFilter {
+	private ActionSet actionSet;
+
+	public void setActionSet(ActionSet actionSet) {
+		this.actionSet = actionSet;
+	}
+
+	@Override
+	public boolean select(Viewer viewer, Object parentElement, Object element) {
+		if (!(element instanceof DisplayItem) || actionSet == null) {
+			return false;
+		}
+		return CustomizePerspectiveDialog.includeInSetStructure((DisplayItem) element, actionSet);
+	}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/ActionSetSelectionChangedListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/ActionSetSelectionChangedListener.java
new file mode 100644
index 0000000..21b93e0
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/ActionSetSelectionChangedListener.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.dialogs.cpd;
+
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.ui.internal.dialogs.cpd.CustomizePerspectiveDialog.ActionSet;
+
+/**
+ * A Listener for a list of command groups, that updates the viewer and filter
+ * who are dependent on the action set selection.
+ *
+ * @since 3.5
+ */
+final class ActionSetSelectionChangedListener implements ISelectionChangedListener {
+	private final TreeViewer filterViewer;
+	private final ActionSetFilter filter;
+
+	public ActionSetSelectionChangedListener(TreeViewer viewer, ActionSetFilter menuStructureFilterByActionSet) {
+		this.filterViewer = viewer;
+		this.filter = menuStructureFilterByActionSet;
+	}
+
+	@Override
+	public void selectionChanged(SelectionChangedEvent event) {
+		Object element = ((IStructuredSelection) event.getSelection()).getFirstElement();
+		filter.setActionSet((ActionSet) element);
+		filterViewer.refresh();
+		filterViewer.expandAll();
+	}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/CategoryCheckProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/CategoryCheckProvider.java
new file mode 100644
index 0000000..cbee10f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/CategoryCheckProvider.java
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.dialogs.cpd;
+
+import org.eclipse.jface.viewers.ICheckStateProvider;
+import org.eclipse.ui.internal.dialogs.cpd.CustomizePerspectiveDialog.Category;
+import org.eclipse.ui.internal.dialogs.cpd.CustomizePerspectiveDialog.DisplayItem;
+import org.eclipse.ui.internal.dialogs.cpd.CustomizePerspectiveDialog.ShortcutItem;
+import org.eclipse.ui.internal.dialogs.cpd.TreeManager.TreeItem;
+
+/**
+ * Provides the check logic for the categories viewer in the shortcuts tab.
+ * Categories have a dual concept of children - their proper children
+ * (sub-Categories, as in the wizards), and the actual elements they
+ * contribute to the menu system. The check state must take this into
+ * account.
+ *
+ * @since 3.5
+ */
+class CategoryCheckProvider implements ICheckStateProvider {
+	@Override
+	public boolean isChecked(Object element) {
+		Category category = (Category) element;
+
+		if (category.getChildren().isEmpty()
+				&& category.getContributionItems().isEmpty()) {
+			return false;
+		}
+
+		// To be checked, any sub-Category can be checked.
+		for (TreeItem treeItem : category.getChildren()) {
+			Category child = (Category) treeItem;
+			if (isChecked(child)) {
+				return true;
+			}
+		}
+
+		// To be checked, any ShortcutItem can be checked.
+		for (ShortcutItem shortcutItem : category.getContributionItems()) {
+			DisplayItem item = shortcutItem;
+			if (item.getState()) {
+				return true;
+			}
+		}
+
+		return false;
+	}
+
+	@Override
+	public boolean isGrayed(Object element) {
+		boolean hasChecked = false;
+		boolean hasUnchecked = false;
+		Category category = (Category) element;
+
+		// Search in sub-Categories and ShortcutItems for one that is
+		// checked and one that is unchecked.
+
+		for (TreeItem treeItem : category.getChildren()) {
+			Category child = (Category) treeItem;
+			if (isGrayed(child)) {
+				return true;
+			}
+			if (isChecked(child)) {
+				hasChecked = true;
+			} else {
+				hasUnchecked = true;
+			}
+			if (hasChecked && hasUnchecked) {
+				return true;
+			}
+		}
+
+		for (ShortcutItem shortcutItem : category.getContributionItems()) {
+			DisplayItem item = shortcutItem;
+			if (item.getState()) {
+				hasChecked = true;
+			} else {
+				hasUnchecked = true;
+			}
+			if (hasChecked && hasUnchecked) {
+				return true;
+			}
+		}
+
+		return false;
+	}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/CustomizeActionBars.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/CustomizeActionBars.java
new file mode 100644
index 0000000..9859e5d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/CustomizeActionBars.java
@@ -0,0 +1,174 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Erik Chou <ekchou@ymail.com> - Bug 378849
+ *     Paul Webster <pwebster@ca.ibm.com> - Bug 378849
+ *     Andrey Loskutov <loskutov@gmx.de> - Bug 420956 - Fix perspective customization on 4.x
+ *******************************************************************************/
+package org.eclipse.ui.internal.dialogs.cpd;
+
+import java.util.ArrayList;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.ui.basic.MTrimElement;
+import org.eclipse.e4.ui.model.application.ui.basic.MTrimmedWindow;
+import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
+import org.eclipse.e4.ui.model.application.ui.menu.MMenu;
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+import org.eclipse.e4.ui.workbench.renderers.swt.MenuManagerRenderer;
+import org.eclipse.e4.ui.workbench.swt.factories.IRendererFactory;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.IStatusLineManager;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.StatusLineManager;
+import org.eclipse.jface.action.ToolBarManager;
+import org.eclipse.jface.internal.provisional.action.IToolBarContributionItem;
+import org.eclipse.jface.internal.provisional.action.ToolBarContributionItem2;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IActionBars2;
+import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
+import org.eclipse.ui.internal.CoolBarToTrimManager;
+import org.eclipse.ui.internal.menus.ActionSet;
+import org.eclipse.ui.internal.provisional.application.IActionBarConfigurer2;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * Fake action bars to build the menus and toolbar contributions for the
+ * workbench. We cannot use the actual workbench action bars, since doing so
+ * would make the action set items visible.
+ *
+ * @since 3.5
+ */
+public class CustomizeActionBars implements IActionBarConfigurer2, IActionBars2 {
+
+	private final IWorkbenchWindowConfigurer configurer;
+	private final StatusLineManager statusLineManager;
+	private final MApplication app;
+
+	final MenuManager menuManager;
+	final CoolBarToTrimManager coolBarManager;
+	final MTrimmedWindow windowModel;
+	final MMenu mainMenu;
+	final MenuManagerRenderer menuRenderer;
+
+	/**
+	 * Create a new instance of this class.
+	 *
+	 * @param configurer
+	 *            non null
+	 * @param context
+	 *            non null
+	 */
+	public CustomizeActionBars(IWorkbenchWindowConfigurer configurer, IEclipseContext context) {
+		this.configurer = configurer;
+		statusLineManager = new StatusLineManager();
+		menuManager = new MenuManager("MenuBar", ActionSet.MAIN_MENU); //$NON-NLS-1$
+
+		IRendererFactory rendererFactory = context.get(IRendererFactory.class);
+		EModelService modelService = context.get(EModelService.class);
+
+		windowModel = modelService.createModelElement(MTrimmedWindow.class);
+		app = context.get(MApplication.class);
+		IEclipseContext eclipseContext = app.getContext().createChild("window - CustomizeActionBars"); //$NON-NLS-1$
+		windowModel.setContext(eclipseContext);
+		eclipseContext.set(MWindow.class, windowModel);
+
+		Shell shell = new Shell();
+		windowModel.setWidget(shell);
+		windowModel.setToBeRendered(false);
+		app.getChildren().add(windowModel);
+		shell.setData(org.eclipse.e4.ui.internal.workbench.swt.AbstractPartRenderer.OWNING_ME, windowModel);
+
+		// See WorkbenchWindow.setup()
+		mainMenu = modelService.createModelElement(MMenu.class);
+		mainMenu.setElementId(ActionSet.MAIN_MENU);
+
+		menuRenderer = (MenuManagerRenderer) rendererFactory.getRenderer(mainMenu, null);
+		menuRenderer.linkModelToManager(mainMenu, menuManager);
+		windowModel.setMainMenu(mainMenu);
+
+		coolBarManager = new CoolBarToTrimManager(app, windowModel, new ArrayList<MTrimElement>(), rendererFactory);
+	}
+
+	@Override
+	public IWorkbenchWindowConfigurer getWindowConfigurer() {
+		return configurer;
+	}
+
+	@Override
+	public IMenuManager getMenuManager() {
+		return menuManager;
+	}
+
+	@Override
+	public IStatusLineManager getStatusLineManager() {
+		return statusLineManager;
+	}
+
+	@Override
+	public CoolBarToTrimManager getCoolBarManager() {
+		return coolBarManager;
+	}
+
+	@Override
+	public IToolBarManager getToolBarManager() {
+		return null;
+	}
+
+	@Override
+	public void setGlobalActionHandler(String actionID, IAction handler) {
+	}
+
+	@Override
+	public void updateActionBars() {
+	}
+
+	@Override
+	public void clearGlobalActionHandlers() {
+	}
+
+	@Override
+	public IAction getGlobalActionHandler(String actionId) {
+		return null;
+	}
+
+	@Override
+	public void registerGlobalAction(IAction action) {
+	}
+
+	/**
+	 * Clean up the action bars.
+	 */
+	public void dispose() {
+		coolBarManager.dispose();
+		menuManager.dispose();
+		statusLineManager.dispose();
+		windowModel.getContext().deactivate();
+		windowModel.getContext().dispose();
+		((Shell) windowModel.getWidget()).dispose();
+		app.getChildren().remove(windowModel);
+	}
+
+	@Override
+	public final IServiceLocator getServiceLocator() {
+		return configurer.getWindow();
+	}
+
+	@Override
+	public IToolBarContributionItem createToolBarContributionItem(IToolBarManager toolBarManager, String id) {
+		return new ToolBarContributionItem2(toolBarManager, id);
+	}
+
+	@Override
+	public IToolBarManager createToolBarManager() {
+		return new ToolBarManager();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/CustomizePerspectiveDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/CustomizePerspectiveDialog.java
new file mode 100644
index 0000000..3b6f064
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/CustomizePerspectiveDialog.java
@@ -0,0 +1,2436 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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
+ *     Tom Hochstein (Freescale) - Bug 407522 - Perspective reset not working correctly
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 422040, 431992, 472654
+ *     Andrey Loskutov <loskutov@gmx.de> - Bug 456729, 404348, 421178, 420956, 424638, 460503
+ *******************************************************************************/
+package org.eclipse.ui.internal.dialogs.cpd;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.e4.core.commands.ECommandService;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.ui.bindings.EBindingService;
+import org.eclipse.e4.ui.internal.workbench.OpaqueElementUtil;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.commands.MParameter;
+import org.eclipse.e4.ui.model.application.ui.MUIElement;
+import org.eclipse.e4.ui.model.application.ui.basic.MTrimBar;
+import org.eclipse.e4.ui.model.application.ui.basic.MTrimElement;
+import org.eclipse.e4.ui.model.application.ui.menu.MHandledItem;
+import org.eclipse.e4.ui.model.application.ui.menu.MHandledMenuItem;
+import org.eclipse.e4.ui.model.application.ui.menu.MItem;
+import org.eclipse.e4.ui.model.application.ui.menu.MMenu;
+import org.eclipse.e4.ui.model.application.ui.menu.MMenuElement;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolBar;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolBarElement;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolBarSeparator;
+import org.eclipse.e4.ui.workbench.IPresentationEngine;
+import org.eclipse.e4.ui.workbench.IResourceUtilities;
+import org.eclipse.e4.ui.workbench.renderers.swt.MenuManagerRenderer;
+import org.eclipse.e4.ui.workbench.renderers.swt.ToolBarManagerRenderer;
+import org.eclipse.e4.ui.workbench.swt.util.ISWTResourceUtilities;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.jface.action.ActionContributionItem;
+import org.eclipse.jface.action.ContributionItem;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.IContributionManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.SubContributionItem;
+import org.eclipse.jface.action.ToolBarManager;
+import org.eclipse.jface.bindings.TriggerSequence;
+import org.eclipse.jface.dialogs.TrayDialog;
+import org.eclipse.jface.internal.provisional.action.ToolBarContributionItem2;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.AbstractTreeViewer;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.CheckboxTableViewer;
+import org.eclipse.jface.viewers.CheckboxTreeViewer;
+import org.eclipse.jface.viewers.ComboViewer;
+import org.eclipse.jface.viewers.ICheckStateListener;
+import org.eclipse.jface.viewers.ICheckStateProvider;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.StructuredViewer;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.TabFolder;
+import org.eclipse.swt.widgets.TabItem;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.ToolItem;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.IPerspectiveRegistry;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.ActionFactory;
+import org.eclipse.ui.actions.OpenPerspectiveAction;
+import org.eclipse.ui.activities.WorkbenchActivityHelper;
+import org.eclipse.ui.application.ActionBarAdvisor;
+import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
+import org.eclipse.ui.internal.ActionSetActionBars;
+import org.eclipse.ui.internal.ActionSetContributionItem;
+import org.eclipse.ui.internal.ActionSetMenuManager;
+import org.eclipse.ui.internal.CoolBarToTrimManager;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.Perspective;
+import org.eclipse.ui.internal.PluginActionCoolBarContributionItem;
+import org.eclipse.ui.internal.PluginActionSet;
+import org.eclipse.ui.internal.PluginActionSetBuilder;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPage;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.WorkbenchWindow;
+import org.eclipse.ui.internal.actions.NewWizardShortcutAction;
+import org.eclipse.ui.internal.dialogs.DialogUtil;
+import org.eclipse.ui.internal.dialogs.WorkbenchWizardElement;
+import org.eclipse.ui.internal.dialogs.cpd.TreeManager.TreeItem;
+import org.eclipse.ui.internal.e4.compatibility.ModeledPageLayout;
+import org.eclipse.ui.internal.intro.IIntroConstants;
+import org.eclipse.ui.internal.registry.ActionSetDescriptor;
+import org.eclipse.ui.internal.registry.ActionSetRegistry;
+import org.eclipse.ui.internal.registry.IActionSetDescriptor;
+import org.eclipse.ui.internal.util.BundleUtility;
+import org.eclipse.ui.menus.CommandContributionItem;
+import org.eclipse.ui.model.WorkbenchViewerComparator;
+import org.eclipse.ui.part.PageBook;
+import org.eclipse.ui.views.IViewCategory;
+import org.eclipse.ui.views.IViewDescriptor;
+import org.eclipse.ui.views.IViewRegistry;
+import org.eclipse.ui.wizards.IWizardCategory;
+import org.eclipse.ui.wizards.IWizardDescriptor;
+
+/**
+ * Dialog to allow users the ability to customize the perspective. This includes
+ * customizing menus and toolbars by adding, removing, or re-arranging commands
+ * or groups of commands.
+ *
+ */
+public class CustomizePerspectiveDialog extends TrayDialog {
+
+	private static final String TOOLBAR_ICON = "$nl$/icons/full/obj16/toolbar.png"; //$NON-NLS-1$
+	private static final String SUBMENU_ICON = "$nl$/icons/full/obj16/submenu.png"; //$NON-NLS-1$
+	private static final String MENU_ICON = "$nl$/icons/full/obj16/menu.png"; //$NON-NLS-1$
+	private static final String WARNING_ICON = "$nl$/icons/full/obj16/warn_tsk.png"; //$NON-NLS-1$
+
+	private static final String SHORTCUT_CONTRIBUTION_ITEM_ID_OPEN_PERSPECTIVE = "openPerspective"; //$NON-NLS-1$
+	private static final String SHORTCUT_CONTRIBUTION_ITEM_ID_SHOW_VIEW = "showView"; //$NON-NLS-1$
+
+	static final String KEYS_PREFERENCE_PAGE_ID = "org.eclipse.ui.preferencePages.Keys"; //$NON-NLS-1$
+
+	static final String NEW_LINE = System.getProperty("line.separator"); //$NON-NLS-1$
+
+	static final int MIN_TOOLTIP_WIDTH = 160;
+
+	WorkbenchWindow window;
+
+	private WorkbenchPage windowPage;
+
+	private Perspective perspective;
+
+	private TabFolder tabFolder;
+
+	private final static int TAB_WIDTH_IN_DLUS = 490;
+
+	private final static int TAB_HEIGHT_IN_DLUS = 230;
+
+	private final String shortcutMenuColumnHeaders[] = {
+			WorkbenchMessages.get().ActionSetSelection_menuColumnHeader,
+			WorkbenchMessages.get().ActionSetSelection_descriptionColumnHeader };
+
+	private int[] shortcutMenuColumnWidths = { 125, 300 };
+
+	ImageDescriptor menuImageDescriptor;
+
+	ImageDescriptor submenuImageDescriptor;
+
+	ImageDescriptor toolbarImageDescriptor;
+
+	ImageDescriptor warningImageDescriptor;
+
+	private TreeManager treeManager;
+
+	private DisplayItem menuItems;
+
+	private DisplayItem toolBarItems;
+
+	private Category shortcuts;
+
+	private DisplayItem wizards;
+
+	private DisplayItem perspectives;
+
+	private DisplayItem views;
+
+	Map<String, ActionSet> idToActionSet = new HashMap<>();
+
+	private final List<ActionSet> actionSets = new ArrayList<>();
+
+	private IWorkbenchWindowConfigurer configurer;
+
+	private TabItem actionSetTab;
+
+	private CheckboxTableViewer actionSetAvailabilityTable;
+
+	private TreeViewer actionSetMenuViewer;
+
+	private TreeViewer actionSetToolbarViewer;
+
+	private CheckboxTreeViewer menuStructureViewer1;
+
+	private CheckboxTreeViewer menuStructureViewer2;
+
+	private CheckboxTreeViewer toolbarStructureViewer1;
+
+	private CheckboxTreeViewer toolbarStructureViewer2;
+
+	private CustomizeActionBars customizeActionBars;
+
+	private MenuManagerRenderer menuMngrRenderer;
+	private ToolBarManagerRenderer toolbarMngrRenderer;
+
+	private ISWTResourceUtilities resUtils;
+	private IEclipseContext context;
+
+	/**
+	 * Represents a menu item or a tool bar item.
+	 *
+	 * @since 3.5
+	 */
+	class DisplayItem extends TreeItem {
+		/** The logic item represented */
+		private IContributionItem item;
+
+		/** The action set this item belongs to (optional) */
+		ActionSet actionSet;
+
+		public DisplayItem(String label, IContributionItem item) {
+			treeManager.super(label == null ? null : DialogUtil
+					.removeAccel(removeShortcut(label)));
+			this.item = item;
+		}
+
+		public void setActionSet(ActionSet actionSet) {
+			this.actionSet = actionSet;
+			if (actionSet != null) {
+				actionSet.addItem(this);
+			}
+		}
+
+		public ActionSet getActionSet() {
+			return actionSet;
+		}
+
+		public IContributionItem getIContributionItem() {
+			return item;
+		}
+
+		@Override
+		public String toString() {
+			return super.toString() + item == null ? "" : (" [" + item.getId() + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		}
+	}
+
+	/**
+	 * Represents a menu item whose content is dynamic. Contains a list of the
+	 * current items being displayed.
+	 *
+	 * @since 3.5
+	 */
+	class DynamicContributionItem extends DisplayItem {
+		private List<MenuItem> preview;
+
+		public DynamicContributionItem(IContributionItem item) {
+			super(WorkbenchMessages.get().HideItems_dynamicItemName, item);
+			preview = new ArrayList<>();
+		}
+
+		public void addCurrentItem(MenuItem item) {
+			preview.add(item);
+		}
+
+		public List<MenuItem> getCurrentItems() {
+			return preview;
+		}
+	}
+
+	/**
+	 * @param descriptor
+	 * @param window
+	 * @return the appropriate {@link IContributionItem} for the given wizard
+	 */
+	private static ActionContributionItem getIContributionItem(
+			IWizardDescriptor descriptor, IWorkbenchWindow window) {
+		IAction action = new NewWizardShortcutAction(window, descriptor);
+		return new ActionContributionItem(action);
+	}
+
+	/**
+	 * @param descriptor
+	 * @param window
+	 * @return the appropriate {@link IContributionItem} for the given
+	 *         perspective
+	 */
+	private static ActionContributionItem getIContributionItem(
+			IPerspectiveDescriptor descriptor, IWorkbenchWindow window) {
+		IAction action = new OpenPerspectiveAction(window, descriptor, null);
+		return new ActionContributionItem(action);
+	}
+
+	/**
+	 * @param window
+	 * @return the appropriate {@link IContributionItem} for showing views
+	 */
+	private static ActionContributionItem getIContributionItem(
+			IWorkbenchWindow window) {
+		IAction action = ActionFactory.SHOW_VIEW_MENU.create(window);
+		return new ActionContributionItem(action);
+	}
+
+	/**
+	 * Represents a menu item which needs to be shown in the Shortcuts tab.
+	 *
+	 * @since 3.5
+	 */
+	class ShortcutItem extends DisplayItem {
+		/** The description to show in the table */
+		private String description;
+
+		/** The category this shortcut is in (should be set) */
+		private Category category;
+
+		private Object descriptor;
+
+		public ShortcutItem(String label, IWizardDescriptor descriptor) {
+			super(label, CustomizePerspectiveDialog.getIContributionItem(
+					descriptor, window));
+			this.descriptor = descriptor;
+		}
+
+		public ShortcutItem(String label, IPerspectiveDescriptor descriptor) {
+			super(label, CustomizePerspectiveDialog.getIContributionItem(
+					descriptor, window));
+			this.descriptor = descriptor;
+		}
+
+		public ShortcutItem(String label, IViewDescriptor descriptor) {
+			super(label, CustomizePerspectiveDialog
+					.getIContributionItem(window));
+			this.descriptor = descriptor;
+		}
+
+		public Object getDescriptor() {
+			return descriptor;
+		}
+
+		public void setDescription(String description) {
+			this.description = description;
+		}
+
+		public String getDescription() {
+			return description;
+		}
+
+		public void setCategory(Category category) {
+			this.category = category;
+		}
+
+		public Category getCategory() {
+			return category;
+		}
+	}
+
+	/**
+	 * Represents a category in the shortcuts menu. Since categories can have a
+	 * tree-structure, the functionality provided by the TreeManager and
+	 * TreeItem classes is used, however the logic for visibility changes and
+	 * gray states is more sophisticated.
+	 *
+	 * @since 3.5
+	 */
+	class Category extends TreeItem {
+
+		/** ShortcutItems which are contributed in this Category */
+		private List<ShortcutItem> contributionItems;
+
+		public Category(String label) {
+			treeManager.super(label == null ? null : DialogUtil
+					.removeAccel(removeShortcut(label)));
+			this.contributionItems = new ArrayList<>();
+		}
+
+		public List<ShortcutItem> getContributionItems() {
+			return contributionItems;
+		}
+
+		/**
+		 * Adds another ShortcutItem to this Category's list of ShortcutItems
+		 * and creates a pseudo-child/parent relationship.
+		 *
+		 * @param item
+		 *            the item to add
+		 */
+		public void addShortcutItem(ShortcutItem item) {
+			contributionItems.add(item);
+			item.setCategory(this);
+		}
+
+		/**
+		 * While the child/parent state in the Category hierarchy is
+		 * automatically maintained, the pseudo-child/parent relationship must
+		 * be explicitly updated. This method will update Categories if their
+		 * states need to change as a result of their ShortcutItems.
+		 */
+		public void update() {
+			for (ShortcutItem shortcutItem : contributionItems) {
+				DisplayItem item = shortcutItem;
+				if (item.getState()) {
+					this.setCheckState(true);
+					return;
+				}
+			}
+
+			this.setCheckState(false);
+		}
+
+		/**
+		 * Changes the state of all pseudo-descendant ShortcutItems, causing the
+		 * effective state of this Category and all its sub-Categories to match.
+		 *
+		 * @param state
+		 *            The state to set this branch to.
+		 */
+		public void setItemsState(boolean state) {
+			for (ShortcutItem shortcutItem : contributionItems) {
+				shortcutItem.setCheckState(state);
+			}
+
+			for (Object o : getChildren()) {
+				Category category = (Category) o;
+				category.setItemsState(state);
+			}
+		}
+	}
+
+	/**
+	 * Represents an action set, under which ContributionItems exist. There is
+	 * no inherent hierarchy in action sets - they exist independent of one
+	 * another, simply contribution menu items and tool bar items.
+	 *
+	 * @since 3.5
+	 */
+	class ActionSet {
+		/** The descriptor which describes the action set represented */
+		ActionSetDescriptor descriptor;
+
+		/** ContributionItems contributed by this action set */
+		private List<DisplayItem> contributionItems;
+
+		private boolean active;
+
+		private boolean wasChanged = false;
+
+		public ActionSet(ActionSetDescriptor descriptor, boolean active) {
+			this.descriptor = descriptor;
+			this.active = active;
+			this.contributionItems = new ArrayList<>();
+		}
+
+		public void addItem(DisplayItem item) {
+			contributionItems.add(item);
+		}
+
+		@Override
+		public String toString() {
+			return descriptor.getLabel();
+		}
+
+		public boolean isActive() {
+			return active;
+		}
+
+		public boolean wasChanged() {
+			return wasChanged;
+		}
+
+		public void setActive(boolean active) {
+			boolean wasActive = this.active;
+			this.active = active;
+			if (!active) {
+				for (DisplayItem item : contributionItems) {
+					item.setCheckState(false);
+				}
+			}
+			if (wasActive != active) {
+				actionSetAvailabilityChanged();
+			}
+
+			wasChanged = true;
+		}
+	}
+
+	/**
+	 * Create an instance of this Dialog.
+	 *
+	 * @param configurer
+	 *            the configurer
+	 * @param persp
+	 *            the perspective
+	 * @param context
+	 *            The runtime context for this window
+	 */
+	public CustomizePerspectiveDialog(IWorkbenchWindowConfigurer configurer, Perspective persp,
+			IEclipseContext context) {
+		super(configurer.getWindow().getShell());
+		this.treeManager = new TreeManager();
+		this.configurer = configurer;
+		this.context = context;
+		perspective = persp;
+		window = (WorkbenchWindow) configurer.getWindow();
+		windowPage = (WorkbenchPage) window.getActivePage();
+		menuMngrRenderer = context.get(MenuManagerRenderer.class);
+		toolbarMngrRenderer = context.get(ToolBarManagerRenderer.class);
+		resUtils = (ISWTResourceUtilities) context.get(IResourceUtilities.class);
+
+		initializeIcons();
+
+		initializeActionSetInput();
+		loadMenuAndToolbarStructure();
+	}
+
+	@Override
+	protected void configureShell(Shell shell) {
+		super.configureShell(shell);
+		String title = perspective.getDesc().getLabel();
+
+		title = NLS.bind(WorkbenchMessages.get().ActionSetSelection_customize, title);
+		shell.setText(title);
+		window.getWorkbench().getHelpSystem().setHelp(shell,
+				IWorkbenchHelpContextIds.ACTION_SET_SELECTION_DIALOG);
+	}
+
+	@Override
+	protected Control createDialogArea(Composite parent) {
+		Composite composite = (Composite) super.createDialogArea(parent);
+
+		// tab folder
+		tabFolder = new TabFolder(composite, SWT.NONE);
+
+		GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
+		gd.widthHint = convertHorizontalDLUsToPixels(TAB_WIDTH_IN_DLUS);
+		gd.heightHint = convertVerticalDLUsToPixels(TAB_HEIGHT_IN_DLUS);
+		tabFolder.setLayoutData(gd);
+
+		// Tool Bar Item Hiding Page
+		TabItem tab = new TabItem(tabFolder, SWT.NONE);
+		tab.setText(WorkbenchMessages.get().HideToolBarItems_toolBarItemsTab);
+		tab.setControl(createToolBarVisibilityPage(tabFolder));
+
+		// Menu Item Hiding Page
+		tab = new TabItem(tabFolder, SWT.NONE);
+		tab.setControl(createMenuVisibilityPage(tabFolder));
+		tab.setText(WorkbenchMessages.get().HideMenuItems_menuItemsTab);
+
+		// Action Set Availability Page
+		actionSetTab = new TabItem(tabFolder, SWT.NONE);
+		actionSetTab
+				.setText(WorkbenchMessages.get().ActionSetSelection_actionSetsTab);
+		actionSetTab.setControl(createActionSetAvailabilityPage(tabFolder));
+
+		// Shortcuts Page
+		if (showShortcutTab()) {
+			TabItem item1 = new TabItem(tabFolder, SWT.NONE);
+			item1.setText(WorkbenchMessages.get().Shortcuts_shortcutTab);
+			item1.setControl(createShortCutsPage(tabFolder));
+		}
+
+		applyDialogFont(tabFolder);
+
+		return composite;
+	}
+
+	private Composite createShortCutsPage(Composite parent) {
+		GridData data;
+
+		Composite menusComposite = new Composite(parent, SWT.NONE);
+		GridLayout layout = new GridLayout();
+		menusComposite.setLayout(layout);
+
+		// Select... label
+		Label label = new Label(menusComposite, SWT.WRAP);
+		label.setText(NLS.bind(
+				WorkbenchMessages.get().Shortcuts_selectShortcutsLabel, perspective
+						.getDesc().getLabel()));
+		data = new GridData(SWT.FILL, SWT.CENTER, true, false);
+		label.setLayoutData(data);
+
+		Label sep = new Label(menusComposite, SWT.HORIZONTAL | SWT.SEPARATOR);
+		sep.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+		SashForm sashComposite = new SashForm(menusComposite, SWT.HORIZONTAL);
+		data = new GridData(SWT.FILL, SWT.FILL, true, true);
+		sashComposite.setLayoutData(data);
+
+		// Menus List
+		Composite menusGroup = new Composite(sashComposite, SWT.NONE);
+		layout = new GridLayout();
+		layout.marginHeight = 0;
+		layout.marginWidth = 0;
+		menusGroup.setLayout(layout);
+		menusGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+		label = new Label(menusGroup, SWT.WRAP);
+		label.setText(WorkbenchMessages.get().Shortcuts_availableMenus);
+		label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+		Combo menusCombo = new Combo(menusGroup, SWT.READ_ONLY);
+		menusCombo
+				.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+		ComboViewer menusViewer = new ComboViewer(menusCombo);
+		menusViewer.setContentProvider(TreeManager.getTreeContentProvider());
+		menusViewer.setLabelProvider(TreeManager.getLabelProvider());
+
+		// Categories Tree
+		label = new Label(menusGroup, SWT.WRAP);
+		label.setText(WorkbenchMessages.get().Shortcuts_availableCategories);
+		label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+		final CheckboxTreeViewer menuCategoriesViewer = new CheckboxTreeViewer(
+				menusGroup);
+		menuCategoriesViewer.getControl().setLayoutData(
+				new GridData(SWT.FILL, SWT.FILL, true, true));
+		menuCategoriesViewer.setLabelProvider(TreeManager.getLabelProvider());
+		menuCategoriesViewer.setContentProvider(TreeManager
+				.getTreeContentProvider());
+		menuCategoriesViewer.setComparator(new WorkbenchViewerComparator());
+		menuCategoriesViewer.setCheckStateProvider(new CategoryCheckProvider());
+		menuCategoriesViewer.addCheckStateListener(event -> {
+			Category category = (Category) event.getElement();
+			category.setItemsState(event.getChecked());
+			updateCategoryAndParents(menuCategoriesViewer, category);
+		});
+
+		treeManager.addListener(changedItem -> {
+			if (changedItem instanceof Category) {
+				menuCategoriesViewer.update(changedItem, null);
+			} else if (changedItem instanceof ShortcutItem) {
+				ShortcutItem item = (ShortcutItem) changedItem;
+				if (item.getCategory() != null) {
+					item.getCategory().update();
+					updateCategoryAndParents(menuCategoriesViewer, item
+							.getCategory());
+				}
+			}
+		});
+
+		// Menu items list
+		Composite menuItemsGroup = new Composite(sashComposite, SWT.NONE);
+		layout = new GridLayout();
+		layout.marginHeight = 0;
+		layout.marginWidth = 0;
+		menuItemsGroup.setLayout(layout);
+		menuItemsGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
+				true));
+
+		label = new Label(menuItemsGroup, SWT.WRAP);
+		label.setText(WorkbenchMessages.get().Shortcuts_allShortcuts);
+		label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+		final CheckboxTableViewer menuItemsViewer = CheckboxTableViewer
+				.newCheckList(menuItemsGroup, SWT.BORDER | SWT.H_SCROLL
+						| SWT.V_SCROLL);
+		Table menuTable = menuItemsViewer.getTable();
+		menuTable.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+		menuItemsViewer.setLabelProvider(new ShortcutLabelProvider());
+		menuItemsViewer.setCheckStateProvider(TreeManager
+				.getCheckStateProvider());
+		menuItemsViewer.addCheckStateListener(treeManager
+				.getViewerCheckStateListener());
+		treeManager.getCheckListener(menuItemsViewer);
+
+		menuItemsViewer
+				.setContentProvider(new TreeManager.TreeItemContentProvider() {
+					@Override
+					public Object[] getChildren(Object parentElement) {
+						if (parentElement instanceof Category) {
+							return ((Category) parentElement)
+									.getContributionItems().toArray();
+						}
+						return super.getChildren(parentElement);
+					}
+				});
+		menuItemsViewer.setComparator(new WorkbenchViewerComparator());
+
+		// update menuCategoriesViewer, and menuItemsViewer on a change to
+		// menusViewer
+		menusViewer
+				.addSelectionChangedListener(event -> {
+					Category category = (Category) ((IStructuredSelection) event
+							.getSelection()).getFirstElement();
+					menuCategoriesViewer.setInput(category);
+					menuItemsViewer.setInput(category);
+					if (category.getChildrenCount() != 0) {
+						setSelectionOn(menuCategoriesViewer, category
+								.getChildren().get(0));
+					}
+				});
+
+		// update menuItemsViewer on a change to menuCategoriesViewer
+		menuCategoriesViewer
+				.addSelectionChangedListener(event -> {
+					Category category = (Category) ((IStructuredSelection) event
+							.getSelection()).getFirstElement();
+					menuItemsViewer.setInput(category);
+				});
+
+		menuTable.setHeaderVisible(true);
+		int[] columnWidths = new int[shortcutMenuColumnWidths.length];
+		for (int i = 0; i < shortcutMenuColumnWidths.length; i++) {
+			columnWidths[i] = convertHorizontalDLUsToPixels(shortcutMenuColumnWidths[i]);
+		}
+		for (int i = 0; i < shortcutMenuColumnHeaders.length; i++) {
+			TableColumn tc = new TableColumn(menuTable, SWT.NONE, i);
+			tc.setResizable(true);
+			tc.setText(shortcutMenuColumnHeaders[i]);
+			tc.setWidth(columnWidths[i]);
+		}
+		sashComposite.setWeights(new int[] { 30, 70 });
+
+		menusViewer.setInput(shortcuts);
+
+		if (shortcuts.getChildrenCount() > 0) {
+			setSelectionOn(menusViewer, shortcuts.getChildren().get(0));
+		}
+
+		return menusComposite;
+	}
+
+	private Composite createActionSetAvailabilityPage(Composite parent) {
+		GridData data;
+
+		Composite actionSetsComposite = new Composite(parent, SWT.NONE);
+		GridLayout layout = new GridLayout();
+		actionSetsComposite.setLayout(layout);
+
+		// Select... label
+		Label label = new Label(actionSetsComposite, SWT.WRAP);
+		label.setText(NLS.bind(
+				WorkbenchMessages.get().ActionSetSelection_selectActionSetsLabel,
+				perspective.getDesc().getLabel()));
+		data = new GridData(SWT.FILL, SWT.CENTER, true, false);
+		label.setLayoutData(data);
+
+		Label sep = new Label(actionSetsComposite, SWT.HORIZONTAL
+				| SWT.SEPARATOR);
+		sep.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+		SashForm sashComposite = new SashForm(actionSetsComposite,
+				SWT.HORIZONTAL);
+		data = new GridData(SWT.FILL, SWT.FILL, true, true);
+		sashComposite.setLayoutData(data);
+
+		// Action Set List Composite
+		Composite actionSetGroup = new Composite(sashComposite, SWT.NONE);
+		layout = new GridLayout();
+		layout.marginHeight = 0;
+		layout.marginWidth = 0;
+		actionSetGroup.setLayout(layout);
+		actionSetGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
+				true));
+
+		label = new Label(actionSetGroup, SWT.WRAP);
+		label.setText(WorkbenchMessages.get().ActionSetSelection_availableActionSets);
+		label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+		final CheckboxTableViewer actionSetsViewer = CheckboxTableViewer
+				.newCheckList(actionSetGroup, SWT.BORDER | SWT.H_SCROLL
+						| SWT.V_SCROLL);
+		actionSetAvailabilityTable = actionSetsViewer;
+		actionSetsViewer.getTable().setLayoutData(
+				new GridData(SWT.FILL, SWT.FILL, true, true));
+		actionSetsViewer.setContentProvider(new ArrayContentProvider());
+		actionSetsViewer.setComparator(new WorkbenchViewerComparator());
+		actionSetsViewer.setCheckStateProvider(new ICheckStateProvider() {
+			@Override
+			public boolean isChecked(Object element) {
+				return ((ActionSet) element).isActive();
+			}
+
+			@Override
+			public boolean isGrayed(Object element) {
+				return false;
+			}
+		});
+		actionSetsViewer.setInput(actionSets.toArray());
+
+		Table table = actionSetsViewer.getTable();
+		// RAP [bm] ToolTip
+//		new TableToolTip(table);
+
+		final ActionSet[] selectedActionSet = { null };
+
+		// Filter to show only branches necessary for the selected action set.
+		final ViewerFilter setFilter = new ViewerFilter() {
+			@Override
+			public boolean select(Viewer viewer, Object parentElement,
+					Object element) {
+				if (selectedActionSet[0] == null) {
+					return false;
+				}
+				return includeInSetStructure((DisplayItem) element,
+						selectedActionSet[0]);
+			}
+		};
+
+		// Updates the check state of action sets
+		actionSetsViewer.addCheckStateListener(event -> {
+			final ActionSet actionSet = (ActionSet) event.getElement();
+			if (event.getChecked()) {
+				actionSet.setActive(true);
+				for (DisplayItem item : actionSet.contributionItems) {
+					item.setCheckState(true);
+				}
+			} else {
+				actionSet.setActive(false);
+			}
+		});
+
+		// Menu and toolbar composite
+		Composite actionGroup = new Composite(sashComposite, SWT.NONE);
+		layout = new GridLayout();
+		layout.numColumns = 2;
+		layout.makeColumnsEqualWidth = true;
+		layout.marginHeight = 0;
+		layout.marginWidth = 0;
+		layout.horizontalSpacing = 0;
+		actionGroup.setLayout(layout);
+		actionGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+		Composite menubarGroup = new Composite(actionGroup, SWT.NONE);
+		layout = new GridLayout();
+		layout.marginHeight = 0;
+		layout.marginWidth = 0;
+		menubarGroup.setLayout(layout);
+		menubarGroup
+				.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+		label = new Label(menubarGroup, SWT.WRAP);
+		label.setText(WorkbenchMessages.get().ActionSetSelection_menubarActions);
+		label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+		actionSetMenuViewer = new TreeViewer(menubarGroup);
+		actionSetMenuViewer.setAutoExpandLevel(AbstractTreeViewer.ALL_LEVELS);
+		actionSetMenuViewer.getControl().setLayoutData(
+				new GridData(SWT.FILL, SWT.FILL, true, true));
+		actionSetMenuViewer.setUseHashlookup(true);
+		actionSetMenuViewer.setContentProvider(TreeManager
+				.getTreeContentProvider());
+		actionSetMenuViewer.setLabelProvider(new GrayOutUnavailableLabelProvider(null));
+		actionSetMenuViewer.addFilter(setFilter);
+		actionSetMenuViewer.setInput(menuItems);
+
+		Tree tree = actionSetMenuViewer.getTree();
+		// RAP [bm] ToolTip
+//		new ItemDetailToolTip(this, actionSetMenuViewer, tree, false, true, setFilter);
+
+		Composite toolbarGroup = new Composite(actionGroup, SWT.NONE);
+		layout = new GridLayout();
+		layout.marginHeight = 0;
+		layout.marginWidth = 0;
+		toolbarGroup.setLayout(layout);
+		toolbarGroup
+				.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+		label = new Label(toolbarGroup, SWT.WRAP);
+		label.setText(WorkbenchMessages.get().ActionSetSelection_toolbarActions);
+		label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+		actionSetToolbarViewer = new TreeViewer(toolbarGroup);
+		actionSetToolbarViewer
+				.setAutoExpandLevel(AbstractTreeViewer.ALL_LEVELS);
+		actionSetToolbarViewer.getControl().setLayoutData(
+				new GridData(SWT.FILL, SWT.FILL, true, true));
+		actionSetToolbarViewer.setContentProvider(TreeManager
+				.getTreeContentProvider());
+		actionSetToolbarViewer.setLabelProvider(new GrayOutUnavailableLabelProvider(null));
+		actionSetToolbarViewer.addFilter(setFilter);
+		actionSetToolbarViewer.setInput(toolBarItems);
+
+		tree = actionSetToolbarViewer.getTree();
+		// RAP [bm] ToolTip
+//		new ItemDetailToolTip(this, actionSetToolbarViewer, tree, false, true, setFilter);
+
+		// Updates the menu item and toolbar items tree viewers when the
+		// selection changes
+		actionSetsViewer
+				.addSelectionChangedListener(event -> {
+					selectedActionSet[0] = (ActionSet) ((IStructuredSelection) event
+							.getSelection()).getFirstElement();
+					actionSetMenuViewer.setInput(menuItems);
+					actionSetToolbarViewer.setInput(toolBarItems);
+				});
+
+		sashComposite.setWeights(new int[] { 30, 70 });
+
+		return actionSetsComposite;
+	}
+
+	/**
+	 * Creates the page used to allow users to choose menu items to hide.
+	 */
+	private Composite createMenuVisibilityPage(Composite parent) {
+		GridData data;
+
+		Composite hideMenuItemsComposite = new Composite(parent, SWT.NONE);
+		GridLayout layout = new GridLayout();
+		hideMenuItemsComposite.setLayout(layout);
+
+		// Label for entire tab
+		Label label = new Label(hideMenuItemsComposite, SWT.WRAP);
+		label.setText(WorkbenchMessages.get().HideMenuItems_chooseMenuItemsLabel);
+		data = new GridData(SWT.FILL, SWT.CENTER, true, false);
+		label.setLayoutData(data);
+
+		Label sep = new Label(hideMenuItemsComposite, SWT.HORIZONTAL
+				| SWT.SEPARATOR);
+		sep.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+		// Main contents of tab
+		final PageBook book = new PageBook(hideMenuItemsComposite, SWT.NONE);
+		data = new GridData(GridData.FILL_BOTH);
+		book.setLayoutData(data);
+
+		// Simple view: just the menu structure
+		final Composite simpleComposite = createItemStructureGroup(book,
+				WorkbenchMessages.get().HideMenuItems_menuStructure);
+		menuStructureViewer1 = initStructureViewer(simpleComposite,
+				new TreeManager.ViewerCheckStateListener(), null);
+
+		// Update the viewer when the model changes
+		treeManager.getCheckListener(menuStructureViewer1); // To update ctv on
+															// model changes
+
+		// Simply grab the checkstate out of the model
+		menuStructureViewer1.setCheckStateProvider(TreeManager
+				.getCheckStateProvider());
+
+		// Init with input
+		menuStructureViewer1.setInput(menuItems);
+
+		// Advanced view: action set with filtered menu structure
+		final SashForm advancedComposite = new SashForm(book, SWT.HORIZONTAL);
+		data = new GridData(SWT.FILL, SWT.FILL, true, true);
+		advancedComposite.setLayoutData(data);
+
+		// Action set list
+		final TableViewer actionSetViewer = initActionSetViewer(createActionSetGroup(advancedComposite));
+
+		// Filter to only show action sets which have useful menu items
+		actionSetViewer.addFilter(new ShowUsedActionSetsFilter(menuItems));
+
+		// Init with input
+		actionSetViewer.setInput(actionSets.toArray());
+
+		// Filter to only show items in the current action set
+		final ActionSetFilter menuStructureFilterByActionSet = new ActionSetFilter();
+
+		final Composite menuStructureComposite = createItemStructureGroup(
+				advancedComposite,
+				WorkbenchMessages.get().HideMenuItems_menuStructure);
+		final ICheckStateListener menuStructureFilter = new FilteredViewerCheckListener(
+				TreeManager.getTreeContentProvider(),
+				menuStructureFilterByActionSet);
+		menuStructureViewer2 = initStructureViewer(menuStructureComposite,
+				menuStructureFilter, menuStructureFilterByActionSet);
+
+		treeManager.addListener(new FilteredModelCheckListener(
+				menuStructureFilterByActionSet, menuStructureViewer2));
+
+		menuStructureViewer2.addFilter(menuStructureFilterByActionSet);
+
+		// Update filter when a new action set is selected
+		actionSetViewer
+				.addSelectionChangedListener(new ActionSetSelectionChangedListener(
+						menuStructureViewer2, menuStructureFilterByActionSet));
+
+		// Check state provider to emulate standard SWT
+		// behaviour on visual tree
+		menuStructureViewer2
+				.setCheckStateProvider(new FilteredTreeCheckProvider(
+						TreeManager.getTreeContentProvider(),
+						menuStructureFilterByActionSet));
+
+		// Init input
+		menuStructureViewer2.setInput(menuItems);
+
+		// Override any attempts to set an item to visible
+		// which exists in an unavailable action set
+		treeManager.addListener(changedItem -> {
+			if (!(changedItem instanceof DisplayItem)) {
+				return;
+			}
+			if (!changedItem.getState()) {
+				return;
+			}
+			if (isAvailable((DisplayItem) changedItem)) {
+				return;
+			}
+			changedItem.setCheckState(false);
+		});
+
+		final Button showCommandGroupFilterButton = new Button(
+				hideMenuItemsComposite, SWT.CHECK);
+		showCommandGroupFilterButton
+				.setText(WorkbenchMessages.get().HideItems_turnOnActionSets);
+		showCommandGroupFilterButton
+				.addSelectionListener(new SelectionListener() {
+					@Override
+					public void widgetDefaultSelected(SelectionEvent e) {
+					}
+
+					@Override
+					public void widgetSelected(SelectionEvent e) {
+						if (showCommandGroupFilterButton.getSelection()) {
+							Object o = ((StructuredSelection) menuStructureViewer1
+									.getSelection()).getFirstElement();
+							ActionSet initSelectAS = null;
+							DisplayItem initSelectCI = null;
+							if (o instanceof DisplayItem) {
+								initSelectCI = ((DisplayItem) o);
+								initSelectAS = initSelectCI.getActionSet();
+							}
+							if (initSelectAS == null) {
+								initSelectAS = (ActionSet) actionSetViewer
+										.getElementAt(0);
+							}
+							if (initSelectAS != null) {
+								setSelectionOn(actionSetViewer, initSelectAS);
+								actionSetViewer.reveal(initSelectAS);
+							}
+							if (initSelectCI != null) {
+								setSelectionOn(menuStructureViewer2,
+										initSelectCI);
+								menuStructureViewer2.reveal(initSelectCI);
+							}
+							book.showPage(advancedComposite);
+						} else {
+							book.showPage(simpleComposite);
+						}
+					}
+				});
+
+		book.showPage(simpleComposite);
+		advancedComposite.setWeights(new int[] { 30, 70 });
+
+		return hideMenuItemsComposite;
+	}
+
+	/**
+	 * Creates the page used to allow users to choose menu items to hide.
+	 */
+	private Composite createToolBarVisibilityPage(Composite parent) {
+		GridData data;
+
+		Composite hideToolbarItemsComposite = new Composite(parent, SWT.NONE);
+		GridLayout layout = new GridLayout();
+		hideToolbarItemsComposite.setLayout(layout);
+
+		// Label for entire tab
+		Label label = new Label(hideToolbarItemsComposite, SWT.WRAP);
+		label
+				.setText(WorkbenchMessages.get().HideToolBarItems_chooseToolBarItemsLabel);
+		data = new GridData(SWT.FILL, SWT.CENTER, true, false);
+		label.setLayoutData(data);
+
+		Label sep = new Label(hideToolbarItemsComposite, SWT.HORIZONTAL
+				| SWT.SEPARATOR);
+		sep.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+		// Main contents of tab
+		final PageBook book = new PageBook(hideToolbarItemsComposite, SWT.NONE);
+		data = new GridData(GridData.FILL_BOTH);
+		book.setLayoutData(data);
+
+		// Simple view: just the toolbar structure
+		final Composite simpleComposite = createItemStructureGroup(book,
+				WorkbenchMessages.get().HideToolBarItems_toolBarStructure);
+		toolbarStructureViewer1 = initStructureViewer(simpleComposite,
+				new TreeManager.ViewerCheckStateListener(), null);
+
+		// Update the viewer when the model changes
+		treeManager.getCheckListener(toolbarStructureViewer1); // To update ctv
+																// on model
+																// changes
+
+		// Simply grab the check state out of the model
+		toolbarStructureViewer1.setCheckStateProvider(TreeManager
+				.getCheckStateProvider());
+
+		// Init with input
+		toolbarStructureViewer1.setInput(toolBarItems);
+
+		// Advanced view: action set with filtered toolbar structure
+		final SashForm advancedComposite = new SashForm(book, SWT.HORIZONTAL);
+		data = new GridData(SWT.FILL, SWT.FILL, true, true);
+		advancedComposite.setLayoutData(data);
+
+		// Action set list
+		final TableViewer actionSetViewer = initActionSetViewer(createActionSetGroup(advancedComposite));
+
+		// Filter to only show action sets which have useful toolbar items
+		actionSetViewer.addFilter(new ShowUsedActionSetsFilter(toolBarItems));
+
+		// Init with input
+		actionSetViewer.setInput(actionSets.toArray());
+
+		// Filter to only show items in the current action set
+		final ActionSetFilter toolbarStructureFilterByActionSet = new ActionSetFilter();
+
+		final Composite toolbarStructureComposite = createItemStructureGroup(
+				advancedComposite,
+				WorkbenchMessages.get().HideToolBarItems_toolBarStructure);
+		final ICheckStateListener toolbarStructureFilter = new FilteredViewerCheckListener(
+				TreeManager.getTreeContentProvider(),
+				toolbarStructureFilterByActionSet);
+		toolbarStructureViewer2 = initStructureViewer(
+				toolbarStructureComposite, toolbarStructureFilter,
+				toolbarStructureFilterByActionSet);
+
+		toolbarStructureViewer2.addFilter(toolbarStructureFilterByActionSet);
+
+		treeManager.addListener(new FilteredModelCheckListener(
+				toolbarStructureFilterByActionSet, toolbarStructureViewer2));
+
+		// Update filter when a new action set is selected
+		actionSetViewer
+				.addSelectionChangedListener(new ActionSetSelectionChangedListener(
+						toolbarStructureViewer2,
+						toolbarStructureFilterByActionSet));
+
+		// Check state provider to emulate standard SWT
+		// behaviour on visual tree
+		toolbarStructureViewer2
+				.setCheckStateProvider(new FilteredTreeCheckProvider(
+						TreeManager.getTreeContentProvider(),
+						toolbarStructureFilterByActionSet));
+
+		// Init input
+		toolbarStructureViewer2.setInput(toolBarItems);
+
+		// Override any attempts to set an item to visible
+		// which exists in an unavailable action set
+		treeManager.addListener(changedItem -> {
+			if (!(changedItem instanceof DisplayItem)) {
+				return;
+			}
+			if (!changedItem.getState()) {
+				return;
+			}
+			if (isAvailable((DisplayItem) changedItem)) {
+				return;
+			}
+			changedItem.setCheckState(false);
+		});
+
+		final Button showCommandGroupFilterButton = new Button(
+				hideToolbarItemsComposite, SWT.CHECK);
+		showCommandGroupFilterButton
+				.setText(WorkbenchMessages.get().HideItems_turnOnActionSets);
+		showCommandGroupFilterButton
+				.addSelectionListener(new SelectionListener() {
+					@Override
+					public void widgetDefaultSelected(SelectionEvent e) {
+					}
+
+					@Override
+					public void widgetSelected(SelectionEvent e) {
+						if (showCommandGroupFilterButton.getSelection()) {
+							Object o = ((StructuredSelection) toolbarStructureViewer1
+									.getSelection()).getFirstElement();
+							ActionSet initSelectAS = null;
+							DisplayItem initSelectCI = null;
+							if (o instanceof DisplayItem) {
+								initSelectCI = ((DisplayItem) o);
+								initSelectAS = initSelectCI.getActionSet();
+							}
+							if (initSelectAS == null) {
+								initSelectAS = (ActionSet) actionSetViewer
+										.getElementAt(0);
+							}
+							if (initSelectAS != null) {
+								setSelectionOn(actionSetViewer, initSelectAS);
+								actionSetViewer.reveal(initSelectAS);
+							}
+							if (initSelectCI != null) {
+								setSelectionOn(toolbarStructureViewer2,
+										initSelectCI);
+								toolbarStructureViewer2.reveal(initSelectCI);
+							}
+							book.showPage(advancedComposite);
+						} else {
+							book.showPage(simpleComposite);
+						}
+					}
+				});
+
+		book.showPage(simpleComposite);
+		advancedComposite.setWeights(new int[] { 30, 70 });
+
+		return hideToolbarItemsComposite;
+	}
+
+	/**
+	 * Creates a table to display action sets.
+	 *
+	 * @param parent
+	 * @return a viewer to display action sets
+	 */
+	private static TableViewer initActionSetViewer(Composite parent) {
+		// List of categories
+		final TableViewer actionSetViewer = new TableViewer(parent, SWT.BORDER
+				| SWT.H_SCROLL | SWT.V_SCROLL);
+		actionSetViewer.getTable().setLayoutData(
+				new GridData(GridData.FILL_BOTH));
+		actionSetViewer.setLabelProvider(new GrayOutUnavailableLabelProvider(null));
+		actionSetViewer.setComparator(new WorkbenchViewerComparator());
+		actionSetViewer.setContentProvider(new ArrayContentProvider());
+
+		// Tooltip on tree items
+		Table table = actionSetViewer.getTable();
+		// RAP [bm] ToolTip
+//		new TableToolTip(table);
+		return actionSetViewer;
+	}
+
+	/**
+	 * Creates a CheckboxTreeViewer to display menu or toolbar structure.
+	 *
+	 * @param parent
+	 * @param checkStateListener
+	 *            the listener which listens to the viewer for check changes
+	 * @param filter
+	 *            the filter used in the viewer (null for none)
+	 * @return A viewer within <code>parent</code> which will show menu or
+	 *         toolbar structure. It comes setup, only missing a
+	 *         CheckStateProvider and its input.
+	 */
+	private CheckboxTreeViewer initStructureViewer(Composite parent,
+			ICheckStateListener checkStateListener, ViewerFilter filter) {
+		CheckboxTreeViewer ctv = new CheckboxTreeViewer(parent, SWT.BORDER
+				| SWT.H_SCROLL | SWT.V_SCROLL);
+		ctv.getControl().setLayoutData(new GridData(GridData.FILL_BOTH));
+		ctv.setUseHashlookup(true);
+		ctv.setContentProvider(TreeManager.getTreeContentProvider());
+		// use an UnavailableContributionItemCheckListener to filter check
+		// events: if it is legal, forward it to the actual checkStateListener,
+		// if not, inform the user
+		ctv.addCheckStateListener(new UnavailableContributionItemCheckListener(
+				this, ctv, checkStateListener));
+		ctv.setLabelProvider(new GrayOutUnavailableLabelProvider(filter));
+		// RAP [bm] ToolTip
+//		new ItemDetailToolTip(this, ctv, ctv.getTree(), true, true, filter);
+		return ctv;
+	}
+
+	/**
+	 * Creates a composite to put a tree viewer in to display menu or toolbar
+	 * items.
+	 */
+	private static Composite createItemStructureGroup(
+			final Composite composite, String labelText) {
+		GridLayout layout;
+		Label label;
+		layout = new GridLayout();
+		Composite menubarGroup = new Composite(composite, SWT.NONE);
+		layout.marginHeight = 0;
+		layout.marginWidth = 0;
+		menubarGroup.setLayout(layout);
+		menubarGroup
+				.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+		label = new Label(menubarGroup, SWT.WRAP);
+		label.setText(labelText);
+		label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+		return menubarGroup;
+	}
+
+	/**
+	 * Creates a composite to put a viewer in to display action sets.
+	 */
+	private static Composite createActionSetGroup(final Composite composite) {
+		GridLayout layout;
+		Label label;
+		Composite actionSetGroup = new Composite(composite, SWT.NONE);
+		layout = new GridLayout();
+		layout.marginHeight = 0;
+		layout.marginWidth = 0;
+		actionSetGroup.setLayout(layout);
+		actionSetGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
+				true));
+
+		label = new Label(actionSetGroup, SWT.WRAP);
+		label.setText(WorkbenchMessages.get().HideItems_commandGroupTitle);
+		label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+		return actionSetGroup;
+	}
+
+	/**
+	 * Set the selection on a structured viewer.
+	 *
+	 * @param viewer
+	 * @param selected
+	 */
+	private static void setSelectionOn(Viewer viewer, final Object selected) {
+		ISelection selection;
+		if (selected == null) {
+			selection = StructuredSelection.EMPTY;
+		} else {
+			selection = new StructuredSelection(selected);
+		}
+		boolean reveal = selection != StructuredSelection.EMPTY;
+		viewer.setSelection(selection, reveal);
+	}
+
+	/**
+	 * Searches deeply to see if <code>item</code> is a node in a branch
+	 * containing a ContributionItem contributed by <code>set</code>.
+	 *
+	 * @param item
+	 *            the item in question
+	 * @param set
+	 *            the action set to look for
+	 * @return true iff <code>item</code> is required in build a tree including
+	 *         elements in <code>set</code>
+	 */
+	static boolean includeInSetStructure(DisplayItem item, ActionSet set) {
+		if (item.actionSet != null && item.actionSet.equals(set)) {
+			return true;
+		}
+		for (TreeItem treeItem : item.getChildren()) {
+			DisplayItem child = (DisplayItem) treeItem;
+			if (includeInSetStructure(child, set)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * @param item
+	 * @return true iff the item is available - i.e. if it belongs to an action
+	 *         set, that that action set is available, or has a child which is
+	 *         available thus must be displayed in order to display the child
+	 */
+	static boolean isAvailable(DisplayItem item) {
+		if (item.getActionSet() != null && item.getChildren().isEmpty()) {
+			return item.getActionSet().isActive();
+		}
+		for (TreeItem treeItem : item.getChildren()) {
+			DisplayItem child = (DisplayItem) treeItem;
+			if (isAvailable(child)) {
+				return true;
+			}
+		}
+		return item.getIContributionItem() != null && item.getIContributionItem().isVisible();
+	}
+
+	/**
+	 * @param item
+	 * @return true iff the item will show up in a menu or tool bar structure -
+	 *         i.e. it is available, or has a child which is available thus must
+	 *         be displayed in order to display the child
+	 */
+	static boolean isEffectivelyAvailable(DisplayItem item, ViewerFilter filter) {
+		if (!isAvailable(item)) {
+			return false;
+		}
+		final List<TreeItem> children = item.getChildren();
+		if (children.isEmpty()) {
+			return true;
+		}
+		for (TreeItem treeItem : children) {
+			DisplayItem child = (DisplayItem) treeItem;
+			if(filter != null && !filter.select(null, null, child)) {
+				continue;
+			}
+			if (isAvailable(child)) {
+				return true;
+			}
+		}
+		for (TreeItem treeItem : children) {
+			DisplayItem child = (DisplayItem) treeItem;
+			if(filter != null && !filter.select(null, null, child)) {
+				continue;
+			}
+			if (isEffectivelyAvailable(child, filter)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * On a change to availability, updates the appropriate widgets.
+	 */
+	private void actionSetAvailabilityChanged() {
+		actionSetAvailabilityTable.refresh();
+		actionSetMenuViewer.refresh();
+		actionSetToolbarViewer.refresh();
+
+		menuStructureViewer1.refresh();
+		menuStructureViewer2.refresh();
+		toolbarStructureViewer1.refresh();
+		toolbarStructureViewer2.refresh();
+	}
+
+	private void initializeActionSetInput() {
+		// Just get the action sets at this point. Do not load the action set
+		// until it is actually selected in the dialog.
+		ActionSetRegistry reg = WorkbenchPlugin.getDefault()
+				.getActionSetRegistry();
+		IActionSetDescriptor[] sets = reg.getActionSets();
+		IActionSetDescriptor[] actionSetDescriptors = ((WorkbenchPage) window
+				.getActivePage()).getActionSets();
+		List<IActionSetDescriptor> initiallyAvailableActionSets = Arrays.asList(actionSetDescriptors);
+
+		for (IActionSetDescriptor set : sets) {
+			ActionSetDescriptor actionSetDesc = (ActionSetDescriptor) set;
+			if (WorkbenchActivityHelper.filterItem(actionSetDesc)) {
+				continue;
+			}
+			ActionSet actionSet = new ActionSet(actionSetDesc,
+					initiallyAvailableActionSets.contains(actionSetDesc));
+			idToActionSet.put(actionSetDesc.getId(), actionSet);
+			actionSets.add(actionSet);
+		}
+	}
+
+	private String getToolbarLabel(MUIElement elt) {
+		MApplication app = context.get(MApplication.class);
+		String toolbarLabel = CoolBarToTrimManager.getToolbarLabel(app, elt);
+		if (toolbarLabel != null) {
+			return toolbarLabel;
+		}
+		String elementId = elt.getElementId();
+		ActionSetRegistry registry = WorkbenchPlugin.getDefault().getActionSetRegistry();
+		IActionSetDescriptor findActionSet = registry.findActionSet(elementId);
+		if (findActionSet != null) {
+			return findActionSet.getLabel();
+		}
+		// Nothing is available. Let's smartly guess the name then.
+		String[] nameParts = elementId.split("\\."); //$NON-NLS-1$
+		return nameParts[nameParts.length - 1];
+	}
+
+	private void initializeIcons() {
+		String iconPath = MENU_ICON;
+		URL url = BundleUtility.find(PlatformUI.PLUGIN_ID, iconPath);
+		menuImageDescriptor = ImageDescriptor.createFromURL(url);
+
+		iconPath = SUBMENU_ICON;
+		url = BundleUtility.find(PlatformUI.PLUGIN_ID, iconPath);
+		submenuImageDescriptor = ImageDescriptor.createFromURL(url);
+
+		iconPath = TOOLBAR_ICON;
+		url = BundleUtility.find(PlatformUI.PLUGIN_ID, iconPath);
+		toolbarImageDescriptor = ImageDescriptor.createFromURL(url);
+
+		iconPath = WARNING_ICON;
+		url = BundleUtility.find(PlatformUI.PLUGIN_ID, iconPath);
+		warningImageDescriptor = ImageDescriptor.createFromURL(url);
+	}
+
+	private void initializeNewWizardsMenu(DisplayItem menu,
+			Category parentCategory, IWizardCategory element, List<String> activeIds) {
+		Category category = new Category(element.getLabel());
+		parentCategory.addChild(category);
+
+		Object[] wizards = element.getWizards();
+		for (Object wizard2 : wizards) {
+			WorkbenchWizardElement wizard = (WorkbenchWizardElement) wizard2;
+
+			ShortcutItem item = new ShortcutItem(wizard.getLabel(), wizard);
+			item.setLabel(wizard.getLabel());
+			item.setDescription(wizard.getDescription());
+			if (wizard.getImageDescriptor() != null) {
+				item.setImageDescriptor(wizard.getImageDescriptor());
+			}
+			item.setCheckState(activeIds.contains(wizard.getId()));
+			menu.addChild(item);
+			category.addShortcutItem(item);
+		}
+		// @issue should not pass in null
+		for (IWizardCategory child : element.getCategories()) {
+			initializeNewWizardsMenu(menu, category, child, activeIds);
+		}
+	}
+
+	private void initializeNewWizardsMenu(DisplayItem menu) {
+		Category rootForNewWizards = new Category(
+				WorkbenchMessages.get().ActionSetDialogInput_wizardCategory);
+		shortcuts.addChild(rootForNewWizards);
+
+		IWizardCategory wizardCollection = WorkbenchPlugin.getDefault()
+				.getNewWizardRegistry().getRootCategory();
+		IWizardCategory[] wizardCategories = wizardCollection.getCategories();
+		List<String> activeIDs = Arrays.asList(perspective.getNewWizardShortcuts());
+
+		for (IWizardCategory element : wizardCategories) {
+			if (WorkbenchActivityHelper.filterItem(element)) {
+				continue;
+			}
+			initializeNewWizardsMenu(menu, rootForNewWizards, element,
+					activeIDs);
+		}
+	}
+
+	private void initializePerspectivesMenu(DisplayItem menu) {
+		Category rootForPerspectives = new Category(
+				WorkbenchMessages.get().ActionSetDialogInput_perspectiveCategory);
+		shortcuts.addChild(rootForPerspectives);
+
+		IPerspectiveRegistry perspReg = WorkbenchPlugin.getDefault()
+				.getPerspectiveRegistry();
+		IPerspectiveDescriptor[] persps = perspReg.getPerspectives();
+
+		List<String> activeIds = Arrays.asList(perspective.getPerspectiveShortcuts());
+
+		for (IPerspectiveDescriptor perspective : persps) {
+			if (WorkbenchActivityHelper.filterItem(perspective)) {
+				continue;
+			}
+
+			ShortcutItem child = new ShortcutItem(perspective.getLabel(),
+					perspective);
+			child.setImageDescriptor(perspective.getImageDescriptor());
+			child.setDescription(perspective.getDescription());
+			child.setCheckState(activeIds.contains(perspective.getId()));
+			menu.addChild(child);
+
+			rootForPerspectives.addShortcutItem(child);
+		}
+	}
+
+	private void initializeViewsMenu(DisplayItem menu) {
+		Category rootForViews = new Category(
+				WorkbenchMessages.get().ActionSetDialogInput_viewCategory);
+
+		shortcuts.addChild(rootForViews);
+
+		IViewRegistry viewReg = WorkbenchPlugin.getDefault().getViewRegistry();
+		IViewCategory[] categories = viewReg.getCategories();
+
+		List<String> activeIds = Arrays.asList(perspective.getShowViewShortcuts());
+
+		for (IViewCategory category : categories) {
+			if (WorkbenchActivityHelper.filterItem(category)) {
+				continue;
+			}
+
+			Category viewCategory = new Category(category.getLabel());
+			rootForViews.addChild(viewCategory);
+
+			IViewDescriptor[] views = category.getViews();
+
+			if (views != null) {
+				for (IViewDescriptor view : views) {
+					if (view.getId().equals(IIntroConstants.INTRO_VIEW_ID)) {
+						continue;
+					}
+					if (WorkbenchActivityHelper.filterItem(view)) {
+						continue;
+					}
+
+					ShortcutItem child = new ShortcutItem(view.getLabel(), view);
+					child.setImageDescriptor(view.getImageDescriptor());
+					child.setDescription(view.getDescription());
+					child.setCheckState(activeIds.contains(view.getId()));
+					menu.addChild(child);
+					viewCategory.addShortcutItem(child);
+				}
+			}
+		}
+	}
+
+	/**
+	 * Loads the current perspective's menu structure and also loads which menu
+	 * items are visible and not.
+	 */
+	private void loadMenuAndToolbarStructure() {
+		customizeActionBars = new CustomizeActionBars(configurer, context);
+
+		// Fill fake action bars with static menu information.
+		window.fillActionBars(customizeActionBars, ActionBarAdvisor.FILL_PROXY
+				| ActionBarAdvisor.FILL_MENU_BAR
+				| ActionBarAdvisor.FILL_COOL_BAR);
+
+		window.fill(customizeActionBars.menuRenderer,
+				 customizeActionBars.mainMenu, customizeActionBars.menuManager);
+
+		// Populate the action bars with the action sets' data
+		for (ActionSet actionSet : actionSets) {
+			ActionSetDescriptor descriptor = actionSet.descriptor;
+			PluginActionSet pluginActionSet = buildMenusAndToolbarsFor(
+					customizeActionBars, descriptor);
+
+			if (pluginActionSet != null) {
+				pluginActionSet.dispose();
+			}
+		}
+
+		// Add actionSet MenuManagers to menu
+		MenuManager menuManager = customizeActionBars.menuManager;
+		IContributionItem[] items = menuManager.getItems();
+		for (IContributionItem item : items) {
+			if (item instanceof ActionSetContributionItem) {
+				ActionSetContributionItem asci = (ActionSetContributionItem) item;
+				menuManager.add(asci.getInnerItem());
+			}
+		}
+
+		// Make all menu items visible so they are included in the list.
+		customizeActionBars.menuManager.setVisible(true);
+
+		makeAllContributionsVisible(customizeActionBars.menuManager);
+
+		customizeActionBars.menuRenderer.reconcileManagerToModel(customizeActionBars.menuManager,
+				customizeActionBars.mainMenu);
+
+		IPresentationEngine engine = context.get(IPresentationEngine.class);
+		engine.createGui(customizeActionBars.mainMenu, customizeActionBars.windowModel.getWidget(),
+				customizeActionBars.windowModel.getContext());
+
+		MTrimBar topTrim = customizeActionBars.coolBarManager.getTopTrim();
+		topTrim.setToBeRendered(true);
+
+		// Get the menu from the action bars
+		engine.createGui(topTrim, customizeActionBars.windowModel.getWidget(),
+				customizeActionBars.windowModel.getContext());
+
+		// Ensure the menu is completely built by updating the menu manager.
+		// (This method call requires a menu already be created)
+		customizeActionBars.menuManager.updateAll(true);
+		customizeActionBars.coolBarManager.update(true);
+
+		shortcuts = new Category(""); //$NON-NLS-1$
+		toolBarItems = createTrimBarEntries(topTrim);
+		menuItems = createMenuStructure(customizeActionBars.mainMenu);
+	}
+
+	private PluginActionSet buildMenusAndToolbarsFor(
+			CustomizeActionBars customizeActionBars,
+			ActionSetDescriptor actionSetDesc) {
+		String id = actionSetDesc.getId();
+		ActionSetActionBars bars = new ActionSetActionBars(customizeActionBars,
+				window, customizeActionBars, id);
+		bars.getMenuManager().setVisible(true);
+		PluginActionSetBuilder builder = new PluginActionSetBuilder();
+		PluginActionSet actionSet = null;
+		try {
+			actionSet = (PluginActionSet) actionSetDesc.createActionSet();
+			actionSet.init(null, bars);
+		} catch (CoreException ex) {
+			WorkbenchPlugin.log(
+					"Unable to create action set " + actionSetDesc.getId(), ex); //$NON-NLS-1$
+			return null;
+		}
+		builder.buildMenuAndToolBarStructure(actionSet, window);
+		return actionSet;
+	}
+
+	/**
+	 * @return can return null
+	 */
+	static String getCommandID(DisplayItem item) {
+		Object object = item.getIContributionItem();
+
+		if (item instanceof ShortcutItem && isShowView(item)) {
+			return IWorkbenchCommandConstants.VIEWS_SHOW_VIEW;
+		}
+
+		return getIDFromIContributionItem(object);
+	}
+
+	/**
+	 * Given an object, tries to find an id which will uniquely identify it.
+	 *
+	 * @param object
+	 *            an instance of {@link IContributionItem},
+	 *            {@link IPerspectiveDescriptor}, {@link IViewDescriptor} or
+	 *            {@link WorkbenchWizardElement}.
+	 * @return an id, can return null
+	 * @throws IllegalArgumentException
+	 *             if object is not one of the listed types
+	 */
+	public static String getIDFromIContributionItem(Object object) {
+		if (object instanceof ActionContributionItem) {
+			ActionContributionItem item = (ActionContributionItem) object;
+			IAction action = item.getAction();
+			if (action == null) {
+				return null;
+			}
+			if (action instanceof NewWizardShortcutAction) {
+				return IWorkbenchCommandConstants.FILE_NEW;
+			}
+			if (action instanceof OpenPerspectiveAction) {
+				return IWorkbenchCommandConstants.PERSPECTIVES_SHOW_PERSPECTIVE;
+			}
+			String id = action.getActionDefinitionId();
+			if (id != null) {
+				return id;
+			}
+			return action.getId();
+		}
+		if (object instanceof ActionSetContributionItem) {
+			ActionSetContributionItem item = (ActionSetContributionItem) object;
+			IContributionItem subitem = item.getInnerItem();
+			return getIDFromIContributionItem(subitem);
+		}
+		if (object instanceof CommandContributionItem) {
+			CommandContributionItem item = (CommandContributionItem) object;
+			ParameterizedCommand command = item.getCommand();
+			if (command == null) {
+				return null;
+			}
+			return command.getId();
+		}
+		if (object instanceof IPerspectiveDescriptor) {
+			return ((IPerspectiveDescriptor) object).getId();
+		}
+		if (object instanceof IViewDescriptor) {
+			return ((IViewDescriptor) object).getId();
+		}
+		if (object instanceof WorkbenchWizardElement) {
+			return ((WorkbenchWizardElement) object).getLocalId();
+		}
+		if (object instanceof IContributionItem) {
+			String id = ((IContributionItem) object).getId();
+			if (id != null) {
+				return id;
+			}
+			return object.getClass().getName();
+		}
+		return null;	//couldn't determine the id
+	}
+
+	static String getParamID(DisplayItem object) {
+		if (object instanceof ShortcutItem) {
+			ShortcutItem shortcutItem = (ShortcutItem) object;
+
+			if (isNewWizard(shortcutItem)) {
+				ActionContributionItem item = (ActionContributionItem) object
+						.getIContributionItem();
+				NewWizardShortcutAction nwsa = (NewWizardShortcutAction) item
+						.getAction();
+				return nwsa.getLocalId();
+			}
+
+			if (isShowPerspective(shortcutItem)) {
+				ActionContributionItem item = (ActionContributionItem) object
+						.getIContributionItem();
+				OpenPerspectiveAction opa = (OpenPerspectiveAction) item
+						.getAction();
+				return opa.getLocalId();
+			}
+
+			if (isShowView(shortcutItem)) {
+				IViewDescriptor descriptor = (IViewDescriptor) shortcutItem
+						.getDescriptor();
+				return descriptor.getId();
+			}
+		}
+
+		return null;
+	}
+
+	static boolean isNewWizard(DisplayItem item) {
+		if (!(item instanceof ShortcutItem)) {
+			return false;
+		}
+		return ((ShortcutItem) item).getDescriptor() instanceof IWizardDescriptor;
+	}
+
+	static boolean isShowPerspective(DisplayItem item) {
+		if (!(item instanceof ShortcutItem)) {
+			return false;
+		}
+		return ((ShortcutItem) item).getDescriptor() instanceof IPerspectiveDescriptor;
+	}
+
+	static boolean isShowView(DisplayItem item) {
+		if (!(item instanceof ShortcutItem)) {
+			return false;
+		}
+		return ((ShortcutItem) item).getDescriptor() instanceof IViewDescriptor;
+	}
+
+	private static String getActionSetID(IContributionItem item) {
+		if (item instanceof ActionSetContributionItem) {
+			return ((ActionSetContributionItem) item).getActionSetId();
+		}
+		if (item instanceof PluginActionCoolBarContributionItem) {
+			return ((PluginActionCoolBarContributionItem) item).getActionSetId();
+		}
+		if (item instanceof ContributionItem) {
+			IContributionManager parent = ((ContributionItem) item).getParent();
+			if (parent instanceof ActionSetMenuManager) {
+				return ((ActionSetMenuManager) parent).getActionSetId();
+			}
+			if (item instanceof ToolBarContributionItem2) {
+				return item.getId();
+			}
+		}
+		return null;
+	}
+
+	private static String getActionSetID(MUIElement item) {
+		String id = (String) item.getTransientData().get("ActionSet"); //$NON-NLS-1$
+		if (id != null) {
+			return id;
+		}
+		Object data = OpaqueElementUtil.getOpaqueItem(item);
+		if (data == null) {
+			data = item.getTransientData().get(CoolBarToTrimManager.OBJECT);
+		}
+		if (data instanceof IContributionItem) {
+			return getActionSetID((IContributionItem) data);
+		}
+		return null;
+	}
+
+	/**
+	 * Causes all items under the manager to be visible, so they can be read.
+	 *
+	 * @param manager
+	 */
+	private static void makeAllContributionsVisible(IContributionManager manager) {
+		IContributionItem[] items = manager.getItems();
+
+		for (IContributionItem item : items) {
+			makeContributionVisible(item);
+		}
+	}
+
+	/**
+	 * Makes all items under the item to be visible, so they can be read.
+	 *
+	 * @param item
+	 */
+	private static void makeContributionVisible(IContributionItem item) {
+		item.setVisible(true);
+
+		if (item instanceof IContributionManager) {
+			makeAllContributionsVisible((IContributionManager) item);
+		}
+		if (item instanceof SubContributionItem) {
+			makeContributionVisible(((SubContributionItem) item).getInnerItem());
+		}
+	}
+
+	private DisplayItem createMenuStructure(MMenu menu) {
+		DisplayItem root = new DisplayItem("", null); //$NON-NLS-1$
+		createMenuEntries(menu, root);
+		return root;
+	}
+
+	private void createMenuEntries(MMenu menu, DisplayItem parent) {
+		Map<IContributionItem, IContributionItem> findDynamics = new HashMap<>();
+		DynamicContributionItem dynamicEntry = null;
+
+		if (menu.getParent() != null) {
+			// Search for any dynamic menu entries which will be handled later
+			Object data = menuMngrRenderer.getManager(menu);
+			if (data instanceof IContributionManager) {
+				IContributionManager manager = (IContributionManager) data;
+				IContributionItem[] items = manager.getItems();
+				for (int i = 0; i < items.length; i++) {
+					IContributionItem ci = items[i];
+					if (ci.isDynamic()) {
+						findDynamics.put(i > 0 ? items[i - 1] : null, ci);
+					}
+				}
+				// If there is an item with no preceding item, set it up to be
+				// added first.
+				if (findDynamics.containsKey(null)) {
+					IContributionItem item = findDynamics.get(null);
+					dynamicEntry = new DynamicContributionItem(item);
+					dynamicEntry.setCheckState(getMenuItemIsVisible(dynamicEntry));
+					dynamicEntry.setActionSet(idToActionSet.get(getActionSetID(item)));
+					parent.addChild(dynamicEntry);
+				}
+			}
+		}
+
+		for (MMenuElement menuItem : menu.getChildren()) {
+			dynamicEntry = createMenuEntry(parent, findDynamics, dynamicEntry, menuItem);
+		}
+	}
+
+	private DynamicContributionItem createMenuEntry(DisplayItem parent,
+			Map<IContributionItem, IContributionItem> findDynamics, DynamicContributionItem dynamicEntry,
+			MMenuElement menuItem) {
+		String text = menuItem.getLocalizedLabel();
+		if (text == null || text.length() == 0) {
+			text = menuItem.getLabel();
+		}
+		if ((text != null && text.length() != 0)
+				|| (menuItem instanceof MHandledMenuItem) || menuItem.getWidget() != null) {
+			IContributionItem contributionItem;
+			if (menuItem instanceof MMenu) {
+				contributionItem = menuMngrRenderer.getManager((MMenu) menuItem);
+			} else {
+				contributionItem = menuMngrRenderer.getContribution(menuItem);
+			}
+			if (contributionItem == null) {
+				return dynamicEntry;
+			}
+			if (dynamicEntry != null
+					&& contributionItem.equals(dynamicEntry.getIContributionItem())) {
+				// If the last item added is the item meant to go before the
+				// given dynamic entry, add the dynamic entry so it is in
+				// the correct order.
+				dynamicEntry.addCurrentItem((MenuItem) menuItem.getWidget());
+				// TODO: might not work
+			} else {
+				ImageDescriptor iconDescriptor = null;
+				String iconURI = menuItem.getIconURI();
+				if (iconURI != null && iconURI.length() > 0) {
+					iconDescriptor = resUtils.imageDescriptorFromURI(URI.createURI(iconURI));
+				}
+
+				if (menuItem.getWidget() instanceof MenuItem) {
+					MenuItem item = (MenuItem) menuItem.getWidget();
+					if (text == null) {
+						if ("".equals(item.getText())) { //$NON-NLS-1$
+							return dynamicEntry;
+						}
+						text = item.getText();
+					}
+					if (iconDescriptor == null) {
+						Image image = item.getImage();
+						if (image != null) {
+							iconDescriptor = ImageDescriptor.createFromImage(image);
+						}
+					}
+				} else if (menuItem instanceof MHandledMenuItem) {
+					MHandledMenuItem hmi = (MHandledMenuItem) menuItem;
+					final String i18nLabel = hmi.getLocalizedLabel();
+					if (i18nLabel != null) {
+						text = i18nLabel;
+					} else if (hmi.getWbCommand() != null) {
+						try {
+							text = hmi.getWbCommand().getName();
+						} catch (NotDefinedException e) {
+							// we'll just ignore a failure
+						}
+					}
+				}
+				DisplayItem menuEntry = new DisplayItem(text, contributionItem);
+
+				if (iconDescriptor != null) {
+					menuEntry.setImageDescriptor(iconDescriptor);
+				}
+				menuEntry.setActionSet(idToActionSet.get(getActionSetID(menuItem)));
+				parent.addChild(menuEntry);
+
+				if (ActionFactory.NEW.getId().equals(contributionItem.getId())) {
+					initializeNewWizardsMenu(menuEntry);
+					wizards = menuEntry;
+				} else if (SHORTCUT_CONTRIBUTION_ITEM_ID_OPEN_PERSPECTIVE
+						.equals(contributionItem.getId())) {
+					initializePerspectivesMenu(menuEntry);
+					perspectives = menuEntry;
+				} else if (SHORTCUT_CONTRIBUTION_ITEM_ID_SHOW_VIEW.equals(contributionItem
+						.getId())) {
+					initializeViewsMenu(menuEntry);
+					views = menuEntry;
+				} else {
+					if (menuItem instanceof MMenu) {// TODO:menuItem any
+													// other instance
+						createMenuEntries((MMenu) menuItem, menuEntry);
+					}
+				}
+
+				if (menuEntry.getChildren().isEmpty()) {
+					menuEntry.setCheckState(getMenuItemIsVisible(menuEntry));
+				}
+
+				if (iconDescriptor == null) {
+					if (parent.getParent() == null) {
+						menuEntry.setImageDescriptor(menuImageDescriptor);
+					} else if (menuEntry.getChildrenCount() > 0) {
+						menuEntry.setImageDescriptor(submenuImageDescriptor);
+					}
+				}
+			}
+			if (findDynamics.containsKey(contributionItem)) {
+				IContributionItem item = findDynamics.get(contributionItem);
+				dynamicEntry = new DynamicContributionItem(item);
+				dynamicEntry.setCheckState(getMenuItemIsVisible(dynamicEntry));
+				dynamicEntry.setActionSet(idToActionSet.get(getActionSetID(contributionItem)));
+				parent.addChild(dynamicEntry);
+			} else {
+				return dynamicEntry;
+			}
+		} else if (OpaqueElementUtil.isOpaqueMenuItem(menuItem)) {
+			IContributionItem contributionItem = menuMngrRenderer.getContribution(menuItem);
+			if (contributionItem instanceof ActionContributionItem) {
+				final IAction action = ((ActionContributionItem) contributionItem).getAction();
+				DisplayItem menuEntry = new DisplayItem(action.getText(), contributionItem);
+				menuEntry.setImageDescriptor(action.getImageDescriptor());
+				menuEntry.setActionSet(idToActionSet.get(getActionSetID(contributionItem)));
+				parent.addChild(menuEntry);
+				if (menuEntry.getChildren().isEmpty()) {
+					menuEntry.setCheckState(getMenuItemIsVisible(menuEntry));
+				}
+			}
+		} else {
+			return dynamicEntry;
+		}
+		return dynamicEntry;
+	}
+
+	private boolean getMenuItemIsVisible(DisplayItem item) {
+		return getItemIsVisible(item, ModeledPageLayout.HIDDEN_MENU_PREFIX);
+	}
+
+	private boolean getToolbarItemIsVisible(DisplayItem item) {
+		return getItemIsVisible(item, ModeledPageLayout.HIDDEN_TOOLBAR_PREFIX);
+	}
+
+	private boolean getItemIsVisible(DisplayItem item, String prefix) {
+		return isAvailable(item) && !isHiddenItem(item, prefix);
+	}
+
+	private boolean isHiddenItem(DisplayItem item, String prefix) {
+		String itemId = prefix + getCommandID(item) + ","; //$NON-NLS-1$
+		return windowPage.getHiddenItems().contains(itemId);
+	}
+
+	/**
+	 * Causes a viewer to update the state of a category and all its ancestors.
+	 *
+	 * @param viewer
+	 * @param category
+	 */
+	private void updateCategoryAndParents(StructuredViewer viewer,
+			Category category) {
+		while (category.getParent() != shortcuts) {
+			viewer.update(category, null);
+			category = (Category) category.getParent();
+		}
+	}
+
+	private static boolean hasVisibleItems(MToolBar toolBar) {
+		for (MToolBarElement e : toolBar.getChildren()) {
+			if (!(e instanceof MToolBarSeparator)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	private DisplayItem createTrimBarEntries(MTrimBar trimBar) {
+		// create a root element
+		DisplayItem root = new DisplayItem(null, null);
+		if (trimBar == null) {
+			return root;
+		}
+		for (MTrimElement trimElement : trimBar.getChildren()) {
+			if (!(trimElement instanceof MToolBar)) {
+				continue;
+			}
+			MToolBar toolBar = (MToolBar) trimElement;
+			ToolBarManager manager = toolbarMngrRenderer.getManager(toolBar);
+			if (manager != null) {
+				toolbarMngrRenderer.reconcileManagerToModel(manager, toolBar);
+				IContributionItem contributionItem = (IContributionItem) toolBar.getTransientData().get(
+						CoolBarToTrimManager.OBJECT);
+				String text = getToolbarLabel(toolBar);
+				DisplayItem toolBarEntry = new DisplayItem(text, contributionItem);
+				toolBarEntry.setImageDescriptor(toolbarImageDescriptor);
+				toolBarEntry.setActionSet(idToActionSet.get(getActionSetID(toolBar)));
+				if (!hasVisibleItems(toolBar)) {
+					// TODO: there are two "Launch" toolbars, one of them is
+					// empty. Why?
+					continue;
+				}
+				root.addChild(toolBarEntry);
+				toolBarEntry.setCheckState(getToolbarItemIsVisible(toolBarEntry));
+				createToolbarEntries(toolBar, toolBarEntry);
+			}
+		}
+		return root;
+	}
+
+	private void createToolbarEntries(MToolBar toolbar, DisplayItem parent) {
+		if (toolbar == null) {
+			return;
+		}
+		for (MToolBarElement element : toolbar.getChildren()) {
+			createToolbarEntry(parent, element);
+		}
+	}
+
+	private void createToolbarEntry(DisplayItem parent, MToolBarElement element) {
+		IContributionItem contributionItem = toolbarMngrRenderer.getContribution(element);
+		if (isGroupOrSeparator(element, contributionItem)) {
+			return;
+		}
+
+		if (OpaqueElementUtil.isOpaqueToolItem(element)) {
+			if (contributionItem instanceof ActionContributionItem) {
+				final IAction action = ((ActionContributionItem) contributionItem).getAction();
+				DisplayItem toolbarEntry = new DisplayItem(action.getText(), contributionItem);
+				toolbarEntry.setImageDescriptor(action.getImageDescriptor());
+				toolbarEntry.setActionSet(idToActionSet.get(getActionSetID(contributionItem)));
+				if (toolbarEntry.getChildren().isEmpty()) {
+					toolbarEntry.setCheckState(getToolbarItemIsVisible(toolbarEntry));
+				}
+				parent.addChild(toolbarEntry);
+			}
+			return;
+		}
+
+		String text = null;
+		if (element instanceof MItem) {
+			text = getToolTipText((MItem) element);
+		}
+		ImageDescriptor iconDescriptor = null;
+		String iconURI = element instanceof MItem ? ((MItem) element).getIconURI() : null;
+		if (iconURI != null && iconURI.length() > 0) {
+			iconDescriptor = resUtils.imageDescriptorFromURI(URI.createURI(iconURI));
+		}
+		if (element.getWidget() instanceof ToolItem) {
+			ToolItem item = (ToolItem) element.getWidget();
+			if (text == null) {
+				text = item.getToolTipText();
+			}
+			if (text == null) {
+				text = item.getText();
+			}
+			if (iconDescriptor == null) {
+				Image image = item.getImage();
+				if (image != null) {
+					iconDescriptor = ImageDescriptor.createFromImage(image);
+				}
+			}
+		}
+		if (text == null) {
+			text = getToolbarLabel(element);
+		}
+
+		DisplayItem toolBarEntry = new DisplayItem(text, contributionItem);
+		if (iconDescriptor != null) {
+			toolBarEntry.setImageDescriptor(iconDescriptor);
+		}
+		toolBarEntry.setActionSet(idToActionSet.get(getActionSetID(element)));
+		if (toolBarEntry.getChildren().isEmpty()) {
+			toolBarEntry.setCheckState(getToolbarItemIsVisible(toolBarEntry));
+		}
+		parent.addChild(toolBarEntry);
+	}
+
+	private static boolean isGroupOrSeparator(MToolBarElement element, IContributionItem contributionItem) {
+		return element instanceof MToolBarSeparator
+				|| (contributionItem == null || contributionItem.isGroupMarker() || contributionItem
+						.isSeparator());
+	}
+
+	private static ParameterizedCommand generateParameterizedCommand(final MHandledItem item,
+			final IEclipseContext lclContext) {
+		ECommandService cmdService = (ECommandService) lclContext.get(ECommandService.class
+				.getName());
+		Map<String, Object> parameters = null;
+		List<MParameter> modelParms = item.getParameters();
+		if (modelParms != null && !modelParms.isEmpty()) {
+			parameters = new HashMap<>();
+			for (MParameter mParm : modelParms) {
+				parameters.put(mParm.getName(), mParm.getValue());
+			}
+		}
+		ParameterizedCommand cmd = cmdService.createCommand(item.getCommand().getElementId(),
+				parameters);
+		item.setWbCommand(cmd);
+		return cmd;
+	}
+
+	private String getToolTipText(MItem item) {
+		String text = item.getLocalizedTooltip();
+		if (item instanceof MHandledItem) {
+			MHandledItem handledItem = (MHandledItem) item;
+			EBindingService bs = (EBindingService) context.get(EBindingService.class.getName());
+			ParameterizedCommand cmd = handledItem.getWbCommand();
+			if (cmd == null) {
+				cmd = generateParameterizedCommand(handledItem, context);
+			}
+			TriggerSequence sequence = bs.getBestSequenceFor(handledItem.getWbCommand());
+			if (sequence != null) {
+				if (text == null) {
+					try {
+						text = cmd.getName();
+					} catch (NotDefinedException e) {
+						return null;
+					}
+				}
+				text = text + " (" + sequence.format() + ')'; //$NON-NLS-1$
+			}
+			return text;
+		} else if (OpaqueElementUtil.isOpaqueMenuItem(item)) {
+			Object opaque = OpaqueElementUtil.getOpaqueItem(item);
+			if (opaque instanceof ActionContributionItem) {
+				return ((ActionContributionItem) opaque).getAction().getText();
+			}
+		} else if (OpaqueElementUtil.isOpaqueToolItem(item)) {
+			Object opaque = OpaqueElementUtil.getOpaqueItem(item);
+			if (opaque instanceof ActionContributionItem) {
+				return ((ActionContributionItem) opaque).getAction().getToolTipText();
+			}
+		}
+		return text;
+	}
+
+	/**
+	 * Returns whether the shortcut tab should be shown.
+	 *
+	 * @return <code>true</code> if the shortcut tab should be shown, and
+	 *         <code>false</code> otherwise
+	 * @since 3.0
+	 */
+	private boolean showShortcutTab() {
+		return window.containsSubmenu(WorkbenchWindow.NEW_WIZARD_SUBMENU)
+				|| window
+						.containsSubmenu(WorkbenchWindow.OPEN_PERSPECTIVE_SUBMENU)
+				|| window.containsSubmenu(WorkbenchWindow.SHOW_VIEW_SUBMENU);
+	}
+
+	private static ArrayList<String> getVisibleIDs(DisplayItem root) {
+		if (root == null) {
+			return new ArrayList<>();
+		}
+		ArrayList<String> ids = new ArrayList<>(root.getChildrenCount());
+		for (TreeItem treeItem : root.getChildren()) {
+			DisplayItem object = (DisplayItem) treeItem;
+			if (object instanceof ShortcutItem && object.getState()) {
+				ids.add(getParamID(object));
+			}
+		}
+		return ids;
+	}
+
+	private void getChangedIds(DisplayItem item, List<String> invisible, List<String> visible) {
+		if (item instanceof ShortcutItem) {
+			return;
+		}
+
+		if (item == wizards || item == perspectives || item == views) {
+			// We always want the top-level wizard/perspective/view shortcuts to
+			// be visible, see bug 293448
+			return;
+		} else if (item.getChildrenCount() > 0) {
+			if (item.isChangedByUser()) {
+				String id = getCommandID(item);
+				if (id != null) {
+					if (item.getState()) {
+						visible.add(id);
+					} else {
+						invisible.add(id);
+					}
+				}
+			}
+			for (TreeItem treeItem : item.getChildren()) {
+				getChangedIds((DisplayItem) treeItem, invisible, visible);
+			}
+		} else if (item.isChangedByUser()) {
+			String id = getCommandID(item);
+			if (id != null) {
+				if (item.getState()) {
+					visible.add(id);
+				} else {
+					invisible.add(id);
+				}
+			}
+		}
+	}
+
+	private boolean updateHiddenElements(List<ActionSet> items, String currentHidden, String prefix) {
+		List<String> changedAndVisible = new ArrayList<>();
+		List<String> changedAndInvisible = new ArrayList<>();
+		for (ActionSet actionSet : items) {
+			if (!actionSet.wasChanged()) {
+				continue;
+			}
+			if (actionSet.isActive()) {
+				changedAndVisible.add(actionSet.descriptor.getId());
+			} else {
+				changedAndInvisible.add(actionSet.descriptor.getId());
+			}
+		}
+		return updateHiddenElements(currentHidden, prefix, changedAndVisible, changedAndInvisible);
+	}
+
+	private boolean updateHiddenElements(DisplayItem items, String currentHidden, String prefix) {
+		List<String> changedAndVisible = new ArrayList<>();
+		List<String> changedAndInvisible = new ArrayList<>();
+		getChangedIds(items, changedAndInvisible, changedAndVisible);
+
+		return updateHiddenElements(currentHidden, prefix, changedAndVisible, changedAndInvisible);
+	}
+
+	private boolean updateHiddenElements(String currentHidden, String prefix, List<String> changedAndVisible,
+			List<String> changedAndInvisible) {
+		boolean hasChanges = false;
+		// Remove explicitly 'visible' elements from the current list
+		for (String id : changedAndVisible) {
+			String itemId = prefix + id;
+			if (currentHidden.contains(itemId + ",")) { //$NON-NLS-1$
+				hasChanges = true;
+				windowPage.removeHiddenItems(itemId);
+			}
+		}
+
+		// Add explicitly 'hidden' elements to the current list
+		for (String id : changedAndInvisible) {
+			String itemId = prefix + id;
+			if (!currentHidden.contains(itemId + ",")) { //$NON-NLS-1$
+				hasChanges = true;
+				windowPage.addHiddenItems(itemId);
+			}
+		}
+
+		return hasChanges;
+	}
+
+	@Override
+	protected void okPressed() {
+
+		// Shortcuts
+		if (showShortcutTab()) {
+			windowPage.setNewShortcuts(getVisibleIDs(wizards), ModeledPageLayout.NEW_WIZARD_TAG);
+			windowPage.setNewShortcuts(getVisibleIDs(perspectives), ModeledPageLayout.PERSP_SHORTCUT_TAG);
+			windowPage.setNewShortcuts(getVisibleIDs(views), ModeledPageLayout.SHOW_VIEW_TAG);
+		}
+
+		// Determine if anything has changed and, if so, update the menu & tb's
+		boolean requiresUpdate = false;
+
+		// Action Sets
+		ArrayList<ActionSetDescriptor> toAdd = new ArrayList<>();
+		ArrayList<ActionSetDescriptor> toRemove = new ArrayList<>();
+
+		for (ActionSet actionSet : actionSets) {
+			if (!actionSet.wasChanged()) {
+				continue;
+			}
+
+			// Something has changed
+			requiresUpdate = true;
+
+			if (actionSet.isActive()) {
+				toAdd.add(actionSet.descriptor);
+			} else {
+				toRemove.add(actionSet.descriptor);
+			}
+		}
+
+		perspective.turnOnActionSets(toAdd.toArray(new IActionSetDescriptor[toAdd.size()]));
+		perspective.turnOffActionSets(toRemove.toArray(new IActionSetDescriptor[toRemove.size()]));
+
+		requiresUpdate |= updateHiddenElements(actionSets, windowPage.getHiddenItems(),
+				ModeledPageLayout.HIDDEN_ACTIONSET_PREFIX);
+		// Menu and Toolbar Items
+		requiresUpdate |= updateHiddenElements(menuItems, windowPage.getHiddenItems(),
+				ModeledPageLayout.HIDDEN_MENU_PREFIX);
+		requiresUpdate |= updateHiddenElements(toolBarItems, windowPage.getHiddenItems(),
+				ModeledPageLayout.HIDDEN_TOOLBAR_PREFIX);
+
+		if (requiresUpdate) {
+			perspective.updateActionBars();
+		}
+
+		super.okPressed();
+	}
+
+	@Override
+	public boolean close() {
+
+		treeManager.dispose();
+		customizeActionBars.dispose();
+
+		return super.close();
+	}
+
+	private static String removeShortcut(String label) {
+		if (label == null) {
+			return label;
+		}
+		int end = label.lastIndexOf('@');
+		if (end >= 0) {
+			label = label.substring(0, end);
+		}
+
+		end = label.lastIndexOf('\t');
+		if (end >= 0) {
+			label = label.substring(0, end);
+		}
+
+		return label;
+	}
+
+
+	@Override
+	protected boolean isResizable() {
+		return true;
+	}
+
+	void showActionSet(final DisplayItem item) {
+		if (item.getActionSet() != null) {
+			showActionSet(item.getActionSet());
+		}
+	}
+
+	void showActionSet(final ActionSet actionSet) {
+		tabFolder.setSelection(actionSetTab);
+		actionSetAvailabilityTable.reveal(actionSet);
+		setSelectionOn(actionSetAvailabilityTable, actionSet);
+		actionSetAvailabilityTable.getControl().setFocus();
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/FilteredModelCheckListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/FilteredModelCheckListener.java
new file mode 100644
index 0000000..c0a4ca5
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/FilteredModelCheckListener.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.dialogs.cpd;
+
+import org.eclipse.jface.viewers.StructuredViewer;
+import org.eclipse.ui.internal.dialogs.cpd.TreeManager.CheckListener;
+import org.eclipse.ui.internal.dialogs.cpd.TreeManager.TreeItem;
+
+/**
+ * On a model change, update a filtered listener. While the check listener
+ * provided by the model will take care of the elements which change, since
+ * we simulate our own check state of parents, the parents may need to be
+ * updated.
+ *
+ * @since 3.5
+ */
+final class FilteredModelCheckListener implements CheckListener {
+	private final ActionSetFilter filter;
+	private final StructuredViewer viewer;
+
+	FilteredModelCheckListener(ActionSetFilter filter, StructuredViewer viewer) {
+		this.filter = filter;
+		this.viewer = viewer;
+	}
+
+	@Override
+	public void checkChanged(TreeItem changedItem) {
+		TreeItem item = changedItem;
+		boolean update = false;
+
+		// Force an update on all parents.
+		while (item != null) {
+			update = update || filter.select(null, null, item);
+			if (update) {
+				viewer.update(item, null);
+			}
+			item = item.getParent();
+		}
+	}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/FilteredTreeCheckProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/FilteredTreeCheckProvider.java
new file mode 100644
index 0000000..fd4752d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/FilteredTreeCheckProvider.java
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.dialogs.cpd;
+
+import org.eclipse.jface.viewers.ICheckStateProvider;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.ui.internal.dialogs.cpd.TreeManager.TreeItem;
+
+/**
+ * A check provider which calculates checked state based on leaf states in
+ * the tree (as opposed to children in a model).
+ *
+ * @since 3.5
+ */
+class FilteredTreeCheckProvider implements ICheckStateProvider {
+	private ITreeContentProvider contentProvider;
+	private ViewerFilter filter;
+
+	public FilteredTreeCheckProvider(ITreeContentProvider contentProvider,
+			ViewerFilter filter) {
+		this.contentProvider = contentProvider;
+		this.filter = filter;
+	}
+
+	@Override
+	public boolean isChecked(Object element) {
+		TreeItem treeItem = (TreeItem) element;
+		return getLeafStates(treeItem, contentProvider, filter) != TreeManager.CHECKSTATE_UNCHECKED;
+	}
+
+	@Override
+	public boolean isGrayed(Object element) {
+		TreeItem treeItem = (TreeItem) element;
+		return getLeafStates(treeItem, contentProvider, filter) == TreeManager.CHECKSTATE_GRAY;
+	}
+
+	/**
+	 * Determines the state <code>item</code> should be (checked, gray or
+	 * unchecked) based only on the leafs underneath it (unless it is indeed a
+	 * leaf).
+	 *
+	 * @param item
+	 *            the item to find the state of
+	 * @param provider
+	 *            the content provider which will provide <code>item</code>'s
+	 *            children
+	 * @param filter
+	 *            the filter that will only select elements in the currently
+	 *            chosen action set
+	 * @return {@link TreeManager#CHECKSTATE_CHECKED},
+	 *         {@link TreeManager#CHECKSTATE_GRAY} or
+	 *         {@link TreeManager#CHECKSTATE_UNCHECKED}
+	 */
+	static int getLeafStates(TreeItem item, ITreeContentProvider provider, ViewerFilter filter) {
+		Object[] children = provider.getChildren(item);
+
+		boolean checkedFound = false;
+		boolean uncheckedFound = false;
+
+		for (Object element : children) {
+			if (filter.select(null, null, element)) {
+				TreeItem child = (TreeItem) element;
+				switch (getLeafStates(child, provider, filter)) {
+				case TreeManager.CHECKSTATE_CHECKED: {
+					checkedFound = true;
+					break;
+				}
+				case TreeManager.CHECKSTATE_GRAY: {
+					checkedFound = uncheckedFound = true;
+					break;
+				}
+				case TreeManager.CHECKSTATE_UNCHECKED: {
+					uncheckedFound = true;
+					break;
+				}
+				}
+				if (checkedFound && uncheckedFound) {
+					return TreeManager.CHECKSTATE_GRAY;
+				}
+			}
+		}
+
+		if (!checkedFound && !uncheckedFound) {
+			return item.getState() ? TreeManager.CHECKSTATE_CHECKED : TreeManager.CHECKSTATE_UNCHECKED;
+		}
+		return checkedFound ? TreeManager.CHECKSTATE_CHECKED : TreeManager.CHECKSTATE_UNCHECKED;
+	}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/FilteredViewerCheckListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/FilteredViewerCheckListener.java
new file mode 100644
index 0000000..8d098b0
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/FilteredViewerCheckListener.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.dialogs.cpd;
+
+import org.eclipse.jface.viewers.CheckStateChangedEvent;
+import org.eclipse.jface.viewers.ICheckStateListener;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.ui.internal.dialogs.cpd.CustomizePerspectiveDialog.DisplayItem;
+
+/**
+ * A check listener to bring about the expected change in a model based on a
+ * check event in a filtered viewer. Since the checked state of a parent in
+ * a filtered viewer is not based on its model state, but rather its leafs'
+ * states, when a non-leaf element's check state changes, its model state
+ * does not necessarily change, but its leafs' model states do.
+ *
+ * @since 3.5
+ */
+class FilteredViewerCheckListener implements ICheckStateListener {
+	private ITreeContentProvider contentProvider;
+	private ViewerFilter filter;
+
+	public FilteredViewerCheckListener(
+			ITreeContentProvider contentProvider, ViewerFilter filter) {
+		this.contentProvider = contentProvider;
+		this.filter = filter;
+	}
+
+	@Override
+	public void checkStateChanged(CheckStateChangedEvent event) {
+		setAllLeafs((DisplayItem) event.getElement(), event
+				.getChecked(), contentProvider, filter);
+	}
+
+	/**
+	 * Sets all leafs under a {@link DisplayItem} to either visible or
+	 * invisible. This is for use with the action set trees, where the only
+	 * state used is that of leafs, and the rest is rolled up to the parents.
+	 * Thus, this method effectively sets the state of the entire branch.
+	 *
+	 * @param item
+	 *            the item whose leafs underneath (or itself, if it is a leaf)
+	 *            to <code>value</code>
+	 * @param value
+	 *            <code>true</code>for visible, <code>false</code> for invisible
+	 * @param provider
+	 *            the content provider which will provide <code>item</code>'s
+	 *            children
+	 * @param filter
+	 *            the filter that will only select elements in the currently
+	 *            chosen action set
+	 */
+	static void setAllLeafs(DisplayItem item, boolean value, ITreeContentProvider provider, ViewerFilter filter) {
+		Object[] children = provider.getChildren(item);
+		boolean isLeaf = true;
+
+		for (Object element : children) {
+			isLeaf = false;
+			if (filter.select(null, null, element)) {
+				DisplayItem child = (DisplayItem) element;
+				setAllLeafs(child, value, provider, filter);
+			}
+		}
+
+		if (isLeaf) {
+			item.setCheckState(value);
+		}
+	}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/GrayOutUnavailableLabelProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/GrayOutUnavailableLabelProvider.java
new file mode 100644
index 0000000..2a59777
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/GrayOutUnavailableLabelProvider.java
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Andrey Loskutov <loskutov@gmx.de> - Bug 420956
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ *******************************************************************************/
+package org.eclipse.ui.internal.dialogs.cpd;
+
+import java.util.HashSet;
+import java.util.Set;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.IColorProvider;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.dialogs.cpd.CustomizePerspectiveDialog.ActionSet;
+import org.eclipse.ui.internal.dialogs.cpd.CustomizePerspectiveDialog.DisplayItem;
+
+/**
+ * A label provider which takes the default label provider in the
+ * TreeManager, and adds on functionality to gray out text and icons of
+ * contribution items whose action sets are unavailable.
+ *
+ * @since 3.5
+ *
+ */
+class GrayOutUnavailableLabelProvider extends TreeManager.TreeItemLabelProvider implements IColorProvider {
+	private Display display;
+	private ViewerFilter filter;
+	private Set<Image> toDispose;
+
+	public GrayOutUnavailableLabelProvider(ViewerFilter filter) {
+		this.display = PlatformUI.getWorkbench().getDisplay();
+		this.filter = filter;
+		toDispose = new HashSet<>();
+	}
+
+	@Override
+	public Color getBackground(Object element) {
+		return null;
+	}
+
+	@Override
+	public Color getForeground(Object element) {
+		if (element instanceof DisplayItem) {
+			if (!CustomizePerspectiveDialog.isEffectivelyAvailable((DisplayItem) element, filter)) {
+				return display.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW);
+			}
+		}
+		if (element instanceof ActionSet) {
+			if (!((ActionSet) element).isActive()) {
+				return display.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW);
+			}
+		}
+		return null;
+	}
+
+	@Override
+	public Image getImage(Object element) {
+		Image actual = super.getImage(element);
+
+		if (element instanceof DisplayItem && actual != null) {
+			DisplayItem item = (DisplayItem) element;
+			if (!CustomizePerspectiveDialog.isEffectivelyAvailable(item, filter)) {
+				// RAP [bm] IMAGE_DISABLED
+//				ImageDescriptor original = ImageDescriptor
+//						.createFromImage(actual);
+//				ImageDescriptor disable = ImageDescriptor.createWithFlags(
+//						original, SWT.IMAGE_DISABLE);
+//				Image newImage = disable.createImage();
+				Image newImage = actual;
+				toDispose.add(newImage);
+				return newImage;
+			}
+		}
+
+		return actual;
+	}
+
+	@Override
+	public void dispose() {
+		for (Image image : toDispose) {
+			image.dispose();
+		}
+		toDispose.clear();
+		super.dispose();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/ShortcutLabelProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/ShortcutLabelProvider.java
new file mode 100644
index 0000000..7fb9235
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/ShortcutLabelProvider.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.dialogs.cpd;
+
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.internal.dialogs.cpd.CustomizePerspectiveDialog.ShortcutItem;
+
+/**
+ * A label provider to include the description field of ShortcutItems in the
+ * table.
+ *
+ * @since 3.5
+ */
+class ShortcutLabelProvider extends
+		TreeManager.TreeItemLabelProvider implements ITableLabelProvider {
+	@Override
+	public Image getColumnImage(Object element, int columnIndex) {
+		if (columnIndex == 0) {
+			return this.getImage(element);
+		}
+		return null;
+	}
+
+	@Override
+	public String getColumnText(Object element, int columnIndex) {
+		if (columnIndex == 1) {
+			return ((ShortcutItem) element).getDescription();
+		}
+		return this.getText(element);
+	}
+
+	@Override
+	public void addListener(ILabelProviderListener listener) {
+	}
+
+	@Override
+	public boolean isLabelProperty(Object element, String property) {
+		return false;
+	}
+
+	@Override
+	public void removeListener(ILabelProviderListener listener) {
+	}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/ShowUsedActionSetsFilter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/ShowUsedActionSetsFilter.java
new file mode 100644
index 0000000..b04d395
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/ShowUsedActionSetsFilter.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.dialogs.cpd;
+
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.ui.internal.dialogs.cpd.CustomizePerspectiveDialog.ActionSet;
+import org.eclipse.ui.internal.dialogs.cpd.CustomizePerspectiveDialog.DisplayItem;
+
+/**
+ * A filter which will only show action sets which contribute items in the
+ * given tree structure.
+ *
+ * @since 3.5
+ */
+final class ShowUsedActionSetsFilter extends ViewerFilter {
+	private DisplayItem rootItem;
+
+	public ShowUsedActionSetsFilter(DisplayItem rootItem) {
+		this.rootItem = rootItem;
+	}
+
+	@Override
+	public boolean select(Viewer viewer, Object parentElement, Object element) {
+		return (CustomizePerspectiveDialog.includeInSetStructure(rootItem, (ActionSet) element));
+	}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/TreeManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/TreeManager.java
new file mode 100644
index 0000000..f7377d6
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/TreeManager.java
@@ -0,0 +1,555 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ *******************************************************************************/
+package org.eclipse.ui.internal.dialogs.cpd;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.jface.viewers.CheckStateChangedEvent;
+import org.eclipse.jface.viewers.CheckboxTableViewer;
+import org.eclipse.jface.viewers.CheckboxTreeViewer;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.jface.viewers.ICheckStateListener;
+import org.eclipse.jface.viewers.ICheckStateProvider;
+import org.eclipse.jface.viewers.ICheckable;
+import org.eclipse.jface.viewers.IContentProvider;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * Manages a tree which provides "standard checkbox tree behavior". I.e. it
+ * follows these rules:
+ * <ol>
+ * 	<li>If a check box is checked, all its children must be checked.</li>
+ * 	<li>If a check box is unchecked, all its children must be unchecked.</li>
+ * 	<li>If a check box is grayed, each of its children may be either checked or
+ * 		unchecked, however, there must be one of each.</li>
+ * 	<li>If a user checks a check box, its children or parents must change state
+ * 		accordingly.</li>
+ * </ol>
+ * <p>
+ * <b>Note:</b> be sure to call dispose()
+ * </p>
+ * @since 3.5
+ *
+ */
+public class TreeManager {
+	public static final int CHECKSTATE_UNCHECKED = 0;
+	public static final int CHECKSTATE_GRAY = 1;
+	public static final int CHECKSTATE_CHECKED = 2;
+
+	private static ICheckStateProvider checkStateProvider = null;
+	private static IBaseLabelProvider labelProvider = null;
+	private static ICheckStateListener viewerCheckListener = null;
+	private static ITreeContentProvider treeContentProvider = null;
+
+	private List<CheckListener> listeners = new ArrayList<>();
+	private LocalResourceManager resourceManager = new LocalResourceManager(JFaceResources.getResources());
+
+	/**
+	 * Instances of this interface will handle changes in the model
+	 * representation of checkstates.
+	 */
+	public interface CheckListener {
+		/**
+		 * Invoked when a {@link TreeManager.TreeItem}'s check state has
+		 * changed.
+		 *
+		 * @param changedItem
+		 *            The item whose check state has changed
+		 */
+		public void checkChanged(TreeItem changedItem);
+	}
+
+	/**
+	 * Implementation of {@link TreeManager.CheckListener} for use in a {@link CheckboxTreeViewer}.
+	 */
+	public static class ModelListenerForCheckboxTree implements CheckListener {
+		private CheckboxTreeViewer treeViewer;
+		public ModelListenerForCheckboxTree(TreeManager manager, CheckboxTreeViewer treeViewer) {
+			this.treeViewer = treeViewer;
+			manager.addListener(this);
+		}
+
+		@Override
+		public void checkChanged(TreeItem changedItem) {
+			treeViewer.update(changedItem, null);
+		}
+	}
+
+	/**
+	 * Implementation of {@link TreeManager}CheckListener for use in a
+	 * {@link CheckboxTableViewer}.
+	 */
+	public static class ModelListenerForCheckboxTable implements CheckListener {
+		private CheckboxTableViewer tableViewer;
+		public ModelListenerForCheckboxTable(TreeManager manager, CheckboxTableViewer tableViewer) {
+			this.tableViewer = tableViewer;
+			manager.addListener(this);
+		}
+
+		@Override
+		public void checkChanged(TreeItem changedItem) {
+			tableViewer.update(changedItem, null);
+		}
+	}
+
+	public static class ViewerCheckStateListener implements ICheckStateListener {
+		@Override
+		public void checkStateChanged(CheckStateChangedEvent event) {
+			Object checked = event.getElement();
+			if(checked instanceof TreeItem) {
+				((TreeItem)checked).setChangedByUser(true);
+				((TreeItem)checked).setCheckState(event.getChecked());
+			}
+		}
+	}
+
+	/**
+	 * An {@link ICheckStateProvider} which properly provides checkbox state on
+	 * {@link TreeManager.TreeItem}s.
+	 */
+	public static class CheckStateProvider implements ICheckStateProvider {
+		@Override
+		public boolean isChecked(Object element) {
+			return ((TreeItem)element).checkState != CHECKSTATE_UNCHECKED;
+		}
+
+		@Override
+		public boolean isGrayed(Object element) {
+			return ((TreeItem)element).checkState == CHECKSTATE_GRAY;
+		}
+	}
+
+	/**
+	 * A {@link IBaseLabelProvider} for {@link TreeManager.TreeItem}s.
+	 */
+	public static class TreeItemLabelProvider extends LabelProvider {
+		@Override
+		public String getText(Object element) {
+			if (element instanceof TreeItem) {
+				return ((TreeItem) element).getLabel();
+			}
+			return super.getText(element);
+		}
+
+		@Override
+		public Image getImage(Object element) {
+			if (element instanceof TreeItem) {
+				return ((TreeItem) element).getImage();
+			}
+			return super.getImage(element);
+		}
+	}
+
+	/**
+	 * An {@link ITreeContentProvider} for {@link TreeManager.TreeItem}s - will completely build the
+	 * tree structure represented by {@link TreeManager.TreeItem}s.
+	 */
+	public static class TreeItemContentProvider implements ITreeContentProvider {
+		@Override
+		public Object[] getChildren(Object parentElement) {
+			return ((TreeItem)parentElement).getChildren().toArray();
+		}
+
+		@Override
+		public Object getParent(Object element) {
+			return ((TreeItem)element).getParent();
+		}
+
+		@Override
+		public boolean hasChildren(Object element) {
+			return getChildren(element).length > 0;
+		}
+
+		@Override
+		public Object[] getElements(Object inputElement) {
+			return getChildren(inputElement);
+		}
+
+		@Override
+		public void dispose() {}
+
+		@Override
+		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {}
+	}
+
+	/**
+	 * @return	an {@link ICheckStateProvider} which will operate on
+	 * 		{@link TreeItem}s
+	 */
+	public static ICheckStateProvider getCheckStateProvider() {
+		if(checkStateProvider == null) {
+			checkStateProvider = new CheckStateProvider();
+		}
+		return checkStateProvider;
+	}
+
+	/**
+	 * @return	an {@link IBaseLabelProvider} which will provide the labels and
+	 * 		images of {@link TreeItem}s
+	 */
+	public static IBaseLabelProvider getLabelProvider() {
+		if(labelProvider == null) {
+			labelProvider = new TreeItemLabelProvider();
+		}
+		return labelProvider;
+	}
+
+	/**
+	 * @return	an {@link ITreeContentProvider} which will provide
+	 * 		{@link TreeItem} content in tree format.
+	 */
+	public static ITreeContentProvider getTreeContentProvider() {
+		if(treeContentProvider == null)
+			treeContentProvider = new TreeItemContentProvider();
+		return treeContentProvider;
+	}
+
+	/**
+	 * @return	an {@link ICheckStateListener} which will respond to
+	 * 		{@link CheckStateChangedEvent}s by updating the model to reflect
+	 * 		them
+	 */
+	public ICheckStateListener getViewerCheckStateListener() {
+		if(viewerCheckListener == null)
+			viewerCheckListener = new ViewerCheckStateListener();
+		return viewerCheckListener;
+	}
+
+	/**
+	 * A single item in a tree of managed checkbox states.
+	 */
+	public class TreeItem {
+		private String label;
+		private ImageDescriptor imageDescriptor;
+		private Image image;
+		private TreeItem parent;
+		private List<TreeItem> children;
+		private int checkState;
+		private boolean changedByUser;
+
+		public TreeItem(String label) {
+			this.label = label;
+			this.children = new ArrayList<>();
+		}
+
+		public String getLabel() {
+			return label;
+		}
+
+		public void setLabel(String label) {
+			this.label = label;
+		}
+
+		public Image getImage() {
+			if(image == null) {
+				if(imageDescriptor == null) {
+					return null;
+				}
+				image = resourceManager.createImage(imageDescriptor);
+			}
+			return image;
+		}
+
+		public void setImageDescriptor(ImageDescriptor imageDescriptor) {
+			this.imageDescriptor = imageDescriptor;
+		}
+
+		public void addChild(TreeItem newChild) {
+            newChild.parent = this;
+            children.add(newChild);
+            synchParents(newChild);
+        }
+
+		public List<TreeItem> getChildren() {
+			return children;
+		}
+
+		public int getChildrenCount() {
+			return children.size();
+		}
+
+		public TreeItem getParent() {
+			return parent;
+		}
+
+        /**
+		 * An internal call that forwards the change events but does <b>not</b>
+		 * cause any iterative synchronization to take place.
+		 *
+		 * @param newState
+		 */
+        private void internalSetCheckState(int newState) {
+			if (newState == checkState)
+				return;
+
+			checkState = newState;
+			fireListeners(this);
+        }
+
+		/**
+		 * External call to explicitly set the particular state of a
+		 * {@link TreeManager.TreeItem}. This is usually a response to an SWT
+		 * check changed event generated by a Tree/Table.
+		 *
+		 * @param checked
+		 */
+		public void setCheckState(boolean checked) {
+			int newState = checked ? CHECKSTATE_CHECKED : CHECKSTATE_UNCHECKED;
+			if (checkState == newState)
+				return;
+			// Actually set the state and fire the CheckChangeEvent
+			internalSetCheckState(newState);
+
+			// Enforce the SWT rules for checked/gray behavior
+			synchChildren(this);
+			synchParents(this);
+		}
+
+		/**
+		 * From the client's perspective the state is a boolean.
+		 *
+		 * @return <code>true</code> if the state is not UNCHECKED
+		 */
+		public boolean getState() {
+			return !(checkState == CHECKSTATE_UNCHECKED);
+		}
+
+		int getCheckState() {
+			return checkState;
+		}
+
+		/**
+		 * If the new state is not "GRAY" then force all children to match that
+		 * state (recursively).
+		 *
+		 * @param changedItem
+		 */
+		private void synchChildren(TreeItem changedItem) {
+			int newState = changedItem.checkState;
+
+			// if the new state is 'GRAY'
+			if (newState != CHECKSTATE_GRAY) {
+				for (TreeItem treeItem : changedItem.children) {
+					TreeItem curItem = treeItem;
+					curItem.internalSetCheckState(newState);
+					curItem.setChangedByUser(changedItem.isChangedByUser());
+
+					synchChildren(curItem);
+				}
+			}
+		}
+
+		/**
+		 * Set the parent's state based on the aggregate state of its children
+		 * using the following rules:
+		 * <ul>
+		 * <li>All children checked...parent checked</li>
+		 * <li>All children unchecked...parent unchecked</li>
+		 * <li>else...parent GRAY</li>
+		 * </ul>
+		 *
+		 * @param changedItem
+		 */
+		private void synchParents(TreeItem changedItem) {
+			if(changedItem.parent == null)
+				return;
+
+			int newState = changedItem.checkState;
+
+			if (newState == CHECKSTATE_GRAY) {
+				// if the new state is 'GRAY' then -ALL- the parents are gray
+				while (changedItem.parent != null && changedItem.parent.checkState != CHECKSTATE_GRAY) {
+					changedItem.parent.internalSetCheckState(CHECKSTATE_GRAY);
+					if (changedItem.isChangedByUser()) {
+						changedItem.parent.setChangedByUser(true);
+					}
+					changedItem = changedItem.parent;
+				}
+			} else {
+				// compute the parent's state - checked if all children are
+				// checked, unchecked if all children are unchecked, gray if
+				// some of each
+				boolean checkedFound = newState == CHECKSTATE_CHECKED;
+				boolean uncheckedFound = newState == CHECKSTATE_UNCHECKED;
+				for (Iterator<TreeItem> i = changedItem.parent.children.iterator(); i.hasNext()
+						&& (!checkedFound || !uncheckedFound);) {
+					TreeItem item = i.next();
+					switch(item.checkState) {
+					case CHECKSTATE_CHECKED: {
+						checkedFound = true;
+						break;
+					} case CHECKSTATE_GRAY: {
+						checkedFound = uncheckedFound = true;
+						break;
+					} case CHECKSTATE_UNCHECKED: {
+						uncheckedFound = true;
+						break;
+					}}
+				}
+
+				int oldState = changedItem.parent.checkState;
+				if(checkedFound && uncheckedFound) {
+					changedItem.parent.internalSetCheckState(CHECKSTATE_GRAY);
+				} else if (checkedFound) {
+					changedItem.parent.internalSetCheckState(CHECKSTATE_CHECKED);
+				} else {
+					changedItem.parent.internalSetCheckState(CHECKSTATE_UNCHECKED);
+				}
+				if(oldState != changedItem.parent.checkState) {
+					if (changedItem.isChangedByUser()) {
+						changedItem.parent.setChangedByUser(true);
+					}
+					synchParents(changedItem.parent);
+				}
+			}
+		}
+
+		/**
+		 * @param changedByUser The changedByUser to set.
+		 */
+		public void setChangedByUser(boolean changedByUser) {
+			this.changedByUser = changedByUser;
+		}
+
+		/**
+		 * @return Returns the changedByUser.
+		 */
+		public boolean isChangedByUser() {
+			return changedByUser;
+		}
+
+		@Override
+		public String toString() {
+			return label + ", check=" + getState() + ", changed=" + changedByUser; //$NON-NLS-1$ //$NON-NLS-2$
+		}
+
+	}
+
+	/**
+	 * Creates a new {@link TreeManager}.
+	 */
+	public TreeManager() {
+		listeners = new ArrayList<>();
+	}
+
+	/**
+	 * Add a {@link CheckListener} whose
+	 * {@link CheckListener#checkChanged(TreeManager.TreeItem)} method will be
+	 * invoked when a {@link TreeItem} created in this {@link TreeManager} has a
+	 * check state change.
+	 *
+	 * @param listener
+	 */
+	public void addListener(CheckListener listener) {
+		listeners.add(listener);
+	}
+
+	/**
+	 * Provides a {@link CheckListener} which updates a viewer whenever the
+	 * {@link TreeManager} model changes.
+	 * @param viewer	The viewer whose check states will be appropriately
+	 * 		updated on a change to the model.
+	 * @return	The created {@link CheckListener}.
+	 */
+	public CheckListener getCheckListener(ICheckable viewer) {
+		if(viewer instanceof CheckboxTreeViewer)
+			return new ModelListenerForCheckboxTree(this, (CheckboxTreeViewer)viewer);
+		if(viewer instanceof CheckboxTableViewer)
+			return new ModelListenerForCheckboxTable(this, (CheckboxTableViewer)viewer);
+		return null;
+	}
+
+	/**
+	 * Sets up this {@link TreeManager} for standard interaction with the
+	 * provided {@link CheckboxTreeViewer}. In particular:
+	 * <ul>
+	 * 	<li>Adds a Label Provider for {@link TreeItem}s which provides both
+	 * 		labels and images.</li>
+	 * 	<li>Adds a {@link CheckStateProvider} for {@link TreeItem}s.</li>
+	 * 	<li>Adds an {@link IContentProvider} to build a tree from input
+	 * 		{@link TreeItem}s.</li>
+	 * 	<li>Adds an {@link ICheckStateListener} to the viewer to update the
+	 * 		appropriate {@link TreeItem}s upon a check box state change in the
+	 * 		viewer.</li>
+	 * 	<li>Adds a {@link CheckListener} to the {@link TreeManager} which will
+	 * 		automatically update the viewer on a {@link TreeItem} check state
+	 * 		change.</li>
+	 * </ul>
+	 * @param viewer	the viewer to configure with this TreeManager.
+	 */
+	public void attachAll(CheckboxTreeViewer viewer) {
+		viewer.setLabelProvider(getLabelProvider());
+		viewer.setCheckStateProvider(getCheckStateProvider());
+		viewer.setContentProvider(getTreeContentProvider());
+		viewer.addCheckStateListener(getViewerCheckStateListener());
+		getCheckListener(viewer);
+	}
+
+	/**
+	 * Sets up this {@link TreeManager} for standard interaction with the
+	 * provided {@link CheckboxTableViewer}. In particular:
+	 * <ul>
+	 * 	<li>Adds a Label Provider for {@link TreeItem}s which provides both
+	 * 		labels and images.</li>
+	 * 	<li>Adds a {@link CheckStateProvider} for {@link TreeItem}s.</li>
+	 * 	<li>Adds an {@link IContentProvider} to build a tree from input
+	 * 		{@link TreeItem}s.</li>
+	 * 	<li>Adds an {@link ICheckStateListener} to the viewer to update the
+	 * 		appropriate {@link TreeItem}s upon a check box state change in the
+	 * 		viewer.</li>
+	 * 	<li>Adds a {@link CheckListener} to the {@link TreeManager} which will
+	 * 		automatically update the viewer on a {@link TreeItem} check state
+	 * 		change.</li>
+	 * </ul>
+	 * @param viewer	the viewer to configure with this TreeManager.
+	 */
+	public void attachAll(CheckboxTableViewer viewer) {
+		viewer.setLabelProvider(getLabelProvider());
+		viewer.setCheckStateProvider(getCheckStateProvider());
+		viewer.setContentProvider(getTreeContentProvider());
+		viewer.addCheckStateListener(getViewerCheckStateListener());
+		getCheckListener(viewer);
+	}
+
+	/**
+	 * Dissociates a listener.
+	 * @param listener	The listener to remove.
+	 */
+	public void removeListener(CheckListener listener) {
+		listeners.remove(listener);
+	}
+
+	/**
+	 * Fires all listeners.
+	 * @param item	The {@link TreeItem} that changed.
+	 */
+	private void fireListeners(TreeItem item) {
+		for (CheckListener checkListener : listeners) {
+			CheckListener listener = checkListener;
+			listener.checkChanged(item);
+		}
+	}
+
+	public void dispose() {
+		resourceManager.dispose();
+		resourceManager = null;
+		listeners.clear();
+		listeners = null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/UnavailableContributionItemCheckListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/UnavailableContributionItemCheckListener.java
new file mode 100644
index 0000000..9a6592d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dialogs/cpd/UnavailableContributionItemCheckListener.java
@@ -0,0 +1,112 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Andrey Loskutov <loskutov@gmx.de> - Bug 445538
+ *******************************************************************************/
+package org.eclipse.ui.internal.dialogs.cpd;
+
+import org.eclipse.e4.ui.workbench.renderers.swt.HandledContributionItem;
+import org.eclipse.jface.viewers.AbstractTreeViewer;
+import org.eclipse.jface.viewers.CheckStateChangedEvent;
+import org.eclipse.jface.viewers.CheckboxTreeViewer;
+import org.eclipse.jface.viewers.ICheckStateListener;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.MessageBox;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.dialogs.cpd.CustomizePerspectiveDialog.DisplayItem;
+
+/**
+ * A check listener which, upon changing the check state of a contribution
+ * item, checks if that item is eligible to be checked (i.e. it is in an
+ * available action set), and if not, informs the user of the illegal
+ * operation. If the operation is legal, the event is forwarded to the check
+ * listener to actually perform a useful action.
+ *
+ * @since 3.5
+ */
+class UnavailableContributionItemCheckListener implements ICheckStateListener {
+
+	private final CustomizePerspectiveDialog dialog;
+	private CheckboxTreeViewer viewer;
+	private ICheckStateListener originalListener;
+
+	/**
+	 * @param viewer
+	 *            the viewer being listened to
+	 * @param originalListener
+	 *            the listener to invoke upon a legal action
+	 * @param dialog
+	 *            parent
+	 */
+	public UnavailableContributionItemCheckListener(CustomizePerspectiveDialog dialog, CheckboxTreeViewer viewer,
+			ICheckStateListener originalListener) {
+		this.dialog = dialog;
+		this.viewer = viewer;
+		this.originalListener = originalListener;
+	}
+
+	@Override
+	public void checkStateChanged(CheckStateChangedEvent event) {
+		DisplayItem item = (DisplayItem) event.getElement();
+		ViewerFilter[] filters = viewer.getFilters();
+		boolean isEffectivelyAvailable = CustomizePerspectiveDialog.isEffectivelyAvailable(item, filters.length > 0 ? filters[0] : null);
+
+		if (isEffectivelyAvailable) {
+			// legal action - invoke the listener which will do actual work
+			originalListener.checkStateChanged(event);
+			return;
+		}
+
+		boolean isAvailable = CustomizePerspectiveDialog.isAvailable(item);
+		viewer.update(event.getElement(), null);
+
+		if (isAvailable) {
+
+			// the case where this item is unavailable because of its
+			// children
+			if (!viewer.getExpandedState(item)) {
+				viewer.expandToLevel(item, AbstractTreeViewer.ALL_LEVELS);
+			}
+			MessageBox mb = new MessageBox(viewer.getControl().getShell(), SWT.OK | SWT.ICON_WARNING | SWT.SHEET);
+			mb.setText(WorkbenchMessages.get().HideItemsCannotMakeVisible_dialogTitle);
+			mb.setMessage(NLS.bind(WorkbenchMessages.get().HideItemsCannotMakeVisible_unavailableChildrenText,
+					item.getLabel()));
+			mb.open();
+		} else {
+			MessageBox mb;
+			if (item.getIContributionItem() instanceof HandledContributionItem) {
+				mb = new MessageBox(viewer.getControl().getShell(), SWT.OK | SWT.ICON_WARNING | SWT.SHEET);
+				mb.setText(WorkbenchMessages.get().HideItemsCannotMakeVisible_dialogTitle);
+				// the case of a command contribution which has its own
+				// enablement rules, e.g. "org.eclipse.ui.window.pinEditor"
+				// command
+				final String errorExplanation = NLS.bind(
+						WorkbenchMessages.get().HideItemsCannotMakeVisible_unavailableCommandItemText, item.getLabel());
+				mb.setMessage(errorExplanation);
+			} else {
+				// the case where this item is unavailable because it belongs to
+				// an unavailable action set
+				mb = new MessageBox(viewer.getControl().getShell(), SWT.YES | SWT.NO | SWT.ICON_WARNING | SWT.SHEET);
+				mb.setText(WorkbenchMessages.get().HideItemsCannotMakeVisible_dialogTitle);
+				final String errorExplanation = NLS.bind(
+						WorkbenchMessages.get().HideItemsCannotMakeVisible_unavailableCommandGroupText, item.getLabel(),
+						item.getActionSet());
+				final String message = NLS
+						.bind("{0}{1}{1}{2}", new Object[] { errorExplanation, CustomizePerspectiveDialog.NEW_LINE, WorkbenchMessages.get().HideItemsCannotMakeVisible_switchToCommandGroupTab }); //$NON-NLS-1$
+				mb.setMessage(message);
+			}
+			if (mb.open() == SWT.YES) {
+				dialog.showActionSet(item);
+			}
+		}
+	}
+
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dnd/AbstractDropTarget.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dnd/AbstractDropTarget.java
new file mode 100644
index 0000000..550ddae
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dnd/AbstractDropTarget.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.dnd;
+
+import org.eclipse.swt.graphics.Cursor;
+import org.eclipse.swt.graphics.Rectangle;
+
+/**
+ */
+public abstract class AbstractDropTarget implements IDropTarget {
+    @Override
+	public abstract void drop();
+
+    @Override
+	public abstract Cursor getCursor();
+
+    @Override
+	public Rectangle getSnapRectangle() {
+        return null;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dnd/CompatibilityDragTarget.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dnd/CompatibilityDragTarget.java
new file mode 100644
index 0000000..5dfd316
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dnd/CompatibilityDragTarget.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.dnd;
+
+import org.eclipse.jface.util.Geometry;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Control;
+
+/**
+ * Compatibility layer for the old-style drag-and-drop. Adapts an old-style
+ * IPartDropListener into an IDragTarget.
+ *
+ */
+public class CompatibilityDragTarget {
+
+    // Define width of part's "hot" border
+    private final static int MARGIN = 30;
+
+    /**
+     * Returns the relative position of the given point (in display coordinates)
+     * with respect to the given control. Returns one of SWT.LEFT, SWT.RIGHT, SWT.CENTER, SWT.TOP,
+     * or SWT.BOTTOM if the point is on the control or SWT.DEFAULT if the point is not on the control.
+     *
+     * @param control control to perform hit detection on
+     * @param toTest point to test, in display coordinates
+     * @return
+     */
+    public static int getRelativePosition(Control c, Point toTest) {
+        Point p = c.toControl(toTest);
+        Point e = c.getSize();
+
+        if (p.x > e.x || p.y > e.y || p.x < 0 || p.y < 0) {
+            return SWT.DEFAULT;
+        }
+
+        // first determine whether mouse position is in center of part
+        int hmargin = Math.min(e.x / 3, MARGIN);
+        int vmargin = Math.min(e.y / 3, MARGIN);
+
+        Rectangle inner = new Rectangle(hmargin, vmargin, e.x - (hmargin * 2),
+                e.y - (vmargin * 2));
+        if (inner.contains(p)) {
+            return SWT.CENTER;
+        } else {
+            return Geometry.getClosestSide(inner, p);
+        }
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dnd/DragBorder.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dnd/DragBorder.java
new file mode 100644
index 0000000..496bf79
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dnd/DragBorder.java
@@ -0,0 +1,145 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.dnd;
+
+import org.eclipse.jface.util.Geometry;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.themes.ColorUtil;
+
+/**
+ * Utility class that wraps a given control with a black 'border'. Moving the
+ * border control will cause the given control to move to stay within its bounds.
+ *
+ * @since 3.2
+ *
+ */
+public class DragBorder {
+	// Controls
+	private Composite clientControl = null;
+	private Control dragControl = null;
+	private Canvas border = null;
+
+	// Colors
+	private Color baseColor;
+	private Color hilightColor;
+	private boolean isHighlight;
+
+	/**
+	 * Construct a new DragBorder.
+	 *
+	 * @param client The client window that the border must stay within
+	 * @param toDrag The control to be placed 'inside' the border
+	 */
+	public DragBorder(Composite client, Control toDrag, boolean provideFrame) {
+		clientControl = client;
+		dragControl = toDrag;
+		Point dragSize = toDrag.getSize();
+
+		// Create a control large enough to 'contain' the dragged control
+		border = new Canvas(dragControl.getParent(), SWT.NONE);
+		border.setSize(dragSize.x+2, dragSize.y+2);
+
+		// Use the SWT 'title' colors since they should always have a proper contrast
+		// and are 'related' (i.e. should look good together)
+		baseColor = border.getDisplay().getSystemColor(SWT.COLOR_LIST_SELECTION);
+		RGB background  = border.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND).getRGB();
+		RGB blended = ColorUtil.blend(baseColor.getRGB(), background);
+		hilightColor = new Color(border.getDisplay(), blended);
+
+		// Ensure the border is visible and the control is 'above' it...
+		border.moveAbove(null);
+		dragControl.moveAbove(null);
+
+		if (provideFrame) {
+			border.addPaintListener(e -> {
+				if (isHighlight) {
+					e.gc.setForeground(hilightColor);
+				}
+				else {
+					e.gc.setForeground(baseColor);
+				}
+
+				// Draw a rectangle as our 'border'
+				Rectangle bb = border.getBounds();
+				e.gc.drawRectangle(0,0,bb.width-1, bb.height-1);
+			});
+		}
+	}
+
+
+    /**
+     * Move the border (and its 'contained' control to a new position. The new
+     * position will be adjusted to lie entirely within the client area of the
+     * <code>clientControl</code>.
+     *
+     * @param newPos The new position for the border
+     * @param alignment The location of the cursor relative to the border being dragged.
+     * Current implementation only recognizes SWT.TOP & SWT.BOTTOM (which implies SWT.LEFT)
+     * and SWT.CENTER (which centers teh dragged border on the cursor.
+     */
+    public void setLocation(Point newPos, int alignment) {
+		// Move the border but ensure that it is still inside the Client area
+    	if (alignment == SWT.CENTER) {
+    		Point size = border.getSize();
+    		border.setLocation(newPos.x - (size.x/2), newPos.y - (size.y/2));
+    	}
+    	else if (alignment == SWT.TOP) {
+    		border.setLocation(newPos.x, newPos.y);
+    	} else {
+			border.setLocation(newPos.x, newPos.y - border.getSize().y);
+		}
+
+    	// Force the control to remain inside the shell
+		Rectangle bb = border.getBounds();
+		Rectangle cr = clientControl.getClientArea();
+		Geometry.moveInside(bb,cr);
+
+		// Ensure that the controls are the 'topmost' controls
+		border.moveAbove(null);
+		dragControl.moveAbove(null);
+
+		// OK, now move the drag control and the border to their new locations
+		dragControl.setLocation(bb.x+1, bb.y+1);
+		border.setBounds(bb);
+    }
+
+	/**
+	 * Sets the hilight 'mode' for the control.
+	 * @param highlight true if the border should be drawn as 'hilighted'
+	 */
+	public void setHighlight(boolean highlight) {
+		isHighlight = highlight;
+		border.redraw();
+	}
+
+	/**
+	 * Dispose the controls owned by the border.
+	 */
+	public void dispose() {
+		hilightColor.dispose();
+		border.dispose();
+	}
+
+
+	/**
+	 * @return The bounds of the border's control.
+	 */
+	public Rectangle getBounds() {
+		return border.getBounds();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dnd/DragUtil.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dnd/DragUtil.java
new file mode 100644
index 0000000..f5e1eb4
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dnd/DragUtil.java
@@ -0,0 +1,401 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.dnd;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.jface.util.Geometry;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * Provides the methods for attaching drag-and-drop listeners to SWT controls.
+ */
+public class DragUtil {
+    private static final String DROP_TARGET_ID = "org.eclipse.ui.internal.dnd.dropTarget"; //$NON-NLS-1$
+
+    /**
+     * The location where all drags will end. If this is non-null, then
+     * all user input is ignored in drag/drop. If null, we use user input
+     * to determine where objects should be dropped.
+     */
+    private static TestDropLocation forcedDropTarget = null;
+
+    /**
+     * List of IDragOverListener
+     */
+    private static List defaultTargets = new ArrayList();
+
+    /**
+     * Sets the drop target for the given control. It is possible to add one or more
+     * targets for a "null" control. This becomes a default target that is used if no
+     * other targets are found (for example, when dragging objects off the application
+     * window).
+     *
+     * @param control the control that should be treated as a drag target, or null
+     * to indicate the default target
+     * @param target the drag target to handle the given control
+     */
+    public static void addDragTarget(Control control, IDragOverListener target) {
+        if (control == null) {
+            defaultTargets.add(target);
+        } else {
+            List targetList = getTargetList(control);
+
+            if (targetList == null) {
+                targetList = new ArrayList(1);
+            }
+            targetList.add(target);
+            control.setData(DROP_TARGET_ID, targetList);
+        }
+    }
+
+    /**
+     * Return the list of 'IDragOverListener' elements associated with
+     * the given control. If there's a 'global' listener then always
+     * return it.
+     *
+     * @param control
+     * @return
+     */
+    private static List getTargetList(Control control) {
+        List result = (List) control.getData(DROP_TARGET_ID);
+        return result;
+    }
+
+    /**
+     * Removes a drop target from the given control.
+     *
+     * @param control
+     * @param target
+     */
+    public static void removeDragTarget(Control control,
+            IDragOverListener target) {
+        if (control == null) {
+            defaultTargets.remove(target);
+        } else {
+            List targetList = getTargetList(control);
+            if (targetList != null) {
+                targetList.remove(target);
+                if (targetList.isEmpty()) {
+                    control.setData(DROP_TARGET_ID, null);
+                }
+            }
+        }
+    }
+
+    /**
+     * Shorthand method. Returns the bounding rectangle for the given control, in
+     * display coordinates. Note that all 'Shell' controls are expected to be 'top level'
+     * so DO NOT do the origin offset for them.
+     *
+     * @param draggedItem
+     * @param boundsControl
+     * @return
+     */
+    public static Rectangle getDisplayBounds(Control boundsControl) {
+        Control parent = boundsControl.getParent();
+        if (parent == null || boundsControl instanceof Shell) {
+            return boundsControl.getBounds();
+        }
+
+        return Geometry.toDisplay(parent, boundsControl.getBounds());
+    }
+
+//    public static boolean performDrag(final Object draggedItem,
+//            Rectangle sourceBounds, Point initialLocation, boolean allowSnapping) {
+//
+//        IDropTarget target = dragToTarget(draggedItem, sourceBounds,
+//                initialLocation, allowSnapping);
+//
+//        if (target == null) {
+//            return false;
+//        }
+//
+//        target.drop();
+//
+//        // If the target can handle a 'finished' notification then send one
+//        if (target!= null && target instanceof IDropTarget2) {
+//        	((IDropTarget2)target).dragFinished(true);
+//        }
+//
+//        return true;
+//    }
+
+    /**
+     * Drags the given item to the given location (in display coordinates). This
+     * method is intended for use by test suites.
+     *
+     * @param draggedItem object being dragged
+     * @param finalLocation location being dragged to
+     * @return true iff the drop was accepted
+     */
+    public static boolean dragTo(Display display, Object draggedItem,
+            Point finalLocation, Rectangle dragRectangle) {
+        Control currentControl = SwtUtil.findControl(display, finalLocation);
+
+        IDropTarget target = getDropTarget(currentControl, draggedItem,
+                finalLocation, dragRectangle);
+
+        if (target == null) {
+            return false;
+        }
+
+        target.drop();
+
+        return true;
+    }
+
+    /**
+     * Forces all drags to end at the given position (display coordinates). Intended
+     * for use by test suites. If this method is called, then all subsequent calls
+     * to performDrag will terminate immediately and behave as though the object were
+     * dragged to the given location. Calling this method with null cancels this
+     * behavior and causes performDrag to behave normally.
+     *
+     * @param forcedLocation location where objects will be dropped (or null to
+     * cause drag/drop to behave normally).
+     */
+    public static void forceDropLocation(TestDropLocation forcedLocation) {
+        forcedDropTarget = forcedLocation;
+    }
+
+//    /**
+//     * Drags the given item, given an initial bounding rectangle in display coordinates.
+//     * Due to a quirk in the Tracker class, changing the tracking rectangle when using the
+//     * keyboard will also cause the mouse cursor to move. Since "snapping" causes the tracking
+//     * rectangle to change based on the position of the mouse cursor, it is impossible to do
+//     * drag-and-drop with the keyboard when snapping is enabled.
+//     *
+//     * @param draggedItem object being dragged
+//     * @param sourceBounds initial bounding rectangle for the dragged item
+//     * @param initialLocation initial position of the mouse cursor
+//     * @param allowSnapping true iff the rectangle should snap to the drop location. This must
+//     * be false if the user might be doing drag-and-drop using the keyboard.
+//     *
+//     * @return
+//     */
+//    static IDropTarget dragToTarget(final Object draggedItem,
+//            final Rectangle sourceBounds, final Point initialLocation,
+//            final boolean allowSnapping) {
+//        final Display display = Display.getCurrent();
+//
+//        // Testing...immediately 'drop' onto the test target
+//        if (forcedDropTarget != null) {
+//            Point location = forcedDropTarget.getLocation();
+//
+//            Control currentControl = SwtUtil.findControl(forcedDropTarget.getShells(), location);
+//            return getDropTarget(currentControl, draggedItem, location,
+//                    sourceBounds);
+//        }
+//
+//        // Create a tracker.  This is just an XOR rect on the screen.
+//        // As it moves we notify the drag listeners.
+//        final Tracker tracker = new Tracker(display, SWT.NULL);
+//        tracker.setStippled(true);
+//
+//        tracker.addListener(SWT.Move, event -> display.syncExec(() -> {
+//			// Get the curslor location as a point
+//		    Point location = new Point(event.x, event.y);
+//
+//		    // Select a drop target; use the global one by default
+//			IDropTarget target = null;
+//
+//		    Control targetControl = display.getCursorControl();
+//
+//		    // Get the drop target for this location
+//		    target = getDropTarget(targetControl,
+//		            draggedItem, location,
+//		            tracker.getRectangles()[0]);
+//
+//			// Set up the tracker feedback based on the target
+//		    Rectangle snapTarget = null;
+//		    if (target != null) {
+//		        snapTarget = target.getSnapRectangle();
+//
+//		        tracker.setCursor(target.getCursor());
+//		    } else {
+//		        tracker.setCursor(DragCursors
+//		                .getCursor(DragCursors.INVALID));
+//		    }
+//
+//		    // If snapping then reset the tracker's rectangle based on the current drop target
+//		    if (allowSnapping) {
+//		        if (snapTarget == null) {
+//		            snapTarget = new Rectangle(sourceBounds.x
+//		                    + location.x - initialLocation.x,
+//		                    sourceBounds.y + location.y
+//		                            - initialLocation.y,
+//		                    sourceBounds.width, sourceBounds.height);
+//		        }
+//
+//		        // Try to prevent flicker: don't change the rectangles if they're already in
+//		        // the right location
+//		        Rectangle[] currentRectangles = tracker.getRectangles();
+//
+//		        if (!(currentRectangles.length == 1 && currentRectangles[0]
+//		                .equals(snapTarget))) {
+//					tracker.setRectangles(new Rectangle[] { Geometry.copy(snapTarget) });
+//		        }
+//		    }
+//		}));
+//
+//        // Setup...when the drag starts we might already be over a valid target, check this...
+//        // If there is a 'global' target then skip the check
+//        IDropTarget target = null;
+//        Control startControl = display.getCursorControl();
+//
+//        if (startControl != null && allowSnapping) {
+//            target = getDropTarget(startControl,
+//                draggedItem, initialLocation,
+//                sourceBounds);
+//        }
+//
+//        // Set up an initial tracker rectangle
+//        Rectangle startRect = sourceBounds;
+//        if (target != null) {
+//            Rectangle rect = target.getSnapRectangle();
+//
+//            if (rect != null) {
+//                startRect = rect;
+//            }
+//
+//            tracker.setCursor(target.getCursor());
+//        }
+//
+//        if (startRect != null) {
+//            tracker.setRectangles(new Rectangle[] { Geometry.copy(startRect)});
+//        }
+//
+//        // Tracking Loop...tracking is preformed on the 'SWT.Move' listener registered
+//        // against the tracker.
+//
+//        // HACK:
+//        // Some control needs to capture the mouse during the drag or other
+//        // controls will interfere with the cursor
+//        Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
+//        if (shell != null) {
+//            shell.setCapture(true);
+//        }
+//
+//        // Run tracker until mouse up occurs or escape key pressed.
+//        boolean trackingOk = tracker.open();
+//
+//        // HACK:
+//        // Release the mouse now
+//        if (shell != null) {
+//            shell.setCapture(false);
+//        }
+//
+//        // Done tracking...
+//
+//        // Get the current drop target
+//        IDropTarget dropTarget = null;
+//        Point finalLocation = display.getCursorLocation();
+//        Control targetControl = display.getCursorControl();
+//        dropTarget = getDropTarget(targetControl, draggedItem,
+//                finalLocation, tracker.getRectangles()[0]);
+//
+//        // Cleanup...
+//        tracker.dispose();
+//
+//        // if we're going to perform a 'drop' then delay the issuing of the 'finished'
+//        // callback until after it's done...
+//        if (trackingOk) {
+//        	return dropTarget;
+//        }
+//        else if (dropTarget!= null && dropTarget instanceof IDropTarget2) {
+//            // If the target can handle a 'finished' notification then send one
+//        	((IDropTarget2)dropTarget).dragFinished(false);
+//        }
+//
+//        return null;
+//    }
+
+    /**
+     * Given a list of IDragOverListeners and a description of what is being dragged, it returns
+     * a IDropTarget for the current drop.
+     *
+     * @param toSearch
+     * @param mostSpecificControl
+     * @param draggedObject
+     * @param position
+     * @param dragRectangle
+     * @return
+     */
+    private static IDropTarget getDropTarget(List toSearch,
+            Control mostSpecificControl, Object draggedObject, Point position,
+            Rectangle dragRectangle) {
+        if (toSearch == null) {
+            return null;
+        }
+
+        Iterator iter = toSearch.iterator();
+        while (iter.hasNext()) {
+            IDragOverListener next = (IDragOverListener) iter.next();
+
+            IDropTarget dropTarget = next.drag(mostSpecificControl,
+                    draggedObject, position, dragRectangle);
+
+            if (dropTarget != null) {
+                return dropTarget;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns the drag target for the given control or null if none.
+     *
+     * @param toSearch
+     * @param e
+     * @return
+     */
+    public static IDropTarget getDropTarget(Control toSearch,
+            Object draggedObject, Point position, Rectangle dragRectangle) {
+    	// Search for a listener by walking the control's parent hierarchy
+        for (Control current = toSearch; current != null; current = current
+                .getParent()) {
+            IDropTarget dropTarget = getDropTarget(getTargetList(current),
+                    toSearch, draggedObject, position, dragRectangle);
+
+            if (dropTarget != null) {
+                return dropTarget;
+            }
+
+            // Don't look to parent shells for drop targets
+            if (current instanceof Shell) {
+                break;
+            }
+        }
+
+        // No controls could handle this event -- check for default targets
+        return getDropTarget(defaultTargets, toSearch, draggedObject, position,
+                dragRectangle);
+    }
+
+    /**
+     * Returns the location of the given event, in display coordinates
+     * @return
+     */
+    public static Point getEventLoc(Event event) {
+        Control ctrl = (Control) event.widget;
+        return ctrl.toDisplay(new Point(event.x, event.y));
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dnd/IDragOverListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dnd/IDragOverListener.java
new file mode 100644
index 0000000..d0d0e91
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dnd/IDragOverListener.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.dnd;
+
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Control;
+
+/**
+ * Implementers of this interface will receive notifications when objects are dragged over
+ * a particular SWT control.
+ */
+public interface IDragOverListener {
+
+    /**
+     * Notifies the receiver that the given object has been dragged over
+     * the given position. Returns a drop target if the object may be
+     * dropped in this position. Returns null otherwise.
+     *
+     * @param draggedObject object being dragged over this location
+     * @param position location of the cursor
+     * @param dragRectangle current drag rectangle (may be an empty rectangle if none)
+     * @return a valid drop target or null if none
+     */
+    IDropTarget drag(Control currentControl, Object draggedObject,
+            Point position, Rectangle dragRectangle);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dnd/IDropTarget.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dnd/IDropTarget.java
new file mode 100644
index 0000000..c695f5f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dnd/IDropTarget.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.dnd;
+
+import org.eclipse.swt.graphics.Cursor;
+import org.eclipse.swt.graphics.Rectangle;
+
+/**
+ * This interface is used to drop objects. It knows how to drop a particular object
+ * in a particular location. IDropTargets are typically created by IDragOverListeners, and
+ * it is the job of the IDragOverListener to supply the drop target with information about
+ * the object currently being dragged.
+ *
+ * @see org.eclipse.ui.internal.dnd.IDragOverListener
+ */
+public interface IDropTarget {
+
+    /**
+     * Drops the object in this position
+     */
+    void drop();
+
+    /**
+     * Returns a cursor describing this drop operation
+     *
+     * @return a cursor describing this drop operation
+     */
+    Cursor getCursor();
+
+    /**
+     * Returns a rectangle (screen coordinates) describing the target location
+     * for this drop operation.
+     *
+     * @return a snap rectangle or null if this drop target does not have a specific snap
+     * location.
+     */
+    Rectangle getSnapRectangle();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dnd/IDropTarget2.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dnd/IDropTarget2.java
new file mode 100644
index 0000000..d0a5b01
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dnd/IDropTarget2.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.dnd;
+
+/**
+ * This interface allows a particular drop target to be informed that
+ * the drag operation was cancelled. This allows the target to clean
+ * up any extended drag feedback.
+ *
+ * @since 3.2
+ *
+ */
+public interface IDropTarget2 extends IDropTarget {
+	/**
+	 * This is called whenever a drag operation is cancelled
+	 */
+	public void dragFinished(boolean dropPerformed);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dnd/InsertCaret.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dnd/InsertCaret.java
new file mode 100644
index 0000000..748a0d2
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dnd/InsertCaret.java
@@ -0,0 +1,153 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.dnd;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.themes.ColorUtil;
+
+/**
+ * This class provides 'insertion' feedback to the User. It can be used to draw a
+ * 'bracket' based on the trim area's rectangle.
+ *
+ * @since 3.2
+ */
+public class InsertCaret {
+	// Constants
+	private static final int width = 6; // the handle's 'thickness'
+	private static final int pctInset = 10; // The percentage of the area left at each 'end'
+
+	// Control info
+	private Canvas caretControl;
+	private Canvas end1;
+	private Canvas end2;
+
+	// Colors
+	private Color baseColor;
+	private Color hilightColor;
+	private boolean isHighlight;
+
+	/**
+	 * Creates an affordance to indicate that the given trim area is a valid location for the
+	 * trim being dragged.
+	 *
+	 * @param windowComposite The window to create the affordance as a child of
+	 * @param trimRect The rectangle to show the affordance for
+	 * @param swtSide The 'side' that the rectangle is on
+	 * @param threshold The amount to offfset the affordance by
+	 */
+	public InsertCaret(Composite parent, Rectangle trimRect, int swtSide, int threshold) {
+		// Use the SWT 'title' colors since they should always have a proper contrast
+		// and are 'related' (i.e. should look good together)
+		baseColor = parent.getDisplay().getSystemColor(SWT.COLOR_LIST_SELECTION);
+		RGB background  = parent.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND).getRGB();
+		RGB blended = ColorUtil.blend(baseColor.getRGB(), background);
+		hilightColor = new Color(parent.getDisplay(), blended);
+
+		//Create the caret control
+		createControl(parent, trimRect, swtSide, threshold);
+	}
+
+	/**
+	 * Creates a control to show the 'area valid' affordance. The current implementation creates a
+	 * simple rect half the length of the rect, centered and offset by the 'threshold' value.
+	 *
+	 * @param parent The control to used as the parent of the affordance control
+	 * @param trimRect The trim rectangle
+	 * @param swtSide The SWT side that the trim is on
+	 * @param threshold The offset value
+	 */
+	private void createControl(Composite parent, Rectangle trimRect, int swtSide, int threshold) {
+		int hDelta = trimRect.width/pctInset;
+		int vDelta = trimRect.height/pctInset;
+		caretControl = new Canvas (parent.getShell(), SWT.BORDER);
+
+		end1 = new Canvas (parent.getShell(), SWT.BORDER);
+		end1.setSize(width, width);
+		end2 = new Canvas (parent.getShell(), SWT.BORDER);
+		end2.setSize(width, width);
+
+		Rectangle bb;
+		switch (swtSide) {
+		case SWT.TOP:
+			caretControl.setSize(trimRect.width-(2*hDelta), width);
+			caretControl.setLocation(trimRect.x + hDelta, trimRect.y + trimRect.height + threshold);
+			bb = caretControl.getBounds();
+			end1.setLocation(bb.x, bb.y-width);
+			end2.setLocation((bb.x+bb.width)-width, bb.y-width);
+			break;
+		case SWT.BOTTOM:
+			caretControl.setSize(trimRect.width-(2*hDelta), width);
+			caretControl.setLocation(trimRect.x + hDelta, trimRect.y - threshold);
+			bb = caretControl.getBounds();
+			end1.setLocation(bb.x, bb.y+width);
+			end2.setLocation((bb.x+bb.width)-width, bb.y+width);
+			break;
+		case SWT.LEFT:
+			caretControl.setSize(width, trimRect.height -(2*vDelta));
+			caretControl.setLocation(trimRect.x + trimRect.width + threshold,
+									trimRect.y + vDelta);
+			bb = caretControl.getBounds();
+			end1.setLocation(bb.x-bb.width, bb.y);
+			end2.setLocation(bb.x-bb.width, (bb.y+bb.height)-width);
+			break;
+		case SWT.RIGHT:
+			caretControl.setSize(width, trimRect.height -(2*vDelta));
+			caretControl.setLocation(trimRect.x - threshold,
+									trimRect.y + vDelta);
+			bb = caretControl.getBounds();
+			end1.setLocation(bb.x+bb.width, bb.y);
+			end2.setLocation(bb.x+bb.width, (bb.y+bb.height)-width);
+			break;
+		}
+
+		// Initially create as not hilighted
+		setHighlight(false);
+		caretControl.moveAbove(null);
+		end1.moveAbove(null);
+		end2.moveAbove(null);
+	}
+
+	/**
+	 * Sets the hilight 'mode' for the control.
+	 * @param highlight true if the caret should be drawn as 'hilighted'
+	 */
+	public void setHighlight(boolean highlight) {
+		isHighlight = highlight;
+
+		// if we're displaying as a 'bar' then set the control's background to the
+		// appropriate value
+		if (isHighlight) {
+			caretControl.setBackground(hilightColor);
+			end1.setBackground(hilightColor);
+			end2.setBackground(hilightColor);
+		}
+		else {
+			caretControl.setBackground(baseColor);
+			end1.setBackground(baseColor);
+			end2.setBackground(baseColor);
+		}
+	}
+
+	public void dispose() {
+		// Dispose the control's resources (we don't have to dispose the
+		// 'bacseColor' because it's a system color
+		hilightColor.dispose();
+
+		caretControl.dispose();
+		end1.dispose();
+		end2.dispose();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dnd/SwtUtil.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dnd/SwtUtil.java
new file mode 100644
index 0000000..18bdf54
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dnd/SwtUtil.java
@@ -0,0 +1,232 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.dnd;
+
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Monitor;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * Contains static methods for manipulating SWT controls
+ *
+ * @since 3.0
+ */
+public class SwtUtil {
+
+    private SwtUtil() {
+
+    }
+
+    /**
+     * Returns true if the given control is null or has been disposed
+     *
+     * @param toTest the control to test
+     * @return false if it is safe to invoke methods on the given control
+     */
+    public static boolean isDisposed(Control toTest) {
+        return toTest == null || toTest.isDisposed();
+    }
+
+    /**
+     * Returns the control that is covering the given control, or null if none.
+     *
+     * @param toTest control to test
+     * @return a control that obscures the test control or null if none
+     */
+    public static Control controlThatCovers(Control toTest) {
+        return controlThatCovers(toTest, DragUtil.getDisplayBounds(toTest));
+    }
+
+    private static Control controlThatCovers(Control toTest, Rectangle testRegion) {
+        Composite parent = toTest.getParent();
+
+        if (parent == null || toTest instanceof Shell) {
+            return null;
+        }
+
+		for (Control element : parent.getChildren()) {
+            Control control = element;
+
+            if (control == toTest) {
+                break;
+            }
+
+            if (!control.isVisible()) {
+                continue;
+            }
+
+            Rectangle nextBounds = DragUtil.getDisplayBounds(control);
+
+            if (nextBounds.intersects(testRegion)) {
+                return control;
+            }
+        }
+
+        return controlThatCovers(parent, testRegion);
+    }
+
+    /**
+	 * Determines if one control is a child of another.
+	 *
+	 * @param potentialParent
+	 * @param childToTest
+	 * @return <code>true</code> if the second argument is a child of the first
+	 *         or the same object, <code>false</code> otherwise
+	 */
+    public static boolean isChild(Control potentialParent, Control childToTest) {
+        if (childToTest == null) {
+            return false;
+        }
+
+        if (childToTest == potentialParent) {
+            return true;
+        }
+
+        return isChild(potentialParent, childToTest.getParent());
+    }
+
+    public static boolean isFocusAncestor(Control potentialParent) {
+		if (potentialParent == null)
+			return false;
+        Control focusControl = Display.getCurrent().getFocusControl();
+        if (focusControl == null) {
+            return false;
+        }
+        return isChild(potentialParent, focusControl);
+    }
+
+    /**
+	 * Finds and returns the most specific SWT control at the given location.
+	 * (Note: this does a DFS on the SWT widget hierarchy, which is slow).
+	 *
+	 * @param displayToSearch
+	 * @param locationToFind
+	 * @return the most specific SWT control at the given location
+	 */
+    public static Control findControl(Display displayToSearch,
+            Point locationToFind) {
+        Shell[] shells = displayToSearch.getShells();
+
+        return findControl(shells, locationToFind);
+    }
+
+    /**
+     * Searches the given list of controls for a control containing the given point.
+     * If the array contains any composites, those composites will be recursively
+     * searched to find the most specific child that contains the point.
+     *
+     * @param toSearch an array of composites
+     * @param locationToFind a point (in display coordinates)
+     * @return the most specific Control that overlaps the given point, or null if none
+     */
+    public static Control findControl(Control[] toSearch, Point locationToFind) {
+        for (int idx = toSearch.length - 1; idx >= 0; idx--) {
+            Control next = toSearch[idx];
+
+            if (!next.isDisposed() && next.isVisible()) {
+
+                Rectangle bounds = DragUtil.getDisplayBounds(next);
+
+                if (bounds.contains(locationToFind)) {
+                    if (next instanceof Composite) {
+                        Control result = findControl((Composite) next,
+                                locationToFind);
+
+                        if (result != null) {
+                            return result;
+                        }
+                    }
+
+                    return next;
+                }
+            }
+        }
+
+        return null;
+    }
+
+    public static Control[] getAncestors(Control theControl) {
+        return getAncestors(theControl, 1);
+    }
+
+    private static Control[] getAncestors(Control theControl, int children) {
+        Control[] result;
+
+        if (theControl.getParent() == null) {
+            result = new Control[children];
+        } else {
+            result = getAncestors(theControl.getParent(), children + 1);
+        }
+
+        result[result.length - children] = theControl;
+
+        return result;
+    }
+
+    public static Control findCommonAncestor(Control control1, Control control2) {
+        Control[] control1Ancestors = getAncestors(control1);
+        Control[] control2Ancestors = getAncestors(control2);
+
+        Control mostSpecific = null;
+
+        for (int idx = 0; idx < Math.min(control1Ancestors.length, control2Ancestors.length); idx++) {
+            Control control1Ancestor = control1Ancestors[idx];
+            if (control1Ancestor == control2Ancestors[idx]) {
+                mostSpecific = control1Ancestor;
+            } else {
+                break;
+            }
+        }
+
+        return mostSpecific;
+    }
+
+    /**
+	 * Finds the control at the given location.
+	 *
+	 * @param toSearch
+	 * @param locationToFind
+	 *            location (in display coordinates)
+	 * @return the control at the given location
+	 */
+    public static Control findControl(Composite toSearch, Point locationToFind) {
+        Control[] children = toSearch.getChildren();
+
+        return findControl(children, locationToFind);
+    }
+
+    /**
+	 *
+	 * Returns true iff the given rectangle is located in the client area of any
+	 * monitor.
+	 *
+	 * @param display
+	 *            the display
+	 * @param someRectangle
+	 *            a rectangle in display coordinates (not null)
+	 * @return true iff the given point can be seen on any monitor
+	 */
+    public static boolean intersectsAnyMonitor(Display display,
+            Rectangle someRectangle) {
+		for (Monitor monitor : display.getMonitors()) {
+			if (monitor.getClientArea().intersects(someRectangle)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dnd/TestDropLocation.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dnd/TestDropLocation.java
new file mode 100644
index 0000000..05bab03
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/dnd/TestDropLocation.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.dnd;
+
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * This is an interface intended for use in test suites. Objects can implement
+ * this interface to force any dragged object to be dropped at a particular
+ * location.
+ *
+ * @since 3.0
+ */
+public interface TestDropLocation {
+
+    /**
+     * Location where the object should be dropped, in display coordinates
+     *
+     * @return a location in display coordinates
+     */
+    public Point getLocation();
+
+    /**
+     * The drop code will pretend that only the given shells are open,
+     * and that they have the specified Z-order.
+     *
+     * @return the shells to check for drop targets, from bottom to top.
+     */
+    public Shell[] getShells();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/compatibility/ActionBars.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/compatibility/ActionBars.java
new file mode 100644
index 0000000..c9307d5
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/compatibility/ActionBars.java
@@ -0,0 +1,182 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2015 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.ui.internal.e4.compatibility;
+
+import org.eclipse.e4.ui.model.application.ui.MElementContainer;
+import org.eclipse.e4.ui.model.application.ui.MGenericStack;
+import org.eclipse.e4.ui.model.application.ui.MUIElement;
+import org.eclipse.e4.ui.model.application.ui.advanced.MPlaceholder;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.model.application.ui.basic.MPartStack;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolBar;
+import org.eclipse.e4.ui.workbench.renderers.swt.StackRenderer;
+import org.eclipse.e4.ui.workbench.renderers.swt.ToolBarManagerRenderer;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.ToolBarManager;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CTabFolder;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.SubActionBars;
+import org.eclipse.ui.services.IServiceLocator;
+
+public class ActionBars extends SubActionBars {
+
+	private IToolBarManager toolbarManager;
+
+	private IMenuManager menuManager;
+
+	private MPart part;
+
+	public ActionBars(final IActionBars parent, final IServiceLocator serviceLocator, MPart part) {
+		super(parent, serviceLocator);
+		this.part = part;
+	}
+
+	@Override
+	public IMenuManager getMenuManager() {
+		if (menuManager == null) {
+			menuManager = new MenuManager();
+		}
+		return menuManager;
+	}
+
+
+	@Override
+	public IToolBarManager getToolBarManager() {
+		if (toolbarManager == null) {
+			toolbarManager = new ToolBarManager(SWT.FLAT | SWT.RIGHT | SWT.WRAP);
+		}
+		return toolbarManager;
+	}
+
+	@Override
+	public void updateActionBars() {
+		// FIXME compat: updateActionBars : should do something useful
+		getStatusLineManager().update(false);
+		getMenuManager().update(false);
+		if (toolbarManager != null) {
+			//			System.err.println("update toolbar manager for " + part.getElementId()); //$NON-NLS-1$
+			if (toolbarManager instanceof ToolBarManager) {
+				ToolBarManager tbm = (ToolBarManager) toolbarManager;
+				Control tbCtrl = tbm.getControl();
+				if (tbCtrl == null || tbCtrl.isDisposed()) {
+					if (part.getContext() != null) {
+						// TODO what to do
+					}
+				} else {
+					tbm.update(true);
+					if (!tbCtrl.isDisposed()) {
+						Control packParent = getPackParent(tbCtrl);
+						packParent.pack();
+
+						// Specifically lay out the CTF
+						if (packParent.getParent() instanceof CTabFolder)
+							packParent.getParent().layout(true);
+					}
+				}
+			} else {
+				toolbarManager.update(false);
+			}
+
+			MToolBar toolbar = part.getToolbar();
+			if (toolbar != null) {
+				Object renderer = toolbar.getRenderer();
+				if (renderer instanceof ToolBarManagerRenderer) {
+					// update the mapping of opaque items
+					((ToolBarManagerRenderer) renderer).reconcileManagerToModel(toolbarManager,
+							toolbar);
+				}
+			}
+		}
+
+		MUIElement parent = getParentModel();
+		if (parent != null && isOnTop()) {
+			Object renderer = parent.getRenderer();
+			if (renderer instanceof StackRenderer) {
+				StackRenderer stackRenderer = (StackRenderer) renderer;
+				CTabFolder folder = (CTabFolder) parent.getWidget();
+				stackRenderer.adjustTopRight(folder);
+			}
+		}
+
+		super.updateActionBars();
+	}
+
+	private MUIElement getParentModel() {
+		MElementContainer<MUIElement> parent = part.getParent();
+		if (parent == null) {
+			MPlaceholder placeholder = part.getCurSharedRef();
+			return placeholder == null ? null : placeholder.getParent();
+		}
+		return parent;
+	}
+
+	private boolean isOnTop() {
+		MUIElement parentModel = getParentModel();
+		if (parentModel.getRenderer() instanceof StackRenderer) {
+			MPartStack stack = (MPartStack) parentModel;
+			if (stack.getSelectedElement() == part)
+				return true;
+			if (stack.getSelectedElement() instanceof MPlaceholder) {
+				MPlaceholder ph = (MPlaceholder) stack.getSelectedElement();
+				return ph.getRef() == part;
+			}
+		}
+
+		return true;
+	}
+
+	private Control getPackParent(Control control) {
+		Composite parent = control.getParent();
+		while (parent != null) {
+			if (parent instanceof CTabFolder) {
+				Control topRight = ((CTabFolder) parent).getTopRight();
+				if (topRight != null) {
+					return topRight;
+				}
+				break;
+			}
+			parent = parent.getParent();
+		}
+		return control.getParent();
+	}
+
+	boolean isSelected(MPart part) {
+		MElementContainer<?> parent = part.getParent();
+		if (parent == null) {
+			MPlaceholder placeholder = part.getCurSharedRef();
+			if (placeholder == null) {
+				return false;
+			}
+
+			parent = placeholder.getParent();
+			return parent instanceof MGenericStack ? parent.getSelectedElement() == placeholder
+					: parent != null;
+		}
+		return parent instanceof MGenericStack ? parent.getSelectedElement() == part
+				: parent != null;
+	}
+
+	@Override
+	public void dispose() {
+		menuManager.dispose();
+		if (toolbarManager instanceof ToolBarManager) {
+			((ToolBarManager) toolbarManager).dispose();
+		}
+		super.dispose();
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/compatibility/CompatibilityEditor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/compatibility/CompatibilityEditor.java
new file mode 100644
index 0000000..0f5669a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/compatibility/CompatibilityEditor.java
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 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.ui.internal.e4.compatibility;
+
+import javax.inject.Inject;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+import org.eclipse.e4.ui.workbench.modeling.EPartService;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorRegistry;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.internal.EditorActionBars;
+import org.eclipse.ui.internal.EditorReference;
+import org.eclipse.ui.internal.PartSite;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPartReference;
+import org.eclipse.ui.internal.menus.MenuHelper;
+import org.eclipse.ui.internal.registry.EditorDescriptor;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.testing.ContributionInfoMessages;
+import org.eclipse.ui.part.AbstractMultiEditor;
+import org.eclipse.ui.part.MultiEditor;
+import org.eclipse.ui.part.MultiEditorInput;
+import org.eclipse.ui.testing.ContributionInfo;
+
+public class CompatibilityEditor extends CompatibilityPart {
+
+	public static final String MODEL_ELEMENT_ID = "org.eclipse.e4.ui.compatibility.editor"; //$NON-NLS-1$
+
+	private EditorReference reference;
+
+	@Inject
+	private EModelService modelService;
+
+	@Inject
+	CompatibilityEditor(MPart part, EditorReference ref) {
+		super(part);
+		reference = ref;
+
+		if (!part.getTags().contains(EPartService.REMOVE_ON_HIDE_TAG)) {
+			part.getTags().add(EPartService.REMOVE_ON_HIDE_TAG);
+		}
+	}
+
+	@Override
+	IWorkbenchPart createPart(WorkbenchPartReference reference) throws PartInitException {
+		IWorkbenchPart part = super.createPart(reference);
+		IEditorInput input = ((EditorReference) reference).getEditorInput();
+		if (input instanceof MultiEditorInput && part instanceof MultiEditor) {
+			createMultiEditorChildren(part, input);
+		}
+		return part;
+	}
+
+	private void createMultiEditorChildren(IWorkbenchPart part, IEditorInput input)
+			throws PartInitException {
+		IWorkbenchPage page = reference.getPage();
+		MPart model = getModel();
+		MWindow window = modelService.getTopLevelWindowFor(model);
+		IEditorRegistry registry = model.getContext().get(IEditorRegistry.class);
+		MultiEditorInput multiEditorInput = (MultiEditorInput) input;
+		IEditorInput[] inputs = multiEditorInput.getInput();
+		String[] editorIds = multiEditorInput.getEditors();
+		IEditorPart[] editors = new IEditorPart[editorIds.length];
+		for (int i = 0; i < editorIds.length; i++) {
+			EditorDescriptor innerDesc = (EditorDescriptor) registry.findEditor(editorIds[i]);
+			if (innerDesc == null) {
+				throw new PartInitException(NLS.bind(
+						WorkbenchMessages.get().EditorManager_unknownEditorIDMessage, editorIds[i]));
+			}
+
+			EditorReference innerReference = new EditorReference(window.getContext(), page, model,
+					inputs[i], innerDesc, null);
+			editors[i] = (IEditorPart) innerReference.createPart();
+			innerReference.initialize(editors[i]);
+		}
+
+		((AbstractMultiEditor) part).setChildren(editors);
+	}
+
+	@Override
+	protected boolean createPartControl(final IWorkbenchPart legacyPart, Composite parent) {
+		super.createPartControl(legacyPart, parent);
+
+		clearMenuItems();
+
+		part.getContext().set(IEditorPart.class, (IEditorPart) legacyPart);
+
+		EditorDescriptor descriptor = reference.getDescriptor();
+		if (descriptor != null) {
+			IConfigurationElement element = descriptor.getConfigurationElement();
+			if (element != null) {
+				String iconURI = MenuHelper.getIconURI(element,
+						IWorkbenchRegistryConstants.ATT_ICON);
+				part.setIconURI(iconURI);
+			}
+			if (descriptor.getPluginId() != null) {
+				parent.setData(new ContributionInfo(descriptor.getPluginId(),
+						ContributionInfoMessages.ContributionInfo_Editor, null));
+			}
+		}
+
+		if (legacyPart instanceof AbstractMultiEditor && !(legacyPart instanceof MultiEditor)) {
+			try {
+				createMultiEditorChildren(legacyPart, reference.getEditorInput());
+			} catch (PartInitException e) {
+				handlePartInitException(e);
+				return false;
+			}
+		}
+
+		return true;
+	}
+
+	public IEditorPart getEditor() {
+		return (IEditorPart) getPart();
+	}
+
+	@Override
+	public WorkbenchPartReference getReference() {
+		return reference;
+	}
+
+	@Override
+	void disposeSite(PartSite site) {
+		EditorActionBars bars = (EditorActionBars) site.getActionBars();
+		EditorReference.disposeEditorActionBars(bars);
+		super.disposeSite(site);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/compatibility/CompatibilityPart.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/compatibility/CompatibilityPart.java
new file mode 100644
index 0000000..41ac86c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/compatibility/CompatibilityPart.java
@@ -0,0 +1,471 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2016 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
+ *     Steven Spungin <steven@spungin.tv> - Bug 436908
+ *     Andrey Loskutov <loskutov@gmx.de> - Bug 372799, 446864
+ *     Snjezana Peco <snjezana.peco@redhat.com> - Bug 414888
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 503379
+ ******************************************************************************/
+
+package org.eclipse.ui.internal.e4.compatibility;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.e4.core.contexts.ContextInjectionFactory;
+import org.eclipse.e4.core.services.events.IEventBroker;
+import org.eclipse.e4.core.services.log.Logger;
+import org.eclipse.e4.ui.di.Focus;
+import org.eclipse.e4.ui.di.Persist;
+import org.eclipse.e4.ui.di.PersistState;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.model.application.ui.menu.MMenu;
+import org.eclipse.e4.ui.workbench.IPresentationEngine;
+import org.eclipse.e4.ui.workbench.UIEvents;
+import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
+import org.eclipse.jface.viewers.IPostSelectionProvider;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.ISaveablePart;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPart2;
+import org.eclipse.ui.IWorkbenchPartConstants;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.internal.ErrorEditorPart;
+import org.eclipse.ui.internal.ErrorViewPart;
+import org.eclipse.ui.internal.IWorkbenchConstants;
+import org.eclipse.ui.internal.PartSite;
+import org.eclipse.ui.internal.SaveableHelper;
+import org.eclipse.ui.internal.WorkbenchPage;
+import org.eclipse.ui.internal.WorkbenchPartReference;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.util.Util;
+import org.eclipse.ui.part.IWorkbenchPartOrientation;
+import org.osgi.service.event.EventHandler;
+
+public abstract class CompatibilityPart implements ISelectionChangedListener {
+
+	public static final String COMPATIBILITY_EDITOR_URI = "bundleclass://org.eclipse.rap.ui.workbench/org.eclipse.ui.internal.e4.compatibility.CompatibilityEditor"; //$NON-NLS-1$
+
+	public static final String COMPATIBILITY_VIEW_URI = "bundleclass://org.eclipse.rap.ui.workbench/org.eclipse.ui.internal.e4.compatibility.CompatibilityView"; //$NON-NLS-1$
+
+	public static final String ENABLE_DEPENDENCY_INJECTION_FOR_E3_PARTS = "ENABLE_DEPENDENCY_INJECTION_FOR_E3"; ////$NON-NLS-1$
+
+	@Inject
+	Composite composite;
+
+	@Inject
+	Logger logger;
+
+	IWorkbenchPart wrapped;
+
+	MPart part;
+
+	@Inject
+	private IEventBroker eventBroker;
+
+	private boolean beingDisposed = false;
+
+	private boolean alreadyDisposed = false;
+
+	private boolean focusDelegatingInProgress;
+
+	/**
+	 * This handler will be notified when the part's widget has been un/set.
+	 */
+	private EventHandler widgetSetHandler = event -> {
+		// check that we're looking at our own part and that the widget is
+		// being unset
+		if (event.getProperty(UIEvents.EventTags.ELEMENT) == part
+				&& event.getProperty(UIEvents.EventTags.NEW_VALUE) == null) {
+			 Assert.isTrue(!composite.isDisposed(),
+									"The widget should not have been disposed at this point"); //$NON-NLS-1$
+			beingDisposed = true;
+			WorkbenchPartReference reference = getReference();
+			// notify the workbench we're being closed
+			((WorkbenchPage) reference.getPage()).firePartDeactivatedIfActive(part);
+			((WorkbenchPage) reference.getPage()).firePartHidden(part);
+			((WorkbenchPage) reference.getPage()).firePartClosed(CompatibilityPart.this);
+		}
+	};
+
+	/**
+	 * This handler will be notified when the part's client object has been
+	 * un/set.
+	 */
+	private EventHandler objectSetHandler = event -> {
+		// check that we're looking at our own part and that the object is
+		// being set
+		if (event.getProperty(UIEvents.EventTags.ELEMENT) == part
+				&& event.getProperty(UIEvents.EventTags.NEW_VALUE) != null) {
+			WorkbenchPartReference reference = getReference();
+			// notify the workbench we've been opened
+			((WorkbenchPage) reference.getPage()).firePartOpened(CompatibilityPart.this);
+		}
+	};
+
+	private ISelectionChangedListener postListener = e -> {
+		ESelectionService selectionService = part.getContext().get(ESelectionService.class);
+		selectionService.setPostSelection(e.getSelection());
+	};
+
+	private IWorkbenchPart legacyPart;
+
+	CompatibilityPart(MPart part) {
+		this.part = part;
+	}
+
+	@PersistState
+	void persistState() {
+		ContextInjectionFactory.invoke(wrapped, PersistState.class, part.getContext(), null);
+	}
+
+	public abstract WorkbenchPartReference getReference();
+
+	protected boolean createPartControl(final IWorkbenchPart legacyPart, Composite parent) {
+		this.legacyPart = legacyPart;
+		IWorkbenchPartSite site = null;
+		try {
+			site = legacyPart.getSite();
+			part.getContext().set(Composite.class, parent);
+			// call createPartControl after dependency injection
+			if (part.getTags().contains(IWorkbenchConstants.TAG_USE_DEPENDENCY_INJECTION)) {
+				ContextInjectionFactory.inject(legacyPart, part.getContext());
+			}
+			legacyPart.createPartControl(parent);
+
+		} catch (RuntimeException e) {
+			logger.error(e);
+
+			try {
+				// couldn't create the part, dispose of it
+				legacyPart.dispose();
+			} catch (Exception ex) {
+				// client code may have errors so we need to catch it
+				logger.error(ex);
+			}
+
+			// dispose the site that was originally initialized for this part
+			internalDisposeSite(site);
+
+			// create a new error part notifying the user of the failure
+			IStatus status = new Status(IStatus.ERROR, WorkbenchPlugin.PI_WORKBENCH,
+					"Failed to create the part's controls", e); //$NON-NLS-1$
+			WorkbenchPartReference reference = getReference();
+			wrapped = reference.createErrorPart(status);
+			try {
+				reference.initialize(wrapped);
+				wrapped.createPartControl(parent);
+			} catch (RuntimeException ex) {
+				// failed to create the error part, log it
+				logger.error(ex);
+			} catch (PartInitException ex) {
+				WorkbenchPlugin.log("Unable to initialize error part", ex.getStatus()); //$NON-NLS-1$
+			}
+		}
+
+		if (site != null) {
+			ISelectionProvider selectionProvider = site.getSelectionProvider();
+			if (selectionProvider != null) {
+				selectionProvider.addSelectionChangedListener(this);
+
+				if (selectionProvider instanceof IPostSelectionProvider) {
+					((IPostSelectionProvider) selectionProvider)
+							.addPostSelectionChangedListener(postListener);
+				} else {
+					selectionProvider.addSelectionChangedListener(postListener);
+				}
+				ESelectionService selectionService = part.getContext().get(ESelectionService.class);
+				selectionService.setSelection(selectionProvider.getSelection());
+			}
+		}
+		return true;
+	}
+
+	@Focus
+	void delegateSetFocus() {
+		if (focusDelegatingInProgress) {
+			if (logger != null && logger.isDebugEnabled()) {
+				logger.debug("Ignored attempt to set focus during set focus for: " + this); //$NON-NLS-1$
+			}
+			return;
+		}
+		focusDelegatingInProgress = true;
+		try {
+			// first involve @Focus if present
+			if (part.getTags().contains(IWorkbenchConstants.TAG_USE_DEPENDENCY_INJECTION)) {
+				ContextInjectionFactory.invoke(wrapped, Focus.class, part.getContext(), null);
+			}
+			// ensure to comply to the 3.x API contract
+			wrapped.setFocus();
+		} catch (Exception e) {
+			if (logger != null) {
+				String msg = "Error setting focus to : " + part.getClass().getName(); //$NON-NLS-1$
+				msg += ' ' + part.getLocalizedLabel();
+				logger.error(e, msg);
+			}
+		} finally {
+			focusDelegatingInProgress = false;
+		}
+	}
+
+	private void invalidate() {
+		IWorkbenchPartSite site = null;
+		if (wrapped != null) {
+			site = wrapped.getSite();
+			if (site != null) {
+				ISelectionProvider selectionProvider = site.getSelectionProvider();
+				if (selectionProvider != null) {
+					selectionProvider.removeSelectionChangedListener(this);
+
+					if (selectionProvider instanceof IPostSelectionProvider) {
+						((IPostSelectionProvider) selectionProvider)
+								.removePostSelectionChangedListener(postListener);
+					} else {
+						selectionProvider.removeSelectionChangedListener(postListener);
+					}
+				}
+			}
+		}
+
+		WorkbenchPartReference reference = getReference();
+		reference.invalidate();
+
+		if (wrapped != null) {
+			try {
+				wrapped.dispose();
+			} catch (Exception e) {
+				// client code may have errors so we need to catch it
+				logger.error(e);
+			}
+			wrapped = null;
+		}
+
+		internalDisposeSite(site);
+		alreadyDisposed = true;
+	}
+
+	private String computeLabel() {
+		if (wrapped instanceof IWorkbenchPart2) {
+			String label = ((IWorkbenchPart2) wrapped).getPartName();
+			return Util.safeString(label);
+		}
+
+		IWorkbenchPartSite site = wrapped.getSite();
+		if (site != null) {
+			return Util.safeString(site.getRegisteredName());
+		}
+		return Util.safeString(wrapped.getTitle());
+	}
+
+	/**
+	 * Returns whether this part is being disposed. This is used for
+	 * invalidating this part so that it is not returned when a method expects a
+	 * "working" part.
+	 * <p>
+	 * See bug 308492.
+	 * </p>
+	 *
+	 * @return if the part is currently being disposed
+	 */
+	public boolean isBeingDisposed() {
+		return beingDisposed;
+	}
+
+	IWorkbenchPart createPart(WorkbenchPartReference reference) throws PartInitException {
+		// ask our reference to instantiate the part through the registry
+		return reference.createPart();
+	}
+
+	boolean handlePartInitException(PartInitException e) {
+		WorkbenchPartReference reference = getReference();
+		IWorkbenchPartSite site = reference.getSite();
+		reference.invalidate();
+		if (wrapped instanceof IEditorPart) {
+			try {
+				wrapped.dispose();
+			} catch (Exception ex) {
+				// client code may have errors so we need to catch it
+				logger.error(ex);
+			}
+		}
+		internalDisposeSite(site);
+
+		alreadyDisposed = false;
+		WorkbenchPlugin.log("Unable to create part", e.getStatus()); //$NON-NLS-1$
+
+		wrapped = reference.createErrorPart(e.getStatus());
+		try {
+			reference.initialize(wrapped);
+		} catch (PartInitException ex) {
+			WorkbenchPlugin.log("Unable to initialize error part", ex.getStatus()); //$NON-NLS-1$
+			return false;
+		}
+		return true;
+	}
+
+	@PostConstruct
+	public void create() {
+		eventBroker.subscribe(UIEvents.UIElement.TOPIC_WIDGET, widgetSetHandler);
+		eventBroker.subscribe(UIEvents.Contribution.TOPIC_OBJECT, objectSetHandler);
+
+		WorkbenchPartReference reference = getReference();
+
+		try {
+			wrapped = createPart(reference);
+			// invoke init methods
+			reference.initialize(wrapped);
+		} catch (PartInitException e) {
+			if (!handlePartInitException(e)) {
+				return;
+			}
+		} catch (Exception e) {
+			WorkbenchPlugin.log("Unable to initialize part", e); //$NON-NLS-1$
+			if (!handlePartInitException(new PartInitException(e.getMessage()))) {
+				return;
+			}
+		}
+
+		// hook reference listeners to the part
+		// reference.hookPropertyListeners();
+
+		int style = SWT.NONE;
+		if (wrapped instanceof IWorkbenchPartOrientation) {
+			style = ((IWorkbenchPartOrientation) wrapped).getOrientation();
+		}
+
+		Composite parent = new Composite(composite, style);
+		parent.setLayout(new FillLayout());
+		if (!createPartControl(wrapped, parent)) {
+			return;
+		}
+
+		// Only update 'valid' parts
+		if (!(wrapped instanceof ErrorEditorPart) && !(wrapped instanceof ErrorViewPart)) {
+			part.setLabel(computeLabel());
+			part.getTransientData().put(IPresentationEngine.OVERRIDE_TITLE_TOOL_TIP_KEY, wrapped.getTitleToolTip());
+			part.getTransientData().put(IPresentationEngine.OVERRIDE_ICON_IMAGE_KEY, wrapped.getTitleImage());
+		}
+
+		ISaveablePart saveable = SaveableHelper.getSaveable(wrapped);
+		if (saveable != null && SaveableHelper.isDirtyStateSupported(wrapped)) {
+			part.setDirty(saveable.isDirty());
+		}
+
+		wrapped.addPropertyListener((source, propId) -> {
+			switch (propId) {
+			case IWorkbenchPartConstants.PROP_TITLE:
+				part.setLabel(computeLabel());
+
+				if (wrapped.getTitleImage() != null) {
+					Image newImage = wrapped.getTitleImage();
+					part.getTransientData().put(IPresentationEngine.OVERRIDE_ICON_IMAGE_KEY,
+							newImage);
+				}
+				String titleToolTip = wrapped.getTitleToolTip();
+				if (titleToolTip != null) {
+					part.getTransientData().put(IPresentationEngine.OVERRIDE_TITLE_TOOL_TIP_KEY, titleToolTip);
+				}
+				break;
+			case IWorkbenchPartConstants.PROP_DIRTY:
+				boolean supportsDirtyState = SaveableHelper.isDirtyStateSupported(wrapped);
+				if (!supportsDirtyState) {
+					part.setDirty(false);
+					return;
+				}
+				ISaveablePart saveable1 = SaveableHelper.getSaveable(wrapped);
+				if (saveable1 != null) {
+					part.setDirty(saveable1.isDirty());
+				} else if (part.isDirty()) {
+					// reset if the wrapped legacy part do not exposes
+					// saveable adapter anymore, see bug 495567 comment 6
+					part.setDirty(false);
+				}
+				break;
+			case IWorkbenchPartConstants.PROP_INPUT:
+				WorkbenchPartReference ref = getReference();
+				((WorkbenchPage) ref.getSite().getPage()).firePartInputChanged(ref);
+				break;
+			}
+		});
+	}
+
+	@PreDestroy
+	void destroy() {
+		if (!alreadyDisposed) {
+			invalidate();
+		}
+
+		eventBroker.unsubscribe(widgetSetHandler);
+		eventBroker.unsubscribe(objectSetHandler);
+	}
+
+	/**
+	 * Disposes of the 3.x part's site if it has one. Subclasses may override
+	 * but must call <code>super.disposeSite()</code> in its implementation.
+	 */
+	private void internalDisposeSite(IWorkbenchPartSite site) {
+		if (site instanceof PartSite) {
+			disposeSite((PartSite) site);
+		}
+	}
+
+	/**
+	 * Disposes of the 3.x part's site if it has one. Subclasses may override
+	 * but must call <code>super.disposeSite()</code> in its implementation.
+	 */
+	void disposeSite(PartSite site) {
+		site.dispose();
+		if (part.getTags().contains(IWorkbenchConstants.TAG_USE_DEPENDENCY_INJECTION)) {
+			ContextInjectionFactory.uninject(legacyPart, part.getContext());
+		}
+	}
+
+	@Persist
+	void doSave() {
+		ISaveablePart saveable = SaveableHelper.getSaveable(wrapped);
+		if (saveable != null) {
+			SaveableHelper.savePart(saveable, wrapped, getReference().getSite()
+					.getWorkbenchWindow(), false);
+		}
+		// ContextInjectionFactory.invoke(wrapped, Persist.class, part.getContext(), null);
+	}
+
+	public IWorkbenchPart getPart() {
+		return wrapped;
+	}
+
+	public MPart getModel() {
+		return part;
+	}
+
+	@Override
+	public void selectionChanged(SelectionChangedEvent e) {
+		ESelectionService selectionService = part.getContext().get(ESelectionService.class);
+		selectionService.setSelection(e.getSelection());
+	}
+
+	protected void clearMenuItems() {
+		// in the workbench, view menus are re-created on startup
+		for (MMenu menu : part.getMenus()) {
+			menu.getChildren().clear();
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/compatibility/CompatibilityView.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/compatibility/CompatibilityView.java
new file mode 100644
index 0000000..d6ae0b1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/compatibility/CompatibilityView.java
@@ -0,0 +1,291 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2016 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 503387
+ ******************************************************************************/
+
+package org.eclipse.ui.internal.e4.compatibility;
+
+import java.util.Iterator;
+import java.util.concurrent.atomic.AtomicBoolean;
+import javax.inject.Inject;
+import org.eclipse.e4.core.contexts.ContextFunction;
+import org.eclipse.e4.core.contexts.IContextFunction;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.ui.internal.workbench.ContributionsAnalyzer;
+import org.eclipse.e4.ui.internal.workbench.OpaqueElementUtil;
+import org.eclipse.e4.ui.internal.workbench.swt.AbstractPartRenderer;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.model.application.ui.menu.MMenu;
+import org.eclipse.e4.ui.model.application.ui.menu.MMenuElement;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolBar;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolBarElement;
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+import org.eclipse.e4.ui.workbench.renderers.swt.MenuManagerRenderer;
+import org.eclipse.e4.ui.workbench.renderers.swt.StackRenderer;
+import org.eclipse.e4.ui.workbench.renderers.swt.ToolBarManagerRenderer;
+import org.eclipse.e4.ui.workbench.swt.factories.IRendererFactory;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.ToolBarManager;
+import org.eclipse.jface.commands.ActionHandler;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.internal.ActionDescriptor;
+import org.eclipse.ui.internal.PartSite;
+import org.eclipse.ui.internal.ViewActionBuilder;
+import org.eclipse.ui.internal.ViewReference;
+import org.eclipse.ui.internal.WorkbenchPartReference;
+import org.eclipse.ui.internal.registry.ViewDescriptor;
+import org.eclipse.ui.internal.testing.ContributionInfoMessages;
+import org.eclipse.ui.testing.ContributionInfo;
+
+public class CompatibilityView extends CompatibilityPart {
+
+	private ViewReference reference;
+
+	@Inject
+	EModelService modelService;
+
+	@Inject
+	CompatibilityView(MPart part, ViewReference ref) {
+		super(part);
+		reference = ref;
+	}
+
+	public IViewPart getView() {
+		return (IViewPart) getPart();
+	}
+
+	@Override
+	public WorkbenchPartReference getReference() {
+		return reference;
+	}
+
+	private MMenu getViewMenu() {
+		for (MMenu menu : part.getMenus()) {
+			if (menu.getTags().contains(StackRenderer.TAG_VIEW_MENU)) {
+				return menu;
+			}
+		}
+		return null;
+	}
+
+	@Override
+	protected boolean createPartControl(IWorkbenchPart legacyPart, Composite parent) {
+		clearMenuItems();
+		part.getContext().set(IViewPart.class, (IViewPart) legacyPart);
+
+		final IEclipseContext partContext = getModel().getContext();
+		IRendererFactory rendererFactory = partContext.get(IRendererFactory.class);
+
+		// Some views (i.e. Console) require that the actual ToolBar be
+		// instantiated before they are
+		final IActionBars actionBars = ((IViewPart) legacyPart).getViewSite().getActionBars();
+		ToolBarManager tbm = (ToolBarManager) actionBars.getToolBarManager();
+		Composite toolBarParent = new Composite(parent, SWT.NONE);
+		tbm.createControl(toolBarParent);
+
+		MenuManager mm = (MenuManager) actionBars.getMenuManager();
+		MMenu menu = getViewMenu();
+		if (menu == null) {
+			menu = modelService.createModelElement(MMenu.class);
+
+			// If the id contains a ':' use the part before it as the descriptor
+			// id
+			String partId = part.getElementId();
+			int colonIndex = partId.indexOf(':');
+			String descId = colonIndex == -1 ? partId : partId.substring(0, colonIndex);
+			menu.setElementId(descId);
+
+			menu.getTags().add(StackRenderer.TAG_VIEW_MENU);
+			menu.getTags().add(ContributionsAnalyzer.MC_MENU);
+			part.getMenus().add(menu);
+
+		}
+		AbstractPartRenderer apr = rendererFactory.getRenderer(menu, parent);
+		if (apr instanceof MenuManagerRenderer) {
+			MenuManagerRenderer renderer = (MenuManagerRenderer) apr;
+			renderer.linkModelToManager(menu, mm);
+		}
+
+		// Construct the toolbar (if necessary)
+		MToolBar toolbar = part.getToolbar();
+		if (toolbar == null) {
+			toolbar = modelService.createModelElement(MToolBar.class);
+
+			// If the id contains a ':' use the part before it as the descriptor
+			// id
+			String partId = part.getElementId();
+			int colonIndex = partId.indexOf(':');
+			String descId = colonIndex == -1 ? partId : partId.substring(0, colonIndex);
+			toolbar.setElementId(descId);
+
+			part.setToolbar(toolbar);
+		} else {
+			// clear out the model entries so they can be re-created by
+			// contributions
+			// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=402561
+			toolbar.getChildren().clear();
+		}
+		apr = rendererFactory.getRenderer(toolbar, parent);
+		if (apr instanceof ToolBarManagerRenderer) {
+			((ToolBarManagerRenderer) apr).linkModelToManager(toolbar, tbm);
+		}
+
+		super.createPartControl(legacyPart, parent);
+
+		ViewDescriptor desc = reference.getDescriptor();
+		if (desc != null && desc.getPluginId() != null) {
+			parent.setData(new ContributionInfo(desc.getPluginId(),
+					ContributionInfoMessages.ContributionInfo_View, null));
+		}
+
+		// dispose the tb, it will be re-created when the tab is shown
+		toolBarParent.dispose();
+
+		apr = rendererFactory.getRenderer(menu, parent);
+		if (apr instanceof MenuManagerRenderer) {
+			MenuManagerRenderer renderer = (MenuManagerRenderer) apr;
+			// create opaque items for any contribution items that were added
+			// directly to the manager
+			renderer.reconcileManagerToModel(mm, menu);
+		}
+
+		apr = rendererFactory.getRenderer(toolbar, parent);
+		if (apr instanceof ToolBarManagerRenderer) {
+			// create opaque items for any contribution items that were added
+			// directly to the manager
+			((ToolBarManagerRenderer) apr).reconcileManagerToModel(tbm, toolbar);
+		}
+		final AtomicBoolean toolbarContributed = new AtomicBoolean();
+		final IContextFunction func = new ContextFunction() {
+			@Override
+			public Object compute(IEclipseContext context, String contextKey) {
+				if (toolbarContributed.get()) {
+					// fix for bug 448873: don't contribute to the toolbar twice
+					return null;
+				}
+				toolbarContributed.set(true);
+				final ViewActionBuilder actionBuilder = new ViewActionBuilder();
+				actionBuilder.readActionExtensions(getView());
+				ActionDescriptor[] actionDescriptors = actionBuilder.getExtendedActions();
+				if (actionDescriptors != null) {
+					IHandlerService hs = partContext.get(IHandlerService.class);
+					for (ActionDescriptor actionDescriptor : actionDescriptors) {
+						if (actionDescriptor != null) {
+							IAction action = actionDescriptor.getAction();
+
+							if (action != null && action.getActionDefinitionId() != null) {
+								hs.activateHandler(action.getActionDefinitionId(),
+										new ActionHandler(action));
+							}
+						}
+					}
+				}
+				actionBars.updateActionBars();
+				final Runnable dispose = () -> actionBuilder.dispose();
+				return dispose;
+			}
+		};
+		if (toolbar.getWidget() == null) {
+			toolbar.getTransientData().put(ToolBarManagerRenderer.POST_PROCESSING_FUNCTION, func);
+		} else {
+			toolbar.getTransientData().put(ToolBarManagerRenderer.POST_PROCESSING_DISPOSE,
+					func.compute(partContext, null));
+		}
+
+		return true;
+	}
+
+	private void clearOpaqueMenuItems(MenuManagerRenderer renderer, MMenu menu) {
+		for (Iterator<MMenuElement> it = menu.getChildren().iterator(); it.hasNext();) {
+			MMenuElement child = it.next();
+			IContributionItem contribution = renderer.getContribution(child);
+			if (contribution != null) {
+				renderer.clearModelToContribution(child, contribution);
+			}
+
+			if (OpaqueElementUtil.isOpaqueMenuSeparator(child)) {
+				OpaqueElementUtil.clearOpaqueItem(child);
+				it.remove();
+			} else if (OpaqueElementUtil.isOpaqueMenuItem(child)) {
+				OpaqueElementUtil.clearOpaqueItem(child);
+				it.remove();
+			} else if (child instanceof MMenu) {
+				MMenu submenu = (MMenu) child;
+				MenuManager manager = renderer.getManager(submenu);
+				if (manager != null) {
+					renderer.clearModelToManager(submenu, manager);
+				}
+
+				if (OpaqueElementUtil.isOpaqueMenu(child)) {
+					it.remove();
+				}
+				clearOpaqueMenuItems(renderer, submenu);
+			}
+		}
+	}
+
+	@Override
+	void disposeSite(PartSite site) {
+		IEclipseContext context = getModel().getContext();
+		IRendererFactory rendererFactory = context.get(IRendererFactory.class);
+		IActionBars actionBars = site.getActionBars();
+
+		for (MMenu menu : part.getMenus()) {
+			if (menu.getTags().contains(StackRenderer.TAG_VIEW_MENU)) {
+				AbstractPartRenderer apr = rendererFactory.getRenderer(menu, null);
+				if (apr instanceof MenuManagerRenderer) {
+					MenuManagerRenderer renderer = (MenuManagerRenderer) apr;
+					MenuManager mm = (MenuManager) actionBars.getMenuManager();
+					renderer.clearModelToManager(menu, mm);
+					clearOpaqueMenuItems(renderer, menu);
+				}
+				break;
+			}
+		}
+
+		MToolBar toolbar = part.getToolbar();
+		if (toolbar != null) {
+			AbstractPartRenderer apr = rendererFactory.getRenderer(toolbar, null);
+			if (apr instanceof ToolBarManagerRenderer) {
+				ToolBarManager tbm = (ToolBarManager) actionBars.getToolBarManager();
+				ToolBarManagerRenderer tbmr = (ToolBarManagerRenderer) apr;
+				tbmr.clearModelToManager(toolbar, tbm);
+				clearOpaqueToolBarItems(tbmr, toolbar);
+			}
+		}
+
+		super.disposeSite(site);
+	}
+
+	private void clearOpaqueToolBarItems(ToolBarManagerRenderer tbmr, MToolBar toolbar) {
+		// remove opaque mappings
+		for (Iterator<MToolBarElement> it = toolbar.getChildren().iterator(); it.hasNext();) {
+			MToolBarElement element = it.next();
+			IContributionItem contribution = tbmr.getContribution(element);
+			if (contribution != null) {
+				tbmr.clearModelToContribution(element, contribution);
+			}
+			if (OpaqueElementUtil.isOpaqueToolItem(element)) {
+				// clear the reference
+				OpaqueElementUtil.clearOpaqueItem(element);
+				// remove the opaque item
+				it.remove();
+			}
+		}
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/compatibility/E4Util.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/compatibility/E4Util.java
new file mode 100644
index 0000000..d4919b7
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/compatibility/E4Util.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2015 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.ui.internal.e4.compatibility;
+
+import org.eclipse.osgi.service.debug.DebugOptions;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+
+/**
+ *
+ */
+public class E4Util {
+
+	// debug tracing
+	private static final String OPTION_DEBUG_E4 = "org.eclipse.ui.workbench/debug/e4"; //$NON-NLS-1$;
+
+	public final static boolean DEBUG_E4;
+
+	static {
+		WorkbenchPlugin activator = WorkbenchPlugin.getDefault();
+		if (activator == null)
+			DEBUG_E4 = false;
+		else {
+			DebugOptions debugOptions = activator.getDebugOptions();
+			if (debugOptions == null)
+				DEBUG_E4 = false;
+			else
+				DEBUG_E4 = debugOptions.getBooleanOption(OPTION_DEBUG_E4, false);
+		}
+	}
+
+	public static void unsupported(String msg) throws UnsupportedOperationException {
+		if (DEBUG_E4)
+			WorkbenchPlugin.log("unsupported: " + msg); //$NON-NLS-1$
+	}
+
+	public static void message(String msg) throws UnsupportedOperationException {
+		if (DEBUG_E4)
+			WorkbenchPlugin.log(msg);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/compatibility/ModeledFolderLayout.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/compatibility/ModeledFolderLayout.java
new file mode 100644
index 0000000..d08563d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/compatibility/ModeledFolderLayout.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2014 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.ui.internal.e4.compatibility;
+
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.ui.MUIElement;
+import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective;
+import org.eclipse.e4.ui.model.application.ui.basic.MPartStack;
+import org.eclipse.e4.ui.model.application.ui.basic.MStackElement;
+import org.eclipse.ui.IFolderLayout;
+
+public class ModeledFolderLayout extends ModeledPlaceholderFolderLayout
+		implements IFolderLayout {
+	public ModeledFolderLayout(ModeledPageLayout layout, MApplication application,
+			MPartStack stackModel) {
+		super(layout, application, stackModel);
+	}
+
+	@Override
+	public void addView(String viewId) {
+		MStackElement viewModel = ModeledPageLayout.createViewModel(application, viewId, true,
+				layout.page,
+				layout.partService,
+				layout.createReferences);
+		if (viewModel != null) {
+			// adding a non-placeholder to this folder, make sure the folder
+			// will be rendered
+			MUIElement parent = folderModel.getParent();
+			while (parent != null && !(parent instanceof MPerspective)) {
+				parent.setToBeRendered(true);
+				parent = parent.getParent();
+			}
+			folderModel.setToBeRendered(true);
+			boolean isFiltered = layout.isViewFiltered(viewId);
+			if (isFiltered)
+				layout.addViewActivator(viewModel);
+			viewModel.setToBeRendered(!isFiltered);
+			folderModel.getChildren().add(viewModel);
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/compatibility/ModeledPageLayout.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/compatibility/ModeledPageLayout.java
new file mode 100644
index 0000000..b5cd2c5
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/compatibility/ModeledPageLayout.java
@@ -0,0 +1,638 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2016 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
+ *     Simon Scholz <simon.scholz@vogella.com> - Bug 433450
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ ******************************************************************************/
+
+package org.eclipse.ui.internal.e4.compatibility;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.descriptor.basic.MPartDescriptor;
+import org.eclipse.e4.ui.model.application.ui.MElementContainer;
+import org.eclipse.e4.ui.model.application.ui.MUIElement;
+import org.eclipse.e4.ui.model.application.ui.advanced.MArea;
+import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective;
+import org.eclipse.e4.ui.model.application.ui.advanced.MPlaceholder;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.model.application.ui.basic.MPartSashContainerElement;
+import org.eclipse.e4.ui.model.application.ui.basic.MPartStack;
+import org.eclipse.e4.ui.model.application.ui.basic.MStackElement;
+import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
+import org.eclipse.e4.ui.workbench.IPresentationEngine;
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+import org.eclipse.e4.ui.workbench.modeling.EPartService;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.IFolderLayout;
+import org.eclipse.ui.IPageLayout;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.IPlaceholderFolderLayout;
+import org.eclipse.ui.IPluginContribution;
+import org.eclipse.ui.IViewLayout;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.activities.IIdentifier;
+import org.eclipse.ui.activities.IIdentifierListener;
+import org.eclipse.ui.activities.IWorkbenchActivitySupport;
+import org.eclipse.ui.activities.IdentifierEvent;
+import org.eclipse.ui.activities.WorkbenchActivityHelper;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPage;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.internal.registry.ActionSetRegistry;
+import org.eclipse.ui.internal.registry.IActionSetDescriptor;
+import org.eclipse.ui.views.IViewDescriptor;
+import org.eclipse.ui.views.IViewRegistry;
+
+public class ModeledPageLayout implements IPageLayout {
+
+	public static final String ACTION_SET_TAG = "persp.actionSet:"; //$NON-NLS-1$
+	public static final String NEW_WIZARD_TAG = "persp.newWizSC:"; //$NON-NLS-1$
+	public static final String PERSP_SHORTCUT_TAG = "persp.perspSC:"; //$NON-NLS-1$
+	public static final String SHOW_IN_PART_TAG = "persp.showIn:"; //$NON-NLS-1$
+	public static final String SHOW_VIEW_TAG = "persp.viewSC:"; //$NON-NLS-1$
+	public static final String EDITOR_STACK_TAG = "EditorStack"; //$NON-NLS-1$
+	public static final String HIDDEN_MENU_PREFIX = "persp.hideMenuSC:"; //$NON-NLS-1$
+	public static final String HIDDEN_TOOLBAR_PREFIX = "persp.hideToolbarSC:"; //$NON-NLS-1$
+	public static final String HIDDEN_ACTIONSET_PREFIX = "persp.hideActionSetSC:"; //$NON-NLS-1$
+	public static final String HIDDEN_ITEMS_KEY = "persp.hiddenItems"; //$NON-NLS-1$
+
+	public static List<String> getIds(MPerspective model, String tagPrefix) {
+		if (model == null) {
+			return Collections.emptyList();
+		}
+		ArrayList<String> result = new ArrayList<>();
+		for (String tag : model.getTags()) {
+			if (tag.startsWith(tagPrefix)) {
+				result.add(tag.substring(tagPrefix.length()));
+			}
+		}
+		return result;
+	}
+
+	private MApplication application;
+	// private MWindow window;
+	private EModelService modelService;
+
+	EPartService partService;
+	WorkbenchPage page;
+	MPerspective perspModel;
+	private IPerspectiveDescriptor descriptor;
+
+	private MPlaceholder eaRef;
+
+	private MPartStack editorStack;
+
+	boolean createReferences;
+
+	private IViewRegistry viewRegistry;
+
+	private ModeledPageLayoutUtils layoutUtils;
+
+	private class ViewActivator implements IIdentifierListener {
+		private MUIElement element;
+
+		public ViewActivator(MUIElement element) {
+			this.element = element;
+		}
+
+		@Override
+		public void identifierChanged(IdentifierEvent identifierEvent) {
+			IIdentifier identifier = identifierEvent.getIdentifier();
+
+			// Not activated, do nothing
+			if (!identifier.isEnabled())
+				return;
+
+			// stop listening for activations
+			identifier.removeIdentifierListener(this);
+
+			element.setToBeRendered(true);
+		}
+	}
+
+	public ModeledPageLayout(MWindow window, EModelService modelService,
+			EPartService partService,
+			MPerspective perspModel, IPerspectiveDescriptor descriptor, WorkbenchPage page,
+			boolean createReferences) {
+		// this.window = window;
+		MUIElement winParent = window.getParent();
+		this.application = (MApplication) winParent;
+		this.modelService = modelService;
+		this.partService = partService;
+		this.viewRegistry = PlatformUI.getWorkbench().getViewRegistry();
+		this.page = page;
+		// Create the editor area stack
+		this.perspModel = perspModel;
+		this.descriptor = descriptor;
+		this.layoutUtils = new ModeledPageLayoutUtils(modelService);
+
+		this.createReferences = createReferences;
+
+		MArea sharedArea = null;
+		List<MUIElement> sharedElements = window.getSharedElements();
+		for (MUIElement element : sharedElements) {
+			if (element.getElementId().equals(getEditorArea())) {
+				sharedArea = (MArea) element;
+				break;
+			}
+		}
+
+		if (sharedArea == null) {
+			sharedArea = modelService.createModelElement(MArea.class);
+			// sharedArea.setLabel("Editor Area"); //$NON-NLS-1$
+
+			editorStack = modelService.createModelElement(MPartStack.class);
+			editorStack.getTags().add("org.eclipse.e4.primaryDataStack"); //$NON-NLS-1$
+			editorStack.getTags().add(EDITOR_STACK_TAG);
+			editorStack.setElementId("org.eclipse.e4.primaryDataStack"); //$NON-NLS-1$
+			sharedArea.getChildren().add(editorStack);
+			sharedArea.setElementId(getEditorArea());
+
+			window.getSharedElements().add(sharedArea);
+		} else {
+			List<MPartStack> stacks = modelService.findElements(sharedArea, null, MPartStack.class,
+					null);
+			if (!stacks.isEmpty()) {
+				editorStack = stacks.get(0);
+			}
+		}
+
+		eaRef = modelService.createModelElement(MPlaceholder.class);
+		eaRef.setElementId(getEditorArea());
+		eaRef.setRef(sharedArea);
+
+		perspModel.getChildren().add(eaRef);
+
+		ActionSetRegistry registry = application.getContext().get(ActionSetRegistry.class);
+		for (IActionSetDescriptor actionSetDescriptor : registry.getActionSets()) {
+			if (actionSetDescriptor.isInitiallyVisible()) {
+				addActionSet(actionSetDescriptor.getId());
+			}
+		}
+	}
+
+	public MPerspective getModel() {
+		return perspModel;
+	}
+
+	@Override
+	public void addActionSet(String actionSetId) {
+		perspModel.getTags().add(ACTION_SET_TAG + actionSetId);
+	}
+
+	@Override
+	public void addFastView(String viewId) {
+		E4Util.unsupported("addFastView: " + viewId); //$NON-NLS-1$
+		logDeprecatedWarning(viewId);
+	}
+
+	@Override
+	public void addFastView(String viewId, float ratio) {
+		E4Util.unsupported("addFastView: " + viewId); //$NON-NLS-1$
+		logDeprecatedWarning(viewId);
+	}
+
+	private void logDeprecatedWarning(String viewId) {
+		String message = viewId + ": Deprecated relationship \"fast\" should be converted to \"stack\"."; //$NON-NLS-1$
+		WorkbenchPlugin.log(message, StatusUtil.newStatus(IStatus.WARNING, message, null));
+	}
+
+	@Override
+	public void addNewWizardShortcut(String id) {
+		perspModel.getTags().add(NEW_WIZARD_TAG + id);
+	}
+
+	@Override
+	public void addPerspectiveShortcut(String id) {
+		perspModel.getTags().add(PERSP_SHORTCUT_TAG + id);
+	}
+
+	@Override
+	public void addPlaceholder(String viewId, int relationship, float ratio,
+			String refId) {
+		insertView(viewId, relationship, ratio, refId, false, true);
+	}
+
+	@Override
+	public void addShowInPart(String id) {
+		perspModel.getTags().add(SHOW_IN_PART_TAG + id);
+	}
+
+	@Override
+	public void addShowViewShortcut(String id) {
+		perspModel.getTags().add(SHOW_VIEW_TAG + id);
+	}
+
+	@Override
+	public void addStandaloneView(String viewId, boolean showTitle,
+			int relationship, float ratio, String refId) {
+		MUIElement newElement = insertView(viewId, relationship, ratio, refId, true, showTitle);
+		if (newElement instanceof MPartStack) {
+			MPartStack stack = (MPartStack) newElement;
+			stack.getTags().add(IPresentationEngine.STANDALONE);
+			stack.getChildren().get(0).getTags().add(IPresentationEngine.NO_MOVE);
+		} else {
+			newElement.getTags().add(IPresentationEngine.STANDALONE);
+		}
+	}
+
+	@Override
+	public void addStandaloneViewPlaceholder(String viewId, int relationship,
+			float ratio, String refId, boolean showTitle) {
+		MUIElement newElement = insertView(viewId, relationship, ratio, refId, false, showTitle);
+		if (newElement instanceof MPartStack) {
+			MPartStack stack = (MPartStack) newElement;
+			stack.getTags().add(IPresentationEngine.STANDALONE);
+			stack.getChildren().get(0).getTags().add(IPresentationEngine.NO_MOVE);
+		} else {
+			newElement.getTags().add(IPresentationEngine.STANDALONE);
+		}
+	}
+
+	@Override
+	public void addView(String viewId, int relationship, float ratio, String refId) {
+		insertView(viewId, relationship, ratio, refId, true, true);
+	}
+
+	public void addView(String viewId, int relationship, float ratio, String refId,
+			boolean minimized) {
+		if (minimized) {
+			E4Util.unsupported("addView: use of minimized for " + viewId + " ref " + refId); //$NON-NLS-1$ //$NON-NLS-2$
+		}
+		addView(viewId, relationship, ratio, refId);
+	}
+
+	protected boolean isViewFiltered(String viewID) {
+		IViewDescriptor viewDescriptor = viewRegistry.find(viewID);
+		if (viewDescriptor == null)
+			return false;
+		if (WorkbenchActivityHelper.restrictUseOf(viewDescriptor))
+			return true;
+		return WorkbenchActivityHelper.filterItem(viewDescriptor);
+	}
+
+	protected void addViewActivator(MUIElement element) {
+		IPluginContribution contribution = (IPluginContribution) viewRegistry.find(element
+				.getElementId());
+		IWorkbenchActivitySupport support = PlatformUI.getWorkbench().getActivitySupport();
+		IIdentifier identifier = support.getActivityManager().getIdentifier(
+				WorkbenchActivityHelper.createUnifiedId(contribution));
+		identifier.addIdentifierListener(new ViewActivator(element));
+	}
+
+	@Override
+	public IFolderLayout createFolder(String folderId, int relationship,
+			float ratio, String refId) {
+		MPartStack stack = insertStack(folderId, relationship, ratio, refId,
+				false);
+		return new ModeledFolderLayout(this, application, stack);
+	}
+
+	@Override
+	public IPlaceholderFolderLayout createPlaceholderFolder(String folderId,
+			int relationship, float ratio, String refId) {
+		MPartStack Stack = insertStack(folderId, relationship, ratio, refId,
+				false);
+		return new ModeledPlaceholderFolderLayout(this, application, Stack);
+	}
+
+	@Override
+	public IPerspectiveDescriptor getDescriptor() {
+		return descriptor;
+	}
+
+	public static String internalGetEditorArea() {
+		return IPageLayout.ID_EDITOR_AREA;
+	}
+
+	@Override
+	public String getEditorArea() {
+		return internalGetEditorArea();
+	}
+
+	@Override
+	public int getEditorReuseThreshold() {
+		return -1;
+	}
+
+	@Override
+	public IPlaceholderFolderLayout getFolderForView(String id) {
+		MPart view = findPart(perspModel, id);
+		if (view == null)
+			return null;
+
+		MUIElement stack = view.getParent();
+		if (stack == null || !(stack instanceof MPartStack))
+			return null;
+
+		return new ModeledPlaceholderFolderLayout(this, application, (MPartStack) stack);
+	}
+
+	@Override
+	public IViewLayout getViewLayout(String id) {
+		MPart view = findPart(perspModel, id);
+		if (view != null)
+			return new ModeledViewLayout(view);
+
+		MPlaceholder placeholder = findPlaceholder(perspModel, id);
+		if (placeholder != null)
+			return new ModeledViewLayout(placeholder);
+
+		return null;
+	}
+
+	@Override
+	public boolean isEditorAreaVisible() {
+		return true;
+	}
+
+	@Override
+	public boolean isFixed() {
+		return false;
+	}
+
+	@Override
+	public void setEditorAreaVisible(boolean showEditorArea) {
+		eaRef.setToBeRendered(showEditorArea);
+	}
+
+	@Override
+	public void setEditorReuseThreshold(int openEditors) {
+		// ignored, no-op, same as 3.x implementation
+	}
+
+	@Override
+	public void setFixed(boolean isFixed) {
+		// perspModel.setFixed(isFixed);
+	}
+
+	public static MStackElement createViewModel(MApplication application, String id,
+			boolean visible,
+			WorkbenchPage page, EPartService partService, boolean createReferences) {
+		EModelService ms = application.getContext().get(EModelService.class);
+		MPartDescriptor partDesc = ms.getPartDescriptor(id);
+		if (partDesc != null) {
+			MPlaceholder ph = partService.createSharedPart(id);
+			ph.setToBeRendered(visible);
+
+			MPart part = (MPart) (ph.getRef());
+			// as a shared part, this should be true, actual un/rendering
+			// will be dependent on any placeholders that are referencing
+			// this part
+			part.setToBeRendered(true);
+
+			// there should only be view references for 3.x views that are
+			// visible to the end user, that is, the tab items are being
+			// drawn
+			if (visible
+					&& createReferences
+					&& CompatibilityPart.COMPATIBILITY_VIEW_URI.equals(partDesc
+							.getContributionURI())) {
+				page.createViewReferenceForPart(part, id);
+			}
+			return ph;
+		}
+		return null;
+	}
+
+	private MUIElement insertView(String viewId, int relationship, float ratio,
+			String refId, boolean visible, boolean withStack) {
+
+		// Hide views that are filtered by capabilities
+		boolean isFiltered = isViewFiltered(viewId);
+
+		MStackElement viewModel = createViewModel(application, viewId, visible && !isFiltered,
+				page, partService,
+				createReferences);
+		MUIElement retVal = viewModel;
+
+		if (viewModel != null) {
+			if (withStack) {
+				String stackId = viewId + "MStack"; // Default id...basically unusable //$NON-NLS-1$
+				MPartStack stack = insertStack(stackId, relationship, ratio, refId, visible
+						& !isFiltered);
+				stack.getChildren().add(viewModel);
+				retVal = stack;
+			} else {
+				layoutUtils.insert(viewModel, findRefModel(refId), layoutUtils.plRelToSwt(relationship), ratio);
+			}
+
+		}
+
+		if (isFiltered) {
+			addViewActivator(viewModel);
+		}
+
+		return retVal;
+	}
+
+	private MUIElement findRefModel(String refId) {
+		MUIElement refModel = findElement(perspModel, refId);
+		if (refModel instanceof MPart) {
+			MUIElement parent = refModel.getParent();
+			return parent instanceof MPartStack ? parent : refModel;
+		} else if (refModel instanceof MPlaceholder) {
+			MUIElement ref = ((MPlaceholder) refModel).getRef();
+			if (ref instanceof MPart) {
+				MUIElement parent = refModel.getParent();
+				return parent instanceof MPartStack ? parent : refModel;
+			}
+		}
+		return refModel;
+	}
+
+	private MUIElement getLastElement(MUIElement element) {
+		if (element instanceof MElementContainer<?>) {
+			MElementContainer<?> container = (MElementContainer<?>) element;
+			List<?> children = container.getChildren();
+			return children.isEmpty() ? container : getLastElement((MUIElement) children
+					.get(children.size() - 1));
+		}
+
+		MUIElement parent = element.getParent();
+		return parent == perspModel ? element : parent;
+	}
+
+	/**
+	 * Returns the element that is the deepest and last element of the
+	 * containers underneath the current perspective. If this element's parent
+	 * is the perspective itself, the element will be returned. The perspective
+	 * will only be returned if the perspective itself has no children.
+	 *
+	 * @return the parent of the final element in the recursion chain of
+	 *         children, or the element itself if its parent is the perspective,
+	 *         or the perspective if the perspective itself has no children
+	 */
+	private MUIElement getLastElement() {
+		List<MPartSashContainerElement> children = perspModel.getChildren();
+		if (children.isEmpty()) {
+			return perspModel;
+		}
+		return getLastElement(children.get(children.size() - 1));
+	}
+
+	private MPartStack insertStack(String stackId, int relationship,
+			float ratio, String refId, boolean visible) {
+		MUIElement refModel = findElement(perspModel, refId);
+		if (refModel == null) {
+			WorkbenchPlugin.log(NLS.bind(WorkbenchMessages.get().PageLayout_missingRefPart, refId));
+			MPartStack stack = layoutUtils.createStack(stackId, visible);
+			layoutUtils.insert(stack, getLastElement(), layoutUtils.plRelToSwt(relationship), ratio);
+			return stack;
+		}
+		// If the 'refModel' is -not- a stack then find one
+		// This covers cases where the defining layout is adding
+		// Views relative to other views and relying on the stacks
+		// being automatically created.
+		// if (!(refModel instanceof MPartStack)) {
+		// while (refModel.getParent() != null) {
+		// refModel = refModel.getParent();
+		// if (refModel instanceof MPartStack)
+		// break;
+		// }
+		// if (!(refModel instanceof MPartStack))
+		// return null;
+		// }
+
+		MPartStack stack = layoutUtils.createStack(stackId, visible);
+		MElementContainer<?> parent = refModel.getParent();
+		if (parent instanceof MPartStack) {
+			// we don't want to put a stack in a stack
+			refModel = parent;
+		}
+		layoutUtils.insert(stack, refModel, layoutUtils.plRelToSwt(relationship), ratio);
+
+		return stack;
+	}
+
+	public static void replace(MUIElement relTo,
+			MElementContainer<MUIElement> newParent) {
+		if (relTo == null || newParent == null)
+			return;
+
+		MElementContainer<MUIElement> parent = relTo.getParent();
+		if (parent == null)
+			return;
+
+		List<MUIElement> kids = parent.getChildren();
+		if (kids == null)
+			return;
+
+		kids.add(kids.indexOf(relTo), newParent);
+		kids.remove(relTo);
+	}
+
+	public static void insertParent(MElementContainer<MUIElement> newParent,
+			MUIElement relTo) {
+		if (newParent == null || relTo == null)
+			return;
+
+		MPart curParent = (MPart) relTo.getParent();
+		if (curParent != null) {
+			replace(relTo, newParent);
+		}
+
+		// Move the child under the new parent
+		newParent.getChildren().add(relTo);
+	}
+
+	MUIElement findElement(MUIElement toSearch, String id) {
+		List<Object> found = modelService.findElements(toSearch, id, null, null,
+				EModelService.IN_ANY_PERSPECTIVE);
+		if (found.size() > 0)
+			return (MUIElement) found.get(0);
+
+		MUIElement foundElement = modelService.find(id, toSearch);
+		return foundElement;
+	}
+
+	private MPart findPart(MUIElement toSearch, String id) {
+		MUIElement element = modelService.find(id, toSearch);
+		return element instanceof MPart ? (MPart) element : null;
+	}
+
+	private MPlaceholder findPlaceholder(MUIElement toSearch, String id) {
+		MUIElement element = modelService.find(id, toSearch);
+		return element instanceof MPlaceholder ? (MPlaceholder) element : null;
+	}
+
+	public void addHiddenMenuItemId(String id) {
+		page.addHiddenItems(perspModel, HIDDEN_MENU_PREFIX + id);
+	}
+
+	public void addHiddenToolBarItemId(String id) {
+		page.addHiddenItems(perspModel, HIDDEN_TOOLBAR_PREFIX + id);
+	}
+
+	public void removePlaceholder(String id) {
+		MUIElement refModel = findElement(perspModel, id);
+		if (!(refModel instanceof MPlaceholder)) {
+			E4Util.unsupported("removePlaceholder: failed to find " + id + ": " + refModel); //$NON-NLS-1$ //$NON-NLS-2$
+			return;
+		}
+
+		// placeholders in the shared area should be ignored
+		if (modelService.getElementLocation(refModel) != EModelService.IN_SHARED_AREA) {
+			MElementContainer<MUIElement> parent = refModel.getParent();
+			if (parent != null) {
+				parent.getChildren().remove(refModel);
+			}
+		}
+	}
+
+	public void stackView(String id, String refId, boolean visible) {
+		MUIElement refModel = refId.equals(getEditorArea()) ? editorStack : findElement(perspModel,
+				refId);
+		if (refModel == null) {
+			addView(id, LEFT, DEFAULT_VIEW_RATIO, refId);
+			return;
+		}
+
+		if (refModel instanceof MPart || refModel instanceof MPlaceholder) {
+			refModel = refModel.getParent();
+		}
+		if (!(refModel instanceof MPartStack)) {
+			E4Util.unsupported("stackView: failed to find " + refId + " for " + id); //$NON-NLS-1$//$NON-NLS-2$
+			return;
+		}
+
+		// Hide views that are filtered by capabilities
+		boolean isFiltered = isViewFiltered(id);
+		boolean toBeRendered = visible && !isFiltered;
+
+		MStackElement viewModel = createViewModel(application, id, toBeRendered, page, partService,
+				createReferences);
+		if (viewModel != null) {
+			MPartStack stack = (MPartStack) refModel;
+			boolean wasEmpty = stack.getChildren().isEmpty();
+			stack.getChildren().add(viewModel);
+			if (wasEmpty && toBeRendered) {
+				// the stack didn't originally have any children, set this as
+				// the selected element
+				stack.setSelectedElement(viewModel);
+			}
+
+			if (viewModel.isToBeRendered()) {
+				// ensure that the parent is being rendered, it may have been a
+				// placeholder folder so its flag may actually be false
+				layoutUtils.resetToBeRenderedFlag(viewModel, true);
+			}
+
+			if (isFiltered) {
+				addViewActivator(viewModel);
+			}
+		}
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/compatibility/ModeledPageLayoutUtils.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/compatibility/ModeledPageLayoutUtils.java
new file mode 100644
index 0000000..a3115ac
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/compatibility/ModeledPageLayoutUtils.java
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.ui.internal.e4.compatibility;
+
+import java.util.List;
+import org.eclipse.e4.ui.model.application.ui.MElementContainer;
+import org.eclipse.e4.ui.model.application.ui.MUIElement;
+import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective;
+import org.eclipse.e4.ui.model.application.ui.basic.MPartSashContainer;
+import org.eclipse.e4.ui.model.application.ui.basic.MPartSashContainerElement;
+import org.eclipse.e4.ui.model.application.ui.basic.MPartStack;
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+import org.eclipse.swt.SWT;
+import org.eclipse.ui.IPageLayout;
+
+public class ModeledPageLayoutUtils {
+
+	private EModelService modelService;
+
+	public ModeledPageLayoutUtils(EModelService modelService) {
+		this.modelService = modelService;
+	}
+
+	public int plRelToSwt(int rel) {
+		switch (rel) {
+		case IPageLayout.BOTTOM:
+			return SWT.BOTTOM;
+		case IPageLayout.LEFT:
+			return SWT.LEFT;
+		case IPageLayout.RIGHT:
+			return SWT.RIGHT;
+		case IPageLayout.TOP:
+			return SWT.TOP;
+		default:
+			return 0;
+		}
+	}
+
+	public void insert(MUIElement toInsert, MUIElement relTo, int swtSide, float ratio) {
+		int pct = (int) (ratio * 10000);
+		insert(toInsert, relTo, swtSide, pct);
+	}
+
+	public void insert(MUIElement toInsert, MUIElement relTo, int swtSide, int ratio) {
+		if (toInsert == null || relTo == null)
+			return;
+
+		MElementContainer<MUIElement> relParent = relTo.getParent();
+		if (relParent != null) {
+			List<MUIElement> children = relParent.getChildren();
+			int index = children.indexOf(relTo);
+			MPartSashContainer psc = modelService.createModelElement(MPartSashContainer.class);
+			psc.setContainerData(relTo.getContainerData());
+			relParent.getChildren().add(index + 1, psc);
+
+			switch (swtSide) {
+			case SWT.LEFT:
+				psc.getChildren().add((MPartSashContainerElement) toInsert);
+				psc.getChildren().add((MPartSashContainerElement) relTo);
+				toInsert.setContainerData("" + ratio); //$NON-NLS-1$
+				relTo.setContainerData("" + (10000 - ratio)); //$NON-NLS-1$
+				psc.setHorizontal(true);
+				break;
+			case SWT.RIGHT:
+				psc.getChildren().add((MPartSashContainerElement) relTo);
+				psc.getChildren().add((MPartSashContainerElement) toInsert);
+				relTo.setContainerData("" + ratio); //$NON-NLS-1$
+				toInsert.setContainerData("" + (10000 - ratio)); //$NON-NLS-1$
+				psc.setHorizontal(true);
+				break;
+			case SWT.TOP:
+				psc.getChildren().add((MPartSashContainerElement) toInsert);
+				psc.getChildren().add((MPartSashContainerElement) relTo);
+				toInsert.setContainerData("" + ratio); //$NON-NLS-1$
+				relTo.setContainerData("" + (10000 - ratio)); //$NON-NLS-1$
+				psc.setHorizontal(false);
+				break;
+			case SWT.BOTTOM:
+				psc.getChildren().add((MPartSashContainerElement) relTo);
+				psc.getChildren().add((MPartSashContainerElement) toInsert);
+				relTo.setContainerData("" + ratio); //$NON-NLS-1$
+				toInsert.setContainerData("" + (10000 - ratio)); //$NON-NLS-1$
+				psc.setHorizontal(false);
+				break;
+			}
+
+			if (relTo.isToBeRendered() || toInsert.isToBeRendered()) {
+				// one of the items to be inserted should be rendered, render
+				// all parent elements as well
+				resetToBeRenderedFlag(psc, true);
+			} else {
+				// no child elements need to be rendered, the parent part sash
+				// container does not need to be rendered either then
+				psc.setToBeRendered(false);
+			}
+			return;
+		}
+	}
+
+	public void resetToBeRenderedFlag(MUIElement element, boolean toBeRendered) {
+		MUIElement parent = element.getParent();
+		while (parent != null && !(parent instanceof MPerspective)) {
+			parent.setToBeRendered(toBeRendered);
+			parent = parent.getParent();
+		}
+		element.setToBeRendered(toBeRendered);
+	}
+
+	public MPartStack createStack(String id, boolean visible) {
+		MPartStack newStack = modelService.createModelElement(MPartStack.class);
+		newStack.setElementId(id);
+		newStack.setToBeRendered(visible);
+		return newStack;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/compatibility/ModeledPlaceholderFolderLayout.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/compatibility/ModeledPlaceholderFolderLayout.java
new file mode 100644
index 0000000..ca8b887
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/compatibility/ModeledPlaceholderFolderLayout.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2014 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.ui.internal.e4.compatibility;
+
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.ui.basic.MPartStack;
+import org.eclipse.e4.ui.model.application.ui.basic.MStackElement;
+import org.eclipse.ui.IPlaceholderFolderLayout;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.views.IViewRegistry;
+
+public class ModeledPlaceholderFolderLayout implements IPlaceholderFolderLayout {
+
+	protected MApplication application;
+	protected MPartStack folderModel;
+	protected ModeledPageLayout layout;
+	protected IViewRegistry viewRegistry;
+
+	public ModeledPlaceholderFolderLayout(ModeledPageLayout l, MApplication application,
+			MPartStack stackModel) {
+		this.application = application;
+		this.viewRegistry = PlatformUI.getWorkbench().getViewRegistry();
+		folderModel = stackModel;
+		layout = l;
+	}
+
+	@Override
+	public void addPlaceholder(String viewId) {
+		boolean containsWildcards = viewId.indexOf('?') != -1;
+		if (containsWildcards) {
+			E4Util.unsupported("IPageLayout.addPlacehoder(): wildcard in view id: " + viewId); //$NON-NLS-1$
+			return;
+		}
+
+		MStackElement viewModel = ModeledPageLayout.createViewModel(application, viewId, false,
+				layout.page, layout.partService, layout.createReferences);
+		if (viewModel != null) {
+			folderModel.getChildren().add(viewModel);
+		}
+	}
+
+	@Override
+	public String getProperty(String id) {
+		Object propVal = null;
+		return propVal == null ? "" : propVal.toString(); //$NON-NLS-1$
+	}
+
+	@Override
+	public void setProperty(String id, String value) {
+		// folderModel.setProperty(id, value);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/compatibility/ModeledViewLayout.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/compatibility/ModeledViewLayout.java
new file mode 100644
index 0000000..fbd0e64
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/compatibility/ModeledViewLayout.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2014 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.ui.internal.e4.compatibility;
+
+import org.eclipse.e4.ui.model.application.ui.MUIElement;
+import org.eclipse.e4.ui.model.application.ui.advanced.MPlaceholder;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.model.application.ui.basic.MPartStack;
+import org.eclipse.e4.ui.workbench.IPresentationEngine;
+import org.eclipse.ui.IViewLayout;
+
+public class ModeledViewLayout implements IViewLayout {
+	private MUIElement viewME;
+
+	public ModeledViewLayout(MPart view) {
+		viewME = view;
+	}
+
+	public ModeledViewLayout(MPlaceholder placeholder) {
+		viewME = placeholder;
+	}
+
+	@Override
+	public boolean getShowTitle() {
+		return !viewME.getTags().contains(IPresentationEngine.NO_TITLE);
+	}
+
+	@Override
+	public boolean isCloseable() {
+		return !viewME.getTags().contains(IPresentationEngine.NO_CLOSE);
+	}
+
+	@Override
+	public boolean isMoveable() {
+		return !viewME.getTags().contains(IPresentationEngine.NO_MOVE);
+	}
+
+	@Override
+	public boolean isStandalone() {
+		MUIElement parentElement = viewME.getParent();
+		return !(parentElement instanceof MPartStack);
+	}
+
+	@Override
+	public void setCloseable(boolean closeable) {
+		if (closeable)
+			viewME.getTags().remove(IPresentationEngine.NO_CLOSE);
+		else
+			viewME.getTags().add(IPresentationEngine.NO_CLOSE);
+	}
+
+	@Override
+	public void setMoveable(boolean moveable) {
+		if (moveable)
+			viewME.getTags().remove(IPresentationEngine.NO_MOVE);
+		else
+			viewME.getTags().add(IPresentationEngine.NO_MOVE);
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/compatibility/SelectionService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/compatibility/SelectionService.java
new file mode 100644
index 0000000..2fe7a35
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/compatibility/SelectionService.java
@@ -0,0 +1,358 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2016 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ ******************************************************************************/
+
+package org.eclipse.ui.internal.e4.compatibility;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+import javax.inject.Named;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.di.annotations.Optional;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.services.IServiceConstants;
+import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.ui.INullSelectionListener;
+import org.eclipse.ui.ISelectionListener;
+import org.eclipse.ui.ISelectionService;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.internal.E4PartWrapper;
+import org.eclipse.ui.internal.WorkbenchPage;
+
+public class SelectionService implements ISelectionChangedListener, ISelectionService {
+
+	@Inject
+	private IEclipseContext context;
+
+	@Inject
+	private MApplication application;
+
+	private ESelectionService selectionService;
+
+	@Inject
+	@Optional
+	@Named("org.eclipse.ui.IWorkbenchPage")
+	private WorkbenchPage page;
+
+	private IWorkbenchPart activePart;
+
+	private ListenerList<ISelectionListener> listeners = new ListenerList<>();
+	private ListenerList<ISelectionListener> postSelectionListeners = new ListenerList<>();
+	private Map<String, Set<ISelectionListener>> targetedListeners = new HashMap<>();
+	private Map<String, Set<ISelectionListener>> targetedPostSelectionListeners = new HashMap<>();
+
+	private org.eclipse.e4.ui.workbench.modeling.ISelectionListener listener = (part, selection) -> handleSelectionChanged(part, selection, false);
+
+	private org.eclipse.e4.ui.workbench.modeling.ISelectionListener targetedListener = (part, selection) -> handleSelectionChanged(part, selection, true);
+
+	private org.eclipse.e4.ui.workbench.modeling.ISelectionListener postListener = (part, selection) -> handlePostSelectionChanged(part, selection, false);
+
+	private org.eclipse.e4.ui.workbench.modeling.ISelectionListener targetedPostListener = (part, selection) -> handlePostSelectionChanged(part, selection, true);
+
+	private void handleSelectionChanged(MPart part, Object selection, boolean targeted) {
+		selection = createCompatibilitySelection(selection);
+		context.set(ISources.ACTIVE_CURRENT_SELECTION_NAME, selection);
+
+		IEclipseContext applicationContext = application.getContext();
+		if (applicationContext.getActiveChild() == context) {
+			application.getContext().set(ISources.ACTIVE_CURRENT_SELECTION_NAME, selection);
+		}
+
+		Object client = part.getObject();
+		if (client instanceof CompatibilityPart) {
+			IWorkbenchPart workbenchPart = ((CompatibilityPart) client).getPart();
+			if (targeted) {
+				notifyListeners(workbenchPart, (ISelection) selection, part.getElementId(),
+						targetedListeners);
+			} else {
+				notifyListeners(workbenchPart, (ISelection) selection, listeners);
+			}
+		} else if (client != null) {
+			if (part.getTransientData().get(E4PartWrapper.E4_WRAPPER_KEY) instanceof E4PartWrapper) {
+				IWorkbenchPart workbenchPart = (IWorkbenchPart) part.getTransientData()
+						.get(E4PartWrapper.E4_WRAPPER_KEY);
+				if (targeted) {
+					notifyListeners(workbenchPart, (ISelection) selection, part.getElementId(), targetedListeners);
+				} else {
+					notifyListeners(workbenchPart, (ISelection) selection, listeners);
+				}
+			}
+		}
+	}
+
+	private void handlePostSelectionChanged(MPart part, Object selection, boolean targeted) {
+		selection = createCompatibilitySelection(selection);
+
+		Object client = part.getObject();
+		if (client instanceof CompatibilityPart) {
+			IWorkbenchPart workbenchPart = ((CompatibilityPart) client).getPart();
+			if (targeted) {
+				notifyListeners(workbenchPart, (ISelection) selection, part.getElementId(),
+						targetedPostSelectionListeners);
+			} else {
+				notifyListeners(workbenchPart, (ISelection) selection, postSelectionListeners);
+			}
+		} else if (client != null) {
+			if (part.getTransientData().get(E4PartWrapper.E4_WRAPPER_KEY) instanceof E4PartWrapper) {
+				IWorkbenchPart workbenchPart = (IWorkbenchPart) part.getTransientData()
+						.get(E4PartWrapper.E4_WRAPPER_KEY);
+				if (targeted) {
+					notifyListeners(workbenchPart, (ISelection) selection, part.getElementId(),
+							targetedPostSelectionListeners);
+				} else {
+					notifyListeners(workbenchPart, (ISelection) selection, postSelectionListeners);
+				}
+			}
+		}
+	}
+
+	private static ISelection createCompatibilitySelection(Object selection) {
+		if (selection instanceof ISelection) {
+			return (ISelection) selection;
+		}
+		return selection == null ? StructuredSelection.EMPTY : new StructuredSelection(
+				selection);
+	}
+
+	/**
+	 * Updates the selection of the workbench window with that of the active
+	 * part's.
+	 *
+	 * @param activePart
+	 *            the currently active part
+	 */
+	public void updateSelection(IWorkbenchPart activePart) {
+		if (activePart != null) {
+			ISelectionProvider selectionProvider = activePart.getSite().getSelectionProvider();
+			if (selectionProvider != null) {
+				ISelection selection = selectionProvider.getSelection();
+				context.set(ISources.ACTIVE_CURRENT_SELECTION_NAME, selection);
+
+				IEclipseContext applicationContext = application.getContext();
+				if (applicationContext.getActiveChild() == context) {
+					application.getContext().set(ISources.ACTIVE_CURRENT_SELECTION_NAME, selection);
+				}
+			}
+		}
+	}
+
+	/**
+	 * Notifies selection listeners about selection change caused by active part
+	 * change.
+	 *
+	 * @param activePart
+	 *            the currently active part
+	 */
+	public void notifyListeners(IWorkbenchPart activePart) {
+		if (activePart != null) {
+			ISelectionProvider selectionProvider = activePart.getSite().getSelectionProvider();
+			if (selectionProvider != null) {
+				ISelection selection = selectionProvider.getSelection();
+
+				notifyListeners(activePart, selection, listeners);
+				notifyListeners(activePart, selection, activePart.getSite().getId(), targetedListeners);
+				notifyListeners(activePart, selection, postSelectionListeners);
+				notifyListeners(activePart, selection, activePart.getSite().getId(), targetedPostSelectionListeners);
+			}
+		}
+	}
+
+	@Inject
+	void setPart(@Optional @Named(IServiceConstants.ACTIVE_PART) final MPart part) {
+		activePart = null;
+		if (part != null) {
+			Object client = part.getObject();
+			if (client instanceof CompatibilityPart) {
+				IWorkbenchPart workbenchPart = ((CompatibilityPart) client).getPart();
+				activePart = workbenchPart;
+			} else if (client != null) {
+				if (part.getTransientData().get(E4PartWrapper.E4_WRAPPER_KEY) instanceof E4PartWrapper) {
+					activePart = (IWorkbenchPart) part.getTransientData().get(
+							E4PartWrapper.E4_WRAPPER_KEY);
+				}
+			}
+		}
+	}
+
+	@Inject
+	void setSelectionService(@Optional ESelectionService selectionService) {
+		if (this.selectionService != null) {
+			this.selectionService.removeSelectionListener(listener);
+			for (String partId : targetedListeners.keySet()) {
+				this.selectionService.removeSelectionListener(partId, targetedListener);
+			}
+
+			this.selectionService.removePostSelectionListener(postListener);
+			for (String partId : targetedPostSelectionListeners.keySet()) {
+				this.selectionService.removePostSelectionListener(partId, targetedPostListener);
+			}
+		}
+
+		if (selectionService != null) {
+			selectionService.addSelectionListener(listener);
+			for (String partId : targetedListeners.keySet()) {
+				selectionService.addSelectionListener(partId, targetedListener);
+			}
+
+			selectionService.addPostSelectionListener(postListener);
+			for (String partId : targetedPostSelectionListeners.keySet()) {
+				selectionService.addPostSelectionListener(partId, targetedPostListener);
+			}
+			this.selectionService = selectionService;
+		}
+	 }
+
+	@PreDestroy
+	public void dispose() {
+		setSelectionService(null);
+		selectionService = null;
+		listeners.clear();
+		postSelectionListeners.clear();
+		targetedListeners.clear();
+		targetedPostSelectionListeners.clear();
+	}
+
+	private void notifyListeners(IWorkbenchPart workbenchPart, ISelection selection,
+			ListenerList<ISelectionListener> listenerList) {
+		for (ISelectionListener listener : listenerList) {
+			if (selection != null || listener instanceof INullSelectionListener) {
+				listener.selectionChanged(workbenchPart, selection);
+			}
+		}
+	}
+
+	private void notifyListeners(IWorkbenchPart workbenchPart, ISelection selection, String id,
+			Map<String, Set<ISelectionListener>> listenerMap) {
+		if (id != null) {
+			Set<ISelectionListener> listeners = listenerMap.get(id);
+			if (listeners != null) {
+				for (ISelectionListener listener : listeners) {
+					if (selection != null || listener instanceof INullSelectionListener) {
+						listener.selectionChanged(workbenchPart, selection);
+					}
+				}
+			}
+		}
+	}
+
+	@Override
+	public void addSelectionListener(ISelectionListener listener) {
+		listeners.add(listener);
+	}
+
+	@Override
+	public void addSelectionListener(String partId, ISelectionListener listener) {
+		Set<ISelectionListener> listeners = targetedListeners.get(partId);
+		if (listeners == null) {
+			listeners = new HashSet<>();
+			targetedListeners.put(partId, listeners);
+		}
+		if (listeners.size() == 0 && selectionService != null) {
+			selectionService.addSelectionListener(partId, this.targetedListener);
+		}
+		listeners.add(listener);
+	}
+
+	@Override
+	public void addPostSelectionListener(ISelectionListener listener) {
+		postSelectionListeners.add(listener);
+	}
+
+	@Override
+	public void addPostSelectionListener(String partId, ISelectionListener listener) {
+		Set<ISelectionListener> listeners = targetedPostSelectionListeners.get(partId);
+		if (listeners == null) {
+			listeners = new HashSet<>();
+			targetedPostSelectionListeners.put(partId, listeners);
+		}
+		if (listeners.size() == 0 && selectionService != null) {
+			selectionService.addPostSelectionListener(partId, targetedPostListener);
+		}
+		listeners.add(listener);
+	}
+
+	@Override
+	public ISelection getSelection() {
+		if (activePart != null) {
+			// get the selection from the active part
+			ISelectionProvider selectionProvider = activePart.getSite().getSelectionProvider();
+			return selectionProvider == null ? null : selectionProvider.getSelection();
+		}
+
+		Object selection = selectionService.getSelection();
+		if (selection == null || selection instanceof ISelection) {
+			return (ISelection) selection;
+		}
+		return new StructuredSelection(selection);
+	}
+
+	@Override
+	public ISelection getSelection(String partId) {
+		Object selection = selectionService.getSelection(partId);
+		if (selection == null || selection instanceof ISelection) {
+			return (ISelection) selection;
+		}
+		return new StructuredSelection(selection);
+	}
+
+	@Override
+	public void removeSelectionListener(ISelectionListener listener) {
+		listeners.remove(listener);
+	}
+
+	@Override
+	public void removeSelectionListener(String partId, ISelectionListener listener) {
+		Set<ISelectionListener> listeners = targetedListeners.get(partId);
+		if (listeners != null) {
+			listeners.remove(listener);
+			if (listeners.size() == 0 && selectionService != null) {
+				selectionService.removeSelectionListener(partId, this.targetedListener);
+			}
+		}
+	}
+
+	@Override
+	public void removePostSelectionListener(ISelectionListener listener) {
+		postSelectionListeners.remove(listener);
+	}
+
+	@Override
+	public void removePostSelectionListener(String partId, ISelectionListener listener) {
+		Set<ISelectionListener> listeners = targetedPostSelectionListeners.get(partId);
+		if (listeners != null) {
+			listeners.remove(listener);
+			if (listeners.size() == 0 && selectionService != null) {
+				selectionService.removePostSelectionListener(partId, targetedPostListener);
+			}
+		}
+	}
+
+	@Override
+	public void selectionChanged(SelectionChangedEvent e) {
+		MPart part = page.findPart(activePart);
+		ESelectionService selectionService = (ESelectionService) part.getContext().get(
+				ESelectionService.class.getName());
+		selectionService.setSelection(e.getSelection());
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/migration/ApplicationBuilder.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/migration/ApplicationBuilder.java
new file mode 100644
index 0000000..97c1c63
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/migration/ApplicationBuilder.java
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.ui.internal.e4.migration;
+
+import java.io.StringReader;
+import java.util.List;
+import java.util.Map;
+import javax.inject.Inject;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.e4.core.di.extensions.Preference;
+import org.eclipse.e4.ui.model.application.MAddon;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.ui.MUIElement;
+import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective;
+import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.WorkbenchException;
+import org.eclipse.ui.XMLMemento;
+import org.eclipse.ui.internal.IWorkbenchConstants;
+import org.eclipse.ui.internal.Workbench;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+
+@SuppressWarnings("restriction")
+public class ApplicationBuilder {
+
+	@Inject
+	private MApplication application;
+
+	@Inject
+	private WorkbenchMementoReader reader;
+
+	@Inject
+	private IModelBuilderFactory builderFactory;
+
+	@Inject
+	@Preference(nodePath = "org.eclipse.ui.workbench")
+	private IEclipsePreferences preferences;
+
+	private Map<String, String> minMaxPersistedState;
+
+	void createApplication() {
+		List<MWindow> windows = application.getChildren();
+		for (WindowReader windowReader : reader.getWindowReaders()) {
+			WindowBuilder windowBuilder = builderFactory.createWindowBuilder(windowReader);
+			MWindow window = windowBuilder.createWindow();
+			windows.add(window);
+			if (windowBuilder.isSelected()) {
+				application.setSelectedElement(window);
+			}
+			Object list = window.getTransientData().remove(WindowBuilder.PERSPECTIVES);
+			if (list instanceof List<?>) {
+				List<MPerspective> perspectiveList = (List<MPerspective>) list;
+				for (MPerspective perspective : perspectiveList) {
+					importToolbarsLocation(perspective);
+				}
+			}
+		}
+		addClosedPerspectives();
+		addMRU();
+	}
+
+	private void addClosedPerspectives() {
+		String perspProp = preferences.get(IWorkbenchConstants.TAG_PERSPECTIVES, null);
+		if (perspProp == null) {
+			return;
+		}
+		List<MUIElement> snippets = application.getSnippets();
+		for (String perspName : perspProp.split(" ")) { //$NON-NLS-1$
+			IMemento memento = null;
+			try {
+				memento = XMLMemento.createReadRoot(new StringReader(preferences.get(perspName + "_persp", ""))); //$NON-NLS-1$ //$NON-NLS-2$
+			} catch (WorkbenchException e) {
+				WorkbenchPlugin.log("Loading custom perspective failed: " + perspName, e); //$NON-NLS-1$
+			}
+			snippets.add(builderFactory.createPerspectiveBuilder(new PerspectiveReader(memento)).createPerspective());
+		}
+	}
+
+	private void addMRU() {
+		application.getPersistedState().put(Workbench.MEMENTO_KEY,
+				new MementoSerializer(reader.getMruMemento()).serialize());
+	}
+
+	private void importToolbarsLocation(MPerspective persp) {
+		String trimsData = persp.getPersistedState().get("trims"); //$NON-NLS-1$
+		if (trimsData == null || trimsData.trim().isEmpty()) {
+			return;
+		}
+		persp.getPersistedState().remove("trims"); //$NON-NLS-1$
+		Map<String, String> minMaxPersState = getMinMaxPersistedState();
+		if (minMaxPersState == null) {
+			return;
+		}
+		minMaxPersState.put(persp.getElementId(), trimsData);
+	}
+
+	private Map<String, String> getMinMaxPersistedState() {
+		if (minMaxPersistedState != null) {
+			return minMaxPersistedState;
+		}
+		for (MAddon addon : application.getAddons()) {
+			if ("MinMax Addon".equals(addon.getElementId())) { //$NON-NLS-1$
+				minMaxPersistedState = addon.getPersistedState();
+				break;
+			}
+		}
+		return minMaxPersistedState;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/migration/IModelBuilderFactory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/migration/IModelBuilderFactory.java
new file mode 100644
index 0000000..32a7f21
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/migration/IModelBuilderFactory.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.ui.internal.e4.migration;
+
+public interface IModelBuilderFactory {
+
+	ApplicationBuilder createApplicationBuilder(WorkbenchMementoReader reader);
+
+	WindowBuilder createWindowBuilder(WindowReader windowReader);
+
+	PerspectiveBuilder createPerspectiveBuilder(PerspectiveReader perspReader);
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/migration/InfoReader.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/migration/InfoReader.java
new file mode 100644
index 0000000..65bcbdc
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/migration/InfoReader.java
@@ -0,0 +1,145 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.ui.internal.e4.migration;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IPageLayout;
+import org.eclipse.ui.internal.IWorkbenchConstants;
+
+public class InfoReader extends MementoReader {
+
+	private List<PageReader> pages;
+
+	private IMemento memFolder;
+
+	InfoReader(IMemento memento) {
+		super(memento);
+	}
+
+	String getId() {
+		return getString(IWorkbenchConstants.TAG_PART);
+	}
+
+	boolean isRelativelyPositioned() {
+		return contains(IWorkbenchConstants.TAG_RATIO);
+	}
+
+	boolean isFolder() {
+		return getBoolean(IWorkbenchConstants.TAG_FOLDER);
+	}
+
+	boolean isEditorArea() {
+		String id = getId();
+		return IPageLayout.ID_EDITOR_AREA.equals(id);
+	}
+
+	private IMemento getFolder() {
+		if (memFolder == null) {
+			memFolder = memento.getChild(IWorkbenchConstants.TAG_FOLDER);
+		}
+		return memFolder;
+	}
+
+	int[] getPartOrder() {
+		IMemento folder = getFolder();
+		if (folder == null) {
+			return null;
+		}
+
+		IMemento presentation = folder.getChild(IWorkbenchConstants.TAG_PRESENTATION);
+		if (presentation == null) {
+			return null;
+		}
+
+		IMemento[] partPositions = presentation.getChildren(IWorkbenchConstants.TAG_PART);
+		int[] partOrder = new int[partPositions.length];
+		for (int i = 0; i < partPositions.length; i++) {
+			partOrder[i] = partPositions[i].getInteger(IWorkbenchConstants.TAG_ID);
+		}
+		return partOrder;
+	}
+
+	List<PageReader> getPages() {
+		if (pages != null) {
+			return pages;
+		}
+
+		IMemento folder = getFolder();
+		if (folder != null) {
+			IMemento[] pageMems = folder.getChildren(IWorkbenchConstants.TAG_PAGE);
+			pages = new ArrayList<>(pageMems.length);
+			for (IMemento pageMem : pageMems) {
+				pages.add(new PageReader(pageMem));
+			}
+		}
+		return pages;
+	}
+
+	String getActivePageId() {
+		String activePageId = null;
+		IMemento folder = getFolder();
+		if (folder != null) {
+			activePageId = folder.getString(IWorkbenchConstants.TAG_ACTIVE_PAGE_ID);
+		}
+		return activePageId;
+	}
+
+	float getRatio() {
+		return getFloat(IWorkbenchConstants.TAG_RATIO);
+	}
+
+	int getRelationship() {
+		return getInteger(IWorkbenchConstants.TAG_RELATIONSHIP);
+	}
+
+	String getRelative() {
+		return getString(IWorkbenchConstants.TAG_RELATIVE);
+	}
+
+	public PartState getState() {
+		PartState state = PartState.RESTORED;
+		IMemento folder = getFolder();
+		int value = folder.getInteger(IWorkbenchConstants.TAG_EXPANDED);
+		switch (value) {
+		case 0:
+			state = PartState.MINIMIZED;
+			break;
+		case 1:
+			state = PartState.MAXIMIZED;
+			break;
+		}
+		return state;
+	}
+
+	public static enum PartState {
+		MINIMIZED, MAXIMIZED, RESTORED;
+	}
+
+	static class PageReader extends MementoReader {
+
+		PageReader(IMemento pageMemento) {
+			super(pageMemento);
+		}
+
+		String getId() {
+			return getString(IWorkbenchConstants.TAG_CONTENT);
+		}
+
+		String getLabel() {
+			return getString(IWorkbenchConstants.TAG_LABEL);
+		}
+
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/migration/MementoReader.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/migration/MementoReader.java
new file mode 100644
index 0000000..af3dea6
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/migration/MementoReader.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.ui.internal.e4.migration;
+
+import java.util.Arrays;
+import org.eclipse.ui.IMemento;
+
+public class MementoReader {
+
+	protected IMemento memento;
+
+	MementoReader() {
+	}
+
+	MementoReader(IMemento memento) {
+		this.memento = memento;
+	}
+
+	protected String getString(String attribute) {
+		return memento.getString(attribute);
+	}
+
+	/**
+	 * @param attribute
+	 * @return value or false when attribute not found
+	 */
+	protected boolean getBoolean(String attribute) {
+		return Boolean.TRUE.equals(memento.getBoolean(attribute));
+	}
+
+	protected boolean getBoolean(String attribute, boolean defaultValue) {
+		Boolean value = memento.getBoolean(attribute);
+		return value == null ? defaultValue : value;
+	}
+
+	protected Integer getInteger(String attribute) {
+		return memento.getInteger(attribute);
+	}
+
+	protected Float getFloat(String attribute) {
+		return memento.getFloat(attribute);
+	}
+
+	protected boolean contains(String attribute) {
+		return Arrays.asList(memento.getAttributeKeys()).contains(attribute);
+	}
+
+	protected IMemento[] getChildren(String tagName) {
+		return memento.getChildren(tagName);
+	}
+
+	protected IMemento getChild(String tagName) {
+		return memento.getChild(tagName);
+	}
+
+	IMemento getMemento() {
+		return memento;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/migration/MementoSerializer.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/migration/MementoSerializer.java
new file mode 100644
index 0000000..9e6c5fd
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/migration/MementoSerializer.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.ui.internal.e4.migration;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.XMLMemento;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+
+public class MementoSerializer {
+
+	private IMemento memento;
+
+	MementoSerializer(IMemento memento) {
+		this.memento = memento;
+	}
+
+	String serialize() {
+		if (!(memento instanceof XMLMemento)) {
+			return null;
+		}
+		StringWriter writer = new StringWriter();
+		try {
+			((XMLMemento) memento).save(writer);
+		} catch (IOException e) {
+			WorkbenchPlugin.log(e);
+		}
+		return writer.toString();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/migration/ModelBuilderFactoryImpl.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/migration/ModelBuilderFactoryImpl.java
new file mode 100644
index 0000000..0fcb132
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/migration/ModelBuilderFactoryImpl.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.ui.internal.e4.migration;
+
+import javax.inject.Inject;
+import org.eclipse.e4.core.contexts.ContextInjectionFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+
+public class ModelBuilderFactoryImpl implements IModelBuilderFactory {
+
+	@Inject
+	private IEclipseContext context;
+
+	@Override
+	public WindowBuilder createWindowBuilder(WindowReader windowReader) {
+		IEclipseContext childContext = context.createChild();
+		childContext.set(WindowReader.class, windowReader);
+		return ContextInjectionFactory.make(WindowBuilder.class, childContext);
+	}
+
+	@Override
+	public PerspectiveBuilder createPerspectiveBuilder(PerspectiveReader perspReader) {
+		IEclipseContext childContext = context.createChild();
+		childContext.set(PerspectiveReader.class, perspReader);
+		return ContextInjectionFactory.make(PerspectiveBuilder.class,
+				childContext);
+	}
+
+	@Override
+	public ApplicationBuilder createApplicationBuilder(WorkbenchMementoReader reader) {
+		IEclipseContext childContext = context.createChild();
+		childContext.set(WorkbenchMementoReader.class, reader);
+		return ContextInjectionFactory.make(ApplicationBuilder.class,
+				childContext);
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/migration/PerspectiveBuilder.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/migration/PerspectiveBuilder.java
new file mode 100644
index 0000000..2151df0
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/migration/PerspectiveBuilder.java
@@ -0,0 +1,719 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 2016 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.ui.internal.e4.migration;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.e4.ui.model.application.ui.MElementContainer;
+import org.eclipse.e4.ui.model.application.ui.MUIElement;
+import org.eclipse.e4.ui.model.application.ui.SideValue;
+import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective;
+import org.eclipse.e4.ui.model.application.ui.advanced.MPlaceholder;
+import org.eclipse.e4.ui.model.application.ui.basic.MPartSashContainer;
+import org.eclipse.e4.ui.model.application.ui.basic.MPartSashContainerElement;
+import org.eclipse.e4.ui.model.application.ui.basic.MPartStack;
+import org.eclipse.e4.ui.model.application.ui.basic.MStackElement;
+import org.eclipse.e4.ui.model.application.ui.basic.MTrimmedWindow;
+import org.eclipse.e4.ui.workbench.IPresentationEngine;
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.ui.IPageLayout;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.IWorkbenchConstants;
+import org.eclipse.ui.internal.PerspectiveTagger;
+import org.eclipse.ui.internal.e4.compatibility.ModeledPageLayout;
+import org.eclipse.ui.internal.e4.compatibility.ModeledPageLayoutUtils;
+import org.eclipse.ui.internal.e4.migration.InfoReader.PageReader;
+import org.eclipse.ui.internal.e4.migration.InfoReader.PartState;
+import org.eclipse.ui.internal.e4.migration.PerspectiveReader.DetachedWindowReader;
+import org.eclipse.ui.internal.e4.migration.PerspectiveReader.ViewLayoutReader;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.registry.RegistryReader;
+import org.eclipse.ui.internal.registry.StickyViewDescriptor;
+
+public class PerspectiveBuilder {
+
+	static final String ORIGINAL_ID = "originalId"; //$NON-NLS-1$
+
+	static final String BASE_PERSPECTIVE_ID = "basePerspectiveId"; //$NON-NLS-1$
+
+	private static final String DEFAULT_FASTVIEW_STACK = "defaultFastViewStack"; //$NON-NLS-1$
+
+	private static final String ID_EDITOR_AREA = IPageLayout.ID_EDITOR_AREA;
+
+	@Inject
+	private PerspectiveReader perspReader;
+
+	@Inject
+	private EModelService modelService;
+
+	private MPerspective perspective;
+
+	private List<String> tags;
+
+	private List<String> renderedViews;
+
+	private List<String> defaultFastViews;
+
+	private Map<String, MPlaceholder> viewPlaceholders = new HashMap<>();
+
+	private Map<String, ViewLayoutReader> viewLayouts;
+
+	private MPlaceholder editorAreaPlaceholder;
+
+	private ModeledPageLayoutUtils layoutUtils;
+
+	private Integer defaultFastViewSide;
+
+	@PostConstruct
+	private void postConstruct() {
+		layoutUtils = new ModeledPageLayoutUtils(modelService);
+	}
+
+	public MPerspective createPerspective() {
+		create();
+		tags = perspective.getTags();
+		populate();
+		return perspective;
+	}
+
+	public MPerspective createPerspective(Integer defaultFastViewSide) {
+		this.defaultFastViewSide = defaultFastViewSide;
+		return createPerspective();
+	}
+
+	private void create() {
+		perspective = modelService.createModelElement(MPerspective.class);
+		perspective.setElementId(perspReader.getId());
+		String label = perspReader.getLabel();
+		perspective.setLabel(label);
+		perspective.setTooltip(label);
+		if (perspReader.isCustom()) {
+			perspective.getTransientData().put(BASE_PERSPECTIVE_ID, perspReader.getBasicPerspectiveId());
+			perspective.getTransientData().put(ORIGINAL_ID, perspReader.getOriginalId());
+		}
+	}
+
+	private void populate() {
+		addActionSetTags();
+		addPerspectiveShortcutTags();
+		addNewWizardTags();
+		addShowViewTags();
+		addHiddenItems();
+		addShowInTags();
+
+		for (InfoReader info : perspReader.getInfos()) {
+			if (info.isEditorArea()) {
+				addEditorArea(info);
+			} else if (info.isFolder()) {
+				MPartStack stack = addPartStack(info);
+				populatePartStack(stack, info);
+			}
+		}
+
+		addDefaultFastViewStack();
+		setZoomState();
+		addDetachedWindows();
+		hideEmptyStacks();
+		hideUrenderableSashes();
+		hideInvisibleSashes();
+		processStandaloneViews();
+		correctSelectedElements();
+		addTrimBars();
+		PerspectiveTagger.tagPerspective(perspective, modelService);
+	}
+
+	private void processStandaloneViews() {
+		Map<String, ViewLayoutReader> viewLayouts = perspReader.getViewLayouts();
+		for (Entry<String, ViewLayoutReader> entry : viewLayouts.entrySet()) {
+			String viewId = entry.getKey();
+			MPlaceholder placeholder = viewPlaceholders.get(viewId);
+			if (placeholder == null) {
+				continue;
+			}
+			if (entry.getValue().isStandalone()) {
+				MElementContainer<MUIElement> parent = placeholder.getParent();
+				placeholder.setContainerData(parent.getContainerData());
+				parent.getChildren().remove(placeholder);
+				MElementContainer<MUIElement> grandParent = parent.getParent();
+				int location = grandParent.getChildren().indexOf(parent);
+				grandParent.getChildren().add(location, placeholder);
+				grandParent.getChildren().remove(parent);
+			}
+		}
+	}
+
+	private void addDetachedWindows() {
+		for (DetachedWindowReader detachedWindowReader : perspReader.getDetachedWindows()) {
+			MTrimmedWindow detachedWindow = modelService.createModelElement(MTrimmedWindow.class);
+			Rectangle bounds = detachedWindowReader.getBounds();
+			detachedWindow.setX(bounds.x);
+			detachedWindow.setY(bounds.y);
+			detachedWindow.setWidth(bounds.width);
+			detachedWindow.setHeight(bounds.height);
+			MPartStack stack = modelService.createModelElement(MPartStack.class);
+			populatePartStack(stack, detachedWindowReader);
+			detachedWindow.getChildren().add(stack);
+			perspective.getWindows().add(detachedWindow);
+		}
+	}
+
+	private void addTrimBars() {
+		Map<String, Integer> fastViewBars = perspReader.getFastViewBars();
+		if (fastViewBars.size() == 0 && defaultFastViews.size() == 0) {
+			return;
+		}
+
+		int topCounter = 0;
+		int bottomCounter = 0;
+		int rightCounter = 0;
+		int leftCounter = 0;
+		StringBuilder sb = new StringBuilder();
+
+		if (defaultFastViews.size() > 0) {
+			sb.append(DEFAULT_FASTVIEW_STACK).append(' ');
+			if (defaultFastViewSide != null) {
+				switch (defaultFastViewSide) {
+				case SWT.TOP:
+					sb.append(SideValue.TOP_VALUE).append(' ').append(topCounter++);
+					break;
+				case SWT.BOTTOM:
+					sb.append(SideValue.BOTTOM_VALUE).append(' ').append(bottomCounter++);
+					break;
+				case SWT.RIGHT:
+					sb.append(SideValue.RIGHT_VALUE).append(' ').append(rightCounter++);
+					break;
+				default:
+					sb.append(SideValue.LEFT_VALUE).append(' ').append(leftCounter++);
+					break;
+				}
+			} else {
+				sb.append(SideValue.BOTTOM_VALUE).append(' ').append(bottomCounter++);
+			}
+			sb.append('#');
+		}
+
+		if (fastViewBars.size() > 0) {
+			for (InfoReader folder : perspReader.getInfos()) {
+				String folderId = folder.getId();
+				if (!fastViewBars.containsKey(folderId)) {
+					continue;
+				}
+
+				sb.append(folderId).append(' ');
+
+				Integer side = fastViewBars.get(folderId);
+				if (side == null) {
+					side = SWT.LEFT;
+				}
+
+				switch (side) {
+				case SWT.TOP:
+					sb.append(SideValue.TOP_VALUE).append(' ').append(topCounter++);
+					break;
+				case SWT.BOTTOM:
+					sb.append(SideValue.BOTTOM_VALUE).append(' ').append(bottomCounter++);
+					break;
+				case SWT.RIGHT:
+					sb.append(SideValue.RIGHT_VALUE).append(' ').append(rightCounter++);
+					break;
+				default:
+					sb.append(SideValue.LEFT_VALUE).append(' ').append(leftCounter++);
+					break;
+				}
+
+				sb.append('#');
+			}
+		}
+		perspective.getPersistedState().put("trims", sb.toString()); //$NON-NLS-1$
+	}
+
+	private void hideEmptyStacks() {
+		for (MPartStack stack : modelService.findElements(perspective, null, MPartStack.class, null)) {
+			if (ID_EDITOR_AREA.equals(stack.getElementId()) || ID_EDITOR_AREA.equals(stack.getParent().getElementId())) {
+				continue;
+			}
+			if (!hasRenderableContent(stack)) {
+				stack.setToBeRendered(false);
+			}
+		}
+	}
+
+	private void setZoomState() {
+		List<MPartStack> stacks = modelService.findElements(perspective, null, MPartStack.class, null);
+		boolean isAnythingMaximized = isMaximized(editorAreaPlaceholder) || isAnyMaximized(stacks);
+		if (isAnythingMaximized) {
+			markMinimizedByZoom(editorAreaPlaceholder);
+			for (MPartStack stack : stacks) {
+				markMinimizedByZoom(stack);
+			}
+		}
+	}
+
+	private void markMinimizedByZoom(MUIElement element) {
+		List<String> tags = element.getTags();
+		if (tags.contains(IPresentationEngine.MINIMIZED)) {
+			tags.add(IPresentationEngine.MINIMIZED_BY_ZOOM);
+		}
+	}
+
+	private boolean isAnyMaximized(List<MPartStack> stacks) {
+		for (MPartStack stack : stacks) {
+			if (isMaximized(stack)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	private boolean isMaximized(MUIElement element) {
+		return element.getTags().contains(IPresentationEngine.MAXIMIZED);
+	}
+
+	private void hideUrenderableSashes() {
+		for (MPartSashContainer sash : modelService.findElements(perspective, null, MPartSashContainer.class, null)) {
+			hideUnrenderableSash(sash);
+		}
+	}
+
+	private void hideInvisibleSashes() {
+		for (MPartSashContainer sash : modelService.findElements(perspective, null, MPartSashContainer.class, null)) {
+			hideInvisibleSash(sash);
+		}
+	}
+
+	private void hideInvisibleSash(MElementContainer<?> container) {
+		if ((container instanceof MPartSashContainer) && container != perspective) {
+			if (!hasVisibleContent((MPartSashContainer) container)) {
+				container.setVisible(false);
+				hideInvisibleSash(container.getParent());
+			}
+		}
+	}
+
+	private boolean hasVisibleContent(MPartSashContainer sash) {
+		for (MPartSashContainerElement child : sash.getChildren()) {
+			if (child.isVisible()) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	private void hideUnrenderableSash(MElementContainer<?> container) {
+		if ((container instanceof MPartSashContainer) && container != perspective) {
+			if (modelService.countRenderableChildren(container) == 0) {
+				container.setToBeRendered(false);
+				hideUnrenderableSash(container.getParent());
+			}
+		}
+	}
+
+	private boolean hasRenderableContent(MPartStack stack) {
+		for (MStackElement child : stack.getChildren()) {
+			if (child.isVisible() && child.isToBeRendered()) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	private void correctSelectedElements() {
+		List<MPartSashContainerElement> perspChildren = perspective.getChildren();
+		if (perspective.getSelectedElement() == null && !perspChildren.isEmpty()) {
+			for (MPartSashContainerElement child : perspChildren) {
+				if (child.isToBeRendered()) {
+					perspective.setSelectedElement(child);
+					break;
+				}
+			}
+		}
+
+		for (MPartSashContainerElement child : perspChildren) {
+			correctSelectedElements(child);
+		}
+	}
+
+	private void correctSelectedElements(MUIElement element) {
+		if (!(element instanceof MPartSashContainer || element instanceof MPartStack)) {
+			return;
+		}
+		@SuppressWarnings("unchecked")
+		MElementContainer<MUIElement> container = (MElementContainer<MUIElement>) element;
+		List<MUIElement> children = container.getChildren();
+		if (container.getSelectedElement() == null && !children.isEmpty()) {
+			MUIElement firstRenderableElement = getFirstRenderableElement(children);
+			if (firstRenderableElement != null) {
+				container.setSelectedElement(firstRenderableElement);
+			}
+		}
+		for (MUIElement child : children) {
+			correctSelectedElements(child);
+		}
+	}
+
+	private MUIElement getFirstRenderableElement(List<MUIElement> elements) {
+		for (MUIElement element : elements) {
+			if (element.isToBeRendered()) {
+				return element;
+			}
+		}
+		return null;
+	}
+
+	private void addToPerspective(MPartSashContainerElement element, InfoReader info) {
+		if (info.isRelativelyPositioned()) {
+			insert(element, info);
+		} else {
+			perspective.getChildren().add(element);
+		}
+	}
+
+	private void addEditorArea(InfoReader info) {
+		editorAreaPlaceholder = modelService.createModelElement(MPlaceholder.class);
+		editorAreaPlaceholder.setElementId(ID_EDITOR_AREA);
+		editorAreaPlaceholder.setToBeRendered(perspReader.isEditorAreaVisible());
+		setPartState(editorAreaPlaceholder, perspReader.getEditorAreaState());
+		addToPerspective(editorAreaPlaceholder, info);
+	}
+
+	private MPartStack addPartStack(InfoReader info) {
+		MPartStack stack = createPartStack(info);
+		if (info.isRelativelyPositioned()) {
+			String refElementId = info.getRelative();
+			MUIElement refElement = modelService.find(refElementId, perspective);
+			MElementContainer<?> parent = refElement.getParent();
+			// don't put a stack in another stack
+			if (parent instanceof MPartStack) {
+				refElement = parent;
+			}
+
+			insert(stack, refElement, info);
+		} else {
+			perspective.getChildren().add(stack);
+		}
+		setPartState(stack, info.getState());
+		return stack;
+	}
+
+	private MPartStack addDefaultFastViewStack() {
+		MPartStack stack = null;
+		List<String> views = perspReader.getDefaultFastViewBarViewIds();
+		if (views.size() > 0) {
+			stack = layoutUtils.createStack(DEFAULT_FASTVIEW_STACK, true);
+			MPartSashContainer psc = modelService.createModelElement(MPartSashContainer.class);
+			psc.setHorizontal(true);
+			psc.setContainerData(Integer.toString(5000));
+			stack.setContainerData(Integer.toString(2500));
+			psc.getChildren().add(stack);
+			List<MPartSashContainer> list = modelService.findElements(perspective, null, MPartSashContainer.class,
+					null);
+			if (list == null || list.size() == 0) {
+				perspective.getChildren().add(psc);
+			} else {
+				int size = list.size();
+				MPartSashContainer container = list.get(size - 1);
+				container.getChildren().add(psc);
+			}
+			setPartState(stack, org.eclipse.ui.internal.e4.migration.InfoReader.PartState.MINIMIZED);
+
+			for (String view : views) {
+				addPlaceholderToDefaultFastViewStack(stack, view, null);
+			}
+		}
+		return stack;
+	}
+
+	private void setPartState(MUIElement element, PartState state) {
+		List<String> tags = element.getTags();
+		switch (state) {
+		case MINIMIZED:
+			tags.add(IPresentationEngine.MINIMIZED);
+			element.setVisible(false);
+			break;
+		case MAXIMIZED:
+			tags.add(IPresentationEngine.MAXIMIZED);
+			break;
+		default:
+			break;
+		}
+	}
+
+	private void insert(MUIElement element, MUIElement refElement, InfoReader info) {
+		layoutUtils.insert(element, refElement, layoutUtils.plRelToSwt(info.getRelationship()), info.getRatio());
+	}
+
+	private void insert(MUIElement element, InfoReader info) {
+		insert(element, modelService.find(info.getRelative(), perspective), info);
+	}
+
+	private MPartStack createPartStack(InfoReader info) {
+		String stackId = info.getId();
+		if (stackId != null) {
+			if (stackId.equals(StickyViewDescriptor.STICKY_FOLDER_RIGHT)) {
+				stackId = "legacyStickyFolderRight"; //$NON-NLS-1$
+			}
+		}
+		return layoutUtils.createStack(stackId, true);
+	}
+
+	private void populatePartStack(MPartStack stack, InfoReader info) {
+		for (PageReader page : info.getPages()) {
+			addPlaceholderToStack(stack, page.getId(), page.getLabel());
+		}
+		MStackElement selectedElement = (MStackElement) modelService.find(info.getActivePageId(), stack);
+		if (selectedElement != null) {
+			selectedElement.setToBeRendered(true);
+			selectedElement.setVisible(true);
+		}
+		stack.setSelectedElement(selectedElement);
+
+		// restore order of views in the stacks
+		List<MStackElement> renderedViews = getRenderedViews(stack);
+		if (renderedViews.size() < 2) {
+			return;
+		}
+
+		int[] partOrder = info.getPartOrder();
+		List<MStackElement> stackChildren = stack.getChildren();
+		// unexpected situation - don't order
+		if (partOrder == null || partOrder.length != renderedViews.size()) {
+			return;
+		}
+		List<MStackElement> originalOrder = new ArrayList<>(renderedViews);
+		stackChildren.clear();
+		for (int element : partOrder) {
+			stackChildren.add(originalOrder.get(element));
+		}
+		originalOrder.removeAll(stackChildren);
+		stackChildren.addAll(originalOrder);
+	}
+
+	private List<MStackElement> getRenderedViews(MPartStack stack) {
+		List<MStackElement> renderedViews = new ArrayList<>();
+		for (MStackElement element : stack.getChildren()) {
+			if (element.isToBeRendered()) {
+				renderedViews.add(element);
+			}
+		}
+		return renderedViews;
+	}
+
+	private void populatePartStack(MPartStack stack, DetachedWindowReader info) {
+		for (PageReader page : info.getPages()) {
+			addPlaceholderToStack(stack, page.getId(), page.getLabel());
+		}
+		stack.setSelectedElement((MStackElement) modelService.find(info.getActivePageId(), stack));
+	}
+
+	private void addPlaceholderToStack(MPartStack stack, String partId, String label) {
+		if (partId == null || isDefaultFastView(partId)) {
+			return;
+		}
+		MPlaceholder placeholder = createPlaceHolder(partId, label);
+		if (!isToBeRendered(placeholder)) {
+			placeholder.setToBeRendered(false);
+		}
+		addLayoutTagsToPlaceholder(placeholder, partId);
+		stack.getChildren().add(placeholder);
+		viewPlaceholders.put(partId, placeholder);
+	}
+
+	private void addPlaceholderToDefaultFastViewStack(MPartStack stack, String partId, String label) {
+		MPlaceholder placeholder = createPlaceHolder(partId, label);
+		if (!isDefaultFastView(placeholder)) {
+			placeholder.setToBeRendered(false);
+		}
+		addLayoutTagsToPlaceholder(placeholder, partId);
+		stack.getChildren().add(placeholder);
+		viewPlaceholders.put(partId, placeholder);
+	}
+
+	private void addLayoutTagsToPlaceholder(MPlaceholder placeholder, String partId) {
+		ViewLayoutReader viewLayout = getViewLayout(partId);
+		if (viewLayout == null) {
+			return;
+		}
+		List<String> tags = placeholder.getTags();
+		if (!viewLayout.isCloseable()) {
+			tags.add(IPresentationEngine.NO_CLOSE);
+		}
+		if (viewLayout.isStandalone()) {
+			tags.add(IPresentationEngine.STANDALONE);
+		}
+	}
+
+	private boolean isToBeRendered(MPlaceholder placeholder) {
+		if (renderedViews == null) {
+			renderedViews = perspReader.getRenderedViewIds();
+		}
+		return renderedViews.contains(placeholder.getElementId());
+	}
+
+	private boolean isDefaultFastView(MPlaceholder placeholder) {
+		if (defaultFastViews == null) {
+			defaultFastViews = perspReader.getDefaultFastViewBarViewIds();
+		}
+		return defaultFastViews.contains(placeholder.getElementId());
+	}
+
+	private boolean isDefaultFastView(String placeholderId) {
+		if (defaultFastViews == null) {
+			defaultFastViews = perspReader.getDefaultFastViewBarViewIds();
+		}
+		return defaultFastViews.contains(placeholderId);
+	}
+
+	private void addPerspectiveShortcutTags() {
+		for (String shortcutId : perspReader.getPerspectiveShortcutIds()) {
+			tags.add(ModeledPageLayout.PERSP_SHORTCUT_TAG + shortcutId);
+		}
+	}
+
+	private void addActionSetTags() {
+		for (String actionSetId : perspReader.getActionSetIds()) {
+			tags.add(ModeledPageLayout.ACTION_SET_TAG + actionSetId);
+		}
+	}
+
+	private void addShowInTags() {
+		String origId = null;
+		if (perspReader.isCustom()) {
+			origId = perspReader.getBasicPerspectiveId();
+		} else {
+			origId = perspReader.getId();
+		}
+		ArrayList<String> list = getShowInPartFromRegistry(origId);
+		if (list != null) {
+			for (String showIn : list) {
+				tags.add(ModeledPageLayout.SHOW_IN_PART_TAG + showIn);
+			}
+		}
+		return;
+	}
+
+	public static ArrayList<String> getShowInPartFromRegistry(String targetId) {
+		ArrayList<String> list = new ArrayList<>();
+		IExtension[] extensions = getPerspectiveExtensions();
+		if (extensions != null) {
+			for (IExtension extension : extensions) {
+				list.addAll(getExtensionShowInPartFromRegistry(extension, targetId));
+			}
+		}
+		return list;
+	}
+
+	private static IExtension[] getPerspectiveExtensions() {
+		IExtensionPoint point = Platform.getExtensionRegistry().getExtensionPoint(PlatformUI.PLUGIN_ID,
+				IWorkbenchRegistryConstants.PL_PERSPECTIVE_EXTENSIONS);
+        if (point == null) {
+			return null;
+		}
+		IExtension[] extensions = point.getExtensions();
+        extensions = RegistryReader.orderExtensions(extensions);
+		return extensions;
+	}
+
+	private static ArrayList<String> getExtensionShowInPartFromRegistry(IExtension extension, String targetId) {
+		ArrayList<String> list = new ArrayList<>();
+		IConfigurationElement[] configElements = extension.getConfigurationElements();
+		for (IConfigurationElement configElement : configElements) {
+			String type = configElement.getName();
+			if (type.equals(IWorkbenchRegistryConstants.TAG_PERSPECTIVE_EXTENSION)) {
+				String id = configElement.getAttribute(IWorkbenchRegistryConstants.ATT_TARGET_ID);
+				if (targetId.equals(id) || "*".equals(id)) { //$NON-NLS-1$
+					list.addAll(getConfigElementShowInPartsFromRegistry(configElement));
+				}
+			}
+		}
+		return list;
+	}
+
+	private static ArrayList<String> getConfigElementShowInPartsFromRegistry(IConfigurationElement configElement) {
+		ArrayList<String> list = new ArrayList<>();
+		String tag = IWorkbenchRegistryConstants.TAG_SHOW_IN_PART;
+		IConfigurationElement[] children = configElement.getChildren();
+		for (IConfigurationElement child : children) {
+			String ctype = child.getName();
+			if (tag.equals(ctype)) {
+				String tid = child.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+				if (tid != null) {
+					list.add(tid);
+				}
+			}
+		}
+		return list;
+	}
+
+	private void addNewWizardTags() {
+		for (String actionId : perspReader.getNewWizardActionIds()) {
+			tags.add(ModeledPageLayout.NEW_WIZARD_TAG + actionId);
+		}
+	}
+
+	private void addShowViewTags() {
+		for (String actionId : perspReader.getShowViewActionIds()) {
+			tags.add(ModeledPageLayout.SHOW_VIEW_TAG + actionId);
+		}
+	}
+
+	private void addHiddenItems() {
+		String comma = ","; //$NON-NLS-1$
+		StringBuilder persistedValue = new StringBuilder();
+		for (String elementId : perspReader.getHiddenMenuItemIds()) {
+			persistedValue.append(ModeledPageLayout.HIDDEN_MENU_PREFIX);
+			persistedValue.append(elementId).append(comma);
+		}
+		for (String elementId : perspReader.getHiddenToolbarItemIds()) {
+			persistedValue.append(ModeledPageLayout.HIDDEN_TOOLBAR_PREFIX);
+			persistedValue.append(elementId).append(comma);
+		}
+		perspective.getPersistedState().put(ModeledPageLayout.HIDDEN_ITEMS_KEY, persistedValue.toString());
+	}
+
+	private ViewLayoutReader getViewLayout(String viewId) {
+		if (viewLayouts == null) {
+			viewLayouts = perspReader.getViewLayouts();
+		}
+		return viewLayouts.get(viewId);
+	}
+
+	Collection<MPlaceholder> getPlaceholders() {
+		return viewPlaceholders.values();
+	}
+
+	MPlaceholder getEditorAreaPlaceholder() {
+		return editorAreaPlaceholder;
+	}
+
+	MPlaceholder createPlaceHolder(String str, String label) {
+		MPlaceholder placeholder = null;
+		placeholder = modelService.createModelElement(MPlaceholder.class);
+		placeholder.setElementId(str);
+		if (modelService.getPartDescriptor(str) == null) {
+			placeholder.getTransientData().put(IWorkbenchConstants.TAG_LABEL, label);
+		}
+		return placeholder;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/migration/PerspectiveReader.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/migration/PerspectiveReader.java
new file mode 100644
index 0000000..835427b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/migration/PerspectiveReader.java
@@ -0,0 +1,335 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.ui.internal.e4.migration;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.internal.IWorkbenchConstants;
+import org.eclipse.ui.internal.e4.migration.InfoReader.PageReader;
+import org.eclipse.ui.internal.e4.migration.InfoReader.PartState;
+
+public class PerspectiveReader extends MementoReader {
+
+	private DescriptorReader descriptor;
+
+	public PerspectiveReader(IMemento memento) {
+		super(memento);
+	}
+
+	String getId() {
+		return getDescriptor().getId();
+	}
+
+	String getLabel() {
+		return getDescriptor().getLabel();
+	}
+
+	private DescriptorReader getDescriptor() {
+		if (descriptor == null) {
+			IMemento desriptorMem = getChild(IWorkbenchConstants.TAG_DESCRIPTOR);
+			if (desriptorMem == null) {
+				throw new NullPointerException("Perspective descriptor not found"); //$NON-NLS-1$
+			}
+			descriptor = new DescriptorReader(desriptorMem);
+		}
+		return descriptor;
+	}
+
+	List<InfoReader> getInfos() {
+		IMemento[] infoMems = getInfoMems();
+		List<InfoReader> infos = new ArrayList<>(infoMems.length);
+		for (IMemento infoMem : infoMems) {
+			infos.add(new InfoReader(infoMem));
+		}
+		return infos;
+	}
+
+	private IMemento[] getInfoMems() {
+		IMemento[] infoMems = null;
+		IMemento layout = getLayout();
+		if (layout != null) {
+			IMemento mainWindow = layout.getChild(IWorkbenchConstants.TAG_MAIN_WINDOW);
+			if (mainWindow != null) {
+				infoMems = mainWindow.getChildren(IWorkbenchConstants.TAG_INFO);
+			}
+		}
+		if (infoMems == null) {
+			infoMems = new IMemento[0];
+		}
+		return infoMems;
+	}
+
+	Map<String, ViewLayoutReader> getViewLayouts() {
+		IMemento[] viewLayoutMems = getChildren(IWorkbenchConstants.TAG_VIEW_LAYOUT_REC);
+		Map<String, ViewLayoutReader> viewLayouts = new HashMap<>(viewLayoutMems.length);
+		for (IMemento memento : viewLayoutMems) {
+			ViewLayoutReader viewLayout = new ViewLayoutReader(memento);
+			viewLayouts.put(viewLayout.getViewId(), viewLayout);
+		}
+		return viewLayouts;
+	}
+
+	private IMemento getLayout() {
+		return getChild(IWorkbenchConstants.TAG_LAYOUT);
+	}
+
+	List<String> getPerspectiveShortcutIds() {
+		return getChildrenIds(IWorkbenchConstants.TAG_PERSPECTIVE_ACTION);
+	}
+
+	List<String> getActionSetIds() {
+		return getChildrenIds(IWorkbenchConstants.TAG_ALWAYS_ON_ACTION_SET);
+	}
+
+	List<String> getShowViewActionIds() {
+		return getChildrenIds(IWorkbenchConstants.TAG_SHOW_VIEW_ACTION);
+	}
+
+	List<String> getNewWizardActionIds() {
+		return getChildrenIds(IWorkbenchConstants.TAG_NEW_WIZARD_ACTION);
+	}
+
+	List<String> getRenderedViewIds() {
+		List<String> viewIds = getChildrenIds(IWorkbenchConstants.TAG_VIEW);
+		viewIds.addAll(getFastViewIds());
+		return viewIds;
+	}
+
+	/**
+	 * @return map of fast view bar's ID and side
+	 */
+	Map<String, Integer> getFastViewBars() {
+		Map<String, Integer> bars = new HashMap<>();
+		for (IMemento bar : getFastViewBarMems()) {
+			bars.put(bar.getString(IWorkbenchConstants.TAG_ID),
+					bar.getInteger(IWorkbenchConstants.TAG_FAST_VIEW_SIDE));
+		}
+		return bars;
+	}
+
+	private List<String> getFastViewIds() {
+		List<String> fastViewIds = new ArrayList<>();
+
+		IMemento fastViews = getChild(IWorkbenchConstants.TAG_FAST_VIEWS);
+		if (fastViews != null) {
+			for (IMemento view : fastViews.getChildren(IWorkbenchConstants.TAG_VIEW)) {
+				fastViewIds.add(view.getString(IWorkbenchConstants.TAG_ID));
+			}
+		}
+
+		IMemento[] fastViewBarArr = getFastViewBarMems();
+		for (IMemento fastViewBar : fastViewBarArr) {
+			IMemento fastViewsInBar = fastViewBar.getChild(IWorkbenchConstants.TAG_FAST_VIEWS);
+			if (fastViewsInBar != null) {
+				for (IMemento view : fastViewsInBar.getChildren(IWorkbenchConstants.TAG_VIEW)) {
+					fastViewIds.add(view.getString(IWorkbenchConstants.TAG_ID));
+				}
+			}
+		}
+		return fastViewIds;
+	}
+
+	List<String> getDefaultFastViewBarViewIds() {
+		List<String> fastViewIds = new ArrayList<>();
+		IMemento fastViews = getChild(IWorkbenchConstants.TAG_FAST_VIEWS);
+		if (fastViews != null) {
+			for (IMemento view : fastViews.getChildren(IWorkbenchConstants.TAG_VIEW)) {
+				fastViewIds.add(view.getString(IWorkbenchConstants.TAG_ID));
+			}
+		}
+
+		return fastViewIds;
+	}
+
+	private IMemento[] getFastViewBarMems() {
+		IMemento[] emptyArr = new IMemento[0];
+		IMemento fastViewBars = getChild(IWorkbenchConstants.TAG_FAST_VIEW_BARS);
+		if (fastViewBars == null) {
+			return emptyArr;
+		}
+		IMemento[] fastViewBarArr = fastViewBars.getChildren(IWorkbenchConstants.TAG_FAST_VIEW_BAR);
+		return fastViewBarArr == null ? emptyArr : fastViewBarArr;
+	}
+
+	List<String> getHiddenMenuItemIds() {
+		return getChildrenIds(IWorkbenchConstants.TAG_HIDE_MENU);
+	}
+
+	List<String> getHiddenToolbarItemIds() {
+		return getChildrenIds(IWorkbenchConstants.TAG_HIDE_TOOLBAR);
+	}
+
+	private List<String> getChildrenIds(String tag) {
+		IMemento[] idMemArr = getChildren(tag);
+		List<String> idList = new ArrayList<>(idMemArr.length);
+		for (IMemento idMem : idMemArr) {
+			idList.add(idMem.getString(IWorkbenchConstants.TAG_ID));
+		}
+		return idList;
+	}
+
+	List<DetachedWindowReader> getDetachedWindows() {
+		List<DetachedWindowReader> readers = new ArrayList<>();
+		IMemento layout = getLayout();
+		if (layout != null) {
+			IMemento[] mems = layout.getChildren(IWorkbenchConstants.TAG_DETACHED_WINDOW);
+			for (IMemento mem : mems) {
+				readers.add(new DetachedWindowReader(mem));
+			}
+		}
+		return readers;
+	}
+
+	boolean isCustom() {
+		return getDescriptor().isCustom();
+	}
+
+	String getBasicPerspectiveId() {
+		return getDescriptor().getBasicPerspectiveId();
+	}
+
+	String getOriginalId() {
+		return getDescriptor().getOriginalId();
+	}
+
+	boolean isEditorAreaVisible() {
+		return Integer.valueOf(1).equals(getInteger(IWorkbenchConstants.TAG_AREA_VISIBLE));
+	}
+
+	PartState getEditorAreaState() {
+		PartState state = PartState.RESTORED;
+		int value = getInteger(IWorkbenchConstants.TAG_AREA_TRIM_STATE);
+		switch (value) {
+		case 0:
+		case 4: // minimized by zoom
+			state = PartState.MINIMIZED;
+			break;
+		case 1:
+			state = PartState.MAXIMIZED;
+			break;
+		}
+		return state;
+	}
+
+	static class DetachedWindowReader extends MementoReader {
+
+		private DetachedWindowReader(IMemento memento) {
+			super(memento);
+		}
+
+		Rectangle getBounds() {
+			Rectangle windowBounds = new Rectangle(0, 0, 0, 0);
+			Integer bigInt = getInteger(IWorkbenchConstants.TAG_X);
+			windowBounds.x = bigInt == null ? 0 : bigInt.intValue();
+			bigInt = getInteger(IWorkbenchConstants.TAG_Y);
+			windowBounds.y = bigInt == null ? 0 : bigInt.intValue();
+			bigInt = getInteger(IWorkbenchConstants.TAG_WIDTH);
+			windowBounds.width = bigInt == null ? 0 : bigInt.intValue();
+			bigInt = getInteger(IWorkbenchConstants.TAG_HEIGHT);
+			windowBounds.height = bigInt == null ? 0 : bigInt.intValue();
+			return windowBounds;
+		}
+
+		String getActivePageId() {
+			String activePageId = null;
+			IMemento folder = getFolder();
+			if (folder != null) {
+				activePageId = folder.getString(IWorkbenchConstants.TAG_ACTIVE_PAGE_ID);
+			}
+			return activePageId;
+		}
+
+		List<PageReader> getPages() {
+			IMemento folder = getFolder();
+			List<PageReader> pages = new ArrayList<>();
+			if (folder != null) {
+				IMemento[] pageMems = folder.getChildren(IWorkbenchConstants.TAG_PAGE);
+				for (IMemento pageMem : pageMems) {
+					pages.add(new PageReader(pageMem));
+				}
+			}
+			return pages;
+		}
+
+		private IMemento getFolder() {
+			return getChild(IWorkbenchConstants.TAG_FOLDER);
+		}
+
+	}
+
+	private static class DescriptorReader extends MementoReader {
+
+		private static final String TAG_DESCRIPTOR = IWorkbenchConstants.TAG_DESCRIPTOR;
+
+		DescriptorReader(IMemento memento) {
+			super(memento);
+		}
+
+		String getId() {
+			String id = getOriginalId();
+			if (isCustom()) {
+				id = getBasicPerspectiveId() + "." + id; //$NON-NLS-1$
+			}
+			return id;
+		}
+
+		String getOriginalId() {
+			String id = getString(IWorkbenchConstants.TAG_ID);
+			if (id == null) {
+				throw new NullPointerException("Perspective ID not found"); //$NON-NLS-1$
+			}
+			return id;
+		}
+
+		boolean isCustom() {
+			return contains(TAG_DESCRIPTOR);
+		}
+
+		String getBasicPerspectiveId() {
+			String id = getString(TAG_DESCRIPTOR);
+			if (id == null) {
+				throw new NullPointerException("Basic perspective ID not found"); //$NON-NLS-1$
+			}
+			return id;
+		}
+
+		String getLabel() {
+			return getString(IWorkbenchConstants.TAG_LABEL);
+		}
+
+	}
+
+	static class ViewLayoutReader extends MementoReader {
+
+		private ViewLayoutReader(IMemento memento) {
+			super(memento);
+		}
+
+		String getViewId() {
+			return getString(IWorkbenchConstants.TAG_ID);
+		}
+
+		boolean isCloseable() {
+			return getBoolean(IWorkbenchConstants.TAG_CLOSEABLE, true);
+		}
+
+		boolean isStandalone() {
+			return getBoolean(IWorkbenchConstants.TAG_STANDALONE);
+		}
+
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/migration/WindowBuilder.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/migration/WindowBuilder.java
new file mode 100644
index 0000000..9d87502
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/migration/WindowBuilder.java
@@ -0,0 +1,414 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.ui.internal.e4.migration;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+import org.eclipse.e4.ui.model.application.ui.MElementContainer;
+import org.eclipse.e4.ui.model.application.ui.MUIElement;
+import org.eclipse.e4.ui.model.application.ui.SideValue;
+import org.eclipse.e4.ui.model.application.ui.advanced.MArea;
+import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective;
+import org.eclipse.e4.ui.model.application.ui.advanced.MPerspectiveStack;
+import org.eclipse.e4.ui.model.application.ui.advanced.MPlaceholder;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.model.application.ui.basic.MPartSashContainer;
+import org.eclipse.e4.ui.model.application.ui.basic.MPartStack;
+import org.eclipse.e4.ui.model.application.ui.basic.MStackElement;
+import org.eclipse.e4.ui.model.application.ui.basic.MTrimBar;
+import org.eclipse.e4.ui.model.application.ui.basic.MTrimmedWindow;
+import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolControl;
+import org.eclipse.e4.ui.model.application.ui.menu.impl.MenuFactoryImpl;
+import org.eclipse.e4.ui.workbench.IPresentationEngine;
+import org.eclipse.e4.ui.workbench.addons.minmax.TrimStack;
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+import org.eclipse.e4.ui.workbench.modeling.EPartService;
+import org.eclipse.e4.ui.workbench.renderers.swt.TrimBarLayout;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.ui.IPageLayout;
+import org.eclipse.ui.internal.IPreferenceConstants;
+import org.eclipse.ui.internal.Workbench;
+import org.eclipse.ui.internal.WorkbenchWindow;
+import org.eclipse.ui.internal.e4.compatibility.CompatibilityEditor;
+import org.eclipse.ui.internal.e4.compatibility.CompatibilityPart;
+import org.eclipse.ui.internal.e4.compatibility.ModeledPageLayout;
+import org.eclipse.ui.internal.e4.compatibility.ModeledPageLayoutUtils;
+import org.eclipse.ui.internal.e4.migration.WindowReader.EditorReader;
+import org.eclipse.ui.internal.e4.migration.WindowReader.ViewReader;
+import org.eclipse.ui.internal.registry.StickyViewDescriptor;
+import org.eclipse.ui.internal.registry.ViewRegistry;
+
+public class WindowBuilder {
+
+	private MWindow window;
+
+	private List<MUIElement> sharedElements;
+
+	private MPartSashContainer mainSash;
+
+	@Inject
+	private WindowReader windowReader;
+
+	@Inject
+	private EModelService modelService;
+
+	@Inject
+	private IModelBuilderFactory factory;
+
+	private ModeledPageLayoutUtils layoutUtils;
+
+	private MArea editorArea;
+
+	private List<MPerspective> perspectives;
+
+	public static String PERSPECTIVES = "perspectives"; //$NON-NLS-1$
+
+	@PostConstruct
+	private void postConstruct() {
+		layoutUtils = new ModeledPageLayoutUtils(modelService);
+	}
+
+	MWindow createWindow() {
+		create();
+		populate();
+		return window;
+	}
+
+	boolean isSelected() {
+		return windowReader.isSelected();
+	}
+
+	boolean isWelcomePageOpen() {
+		return windowReader.isWelcomePageOpen();
+	}
+
+	private void create() {
+		window = modelService.createModelElement(MTrimmedWindow.class);
+
+		Rectangle bounds = windowReader.getBounds();
+		window.setX(bounds.x);
+		window.setY(bounds.y);
+		window.setWidth(bounds.width);
+		window.setHeight(bounds.height);
+		window.getTags().add("topLevel"); //$NON-NLS-1$
+
+		String coolbarVisible = Boolean.TRUE.toString();
+		if (!windowReader.isCoolbarVisible() && !isWelcomePageOpen()) {
+			coolbarVisible = Boolean.FALSE.toString();
+		}
+		window.getPersistedState().put(IPreferenceConstants.COOLBAR_VISIBLE, coolbarVisible);
+		window.getPersistedState().put(IPreferenceConstants.PERSPECTIVEBAR_VISIBLE, coolbarVisible);
+
+		// necessary to force correct order of window initial
+		// rendering when there is no perspective
+		if (windowReader.isStatusBarVisible()) {
+			MTrimBar statusBar = modelService.getTrim((MTrimmedWindow) window, SideValue.BOTTOM);
+			if (windowReader.hasStatusLine()) {
+				MToolControl statusLine = modelService.createModelElement(MToolControl.class);
+				statusLine.setElementId(WorkbenchWindow.STATUS_LINE_ID);
+				statusLine.setContributionURI(WorkbenchWindow.TRIM_CONTRIBUTION_URI);
+				statusLine.getTags().add(TrimBarLayout.SPACER);
+				statusBar.getChildren().add(statusLine);
+			}
+		}
+
+		List<String> tags = window.getTags();
+		if (windowReader.isMinimized()) {
+			tags.add(IPresentationEngine.WINDOW_MINIMIZED_TAG);
+		} else if (windowReader.isMaximized()) {
+			tags.add(IPresentationEngine.WINDOW_MAXIMIZED_TAG);
+		}
+		sharedElements = window.getSharedElements();
+	}
+
+	private void populate() {
+		addEditorArea();
+		addEditors();
+		addViews();
+		perspectives = new ArrayList<>();
+		mainSash = modelService.createModelElement(MPartSashContainer.class);
+		mainSash.setHorizontal(true);
+
+		MPerspectiveStack perspectiveStack = createPerspectiveStack();
+		mainSash.getChildren().add(perspectiveStack);
+		mainSash.setSelectedElement(perspectiveStack);
+
+		window.getChildren().add(mainSash);
+		window.setSelectedElement(mainSash);
+
+		for (PerspectiveReader perspReader : windowReader.getPerspectiveReaders()) {
+			PerspectiveBuilder builder = factory.createPerspectiveBuilder(perspReader);
+			MPerspective perspective = builder.createPerspective(windowReader.getDefaultFastViewSide());
+			perspectiveStack.getChildren().add(perspective);
+			MPlaceholder eaPlaceholder = builder.getEditorAreaPlaceholder();
+			if (eaPlaceholder != null) {
+				eaPlaceholder.setRef(editorArea);
+			}
+			for (MPlaceholder viewPlaceholder : builder.getPlaceholders()) {
+				String id = viewPlaceholder.getElementId();
+				if (id != null) {
+					viewPlaceholder.setRef(getSharedView(id));
+				}
+			}
+			perspectives.add(perspective);
+		}
+
+		String activePerspectiveId = windowReader.getActivePerspectiveId();
+		if (activePerspectiveId != null) {
+			for (MPerspective persp : perspectiveStack.getChildren()) {
+				String id = persp.getElementId();
+				String originalId = (String) persp.getTransientData().get(
+						PerspectiveBuilder.ORIGINAL_ID);
+				if (originalId != null) {
+					id = originalId;
+				}
+				if (activePerspectiveId.equals(id)) {
+					perspectiveStack.setSelectedElement(persp);
+					createTrimBars(persp);
+					break;
+				}
+			}
+		}
+		addStickyFolder();
+		window.getTransientData().put(PERSPECTIVES, perspectives);
+	}
+
+	private void createTrimBars(MPerspective perspective) {
+		// Find any minimized stacks and show their trim
+		List<MUIElement> minimizedElements = modelService.findElements(perspective, null, MUIElement.class,
+				Arrays.asList(IPresentationEngine.MINIMIZED));
+		for (MUIElement element : minimizedElements) {
+			createTrim(element, perspective);
+		}
+	}
+
+	private int getBarIndex(MUIElement element, String trimStr) {
+		if (trimStr == null)
+			return -1;
+
+		String[] stacks = trimStr.split("#"); //$NON-NLS-1$
+		for (String stackInfo : stacks) {
+			String[] vals = stackInfo.split(" "); //$NON-NLS-1$
+			if (vals[0].equals(element.getElementId())) {
+				return Integer.parseInt(vals[1]);
+			}
+		}
+		return -1;
+	}
+
+	private int getIndex(MUIElement element, String trimStr) {
+		if (trimStr == null)
+			return -1;
+
+		String[] stacks = trimStr.split("#"); //$NON-NLS-1$
+		for (String stackInfo : stacks) {
+			String[] vals = stackInfo.split(" "); //$NON-NLS-1$
+			if (vals[0].equals(element.getElementId())) {
+				return Integer.parseInt(vals[2]);
+			}
+		}
+		return -1;
+	}
+
+	private void createTrim(MUIElement element, MPerspective perspective) {
+		if (!(window instanceof MTrimmedWindow)) {
+			return;
+		}
+		String trimStr = perspective.getPersistedState().get("trims"); //$NON-NLS-1$
+		MTrimmedWindow win = (MTrimmedWindow) window;
+
+		// Is there already a TrimControl there ?
+		String trimId = element.getElementId() + getMinimizedElementSuffix(perspective);
+		MToolControl trimStack = (MToolControl) modelService.find(trimId, window);
+
+		if (trimStack == null) {
+			trimStack = MenuFactoryImpl.eINSTANCE.createToolControl();
+			trimStack.setElementId(trimId);
+			trimStack.setContributionURI(TrimStack.CONTRIBUTION_URI);
+			trimStack.getTags().add("TrimStack"); //$NON-NLS-1$
+
+			// Check if we have a cached location
+			MTrimBar bar = getBarForElement(element, win, trimStr);
+			int index = getIndex(element, trimStr);
+			if (index == -1 || index >= bar.getChildren().size())
+				bar.getChildren().add(trimStack);
+			else
+				bar.getChildren().add(index, trimStack);
+
+			bar.setVisible(true);
+
+		} else {
+			// get the parent trim bar, see bug 320756
+			MUIElement parent = trimStack.getParent();
+			parent.setVisible(true);
+			trimStack.setToBeRendered(true);
+		}
+	}
+
+	private String getMinimizedElementSuffix(MPerspective perspective) {
+		String id = "(minimized)"; //$NON-NLS-1$
+		if (perspective != null) {
+			id = '(' + perspective.getElementId() + ')';
+		}
+		return id;
+	}
+
+	private MTrimBar getBarForElement(MUIElement element, MTrimmedWindow window, String trimStr) {
+		SideValue side = SideValue.get(getBarIndex(element, trimStr));
+		if (side == null) {
+			side = SideValue.BOTTOM;
+		}
+		MTrimBar bar = modelService.getTrim(window, side);
+		return bar;
+	}
+
+	private void addEditors() {
+		Map<MPartStack, InfoReader> stackToReader = new HashMap<>();
+
+		// add stacks to shared area
+		List<InfoReader> stackReaders = windowReader.getEditorStacks();
+		if (stackReaders.isEmpty()) {
+			// create default stack
+			MPartStack editorStack = modelService.createModelElement(MPartStack.class);
+			editorStack.getTags().add(ModeledPageLayout.EDITOR_STACK_TAG);
+			editorArea.getChildren().add(editorStack);
+		}
+
+		for (InfoReader stackReader : stackReaders) {
+			stackToReader.put(addEditorStack(stackReader), stackReader);
+		}
+
+		editorArea.setSelectedElement(editorArea.getChildren().get(0));
+
+		for (EditorReader editorReader : windowReader.getEditors()) {
+			MPart editor = modelService.createModelElement(MPart.class);
+			editor.setElementId(CompatibilityEditor.MODEL_ELEMENT_ID);
+			editor.setContributionURI(CompatibilityPart.COMPATIBILITY_EDITOR_URI);
+			editor.setLabel(editorReader.getLabel());
+			editor.getPersistedState().put(Workbench.MEMENTO_KEY,
+					new MementoSerializer(editorReader.getMemento()).serialize());
+			List<String> tags = editor.getTags();
+			tags.add(Workbench.EDITOR_TAG);
+			tags.add(EPartService.REMOVE_ON_HIDE_TAG);
+			tags.add(editorReader.getType());
+			MPartStack stack = (MPartStack) modelService.find(editorReader.getStackId(), editorArea);
+			stack.getChildren().add(editor);
+			if (editorReader.isSelected()) {
+				stack.setSelectedElement(editor);
+			}
+		}
+
+		// restore order of editors in stacks
+		for (Entry<MPartStack, InfoReader> entry : stackToReader.entrySet()) {
+			MPartStack editorStack = entry.getKey();
+			if (editorStack.getChildren().size() < 2) {
+				continue;
+			}
+			InfoReader stackReader = entry.getValue();
+			if (stackReader == null) {
+				continue;
+			}
+			int[] partOrder = stackReader.getPartOrder();
+			List<MStackElement> stackChildren = editorStack.getChildren();
+			List<MStackElement> originalOrder = new ArrayList<>(stackChildren);
+			MStackElement selectedElement = editorStack.getSelectedElement();
+			stackChildren.clear();
+			for (int element : partOrder) {
+				stackChildren.add(originalOrder.get(element));
+			}
+			if (selectedElement != null) {
+				editorStack.setSelectedElement(selectedElement);
+			}
+		}
+	}
+
+	private MPartStack addEditorStack(InfoReader info) {
+		MPartStack stack = layoutUtils.createStack(info.getId(), true);
+		if (info.isRelativelyPositioned()) {
+			MUIElement refElement = modelService.find(info.getRelative(), editorArea);
+			MElementContainer<?> parent = refElement.getParent();
+			if (parent instanceof MPartStack) {
+				refElement = parent;
+			}
+			layoutUtils.insert(stack, refElement, layoutUtils.plRelToSwt(info.getRelationship()), info.getRatio());
+		} else {
+			editorArea.getChildren().add(stack);
+		}
+		return stack;
+	}
+
+	private void addViews() {
+		for (ViewReader viewReader : windowReader.getViews()) {
+			sharedElements.add(createView(viewReader));
+		}
+	}
+
+	private MPart createView(ViewReader viewReader) {
+		MPart view = modelService.createModelElement(MPart.class);
+		view.setElementId(viewReader.getId());
+		view.setContributionURI(CompatibilityPart.COMPATIBILITY_VIEW_URI);
+		view.setLabel(viewReader.getLabel());
+		view.getTags().add(ViewRegistry.VIEW_TAG);
+		view.getPersistedState().put(Workbench.MEMENTO_KEY,
+				new MementoSerializer(viewReader.getViewState()).serialize());
+		return view;
+	}
+
+	private void addEditorArea() {
+		editorArea = modelService.createModelElement(MArea.class);
+		sharedElements.add(editorArea);
+		editorArea.setElementId(IPageLayout.ID_EDITOR_AREA);
+	}
+
+	private MPerspectiveStack createPerspectiveStack() {
+		MPerspectiveStack perspStack = modelService
+				.createModelElement(MPerspectiveStack.class);
+		perspStack.setElementId("PerspectiveStack"); //$NON-NLS-1$
+		return perspStack;
+	}
+
+	private void addStickyFolder() {
+		MPartStack stickyFolder = modelService.createModelElement(MPartStack.class);
+		stickyFolder.setElementId(StickyViewDescriptor.STICKY_FOLDER_RIGHT);
+		stickyFolder.setContainerData("2500"); //$NON-NLS-1$
+		stickyFolder.setToBeRendered(false);
+		mainSash.getChildren().add(stickyFolder);
+	}
+
+	private MPart getSharedView(String id) {
+		MPart part = null;
+		for (MUIElement element : sharedElements) {
+			if (id.equals(element.getElementId()) && element instanceof MPart) {
+				part = (MPart) element;
+				break;
+			}
+		}
+		/*
+		 * if (part == null) { part =
+		 * modelService.createModelElement(MPart.class); part.setElementId(id);
+		 * part.setContributionURI(CompatibilityPart.COMPATIBILITY_VIEW_URI);
+		 * part.getTags().add(ViewRegistry.VIEW_TAG); sharedElements.add(part);
+		 * }
+		 */
+		return part;
+	}
+
+
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/migration/WindowReader.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/migration/WindowReader.java
new file mode 100644
index 0000000..ae86b0c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/migration/WindowReader.java
@@ -0,0 +1,282 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.ui.internal.e4.migration;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.XMLMemento;
+import org.eclipse.ui.internal.IWorkbenchConstants;
+
+public class WindowReader extends MementoReader {
+	public static final String STATUS_LINE_MANAGER_ID = "org.eclipse.jface.action.StatusLineManager"; //$NON-NLS-1$
+
+	WindowReader(IMemento memento) {
+		super(memento);
+	}
+
+	Rectangle getBounds() {
+		Rectangle windowBounds = new Rectangle(0, 0, 0, 0);
+		Integer bigInt = getInteger(IWorkbenchConstants.TAG_X);
+		windowBounds.x = bigInt == null ? 0 : bigInt.intValue();
+		bigInt = getInteger(IWorkbenchConstants.TAG_Y);
+		windowBounds.y = bigInt == null ? 0 : bigInt.intValue();
+		bigInt = getInteger(IWorkbenchConstants.TAG_WIDTH);
+		windowBounds.width = bigInt == null ? 0 : bigInt.intValue();
+		bigInt = getInteger(IWorkbenchConstants.TAG_HEIGHT);
+		windowBounds.height = bigInt == null ? 0 : bigInt.intValue();
+		return windowBounds;
+	}
+
+	boolean isMaximized() {
+		return getBoolean(IWorkbenchConstants.TAG_MAXIMIZED, false);
+
+	}
+
+	boolean isMinimized() {
+		return getBoolean(IWorkbenchConstants.TAG_MINIMIZED, false);
+
+	}
+
+	boolean isCoolbarVisible() {
+		IMemento trimLayoutMem = getChild(IWorkbenchConstants.TAG_TRIM);
+		if (trimLayoutMem == null) {
+			return false;
+		}
+
+		boolean visible = false;
+		IMemento[] trimAreas = trimLayoutMem.getChildren(IWorkbenchConstants.TAG_TRIM_AREA);
+		IMemento topTrim = null;
+		for (IMemento trimArea : trimAreas) {
+			// ITrimManager.TOP == SWT.TOP
+			if (SWT.TOP == trimArea.getInteger(IMemento.TAG_ID)) {
+				topTrim = trimArea;
+				break;
+			}
+		}
+		if (topTrim != null) {
+			IMemento[] trimItems = topTrim.getChildren(IWorkbenchConstants.TAG_TRIM_ITEM);
+			for (IMemento trimItem : trimItems) {
+				if ("org.eclipse.ui.internal.WorkbenchWindow.topBar".equals(trimItem //$NON-NLS-1$
+						.getString(IMemento.TAG_ID))) {
+					visible = true;
+					break;
+				}
+			}
+		}
+		return visible;
+	}
+
+	boolean isStatusBarVisible() {
+		return getStatusBar() != null;
+	}
+
+	private IMemento getStatusBar() {
+		IMemento trimLayoutMem = getChild(IWorkbenchConstants.TAG_TRIM);
+		if (trimLayoutMem == null) {
+			return null;
+		}
+
+		IMemento[] trimAreas = trimLayoutMem.getChildren(IWorkbenchConstants.TAG_TRIM_AREA);
+		for (IMemento trimArea : trimAreas) {
+			// ITrimManager.TOP == SWT.TOP
+			if (SWT.BOTTOM == trimArea.getInteger(IMemento.TAG_ID)) {
+				return trimArea;
+			}
+		}
+		return null;
+	}
+
+	boolean hasStatusLine() {
+		IMemento statusBar = getStatusBar();
+		if (statusBar != null) {
+			IMemento[] trimItemMems = statusBar.getChildren(IWorkbenchConstants.TAG_TRIM_ITEM);
+			for (IMemento trimItemMem : trimItemMems) {
+				if (STATUS_LINE_MANAGER_ID.equals(trimItemMem.getID())) {
+					return true;
+				}
+			}
+		}
+		return false;
+	}
+
+	boolean isWelcomePageOpen() {
+		return (getChild(IWorkbenchConstants.TAG_INTRO) != null);
+	}
+
+	List<PerspectiveReader> getPerspectiveReaders() {
+		List<PerspectiveReader> perspectives = new ArrayList<>();
+		IMemento perspContainer = getPerspectiveContainer();
+		if (perspContainer != null) {
+			IMemento[] perspectiveMems = perspContainer
+					.getChildren(IWorkbenchConstants.TAG_PERSPECTIVE);
+			for (IMemento perspectiveMem : perspectiveMems) {
+				PerspectiveReader perspective = new PerspectiveReader(perspectiveMem);
+				perspectives.add(perspective);
+			}
+		}
+		return perspectives;
+	}
+
+	private IMemento getPerspectiveContainer() {
+		IMemento perspContainer = null;
+		IMemento page = getPage();
+		if (page != null) {
+			perspContainer = page.getChild(IWorkbenchConstants.TAG_PERSPECTIVES);
+		}
+		return perspContainer;
+	}
+
+	boolean isSelected() {
+		IMemento page = getPage();
+		if (page == null) {
+			return false;
+		}
+		Boolean selected = page.getBoolean(IWorkbenchConstants.TAG_FOCUS);
+		return selected == null ? false : selected.booleanValue();
+	}
+
+	String getActivePerspectiveId() {
+		String activePerspectiveId = null;
+		IMemento perspContainer = getPerspectiveContainer();
+		if (perspContainer != null) {
+			activePerspectiveId = perspContainer.getString(IWorkbenchConstants.TAG_ACTIVE_PERSPECTIVE);
+		}
+		return activePerspectiveId;
+	}
+
+	List<InfoReader> getEditorStacks() {
+		IMemento editorArea = getEditorArea();
+		List<InfoReader> readers = new ArrayList<>();
+		if (editorArea != null) {
+			IMemento[] editorStackMems = editorArea.getChildren(IWorkbenchConstants.TAG_INFO);
+			for (IMemento memento : editorStackMems) {
+				readers.add(new InfoReader(memento));
+			}
+		}
+		return readers;
+	}
+
+	public Integer getDefaultFastViewSide() {
+		Integer defaultFastViewSide = null;
+		IMemento fastViewData = getChild("fastViewData"); //$NON-NLS-1$
+		if (fastViewData != null) {
+			defaultFastViewSide = fastViewData.getInteger(IWorkbenchConstants.TAG_FAST_VIEW_SIDE);
+		}
+		return defaultFastViewSide;
+	}
+
+	private IMemento getEditorArea() {
+		IMemento editors = getEditorsMemento();
+		if (editors != null) {
+			return editors.getChild(IWorkbenchConstants.TAG_AREA);
+		}
+		return null;
+	}
+
+	List<EditorReader> getEditors() {
+		List<EditorReader> readers = new ArrayList<>();
+		IMemento editors = getEditorsMemento();
+		if (editors != null) {
+			IMemento[] editorMems = editors.getChildren(IWorkbenchConstants.TAG_EDITOR);
+			for (IMemento memento : editorMems) {
+				readers.add(new EditorReader(memento));
+			}
+		}
+		return readers;
+	}
+
+	private IMemento getEditorsMemento() {
+		IMemento page = getPage();
+		if (page == null) {
+			return null;
+		}
+		return page.getChild(IWorkbenchConstants.TAG_EDITORS);
+	}
+
+	List<ViewReader> getViews() {
+		List<ViewReader> readers = new ArrayList<>();
+		IMemento page = getPage();
+		if (page == null) {
+			return readers;
+		}
+		IMemento editors = page.getChild(IWorkbenchConstants.TAG_VIEWS);
+		if (editors != null) {
+			IMemento[] editorMems = editors.getChildren(IWorkbenchConstants.TAG_VIEW);
+			for (IMemento memento : editorMems) {
+				readers.add(new ViewReader(memento));
+			}
+		}
+		return readers;
+	}
+
+	private IMemento getPage() {
+		return getChild(IWorkbenchConstants.TAG_PAGE);
+	}
+
+	static class EditorReader extends MementoReader {
+
+		private EditorReader(IMemento memento) {
+			super(memento);
+		}
+
+		String getLabel() {
+			return getString(IWorkbenchConstants.TAG_TITLE);
+		}
+
+		String getType() {
+			return getString(IWorkbenchConstants.TAG_ID);
+		}
+
+		String getStackId() {
+			return getString(IWorkbenchConstants.TAG_WORKBOOK);
+		}
+
+		boolean isSelected() {
+			return getBoolean(IWorkbenchConstants.TAG_FOCUS);
+		}
+
+	}
+
+	static class ViewReader extends MementoReader {
+
+		private ViewReader(IMemento memento) {
+			super(memento);
+		}
+
+		String getId() {
+			return getString(IWorkbenchConstants.TAG_ID);
+		}
+
+		String getLabel() {
+			return getString(IWorkbenchConstants.TAG_PART_NAME);
+		}
+
+		IMemento getViewState() {
+			IMemento viewStateMem = getChild(IWorkbenchConstants.TAG_VIEW_STATE);
+			if (viewStateMem == null) {
+				return null;
+			}
+			return createRenamedCopy(viewStateMem, IWorkbenchConstants.TAG_VIEW);
+		}
+
+		private XMLMemento createRenamedCopy(IMemento memento, String newName) {
+			XMLMemento newMem = XMLMemento.createWriteRoot(newName);
+			newMem.putMemento(memento);
+			return newMem;
+		}
+
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/migration/WorkbenchMementoReader.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/migration/WorkbenchMementoReader.java
new file mode 100644
index 0000000..2acd943
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/migration/WorkbenchMementoReader.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.ui.internal.e4.migration;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.XMLMemento;
+import org.eclipse.ui.internal.IWorkbenchConstants;
+
+public class WorkbenchMementoReader extends MementoReader {
+
+	WorkbenchMementoReader(IMemento memento) {
+		super(memento);
+	}
+
+	List<WindowReader> getWindowReaders() {
+		IMemento[] windowMems = getChildren(IWorkbenchConstants.TAG_WINDOW);
+		List<WindowReader> windows = new ArrayList<>(windowMems.length);
+		for (IMemento windowMem : windowMems) {
+			windows.add(new WindowReader(windowMem));
+		}
+		return windows;
+	}
+
+	IMemento getMruMemento() {
+		XMLMemento root = XMLMemento.createWriteRoot(IWorkbenchConstants.TAG_WORKBENCH);
+		IMemento mruList = memento.getChild(IWorkbenchConstants.TAG_MRU_LIST);
+		if (mruList != null) {
+			root.copyChild(mruList);
+		}
+		return root;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/migration/WorkbenchMigrationProcessor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/migration/WorkbenchMigrationProcessor.java
new file mode 100644
index 0000000..606c1f3
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/e4/migration/WorkbenchMigrationProcessor.java
@@ -0,0 +1,258 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 2016 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.ui.internal.e4.migration;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+import javax.inject.Inject;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.e4.core.contexts.ContextInjectionFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.ui.internal.workbench.E4Workbench;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.descriptor.basic.MPartDescriptor;
+import org.eclipse.e4.ui.model.application.ui.MElementContainer;
+import org.eclipse.e4.ui.model.application.ui.MUIElement;
+import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective;
+import org.eclipse.e4.ui.model.application.ui.advanced.MPlaceholder;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.model.application.ui.basic.MPartStack;
+import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.IPerspectiveRegistry;
+import org.eclipse.ui.IWorkbenchPreferenceConstants;
+import org.eclipse.ui.WorkbenchException;
+import org.eclipse.ui.XMLMemento;
+import org.eclipse.ui.internal.Workbench;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.e4.compatibility.CompatibilityPart;
+import org.eclipse.ui.internal.menus.MenuHelper;
+import org.eclipse.ui.internal.registry.StickyViewDescriptor;
+import org.eclipse.ui.internal.registry.ViewRegistry;
+import org.eclipse.ui.internal.util.PrefUtil;
+import org.eclipse.ui.views.IStickyViewDescriptor;
+import org.eclipse.ui.views.IViewRegistry;
+
+public class WorkbenchMigrationProcessor {
+
+	@Inject
+	private MApplication application;
+
+	@Inject
+	private IEclipseContext context;
+
+	@Inject
+	private EModelService modelService;
+
+	private IMemento workbenchMemento;
+
+	private File legacyWorkbenchFile;
+
+	private boolean migrated;
+
+	private List<MWindow> defaultWindows;
+
+	public boolean isLegacyWorkbenchDetected() {
+		legacyWorkbenchFile = getLegacyWorkbenchFile();
+		return legacyWorkbenchFile != null && legacyWorkbenchFile.exists();
+	}
+
+	public void migrate() {
+		if (!isLegacyWorkbenchDetected()) {
+			return;
+		}
+
+		workbenchMemento = loadMemento();
+		if (workbenchMemento == null) {
+			return;
+		}
+
+		defaultWindows = new ArrayList<>(application.getChildren());
+		application.getChildren().clear();
+		IEclipseContext builderContext = context.createChild();
+		IModelBuilderFactory builderFactory = ContextInjectionFactory.make(
+				ModelBuilderFactoryImpl.class, builderContext);
+		builderContext.set(IModelBuilderFactory.class, builderFactory);
+		ApplicationBuilder modelBuilder = builderFactory.createApplicationBuilder(new WorkbenchMementoReader(
+				workbenchMemento));
+		modelBuilder.createApplication();
+		context.remove(E4Workbench.NO_SAVED_MODEL_FOUND);
+		PrefUtil.getAPIPreferenceStore().setValue(IWorkbenchPreferenceConstants.SHOW_INTRO, false);
+		migrated = true;
+	}
+
+	private IMemento loadMemento() {
+		BufferedReader reader = null;
+		IMemento memento = null;
+		try {
+			reader = new BufferedReader(
+					new InputStreamReader(new FileInputStream(legacyWorkbenchFile), StandardCharsets.UTF_8));
+			memento = XMLMemento.createReadRoot(reader);
+		} catch (IOException e) {
+			WorkbenchPlugin.log("Failed to load " + legacyWorkbenchFile.getAbsolutePath(), e); //$NON-NLS-1$
+		} catch (WorkbenchException e) {
+			WorkbenchPlugin.log("Failed to load " + legacyWorkbenchFile.getAbsolutePath(), e); //$NON-NLS-1$
+		} finally {
+			if (reader != null) {
+				try {
+					reader.close();
+				} catch (IOException e) {
+					WorkbenchPlugin.log(e);
+				}
+			}
+		}
+		return memento;
+	}
+
+	private File getLegacyWorkbenchFile() {
+		if (legacyWorkbenchFile == null) {
+			IPath path = WorkbenchPlugin.getDefault().getDataLocation();
+			if (path == null) {
+				return null;
+			}
+			path = path.append(Workbench.DEFAULT_WORKBENCH_STATE_FILENAME);
+			legacyWorkbenchFile = path.toFile();
+		}
+		return legacyWorkbenchFile;
+	}
+
+	public boolean isWorkbenchMigrated() {
+		return migrated;
+	}
+
+	public void updatePartsAfterMigration(IPerspectiveRegistry perspectiveRegistry,
+			IViewRegistry viewRegistry) {
+		if (!migrated) {
+			return;
+		}
+
+		for (MPartDescriptor desc : application.getDescriptors()) {
+			for (MPart part : modelService.findElements(application, desc.getElementId(), MPart.class, null)) {
+				if (part.getLabel() == null) {
+					part.setLabel(desc.getLocalizedLabel());
+				}
+				if (part.getTooltip() == null) {
+					part.setTooltip(desc.getLocalizedTooltip());
+				}
+				if (part.getIconURI() == null) {
+					part.setIconURI(desc.getIconURI());
+				}
+			}
+		}
+
+		for (MPerspective persp : modelService.findElements(application, null, MPerspective.class, null)) {
+			setPerspectiveIcon(perspectiveRegistry, persp);
+		}
+
+		for (MUIElement snippet : application.getSnippets()) {
+			if (snippet instanceof MPerspective) {
+				setPerspectiveIcon(perspectiveRegistry, (MPerspective) snippet);
+			}
+		}
+
+		IStickyViewDescriptor[] stickyViews = viewRegistry.getStickyViews();
+		for (MWindow window : application.getChildren()) {
+			moveStickyViews(stickyViews, window);
+		}
+
+	}
+
+	private void moveStickyViews(IStickyViewDescriptor[] stickyViews, MWindow window) {
+		for (IStickyViewDescriptor stickyView : stickyViews) {
+			removeStickyViewFromPerspectives(stickyView, window);
+		}
+		for (MPartStack stickyFolder : modelService.findElements(application,
+				StickyViewDescriptor.STICKY_FOLDER_RIGHT, MPartStack.class, null)) {
+			fillStickyFolder(stickyViews, stickyFolder);
+		}
+	}
+
+	private void removeStickyViewFromPerspectives(IStickyViewDescriptor stickyView, MWindow window) {
+		for (MPlaceholder placeholder : modelService.findElements(window, stickyView.getId(),
+				MPlaceholder.class, null)) {
+			MElementContainer<MUIElement> parent = placeholder.getParent();
+			if (StickyViewDescriptor.STICKY_FOLDER_RIGHT.equals(parent.getElementId())) {
+				continue;
+			}
+			placeholder.setToBeRendered(false);
+			placeholder.setVisible(false);
+			parent.getChildren().remove(placeholder);
+			// remove empty container
+			if (parent.getChildren().isEmpty()) {
+				parent.getParent().getChildren().remove(parent);
+			} else if (parent.getSelectedElement() == placeholder) {
+				parent.setSelectedElement(null);
+			}
+		}
+	}
+
+	private void fillStickyFolder(IStickyViewDescriptor[] stickyViews, MPartStack stickyFolder) {
+		for (IStickyViewDescriptor stickyView : stickyViews) {
+			addPartToStickyFolder(stickyView.getId(), stickyFolder);
+		}
+	}
+
+	private void setPerspectiveIcon(IPerspectiveRegistry perspectiveRegistry, MPerspective perspective) {
+		String perspId = perspective.getElementId();
+		if (perspective.getTransientData().containsKey(PerspectiveBuilder.ORIGINAL_ID)) {
+			perspId = (String) perspective.getTransientData().get(PerspectiveBuilder.ORIGINAL_ID);
+		}
+		IPerspectiveDescriptor orgPerspDescr = perspectiveRegistry.findPerspectiveWithId(perspId);
+		if (orgPerspDescr != null) {
+			perspective.setIconURI(MenuHelper.getIconURI(orgPerspDescr.getImageDescriptor(), context));
+		}
+	}
+
+	private MPlaceholder addPartToStickyFolder(String partId, MPartStack stickyFolder) {
+		MPart part = null;
+		MWindow window = modelService.getTopLevelWindowFor(stickyFolder);
+		for (MUIElement element : window.getSharedElements()) {
+			if (element.getElementId().equals(partId)) {
+				part = (MPart) element;
+				break;
+			}
+		}
+		if (part == null) {
+			part = modelService.createModelElement(MPart.class);
+			part.setElementId(partId);
+			part.setContributionURI(CompatibilityPart.COMPATIBILITY_VIEW_URI);
+			part.getTags().add(ViewRegistry.VIEW_TAG);
+			window.getSharedElements().add(part);
+		}
+		MPlaceholder placeholder = null;
+		placeholder = modelService.createModelElement(MPlaceholder.class);
+		placeholder.setElementId(partId);
+		placeholder.setRef(part);
+		placeholder.setToBeRendered(false);
+		part.setCurSharedRef(placeholder);
+		stickyFolder.getChildren().add(placeholder);
+		return placeholder;
+	}
+
+	public void restoreDefaultModel() {
+		application.getTags().clear();
+		application.getPersistedState().clear();
+		application.getSnippets().clear();
+		application.getDescriptors().clear();
+		application.getChildren().clear();
+		application.getChildren().addAll(defaultWindows);
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/editorsupport/ComponentSupport.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/editorsupport/ComponentSupport.java
new file mode 100644
index 0000000..85cfa17
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/editorsupport/ComponentSupport.java
@@ -0,0 +1,126 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.editorsupport;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.util.Util;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchPreferenceConstants;
+import org.eclipse.ui.internal.util.BundleUtility;
+import org.eclipse.ui.internal.util.PrefUtil;
+import org.osgi.framework.Bundle;
+
+/**
+ * This class provides an OS independent interface to the
+ * components available on the platform
+ */
+public final class ComponentSupport {
+
+    /**
+     * Returns whether the current platform has support
+     * for system in-place editor.
+     */
+    public static boolean inPlaceEditorSupported() {
+    	// check preference
+    	if (PrefUtil.getAPIPreferenceStore().getBoolean(IWorkbenchPreferenceConstants.DISABLE_OPEN_EDITOR_IN_PLACE)) {
+    		return false;
+    	}
+        // only Win32 is supported
+        return Util.isWindows();
+    }
+
+    /**
+     * Return the default system in-place editor part
+     * or <code>null</code> if not support by platform.
+     */
+    public static IEditorPart getSystemInPlaceEditor() {
+        if (inPlaceEditorSupported()) {
+            return getOleEditor();
+        }
+        return null;
+    }
+
+    /**
+     * Returns whether an in-place editor is available to
+     * edit the file.
+     *
+     * @param filename the file name in the system
+     */
+    public static boolean inPlaceEditorAvailable(String filename) {
+        if (inPlaceEditorSupported()) {
+            return testForOleEditor(filename);
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Get a new OLEEditor
+     * @return IEditorPart
+     */
+    private static IEditorPart getOleEditor() {
+        // @issue currently assumes OLE editor is provided by IDE plug-in
+        // IDE plug-in is not on prereq chain of generic wb plug-in
+        // hence: IContributorResourceAdapter.class won't compile
+        // and Class.forName("org.eclipse.ui.internal.editorsupport.win32.OleEditor") won't find it
+        // need to be trickier...
+        Bundle bundle = Platform.getBundle("org.eclipse.ui.ide"); //$NON-NLS-1$
+
+        // it's not our job to activate the plug-in
+        if (!BundleUtility.isActivated(bundle)) {
+			return null;
+		}
+
+        try {
+            Class c = bundle
+                    .loadClass("org.eclipse.ui.internal.editorsupport.win32.OleEditor"); //$NON-NLS-1$
+            return (IEditorPart) c.newInstance();
+        } catch (ClassNotFoundException exception) {
+            return null;
+        } catch (IllegalAccessException exception) {
+            return null;
+        } catch (InstantiationException exception) {
+            return null;
+        }
+    }
+
+    public static boolean testForOleEditor(String filename) {
+        int nDot = filename.lastIndexOf('.');
+        if (nDot >= 0) {
+            try {
+                String strName = filename.substring(nDot);
+                Class oleClass = Class.forName("org.eclipse.swt.ole.win32.OLE"); //$NON-NLS-1$
+                Method findMethod = oleClass.getDeclaredMethod(
+                        "findProgramID", new Class[] { String.class }); //$NON-NLS-1$
+                strName = (String) findMethod.invoke(null,
+                        new Object[] { strName });
+                if (strName.length() > 0) {
+					return true;
+				}
+            } catch (ClassNotFoundException exception) {
+                //Couldn't ask so return false
+                return false;
+            } catch (NoSuchMethodException exception) {
+                //Couldn't find the method so return false
+                return false;
+            } catch (IllegalAccessException exception) {
+                return false;
+            } catch (InvocationTargetException exception) {
+                return false;
+            }
+
+        }
+        return false;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/expressions/ActivePartExpression.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/expressions/ActivePartExpression.java
new file mode 100644
index 0000000..b45b38e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/expressions/ActivePartExpression.java
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.expressions;
+
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.ExpressionInfo;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.IWorkbenchPart;
+
+/**
+ * <p>
+ * An expression that is bound to a particular part instance.
+ * </p>
+ * <p>
+ * This class is not intended for use outside of the
+ * <code>org.eclipse.ui.workbench</code> plug-in.
+ * </p>
+ *
+ * @since 3.2
+ */
+public final class ActivePartExpression extends Expression {
+
+	/**
+	 * The seed for the hash code for all schemes.
+	 */
+	private static final int HASH_INITIAL = ActivePartExpression.class
+			.getName().hashCode();
+
+	/**
+	 * The part that must be active for this expression to evaluate to
+	 * <code>true</code>. This value is never <code>null</code>.
+	 */
+	private final IWorkbenchPart activePart;
+
+	/**
+	 * Constructs a new instance of <code>ActivePartExpression</code>
+	 *
+	 * @param activePart
+	 *            The part to match with the active part; may be
+	 *            <code>null</code>
+	 */
+	public ActivePartExpression(final IWorkbenchPart activePart) {
+		if (activePart == null) {
+			throw new NullPointerException("The active part must not be null"); //$NON-NLS-1$
+		}
+		this.activePart = activePart;
+	}
+
+	@Override
+	public final void collectExpressionInfo(final ExpressionInfo info) {
+		info.addVariableNameAccess(ISources.ACTIVE_PART_NAME);
+	}
+
+	@Override
+	protected final int computeHashCode() {
+		return HASH_INITIAL * HASH_FACTOR + hashCode(activePart);
+	}
+
+	@Override
+	public final boolean equals(final Object object) {
+		if (object instanceof ActivePartExpression) {
+			final ActivePartExpression that = (ActivePartExpression) object;
+			return equals(this.activePart, that.activePart);
+		}
+
+		return false;
+	}
+
+	@Override
+	public final EvaluationResult evaluate(final IEvaluationContext context) {
+		final Object variable = context.getVariable(ISources.ACTIVE_PART_NAME);
+		if (equals(activePart, variable)) {
+			return EvaluationResult.TRUE;
+		}
+		return EvaluationResult.FALSE;
+	}
+
+	@Override
+	public final String toString() {
+		final StringBuffer buffer = new StringBuffer();
+		buffer.append("ActivePartExpression("); //$NON-NLS-1$
+		buffer.append(activePart);
+		buffer.append(')');
+		return buffer.toString();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/expressions/AlwaysEnabledExpression.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/expressions/AlwaysEnabledExpression.java
new file mode 100644
index 0000000..c67eea5
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/expressions/AlwaysEnabledExpression.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal.expressions;
+
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.IEvaluationContext;
+
+/**
+ * An expression that simply returns <code>true</code> at all times. A shared
+ * instance of this expression is provided.
+ *
+ * @since 3.3
+ *
+ */
+public final class AlwaysEnabledExpression extends Expression {
+
+	public static final AlwaysEnabledExpression INSTANCE = new AlwaysEnabledExpression();
+
+
+	/**
+	 * Not to be instantiated
+	 */
+	private AlwaysEnabledExpression() {
+	}
+
+	@Override
+	public EvaluationResult evaluate(IEvaluationContext context) {
+		return EvaluationResult.TRUE;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/expressions/AndExpression.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/expressions/AndExpression.java
new file mode 100644
index 0000000..e00b5e5
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/expressions/AndExpression.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2014 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.ui.internal.expressions;
+
+import java.util.Iterator;
+
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * Copied from org.eclipse.core.internal.expressions.
+ */
+public final class AndExpression extends CompositeExpression {
+
+	/**
+	 * The seed for the hash code for all schemes.
+	 */
+	private static final int HASH_INITIAL = AndExpression.class.getName()
+			.hashCode();
+
+	@Override
+	protected final int computeHashCode() {
+		return HASH_INITIAL * HASH_FACTOR + hashCode(fExpressions);
+	}
+
+	@Override
+	public final boolean equals(final Object object) {
+		if (object instanceof AndExpression) {
+			final AndExpression that = (AndExpression) object;
+			return equals(this.fExpressions, that.fExpressions);
+		}
+
+		return false;
+	}
+
+	@Override
+	public final EvaluationResult evaluate(final IEvaluationContext context)
+			throws CoreException {
+		return evaluateAnd(context);
+	}
+
+	@Override
+	public final String toString() {
+		final StringBuffer buffer = new StringBuffer();
+		buffer.append("AndExpression("); //$NON-NLS-1$
+		if (fExpressions != null) {
+			final Iterator itr = fExpressions.iterator();
+			while (itr.hasNext()) {
+				final Expression expression = (Expression) itr.next();
+				buffer.append(expression.toString());
+				if (itr.hasNext()) {
+					buffer.append(',');
+				}
+			}
+		}
+		buffer.append(')');
+		return buffer.toString();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/expressions/CompositeExpression.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/expressions/CompositeExpression.java
new file mode 100644
index 0000000..2ee28d6
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/expressions/CompositeExpression.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2014 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.ui.internal.expressions;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.ExpressionInfo;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * Copied from org.eclipse.core.internal.expressions.
+ */
+public abstract class CompositeExpression extends Expression {
+
+	private static final Expression[] EMPTY_ARRAY = new Expression[0];
+
+	protected List fExpressions;
+
+	public void add(Expression expression) {
+		if (fExpressions == null) {
+			fExpressions = new ArrayList(2);
+		}
+		fExpressions.add(expression);
+	}
+
+	public Expression[] getChildren() {
+		if (fExpressions == null) {
+			return EMPTY_ARRAY;
+		}
+		return (Expression[]) fExpressions.toArray(new Expression[fExpressions
+				.size()]);
+	}
+
+	protected EvaluationResult evaluateAnd(IEvaluationContext scope)
+			throws CoreException {
+		if (fExpressions == null) {
+			return EvaluationResult.TRUE;
+		}
+		EvaluationResult result = EvaluationResult.TRUE;
+		for (Iterator iter = fExpressions.iterator(); iter.hasNext();) {
+			Expression expression = (Expression) iter.next();
+			result = result.and(expression.evaluate(scope));
+			// keep iterating even if we have a not loaded found. It can be
+			// that we find a false which will result in a better result.
+			if (result == EvaluationResult.FALSE) {
+				return result;
+			}
+		}
+		return result;
+	}
+
+	protected EvaluationResult evaluateOr(IEvaluationContext scope)
+			throws CoreException {
+		if (fExpressions == null) {
+			return EvaluationResult.TRUE;
+		}
+		EvaluationResult result = EvaluationResult.FALSE;
+		for (Iterator iter = fExpressions.iterator(); iter.hasNext();) {
+			Expression expression = (Expression) iter.next();
+			result = result.or(expression.evaluate(scope));
+			if (result == EvaluationResult.TRUE) {
+				return result;
+			}
+		}
+		return result;
+	}
+
+	@Override
+	public void collectExpressionInfo(ExpressionInfo info) {
+		if (fExpressions == null) {
+			return;
+		}
+		for (Iterator iter = fExpressions.iterator(); iter.hasNext();) {
+			Expression expression = (Expression) iter.next();
+			expression.collectExpressionInfo(info);
+		}
+	}
+}
+
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/expressions/LegacyActionExpressionWrapper.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/expressions/LegacyActionExpressionWrapper.java
new file mode 100644
index 0000000..48cfb60
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/expressions/LegacyActionExpressionWrapper.java
@@ -0,0 +1,127 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.expressions;
+
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.ExpressionInfo;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.internal.ActionExpression;
+
+/**
+ * <p>
+ * This wrappers the old {@link ActionExpression} class so that it can
+ * communicate via the {@link Expression} contract.
+ * </p>
+ * <p>
+ * This class is not intended for use outside of the
+ * <code>org.eclipse.ui.workbench</code> plug-in.
+ * </p>
+ *
+ * @since 3.2
+ */
+public final class LegacyActionExpressionWrapper extends
+		WorkbenchWindowExpression {
+
+	/**
+	 * The seed for the hash code for all schemes.
+	 */
+	private static final int HASH_INITIAL = LegacyActionExpressionWrapper.class
+			.getName().hashCode();
+
+	/**
+	 * The legacy action expression being wrapped; never <code>null</code>.
+	 */
+	private final ActionExpression expression;
+
+	/**
+	 * Constructs a new instance of {@link LegacyActionExpressionWrapper}.
+	 *
+	 * @param expression
+	 *            The expression to wrap; must not be <code>null</code>.
+	 * @param window
+	 *            The workbench window which must be active for this expression
+	 *            to evaluate to <code>true</code>; may be <code>null</code>
+	 *            if the window should be disregarded.
+	 */
+	public LegacyActionExpressionWrapper(final ActionExpression expression,
+			final IWorkbenchWindow window) {
+		super(window);
+
+		if (expression == null) {
+			throw new NullPointerException(
+					"The action expression cannot be null"); //$NON-NLS-1$
+		}
+		this.expression = expression;
+	}
+
+	@Override
+	public final void collectExpressionInfo(final ExpressionInfo info) {
+		super.collectExpressionInfo(info);
+		info.markDefaultVariableAccessed();
+	}
+
+	@Override
+	protected final int computeHashCode() {
+		int hashCode = HASH_INITIAL * HASH_FACTOR + hashCode(getWindow());
+		hashCode = hashCode * HASH_FACTOR + hashCode(expression);
+		return hashCode;
+	}
+
+	@Override
+	public final boolean equals(final Object object) {
+		if (object instanceof LegacyActionExpressionWrapper) {
+			final LegacyActionExpressionWrapper that = (LegacyActionExpressionWrapper) object;
+			return equals(this.expression, that.expression)
+					&& equals(this.getWindow(), that.getWindow());
+		}
+
+		return false;
+	}
+
+	@Override
+	public final EvaluationResult evaluate(final IEvaluationContext context)
+			throws CoreException {
+		final EvaluationResult result = super.evaluate(context);
+		if (result == EvaluationResult.FALSE) {
+			return result;
+		}
+
+		final Object defaultVariable = context
+				.getVariable(ISources.ACTIVE_CURRENT_SELECTION_NAME);
+		if (defaultVariable instanceof IStructuredSelection) {
+			final IStructuredSelection selection = (IStructuredSelection) defaultVariable;
+			if (expression.isEnabledFor(selection)) {
+				return EvaluationResult.TRUE;
+			}
+		} else if (expression.isEnabledFor(defaultVariable)) {
+			return EvaluationResult.TRUE;
+		}
+
+		return EvaluationResult.FALSE;
+	}
+
+	@Override
+	public final String toString() {
+		final StringBuffer buffer = new StringBuffer();
+		buffer.append("LegacyActionExpressionWrapper("); //$NON-NLS-1$
+		buffer.append(expression);
+		buffer.append(',');
+		buffer.append(getWindow());
+		buffer.append(')');
+		return buffer.toString();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/expressions/LegacyActionSetExpression.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/expressions/LegacyActionSetExpression.java
new file mode 100644
index 0000000..66347a2
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/expressions/LegacyActionSetExpression.java
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.expressions;
+
+import java.util.Collection;
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.ExpressionInfo;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.IWorkbenchWindow;
+
+/**
+ * <p>
+ * An expression that evaluates whether a particular action set is active.
+ * </p>
+ * <p>
+ * This class is not intended for use outside of the
+ * <code>org.eclipse.ui.workbench</code> plug-in.
+ * </p>
+ *
+ * @since 3.2
+ */
+public final class LegacyActionSetExpression extends WorkbenchWindowExpression {
+
+	/**
+	 * The seed for the hash code for all schemes.
+	 */
+	private static final int HASH_INITIAL = LegacyActionSetExpression.class
+			.getName().hashCode();
+
+	/**
+	 * The identifier of the action set that must be active for this expression
+	 * to evaluate to <code>true</code>. This value is never
+	 * <code>null</code>.
+	 */
+	private final String actionSetId;
+
+	/**
+	 * Constructs a new instance of {@link LegacyActionSetExpression}.
+	 *
+	 * @param actionSetId
+	 *            The identifier of the action set that must be active for this
+	 *            expression to evaluate to <code>true</code>; must not be
+	 *            <code>null</code>.
+	 * @param window
+	 *            The workbench window in which this handler should be active.
+	 *            This avoids conflicts between handlers from different windows.
+	 *            This should not be <code>null</code>.
+	 */
+	public LegacyActionSetExpression(final String actionSetId,
+			final IWorkbenchWindow window) {
+		super(window);
+		if (actionSetId == null) {
+			throw new NullPointerException(
+					"The action set identifier cannot be null"); //$NON-NLS-1$
+		}
+		this.actionSetId = actionSetId;
+	}
+
+	@Override
+	public final void collectExpressionInfo(final ExpressionInfo info) {
+		super.collectExpressionInfo(info);
+		info.addVariableNameAccess(ISources.ACTIVE_CONTEXT_NAME);
+	}
+
+	protected final int computeHhashCode() {
+		int hashCode = HASH_INITIAL * HASH_FACTOR + hashCode(getWindow());
+		hashCode = hashCode * HASH_FACTOR + hashCode(actionSetId);
+		return hashCode;
+	}
+
+	@Override
+	public final boolean equals(final Object object) {
+		if (object instanceof LegacyActionSetExpression) {
+			final LegacyActionSetExpression that = (LegacyActionSetExpression) object;
+			return equals(this.actionSetId, that.actionSetId)
+					&& equals(this.getWindow(), that.getWindow());
+		}
+
+		return false;
+	}
+
+	@Override
+	public final EvaluationResult evaluate(final IEvaluationContext context)
+			throws CoreException {
+		final EvaluationResult result = super.evaluate(context);
+		if (result == EvaluationResult.FALSE) {
+			return result;
+		}
+
+		Object obj = context.getVariable(ISources.ACTIVE_CONTEXT_NAME);
+		if (obj instanceof Collection<?>) {
+			return EvaluationResult.valueOf(((Collection) obj).contains(actionSetId));
+		}
+		return EvaluationResult.FALSE;
+	}
+
+	@Override
+	public final String toString() {
+		final StringBuffer buffer = new StringBuffer();
+		buffer.append("ActionSetExpression("); //$NON-NLS-1$
+		buffer.append(actionSetId);
+		buffer.append(',');
+		buffer.append(getWindow());
+		buffer.append(')');
+		return buffer.toString();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/expressions/LegacyEditorActionBarExpression.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/expressions/LegacyEditorActionBarExpression.java
new file mode 100644
index 0000000..35ba5b8
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/expressions/LegacyEditorActionBarExpression.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.expressions;
+
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.ExpressionInfo;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.internal.services.SourcePriorityNameMapping;
+
+/**
+ * <p>
+ * An expression representing the <code>part id</code> of the legacy editor
+ * action bar contribution.
+ * </p>
+ * <p>
+ * This class is not intended for use outside of the
+ * <code>org.eclipse.ui.workbench</code> plug-in.
+ * </p>
+ *
+ * @since 3.2
+ */
+public class LegacyEditorActionBarExpression extends Expression {
+	/**
+	 * The seed for the hash code for all schemes.
+	 */
+	private static final int HASH_INITIAL = LegacyEditorActionBarExpression.class
+			.getName().hashCode();
+
+	/**
+	 * The identifier for the editor that must be active for this expression to
+	 * evaluate to <code>true</code>. This value is never <code>null</code>.
+	 */
+	private final String activeEditorId;
+
+	/**
+	 * Constructs a new instance of <code>LegacyEditorActionBarExpression</code>
+	 *
+	 * @param editorId
+	 *            The identifier of the editor to match with the active editor;
+	 *            must not be <code>null</code>
+	 */
+	public LegacyEditorActionBarExpression(final String editorId) {
+
+		if (editorId == null) {
+			throw new IllegalArgumentException(
+					"The targetId for an editor contribution must not be null"); //$NON-NLS-1$
+		}
+		activeEditorId = editorId;
+	}
+
+	@Override
+	public final void collectExpressionInfo(final ExpressionInfo info) {
+		info.addVariableNameAccess(ISources.ACTIVE_PART_ID_NAME);
+		info
+				.addVariableNameAccess(SourcePriorityNameMapping.LEGACY_LEGACY_NAME);
+	}
+
+	@Override
+	protected final int computeHashCode() {
+		int hashCode = HASH_INITIAL * HASH_FACTOR + hashCode(activeEditorId);
+		return hashCode;
+	}
+
+	@Override
+	public final boolean equals(final Object object) {
+		if (object instanceof LegacyEditorActionBarExpression) {
+			final LegacyEditorActionBarExpression that = (LegacyEditorActionBarExpression) object;
+			return activeEditorId.equals(that.activeEditorId);
+		}
+
+		return false;
+	}
+
+	@Override
+	public final EvaluationResult evaluate(final IEvaluationContext context) {
+		final Object variable = context
+				.getVariable(ISources.ACTIVE_PART_ID_NAME);
+		if (equals(activeEditorId, variable)) {
+			return EvaluationResult.TRUE;
+		}
+		return EvaluationResult.FALSE;
+	}
+
+	@Override
+	public final String toString() {
+		final StringBuffer buffer = new StringBuffer();
+		buffer.append("LegacyEditorActionBarExpression("); //$NON-NLS-1$
+		buffer.append(activeEditorId);
+		buffer.append(')');
+		return buffer.toString();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/expressions/LegacyEditorContributionExpression.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/expressions/LegacyEditorContributionExpression.java
new file mode 100644
index 0000000..5358a76
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/expressions/LegacyEditorContributionExpression.java
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.expressions;
+
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.ExpressionInfo;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.IWorkbenchWindow;
+
+/**
+ * <p>
+ * An expression representing the <code>targetId</code> of the legacy editor
+ * contributions.
+ * </p>
+ * <p>
+ * This class is not intended for use outside of the
+ * <code>org.eclipse.ui.workbench</code> plug-in.
+ * </p>
+ *
+ * @since 3.2
+ */
+public final class LegacyEditorContributionExpression extends
+		WorkbenchWindowExpression {
+
+	/**
+	 * The seed for the hash code for all schemes.
+	 */
+	private static final int HASH_INITIAL = LegacyEditorContributionExpression.class
+			.getName().hashCode();
+
+	/**
+	 * The identifier for the editor that must be active for this expression to
+	 * evaluate to <code>true</code>. This value is never <code>null</code>.
+	 */
+	private final String activeEditorId;
+
+	/**
+	 * Constructs a new instance of
+	 * <code>LegacyEditorContributionExpression</code>
+	 *
+	 * @param activeEditorId
+	 *            The identifier of the editor to match with the active editor;
+	 *            may be <code>null</code>
+	 * @param window
+	 *            The workbench window in which this handler should be active.
+	 *            This value is never <code>null</code>.
+	 */
+	public LegacyEditorContributionExpression(final String activeEditorId,
+			final IWorkbenchWindow window) {
+		super(window);
+
+		if (activeEditorId == null) {
+			throw new NullPointerException(
+					"The targetId for an editor contribution must not be null"); //$NON-NLS-1$
+		}
+		this.activeEditorId = activeEditorId;
+	}
+
+	@Override
+	public final void collectExpressionInfo(final ExpressionInfo info) {
+		super.collectExpressionInfo(info);
+		info.addVariableNameAccess(ISources.ACTIVE_PART_ID_NAME);
+	}
+
+	@Override
+	protected final int computeHashCode() {
+		int hashCode = HASH_INITIAL * HASH_FACTOR + hashCode(getWindow());
+		hashCode = hashCode * HASH_FACTOR + hashCode(activeEditorId);
+		return hashCode;
+	}
+
+	@Override
+	public final boolean equals(final Object object) {
+		if (object instanceof LegacyEditorContributionExpression) {
+			final LegacyEditorContributionExpression that = (LegacyEditorContributionExpression) object;
+			return equals(this.activeEditorId, that.activeEditorId)
+					&& equals(this.getWindow(), that.getWindow());
+		}
+
+		return false;
+	}
+
+	@Override
+	public final EvaluationResult evaluate(final IEvaluationContext context)
+			throws CoreException {
+		final EvaluationResult result = super.evaluate(context);
+		if (result == EvaluationResult.FALSE) {
+			return result;
+		}
+
+		final Object variable = context
+				.getVariable(ISources.ACTIVE_PART_ID_NAME);
+		if (equals(activeEditorId, variable)) {
+			return EvaluationResult.TRUE;
+		}
+		return EvaluationResult.FALSE;
+	}
+
+	@Override
+	public final String toString() {
+		final StringBuffer buffer = new StringBuffer();
+		buffer.append("LegacyEditorContributionExpression("); //$NON-NLS-1$
+		buffer.append(activeEditorId);
+		buffer.append(',');
+		buffer.append(getWindow());
+		buffer.append(')');
+		return buffer.toString();
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/expressions/LegacySelectionEnablerWrapper.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/expressions/LegacySelectionEnablerWrapper.java
new file mode 100644
index 0000000..7e3cc1c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/expressions/LegacySelectionEnablerWrapper.java
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.expressions;
+
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.ExpressionInfo;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.SelectionEnabler;
+
+/**
+ * <p>
+ * An expression wrapper for the legacy {@link SelectionEnabler}. This emulates
+ * an {@link Expression} using an instance of <code>SelectionEnabler</code>.
+ * </p>
+ * <p>
+ * This class is not intended for use outside of the
+ * <code>org.eclipse.ui.workbench</code> plug-in.
+ * </p>
+ *
+ * @since 3.2
+ */
+public final class LegacySelectionEnablerWrapper extends
+		WorkbenchWindowExpression {
+
+	/**
+	 * The seed for the hash code for all schemes.
+	 */
+	private static final int HASH_INITIAL = LegacySelectionEnablerWrapper.class
+			.getName().hashCode();
+
+	/**
+	 * The enabler for this expression; never <code>null</code>.
+	 */
+	private final SelectionEnabler enabler;
+
+	/**
+	 * Constructs a new instance of <code>SelectionEnablerExpression</code>.
+	 *
+	 * @param enabler
+	 *            The enabler; must not be <code>null</code>.
+	 * @param window
+	 *            The workbench window which must be active for this expression
+	 *            to evaluate to <code>true</code>; may be <code>null</code>
+	 *            if the window should be disregarded.
+	 */
+	public LegacySelectionEnablerWrapper(final SelectionEnabler enabler,
+			final IWorkbenchWindow window) {
+		super(window);
+
+		if (enabler == null) {
+			throw new NullPointerException("There is no enabler"); //$NON-NLS-1$
+		}
+		this.enabler = enabler;
+	}
+
+	@Override
+	public final void collectExpressionInfo(final ExpressionInfo info) {
+		super.collectExpressionInfo(info);
+		info.markDefaultVariableAccessed();
+	}
+
+	@Override
+	protected final int computeHashCode() {
+		int hashCode = HASH_INITIAL * HASH_FACTOR + hashCode(getWindow());
+		hashCode = hashCode * HASH_FACTOR + hashCode(enabler);
+		return hashCode;
+	}
+
+	@Override
+	public final boolean equals(final Object object) {
+		if (object instanceof LegacySelectionEnablerWrapper) {
+			final LegacySelectionEnablerWrapper that = (LegacySelectionEnablerWrapper) object;
+			return equals(this.enabler, that.enabler)
+					&& equals(this.getWindow(), that.getWindow());
+		}
+
+		return false;
+	}
+
+	@Override
+	public final EvaluationResult evaluate(final IEvaluationContext context)
+			throws CoreException {
+		final EvaluationResult result = super.evaluate(context);
+		if (result == EvaluationResult.FALSE) {
+			return result;
+		}
+
+		final Object defaultVariable = context
+				.getVariable(ISources.ACTIVE_CURRENT_SELECTION_NAME);
+		if (defaultVariable instanceof ISelection) {
+			final ISelection selection = (ISelection) defaultVariable;
+			if (enabler.isEnabledForSelection(selection)) {
+				return EvaluationResult.TRUE;
+			}
+		}
+
+		return EvaluationResult.FALSE;
+	}
+
+	@Override
+	public final String toString() {
+		final StringBuffer buffer = new StringBuffer();
+		buffer.append("LegacySelectionEnablerWrapper("); //$NON-NLS-1$
+		buffer.append(enabler);
+		buffer.append(',');
+		buffer.append(getWindow());
+		buffer.append(')');
+		return buffer.toString();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/expressions/LegacyViewContributionExpression.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/expressions/LegacyViewContributionExpression.java
new file mode 100644
index 0000000..9deb663
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/expressions/LegacyViewContributionExpression.java
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.expressions;
+
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.ExpressionInfo;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.IWorkbenchWindow;
+
+/**
+ * <p>
+ * An expression representing the <code>targetId</code> of the legacy view
+ * contributions.
+ * </p>
+ * <p>
+ * This class is not intended for use outside of the
+ * <code>org.eclipse.ui.workbench</code> plug-in.
+ * </p>
+ *
+ * @since 3.2
+ */
+public final class LegacyViewContributionExpression extends
+		WorkbenchWindowExpression {
+
+	/**
+	 * The seed for the hash code for all schemes.
+	 */
+	private static final int HASH_INITIAL = LegacyViewContributionExpression.class
+			.getName().hashCode();
+
+	/**
+	 * The identifier for the part that must be active for this expression to
+	 * evaluate to <code>true</code>. This value is never <code>null</code>.
+	 */
+	private final String activePartId;
+
+	/**
+	 * Constructs a new instance of
+	 * <code>LegacyViewContributionExpression</code>
+	 *
+	 * @param activePartId
+	 *            The identifier of the part to match with the active part; may
+	 *            be <code>null</code>
+	 * @param window
+	 *            The workbench window in which this handler should be active.
+	 *            This value is never <code>null</code>.
+	 */
+	public LegacyViewContributionExpression(final String activePartId,
+			final IWorkbenchWindow window) {
+		super(window);
+
+		if (activePartId == null) {
+			throw new NullPointerException(
+					"The targetId for a view contribution must not be null"); //$NON-NLS-1$
+		}
+		this.activePartId = activePartId;
+	}
+
+	@Override
+	public final void collectExpressionInfo(final ExpressionInfo info) {
+		super.collectExpressionInfo(info);
+		info.addVariableNameAccess(ISources.ACTIVE_PART_ID_NAME);
+	}
+
+	@Override
+	protected final int computeHashCode() {
+		int hashCode = HASH_INITIAL * HASH_FACTOR + hashCode(getWindow());
+		hashCode = hashCode * HASH_FACTOR + hashCode(activePartId);
+		return hashCode;
+	}
+
+	@Override
+	public final boolean equals(final Object object) {
+		if (object instanceof LegacyViewContributionExpression) {
+			final LegacyViewContributionExpression that = (LegacyViewContributionExpression) object;
+			return equals(this.activePartId, that.activePartId)
+					&& equals(this.getWindow(), that.getWindow());
+		}
+
+		return false;
+	}
+
+	@Override
+	public final EvaluationResult evaluate(final IEvaluationContext context)
+			throws CoreException {
+		final EvaluationResult result = super.evaluate(context);
+		if (result == EvaluationResult.FALSE) {
+			return result;
+		}
+
+		final Object variable = context
+				.getVariable(ISources.ACTIVE_PART_ID_NAME);
+		if (equals(activePartId, variable)) {
+			return EvaluationResult.TRUE;
+		}
+		return EvaluationResult.FALSE;
+	}
+
+	@Override
+	public final String toString() {
+		final StringBuffer buffer = new StringBuffer();
+		buffer.append("LegacyViewContributionExpression("); //$NON-NLS-1$
+		buffer.append(activePartId);
+		buffer.append(',');
+		buffer.append(getWindow());
+		buffer.append(')');
+		return buffer.toString();
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/expressions/LegacyViewerContributionExpression.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/expressions/LegacyViewerContributionExpression.java
new file mode 100644
index 0000000..4dbeeeb
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/expressions/LegacyViewerContributionExpression.java
@@ -0,0 +1,158 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.expressions;
+
+import java.util.Collection;
+
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.ExpressionInfo;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.IWorkbenchWindow;
+
+/**
+ * <p>
+ * An expression that can control the activation of a handler derived from a
+ * viewer contribution. The viewer contribution is linked to a menu with a
+ * particular identifier, as well as some other criteria. This expression checks
+ * the target menu id, and contains a child expression for the other criteria.
+ * </p>
+ * <p>
+ * This class is not intended for use outside of the
+ * <code>org.eclipse.ui.workbench</code> plug-in.
+ * </p>
+ *
+ * @see ISources#ACTIVE_MENU_NAME
+ * @since 3.2
+ */
+public final class LegacyViewerContributionExpression extends
+		WorkbenchWindowExpression {
+
+	/**
+	 * The seed for the hash code for all schemes.
+	 */
+	private static final int HASH_INITIAL = LegacyViewerContributionExpression.class
+			.getName().hashCode();
+
+	/**
+	 * The child expression for this viewer contribution. This value may be
+	 * <code>null</code> if there are no criteria beyond the menu id.
+	 */
+	private final Expression expression;
+
+	/**
+	 * The identifier of the menu to which this viewer contribution applies.
+	 * This value is never <code>null</code>.
+	 */
+	private final String targetId;
+
+	/**
+	 * Constructs a new {@link LegacyViewerContributionExpression}.
+	 *
+	 * @param targetId
+	 *            The identifier of the menu to which this viewer contribution
+	 *            applies; never <code>null</code>.
+	 * @param window
+	 *            The workbench window which must be active for this expression
+	 *            to evaluate to <code>true</code>; may be <code>null</code>
+	 *            if the window should be disregarded.
+	 * @param childExpression
+	 *            The child expression for this viewer contribution; may be
+	 *            <code>null</code>.
+	 */
+	public LegacyViewerContributionExpression(final String targetId,
+			final IWorkbenchWindow window, final Expression childExpression) {
+		super(window);
+
+		if (targetId == null) {
+			throw new NullPointerException("The targetId cannot be null"); //$NON-NLS-1$
+		}
+		this.targetId = targetId;
+		this.expression = childExpression;
+	}
+
+	@Override
+	public final void collectExpressionInfo(final ExpressionInfo info) {
+		super.collectExpressionInfo(info);
+		info.addVariableNameAccess(ISources.ACTIVE_MENU_NAME);
+		if (expression != null) {
+			expression.collectExpressionInfo(info);
+		}
+	}
+
+	@Override
+	protected final int computeHashCode() {
+		int hashCode = HASH_INITIAL * HASH_FACTOR + hashCode(getWindow());
+		hashCode = hashCode * HASH_FACTOR + hashCode(expression);
+		hashCode = hashCode * HASH_FACTOR + hashCode(targetId);
+		return hashCode;
+	}
+
+	@Override
+	public final boolean equals(final Object object) {
+		if (object instanceof LegacyViewerContributionExpression) {
+			final LegacyViewerContributionExpression that = (LegacyViewerContributionExpression) object;
+			return equals(this.targetId, that.targetId)
+					&& equals(this.expression, that.expression)
+					&& equals(this.getWindow(), that.getWindow());
+		}
+
+		return false;
+	}
+
+	@Override
+	public final EvaluationResult evaluate(final IEvaluationContext context)
+			throws CoreException {
+		final EvaluationResult result = super.evaluate(context);
+		if (result == EvaluationResult.FALSE) {
+			return result;
+		}
+
+		final Object value = context.getVariable(ISources.ACTIVE_MENU_NAME);
+		if (value instanceof String) {
+			final String menuId = (String) value;
+			if (targetId.equals(menuId)) {
+				if (expression == null) {
+					return EvaluationResult.TRUE;
+				}
+
+				return expression.evaluate(context);
+			}
+		} else if (value instanceof Collection) {
+			final Collection menuIds = (Collection) value;
+			if (menuIds.contains(targetId)) {
+				if (expression == null) {
+					return EvaluationResult.TRUE;
+				}
+
+				return expression.evaluate(context);
+			}
+		}
+
+		return EvaluationResult.FALSE;
+	}
+
+	@Override
+	public final String toString() {
+		final StringBuffer buffer = new StringBuffer();
+		buffer.append("ViewerContributionExpression("); //$NON-NLS-1$
+		buffer.append(targetId);
+		buffer.append(',');
+		buffer.append(expression);
+		buffer.append(',');
+		buffer.append(getWindow());
+		buffer.append(')');
+		return buffer.toString();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/expressions/WorkbenchWindowExpression.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/expressions/WorkbenchWindowExpression.java
new file mode 100644
index 0000000..25b9a96
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/expressions/WorkbenchWindowExpression.java
@@ -0,0 +1,112 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.expressions;
+
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.ExpressionInfo;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.IWorkbenchWindow;
+
+/**
+ * <p>
+ * An expression that evaluates to {@link EvaluationResult#TRUE} when the active
+ * workbench window matches the window held by this expression.
+ * </p>
+ *
+ * @since 3.2
+ */
+public class WorkbenchWindowExpression extends Expression {
+
+	/**
+	 * The seed for the hash code for all schemes.
+	 */
+	private static final int HASH_INITIAL = WorkbenchWindowExpression.class
+			.getName().hashCode();
+
+	/**
+	 * The workbench window that must be active for this expression to evaluate
+	 * to <code>true</code>. If this value is <code>null</code>, then any
+	 * workbench window may be active.
+	 */
+	private final IWorkbenchWindow window;
+
+	/**
+	 * Constructs a new instance.
+	 *
+	 * @param window
+	 *            The workbench window which must be active for this expression
+	 *            to evaluate to <code>true</code>; may be <code>null</code>
+	 *            if this expression is always <code>true</code>.
+	 */
+	public WorkbenchWindowExpression(final IWorkbenchWindow window) {
+		this.window = window;
+	}
+
+	@Override
+	public void collectExpressionInfo(final ExpressionInfo info) {
+		if (window != null) {
+			info.addVariableNameAccess(ISources.ACTIVE_WORKBENCH_WINDOW_NAME);
+		}
+	}
+
+	@Override
+	protected int computeHashCode() {
+		return HASH_INITIAL * HASH_FACTOR + hashCode(window);
+	}
+
+	@Override
+	public boolean equals(final Object object) {
+		if (object instanceof WorkbenchWindowExpression) {
+			final WorkbenchWindowExpression that = (WorkbenchWindowExpression) object;
+			return equals(this.window, that.window);
+		}
+
+		return false;
+	}
+
+	@Override
+	public EvaluationResult evaluate(final IEvaluationContext context)
+			throws CoreException {
+		if (window != null) {
+			Object value = context
+					.getVariable(ISources.ACTIVE_WORKBENCH_WINDOW_NAME);
+			if (window.equals(value)) {
+				return EvaluationResult.TRUE;
+			}
+		}
+
+		return EvaluationResult.FALSE;
+	}
+
+	/**
+	 * Returns the workbench window to which this expression applies.
+	 *
+	 * @return The workbench window to which this expression applies; may be
+	 *         <code>null</code>.
+	 */
+	protected final IWorkbenchWindow getWindow() {
+		return window;
+	}
+
+	@Override
+	public String toString() {
+		final StringBuffer buffer = new StringBuffer();
+		buffer.append("WorkbenchWindowExpression("); //$NON-NLS-1$
+		buffer.append(window);
+		buffer.append(')');
+		return buffer.toString();
+	}
+}
+
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/AbstractSaveHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/AbstractSaveHandler.java
new file mode 100644
index 0000000..3f97972
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/AbstractSaveHandler.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2015 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
+ *     Andrey Loskutov <loskutov@gmx.de> - Bug 372799
+ ******************************************************************************/
+package org.eclipse.ui.internal.handlers;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.ExpressionInfo;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.ui.ISaveablePart;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.eclipse.ui.internal.AbstractEvaluationHandler;
+import org.eclipse.ui.internal.InternalHandlerUtil;
+import org.eclipse.ui.internal.SaveableHelper;
+
+/**
+ * @since 3.7
+ *
+ */
+public abstract class AbstractSaveHandler extends AbstractEvaluationHandler {
+
+	protected static DirtyStateTracker dirtyStateTracker;
+	private Expression enabledWhen;
+
+	public AbstractSaveHandler() {
+		if (dirtyStateTracker == null) {
+			dirtyStateTracker = new DirtyStateTracker();
+		}
+	}
+
+	@Override
+	protected Expression getEnabledWhenExpression() {
+		if (enabledWhen == null) {
+			enabledWhen = new Expression() {
+				@Override
+				public EvaluationResult evaluate(IEvaluationContext context) {
+					return AbstractSaveHandler.this.evaluate(context);
+				}
+
+				@Override
+				public void collectExpressionInfo(ExpressionInfo info) {
+					info.addVariableNameAccess(ISources.ACTIVE_PART_NAME);
+				}
+			};
+		}
+		return enabledWhen;
+	}
+
+	protected abstract EvaluationResult evaluate(IEvaluationContext context);
+
+	protected ISaveablePart getSaveablePart(IEvaluationContext context) {
+		IWorkbenchPart activePart = InternalHandlerUtil.getActivePart(context);
+		ISaveablePart part = SaveableHelper.getSaveable(activePart);
+		if (part != null) {
+			return part;
+		}
+		return InternalHandlerUtil.getActiveEditor(context);
+	}
+
+	protected ISaveablePart getSaveablePart(ExecutionEvent event) {
+		IWorkbenchPart activePart = HandlerUtil.getActivePart(event);
+		ISaveablePart part = SaveableHelper.getSaveable(activePart);
+		if (part != null) {
+			return part;
+		}
+		return HandlerUtil.getActiveEditor(event);
+	}
+
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ActionCommandMappingService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ActionCommandMappingService.java
new file mode 100644
index 0000000..8f7f597
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ActionCommandMappingService.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.handlers;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+
+/**
+ * <p>
+ * A service which holds mappings between retarget action identifiers and
+ * command identifiers (aka: action definition ids). This implementation does
+ * not clean up in the case of dynamic plug-ins.
+ * </p>
+ * <p>
+ * This class is not intended for use outside of the
+ * <code>org.eclipse.ui.workbench</code> plug-in.
+ * </p>
+ *
+ * @since 3.2
+ */
+public final class ActionCommandMappingService implements
+		IActionCommandMappingService {
+
+	/**
+	 * The map of action identifiers ({@link String}) to command identifiers ({@link String}).
+	 * This value is never <code>null</code>.
+	 */
+	private final Map mapping = new HashMap();
+
+	@Override
+	public final String getCommandId(final String actionId) {
+		if (actionId == null) {
+			throw new NullPointerException(
+					"Cannot get the command identifier for a null action id"); //$NON-NLS-1$
+		}
+
+		return (String) mapping.get(actionId);
+	}
+
+	@Override
+	public final void map(final String actionId, final String commandId) {
+		if (actionId == null) {
+			throw new NullPointerException("The action id cannot be null"); //$NON-NLS-1$
+		}
+
+		if (commandId == null) {
+			throw new NullPointerException("The command id cannot be null"); //$NON-NLS-1$
+		}
+
+		mapping.put(actionId, commandId);
+	}
+
+	@Override
+	public final String getGeneratedCommandId(String targetId, String actionId) {
+		return IWorkbenchRegistryConstants.AUTOGENERATED_PREFIX + targetId
+				+ '/' + actionId;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ActionDelegateHandlerProxy.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ActionDelegateHandlerProxy.java
new file mode 100644
index 0000000..865857d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ActionDelegateHandlerProxy.java
@@ -0,0 +1,750 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2016 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
+ *     Friederike Schertel <friederike@schertel.org> - Bug 478336
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.handlers;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.core.commands.IHandler2;
+import org.eclipse.core.commands.IHandlerListener;
+import org.eclipse.core.commands.IObjectWithState;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.commands.State;
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.InvalidRegistryObjectException;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.ui.IActionDelegate;
+import org.eclipse.ui.IActionDelegate2;
+import org.eclipse.ui.IActionDelegateWithEvent;
+import org.eclipse.ui.IEditorActionDelegate;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.INullSelectionListener;
+import org.eclipse.ui.IObjectActionDelegate;
+import org.eclipse.ui.IPartListener2;
+import org.eclipse.ui.ISelectionListener;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.IViewActionDelegate;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartReference;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.IWorkbenchWindowActionDelegate;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.util.BundleUtility;
+
+/**
+ * <p>
+ * This proxies an {@link IActionDelegate} so that it can impersonate an
+ * {@link IHandler}.
+ * </p>
+ * <p>
+ * This class is not intended for use outside of the
+ * <code>org.eclipse.ui.workbench</code> plug-in.
+ * </p>
+ *
+ * @since 3.2
+ */
+public final class ActionDelegateHandlerProxy implements ISelectionListener,
+		ISelectionChangedListener, INullSelectionListener, IHandler2,
+		IObjectWithState, IPartListener2 {
+
+	/**
+	 * The fake action that proxies all of the command-based services. This
+	 * value is never <code>null</code>.
+	 */
+	private CommandLegacyActionWrapper action;
+
+	/**
+	 * The identifier of the actions to create as a wrapper to the command
+	 * architecture. This value may be <code>null</code>.
+	 */
+	private String actionId;
+
+	/**
+	 * The command that will back the dummy actions exposed to this delegate.
+	 * This value is never <code>null</code>.
+	 */
+	private ParameterizedCommand command;
+
+	/**
+	 * This is the current selection, as seen by this proxy.
+	 */
+	private ISelection currentSelection;
+
+	/**
+	 * The delegate, if it has been created yet.
+	 */
+	private IActionDelegate delegate;
+
+	//
+	// instead of casting, which is unreliable, pick
+	// a delegate type based on the IConfigurationElement
+	//
+	private IEditorActionDelegate editorDelegate = null;
+	private IViewActionDelegate viewDelegate = null;
+	private IObjectActionDelegate objectDelegate = null;
+	private IWorkbenchWindowActionDelegate windowDelegate = null;
+
+	private IWorkbenchPart currentPart = null;
+
+	/**
+	 * The name of the configuration element attribute which contains the
+	 * information necessary to instantiate the real handler.
+	 */
+	private String delegateAttributeName;
+
+	/**
+	 * The configuration element from which the handler can be created. This
+	 * value will exist until the element is converted into a real class -- at
+	 * which point this value will be set to <code>null</code>.
+	 */
+	private IConfigurationElement element;
+
+	/**
+	 * The <code>enabledWhen</code> expression for the handler. Only if this
+	 * expression evaluates to <code>true</code> (or the value is
+	 * <code>null</code>) should we consult the handler.
+	 */
+	private final Expression enabledWhenExpression;
+
+	/**
+	 * A collection of objects listening to changes to this manager. This
+	 * collection is <code>null</code> if there are no listeners.
+	 */
+	private transient ListenerList<IHandlerListener> listenerList = null;
+
+	/**
+	 * The image style to use when selecting the images to display for this
+	 * delegate. This value may be <code>null</code>, if the default style
+	 * should be used.
+	 */
+	private final String style;
+
+	/**
+	 * The identifier of the view with which this delegate must be associated.
+	 * This value is not <code>null</code> iff the delegate is an
+	 * {@link IViewActionDelegate}.
+	 */
+	private final String viewId;
+
+	/**
+	 * The workbench window in which this delegate is active. This value is
+	 * never <code>null</code>.
+	 */
+	private final IWorkbenchWindow window;
+
+	/**
+	 * Constructs a new instance of <code>ActionDelegateHandlerProxy</code>
+	 * with all the information it needs to try to avoid loading until it is
+	 * needed.
+	 *
+	 * @param element
+	 *            The configuration element from which the real class can be
+	 *            loaded at run-time; must not be <code>null</code>.
+	 * @param delegateAttributeName
+	 *            The name of the attibute or element containing the action
+	 *            delegate; must not be <code>null</code>.
+	 * @param actionId
+	 *            The identifier of the underlying action; may be
+	 *            <code>null</code>.
+	 * @param command
+	 *            The command with which the action delegate will be associated;
+	 *            must not be <code>null</code>.
+	 * @param window
+	 *            The workbench window in which this delegate will be active;
+	 *            must not be <code>null</code>.
+	 * @param style
+	 *            The image style with which the icons are associated; may be
+	 *            <code>null</code>.
+	 * @param enabledWhenExpression
+	 *            The name of the element containing the enabledWhen expression.
+	 *            This should be a child of the
+	 *            <code>configurationElement</code>. If this value is
+	 *            <code>null</code>, then there is no enablement expression
+	 *            (i.e., enablement will be delegated to the handler when
+	 *            possible).
+	 * @param viewId
+	 *            The identifier of the view to which this proxy is bound; may
+	 *            be <code>null</code> if this proxy is not for an
+	 *            {@link IViewActionDelegate}.
+	 */
+	public ActionDelegateHandlerProxy(final IConfigurationElement element,
+			final String delegateAttributeName, final String actionId,
+			final ParameterizedCommand command, final IWorkbenchWindow window,
+			final String style, final Expression enabledWhenExpression,
+			final String viewId) {
+		if (element == null) {
+			throw new NullPointerException(
+					"The configuration element backing a handler proxy cannot be null"); //$NON-NLS-1$
+		}
+
+		if (delegateAttributeName == null) {
+			throw new NullPointerException(
+					"The attribute containing the action delegate must be known"); //$NON-NLS-1$
+		}
+
+		if (window == null) {
+			throw new NullPointerException(
+					"The workbench window for a delegate must not be null"); //$NON-NLS-1$
+		}
+
+		this.element = element;
+		this.enabledWhenExpression = enabledWhenExpression;
+		this.delegateAttributeName = delegateAttributeName;
+		this.window = window;
+		this.command = command;
+		this.actionId = actionId;
+		this.style = style;
+		this.viewId = viewId;
+	}
+
+	@Override
+	public final void addHandlerListener(final IHandlerListener handlerListener) {
+		if (listenerList == null) {
+			listenerList = new ListenerList<>(ListenerList.IDENTITY);
+		}
+
+		listenerList.add(handlerListener);
+	}
+
+	@Override
+	public void addState(String id, State state) {
+	}
+
+
+	@Override
+	public final void dispose() {
+		disposeDelegate();
+	}
+
+	/**
+	 *
+	 */
+	private void disposeDelegate() {
+		final IActionDelegate actDel = getDelegate();
+		if (actDel instanceof IWorkbenchWindowActionDelegate) {
+			final IWorkbenchWindowActionDelegate workbenchWindowDelegate = (IWorkbenchWindowActionDelegate) actDel;
+			workbenchWindowDelegate.dispose();
+		} else if (actDel instanceof IActionDelegate2) {
+			final IActionDelegate2 delegate2 = (IActionDelegate2) actDel;
+			delegate2.dispose();
+		}
+		delegate = null;
+		editorDelegate = null;
+		objectDelegate = null;
+		viewDelegate = null;
+		windowDelegate = null;
+		currentSelection = null;
+	}
+
+	@Override
+	public final Object execute(final ExecutionEvent event) {
+		final IAction action = getAction();
+		if (loadDelegate() && (action != null)) {
+			final Object trigger = event.getTrigger();
+
+			// Attempt to update the selection.
+			final Object applicationContext = event.getApplicationContext();
+			if (applicationContext instanceof IEvaluationContext) {
+				final IEvaluationContext context = (IEvaluationContext) applicationContext;
+				updateDelegate(action, context);
+			}
+
+			if ((action.getStyle() == IAction.AS_CHECK_BOX)
+					|| (action.getStyle() == IAction.AS_RADIO_BUTTON)) {
+				action.setChecked(!action.isChecked());
+			}
+
+			// Decide what type of delegate we have.
+			if ((delegate instanceof IActionDelegate2)
+					&& (trigger instanceof Event)) {
+				// This supports Eclipse 2.1 to Eclipse 3.1.
+				final IActionDelegate2 delegate2 = (IActionDelegate2) delegate;
+				final Event triggeringEvent = (Event) trigger;
+				delegate2.runWithEvent(action, triggeringEvent);
+			} else if ((delegate instanceof IActionDelegateWithEvent)
+					&& (trigger instanceof Event)) {
+				// This supports Eclipse 2.0
+				final IActionDelegateWithEvent delegateWithEvent = (IActionDelegateWithEvent) delegate;
+				final Event triggeringEvent = (Event) trigger;
+				delegateWithEvent.runWithEvent(action, triggeringEvent);
+			} else {
+				delegate.run(action);
+			}
+		}
+
+		return null;
+	}
+
+	/**
+	 * @param action
+	 * @param context
+	 */
+	private void updateDelegate(final IAction action,
+			final IEvaluationContext context) {
+		if (action == null) {
+			return;
+		}
+		if (delegate == null) {
+			if (!BundleUtility.isActive(element.getContributor().getName())) {
+				return;
+			}
+		}
+
+		if (editorDelegate != null) {
+			final Object activeEditor = context
+					.getVariable(ISources.ACTIVE_EDITOR_NAME);
+			if (activeEditor != IEvaluationContext.UNDEFINED_VARIABLE) {
+				editorDelegate.setActiveEditor(action,
+						(IEditorPart) activeEditor);
+			}
+			updateActivePart(activeEditor==IEvaluationContext.UNDEFINED_VARIABLE
+					?null:(IWorkbenchPart)activeEditor);
+		} else if (objectDelegate != null) {
+			final Object activePart = context
+					.getVariable(ISources.ACTIVE_PART_NAME);
+			if (activePart != IEvaluationContext.UNDEFINED_VARIABLE) {
+				objectDelegate.setActivePart(action,
+						(IWorkbenchPart) activePart);
+			}
+			updateActivePart(activePart==IEvaluationContext.UNDEFINED_VARIABLE
+					?null:(IWorkbenchPart) activePart);
+		}
+
+		final Object selectionObject = getCurrentSelection(context);
+		if (selectionObject instanceof ISelection) {
+			currentSelection = (ISelection) selectionObject;
+		} else {
+			currentSelection = null;
+		}
+		if (delegate != null) {
+			delegate.selectionChanged(action, currentSelection);
+		}
+	}
+
+	/**
+	 * @param activePart
+	 */
+	private void updateActivePart(IWorkbenchPart activePart) {
+		if (currentPart == activePart) {
+			return;
+		}
+		if (currentPart != null) {
+			currentPart.getSite().getPage().removePartListener(this);
+		}
+		if (activePart != null) {
+			activePart.getSite().getPage().addPartListener(this);
+		} else {
+			selectionChanged(StructuredSelection.EMPTY);
+			disposeDelegate();
+			if (action!=null) {
+				action.setEnabled(true);
+			}
+		}
+		currentPart = activePart;
+	}
+
+	/**
+	 * @param context
+	 * @return
+	 */
+	private Object getCurrentSelection(final IEvaluationContext context) {
+		Object obj = context
+				.getVariable(ISources.ACTIVE_MENU_EDITOR_INPUT_NAME);
+		if (obj == null || obj == IEvaluationContext.UNDEFINED_VARIABLE) {
+			obj = context.getVariable(ISources.ACTIVE_MENU_SELECTION_NAME);
+			if (obj == null || obj == IEvaluationContext.UNDEFINED_VARIABLE) {
+				obj = context
+						.getVariable(ISources.ACTIVE_CURRENT_SELECTION_NAME);
+			}
+		}
+		return obj;
+	}
+
+	/**
+	 * Retrieves the action corresponding to the currently active workbench
+	 * window, if any.
+	 *
+	 * @return The current action; <code>null</code> if there is no currently
+	 *         active workbench window.
+	 */
+	public final CommandLegacyActionWrapper getAction() {
+		if (action == null) {
+			action = new CommandLegacyActionWrapper(actionId, command, style,
+					window);
+			action.addPropertyChangeListener(event -> {
+				// TODO Update the state somehow.
+			});
+		}
+		return action;
+	}
+
+	/**
+	 * Retrieves the delegate corresponding to the currently active workbench
+	 * window, if any. This does not trigger loading of the delegate.
+	 *
+	 * @return The current delegate; or <code>null</code> if none.
+	 */
+	public final IActionDelegate getDelegate() {
+		return delegate;
+	}
+
+	@Override
+	public State getState(String stateId) {
+		return null;
+	}
+
+	@Override
+	public String[] getStateIds() {
+		return null;
+	}
+
+	public final void handleStateChange(final State state, final Object oldValue) {
+		// TODO What should we do here?
+	}
+
+	/**
+	 * Initialize the action delegate by calling its lifecycle method.
+	 */
+	private final boolean initDelegate() {
+		final IWorkbenchPage page = window.getActivePage();
+		final IWorkbenchPart activePart;
+		final IEditorPart activeEditor;
+		if (page == null) {
+			activePart = null;
+			activeEditor = null;
+		} else {
+			activePart = page.getActivePart();
+			activeEditor = page.getActiveEditor();
+		}
+		final IActionDelegate delegate = getDelegate();
+		final IAction action = getAction();
+
+		// Check to see if the view delegate should be initialized.
+		if ((viewId != null) && (page != null) && (viewDelegate != null)) {
+			final IViewPart viewPart = page.findView(viewId);
+			if (viewPart == null) {
+				return false;
+			}
+		}
+
+		// Initialize the delegate.
+		final ISafeRunnable runnable = new ISafeRunnable() {
+			@Override
+			public final void handleException(final Throwable exception) {
+				// Do nothing.
+			}
+
+			@Override
+			public final void run() {
+				// Handle IActionDelegate2
+				if (delegate instanceof IActionDelegate2) {
+					final IActionDelegate2 delegate2 = (IActionDelegate2) delegate;
+					delegate2.init(action);
+				}
+
+				// Handle IObjectActionDelegates
+				if ((objectDelegate != null) && (activePart != null)) {
+					objectDelegate.setActivePart(action, activePart);
+					updateActivePart(activePart);
+				} else if (editorDelegate != null) {
+					editorDelegate.setActiveEditor(action, activeEditor);
+					updateActivePart(activeEditor);
+				} else if ((viewId != null) && (page != null)
+						&& (viewDelegate != null)) {
+					final IViewPart viewPart = page.findView(viewId);
+					viewDelegate.init(viewPart);
+				} else if (windowDelegate != null) {
+					windowDelegate.init(window);
+				}
+			}
+		};
+		SafeRunner.run(runnable);
+		return true;
+	}
+
+	@Override
+	public void setEnabled(Object evaluationContext) {
+		if (!(evaluationContext instanceof IEvaluationContext)) {
+			return;
+		}
+
+		IEvaluationContext context = (IEvaluationContext) evaluationContext;
+		final CommandLegacyActionWrapper action = getAction();
+		if (enabledWhenExpression != null) {
+			try {
+				final EvaluationResult result = enabledWhenExpression
+						.evaluate(context);
+				if (action != null) {
+					action.setEnabled(result != EvaluationResult.FALSE);
+				}
+			} catch (final CoreException e) {
+				// We will just fall through an let it return false.
+				final StringBuffer message = new StringBuffer(
+						"An exception occurred while evaluating the enabledWhen expression for "); //$NON-NLS-1$
+				if (delegate != null) {
+					message.append(delegate);
+				} else {
+					message.append(element.getAttribute(delegateAttributeName));
+				}
+				message.append("' could not be loaded"); //$NON-NLS-1$
+				final IStatus status = new Status(IStatus.WARNING,
+						WorkbenchPlugin.PI_WORKBENCH, 0, e.getMessage(), e);
+				WorkbenchPlugin.log(message.toString(), status);
+				return;
+			}
+		}
+		updateDelegate(action, context);
+	}
+
+	@Override
+	public final boolean isEnabled() {
+		return (action == null) || action.isEnabledDisregardingCommand();
+	}
+
+	@Override
+	public final boolean isHandled() {
+		return true;
+	}
+
+	/**
+	 * Checks if the declaring plugin has been loaded. This means that there
+	 * will be no need to delay creating the delegate.
+	 *
+	 * @return <code>true</code> if the bundle containing the delegate is
+	 *         already loaded -- making it safe to load the delegate.
+	 */
+	private final boolean isSafeToLoadDelegate() {
+		return false;
+		// TODO This causes problem because some people expect their selections
+		// to be a particular class.
+		// final String bundleId = element.getNamespace();
+		// return BundleUtility.isActive(bundleId);
+	}
+
+	/**
+	 * Loads the delegate, if possible. If the delegate is loaded, then the
+	 * member variables are updated accordingly.
+	 *
+	 * @return <code>true</code> if the delegate is now non-null;
+	 *         <code>false</code> otherwise.
+	 */
+	public final boolean loadDelegate() {
+		// Try to load the delegate, if it hasn't been loaded already.
+		if (delegate == null) {
+			/*
+			 * If this is an IViewActionDelegate, then check to see if we have a
+			 * view ready yet. If not, then we'll have to wait.
+			 */
+			if (viewId != null) {
+				final IWorkbenchPage activePage = window.getActivePage();
+				if (activePage != null) {
+					final IViewPart part = activePage.findView(viewId);
+					if (part == null) {
+						return false;
+					}
+				} else {
+					return false;
+				}
+			}
+
+			// Load the delegate.
+			try {
+				delegate = (IActionDelegate) element
+						.createExecutableExtension(delegateAttributeName);
+				String name = element.getDeclaringExtension()
+						.getExtensionPointUniqueIdentifier();
+				if ("org.eclipse.ui.actionSets".equals(name) //$NON-NLS-1$
+						&& delegate instanceof IWorkbenchWindowActionDelegate) {
+					windowDelegate = (IWorkbenchWindowActionDelegate) delegate;
+				} else if ("org.eclipse.ui.editorActions".equals(name) //$NON-NLS-1$
+						&& delegate instanceof IEditorActionDelegate) {
+					editorDelegate = (IEditorActionDelegate) delegate;
+				} else if ("org.eclipse.ui.viewActions".equals(name) //$NON-NLS-1$
+						&& delegate instanceof IViewActionDelegate) {
+					viewDelegate = (IViewActionDelegate) delegate;
+				} else if ("org.eclipse.ui.popupMenus".equals(name)) { //$NON-NLS-1$
+					IConfigurationElement parent = (IConfigurationElement) element
+							.getParent();
+					if ("objectContribution".equals(parent.getName()) //$NON-NLS-1$
+							&& delegate instanceof IObjectActionDelegate) {
+						objectDelegate = (IObjectActionDelegate) delegate;
+					} else if (viewId == null
+							&& delegate instanceof IEditorActionDelegate) {
+						editorDelegate = (IEditorActionDelegate) delegate;
+					} else if (viewId != null
+							&& delegate instanceof IViewActionDelegate) {
+						viewDelegate = (IViewActionDelegate) delegate;
+					}
+				}
+				if (initDelegate()) {
+					return true;
+				}
+
+				delegate = null;
+				objectDelegate = null;
+				viewDelegate = null;
+				editorDelegate = null;
+				windowDelegate = null;
+				return false;
+
+			} catch (final ClassCastException e) {
+				final String message = "The proxied delegate was the wrong class"; //$NON-NLS-1$
+				final IStatus status = new Status(IStatus.ERROR,
+						WorkbenchPlugin.PI_WORKBENCH, 0, message, e);
+				WorkbenchPlugin.log(message, status);
+				return false;
+
+			} catch (final CoreException e) {
+				final String message = "The proxied delegate for '" //$NON-NLS-1$
+						+ element.getAttribute(delegateAttributeName)
+						+ "' could not be loaded"; //$NON-NLS-1$
+				IStatus status = new Status(IStatus.ERROR,
+						WorkbenchPlugin.PI_WORKBENCH, 0, message, e);
+				WorkbenchPlugin.log(message, status);
+				return false;
+			}
+		}
+
+		return true;
+	}
+
+	/**
+	 * Refresh the action enablement.
+	 */
+	private final void refreshEnablement() {
+		final IActionDelegate delegate = getDelegate();
+		final IAction action = getAction();
+		if ((delegate != null) && (action != null)) {
+			delegate.selectionChanged(action, currentSelection);
+		}
+	}
+
+	@Override
+	public void removeHandlerListener(IHandlerListener handlerListener) {
+		if (listenerList != null) {
+			listenerList.remove(handlerListener);
+
+			if (listenerList.isEmpty()) {
+				listenerList = null;
+			}
+		}
+	}
+
+	@Override
+	public void removeState(String stateId) {
+	}
+
+	private final void selectionChanged(final ISelection selection) {
+		// Update selection.
+		currentSelection = selection;
+		if (currentSelection == null) {
+			currentSelection = StructuredSelection.EMPTY;
+		}
+
+		// The selection is passed to the delegate as-is without
+		// modification. If the selection needs to be modified
+		// the action contributors should do so.
+
+		// If the delegate can be loaded, do so.
+		// Otherwise, just update the enablement.
+		final IActionDelegate delegate = getDelegate();
+		if (delegate == null && isSafeToLoadDelegate()) {
+			loadDelegate();
+		}
+		refreshEnablement();
+	}
+
+	@Override
+	public final void selectionChanged(final IWorkbenchPart part,
+			final ISelection selection) {
+		selectionChanged(selection);
+
+	}
+
+	@Override
+	public final void selectionChanged(final SelectionChangedEvent event) {
+		final ISelection selection = event.getSelection();
+		selectionChanged(selection);
+	}
+
+	@Override
+	public final String toString() {
+		final StringBuffer buffer = new StringBuffer();
+		buffer.append("ActionDelegateHandlerProxy("); //$NON-NLS-1$
+		buffer.append(getDelegate());
+		if (element != null) {
+			buffer.append(',');
+			try {
+				final String className = element
+						.getAttribute(delegateAttributeName);
+				buffer.append(className);
+				final String namespaceId = element.getNamespaceIdentifier();
+				buffer.append(" in ").append(namespaceId); //$NON-NLS-1$
+			} catch (InvalidRegistryObjectException e) {
+				buffer.append(actionId);
+			}
+		}
+		buffer.append(')');
+		return buffer.toString();
+	}
+
+	@Override
+	public void partActivated(IWorkbenchPartReference partRef) {
+	}
+
+	@Override
+	public void partBroughtToTop(IWorkbenchPartReference partRef) {
+	}
+
+	@Override
+	public void partClosed(IWorkbenchPartReference partRef) {
+		if (currentPart != null && partRef.getPart(false) == currentPart) {
+			updateActivePart(null);
+		}
+	}
+
+	@Override
+	public void partDeactivated(IWorkbenchPartReference partRef) {
+	}
+
+	@Override
+	public void partHidden(IWorkbenchPartReference partRef) {
+	}
+
+	@Override
+	public void partInputChanged(IWorkbenchPartReference partRef) {
+	}
+
+	@Override
+	public void partOpened(IWorkbenchPartReference partRef) {
+	}
+
+	@Override
+	public void partVisible(IWorkbenchPartReference partRef) {
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ActiveContextInfoHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ActiveContextInfoHandler.java
new file mode 100644
index 0000000..4106afe
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ActiveContextInfoHandler.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ ******************************************************************************/
+
+package org.eclipse.ui.internal.handlers;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.e4.ui.services.EContextService;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+public class ActiveContextInfoHandler extends AbstractHandler {
+
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		final IWorkbenchPart part = HandlerUtil.getActivePartChecked(event);
+		EContextService service = part.getSite()
+				.getService(EContextService.class);
+		for (String id : service.getActiveContextIds()) {
+			System.out.println("activeContext: " + id); //$NON-NLS-1$
+		}
+		return null;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/CloseAllPerspectivesHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/CloseAllPerspectivesHandler.java
new file mode 100644
index 0000000..50ffc83
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/CloseAllPerspectivesHandler.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal.handlers;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * Closes all the perspectives.
+ *
+ * @since 3.4
+ */
+public class CloseAllPerspectivesHandler extends AbstractHandler {
+
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindow(event);
+		if (window != null) {
+			IWorkbenchPage page = window.getActivePage();
+			if (page != null) {
+				page.closeAllPerspectives(true, true);
+			}
+		}
+		return null;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ClosePartHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ClosePartHandler.java
new file mode 100644
index 0000000..6cfd56e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ClosePartHandler.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.handlers;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * Provide a Handler for the Close Part command. This can then be bound to
+ * whatever keybinding the user prefers.
+ *
+ * @since 3.3
+ */
+public class ClosePartHandler extends AbstractHandler {
+
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		IWorkbenchPart part = HandlerUtil.getActivePartChecked(event);
+		IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindowChecked(event);
+
+		if (part instanceof IEditorPart) {
+			window.getActivePage().closeEditor((IEditorPart) part, true);
+		} else if (part instanceof IViewPart) {
+			window.getActivePage().hideView((IViewPart) part);
+		}
+
+		return null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ClosePerspectiveHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ClosePerspectiveHandler.java
new file mode 100644
index 0000000..a61f243
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ClosePerspectiveHandler.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2014 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.ui.internal.handlers;
+
+import java.util.Map;
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.eclipse.ui.internal.WorkbenchPage;
+import org.eclipse.ui.internal.e4.compatibility.E4Util;
+
+public class ClosePerspectiveHandler extends AbstractHandler {
+
+
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		IWorkbenchWindow activeWorkbenchWindow = HandlerUtil
+				.getActiveWorkbenchWindow(event);
+		if (activeWorkbenchWindow != null) {
+			WorkbenchPage page = (WorkbenchPage) activeWorkbenchWindow
+					.getActivePage();
+			if (page != null) {
+				Map parameters = event.getParameters();
+				String value = (String) parameters
+						.get(IWorkbenchCommandConstants.WINDOW_CLOSE_PERSPECTIVE_PARM_ID);
+				if (value == null) {
+					page.closePerspective(page.getPerspective(), true, true);
+				} else {
+					IPerspectiveDescriptor perspective = activeWorkbenchWindow
+							.getWorkbench().getPerspectiveRegistry()
+							.findPerspectiveWithId(value);
+					if (perspective != null) {
+						page.closePerspective(perspective, true, true);
+					}
+				}
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Closes the specified perspective. Nothing will happen if the given page
+	 * or perspective are <code>null</null>.
+	 * @param page
+	 * 		a reference to the page
+	 * @param persp
+	 * 		the perspective to close
+	 */
+	public static void closePerspective(WorkbenchPage page, Object persp) {
+		// if (page != null && persp != null) {
+		// page.closePerspective(persp.getDesc(), true, true);
+		// }
+		E4Util.unsupported("Need a better way to close the perspective"); //$NON-NLS-1$
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/CommandLegacyActionWrapper.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/CommandLegacyActionWrapper.java
new file mode 100644
index 0000000..2246440
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/CommandLegacyActionWrapper.java
@@ -0,0 +1,547 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.handlers;
+
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.CommandEvent;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.ICommandListener;
+import org.eclipse.core.commands.INamedHandleStateIds;
+import org.eclipse.core.commands.NotHandledException;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.commands.State;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.jface.action.AbstractAction;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IMenuCreator;
+import org.eclipse.jface.bindings.TriggerSequence;
+import org.eclipse.jface.bindings.keys.KeySequence;
+import org.eclipse.jface.bindings.keys.KeyStroke;
+import org.eclipse.jface.commands.RadioState;
+import org.eclipse.jface.commands.ToggleState;
+import org.eclipse.jface.menus.IMenuStateIds;
+import org.eclipse.jface.menus.TextState;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.util.Util;
+import org.eclipse.swt.events.HelpListener;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.ui.commands.ICommandImageService;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.internal.commands.CommandImageManager;
+import org.eclipse.ui.internal.commands.CommandImageService;
+import org.eclipse.ui.keys.IBindingService;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * <p>
+ * A wrapper around the new command infrastructure that imitates the old
+ * <code>IAction</code> interface.
+ * </p>
+ * <p>
+ * Clients may instantiate this class, but must not extend.
+ * </p>
+ * <p>
+ * <strong>PROVISIONAL</strong>. This class or interface has been added as
+ * part of a work in progress. There is a guarantee neither that this API will
+ * work nor that it will remain the same. Please do not use this API without
+ * consulting with the Platform/UI team.
+ * </p>
+ * <p>
+ * This class is eventually intended to exist in
+ * <code>org.eclipse.ui.handlers</code>.
+ * </p>
+ *
+ * @since 3.2
+ */
+public final class CommandLegacyActionWrapper extends AbstractAction {
+
+	/**
+	 * Listens to changes to one or more commands, and forwards them out through
+	 * the property change event mechanism.
+	 */
+	private final class CommandListener implements ICommandListener {
+		@Override
+		public final void commandChanged(final CommandEvent commandEvent) {
+			final Command baseCommand = commandEvent.getCommand();
+
+			// Check if the name changed.
+			if (commandEvent.isNameChanged()) {
+				String newName = null;
+				if (baseCommand.isDefined()) {
+					try {
+						newName = baseCommand.getName();
+					} catch (final NotDefinedException e) {
+						// Not defined, so leave as null.
+					}
+				}
+				firePropertyChange(IAction.TEXT, null, newName);
+			}
+
+			// Check if the description changed.
+			if (commandEvent.isDescriptionChanged()) {
+				String newDescription = null;
+				if (baseCommand.isDefined()) {
+					try {
+						newDescription = baseCommand.getDescription();
+					} catch (final NotDefinedException e) {
+						// Not defined, so leave as null.
+					}
+				}
+				firePropertyChange(IAction.DESCRIPTION, null, newDescription);
+				firePropertyChange(IAction.TOOL_TIP_TEXT, null, newDescription);
+			}
+
+			// Check if the handled property changed.
+			if (commandEvent.isHandledChanged()) {
+				if (baseCommand.isHandled()) {
+					firePropertyChange(IAction.HANDLED, Boolean.FALSE,
+							Boolean.TRUE);
+				} else {
+					firePropertyChange(IAction.HANDLED, Boolean.TRUE,
+							Boolean.FALSE);
+				}
+			}
+		}
+
+	}
+
+	/**
+	 * The command with which this action is associated; never <code>null</code>.
+	 */
+	private ParameterizedCommand command;
+
+	/**
+	 * Listens to changes in a command, and forwards them out through the
+	 * property change event mechanism.
+	 */
+	private final ICommandListener commandListener = new CommandListener();
+
+	/**
+	 * Whether this action has been marked as enabled.
+	 */
+	private boolean enabled = true;
+
+	/**
+	 * The identifier for the action. This may be <code>null</code>.
+	 */
+	private String id;
+
+	/**
+	 * A service locator that can be used for retrieving command-based services.
+	 * This value is never <code>null</code>.
+	 */
+	private final IServiceLocator serviceLocator;
+
+	/**
+	 * The image style to use for this action. This value may be
+	 * <code>null</code>.
+	 */
+	private final String style;
+
+	/**
+	 * Constructs a new instance of <code>ActionProxy</code>.
+	 *
+	 * @param id
+	 *            The initial action identifier; may be <code>null</code>.
+	 * @param command
+	 *            The command with which this action is associated; must not be
+	 *            <code>null</code>.
+	 * @param style
+	 *            The image style to use for this action, may be
+	 *            <code>null</code>.
+	 * @param serviceLocator
+	 *            A service locator that can be used to find various
+	 *            command-based services; must not be <code>null</code>.
+	 */
+	public CommandLegacyActionWrapper(final String id,
+			final ParameterizedCommand command, final String style,
+			final IServiceLocator serviceLocator) {
+		if (command == null) {
+			throw new NullPointerException(
+					"An action proxy can't be created without a command"); //$NON-NLS-1$
+		}
+
+		if (serviceLocator == null) {
+			throw new NullPointerException(
+					"An action proxy can't be created without a service locator"); //$NON-NLS-1$
+		}
+
+		this.command = command;
+		this.id = id;
+		this.style = style;
+		this.serviceLocator = serviceLocator;
+
+		// TODO Needs to listen to command, state, binding and image changes.
+		command.getCommand().addCommandListener(commandListener);
+	}
+
+	@Override
+	public final int getAccelerator() {
+		final String commandId = getActionDefinitionId();
+		final IBindingService bindingService = serviceLocator
+				.getService(IBindingService.class);
+		final TriggerSequence triggerSequence = bindingService
+				.getBestActiveBindingFor(commandId);
+		if (triggerSequence instanceof KeySequence) {
+			final KeySequence keySequence = (KeySequence) triggerSequence;
+			final KeyStroke[] keyStrokes = keySequence.getKeyStrokes();
+			if (keyStrokes.length == 1) {
+				final KeyStroke keyStroke = keyStrokes[0];
+				return keyStroke.getModifierKeys() | keyStroke.getNaturalKey();
+			}
+		}
+
+		return 0;
+	}
+
+	@Override
+	public final String getActionDefinitionId() {
+		return command.getId();
+	}
+
+	@Override
+	public final String getDescription() {
+		try {
+			return command.getCommand().getDescription();
+		} catch (final NotDefinedException e) {
+			return null;
+		}
+	}
+
+	@Override
+	public final ImageDescriptor getDisabledImageDescriptor() {
+		final String commandId = getActionDefinitionId();
+		final ICommandImageService commandImageService = serviceLocator
+				.getService(ICommandImageService.class);
+		return commandImageService.getImageDescriptor(commandId,
+				CommandImageManager.TYPE_DISABLED, style);
+	}
+
+	@Override
+	public final HelpListener getHelpListener() {
+		// TODO Help. Addressing help on commands.
+		return null;
+	}
+
+	@Override
+	public final ImageDescriptor getHoverImageDescriptor() {
+		final String commandId = getActionDefinitionId();
+		final ICommandImageService commandImageService = serviceLocator
+				.getService(ICommandImageService.class);
+		return commandImageService.getImageDescriptor(commandId,
+				CommandImageManager.TYPE_HOVER, style);
+	}
+
+	@Override
+	public final String getId() {
+		return id;
+	}
+
+	@Override
+	public final ImageDescriptor getImageDescriptor() {
+		final String commandId = getActionDefinitionId();
+		final ICommandImageService commandImageService = serviceLocator
+				.getService(ICommandImageService.class);
+		return commandImageService.getImageDescriptor(commandId, style);
+	}
+
+	@Override
+	public final IMenuCreator getMenuCreator() {
+		// TODO Pulldown. What kind of callback is needed here?
+		return null;
+	}
+
+	@Override
+	public final int getStyle() {
+		// TODO Pulldown. This does not currently support the pulldown style.
+		final State state = command.getCommand().getState(IMenuStateIds.STYLE);
+		if (state instanceof RadioState) {
+			return IAction.AS_RADIO_BUTTON;
+		} else if (state instanceof ToggleState) {
+			return IAction.AS_CHECK_BOX;
+		}
+
+		return IAction.AS_PUSH_BUTTON;
+	}
+
+	@Override
+	public final String getText() {
+		try {
+			return command.getName();
+		} catch (final NotDefinedException e) {
+			return null;
+		}
+	}
+
+	@Override
+	public final String getToolTipText() {
+		return getDescription();
+	}
+
+	@Override
+	public final boolean isChecked() {
+		final State state = command.getCommand().getState(IMenuStateIds.STYLE);
+		if (state instanceof ToggleState) {
+			final Boolean currentValue = (Boolean) state.getValue();
+			return currentValue.booleanValue();
+		}
+
+		return false;
+	}
+
+	@Override
+	public final boolean isEnabled() {
+		return isEnabledDisregardingCommand();
+	}
+
+	/**
+	 * Whether this action's local <code>enabled</code> property is set. This
+	 * can be used by handlers that are trying to check if
+	 * {@link #setEnabled(boolean)} has been called. This is typically used by
+	 * legacy action proxies who are trying to avoid a <a
+	 * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=117496">stack
+	 * overflow</a>.
+	 *
+	 * @return <code>false</code> if someone has called
+	 *         {@link #setEnabled(boolean)} with <code>false</code>;
+	 *         <code>true</code> otherwise.
+	 */
+	public final boolean isEnabledDisregardingCommand() {
+		return enabled;
+	}
+
+	@Override
+	public final boolean isHandled() {
+		final Command baseCommand = command.getCommand();
+		return baseCommand.isHandled();
+	}
+
+	@Override
+	public final void run() {
+		runWithEvent(null);
+	}
+
+	@Override
+	public final void runWithEvent(final Event event) {
+		final Command baseCommand = command.getCommand();
+		final ExecutionEvent executionEvent = new ExecutionEvent(command
+				.getCommand(), command.getParameterMap(), event, null);
+		try {
+			baseCommand.execute(executionEvent);
+			firePropertyChange(IAction.RESULT, null, Boolean.TRUE);
+
+		} catch (final NotHandledException e) {
+			firePropertyChange(IAction.RESULT, null, Boolean.FALSE);
+
+		} catch (final ExecutionException e) {
+			firePropertyChange(IAction.RESULT, null, Boolean.FALSE);
+			// TODO Should this be logged?
+
+		}
+	}
+
+	@Override
+	public final void setAccelerator(final int keycode) {
+		// TODO Binding. This is hopefully not essential.
+	}
+
+	@Override
+	public final void setActionDefinitionId(final String id) {
+		// Get the old values.
+		final boolean oldChecked = isChecked();
+		final String oldDescription = getDescription();
+		final boolean oldEnabled = isEnabled();
+		final boolean oldHandled = isHandled();
+		final ImageDescriptor oldDefaultImage = getImageDescriptor();
+		final ImageDescriptor oldDisabledImage = getDisabledImageDescriptor();
+		final ImageDescriptor oldHoverImage = getHoverImageDescriptor();
+		final String oldText = getText();
+
+		// Update the command.
+		final Command oldBaseCommand = command.getCommand();
+		oldBaseCommand.removeCommandListener(commandListener);
+		final ICommandService commandService = serviceLocator
+				.getService(ICommandService.class);
+		final Command newBaseCommand = commandService.getCommand(id);
+		command = new ParameterizedCommand(newBaseCommand, null);
+		newBaseCommand.addCommandListener(commandListener);
+
+		// Get the new values.
+		final boolean newChecked = isChecked();
+		final String newDescription = getDescription();
+		final boolean newEnabled = isEnabled();
+		final boolean newHandled = isHandled();
+		final ImageDescriptor newDefaultImage = getImageDescriptor();
+		final ImageDescriptor newDisabledImage = getDisabledImageDescriptor();
+		final ImageDescriptor newHoverImage = getHoverImageDescriptor();
+		final String newText = getText();
+
+		// Fire property change events, as necessary.
+		if (newChecked != oldChecked) {
+			if (oldChecked) {
+				firePropertyChange(IAction.CHECKED, Boolean.TRUE, Boolean.FALSE);
+			} else {
+				firePropertyChange(IAction.CHECKED, Boolean.FALSE, Boolean.TRUE);
+			}
+		}
+
+		if (!Util.equals(oldDescription, newDescription)) {
+			firePropertyChange(IAction.DESCRIPTION, oldDescription,
+					newDescription);
+			firePropertyChange(IAction.TOOL_TIP_TEXT, oldDescription,
+					newDescription);
+		}
+
+		if (newEnabled != oldEnabled) {
+			if (oldEnabled) {
+				firePropertyChange(IAction.ENABLED, Boolean.TRUE, Boolean.FALSE);
+			} else {
+				firePropertyChange(IAction.ENABLED, Boolean.FALSE, Boolean.TRUE);
+			}
+		}
+
+		if (newHandled != oldHandled) {
+			if (oldHandled) {
+				firePropertyChange(IAction.HANDLED, Boolean.TRUE, Boolean.FALSE);
+			} else {
+				firePropertyChange(IAction.HANDLED, Boolean.FALSE, Boolean.TRUE);
+			}
+		}
+
+		if (!Util.equals(oldDefaultImage, newDefaultImage)) {
+			firePropertyChange(IAction.IMAGE, oldDefaultImage, newDefaultImage);
+		}
+
+		if (!Util.equals(oldDisabledImage, newDisabledImage)) {
+			firePropertyChange(IAction.IMAGE, oldDisabledImage,
+					newDisabledImage);
+		}
+
+		if (!Util.equals(oldHoverImage, newHoverImage)) {
+			firePropertyChange(IAction.IMAGE, oldHoverImage, newHoverImage);
+		}
+
+		if (!Util.equals(oldText, newText)) {
+			firePropertyChange(IAction.TEXT, oldText, newText);
+		}
+	}
+
+	@Override
+	public final void setChecked(final boolean checked) {
+		final State state = command.getCommand().getState(IMenuStateIds.STYLE);
+		if (state instanceof ToggleState) {
+			final Boolean currentValue = (Boolean) state.getValue();
+			if (checked != currentValue.booleanValue()) {
+				if (checked) {
+					state.setValue(Boolean.TRUE);
+				} else {
+					state.setValue(Boolean.FALSE);
+				}
+			}
+		}
+	}
+
+	@Override
+	public final void setDescription(final String text) {
+		final State state = command.getCommand().getState(
+				INamedHandleStateIds.DESCRIPTION);
+		if (state instanceof TextState) {
+			final String currentValue = (String) state.getValue();
+			if (!Util.equals(text, currentValue)) {
+				state.setValue(text);
+			}
+		}
+	}
+
+	@Override
+	public final void setDisabledImageDescriptor(final ImageDescriptor newImage) {
+		final String commandId = getActionDefinitionId();
+		final int type = CommandImageManager.TYPE_DISABLED;
+		final ICommandImageService commandImageService = serviceLocator
+				.getService(ICommandImageService.class);
+		if (commandImageService instanceof CommandImageService) {
+			((CommandImageService) commandImageService).bind(commandId, type,
+					style, newImage);
+		}
+	}
+
+	@Override
+	public final void setEnabled(final boolean enabled) {
+		if (enabled != this.enabled) {
+			final Boolean oldValue = this.enabled ? Boolean.TRUE
+					: Boolean.FALSE;
+			final Boolean newValue = enabled ? Boolean.TRUE : Boolean.FALSE;
+			this.enabled = enabled;
+			firePropertyChange(ENABLED, oldValue, newValue);
+		}
+	}
+
+	@Override
+	public final void setHelpListener(final HelpListener listener) {
+		// TODO Help Haven't even started to look at help yet.
+
+	}
+
+	@Override
+	public final void setHoverImageDescriptor(final ImageDescriptor newImage) {
+		final String commandId = getActionDefinitionId();
+		final int type = CommandImageManager.TYPE_HOVER;
+		final ICommandImageService commandImageService = serviceLocator
+				.getService(ICommandImageService.class);
+		if (commandImageService instanceof CommandImageService) {
+			((CommandImageService) commandImageService).bind(commandId, type,
+					style, newImage);
+		}
+	}
+
+	@Override
+	public final void setId(final String id) {
+		this.id = id;
+	}
+
+	@Override
+	public final void setImageDescriptor(final ImageDescriptor newImage) {
+		final String commandId = getActionDefinitionId();
+		final int type = CommandImageManager.TYPE_DEFAULT;
+		final ICommandImageService commandImageService = serviceLocator
+				.getService(ICommandImageService.class);
+		if (commandImageService instanceof CommandImageService) {
+			((CommandImageService) commandImageService).bind(commandId, type,
+					style, newImage);
+		}
+	}
+
+	@Override
+	public final void setMenuCreator(final IMenuCreator creator) {
+		// TODO Pulldown. This is complicated
+	}
+
+	@Override
+	public final void setText(final String text) {
+		final State state = command.getCommand().getState(
+				INamedHandleStateIds.NAME);
+		if (state instanceof TextState) {
+			final String currentValue = (String) state.getValue();
+			if (!Util.equals(text, currentValue)) {
+				state.setValue(text);
+			}
+		}
+	}
+
+	@Override
+	public final void setToolTipText(final String text) {
+		setDescription(text);
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ContextMenuHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ContextMenuHandler.java
new file mode 100644
index 0000000..ebca22d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ContextMenuHandler.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2013, 2014 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.ui.internal.handlers;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.util.Geometry;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+public class ContextMenuHandler extends AbstractHandler {
+	/**
+	 * @throws ExecutionException
+	 *             {@inheritDoc}
+	 */
+	@Override
+	public Object execute(ExecutionEvent exEvent) throws ExecutionException {
+		Shell shell = HandlerUtil.getActiveShell(exEvent);
+		Display display = shell == null ? Display.getCurrent() : shell.getDisplay();
+		Control focusControl = display.getFocusControl();
+		if (focusControl != null) {
+			Point pt = display.getCursorLocation();
+			Event event = new Event();
+			event.x = pt.x;
+			event.y = pt.y;
+//			event.detail = SWT.MENU_KEYBOARD;
+			focusControl.notifyListeners(SWT.MenuDetect, event);
+			if (focusControl.isDisposed())
+				return null;
+			if (!event.doit)
+				return null;
+			Menu menu = focusControl.getMenu();
+
+			if (menu != null && !menu.isDisposed()) {
+				if (event.x != pt.x || event.y != pt.y) {
+					menu.setLocation(event.x, event.y);
+				}
+				menu.setVisible(true);
+
+			} else {
+				Point size = focusControl.getSize();
+				Point location = focusControl.toDisplay(0, 0);
+
+				Event mouseEvent = new Event();
+				mouseEvent.widget = focusControl;
+
+				if (event.x < location.x || location.x + size.x <= event.x || event.y < location.y
+						|| location.y + size.y <= event.y) {
+					Point center = focusControl.toDisplay(Geometry.divide(size, 2));
+					mouseEvent.x = center.x;
+					mouseEvent.y = center.y;
+					mouseEvent.type = SWT.MouseMove;
+//					display.post(mouseEvent);
+				} else {
+					mouseEvent.x = event.x;
+					mouseEvent.y = event.y;
+				}
+
+				mouseEvent.button = 2;
+				mouseEvent.type = SWT.MouseDown;
+//				display.post(mouseEvent);
+
+				mouseEvent.type = SWT.MouseUp;
+//				display.post(mouseEvent);
+			}
+		}
+		return null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/CyclePageHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/CyclePageHandler.java
new file mode 100644
index 0000000..767319f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/CyclePageHandler.java
@@ -0,0 +1,208 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2016 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *     Patrik Suzzi <psuzzi@gmail.com> - Bug 504091
+ ******************************************************************************/
+
+package org.eclipse.ui.internal.handlers;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.jface.util.Geometry;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.internal.FilteredTableBaseHandler;
+import org.eclipse.ui.internal.PartSite;
+import org.eclipse.ui.internal.WorkbenchPage;
+import org.eclipse.ui.part.PageSwitcher;
+import org.eclipse.ui.part.WorkbenchPart;
+
+/**
+ * Displays a dialog for cycling through pages of a view. A view may implement
+ * its pages however it wishes. As long as the view creates a
+ * {@link PageSwitcher} object, {@link CyclePageHandler} will handle the cycling
+ * of pages.
+ *
+ * @since 3.4
+ *
+ */
+public class CyclePageHandler extends FilteredTableBaseHandler {
+
+	/**
+	 *
+	 */
+	private static final String K_INDEX = "index"; //$NON-NLS-1$
+	/**
+	 * The character limit before text is truncated.
+	 */
+	private static final int TEXT_LIMIT = 65;
+	private PageSwitcher pageSwitcher;
+	private LocalResourceManager lrm;
+
+	public CyclePageHandler(PageSwitcher pageSwitcher) {
+		this.pageSwitcher = pageSwitcher;
+	}
+
+	@Override
+	protected Object getInput(WorkbenchPage page) {
+		List<FilteredTableItem> rows = new ArrayList<>();
+
+		for(int i=0; i<pageSwitcher.getPages().length; i++){
+			Object viewPage = pageSwitcher.getPages()[i];
+			FilteredTableItem item = new FilteredTableItem();
+			ImageDescriptor imageDescriptor = pageSwitcher.getImageDescriptor(viewPage);
+			if (imageDescriptor != null) {
+				if (lrm == null) {
+					lrm = new LocalResourceManager(JFaceResources.getResources());
+				}
+				item.setImage(lrm.createImage(imageDescriptor));
+			}
+			item.putData(K_INDEX, i);
+			String name = pageSwitcher.getName(viewPage);
+			if (name.length() > TEXT_LIMIT) {
+				name = name.substring(0, TEXT_LIMIT) + "..."; //$NON-NLS-1$
+			}
+			item.setText(name);
+			rows.add(item);
+		}
+		return rows;
+	}
+
+	protected void addItemz(Table table, WorkbenchPage page) {
+		for (Object availablePage : pageSwitcher.getPages()) {
+			TableItem item = null;
+			item = new TableItem(table, SWT.NONE);
+			ImageDescriptor imageDescriptor = pageSwitcher
+					.getImageDescriptor(availablePage);
+			if (imageDescriptor != null) {
+				if (lrm == null) {
+					lrm = new LocalResourceManager(JFaceResources
+							.getResources());
+				}
+				item.setImage(lrm.createImage(imageDescriptor));
+			}
+			item.setData(availablePage);
+			String name = pageSwitcher.getName(availablePage);
+			if (name.length() > TEXT_LIMIT) {
+				name = name.substring(0, TEXT_LIMIT) + "..."; //$NON-NLS-1$
+			}
+			item.setText(name);
+		}
+	}
+
+	@Override
+	protected int getCurrentItemIndex() {
+		return pageSwitcher.getCurrentPageIndex();
+	}
+
+	@Override
+	protected ParameterizedCommand getBackwardCommand() {
+		final ICommandService commandService = window
+				.getWorkbench().getService(ICommandService.class);
+		final Command command = commandService.getCommand(IWorkbenchCommandConstants.NAVIGATE_PREVIOUS_PAGE);
+		ParameterizedCommand commandF = new ParameterizedCommand(command, null);
+		return commandF;
+	}
+
+	@Override
+	protected ParameterizedCommand getForwardCommand() {
+		final ICommandService commandService = window
+				.getWorkbench().getService(ICommandService.class);
+		final Command command= commandService.getCommand(IWorkbenchCommandConstants.NAVIGATE_NEXT_PAGE);
+		ParameterizedCommand commandF = new ParameterizedCommand(command, null);
+		return commandF;
+	}
+
+	@Override
+	protected String getTableHeader(IWorkbenchPart activePart) {
+		if (activePart instanceof WorkbenchPart) {
+			return ((WorkbenchPart) activePart).getPartName();
+		}
+
+		return activePart.getTitle();
+	}
+
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		if (event.getCommand().getId().equals(IWorkbenchCommandConstants.NAVIGATE_NEXT_PAGE)) {
+			gotoDirection = true;
+		} else {
+			gotoDirection = false;
+		}
+		super.execute(event);
+		if (lrm != null) {
+			lrm.dispose();
+			lrm = null;
+		}
+		return null;
+	}
+
+	@Override
+	protected void setDialogLocation(final Shell dialog,
+			IWorkbenchPart activePart) {
+		if (dialog == null)
+			return;
+
+		// Default to center on the display
+		Point dlgAnchor = Geometry.centerPoint(dialog.getDisplay().getBounds());
+
+		// Center the dialog within the activePart's pane (if any)
+		if (activePart != null) {
+			WorkbenchPart wbPart = (WorkbenchPart) activePart;
+			PartSite site = (PartSite) wbPart.getSite();
+			Control paneCtrl = (Control) site.getModel().getWidget();
+
+			// Get the center of the view pane's control
+			Rectangle viewBounds = paneCtrl.getBounds();
+			Point vCenter = Geometry.centerPoint(viewBounds);
+
+			// Map it to the display
+			dlgAnchor = paneCtrl.getParent().toDisplay(vCenter);
+		}
+
+		// Offset the point by half the dialog size
+		Rectangle dialogBounds = dialog.getBounds();
+		dlgAnchor.x -= (dialogBounds.width / 2);
+		dlgAnchor.y -= (dialogBounds.height / 2);
+
+		dialog.setLocation(dlgAnchor);
+	}
+
+	@Override
+	public void dispose() {
+		super.dispose();
+		this.pageSwitcher = null;
+	}
+
+	@Override
+	protected void activate(IWorkbenchPage page, Object selectedItem) {
+		if (selectedItem == null) {
+			return;
+		}
+		// activate the page with the selected index
+		pageSwitcher.activatePage(((FilteredTableItem) selectedItem).getData(K_INDEX));
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/DirtyStateTracker.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/DirtyStateTracker.java
new file mode 100644
index 0000000..cc78343
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/DirtyStateTracker.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *     Andrey Loskutov <loskutov@gmx.de> - Bug 372799
+ ******************************************************************************/
+
+package org.eclipse.ui.internal.handlers;
+
+import org.eclipse.ui.IPartListener;
+import org.eclipse.ui.IPropertyListener;
+import org.eclipse.ui.ISaveablePart;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.IWindowListener;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.internal.SaveableHelper;
+import org.eclipse.ui.internal.Workbench;
+import org.eclipse.ui.services.IEvaluationService;
+
+/**
+ * @since 3.7
+ *
+ */
+public class DirtyStateTracker implements IPartListener, IWindowListener, IPropertyListener {
+
+	private final IWorkbench workbench;
+
+	public DirtyStateTracker() {
+		workbench = Workbench.getInstance();
+		workbench.addWindowListener(this);
+		IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
+		register(window);
+	}
+
+	public void update() {
+		IEvaluationService service = workbench.getService(IEvaluationService.class);
+		service.requestEvaluation(ISources.ACTIVE_PART_NAME);
+	}
+
+	private void register(IWorkbenchWindow window) {
+		if (window == null) {
+			return;
+		}
+		window.getPartService().addPartListener(this);
+	}
+
+	@Override
+	public void partActivated(IWorkbenchPart part) {
+		if (SaveableHelper.isSaveable(part)) {
+			part.addPropertyListener(this);
+		}
+	}
+
+	@Override
+	public void partBroughtToTop(IWorkbenchPart part) {
+	}
+
+	@Override
+	public void partClosed(IWorkbenchPart part) {
+		if (SaveableHelper.isSaveable(part)) {
+			part.removePropertyListener(this);
+			update();
+		}
+	}
+
+	@Override
+	public void partDeactivated(IWorkbenchPart part) {
+	}
+
+	@Override
+	public void partOpened(IWorkbenchPart part) {
+		if (SaveableHelper.isSaveable(part)) {
+			part.addPropertyListener(this);
+		}
+	}
+
+	@Override
+	public void windowActivated(IWorkbenchWindow window) {
+		register(window);
+	}
+
+	@Override
+	public void windowDeactivated(IWorkbenchWindow window) {
+	}
+
+	@Override
+	public void windowClosed(IWorkbenchWindow window) {
+		window.getPartService().removePartListener(this);
+	}
+
+	@Override
+	public void windowOpened(IWorkbenchWindow window) {
+		register(window);
+	}
+
+	@Override
+	public void propertyChanged(Object source, int propID) {
+		if (SaveableHelper.isSaveable(source) && propID == ISaveablePart.PROP_DIRTY) {
+			update();
+		}
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/DisplayHelpHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/DisplayHelpHandler.java
new file mode 100644
index 0000000..50f002e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/DisplayHelpHandler.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.handlers;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.help.IWorkbenchHelpSystem;
+
+/**
+ * Displays the help resource specified in the <code>href</code> command
+ * parameter or simply displays the help bookshelf if no parameter was passed.
+ *
+ * @since 3.2
+ */
+public final class DisplayHelpHandler extends AbstractHandler {
+
+	/**
+	 * The identifier of the command parameter for the URI to oepn.
+	 */
+	private static final String PARAM_ID_HREF = "href"; //$NON-NLS-1$
+
+	@Override
+	public final Object execute(final ExecutionEvent event) {
+		final IWorkbenchHelpSystem helpSystem = PlatformUI.getWorkbench()
+				.getHelpSystem();
+		final String href = event.getParameter(PARAM_ID_HREF);
+
+		if (href == null) {
+			helpSystem.displayHelp();
+		} else {
+			helpSystem.displayHelpResource(href);
+		}
+
+		return null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/DynamicHelpHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/DynamicHelpHandler.java
new file mode 100644
index 0000000..02666d1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/DynamicHelpHandler.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2015 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.ui.internal.handlers;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * @author Prakash G.R.
+ * @since 3.7
+ *
+ */
+public class DynamicHelpHandler extends AbstractHandler {
+
+	@Override
+	public Object execute(ExecutionEvent event) {
+
+		BusyIndicator.showWhile(null, () -> PlatformUI.getWorkbench().getHelpSystem().displayDynamicHelp());
+		return null;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/E4HandlerProxy.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/E4HandlerProxy.java
new file mode 100644
index 0000000..481a1bb
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/E4HandlerProxy.java
@@ -0,0 +1,176 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2015 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.ui.internal.handlers;
+
+import java.util.Collections;
+import java.util.Map;
+
+import javax.inject.Named;
+
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.HandlerEvent;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.core.commands.IHandler2;
+import org.eclipse.core.commands.IHandlerListener;
+import org.eclipse.core.commands.NotHandledException;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.e4.core.commands.ExpressionContext;
+import org.eclipse.e4.core.commands.internal.HandlerServiceHandler;
+import org.eclipse.e4.core.commands.internal.HandlerServiceImpl;
+import org.eclipse.e4.core.commands.internal.SetEnabled;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.di.annotations.CanExecute;
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.e4.core.di.annotations.Optional;
+import org.eclipse.e4.ui.internal.workbench.Activator;
+import org.eclipse.e4.ui.internal.workbench.Policy;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.commands.IElementUpdater;
+import org.eclipse.ui.internal.Workbench;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.menus.UIElement;
+
+/**
+ * @since 3.5
+ *
+ */
+public class E4HandlerProxy implements IHandler2, IHandlerListener, IElementUpdater {
+	public HandlerActivation activation = null;
+	private Command command;
+	private IHandler handler;
+	private boolean logExecute = true;
+	private boolean logSetEnabled = true;
+
+	public E4HandlerProxy(Command command, IHandler handler) {
+		this.command = command;
+		this.handler = handler;
+		handler.addHandlerListener(this);
+	}
+
+	@CanExecute
+	public boolean canExecute(IEclipseContext context, @Optional IEvaluationContext staticContext,
+			MApplication application) {
+		if (handler instanceof IHandler2) {
+			Object ctx = staticContext;
+			if (ctx == null) {
+				ctx = new ExpressionContext(application.getContext());
+			}
+			((IHandler2) handler).setEnabled(ctx);
+		}
+		return handler.isEnabled();
+	}
+
+	@Execute
+	public Object execute(IEclipseContext context,
+			@Optional @Named(HandlerServiceImpl.PARM_MAP) Map parms, @Optional Event trigger,
+			@Optional IEvaluationContext staticContext) throws ExecutionException,
+			NotHandledException {
+	    Activator.trace(Policy.DEBUG_CMDS, "execute " + command + " and " //$NON-NLS-1$ //$NON-NLS-2$
+	            + handler + " with: " + context, null); //$NON-NLS-1$
+		IEvaluationContext appContext = staticContext;
+		if (appContext == null) {
+			appContext = new ExpressionContext(context);
+		}
+		ExecutionEvent event = new ExecutionEvent(command, parms == null ? Collections.EMPTY_MAP
+				: parms, trigger, appContext);
+		if (handler != null && handler.isHandled()) {
+				final Object returnValue = handler.execute(event);
+				return returnValue;
+		}
+		return null;
+	}
+
+	public IHandler getHandler() {
+		return handler;
+	}
+
+	@Override
+	public void handlerChanged(HandlerEvent handlerEvent) {
+		IHandler handler = command.getHandler();
+		if (handler instanceof HandlerServiceHandler) {
+			IEclipseContext appContext = ((Workbench) PlatformUI.getWorkbench()).getApplication()
+					.getContext();
+			if (HandlerServiceImpl.lookUpHandler(appContext, command.getId()) == this) {
+				((HandlerServiceHandler) handler).fireHandlerChanged(handlerEvent);
+			}
+		}
+	}
+
+	@Override
+	public void updateElement(UIElement element, Map parameters) {
+		if (handler instanceof IElementUpdater) {
+			((IElementUpdater) handler).updateElement(element, parameters);
+		}
+	}
+
+	@SetEnabled
+	void setEnabled(IEclipseContext context, @Optional IEvaluationContext evalContext) {
+		if (evalContext == null) {
+			evalContext = new ExpressionContext(context);
+		}
+		if (handler instanceof IHandler2) {
+			((IHandler2) handler).setEnabled(evalContext);
+		}
+	}
+
+	@Override
+	public void addHandlerListener(IHandlerListener handlerListener) {
+		handler.addHandlerListener(handlerListener);
+	}
+
+	@Override
+	public void dispose() {
+		handler.dispose();
+	}
+
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		if (logExecute) {
+			logExecute = false;
+			Status status = new Status(IStatus.WARNING, "org.eclipse.ui", //$NON-NLS-1$
+					"Called handled proxy execute(*) directly" + command, new Exception()); //$NON-NLS-1$
+			WorkbenchPlugin.log(status);
+		}
+		return null;
+	}
+
+	@Override
+	public boolean isEnabled() {
+		return handler.isEnabled();
+	}
+
+	@Override
+	public boolean isHandled() {
+		return handler.isHandled();
+	}
+
+	@Override
+	public void removeHandlerListener(IHandlerListener handlerListener) {
+		handler.removeHandlerListener(handlerListener);
+	}
+
+	@Override
+	public void setEnabled(Object evaluationContext) {
+		if (logSetEnabled) {
+			logSetEnabled = false;
+			Status status = new Status(IStatus.WARNING, "org.eclipse.ui", //$NON-NLS-1$
+					"Called handled proxy setEnabled(*) directly" + command, new Exception()); //$NON-NLS-1$
+			WorkbenchPlugin.log(status);
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/EditActionSetsHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/EditActionSetsHandler.java
new file mode 100644
index 0000000..e1d465d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/EditActionSetsHandler.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal.handlers;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.eclipse.ui.internal.WorkbenchPage;
+
+/**
+ * Customize the action sets and shortcuts.
+ *
+ * @since 3.4
+ */
+public class EditActionSetsHandler extends AbstractHandler {
+
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		IWorkbenchWindow activeWorkbenchWindow = HandlerUtil
+				.getActiveWorkbenchWindow(event);
+
+		if (activeWorkbenchWindow != null) {
+			WorkbenchPage page = (WorkbenchPage) activeWorkbenchWindow
+					.getActivePage();
+			if (page != null) {
+				page.editActionSets();
+			}
+		}
+		return null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ExecutableExtensionHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ExecutableExtensionHandler.java
new file mode 100644
index 0000000..a3f43b3
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ExecutableExtensionHandler.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.handlers;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExecutableExtension;
+
+/**
+ * A handler that is intended to be defined in XML. These handlers support the
+ * concept of executable extensions, defined by Platform Core. It is okay for
+ * subclasses to never be used as executable extension. This default
+ * implementation of <code>setInitializationData</code> is only intended as a
+ * convenience for developers.
+ *
+ * @since 3.1
+ */
+public abstract class ExecutableExtensionHandler extends AbstractHandler
+        implements IExecutableExtension {
+
+    /**
+     * Initializes this handler with data provided from XML. By default, an
+     * <code>ExecutableExtensionHandler</code> will do nothing with this
+     * information. Subclasses should override if they expect parameters from
+     * XML.
+     *
+     * @param config
+     *            the configuration element used to trigger this execution. It
+     *            can be queried by the executable extension for specific
+     *            configuration properties
+     * @param propertyName
+     *            the name of an attribute of the configuration element used on
+     *            the <code>createExecutableExtension(String)</code> call.
+     *            This argument can be used in the cases where a single
+     *            configuration element is used to define multiple executable
+     *            extensions.
+     * @param data
+     *            adapter data in the form of a <code>String</code>, a
+     *            <code>Hashtable</code>, or <code>null</code>.
+     * @throws CoreException
+     *             if error(s) detected during initialization processing
+     *
+     * @see org.eclipse.core.runtime.IExecutableExtension#setInitializationData(org.eclipse.core.runtime.IConfigurationElement,
+     *      java.lang.String, java.lang.Object)
+     */
+    @Override
+	public void setInitializationData(final IConfigurationElement config,
+            final String propertyName, final Object data) throws CoreException {
+        // Do nothing, by default
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/FullScreenHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/FullScreenHandler.java
new file mode 100644
index 0000000..398ffcd
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/FullScreenHandler.java
@@ -0,0 +1,194 @@
+/*******************************************************************************
+ * Copyright (c) 2016 vogella GmbH 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:
+ * 	Simon Scholz <simon.scholz@vogella.com> - initial API and implementation;
+ * 	Patrik Suzzi <psuzzi@gmail.com> - Bug 491572, 491785, 492749
+ ******************************************************************************/
+
+package org.eclipse.ui.internal.handlers;
+
+import java.util.Arrays;
+import java.util.Optional;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.e4.core.commands.ECommandService;
+import org.eclipse.e4.ui.bindings.internal.BindingTableManager;
+import org.eclipse.e4.ui.bindings.internal.ContextSet;
+import org.eclipse.jface.bindings.Binding;
+import org.eclipse.jface.bindings.TriggerSequence;
+import org.eclipse.jface.dialogs.PopupDialog;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.contexts.IContextService;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.keys.IBindingService;
+
+/**
+ * Handler, which enables a full screen mode.
+ *
+ * @since 3.5
+ *
+ */
+public class FullScreenHandler extends AbstractHandler {
+
+	private static final String FULL_SCREEN_COMMAND_ID = "org.eclipse.ui.window.fullscreenmode"; //$NON-NLS-1$
+	private static final String FULL_SCREEN_COMMAND_DO_NOT_SHOW_INFO_AGAIN_PREF_ID = "org.eclipse.ui.window.fullscreenmode.donotshowinfoagain"; //$NON-NLS-1$
+
+	private boolean showInfoPopup;
+
+	private int timeLastEvent;
+	private FullScreenInfoPopup fullScreenInfoPopup;
+
+	@Override
+	public Object execute(ExecutionEvent event) {
+		// 493186 skips execution of duplicated event
+		if (checkDuplicatedEvent(event)) {
+			return null;
+		}
+		IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindow(event);
+		Shell shell = window.getShell();
+		IBindingService bindingService = window.getService(IBindingService.class);
+		ECommandService commandService = window.getService(ECommandService.class);
+		BindingTableManager bindingTableManager = window.getService(BindingTableManager.class);
+		IContextService bindingContextService = window.getService(IContextService.class);
+
+		showInfoPopup = !WorkbenchPlugin.getDefault().getPreferenceStore()
+				.getBoolean(FULL_SCREEN_COMMAND_DO_NOT_SHOW_INFO_AGAIN_PREF_ID);
+
+		Optional<TriggerSequence> sequence = getKeybindingSequence(bindingService, commandService, bindingTableManager,
+				bindingContextService, FULL_SCREEN_COMMAND_ID);
+
+		String keybinding = sequence.map(t -> t.format()).orElse(""); //$NON-NLS-1$
+
+		shell.setFullScreen(!shell.getFullScreen());
+
+		if (shell.getFullScreen()) {
+			String message = WorkbenchMessages.get().ToggleFullScreenMode_ActivationPopup_Description_NoKeybinding;
+			if (!keybinding.isEmpty()) {
+				message = NLS.bind(WorkbenchMessages.get().ToggleFullScreenMode_ActivationPopup_Description, keybinding);
+			}
+			if (showInfoPopup) {
+				fullScreenInfoPopup = new FullScreenInfoPopup(shell, PopupDialog.HOVER_SHELLSTYLE, true, false,
+						false, false, false, null, null, message);
+				fullScreenInfoPopup.open();
+			}
+		} else {
+			if (fullScreenInfoPopup != null) {
+				fullScreenInfoPopup.close();
+			}
+		}
+		return Status.OK_STATUS;
+	}
+
+	/**
+	 * Check if an event is duplicate, by recording and comparing the time of
+	 * the trigger event. Returns true if an event is triggered twice with an
+	 * event with the same time
+	 */
+	boolean checkDuplicatedEvent(ExecutionEvent event) {
+		if (event != null && event.getTrigger() != null && event.getTrigger() instanceof Event) {
+			int time = ((Event) event.getTrigger()).time;
+			if (time == timeLastEvent) {
+				return true;
+			}
+			timeLastEvent = time;
+		}
+		return false;
+	}
+
+	private static class FullScreenInfoPopup extends PopupDialog {
+
+		private String message;
+		private String messageDoNotShowAgain;
+
+		public FullScreenInfoPopup(Shell parent, int shellStyle, boolean takeFocusOnOpen, boolean persistSize,
+				boolean persistLocation, boolean showDialogMenu, boolean showPersistActions, String titleText,
+				String infoText, String message) {
+			super(parent, shellStyle, takeFocusOnOpen, persistSize, persistLocation, showDialogMenu, showPersistActions,
+					titleText, infoText);
+			this.message = message;
+			this.messageDoNotShowAgain = WorkbenchMessages.get().ToggleFullScreenMode_ActivationPopup_DoNotShowAgain;
+		}
+
+		@Override
+		protected Point getInitialLocation(Point initialSize) {
+			if (getShell().getParent() == null) {
+				return super.getInitialLocation(initialSize);
+			}
+			Rectangle bounds = getShell().getParent().getMonitor().getBounds();
+			GC gc = new GC(getShell().getDisplay());
+			int textExtendX = gc.textExtent(message).x;
+			gc.dispose();
+
+			return new Point(bounds.x + bounds.width / 2 - textExtendX / 2, bounds.y + bounds.height / 5);
+		}
+
+		@Override
+		protected Control createDialogArea(Composite parent) {
+			Composite composite = (Composite) super.createDialogArea(parent);
+
+			Label label = new Label(composite, SWT.NONE);
+			label.setText(message);
+			GridData gd = new GridData(GridData.BEGINNING | GridData.FILL_BOTH);
+			gd.horizontalIndent = PopupDialog.POPUP_HORIZONTALSPACING;
+			gd.verticalIndent = PopupDialog.POPUP_VERTICALSPACING;
+			label.setLayoutData(gd);
+
+			Button btnDoNotShow = new Button(composite, SWT.CHECK);
+			btnDoNotShow.setText(messageDoNotShowAgain);
+			btnDoNotShow.setSelection(WorkbenchPlugin.getDefault().getPreferenceStore()
+					.getBoolean(FULL_SCREEN_COMMAND_DO_NOT_SHOW_INFO_AGAIN_PREF_ID));
+			GridData gd2 = new GridData(GridData.BEGINNING | GridData.FILL_BOTH);
+			gd2.horizontalIndent = PopupDialog.POPUP_HORIZONTALSPACING;
+			gd2.verticalIndent = PopupDialog.POPUP_VERTICALSPACING;
+			btnDoNotShow.setLayoutData(gd2);
+
+			composite.addDisposeListener((e) -> {
+				WorkbenchPlugin.getDefault().getPreferenceStore()
+						.setValue(FULL_SCREEN_COMMAND_DO_NOT_SHOW_INFO_AGAIN_PREF_ID, btnDoNotShow.getSelection());
+			});
+
+			return composite;
+		}
+
+	}
+
+	protected Optional<TriggerSequence> getKeybindingSequence(IBindingService bindingService,
+			ECommandService eCommandService, BindingTableManager bindingTableManager, IContextService contextService,
+			String commandId) {
+		TriggerSequence triggerSequence = bindingService.getBestActiveBindingFor(commandId);
+		// FIXME Bug 491701 - [KeyBinding] get best active binding is not
+		// working
+		if (triggerSequence == null) {
+			ParameterizedCommand cmd = eCommandService.createCommand(commandId, null);
+			ContextSet contextSet = bindingTableManager
+					.createContextSet(Arrays.asList(contextService.getDefinedContexts()));
+			Binding binding = bindingTableManager.getBestSequenceFor(contextSet, cmd);
+			if (binding != null) {
+				triggerSequence = binding.getTriggerSequence();
+			}
+		}
+		return Optional.ofNullable(triggerSequence);
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/HandlerActivation.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/HandlerActivation.java
new file mode 100644
index 0000000..6f7aaec
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/HandlerActivation.java
@@ -0,0 +1,181 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2016 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
+ *     Friederike Schertel <friederike@schertel.org> - Bug 478336
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.handlers;
+
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.ui.internal.workbench.Activator;
+import org.eclipse.e4.ui.internal.workbench.Policy;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.handlers.IHandlerActivation;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.internal.services.SourcePriorityNameMapping;
+
+/**
+ * <p>
+ * A token representing the activation of a handler. This token can later be
+ * used to cancel that activation. Without this token, then handler will only
+ * become inactive if the component in which the handler was activated is
+ * destroyed.
+ * </p>
+ * <p>
+ * This caches the command id and the handler, so that they can later be
+ * identified.
+ * </p>
+ * <p>
+ * <b>Note:</b> this class has a natural ordering that is inconsistent with
+ * equals.
+ * </p>
+ *
+ * @since 3.1
+ */
+final class HandlerActivation implements IHandlerActivation {
+	IEclipseContext context;
+	private String commandId;
+	private IHandler handler;
+	E4HandlerProxy proxy;
+	private Expression activeWhen;
+	private boolean active;
+	private int sourcePriority;
+	boolean participating = true;
+
+	public HandlerActivation(IEclipseContext context, String cmdId, IHandler handler,
+			E4HandlerProxy handlerProxy, Expression expr) {
+		this.context = context;
+		this.commandId = cmdId;
+		this.handler = handler;
+		this.proxy = handlerProxy;
+		this.activeWhen = expr;
+		this.sourcePriority = SourcePriorityNameMapping.computeSourcePriority(activeWhen);
+		proxy.activation = this;
+	}
+
+	@Override
+	public void clearResult() {
+	}
+
+	@Override
+	public Expression getExpression() {
+		return activeWhen;
+	}
+
+	@Override
+	public int getSourcePriority() {
+		return sourcePriority;
+	}
+
+	@Override
+	public boolean evaluate(IEvaluationContext context) {
+		if (activeWhen == null) {
+			active = true;
+		} else {
+			try {
+				active = false;
+				active = activeWhen.evaluate(context) != EvaluationResult.FALSE;
+			} catch (CoreException e) {
+				/*
+				 * Swallow the exception. It simply means the variable is not
+				 * valid (most frequently, that the value is null or has a
+				 * complex core expression with a property tester). This kind of
+				 * information is not really useful to us, so we can just treat
+				 * it as false.
+				 */
+			    Activator.trace(Policy.DEBUG_CMDS, "Failed to calculate active", e); //$NON-NLS-1$
+			}
+		}
+		return active;
+	}
+
+	@Override
+	public void setResult(boolean result) {
+		active = result;
+	}
+
+	@Override
+	public int compareTo(Object o) {
+		HandlerActivation activation = (HandlerActivation) o;
+		int difference;
+
+		// Check the priorities
+		int thisPriority = this.getSourcePriority();
+		int thatPriority = activation.getSourcePriority();
+
+		// rogue bit problem - ISources.ACTIVE_MENU
+		int thisLsb = 0;
+		int thatLsb = 0;
+
+		if (((thisPriority & ISources.ACTIVE_MENU) | (thatPriority & ISources.ACTIVE_MENU)) != 0) {
+			thisLsb = thisPriority & 1;
+			thisPriority = (thisPriority >> 1) & 0x7fffffff;
+			thatLsb = thatPriority & 1;
+			thatPriority = (thatPriority >> 1) & 0x7fffffff;
+		}
+
+		difference = thisPriority - thatPriority;
+		if (difference != 0) {
+			return difference;
+		}
+
+		// if all of the higher bits are the same, check the
+		// difference of the LSB
+		difference = thisLsb - thatLsb;
+		if (difference != 0) {
+			return difference;
+		}
+
+		// Check depth
+		final int thisDepth = this.getDepth();
+		final int thatDepth = activation.getDepth();
+		difference = thisDepth - thatDepth;
+		return difference;
+	}
+
+	@Override
+	public void clearActive() {
+	}
+
+	@Override
+	public String getCommandId() {
+		return commandId;
+	}
+
+	@Override
+	public int getDepth() {
+		return 0;
+	}
+
+	@Override
+	public IHandler getHandler() {
+		return handler;
+	}
+
+	@Override
+	public IHandlerService getHandlerService() {
+		return (IHandlerService) context.get(IHandlerService.class.getName());
+	}
+
+	@Override
+	public boolean isActive(IEvaluationContext context) {
+		return active;
+	}
+
+	@Override
+	public String toString() {
+		return "EHA: " + active + ":" + sourcePriority + ":" + commandId + ": " + proxy //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+				+ ": " + handler + ": " + context; //$NON-NLS-1$ //$NON-NLS-2$
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/HandlerPersistence.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/HandlerPersistence.java
new file mode 100644
index 0000000..4d47919
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/HandlerPersistence.java
@@ -0,0 +1,381 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.handlers;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionDelta;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.IRegistryChangeEvent;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.handlers.IHandlerActivation;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.services.RegistryPersistence;
+import org.eclipse.ui.services.IEvaluationService;
+
+/**
+ * <p>
+ * A static class for accessing the registry.
+ * </p>
+ *
+ * @since 3.1
+ */
+public final class HandlerPersistence extends RegistryPersistence {
+
+	/**
+	 * The index of the command elements in the indexed array.
+	 *
+	 * @see HandlerPersistence#read()
+	 */
+	private static final int INDEX_COMMAND_DEFINITIONS = 0;
+
+	/**
+	 * The index of the command elements in the indexed array.
+	 *
+	 * @see HandlerPersistence#read()
+	 */
+	private static final int INDEX_HANDLER_DEFINITIONS = 1;
+
+	/**
+	 * The index of the handler submissions in the indexed array.
+	 *
+	 * @see HandlerPersistence#read()
+	 */
+	private static final int INDEX_HANDLER_SUBMISSIONS = 2;
+
+	/**
+	 * The handler activations that have come from the registry. This is used to
+	 * flush the activations when the registry is re-read. This value is never
+	 * <code>null</code>
+	 */
+	private final Collection handlerActivations = new ArrayList();
+
+	/**
+	 * The handler service with which this persistence class is associated. This
+	 * value must not be <code>null</code>.
+	 */
+	private final IHandlerService handlerService;
+
+	private IEvaluationService evaluationService;
+
+	/**
+	 * Constructs a new instance of <code>HandlerPersistence</code>.
+	 *
+	 * @param handlerService
+	 *            The handler service with which the handlers should be
+	 *            registered; must not be <code>null</code>.
+	 * @param evaluationService
+	 *            The evaluation service used by handler proxies with enabled
+	 *            when expressions
+	 */
+	HandlerPersistence(final IHandlerService handlerService,
+			IEvaluationService evaluationService) {
+		this.handlerService = handlerService;
+		this.evaluationService = evaluationService;
+	}
+
+	/**
+	 * Deactivates all of the activations made by this class, and then clears
+	 * the collection. This should be called before every read.
+	 *
+	 * @param handlerService
+	 *            The service handling the activations; must not be
+	 *            <code>null</code>.
+	 */
+	private final void clearActivations(final IHandlerService handlerService) {
+		handlerService.deactivateHandlers(handlerActivations);
+		Iterator i = handlerActivations.iterator();
+		while (i.hasNext()) {
+			IHandlerActivation activation = (IHandlerActivation) i.next();
+			if (activation.getHandler() != null) {
+				try {
+					activation.getHandler().dispose();
+				} catch (Exception e) {
+					WorkbenchPlugin.log("Failed to dispose handler for " //$NON-NLS-1$
+							+ activation.getCommandId(), e);
+				} catch (LinkageError e) {
+					WorkbenchPlugin.log("Failed to dispose handler for " //$NON-NLS-1$
+							+ activation.getCommandId(), e);
+				}
+			}
+		}
+		handlerActivations.clear();
+	}
+
+	@Override
+	public final void dispose() {
+		super.dispose();
+		clearActivations(handlerService);
+	}
+
+	@Override
+	protected final boolean isChangeImportant(final IRegistryChangeEvent event) {
+		return false;
+	}
+
+	public boolean handlersNeedUpdating(final IRegistryChangeEvent event) {
+	    /*
+         * Handlers will need to be re-read (i.e., re-verified) if any of the
+         * handler extensions change (i.e., handlers, commands), or if any of
+         * the command extensions change (i.e., action definitions).
+         */
+        // RAP [bm]: 
+//      final IExtensionDelta[] handlerDeltas = event.getExtensionDeltas(
+//              PlatformUI.PLUGIN_ID, IWorkbenchRegistryConstants.PL_HANDLERS);
+        final IExtensionDelta[] handlerDeltas = event.getExtensionDeltas(
+                PlatformUI.PLUGIN_EXTENSION_NAME_SPACE, IWorkbenchRegistryConstants.PL_HANDLERS);
+        // RAPEND: [bm] 
+        if (handlerDeltas.length == 0) {
+            // RAP [bm]: 
+//          final IExtensionDelta[] commandDeltas = event.getExtensionDeltas(
+//                  PlatformUI.PLUGIN_ID,
+//                  IWorkbenchRegistryConstants.PL_COMMANDS);
+            final IExtensionDelta[] commandDeltas = event.getExtensionDeltas(
+                    PlatformUI.PLUGIN_EXTENSION_NAME_SPACE,
+                    IWorkbenchRegistryConstants.PL_COMMANDS);
+            // RAPEND: [bm] 
+
+            if (commandDeltas.length == 0) {
+                // RAP [bm]: 
+//              final IExtensionDelta[] actionDefinitionDeltas = event
+//                      .getExtensionDeltas(
+//                              PlatformUI.PLUGIN_ID,
+//                              IWorkbenchRegistryConstants.PL_ACTION_DEFINITIONS);
+                final IExtensionDelta[] actionDefinitionDeltas = event
+                .getExtensionDeltas(
+                        PlatformUI.PLUGIN_EXTENSION_NAME_SPACE,
+                        IWorkbenchRegistryConstants.PL_ACTION_DEFINITIONS);
+                if (actionDefinitionDeltas.length == 0) {
+                    return false;
+                }
+            }
+        }
+
+		return true;
+	}
+
+	/**
+	 * Reads all of the handlers from the registry
+	 *
+	 * @param handlerService
+	 *            The handler service which should be populated with the values
+	 *            from the registry; must not be <code>null</code>.
+	 */
+	@Override
+	protected final void read() {
+		super.read();
+		reRead();
+	}
+
+	public final void reRead() {
+		// Create the extension registry mementos.
+		final IExtensionRegistry registry = Platform.getExtensionRegistry();
+		int commandDefinitionCount = 0;
+		int handlerDefinitionCount = 0;
+		int handlerSubmissionCount = 0;
+		final IConfigurationElement[][] indexedConfigurationElements = new IConfigurationElement[3][];
+
+		// Sort the commands extension point based on element name.
+		final IConfigurationElement[] commandsExtensionPoint = registry
+				.getConfigurationElementsFor(EXTENSION_COMMANDS);
+		for (final IConfigurationElement configurationElement : commandsExtensionPoint) {
+			final String name = configurationElement.getName();
+
+			// Check if it is a handler submission or a command definition.
+			if (TAG_HANDLER_SUBMISSION.equals(name)) {
+				addElementToIndexedArray(configurationElement,
+						indexedConfigurationElements,
+						INDEX_HANDLER_SUBMISSIONS, handlerSubmissionCount++);
+			} else if (TAG_COMMAND.equals(name)) {
+				addElementToIndexedArray(configurationElement,
+						indexedConfigurationElements,
+						INDEX_COMMAND_DEFINITIONS, commandDefinitionCount++);
+			}
+		}
+
+		// Sort the handler extension point based on element name.
+		final IConfigurationElement[] handlersExtensionPoint = registry
+				.getConfigurationElementsFor(EXTENSION_HANDLERS);
+		for (final IConfigurationElement configurationElement : handlersExtensionPoint) {
+			final String name = configurationElement.getName();
+
+			// Check if it is a handler submission or a command definition.
+			if (TAG_HANDLER.equals(name)) {
+				addElementToIndexedArray(configurationElement,
+						indexedConfigurationElements,
+						INDEX_HANDLER_DEFINITIONS, handlerDefinitionCount++);
+			}
+		}
+
+		clearActivations(handlerService);
+		readDefaultHandlersFromRegistry(
+				indexedConfigurationElements[INDEX_COMMAND_DEFINITIONS],
+				commandDefinitionCount);
+		readHandlerSubmissionsFromRegistry(
+				indexedConfigurationElements[INDEX_HANDLER_SUBMISSIONS],
+				handlerSubmissionCount);
+		readHandlersFromRegistry(
+				indexedConfigurationElements[INDEX_HANDLER_DEFINITIONS],
+				handlerDefinitionCount);
+	}
+
+	/**
+	 * Reads the default handlers from an array of command elements from the
+	 * commands extension point.
+	 *
+	 * @param configurationElements
+	 *            The configuration elements in the commands extension point;
+	 *            must not be <code>null</code>, but may be empty.
+	 * @param configurationElementCount
+	 *            The number of configuration elements that are really in the
+	 *            array.
+	 */
+	private final void readDefaultHandlersFromRegistry(
+			final IConfigurationElement[] configurationElements,
+			final int configurationElementCount) {
+		for (int i = 0; i < configurationElementCount; i++) {
+			final IConfigurationElement configurationElement = configurationElements[i];
+
+			/*
+			 * Read out the command identifier. This was already checked by
+			 * <code>CommandPersistence</code>, so we'll just ignore any
+			 * problems here.
+			 */
+			final String commandId = readOptional(configurationElement, ATT_ID);
+			if (commandId == null) {
+				continue;
+			}
+
+			// Check to see if we have a default handler of any kind.
+			if ((configurationElement.getAttribute(ATT_DEFAULT_HANDLER) == null)
+					&& (configurationElement.getChildren(TAG_DEFAULT_HANDLER).length == 0)) {
+				continue;
+			}
+
+			handlerActivations.add(handlerService
+					.activateHandler(commandId, new HandlerProxy(commandId,
+							configurationElement, ATT_DEFAULT_HANDLER)));
+		}
+	}
+
+	/**
+	 * Reads all of the handlers from the handlers extension point.
+	 *
+	 * @param configurationElements
+	 *            The configuration elements in the commands extension point;
+	 *            must not be <code>null</code>, but may be empty.
+	 * @param configurationElementCount
+	 *            The number of configuration elements that are really in the
+	 *            array.
+	 * @param handlerService
+	 *            The handler service to which the handlers should be added;
+	 *            must not be <code>null</code>.
+	 */
+	private final void readHandlersFromRegistry(
+			final IConfigurationElement[] configurationElements,
+			final int configurationElementCount) {
+		final List warningsToLog = new ArrayList(1);
+
+		for (int i = 0; i < configurationElementCount; i++) {
+			final IConfigurationElement configurationElement = configurationElements[i];
+
+			// Read out the command identifier.
+			final String commandId = readRequired(configurationElement,
+					ATT_COMMAND_ID, warningsToLog, "Handlers need a command id"); //$NON-NLS-1$
+			if (commandId == null) {
+				continue;
+			}
+
+			// Check to see if we have a handler class.
+			if (!checkClass(configurationElement, warningsToLog,
+					"Handlers need a class", commandId)) { //$NON-NLS-1$
+				continue;
+			}
+
+			// Get the activeWhen and enabledWhen expressions.
+			final Expression activeWhenExpression = readWhenElement(
+					configurationElement, TAG_ACTIVE_WHEN, commandId,
+					warningsToLog);
+			if (activeWhenExpression == ERROR_EXPRESSION) {
+				continue;
+			}
+			final Expression enabledWhenExpression = readWhenElement(
+					configurationElement, TAG_ENABLED_WHEN, commandId,
+					warningsToLog);
+			if (enabledWhenExpression == ERROR_EXPRESSION) {
+				continue;
+			}
+
+			final IHandler proxy = new HandlerProxy(commandId, configurationElement,
+					ATT_CLASS, enabledWhenExpression, evaluationService);
+			handlerActivations.add(handlerService.activateHandler(commandId,
+					proxy, activeWhenExpression));
+
+			// Read out the help context identifier.
+			final String helpContextId = readOptional(configurationElement,
+					ATT_HELP_CONTEXT_ID);
+			handlerService.setHelpContextId(proxy, helpContextId);
+		}
+
+		logWarnings(
+				warningsToLog,
+				"Warnings while parsing the handlers from the 'org.eclipse.ui.handlers' extension point."); //$NON-NLS-1$
+	}
+
+	/**
+	 * Reads all of the handler submissions from the commands extension point.
+	 *
+	 * @param configurationElements
+	 *            The configuration elements in the commands extension point;
+	 *            must not be <code>null</code>, but may be empty.
+	 * @param configurationElementCount
+	 *            The number of configuration elements that are really in the
+	 *            array.
+	 * @param handlerService
+	 *            The handler service to which the handlers should be added;
+	 *            must not be <code>null</code>.
+	 */
+	private final void readHandlerSubmissionsFromRegistry(
+			final IConfigurationElement[] configurationElements,
+			final int configurationElementCount) {
+		final List warningsToLog = new ArrayList(1);
+
+		for (int i = 0; i < configurationElementCount; i++) {
+			final IConfigurationElement configurationElement = configurationElements[i];
+
+			// Read out the command identifier.
+			final String commandId = readRequired(configurationElement,
+					ATT_COMMAND_ID, warningsToLog,
+					"Handler submissions need a command id"); //$NON-NLS-1$
+			if (commandId == null) {
+				continue;
+			}
+
+			handlerActivations.add(handlerService.activateHandler(commandId,
+					new LegacyHandlerWrapper(new LegacyHandlerProxy(
+							configurationElement))));
+		}
+
+		logWarnings(
+				warningsToLog,
+				"Warnings while parsing the handler submissions from the 'org.eclipse.ui.commands' extension point."); //$NON-NLS-1$
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/HandlerProxy.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/HandlerProxy.java
new file mode 100644
index 0000000..4551d3d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/HandlerProxy.java
@@ -0,0 +1,494 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.handlers;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.eclipse.core.commands.AbstractHandlerWithState;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.HandlerEvent;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.core.commands.IHandler2;
+import org.eclipse.core.commands.IHandlerListener;
+import org.eclipse.core.commands.IStateListener;
+import org.eclipse.core.commands.State;
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.commands.IElementUpdater;
+import org.eclipse.ui.handlers.RadioState;
+import org.eclipse.ui.handlers.RegistryToggleState;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.util.BundleUtility;
+import org.eclipse.ui.internal.util.Util;
+import org.eclipse.ui.menus.UIElement;
+import org.eclipse.ui.services.IEvaluationReference;
+import org.eclipse.ui.services.IEvaluationService;
+
+/**
+ * <p>
+ * A proxy for a handler that has been defined in XML. This delays the class
+ * loading until the handler is really asked for information (besides the
+ * priority or the command identifier). Asking a proxy for anything but the
+ * attributes defined publicly in this class will cause the proxy to instantiate
+ * the proxied handler.
+ * </p>
+ *
+ * @since 3.0
+ */
+public final class HandlerProxy extends AbstractHandlerWithState implements
+		IElementUpdater {
+
+	private static Map CEToProxyMap = new HashMap();
+
+	/**
+	 *
+	 */
+	private static final String PROP_ENABLED = "enabled"; //$NON-NLS-1$
+
+	/**
+	 * The configuration element from which the handler can be created. This
+	 * value will exist until the element is converted into a real class -- at
+	 * which point this value will be set to <code>null</code>.
+	 */
+	private IConfigurationElement configurationElement;
+
+	/**
+	 * The <code>enabledWhen</code> expression for the handler. Only if this
+	 * expression evaluates to <code>true</code> (or the value is
+	 * <code>null</code>) should we consult the handler.
+	 */
+	private final Expression enabledWhenExpression;
+
+	/**
+	 * The real handler. This value is <code>null</code> until the proxy is
+	 * forced to load the real handler. At this point, the configuration element
+	 * is converted, nulled out, and this handler gains a reference.
+	 */
+	private IHandler handler = null;
+
+	/**
+	 * The name of the configuration element attribute which contains the
+	 * information necessary to instantiate the real handler.
+	 */
+	private final String handlerAttributeName;
+
+	private IHandlerListener handlerListener;
+
+	/**
+	 * The evaluation service to use when evaluating
+	 * <code>enabledWhenExpression</code>. This value may be
+	 * <code>null</code> only if the <code>enabledWhenExpression</code> is
+	 * <code>null</code>.
+	 */
+	private IEvaluationService evaluationService;
+
+	private IPropertyChangeListener enablementListener;
+
+	private IEvaluationReference enablementRef;
+
+	private boolean proxyEnabled;
+
+	private String commandId;
+
+	//
+	// state to support checked or radio commands.
+	private State checkedState;
+
+	private State radioState;
+
+	// Exception that occurs while loading the proxied handler class
+	private Exception loadException;
+
+	/**
+	 * Constructs a new instance of <code>HandlerProxy</code> with all the
+	 * information it needs to try to avoid loading until it is needed.
+	 *
+	 * @param commandId the id for this handler
+	 * @param configurationElement
+	 *            The configuration element from which the real class can be
+	 *            loaded at run-time; must not be <code>null</code>.
+	 * @param handlerAttributeName
+	 *            The name of the attibute or element containing the handler
+	 *            executable extension; must not be <code>null</code>.
+	 */
+	public HandlerProxy(final String commandId, final IConfigurationElement configurationElement,
+			final String handlerAttributeName) {
+		this(commandId, configurationElement, handlerAttributeName, null, null);
+	}
+
+	/**
+	 * Constructs a new instance of <code>HandlerProxy</code> with all the
+	 * information it needs to try to avoid loading until it is needed.
+	 *
+	 * @param commandId the id for this handler
+	 * @param configurationElement
+	 *            The configuration element from which the real class can be
+	 *            loaded at run-time; must not be <code>null</code>.
+	 * @param handlerAttributeName
+	 *            The name of the attribute or element containing the handler
+	 *            executable extension; must not be <code>null</code>.
+	 * @param enabledWhenExpression
+	 *            The name of the element containing the enabledWhen expression.
+	 *            This should be a child of the
+	 *            <code>configurationElement</code>. If this value is
+	 *            <code>null</code>, then there is no enablement expression
+	 *            (i.e., enablement will be delegated to the handler when
+	 *            possible).
+	 * @param evaluationService
+	 *            The evaluation service to manage enabledWhen expressions
+	 *            trying to evaluate the <code>enabledWhenExpression</code>.
+	 *            This value may be <code>null</code> only if the
+	 *            <code>enabledWhenExpression</code> is <code>null</code>.
+	 */
+	public HandlerProxy(final String commandId,
+			final IConfigurationElement configurationElement,
+			final String handlerAttributeName,
+			final Expression enabledWhenExpression,
+			final IEvaluationService evaluationService) {
+		if (configurationElement == null) {
+			throw new NullPointerException(
+					"The configuration element backing a handler proxy cannot be null"); //$NON-NLS-1$
+		}
+
+		if (handlerAttributeName == null) {
+			throw new NullPointerException(
+					"The attribute containing the handler class must be known"); //$NON-NLS-1$
+		}
+
+		if ((enabledWhenExpression != null) && (evaluationService == null)) {
+			throw new NullPointerException(
+					"We must have a handler service and evaluation service to support the enabledWhen expression"); //$NON-NLS-1$
+		}
+
+		this.commandId = commandId;
+		this.configurationElement = configurationElement;
+		this.handlerAttributeName = handlerAttributeName;
+		this.enabledWhenExpression = enabledWhenExpression;
+		this.evaluationService = evaluationService;
+		if (enabledWhenExpression != null) {
+			setProxyEnabled(false);
+			registerEnablement();
+		} else {
+			setProxyEnabled(true);
+		}
+
+		CEToProxyMap.put(configurationElement, this);
+	}
+
+	public static void updateStaleCEs(IConfigurationElement[] replacements) {
+		for (IConfigurationElement replacement : replacements) {
+			HandlerProxy proxy = (HandlerProxy) CEToProxyMap
+					.get(replacement);
+			if (proxy != null)
+				proxy.configurationElement = replacement;
+		}
+	}
+
+	/**
+	 *
+	 */
+	private void registerEnablement() {
+		enablementRef = evaluationService.addEvaluationListener(
+				enabledWhenExpression, getEnablementListener(), PROP_ENABLED);
+	}
+
+	@Override
+	public void setEnabled(Object evaluationContext) {
+		if (!(evaluationContext instanceof IEvaluationContext)) {
+			return;
+		}
+		IEvaluationContext context = (IEvaluationContext) evaluationContext;
+		if (enabledWhenExpression != null) {
+			try {
+				setProxyEnabled(enabledWhenExpression.evaluate(context) == EvaluationResult.TRUE);
+			} catch (CoreException e) {
+				// TODO should we log this exception, or just treat it as
+				// a failure
+			}
+		}
+		if (isOkToLoad() && loadHandler()) {
+			if (handler instanceof IHandler2) {
+				((IHandler2) handler).setEnabled(evaluationContext);
+			}
+		}
+	}
+
+	void setProxyEnabled(boolean enabled) {
+		proxyEnabled = enabled;
+	}
+
+	boolean getProxyEnabled() {
+		return proxyEnabled;
+	}
+
+	private IPropertyChangeListener getEnablementListener() {
+		if (enablementListener == null) {
+			enablementListener = event -> {
+				if (event.getProperty() == PROP_ENABLED) {
+					setProxyEnabled(event.getNewValue() == null ? false
+							: ((Boolean) event.getNewValue())
+									.booleanValue());
+					fireHandlerChanged(new HandlerEvent(HandlerProxy.this,
+							true, false));
+				}
+			};
+		}
+		return enablementListener;
+	}
+
+	/**
+	 * Passes the dipose on to the proxied handler, if it has been loaded.
+	 */
+	@Override
+	public final void dispose() {
+		if (handler != null) {
+			if (handlerListener != null) {
+				handler.removeHandlerListener(handlerListener);
+				handlerListener = null;
+			}
+			handler.dispose();
+			handler = null;
+		}
+		if (enablementListener != null) {
+			evaluationService.removeEvaluationListener(enablementRef);
+			enablementRef = null;
+			enablementListener = null;
+		}
+	}
+
+	@Override
+	public final Object execute(final ExecutionEvent event)
+			throws ExecutionException {
+		if (loadHandler()) {
+			if (!isEnabled()) {
+				MessageDialog.openInformation(Util.getShellToParentOn(),
+						WorkbenchMessages.get().Information,
+						WorkbenchMessages.get().PluginAction_disabledMessage);
+				return null;
+			}
+			return handler.execute(event);
+		}
+
+		if(loadException !=null)
+			throw new ExecutionException("Exception occured when loading the handler", loadException); //$NON-NLS-1$
+
+		return null;
+	}
+
+	@Override
+	public final boolean isEnabled() {
+		if (enabledWhenExpression != null) {
+			// proxyEnabled reflects the enabledWhen clause
+			if (!getProxyEnabled()) {
+				return false;
+			}
+			if (isOkToLoad() && loadHandler()) {
+				return handler.isEnabled();
+			}
+
+			return true;
+		}
+
+		/*
+		 * There is no enabled when expression, so we just need to consult the
+		 * handler.
+		 */
+		if (isOkToLoad() && loadHandler()) {
+			return handler.isEnabled();
+		}
+		return true;
+	}
+
+	@Override
+	public final boolean isHandled() {
+		if (configurationElement != null && handler == null) {
+			return true;
+		}
+
+		if (isOkToLoad() && loadHandler()) {
+			return handler.isHandled();
+		}
+
+		return false;
+	}
+
+	/**
+	 * Loads the handler, if possible. If the handler is loaded, then the member
+	 * variables are updated accordingly.
+	 *
+	 * @return <code>true</code> if the handler is now non-null;
+	 *         <code>false</code> otherwise.
+	 */
+	private final boolean loadHandler() {
+		if (handler == null) {
+			// Load the handler.
+			try {
+				if (configurationElement != null) {
+					handler = (IHandler) configurationElement
+							.createExecutableExtension(handlerAttributeName);
+					handler.addHandlerListener(getHandlerListener());
+					setEnabled(evaluationService == null ? null
+							: evaluationService.getCurrentState());
+					refreshElements();
+					return true;
+				}
+
+			} catch (final ClassCastException e) {
+				final String message = "The proxied handler was the wrong class"; //$NON-NLS-1$
+				final IStatus status = new Status(IStatus.ERROR,
+						WorkbenchPlugin.PI_WORKBENCH, 0, message, e);
+				WorkbenchPlugin.log(message, status);
+				configurationElement = null;
+				loadException = e;
+
+			} catch (final CoreException e) {
+				final String message = "The proxied handler for '" + configurationElement.getAttribute(handlerAttributeName) //$NON-NLS-1$
+						+ "' could not be loaded"; //$NON-NLS-1$
+				IStatus status = new Status(IStatus.ERROR,
+						WorkbenchPlugin.PI_WORKBENCH, 0, message, e);
+				WorkbenchPlugin.log(message, status);
+				configurationElement = null;
+				loadException = e;
+			}
+			return false;
+		}
+
+		return true;
+	}
+
+	private IHandlerListener getHandlerListener() {
+		if (handlerListener == null) {
+			handlerListener = handlerEvent -> fireHandlerChanged(new HandlerEvent(HandlerProxy.this,
+					handlerEvent.isEnabledChanged(), handlerEvent
+							.isHandledChanged()));
+		}
+		return handlerListener;
+	}
+
+	@Override
+	public final String toString() {
+		if (handler == null) {
+			if (configurationElement != null) {
+				String configurationElementAttribute = getConfigurationElementAttribute();
+				if (configurationElementAttribute != null) {
+					return configurationElementAttribute;
+				}
+			}
+			return "HandlerProxy()"; //$NON-NLS-1$
+		}
+
+		return handler.toString();
+	}
+
+	/**
+	 * Retrives the ConfigurationElement attribute according to the
+	 * <code>handlerAttributeName</code>.
+	 *
+	 * @return the handlerAttributeName value, may be <code>null</code>.
+	 */
+	private String getConfigurationElementAttribute() {
+		String attribute = configurationElement
+				.getAttribute(handlerAttributeName);
+		if (attribute == null) {
+			for (IConfigurationElement configElement : configurationElement.getChildren(handlerAttributeName)) {
+				String childAttribute = configElement
+						.getAttribute(IWorkbenchRegistryConstants.ATT_CLASS);
+				if (childAttribute != null) {
+					return childAttribute;
+				}
+			}
+		}
+		return attribute;
+	}
+
+	private boolean isOkToLoad() {
+		if (PlatformUI.getWorkbench().isClosing())
+			return handler != null;
+
+		if (configurationElement != null && handler == null) {
+			final String bundleId = configurationElement.getContributor()
+					.getName();
+			return BundleUtility.isActive(bundleId);
+		}
+		return true;
+	}
+
+	@Override
+	public void updateElement(UIElement element, Map parameters) {
+		if (checkedState != null) {
+			Boolean value = (Boolean) checkedState.getValue();
+			element.setChecked(value.booleanValue());
+		} else if (radioState != null) {
+			String value = (String) radioState.getValue();
+			Object parameter = parameters.get(RadioState.PARAMETER_ID);
+			element.setChecked(value != null && value.equals(parameter));
+		}
+		if (handler != null && handler instanceof IElementUpdater) {
+			((IElementUpdater) handler).updateElement(element, parameters);
+		}
+	}
+
+	private void refreshElements() {
+		if (commandId == null || !(handler instanceof IElementUpdater)
+				&& (checkedState == null && radioState == null)) {
+			return;
+		}
+		ICommandService cs = PlatformUI.getWorkbench()
+				.getService(ICommandService.class);
+		cs.refreshElements(commandId, null);
+	}
+
+	@Override
+	public void handleStateChange(State state, Object oldValue) {
+		if (state.getId().equals(RegistryToggleState.STATE_ID)) {
+			checkedState = state;
+			refreshElements();
+		} else if (state.getId().equals(RadioState.STATE_ID)) {
+			radioState = state;
+			refreshElements();
+		}
+		if (handler instanceof IStateListener) {
+			((IStateListener) handler).handleStateChange(state, oldValue);
+		}
+	}
+
+	/**
+	 * @return the config element for use with the PDE framework.
+	 */
+	public IConfigurationElement getConfigurationElement() {
+		return configurationElement;
+	}
+
+	public String getAttributeName() {
+		return handlerAttributeName;
+	}
+
+	/**
+	 * @return Returns the handler.
+	 */
+	public IHandler getHandler() {
+		return handler;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/HelpContentsHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/HelpContentsHandler.java
new file mode 100644
index 0000000..676ec3d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/HelpContentsHandler.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2015 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.ui.internal.handlers;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * @author Prakash G.R.
+ * @since 3.7
+ *
+ */
+public class HelpContentsHandler extends AbstractHandler {
+
+	@Override
+	public Object execute(ExecutionEvent event) {
+
+		BusyIndicator.showWhile(null, () -> PlatformUI.getWorkbench().getHelpSystem().displayHelp());
+		return null;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/HelpSearchHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/HelpSearchHandler.java
new file mode 100644
index 0000000..0890e1a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/HelpSearchHandler.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2015 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.ui.internal.handlers;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * @author Prakash G.R.
+ * @since 3.7
+ *
+ */
+public class HelpSearchHandler extends AbstractHandler {
+
+	@Override
+	public Object execute(ExecutionEvent event) {
+
+		BusyIndicator.showWhile(null, () -> PlatformUI.getWorkbench().getHelpSystem().displaySearch());
+		return null;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/HideTrimBarsHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/HideTrimBarsHandler.java
new file mode 100644
index 0000000..4ac24b4
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/HideTrimBarsHandler.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2015 vogella GmbH 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:
+ *     Lars Vogel <Lars.Vogel@vogella.com> - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.handlers;
+
+import java.util.List;
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.e4.ui.model.application.ui.basic.MTrimBar;
+import org.eclipse.e4.ui.model.application.ui.basic.MTrimmedWindow;
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * Handler which allows to hide all trimbars. It adds a tag to the corresponding
+ * window. If triggered again, it restores the original visibility of the
+ * trimbars.
+ */
+public class HideTrimBarsHandler extends AbstractHandler {
+
+	/**
+	 *
+	 */
+	private static final String INITIAL_TRIM_VISIBILIY = "initialTrimVisibilityValue"; //$NON-NLS-1$
+	private static final String WINDOWS_WITH_MINIMIZED_TRIMBARS = "windowsWithMinimizedTrimbars"; //$NON-NLS-1$
+
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindowChecked(event);
+		MTrimmedWindow winModel = window.getService(MTrimmedWindow.class);
+		EModelService modelService = window.getService(EModelService.class);
+
+		// ensure we have everything we need
+		if ((winModel == null || modelService == null)) {
+			return null;
+
+		}
+		if (winModel.getTags().contains(WINDOWS_WITH_MINIMIZED_TRIMBARS)) {
+			winModel.getTags().remove(WINDOWS_WITH_MINIMIZED_TRIMBARS);
+			disableCodeFocus(winModel, modelService);
+		} else {
+			enableCodeFocus(winModel, modelService);
+			winModel.getTags().add(WINDOWS_WITH_MINIMIZED_TRIMBARS);
+		}
+
+		return null;
+	}
+
+	private void disableCodeFocus(MTrimmedWindow window, EModelService modelService) {
+
+		List<MTrimBar> tcList = modelService.findElements(window, null, MTrimBar.class, null);
+		for (MTrimBar tc : tcList) {
+			boolean visible = true;
+			String initialTrimVisibility = tc.getPersistedState().get(INITIAL_TRIM_VISIBILIY);
+			if (initialTrimVisibility != null && !initialTrimVisibility.isEmpty()) {
+				visible = Boolean.parseBoolean(initialTrimVisibility);
+				tc.getPersistedState().remove(INITIAL_TRIM_VISIBILIY);
+			}
+			tc.setVisible(visible);
+		}
+	}
+
+	private void enableCodeFocus(MTrimmedWindow window, EModelService modelService) {
+		List<MTrimBar> tcList = modelService.findElements(window, null, MTrimBar.class, null);
+		for (MTrimBar tc : tcList) {
+			// remember the visibility state in case some trimbars are already
+			// not visible
+			tc.getPersistedState().put(INITIAL_TRIM_VISIBILIY, String.valueOf(tc.isVisible()));
+			tc.setVisible(false);
+		}
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/IActionCommandMappingService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/IActionCommandMappingService.java
new file mode 100644
index 0000000..9ac1f96
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/IActionCommandMappingService.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.handlers;
+
+/**
+ * <p>
+ * A service which holds mappings between retarget action identifiers and
+ * command identifiers (aka: action definition ids).
+ * </p>
+ * <p>
+ * This class is not intended for use outside of the
+ * <code>org.eclipse.ui.workbench</code> plug-in.
+ * </p>
+ *
+ * @since 3.2
+ */
+public interface IActionCommandMappingService {
+
+	/**
+	 * Returns the command identifier corresponding to the given action
+	 * identifier, if any.
+	 *
+	 * @param actionId
+	 *            The identifier of the retarget action for which the command
+	 *            identifier should be retrieved; must not be <code>null</code>.
+	 * @return The identifier of the corresponding command; <code>null</code>
+	 *         if none.
+	 */
+	public String getCommandId(String actionId);
+
+	/**
+	 * Maps an action identifier to a command identifier. This is used for
+	 * retarget action, so that global action handlers can be registered with
+	 * the correct command.
+	 *
+	 * @param actionId
+	 *            The identifier of the retarget action; must not be
+	 *            <code>null</code>.
+	 * @param commandId
+	 *            The identifier of the command; must not be <code>null</code>
+	 */
+	public void map(String actionId, String commandId);
+
+	public String getGeneratedCommandId(String targetId, String actionId);
+}
+
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/IWorkbenchWindowHandlerDelegate.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/IWorkbenchWindowHandlerDelegate.java
new file mode 100644
index 0000000..76cfdde
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/IWorkbenchWindowHandlerDelegate.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.handlers;
+
+import org.eclipse.ui.IWorkbenchWindowActionDelegate;
+
+/**
+ * Allows handlers to be contributed to through action sets.
+ *
+ * @since 3.1
+ */
+public interface IWorkbenchWindowHandlerDelegate extends
+        IWorkbenchWindowActionDelegate {
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/IntroHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/IntroHandler.java
new file mode 100644
index 0000000..a656c14
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/IntroHandler.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2015 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.ui.internal.handlers;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.eclipse.ui.internal.Workbench;
+import org.eclipse.ui.internal.intro.IntroDescriptor;
+import org.eclipse.ui.internal.intro.IntroMessages;
+
+/**
+ *
+ * @author Prakash G.R.
+ *
+ * @since 3.7
+ *
+ */
+public class IntroHandler extends AbstractHandler {
+
+	private Workbench workbench;
+	private IntroDescriptor introDescriptor;
+
+	public IntroHandler() {
+		workbench = (Workbench) PlatformUI.getWorkbench();
+		introDescriptor = workbench.getIntroDescriptor();
+	}
+
+	@Override
+	public Object execute(ExecutionEvent event) {
+
+		if (introDescriptor == null) {
+				MessageDialog.openWarning(HandlerUtil.getActiveShell(event),
+						IntroMessages.Intro_missing_product_title,
+						IntroMessages.Intro_missing_product_message);
+		} else {
+				IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindow(event);
+				workbench.getIntroManager().showIntro(window, false);
+		}
+		return null;
+	}
+
+	@Override
+	public boolean isEnabled() {
+
+		boolean enabled = false;
+		IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+		if (window != null) {
+			enabled = window.getPages().length > 0;
+		}
+		return enabled;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/LegacyHandlerListenerWrapper.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/LegacyHandlerListenerWrapper.java
new file mode 100644
index 0000000..1933ff2
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/LegacyHandlerListenerWrapper.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.handlers;
+
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.ui.commands.HandlerEvent;
+import org.eclipse.ui.commands.IHandlerListener;
+import org.eclipse.ui.internal.commands.ILegacyAttributeNames;
+
+/**
+ * A wrapper so that the new handler listener can work with legacy handlers.
+ * This class is only intended for backward compatibility with Eclipse 3.0.
+ *
+ * @since 3.1
+ */
+public final class LegacyHandlerListenerWrapper implements IHandlerListener {
+
+	/**
+	 * The handler on which this listener is listening; never <code>null</code>.
+	 */
+	private final IHandler handler;
+
+	/**
+	 * The wrapped listener; never <code>null</code>.
+	 */
+	private final org.eclipse.core.commands.IHandlerListener listener;
+
+	/**
+	 * Constructs a new instance of <code>LegacyHandlerListenerWrapper</code>.
+	 *
+	 * @param listener
+	 *            The listener to wrap; must not be <code>null</code>.
+	 */
+	public LegacyHandlerListenerWrapper(final IHandler handler,
+			final org.eclipse.core.commands.IHandlerListener listener) {
+		if (handler == null) {
+			throw new NullPointerException(
+					"A listener wrapper cannot be created on a null handler"); //$NON-NLS-1$
+		}
+
+		if (listener == null) {
+			throw new NullPointerException(
+					"A listener wrapper cannot be created on a null listener"); //$NON-NLS-1$
+		}
+
+		this.handler = handler;
+		this.listener = listener;
+	}
+
+	@Override
+	public void handlerChanged(HandlerEvent event) {
+		final boolean enabledChanged = ((Boolean) event
+				.getPreviousAttributeValuesByName().get(
+						ILegacyAttributeNames.ENABLED)).booleanValue() != handler
+				.isEnabled();
+		final boolean handledChanged = ((Boolean) event
+				.getPreviousAttributeValuesByName().get(
+						ILegacyAttributeNames.HANDLED)).booleanValue() != handler
+				.isHandled();
+		listener.handlerChanged(new org.eclipse.core.commands.HandlerEvent(
+				handler, enabledChanged, handledChanged));
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/LegacyHandlerProxy.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/LegacyHandlerProxy.java
new file mode 100644
index 0000000..be1c844
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/LegacyHandlerProxy.java
@@ -0,0 +1,155 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.handlers;
+
+import java.util.Collections;
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.ui.commands.AbstractHandler;
+import org.eclipse.ui.commands.ExecutionException;
+import org.eclipse.ui.commands.IHandler;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+
+/**
+ * <p>
+ * A proxy for a handler that has been defined in XML. This delays the class
+ * loading until the handler is really asked for information (besides the
+ * priority or the command identifier). Asking a proxy for anything but the
+ * attributes defined publicly in this class will cause the proxy to instantiate
+ * the proxied handler.
+ * </p>
+ *
+ * @since 3.0
+ */
+public final class LegacyHandlerProxy extends AbstractHandler {
+
+	/**
+	 * The name of the configuration element attribute which contains the
+	 * information necessary to instantiate the real handler.
+	 */
+	private static final String HANDLER_ATTRIBUTE_NAME = "handler"; //$NON-NLS-1$
+
+	/**
+	 * The configuration element from which the handler can be created. This
+	 * value will exist until the element is converted into a real class -- at
+	 * which point this value will be set to <code>null</code>.
+	 */
+	private IConfigurationElement configurationElement;
+
+	/**
+	 * The real handler. This value is <code>null</code> until the proxy is
+	 * forced to load the real handler. At this point, the configuration element
+	 * is converted, nulled out, and this handler gains a reference.
+	 */
+	private IHandler handler;
+
+	/**
+	 * Constructs a new instance of <code>HandlerProxy</code> with all the
+	 * information it needs to try to avoid loading until it is needed.
+	 *
+	 * @param newConfigurationElement
+	 *            The configuration element from which the real class can be
+	 *            loaded at run-time.
+	 */
+	public LegacyHandlerProxy(
+			final IConfigurationElement newConfigurationElement) {
+		configurationElement = newConfigurationElement;
+		handler = null;
+	}
+
+	/**
+	 * Passes the dipose on to the proxied handler, if it has been loaded.
+	 */
+	@Override
+	public void dispose() {
+		if (handler != null) {
+			handler.dispose();
+		}
+	}
+
+	/**
+	 * @see IHandler#execute(Map)
+	 */
+	@Override
+	public Object execute(Map parameters) throws ExecutionException {
+		if (loadHandler()) {
+			return handler.execute(parameters);
+		}
+
+		return null;
+	}
+
+	/**
+	 * @see IHandler#getAttributeValuesByName()
+	 */
+	@Override
+	public Map getAttributeValuesByName() {
+		if (loadHandler()) {
+			return handler.getAttributeValuesByName();
+		} else {
+			return Collections.EMPTY_MAP;
+		}
+	}
+
+	/**
+	 * Loads the handler, if possible. If the handler is loaded, then the member
+	 * variables are updated accordingly.
+	 *
+	 * @return <code>true</code> if the handler is now non-null;
+	 *         <code>false</code> otherwise.
+	 */
+	private final boolean loadHandler() {
+		if (handler == null) {
+			// Load the handler.
+			try {
+				handler = (IHandler) configurationElement
+						.createExecutableExtension(HANDLER_ATTRIBUTE_NAME);
+				configurationElement = null;
+				return true;
+			} catch (final CoreException e) {
+				/*
+				 * TODO If it can't be instantiated, should future attempts to
+				 * instantiate be blocked?
+				 */
+				final String message = "The proxied handler for '" + configurationElement.getAttribute(HANDLER_ATTRIBUTE_NAME) //$NON-NLS-1$
+						+ "' could not be loaded"; //$NON-NLS-1$
+				IStatus status = new Status(IStatus.ERROR,
+						WorkbenchPlugin.PI_WORKBENCH, 0, message, e);
+				WorkbenchPlugin.log(message, status);
+				return false;
+			}
+		}
+
+		return true;
+	}
+
+	@Override
+	public final String toString() {
+		final StringBuffer buffer = new StringBuffer();
+
+		buffer.append("LegacyProxy("); //$NON-NLS-1$
+		if (handler == null) {
+			final String className = configurationElement
+					.getAttribute(HANDLER_ATTRIBUTE_NAME);
+			buffer.append(className);
+		} else {
+			buffer.append(handler);
+		}
+		buffer.append(')');
+
+		return buffer.toString();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/LegacyHandlerService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/LegacyHandlerService.java
new file mode 100644
index 0000000..f909f8d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/LegacyHandlerService.java
@@ -0,0 +1,693 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2016 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ *     Daniel Kruegler <daniel.kruegler@gmail.com> - Bug 487418, 494840
+ *     Friederike Schertel <friederike@schertel.org> - Bug 478336
+ ******************************************************************************/
+
+package org.eclipse.ui.internal.handlers;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.core.commands.NotEnabledException;
+import org.eclipse.core.commands.NotHandledException;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.core.expressions.ElementHandler;
+import org.eclipse.core.expressions.EvaluationContext;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.ExpressionConverter;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.e4.core.commands.ECommandService;
+import org.eclipse.e4.core.commands.EHandlerService;
+import org.eclipse.e4.core.commands.ExpressionContext;
+import org.eclipse.e4.core.commands.internal.HandlerServiceHandler;
+import org.eclipse.e4.core.commands.internal.HandlerServiceImpl;
+import org.eclipse.e4.core.commands.internal.ICommandHelpService;
+import org.eclipse.e4.core.contexts.ContextFunction;
+import org.eclipse.e4.core.contexts.EclipseContextFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.di.InjectionException;
+import org.eclipse.e4.ui.internal.workbench.Activator;
+import org.eclipse.e4.ui.internal.workbench.Policy;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.ui.ISourceProvider;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.handlers.IHandlerActivation;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.expressions.AndExpression;
+import org.eclipse.ui.internal.expressions.WorkbenchWindowExpression;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.services.EvaluationService;
+import org.eclipse.ui.services.IEvaluationService;
+import org.eclipse.ui.services.ISourceProviderService;
+
+/**
+ * @since 3.5
+ *
+ */
+public class LegacyHandlerService implements IHandlerService {
+
+	private static final String[] SELECTION_VARIABLES = { ISources.ACTIVE_CURRENT_SELECTION_NAME,
+			ISources.ACTIVE_FOCUS_CONTROL_ID_NAME, ISources.ACTIVE_FOCUS_CONTROL_NAME,
+			ISources.ACTIVE_MENU_EDITOR_INPUT_NAME, ISources.ACTIVE_MENU_NAME,
+			ISources.ACTIVE_MENU_SELECTION_NAME };
+
+	public final static String LEGACY_H_ID = "legacy::handler::"; //$NON-NLS-1$
+
+	static class HandlerSelectionFunction extends ContextFunction {
+
+		private final String commandId;
+
+		public HandlerSelectionFunction(String commandId) {
+			this.commandId = commandId;
+		}
+
+		@Override
+		public Object compute(IEclipseContext context, String contextKey) {
+
+			HashSet<HandlerActivation> activationSet = new HashSet<>();
+			IEclipseContext current = context;
+			while (current != null) {
+				@SuppressWarnings("unchecked")
+				List<HandlerActivation> handlerActivations = (List<HandlerActivation>) current
+						.getLocal(LEGACY_H_ID + commandId);
+				if (handlerActivations != null) {
+					activationSet.addAll(handlerActivations);
+				}
+				current = current.getParent();
+			}
+
+			if (activationSet.isEmpty()) {
+				return null;
+			}
+
+			HandlerActivation bestActivation = null;
+
+			ExpressionContext legacyEvalContext = new ExpressionContext(context);
+
+			HandlerActivation conflictBest = null;
+			HandlerActivation conflictOther = null;
+			for (HandlerActivation handlerActivation : activationSet) {
+				if (!handlerActivation.participating)
+					continue;
+				if (handlerActivation.evaluate(legacyEvalContext)) {
+					if (bestActivation == null) {
+						bestActivation = handlerActivation;
+					} else {
+						int comparison = bestActivation.compareTo(handlerActivation);
+						if (comparison < 0) {
+							bestActivation = handlerActivation;
+						} else if (comparison == 0) {
+							conflictBest = bestActivation;
+							conflictOther = handlerActivation;
+						}
+					}
+				}
+			}
+
+			if (bestActivation != null) {
+				if (bestActivation == conflictBest) {
+					WorkbenchPlugin.log("Conflicting handlers for " + commandId + ": {" //$NON-NLS-1$ //$NON-NLS-2$
+							+ conflictBest.getHandler() + "} vs {" //$NON-NLS-1$
+							+ conflictOther.getHandler() + "}"); //$NON-NLS-1$
+				}
+				return bestActivation.proxy;
+			}
+
+			return null;
+		}
+	}
+
+	private static IHandlerActivation systemHandlerActivation;
+
+
+
+	public static IHandlerActivation registerLegacyHandler(final IEclipseContext context,
+			String id, final String cmdId, IHandler handler, Expression activeWhen) {
+		return registerLegacyHandler(context, id, cmdId, handler, activeWhen, null, null);
+	}
+
+	private static IHandlerActivation registerLegacyHandler(final IEclipseContext context,
+			String id, final String cmdId, IHandler handler, Expression activeWhen, String helpContextId,
+			Collection<HandlerActivation> handlerActivations) {
+		ECommandService cs = (ECommandService) context.get(ECommandService.class.getName());
+		Command command = cs.getCommand(cmdId);
+		boolean handled = command.isHandled();
+		boolean enabled = command.isEnabled();
+		E4HandlerProxy handlerProxy = new E4HandlerProxy(command, handler);
+		if (helpContextId != null) {
+			setHelpContextId(handler, helpContextId, context);
+		}
+		HandlerActivation activation = new HandlerActivation(context, cmdId, handler, handlerProxy,
+				activeWhen);
+		addHandlerActivation(activation);
+		EHandlerService hs = context.get(EHandlerService.class);
+		hs.activateHandler(cmdId, new HandlerSelectionFunction(cmdId));
+		if (handlerActivations != null) {
+			handlerActivations.add(activation);
+		}
+		boolean handledChanged = handled != command.isHandled();
+		boolean enabledChanged = enabled != command.isEnabled();
+		if (handledChanged || enabledChanged) {
+			// IHandler proxy = command.getHandler();
+			// TODO do we need to fire a handler changed event?
+		}
+		return activation;
+	}
+
+	static void addHandlerActivation(HandlerActivation eActivation) {
+		@SuppressWarnings("unchecked")
+		List<HandlerActivation> handlerActivations = (List<HandlerActivation>) eActivation.context
+				.getLocal(LEGACY_H_ID
+				+ eActivation.getCommandId());
+		if (handlerActivations == null) {
+			handlerActivations = new ArrayList<>();
+		} else {
+			if (handlerActivations.contains(eActivation)) {
+				return;
+			}
+			handlerActivations = new ArrayList<>(handlerActivations);
+		}
+		handlerActivations.add(eActivation);
+		// setting this so that we trigger invalidations
+		eActivation.context.set(LEGACY_H_ID + eActivation.getCommandId(), handlerActivations);
+	}
+
+	static void removeHandlerActivation(HandlerActivation eActivation) {
+		@SuppressWarnings("unchecked")
+		List<HandlerActivation> handlerActivations = (List<HandlerActivation>) eActivation.context
+				.getLocal(LEGACY_H_ID
+				+ eActivation.getCommandId());
+		if (handlerActivations == null) {
+			handlerActivations = new ArrayList<>();
+		} else {
+			handlerActivations = new ArrayList<>(handlerActivations);
+		}
+		handlerActivations.remove(eActivation);
+		// setting this so that we trigger invalidations
+		eActivation.context.set(LEGACY_H_ID + eActivation.getCommandId(), handlerActivations);
+	}
+
+	private IEclipseContext eclipseContext;
+	private IEvaluationContext evalContext;
+	private Expression defaultExpression = null;
+
+	/**
+	 * The handler activations that have come from the registry. This is used to
+	 * flush the activations when the registry is re-read. This value is never
+	 * <code>null</code>
+	 */
+	private final Collection<HandlerActivation> handlerActivations = new ArrayList<>();
+
+	public LegacyHandlerService(IEclipseContext context) {
+		eclipseContext = context;
+		evalContext = new ExpressionContext(eclipseContext);
+		IWorkbenchWindow window = (IWorkbenchWindow) eclipseContext.get(IWorkbenchWindow.class
+				.getName());
+		if (window != null) {
+			defaultExpression = new WorkbenchWindowExpression(window);
+		}
+	}
+
+	public LegacyHandlerService(IEclipseContext context, Expression defaultExpression) {
+		eclipseContext = context;
+		evalContext = new ExpressionContext(eclipseContext);
+		this.defaultExpression = defaultExpression;
+	}
+
+	@Override
+	public void addSourceProvider(ISourceProvider provider) {
+	}
+
+	@Override
+	public void removeSourceProvider(ISourceProvider provider) {
+	}
+
+	/**
+	 * Deactivates all of the activations read from the registry, and then
+	 * clears the collection. This should be called before every read.
+	 */
+	private void clearActivations() {
+		deactivateHandlers(handlerActivations);
+		for (IHandlerActivation activation : handlerActivations) {
+			final IHandler handler = activation.getHandler();
+			if (handler != null) {
+				SafeRunner.run(new ISafeRunnable() {
+
+					@Override
+					public void run() throws Exception {
+						handler.dispose();
+					}
+
+					@Override
+					public void handleException(Throwable exception) {
+						WorkbenchPlugin.log("Failed to dispose handler for " //$NON-NLS-1$
+								+ activation.getCommandId(), exception);
+					}
+
+				});
+			}
+		}
+		handlerActivations.clear();
+	}
+
+	@Override
+	public void dispose() {
+		clearActivations();
+	}
+
+	@Override
+	public IHandlerActivation activateHandler(IHandlerActivation activation) {
+		if (activation == systemHandlerActivation) {
+			return activation;
+		}
+		HandlerActivation handlerActivation = (HandlerActivation) activation;
+		handlerActivation.participating = true;
+		addHandlerActivation(handlerActivation);
+		return activation;
+	}
+
+	@Override
+	public IHandlerActivation activateHandler(String commandId, IHandler handler) {
+		return activateHandler(commandId, handler, defaultExpression, false);
+	}
+
+	@Override
+	public IHandlerActivation activateHandler(String commandId, IHandler handler,
+			Expression expression) {
+		return activateHandler(commandId, handler, expression, false);
+	}
+
+	@Override
+	public IHandlerActivation activateHandler(String commandId, IHandler handler,
+			Expression expression, boolean global) {
+		if (global || defaultExpression == null) {
+			return registerLegacyHandler(eclipseContext, commandId, commandId, handler, expression);
+		}
+		Expression e;
+		if (expression != null) {
+			AndExpression andExpr = new AndExpression();
+			andExpr.add(expression);
+			andExpr.add(defaultExpression);
+			e = andExpr;
+		} else {
+			e = defaultExpression;
+		}
+		return registerLegacyHandler(eclipseContext, commandId, commandId, handler, e);
+	}
+
+	@Override
+	public IHandlerActivation activateHandler(String commandId, IHandler handler,
+			Expression expression, int sourcePriorities) {
+		return activateHandler(commandId, handler, expression, false);
+	}
+
+	@Override
+	public ExecutionEvent createExecutionEvent(Command command, Event event) {
+		EvaluationContext legacy = new EvaluationContext(evalContext,
+				evalContext.getDefaultVariable());
+		ExecutionEvent e = new ExecutionEvent(command, Collections.EMPTY_MAP, event, legacy);
+		return e;
+	}
+
+	@Override
+	public ExecutionEvent createExecutionEvent(ParameterizedCommand command, Event event) {
+		EvaluationContext legacy = new EvaluationContext(evalContext,
+				evalContext.getDefaultVariable());
+		ExecutionEvent e = new ExecutionEvent(command.getCommand(), command.getParameterMap(),
+				event, legacy);
+		return e;
+	}
+
+	@Override
+	public void deactivateHandler(IHandlerActivation activation) {
+		// null is not allowed, but some people put it anyway :( see bug 326406
+		if (activation != null && activation != systemHandlerActivation) {
+			HandlerActivation eActivation = (HandlerActivation) activation;
+			eActivation.participating = false;
+			removeHandlerActivation(eActivation);
+		}
+	}
+
+	@Override
+	public void deactivateHandlers(Collection activations) {
+		Object[] array = activations.toArray();
+		// set all activations to not be participating first so that they ignore
+		// the upcoming context change events
+		for (int i = 0; i < array.length; i++) {
+			((HandlerActivation) array[i]).participating = false;
+		}
+
+		for (Object element : array) {
+			deactivateHandler((IHandlerActivation) element);
+		}
+	}
+
+	@Override
+	public Object executeCommand(String commandId, Event event) throws ExecutionException,
+			NotDefinedException, NotEnabledException, NotHandledException {
+		ECommandService cs = eclipseContext.get(ECommandService.class);
+		final Command command = cs.getCommand(commandId);
+		return executeCommand(ParameterizedCommand.generateCommand(command, null), event);
+	}
+
+	@Override
+	public Object executeCommand(ParameterizedCommand command, Event event)
+			throws ExecutionException, NotDefinedException, NotEnabledException,
+			NotHandledException {
+		EHandlerService hs = eclipseContext.get(EHandlerService.class);
+		IEclipseContext staticContext = EclipseContextFactory.create();
+		if (event != null) {
+			staticContext.set(Event.class, event);
+		}
+		try {
+			final Object rc = hs.executeHandler(command, staticContext);
+			final Object obj = staticContext.get(HandlerServiceImpl.HANDLER_EXCEPTION);
+			if (obj instanceof ExecutionException) {
+				throw (ExecutionException) obj;
+			} else if (obj instanceof NotDefinedException) {
+				throw (NotDefinedException) obj;
+			} else if (obj instanceof NotEnabledException) {
+				throw (NotEnabledException) obj;
+			} else if (obj instanceof NotHandledException) {
+				throw (NotHandledException) obj;
+			} else if (obj instanceof Exception) {
+				WorkbenchPlugin.log((Exception) obj);
+			}
+			return rc;
+		} catch (InjectionException e) {
+			rethrow(e);
+			throw e;
+		} finally {
+			staticContext.dispose();
+		}
+	}
+
+	@Override
+	public Object executeCommandInContext(ParameterizedCommand command, Event event,
+			IEvaluationContext context) throws ExecutionException, NotDefinedException,
+			NotEnabledException, NotHandledException {
+		IHandler handler = command.getCommand().getHandler();
+		boolean enabled = handler.isEnabled();
+		IEclipseContext staticContext = null;
+		Object defaultVar = null;
+		if (context instanceof ExpressionContext) {
+			// create a child context so that the primary context doesn't get
+			// populated by parameters by the EHS
+			staticContext = ((ExpressionContext) context).eclipseContext.createChild();
+		} else {
+			staticContext = eclipseContext.getActiveLeaf().createChild("snapshotContext"); //$NON-NLS-1$
+			if (event != null) {
+				staticContext.set(Event.class, event);
+			}
+			staticContext.set(IEvaluationContext.class, context);
+			defaultVar = context.getDefaultVariable();
+			if (defaultVar != null && defaultVar != IEvaluationContext.UNDEFINED_VARIABLE) {
+				staticContext.set(EvaluationService.DEFAULT_VAR, defaultVar);
+			}
+		}
+		IEclipseContext lookupContext = staticContext;
+		// the IEvaluationContext snapshot is not part of our runtime
+		// IEclipseContext hierarchy. In order to work. we need the variables
+		// from the snapshot available in the static context.
+		populateSnapshot(context, staticContext);
+		EHandlerService hs = lookupContext.get(EHandlerService.class);
+		try {
+			final Object rc = hs.executeHandler(command, staticContext);
+			final Object obj = staticContext.get(HandlerServiceImpl.HANDLER_EXCEPTION);
+			if (obj instanceof ExecutionException) {
+				throw (ExecutionException) obj;
+			} else if (obj instanceof NotDefinedException) {
+				throw (NotDefinedException) obj;
+			} else if (obj instanceof NotEnabledException) {
+				throw (NotEnabledException) obj;
+			} else if (obj instanceof NotHandledException) {
+				throw (NotHandledException) obj;
+			} else if (obj instanceof Exception) {
+				WorkbenchPlugin.log((Exception) obj);
+			}
+			return rc;
+		} catch (InjectionException e) {
+			rethrow(e);
+			throw e;
+		} finally {
+			if (handler.isEnabled() != enabled && handler instanceof HandlerServiceHandler) {
+				((HandlerServiceHandler) handler).overrideEnabled(enabled);
+			}
+			staticContext.dispose();
+		}
+	}
+
+	/**
+	 * @param context
+	 * @param staticContext
+	 */
+	private void populateSnapshot(IEvaluationContext context, IEclipseContext staticContext) {
+		IEvaluationContext ctxPtr = context;
+		while (ctxPtr != null && !(ctxPtr instanceof ExpressionContext)) {
+			Map<?, ?> vars = getVariables(ctxPtr);
+			if (vars != null) {
+				Iterator<?> i = vars.entrySet().iterator();
+				while (i.hasNext()) {
+					Map.Entry<?, ?> entry = (Map.Entry<?, ?>) i.next();
+					if (staticContext.getLocal(entry.getKey().toString()) == null) {
+						staticContext.set(entry.getKey().toString(), entry.getValue());
+					}
+				}
+			}
+			ctxPtr = ctxPtr.getParent();
+		}
+	}
+
+	private Map<?, ?> getVariables(IEvaluationContext ctx) {
+		Field vars = getContextVariablesField();
+		if (vars != null) {
+			try {
+				return (Map<?, ?>) vars.get(ctx);
+			} catch (IllegalArgumentException e) {
+
+			} catch (IllegalAccessException e) {
+
+			}
+		}
+		return null;
+	}
+
+	private static Field contextFVariables = null;
+
+	private static Field getContextVariablesField() {
+		if (contextFVariables == null) {
+			try {
+				contextFVariables = EvaluationContext.class.getField("fVariables"); //$NON-NLS-1$
+				contextFVariables.setAccessible(true);
+			} catch (SecurityException e) {
+
+			} catch (NoSuchFieldException e) {
+
+			}
+		}
+		return contextFVariables;
+	}
+
+	/**
+	 * Checks the cause of the provided exception and rethrows the cause instead
+	 * if it was one of the expected exception types.
+	 */
+	private void rethrow(InjectionException e) throws ExecutionException, NotDefinedException,
+			NotEnabledException, NotHandledException {
+		Throwable cause = e.getCause();
+		if (cause instanceof ExecutionException) {
+			throw (ExecutionException) cause;
+		} else if (cause instanceof NotDefinedException) {
+			throw (NotDefinedException) cause;
+		} else if (cause instanceof NotEnabledException) {
+			throw (NotEnabledException) cause;
+		} else if (cause instanceof NotHandledException) {
+			throw (NotHandledException) cause;
+		}
+	}
+
+	@Override
+	public IEvaluationContext createContextSnapshot(boolean includeSelection) {
+		IEvaluationContext tmpContext = getCurrentState();
+		IEvaluationContext context = new EvaluationContext(null,
+				IEvaluationContext.UNDEFINED_VARIABLE);
+
+		if (includeSelection) {
+			for (String variable : SELECTION_VARIABLES) {
+				copyVariable(context, tmpContext, variable);
+			}
+		}
+
+		ISourceProviderService sp = eclipseContext.get(ISourceProviderService.class);
+		for (ISourceProvider provider : sp.getSourceProviders()) {
+			String[] names = provider.getProvidedSourceNames();
+			for (String name : names) {
+				if (!isSelectionVariable(name)) {
+					copyVariable(context, tmpContext, name);
+				}
+			}
+		}
+
+		return context;
+	}
+
+	private boolean isSelectionVariable(String name) {
+		for (String variable : SELECTION_VARIABLES) {
+			if (variable.equals(name)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	private void copyVariable(IEvaluationContext context, IEvaluationContext tmpContext, String var) {
+		Object o = tmpContext.getVariable(var);
+		if (o != null) {
+			context.addVariable(var, o);
+		}
+	}
+
+	@Override
+	public IEvaluationContext getCurrentState() {
+		return new EvaluationContext(evalContext, evalContext.getDefaultVariable());
+	}
+
+	@Override
+	public void readRegistry() {
+		clearActivations();
+		readDefaultHandlers();
+		readHandlers();
+	}
+
+	private void readHandlers() {
+		IExtensionRegistry registry = (IExtensionRegistry) eclipseContext
+				.get(IExtensionRegistry.class.getName());
+		IExtensionPoint extPoint = registry
+				.getExtensionPoint(IWorkbenchRegistryConstants.EXTENSION_HANDLERS);
+		IConfigurationElement[] elements = extPoint.getConfigurationElements();
+		for (IConfigurationElement configElement : elements) {
+			String commandId = configElement
+					.getAttribute(IWorkbenchRegistryConstants.ATT_COMMAND_ID);
+			if (commandId == null || commandId.length() == 0) {
+				continue;
+			}
+			String defaultHandler = configElement
+					.getAttribute(IWorkbenchRegistryConstants.ATT_CLASS);
+			if ((defaultHandler == null)
+					&& (configElement.getChildren(IWorkbenchRegistryConstants.TAG_CLASS).length == 0)) {
+				continue;
+			}
+			Expression activeWhen = null;
+			final IConfigurationElement[] awChildren = configElement
+					.getChildren(IWorkbenchRegistryConstants.TAG_ACTIVE_WHEN);
+			if (awChildren.length > 0) {
+				final IConfigurationElement[] subChildren = awChildren[0].getChildren();
+				if (subChildren.length != 1) {
+				    Activator.trace(Policy.DEBUG_CMDS,
+				            "Incorrect activeWhen element " + commandId, null); //$NON-NLS-1$
+					continue;
+				}
+				final ElementHandler elementHandler = ElementHandler.getDefault();
+				final ExpressionConverter converter = ExpressionConverter.getDefault();
+				try {
+					activeWhen = elementHandler.create(converter, subChildren[0]);
+				} catch (CoreException e) {
+				    Activator.trace(Policy.DEBUG_CMDS,
+							"Incorrect activeWhen element " + commandId, e); //$NON-NLS-1$
+				}
+			}
+			Expression enabledWhen = null;
+			final IConfigurationElement[] ewChildren = configElement
+					.getChildren(IWorkbenchRegistryConstants.TAG_ENABLED_WHEN);
+			if (ewChildren.length > 0) {
+				final IConfigurationElement[] subChildren = ewChildren[0].getChildren();
+				if (subChildren.length != 1) {
+				    Activator.trace(Policy.DEBUG_CMDS,
+							"Incorrect enableWhen element " + commandId, null); //$NON-NLS-1$
+					continue;
+				}
+				final ElementHandler elementHandler = ElementHandler.getDefault();
+				final ExpressionConverter converter = ExpressionConverter.getDefault();
+				try {
+					enabledWhen = elementHandler.create(converter, subChildren[0]);
+				} catch (CoreException e) {
+				    Activator.trace(Policy.DEBUG_CMDS,
+							"Incorrect enableWhen element " + commandId, e); //$NON-NLS-1$
+				}
+			}
+			registerLegacyHandler(
+					eclipseContext,
+					commandId,
+					commandId,
+					new org.eclipse.ui.internal.handlers.HandlerProxy(commandId, configElement,
+							IWorkbenchRegistryConstants.ATT_CLASS, enabledWhen, eclipseContext
+									.get(IEvaluationService.class)), activeWhen,
+					configElement.getAttribute(IWorkbenchRegistryConstants.ATT_HELP_CONTEXT_ID), handlerActivations);
+		}
+	}
+
+	private void readDefaultHandlers() {
+		IExtensionRegistry registry = (IExtensionRegistry) eclipseContext
+				.get(IExtensionRegistry.class.getName());
+		IExtensionPoint extPoint = registry
+				.getExtensionPoint(IWorkbenchRegistryConstants.EXTENSION_COMMANDS);
+		IConfigurationElement[] elements = extPoint.getConfigurationElements();
+		for (IConfigurationElement configElement : elements) {
+			String id = configElement.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+			if (id == null || id.length() == 0) {
+				continue;
+			}
+			String defaultHandler = configElement
+					.getAttribute(IWorkbenchRegistryConstants.ATT_DEFAULT_HANDLER);
+			if ((defaultHandler == null)
+					&& (configElement.getChildren(IWorkbenchRegistryConstants.TAG_DEFAULT_HANDLER).length == 0)) {
+				continue;
+			}
+			registerLegacyHandler(eclipseContext, id, id,
+					new org.eclipse.ui.internal.handlers.HandlerProxy(id, configElement,
+							IWorkbenchRegistryConstants.ATT_DEFAULT_HANDLER),
+					null, null, handlerActivations);
+
+		}
+	}
+
+	@Override
+	public void setHelpContextId(IHandler handler, String helpContextId) {
+		setHelpContextId(handler, helpContextId, eclipseContext);
+	}
+
+	private static void setHelpContextId(IHandler handler, String helpContextId,
+			IEclipseContext eclipseContext) {
+		ICommandHelpService commandHelpService = (ICommandHelpService) eclipseContext
+				.get(ICommandHelpService.class.getName());
+		commandHelpService.setHelpContextId(handler, helpContextId);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/LegacyHandlerWrapper.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/LegacyHandlerWrapper.java
new file mode 100644
index 0000000..e571acb
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/LegacyHandlerWrapper.java
@@ -0,0 +1,148 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.handlers;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.core.commands.IHandlerListener;
+import org.eclipse.core.commands.util.Tracing;
+import org.eclipse.ui.internal.commands.ILegacyAttributeNames;
+import org.eclipse.ui.internal.misc.Policy;
+
+/**
+ * A handler that wraps a legacy handler. This provide backward compatibility
+ * with the handlers release in Eclipse 3.0.
+ *
+ * @since 3.1
+ */
+public final class LegacyHandlerWrapper implements IHandler {
+
+	/**
+	 * This flag can be set to <code>true</code> if commands should print
+	 * information to <code>System.out</code> when changing handlers.
+	 */
+	private static final boolean DEBUG_HANDLERS = Policy.DEBUG_HANDLERS
+			&& Policy.DEBUG_HANDLERS_VERBOSE;
+
+	/**
+	 * The wrapped handler; never <code>null</code>.
+	 */
+	private final org.eclipse.ui.commands.IHandler handler;
+
+	/**
+	 * Constructs a new instance of <code>HandlerWrapper</code>.
+	 *
+	 * @param handler
+	 *            The handler that should be wrapped; must not be
+	 *            <code>null</code>.
+	 */
+	public LegacyHandlerWrapper(final org.eclipse.ui.commands.IHandler handler) {
+		if (handler == null) {
+			throw new NullPointerException(
+					"A handler wrapper cannot be constructed on a null handler"); //$NON-NLS-1$
+		}
+
+		this.handler = handler;
+	}
+
+	@Override
+	public final void addHandlerListener(final IHandlerListener handlerListener) {
+		handler.addHandlerListener(new LegacyHandlerListenerWrapper(this,
+				handlerListener));
+	}
+
+	@Override
+	public final void dispose() {
+		handler.dispose();
+	}
+
+	@Override
+	public final boolean equals(final Object object) {
+		if (object instanceof org.eclipse.ui.commands.IHandler) {
+			return this.handler == object;
+		}
+
+		if (object instanceof LegacyHandlerWrapper) {
+			return this.handler == ((LegacyHandlerWrapper) object).handler;
+		}
+
+		return false;
+	}
+
+	@Override
+	public final Object execute(final ExecutionEvent event)
+			throws ExecutionException {
+		// Debugging output
+		if (DEBUG_HANDLERS) {
+			final StringBuffer buffer = new StringBuffer("Executing LegacyHandlerWrapper for "); //$NON-NLS-1$
+			if (handler == null) {
+				buffer.append("no handler"); //$NON-NLS-1$
+			} else {
+				buffer.append('\'');
+				buffer.append(handler.getClass().getName());
+				buffer.append('\'');
+			}
+			Tracing.printTrace("HANDLERS", buffer.toString()); //$NON-NLS-1$
+		}
+
+		try {
+			return handler.execute(event.getParameters());
+		} catch (final org.eclipse.ui.commands.ExecutionException e) {
+			throw new ExecutionException(e.getMessage(), e.getCause());
+		}
+	}
+
+	@Override
+	public final int hashCode() {
+		return this.handler.hashCode();
+	}
+
+	@Override
+	public final boolean isEnabled() {
+		final Object enabled = handler.getAttributeValuesByName().get(
+				ILegacyAttributeNames.ENABLED);
+		if (enabled instanceof Boolean) {
+			return ((Boolean) enabled).booleanValue();
+		}
+
+		return true;
+	}
+
+	@Override
+	public final boolean isHandled() {
+		final Object handled = handler.getAttributeValuesByName().get(
+				ILegacyAttributeNames.HANDLED);
+		if (handled instanceof Boolean) {
+			return ((Boolean) handled).booleanValue();
+		}
+
+		return true;
+	}
+
+	@Override
+	public final void removeHandlerListener(
+			final IHandlerListener handlerListener) {
+		handler.removeHandlerListener(new LegacyHandlerListenerWrapper(this,
+				handlerListener));
+	}
+
+	@Override
+	public final String toString() {
+		final StringBuffer buffer = new StringBuffer();
+
+		buffer.append("LegacyHandlerWrapper("); //$NON-NLS-1$
+		buffer.append(handler);
+		buffer.append(')');
+
+		return buffer.toString();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/LockToolBarHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/LockToolBarHandler.java
new file mode 100644
index 0000000..fb174ca
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/LockToolBarHandler.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *     Patrik Suzzi <psuzzi@gmail.com> - Bug 409633
+ *******************************************************************************/
+package org.eclipse.ui.internal.handlers;
+
+import java.util.List;
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.e4.ui.model.application.ui.basic.MTrimmedWindow;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolBar;
+import org.eclipse.e4.ui.workbench.IPresentationEngine;
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+import org.eclipse.jface.action.ICoolBarManager;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.eclipse.ui.internal.WorkbenchWindow;
+
+/**
+ *
+ * @author Prakash G.R.
+ *
+ * @since 3.7
+ *
+ */
+public class LockToolBarHandler extends AbstractHandler {
+
+	private static final String TOOLBAR_SEPARATOR = "toolbarSeparator"; //$NON-NLS-1$
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+
+		WorkbenchWindow window = (WorkbenchWindow) HandlerUtil.getActiveWorkbenchWindowChecked(event);
+		MTrimmedWindow winModel = window.getService(MTrimmedWindow.class);
+		EModelService modelService = window.getService(EModelService.class);
+
+		if (window != null) {
+			ICoolBarManager coolBarManager = window.getCoolBarManager2();
+			if (coolBarManager != null) {
+				// lock is the opposite of the original value before toggle
+				boolean lock = !HandlerUtil.toggleCommandState(event.getCommand());
+				final List<MToolBar> children = modelService.findElements(winModel, null, MToolBar.class, null);
+				for (MToolBar el : children) {
+					if (!el.getTags().contains(TOOLBAR_SEPARATOR)) {
+						if (lock) {
+							// locks the toolbars
+							if (!el.getTags().contains(IPresentationEngine.NO_MOVE)) {
+								el.getTags().add(IPresentationEngine.NO_MOVE);
+							}
+							if (el.getTags().contains(IPresentationEngine.DRAGGABLE)) {
+								el.getTags().remove(IPresentationEngine.DRAGGABLE);
+							}
+						} else {
+							// unlocks the toolbars
+							if (el.getTags().contains(IPresentationEngine.NO_MOVE)) {
+								el.getTags().remove(IPresentationEngine.NO_MOVE);
+							}
+							if (!el.getTags().contains(IPresentationEngine.DRAGGABLE)) {
+								el.getTags().add(IPresentationEngine.DRAGGABLE);
+							}
+						}
+						// Force the render, and then the call of frameMeIfPossible.
+						el.setToBeRendered(false);
+						el.setToBeRendered(true);
+					}
+				}
+			}
+		}
+		return null;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/MaximizePartHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/MaximizePartHandler.java
new file mode 100644
index 0000000..0f50591
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/MaximizePartHandler.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal.handlers;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPartReference;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * @since 3.4
+ *
+ */
+public class MaximizePartHandler extends AbstractHandler {
+
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		IWorkbenchWindow activeWorkbenchWindow = HandlerUtil.getActiveWorkbenchWindow(event);
+		if (activeWorkbenchWindow != null) {
+			IWorkbenchPage page = activeWorkbenchWindow.getActivePage();
+			if (page != null) {
+				IWorkbenchPartReference partRef = page.getActivePartReference();
+				if (partRef != null) {
+					page.toggleZoom(partRef);
+				}
+			}
+		}
+
+		return null;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/MinimizePartHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/MinimizePartHandler.java
new file mode 100644
index 0000000..e24eeb9
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/MinimizePartHandler.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 440136
+ ******************************************************************************/
+
+package org.eclipse.ui.internal.handlers;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPartReference;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * @since 3.4
+ *
+ */
+public class MinimizePartHandler extends AbstractHandler {
+
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		IWorkbenchWindow activeWorkbenchWindow = HandlerUtil
+				.getActiveWorkbenchWindow(event);
+		if (activeWorkbenchWindow != null) {
+			IWorkbenchPage page = activeWorkbenchWindow.getActivePage();
+			if (page != null) {
+				IWorkbenchPartReference partRef = page.getActivePartReference();
+				if (partRef != null) {
+					page.setPartState(partRef, IWorkbenchPage.STATE_MINIMIZED);
+				}
+			}
+		}
+		return null;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/NewEditorHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/NewEditorHandler.java
new file mode 100644
index 0000000..b87dc66
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/NewEditorHandler.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal.handlers;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IPersistableEditor;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.XMLMemento;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.eclipse.ui.internal.IWorkbenchConstants;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPage;
+import org.eclipse.ui.internal.dialogs.DialogUtil;
+
+/**
+ * Open a new editor on the active editor's input.
+ *
+ * @since 3.4
+ *
+ */
+public class NewEditorHandler extends AbstractHandler {
+
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		IWorkbenchWindow activeWorkbenchWindow = HandlerUtil
+				.getActiveWorkbenchWindow(event);
+		IWorkbenchPage page = activeWorkbenchWindow.getActivePage();
+		if (page == null) {
+			return null;
+		}
+		IEditorPart editor = page.getActiveEditor();
+		if (editor == null) {
+			return null;
+		}
+		String editorId = editor.getSite().getId();
+		if (editorId == null) {
+			return null;
+		}
+		try {
+			if (editor instanceof IPersistableEditor) {
+				XMLMemento editorState = XMLMemento
+						.createWriteRoot(IWorkbenchConstants.TAG_EDITOR_STATE);
+				((IPersistableEditor) editor).saveState(editorState);
+				((WorkbenchPage) page).openEditor(editor.getEditorInput(),
+ editorId, true,
+						IWorkbenchPage.MATCH_NONE, editorState, true);
+			} else {
+				page.openEditor(editor.getEditorInput(), editorId, true,
+						IWorkbenchPage.MATCH_NONE);
+			}
+		} catch (PartInitException e) {
+			DialogUtil.openError(activeWorkbenchWindow.getShell(),
+					WorkbenchMessages.get().Error, e.getMessage(), e);
+		}
+		return null;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/OpenInNewWindowHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/OpenInNewWindowHandler.java
new file mode 100644
index 0000000..04fdf0b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/OpenInNewWindowHandler.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2015 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.ui.internal.handlers;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.WorkbenchException;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.eclipse.ui.internal.Workbench;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+/**
+ * @since 3.4
+ *
+ */
+public class OpenInNewWindowHandler extends AbstractHandler {
+
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		IWorkbenchWindow activeWorkbenchWindow = HandlerUtil
+				.getActiveWorkbenchWindow(event);
+		if (activeWorkbenchWindow == null) {
+			return null;
+		}
+		try {
+			String perspId = null;
+
+			IWorkbenchPage page = activeWorkbenchWindow.getActivePage();
+			IAdaptable pageInput = ((Workbench) activeWorkbenchWindow
+					.getWorkbench()).getDefaultPageInput();
+			if (page != null && page.getPerspective() != null) {
+				perspId = page.getPerspective().getId();
+				pageInput = page.getInput();
+			} else {
+				perspId = activeWorkbenchWindow.getWorkbench()
+						.getPerspectiveRegistry().getDefaultPerspective();
+			}
+
+			activeWorkbenchWindow.getWorkbench().openWorkbenchWindow(perspId,
+					pageInput);
+		} catch (WorkbenchException e) {
+			StatusUtil.handleStatus(e.getStatus(),
+					WorkbenchMessages.get().OpenInNewWindowAction_errorTitle
+							+ ": " + e.getMessage(), //$NON-NLS-1$
+					StatusManager.SHOW);
+		}
+		return null;
+
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/PinEditorHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/PinEditorHandler.java
new file mode 100644
index 0000000..74ea5c0
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/PinEditorHandler.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ ******************************************************************************/
+
+package org.eclipse.ui.internal.handlers;
+
+import java.util.Map;
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPartReference;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.commands.IElementUpdater;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.eclipse.ui.internal.WorkbenchPartReference;
+import org.eclipse.ui.menus.UIElement;
+
+/**
+ * Replacement for the PinEditorAction.
+ *
+ */
+public class PinEditorHandler extends AbstractHandler implements
+		IElementUpdater {
+
+	@Override
+	public Object execute(ExecutionEvent event) {
+		IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindow(event);
+		if (window == null) {
+			return null;
+		}
+		IEditorPart editor = HandlerUtil.getActiveEditor(event);
+		if (editor == null) {
+			return null;
+		}
+		IWorkbenchPartReference ref = window.getActivePage().getReference(
+				editor);
+		if (ref instanceof WorkbenchPartReference) {
+			WorkbenchPartReference concreteRef = (WorkbenchPartReference) ref;
+
+			concreteRef.setPinned(!concreteRef.isPinned());
+			ICommandService commandService = window
+					.getService(ICommandService.class);
+			commandService.refreshElements(event.getCommand().getId(), null);
+		}
+		return null;
+	}
+
+	@Override
+	public void updateElement(UIElement element, Map parameters) {
+		IWorkbenchWindow window = element
+				.getServiceLocator().getService(IWorkbenchWindow.class);
+		if (window == null) {
+			return;
+		}
+		IWorkbenchPage page = window.getActivePage();
+		if (page == null) {
+			return;
+		}
+		IEditorPart editor = page.getActiveEditor();
+		if (editor == null) {
+			return;
+		}
+		IWorkbenchPartReference ref = page.getReference(
+				editor);
+		if (ref instanceof WorkbenchPartReference) {
+			WorkbenchPartReference concreteRef = (WorkbenchPartReference) ref;
+			element.setChecked(concreteRef.isPinned());
+		}
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/PropertyDialogHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/PropertyDialogHandler.java
new file mode 100644
index 0000000..32a4756
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/PropertyDialogHandler.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal.handlers;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.preference.PreferenceDialog;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.eclipse.ui.internal.dialogs.PropertyDialog;
+
+/**
+ * @since 3.4
+ *
+ */
+public class PropertyDialogHandler extends AbstractHandler {
+
+	private String initialPageId = null;
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		PreferenceDialog dialog;
+		Object element = null;
+		ISelection currentSelection = HandlerUtil.getCurrentSelection(event);
+		IWorkbenchWindow activeWorkbenchWindow = HandlerUtil.getActiveWorkbenchWindow(event);
+		Shell shell;
+
+		if (currentSelection instanceof IStructuredSelection) {
+			element = ((IStructuredSelection) currentSelection)
+					.getFirstElement();
+		} else {
+			return null;
+		}
+
+		if (activeWorkbenchWindow != null){
+			shell = activeWorkbenchWindow.getShell();
+			dialog = PropertyDialog.createDialogOn(shell,
+					initialPageId, element);
+			if (dialog != null) {
+				dialog.open();
+			}
+		}
+		return null;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/QuickMenuHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/QuickMenuHandler.java
new file mode 100644
index 0000000..e2ad083
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/QuickMenuHandler.java
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ ******************************************************************************/
+
+package org.eclipse.ui.internal.handlers;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.action.ContributionManager;
+import org.eclipse.jface.action.IMenuListener2;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.QuickMenuCreator;
+import org.eclipse.ui.menus.IMenuService;
+import org.eclipse.ui.progress.UIJob;
+
+/**
+ * Support for a command based QuickMenuAction that can pop up a
+ * menu-contribution based context menu.
+ * <p>
+ * This is experimental and should not be moved.
+ * </p>
+ *
+ * @since 3.4
+ */
+public class QuickMenuHandler extends AbstractHandler implements IMenuListener2 {
+	private QuickMenuCreator creator = new QuickMenuCreator() {
+
+		@Override
+		protected void fillMenu(IMenuManager menu) {
+			if (!(menu instanceof ContributionManager)) {
+				return;
+			}
+			IMenuService service = PlatformUI.getWorkbench()
+					.getService(IMenuService.class);
+			service.populateContributionManager((ContributionManager) menu,
+					locationURI);
+			menu.addMenuListener(QuickMenuHandler.this);
+		}
+
+	};
+
+	private String locationURI;
+
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		locationURI = event.getParameter("org.eclipse.ui.window.quickMenu.uri"); //$NON-NLS-1$
+		if (locationURI == null) {
+			throw new ExecutionException("locatorURI must not be null"); //$NON-NLS-1$
+		}
+		creator.createMenu();
+		return null;
+	}
+
+	@Override
+	public void dispose() {
+		if (creator != null) {
+			creator.dispose();
+			creator = null;
+		}
+	}
+
+	@Override
+	public void menuAboutToHide(final IMenuManager managerM) {
+		new UIJob("quickMenuCleanup") { //$NON-NLS-1$
+
+			@Override
+			public IStatus runInUIThread(IProgressMonitor monitor) {
+				IMenuService service = PlatformUI.getWorkbench()
+						.getService(IMenuService.class);
+				service.releaseContributions((ContributionManager) managerM);
+				return Status.OK_STATUS;
+			}
+
+		}.schedule();
+	}
+
+	@Override
+	public void menuAboutToShow(IMenuManager manager) {
+		// no-op
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/QuitHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/QuitHandler.java
new file mode 100644
index 0000000..7296fe2
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/QuitHandler.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal.handlers;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IWorkbench;
+
+/**
+ * Exit the workbench. Normal invocation calls {@link IWorkbench#close()}, which
+ * typically doesn't prompt the user before exiting.
+ * <p>
+ * Invocation with parameter mayPrompt="true" calls {@link Display#close()},
+ * which may prompt the user (via a hook installed by
+ * <code>org.eclipse.ui.internal.ide.application.IDEWorkbenchAdvisor</code>).
+ *
+ * @since 3.4
+ *
+ */
+public class QuitHandler extends AbstractHandler {
+	private static final String COMMAND_PARAMETER_ID_MAY_PROMPT = "mayPrompt"; //$NON-NLS-1$
+	private static final String TRUE = "true"; //$NON-NLS-1$
+
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		IEvaluationContext context = (IEvaluationContext) event.getApplicationContext();
+		IWorkbench workbench = (IWorkbench) context.getVariable(IWorkbench.class.getName());
+		if (TRUE.equals(event.getParameter(COMMAND_PARAMETER_ID_MAY_PROMPT))) {
+			workbench.getDisplay().close();
+		} else {
+			workbench.close();
+		}
+		return null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ResetPerspectiveHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ResetPerspectiveHandler.java
new file mode 100644
index 0000000..b7a29cc
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ResetPerspectiveHandler.java
@@ -0,0 +1,84 @@
+/*******************************************************************************

+ * Copyright (c) 2011, 2014 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.ui.internal.handlers;

+

+import org.eclipse.core.commands.AbstractHandler;

+import org.eclipse.core.commands.ExecutionEvent;

+import org.eclipse.jface.dialogs.IDialogConstants;

+import org.eclipse.jface.dialogs.MessageDialog;

+import org.eclipse.jface.dialogs.MessageDialogWithToggle;

+import org.eclipse.osgi.util.NLS;

+import org.eclipse.swt.SWT;

+import org.eclipse.ui.IPerspectiveDescriptor;

+import org.eclipse.ui.IWorkbenchWindow;

+import org.eclipse.ui.PlatformUI;

+import org.eclipse.ui.handlers.HandlerUtil;

+import org.eclipse.ui.internal.WorkbenchMessages;

+import org.eclipse.ui.internal.WorkbenchPage;

+import org.eclipse.ui.internal.registry.PerspectiveDescriptor;

+import org.eclipse.ui.internal.registry.PerspectiveRegistry;

+

+/**

+ * @since 3.5

+ *

+ */

+public class ResetPerspectiveHandler extends AbstractHandler {

+

+	@Override

+	public Object execute(ExecutionEvent event) {

+

+		IWorkbenchWindow activeWorkbenchWindow = HandlerUtil.getActiveWorkbenchWindow(event);

+		if (activeWorkbenchWindow != null) {

+			WorkbenchPage page = (WorkbenchPage) activeWorkbenchWindow.getActivePage();

+			if (page != null) {

+				IPerspectiveDescriptor descriptor = page.getPerspective();

+				if (descriptor != null) {

+					boolean offerRevertToBase = false;

+					if (descriptor instanceof PerspectiveDescriptor) {

+						PerspectiveDescriptor desc = (PerspectiveDescriptor) descriptor;

+						offerRevertToBase = desc.isPredefined() && desc.hasCustomDefinition();

+					}

+

+					if (offerRevertToBase) {

+						String message = NLS.bind(WorkbenchMessages.get().RevertPerspective_message,

+								descriptor.getLabel());

+						boolean toggleState = false;

+						MessageDialogWithToggle dialog = MessageDialogWithToggle.open(

+								MessageDialog.QUESTION, activeWorkbenchWindow.getShell(),

+								WorkbenchMessages.get().RevertPerspective_title, message,

+								WorkbenchMessages.get().RevertPerspective_option, toggleState, null,

+								null, SWT.SHEET);

+						if (dialog.getReturnCode() == IDialogConstants.YES_ID) {

+							if (dialog.getToggleState()) {

+								PerspectiveRegistry reg = (PerspectiveRegistry) PlatformUI

+										.getWorkbench().getPerspectiveRegistry();

+								reg.revertPerspective(descriptor);

+							}

+							page.resetPerspective();

+						}

+					} else {

+						String message = NLS.bind(WorkbenchMessages.get().ResetPerspective_message,

+								descriptor.getLabel());

+						boolean result = MessageDialog.open(MessageDialog.QUESTION,

+								activeWorkbenchWindow.getShell(),

+								WorkbenchMessages.get().ResetPerspective_title, message, SWT.SHEET);

+						if (result) {

+							page.resetPerspective();

+						}

+					}

+				}

+			}

+		}

+

+		return null;

+	}

+}

diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/RestartWorkbenchHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/RestartWorkbenchHandler.java
new file mode 100644
index 0000000..259bcbf
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/RestartWorkbenchHandler.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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:
+ *     Manuel Selva <manuel.selva@st.com> - Bug 197922
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.handlers;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * Provide a Handler for the Restart Workbench command.
+ *
+ */
+public class RestartWorkbenchHandler extends AbstractHandler {
+
+	@Override
+	public Object execute(ExecutionEvent event){
+
+		PlatformUI.getWorkbench().restart(true);
+		return null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ReuseEditorTester.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ReuseEditorTester.java
new file mode 100644
index 0000000..39792a3
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ReuseEditorTester.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2015 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.ui.internal.handlers;
+
+import org.eclipse.core.expressions.PropertyTester;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.ui.internal.IPreferenceConstants;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+
+/**
+ * Test to see if pinning is available.
+ *
+ */
+public class ReuseEditorTester extends PropertyTester {
+
+	@Override
+	public boolean test(Object receiver, String property, Object[] args,
+			Object expectedValue) {
+		IPreferenceStore store = WorkbenchPlugin.getDefault()
+				.getPreferenceStore();
+		return store.getBoolean(IPreferenceConstants.REUSE_EDITORS_BOOLEAN);
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/SaveAllHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/SaveAllHandler.java
new file mode 100644
index 0000000..3db01ad
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/SaveAllHandler.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2013, 2015 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.ui.internal.handlers;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.ui.ISaveablesLifecycleListener;
+import org.eclipse.ui.ISaveablesSource;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.Saveable;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.eclipse.ui.internal.InternalHandlerUtil;
+import org.eclipse.ui.internal.SaveablesList;
+import org.eclipse.ui.internal.WorkbenchPage;
+
+/**
+ * Saves all active editors
+ * <p>
+ * Replacement for SaveAllAction
+ * </p>
+ *
+ * @since 3.7
+ *
+ */
+public class SaveAllHandler extends AbstractSaveHandler {
+
+	public SaveAllHandler() {
+		registerEnablement();
+	}
+
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		IWorkbenchWindow window = HandlerUtil
+				.getActiveWorkbenchWindowChecked(event);
+		IWorkbenchPage page = window.getActivePage();
+		if (page != null) {
+			((WorkbenchPage) page).saveAllEditors(false, false, true);
+		}
+
+		return null;
+	}
+
+	@Override
+	protected EvaluationResult evaluate(IEvaluationContext context) {
+
+		IWorkbenchWindow window = InternalHandlerUtil.getActiveWorkbenchWindow(context);
+		// no window? not active
+		if (window == null)
+			return EvaluationResult.FALSE;
+		WorkbenchPage page = (WorkbenchPage) window.getActivePage();
+
+		// no page? not active
+		if (page == null)
+			return EvaluationResult.FALSE;
+
+		// if at least one dirty part, then we are active
+		if (page.getDirtyParts().length > 0)
+			return EvaluationResult.TRUE;
+
+		// Since Save All also saves saveables from non-part sources,
+		// look if any such saveables exist and are dirty.
+		SaveablesList saveablesList = (SaveablesList) window.getWorkbench().getService(
+				ISaveablesLifecycleListener.class);
+		if (saveablesList == null) {
+			return EvaluationResult.FALSE;
+		}
+
+		for (ISaveablesSource nonPartSource : saveablesList.getNonPartSources()) {
+			Saveable[] saveables = nonPartSource.getSaveables();
+			for (Saveable saveable : saveables) {
+				if (saveable.isDirty()) {
+					return EvaluationResult.TRUE;
+				}
+			}
+		}
+
+		// if nothing, then we are not active
+		return EvaluationResult.FALSE;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/SaveAsHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/SaveAsHandler.java
new file mode 100644
index 0000000..877a40b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/SaveAsHandler.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2015 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.ui.internal.handlers;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.ui.ISaveablePart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.internal.InternalHandlerUtil;
+import org.eclipse.ui.internal.WorkbenchPage;
+
+/**
+ * <p>
+ * Replacement for SaveAsAction
+ * </p>
+ *
+ * @since 3.7
+ *
+ */
+public class SaveAsHandler extends AbstractSaveHandler {
+
+	public SaveAsHandler() {
+		registerEnablement();
+	}
+
+	@Override
+	public Object execute(ExecutionEvent event) {
+
+		ISaveablePart saveablePart = getSaveablePart(event);
+
+		if (saveablePart != null)
+			saveablePart.doSaveAs();
+
+		return null;
+	}
+
+	@Override
+	protected EvaluationResult evaluate(IEvaluationContext context) {
+
+		IWorkbenchWindow window = InternalHandlerUtil.getActiveWorkbenchWindow(context);
+		// no window? not active
+		if (window == null)
+			return EvaluationResult.FALSE;
+		WorkbenchPage page = (WorkbenchPage) window.getActivePage();
+
+		// no page? not active
+		if (page == null)
+			return EvaluationResult.FALSE;
+
+		// get saveable part
+		ISaveablePart saveablePart = getSaveablePart(context);
+		if (saveablePart == null)
+			return EvaluationResult.FALSE;
+
+		// if its availble, return whatever it says
+		return saveablePart.isSaveAsAllowed() ? EvaluationResult.TRUE : EvaluationResult.FALSE;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/SaveHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/SaveHandler.java
new file mode 100644
index 0000000..7c56b5d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/SaveHandler.java
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * Copyright (c) 2013, 2015 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.ui.internal.handlers;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.ISaveablePart;
+import org.eclipse.ui.ISaveablesSource;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.eclipse.ui.internal.InternalHandlerUtil;
+import org.eclipse.ui.internal.SaveableHelper;
+import org.eclipse.ui.internal.WorkbenchPage;
+
+/**
+ * <p>
+ * Replacement for SaveAction
+ * </p>
+ *
+ * @since 3.7
+ *
+ */
+public class SaveHandler extends AbstractSaveHandler {
+
+	public SaveHandler() {
+		registerEnablement();
+	}
+
+	@Override
+	public Object execute(ExecutionEvent event) {
+
+		ISaveablePart saveablePart = getSaveablePart(event);
+
+		// no saveable
+		if (saveablePart == null)
+			return null;
+
+		// if editor
+		if (saveablePart instanceof IEditorPart) {
+			IEditorPart editorPart = (IEditorPart) saveablePart;
+			IWorkbenchPage page = editorPart.getSite().getPage();
+			page.saveEditor(editorPart, false);
+			return null;
+		}
+
+		// if view
+		IWorkbenchPart activePart = HandlerUtil.getActivePart(event);
+		WorkbenchPage page = (WorkbenchPage) activePart.getSite().getPage();
+		page.saveSaveable(saveablePart, activePart, false, false);
+
+		return null;
+
+	}
+
+	@Override
+	protected EvaluationResult evaluate(IEvaluationContext context) {
+
+		IWorkbenchWindow window = InternalHandlerUtil.getActiveWorkbenchWindow(context);
+		// no window? not active
+		if (window == null)
+			return EvaluationResult.FALSE;
+		WorkbenchPage page = (WorkbenchPage) window.getActivePage();
+
+		// no page? not active
+		if (page == null)
+			return EvaluationResult.FALSE;
+
+		// get saveable part
+		ISaveablePart saveablePart = getSaveablePart(context);
+		if (saveablePart == null)
+			return EvaluationResult.FALSE;
+
+		if (saveablePart instanceof ISaveablesSource) {
+			ISaveablesSource modelSource = (ISaveablesSource) saveablePart;
+			if (SaveableHelper.needsSave(modelSource))
+				return EvaluationResult.TRUE;
+			return EvaluationResult.FALSE;
+		}
+
+		if (saveablePart != null && saveablePart.isDirty())
+			return EvaluationResult.TRUE;
+
+		return EvaluationResult.FALSE;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/SavePerspectiveHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/SavePerspectiveHandler.java
new file mode 100644
index 0000000..f835c68
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/SavePerspectiveHandler.java
Binary files differ
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/SelectAllHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/SelectAllHandler.java
new file mode 100644
index 0000000..36a6956
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/SelectAllHandler.java
@@ -0,0 +1,206 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.handlers;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.internal.ExceptionHandler;
+
+/**
+ * This handler is an adaptation of the widget method handler allowing select
+ * all to work even in some cases where the "selectAll" method does not exist.
+ * This handler attempts to use "getTextLimit" and "setSelection" to do select
+ * all. If this doesn't work, then it finally fails.
+ *
+ * @since 3.0
+ */
+public class SelectAllHandler extends WidgetMethodHandler {
+
+	/**
+	 * The parameters for a single point select all.
+	 */
+	private static final Class[] METHOD_PARAMETERS = { Point.class };
+
+	@Override
+	public final Object execute(final ExecutionEvent event)
+			throws ExecutionException {
+		final Method methodToExecute = getMethodToExecute();
+		if (methodToExecute != null) {
+			try {
+				final Control focusControl = Display.getCurrent()
+						.getFocusControl();
+
+				final int numParams = methodToExecute.getParameterTypes().length;
+
+				if ((focusControl instanceof Composite)
+//                        && ((((Composite) focusControl).getStyle() & SWT.EMBEDDED) != 0)
+						) 
+				{
+
+					// we only support selectAll for swing components
+					if (numParams != 0) {
+						return null;
+					}
+
+					/*
+					 * Okay. Have a seat. Relax a while. This is going to be a
+					 * bumpy ride. If it is an embedded widget, then it *might*
+					 * be a Swing widget. At the point where this handler is
+					 * executing, the key event is already bound to be
+					 * swallowed. If I don't do something, then the key will be
+					 * gone for good. So, I will try to forward the event to the
+					 * Swing widget. Unfortunately, we can't even count on the
+					 * Swing libraries existing, so I need to use reflection
+					 * everywhere. And, to top it off, I need to dispatch the
+					 * event on the Swing event queue, which means that it will
+					 * be carried out asynchronously to the SWT event queue.
+					 */
+					try {
+						final Object focusComponent = getFocusComponent();
+						if (focusComponent != null) {
+							Runnable methodRunnable = () -> {
+								try {
+									methodToExecute.invoke(focusComponent);
+									// and back to the UI thread :-)
+									focusControl.getDisplay().asyncExec(
+											() -> {
+												if (!focusControl
+														.isDisposed()) {
+													focusControl
+															.notifyListeners(
+																	SWT.Selection,
+																	null);
+												}
+											});
+								} catch (final IllegalAccessException e1) {
+									// The method is protected, so do
+									// nothing.
+								} catch (final InvocationTargetException e2) {
+									/*
+									 * I would like to log this exception --
+									 * and possibly show a dialog to the
+									 * user -- but I have to go back to the
+									 * SWT event loop to do this. So, back
+									 * we go....
+									 */
+									focusControl.getDisplay().asyncExec(
+											() -> ExceptionHandler
+													.getInstance()
+													.handleException(
+															new ExecutionException(
+																	"An exception occurred while executing " //$NON-NLS-1$
+																			+ methodToExecute
+																					.getName(),
+																	e2
+																			.getTargetException())));
+								}
+							};
+
+							swingInvokeLater(methodRunnable);
+						}
+					} catch (final ClassNotFoundException e) {
+						// There is no Swing support, so do nothing.
+
+					} catch (final NoSuchMethodException e) {
+						// The API has changed, which seems amazingly unlikely.
+						throw new Error("Something is seriously wrong here"); //$NON-NLS-1$
+					}
+				} else if (numParams == 0) {
+					// This is a no-argument selectAll method.
+					methodToExecute.invoke(focusControl);
+					focusControl.notifyListeners(SWT.Selection, null);
+
+				} else if (numParams == 1) {
+					// This is a single-point selection method.
+					final Method textLimitAccessor = focusControl.getClass()
+							.getMethod("getTextLimit", NO_PARAMETERS); //$NON-NLS-1$
+					final Integer textLimit = (Integer) textLimitAccessor
+							.invoke(focusControl);
+					final Object[] parameters = { new Point(0, textLimit
+							.intValue()) };
+					methodToExecute.invoke(focusControl, parameters);
+					if (!(focusControl instanceof Combo)) {
+						focusControl.notifyListeners(SWT.Selection, null);
+					}
+
+				} else {
+					/*
+					 * This means that getMethodToExecute() has been changed,
+					 * while this method hasn't.
+					 */
+					throw new ExecutionException(
+							"Too many parameters on select all", new Exception()); //$NON-NLS-1$
+
+				}
+
+			} catch (IllegalAccessException e) {
+				// The method is protected, so do nothing.
+
+			} catch (InvocationTargetException e) {
+				throw new ExecutionException(
+						"An exception occurred while executing " //$NON-NLS-1$
+								+ getMethodToExecute(), e.getTargetException());
+
+			} catch (NoSuchMethodException e) {
+				// I can't get the text limit. Do nothing.
+
+			}
+		}
+
+		return null;
+	}
+
+	/**
+	 * Looks up the select all method on the given focus control.
+	 *
+	 * @return The method on the focus control; <code>null</code> if none.
+	 */
+	@Override
+	protected Method getMethodToExecute() {
+		Method method = super.getMethodToExecute();
+
+		// Let's see if we have a control that supports point-based selection.
+		if (method == null) {
+			final Control focusControl = Display.getCurrent().getFocusControl();
+			if (focusControl != null) {
+				try {
+					method = focusControl.getClass().getMethod("setSelection", //$NON-NLS-1$
+							METHOD_PARAMETERS);
+				} catch (NoSuchMethodException e) {
+					// Do nothing.
+				}
+			}
+		}
+
+		return method;
+	}
+
+	/**
+	 * @see org.eclipse.core.runtime.IExecutableExtension#setInitializationData(org.eclipse.core.runtime.IConfigurationElement,
+	 *      java.lang.String, java.lang.Object)
+	 */
+	@Override
+	public void setInitializationData(IConfigurationElement config,
+			String propertyName, Object data) {
+		// The name is always "selectAll".
+		methodName = "selectAll"; //$NON-NLS-1$
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ShowKeyAssistHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ShowKeyAssistHandler.java
new file mode 100644
index 0000000..4d41589
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ShowKeyAssistHandler.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.handlers;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.keys.IBindingService;
+
+/**
+ * A handler that displays the key assist dialog when executed.
+ *
+ * @since 3.1
+ */
+public class ShowKeyAssistHandler extends WorkbenchWindowHandlerDelegate {
+
+	/**
+	 * Opens the key assistant. This should never be called until initialization
+	 * occurs.
+	 *
+	 * @param event
+	 *            Ignored
+	 * @return <code>null</code>
+	 */
+	@Override
+	public Object execute(final ExecutionEvent event) {
+		final IWorkbench workbench = PlatformUI.getWorkbench();
+		final IBindingService bindingService = workbench.getService(IBindingService.class);
+		bindingService.openKeyAssistDialog();
+		return null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ShowPreferencePageHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ShowPreferencePageHandler.java
new file mode 100644
index 0000000..b9e2e16
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ShowPreferencePageHandler.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.handlers;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.jface.preference.PreferenceDialog;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.dialogs.PreferencesUtil;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * <p>
+ * Shows the given preference page. If no preference page id is specified in the
+ * parameters, then this opens the preferences dialog to whatever page was
+ * active the last time the dialog was shown.
+ * </p>
+ * <p>
+ * This class is not intended for use outside of the
+ * <code>org.eclipse.ui.workbench</code> plug-in.
+ * </p>
+ *
+ * @since 3.2
+ */
+public final class ShowPreferencePageHandler extends AbstractHandler {
+
+
+	public ShowPreferencePageHandler() {
+		super();
+	}
+
+	@Override
+	public final Object execute(final ExecutionEvent event) {
+		final String preferencePageId = event
+				.getParameter(IWorkbenchCommandConstants.WINDOW_PREFERENCES_PARM_PAGEID);
+		final IWorkbenchWindow activeWorkbenchWindow = HandlerUtil
+				.getActiveWorkbenchWindow(event);
+
+		final Shell shell;
+		if (activeWorkbenchWindow == null) {
+			shell = null;
+		} else {
+			shell = activeWorkbenchWindow.getShell();
+		}
+
+		final PreferenceDialog dialog = PreferencesUtil
+				.createPreferenceDialogOn(shell, preferencePageId, null, null);
+		dialog.open();
+
+		return null;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/SpyHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/SpyHandler.java
new file mode 100644
index 0000000..f51060a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/SpyHandler.java
@@ -0,0 +1,154 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2015 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.ui.internal.handlers;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.eclipse.ui.internal.testing.ContributionInfoMessages;
+import org.eclipse.ui.testing.ContributionInfo;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.FrameworkUtil;
+
+/**
+ * @since 3.6
+ *
+ */
+public class SpyHandler extends AbstractHandler {
+
+	@Override
+	public Object execute(ExecutionEvent event) {
+		Shell shell = HandlerUtil.getActiveShell(event);
+		if (shell != null) {
+			Control control = shell.getDisplay().getFocusControl();
+			if (control != null) {
+				showTooltip(control);
+			}
+		}
+		return null;
+	}
+
+	protected void showTooltip(Control control) {
+		ContributionInfo contributionInfo = null;
+		Point offset = new Point(0, 0);
+		while (control != null) {
+			if (control instanceof Table) {
+				Table table = (Table) control;
+				if (table.getSelectionCount() == 1) {
+					TableItem tableItem = table.getSelection()[0];
+					contributionInfo = getContributionInfo(tableItem.getData(),
+							ContributionInfoMessages.ContributionInfo_TableItem);
+					if (contributionInfo != null) {
+						Rectangle bounds = tableItem.getBounds();
+						offset = new Point(bounds.x, bounds.y);
+						break;
+					}
+				}
+			} else if (control instanceof Tree) {
+				Tree tree = (Tree) control;
+				if (tree.getSelectionCount() == 1) {
+					TreeItem treeItem = tree.getSelection()[0];
+					contributionInfo = getContributionInfo(treeItem.getData(),
+							ContributionInfoMessages.ContributionInfo_TreeItem);
+					if (contributionInfo != null) {
+						Rectangle bounds = treeItem.getBounds();
+						offset = new Point(bounds.x, bounds.y);
+						break;
+					}
+				}
+			}
+			String optionalElementType;
+
+			// "force" a contribution info if we are at a shell
+			if (control instanceof Shell)
+				optionalElementType = ContributionInfoMessages.ContributionInfo_Window;
+			else
+				optionalElementType = null;
+
+			contributionInfo = getContributionInfo(control.getData(), optionalElementType);
+
+			if (contributionInfo != null) {
+				break;
+			}
+			control = control.getParent();
+		}
+		if (contributionInfo == null) {
+			return;
+		}
+		doShowTooltip(control, offset, contributionInfo);
+	}
+
+	/**
+	 * @param control
+	 * @param offset
+	 * @param contributionInfo
+	 */
+	protected void doShowTooltip(Control control, Point offset,
+			final ContributionInfo contributionInfo) {
+	 // RAP
+//      ToolTip toolTip = new ToolTip(control, ToolTip.NO_RECREATE, true) {
+//
+//          @Override
+//          protected Composite createToolTipContentArea(Event event, Composite parent) {
+//              // Create the content area
+//              Composite composite = new Composite(parent, SWT.NONE);
+//              Color fg = parent.getDisplay().getSystemColor(SWT.COLOR_INFO_FOREGROUND);
+//              Color bg = parent.getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND);
+//              composite.setForeground(fg);
+//              composite.setBackground(bg);
+//              Text text = new Text(composite, SWT.READ_ONLY);
+//              text.setForeground(fg);
+//              text.setBackground(bg);
+//              String info = NLS.bind(ContributionInfoMessages.ContributionInfo_ContributedBy,
+//                      contributionInfo.getElementType(), contributionInfo.getBundleId());
+//              text.setText(info);
+//              GridLayoutFactory.fillDefaults().margins(2, 2).generateLayout(composite);
+//              return composite;
+//          }
+//      };
+//      toolTip.setHideOnMouseDown(false);
+//      toolTip.setHideDelay(3000);
+//      toolTip.show(offset);
+	}
+
+	/**
+	 * Returns a ContributionInfo for the given data object (typically, a data
+	 * object associated with a widget). If the data object is a
+	 * ContributionInfo, return it. If it can be adapted to ContributionInfo,
+	 * return the result of the adaptation. Otherwise, if a non-null
+	 * 'optionalElementType' string is given, return a contribution info based
+	 * on it and the bundle that contains the given object's class.
+	 */
+	ContributionInfo getContributionInfo(Object data, String optionalElementType) {
+		if (data instanceof ContributionInfo) {
+			return (ContributionInfo) data;
+		}
+		ContributionInfo result = Adapters.adapt(data, ContributionInfo.class);
+		if (optionalElementType != null && result == null && data != null) {
+			Bundle bundle = FrameworkUtil.getBundle(data.getClass());
+			if (bundle != null) {
+				result = new ContributionInfo(bundle.getSymbolicName(),
+						optionalElementType != null ? optionalElementType
+								: ContributionInfoMessages.ContributionInfo_Unknown, null);
+			}
+		}
+		return result;
+	}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ToggleCoolbarHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ToggleCoolbarHandler.java
new file mode 100644
index 0000000..98e9859
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ToggleCoolbarHandler.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.handlers;
+
+import java.util.Map;
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.commands.IElementUpdater;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchWindow;
+import org.eclipse.ui.internal.services.IWorkbenchLocationService;
+import org.eclipse.ui.menus.UIElement;
+
+/**
+ * Handler that toggles the visibility of the coolbar/perspective bar in a given
+ * window.
+ *
+ * @since 3.3
+ */
+public class ToggleCoolbarHandler extends AbstractHandler implements
+		IElementUpdater {
+
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+		final IWorkbenchWindow activeWorkbenchWindow = HandlerUtil
+				.getActiveWorkbenchWindowChecked(event);
+		if (activeWorkbenchWindow instanceof WorkbenchWindow) {
+			WorkbenchWindow window = (WorkbenchWindow) activeWorkbenchWindow;
+			window.toggleToolbarVisibility();
+		}
+
+		return null;
+	}
+
+	@Override
+	public void updateElement(UIElement element, Map parameters) {
+		IWorkbenchLocationService wls = element
+				.getServiceLocator()
+				.getService(IWorkbenchLocationService.class);
+		IWorkbenchWindow window = wls.getWorkbenchWindow();
+		if (window == null || !(window instanceof WorkbenchWindow))
+			return;
+		element
+				.setText(isCoolbarVisible((WorkbenchWindow) window) ? WorkbenchMessages.get().ToggleCoolbarVisibilityAction_hide_text
+						: WorkbenchMessages.get().ToggleCoolbarVisibilityAction_show_text);
+	}
+
+	/**
+	 * Return whether the coolbar is currently visible.
+	 *
+	 * @param window
+	 * 		the window to test
+	 * @return whether or not the coolbar is visible
+	 */
+	private boolean isCoolbarVisible(WorkbenchWindow window) {
+		return window.getCoolBarVisible() || window.getPerspectiveBarVisible();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ToggleStatusBarHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ToggleStatusBarHandler.java
new file mode 100644
index 0000000..fd941e8
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/ToggleStatusBarHandler.java
@@ -0,0 +1,129 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Patrik Suzzi. 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:
+ * 	Patrik Suzzi <psuzzi@gmail.com> - initial API and implementation;
+ ******************************************************************************/
+
+package org.eclipse.ui.internal.handlers;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.e4.core.services.events.IEventBroker;
+import org.eclipse.e4.ui.model.application.ui.MUIElement;
+import org.eclipse.e4.ui.workbench.UIEvents;
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.commands.IElementUpdater;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchWindow;
+import org.eclipse.ui.internal.services.IWorkbenchLocationService;
+import org.eclipse.ui.menus.UIElement;
+import org.eclipse.ui.services.IServiceScopes;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventHandler;
+
+/**
+ * Toggle the visibility of the status bar. Implementation of the
+ * {@code org.eclipse.ui.window.togglestatusbar} command.
+ *
+ */
+public class ToggleStatusBarHandler extends AbstractHandler implements IElementUpdater {
+
+	public static final String COMMAND_ID_TOGGLE_STATUSBAR = "org.eclipse.ui.window.togglestatusbar"; //$NON-NLS-1$
+
+	// id of the status bar, as defined in the LegacyIDE.e4xmi
+	private static final String BOTTOM_TRIM_ID = "org.eclipse.ui.trim.status"; //$NON-NLS-1$
+
+	// keep references of event handlers and brokers per each window
+	private HashMap<IWorkbenchWindow, EventHandler> eventHandlers = new HashMap<>();
+	private HashMap<IWorkbenchWindow, IEventBroker> eventBrokers = new HashMap<>();
+
+	@Override
+	public Object execute(ExecutionEvent event) {
+		IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindow(event);
+		if (!(window instanceof WorkbenchWindow))
+			return null;
+		// initialize event handler
+		if (!eventHandlers.containsKey(window)) {
+			initializeEventHandler(window);
+		}
+		// perform operation
+		MUIElement trimStatus = getTrimStatus((WorkbenchWindow) window);
+		if (trimStatus != null) {
+			// toggle statusbar visibility
+			trimStatus.setVisible(!trimStatus.isVisible());
+		}
+		return null;
+	}
+
+	/**
+	 * @param window
+	 */
+	private void initializeEventHandler(IWorkbenchWindow window) {
+		final IEventBroker eventBroker = window.getService(IEventBroker.class);
+		eventBrokers.put(window, eventBroker);
+		EventHandler eventHandler = new EventHandler() {
+			@Override
+			public void handleEvent(Event event) {
+				Object element = event.getProperty(UIEvents.EventTags.ELEMENT);
+				// if the current-window trim is the event element
+				if (element != null && element == getTrimStatus((WorkbenchWindow) window)) {
+					// refresh menu item label, triggering updateElement()
+					ICommandService commandService = window.getService(ICommandService.class);
+					Map<String, WorkbenchWindow> filter = new HashMap<>();
+					filter.put(IServiceScopes.WINDOW_SCOPE, (WorkbenchWindow) window);
+					commandService.refreshElements(COMMAND_ID_TOGGLE_STATUSBAR, filter);
+				}
+			}
+		};
+		eventHandlers.put(window, eventHandler);
+		eventBroker.subscribe(UIEvents.UIElement.TOPIC_VISIBLE, eventHandler);
+	}
+
+	@Override
+	public void dispose() {
+		for (IWorkbenchWindow w : eventHandlers.keySet()) {
+			IEventBroker eventBroker = eventBrokers.get(w);
+			EventHandler eventHandler = eventHandlers.get(w);
+			if (eventBroker != null && eventHandler != null) {
+				eventBroker.unsubscribe(eventHandler);
+			}
+		}
+		super.dispose();
+	}
+
+	/**
+	 * Updates the visibilty status of the element.
+	 */
+	@Override
+	public void updateElement(UIElement element, Map parameters) {
+		IWorkbenchLocationService wls = element
+				.getServiceLocator()
+				.getService(IWorkbenchLocationService.class);
+		IWorkbenchWindow window = wls.getWorkbenchWindow();
+		if (!(window instanceof WorkbenchWindow))
+			return;
+		MUIElement trimStatus = getTrimStatus((WorkbenchWindow) window);
+		if(trimStatus != null) {
+			element.setText(trimStatus.isVisible() ? WorkbenchMessages.get().ToggleStatusBarVisibilityAction_hide_text
+					: WorkbenchMessages.get().ToggleStatusBarVisibilityAction_show_text);
+		}
+	}
+
+	/* Get the MUIElement representing the status bar for the given window */
+	private static MUIElement getTrimStatus(WorkbenchWindow window) {
+		EModelService modelService = window.getService(EModelService.class);
+		MUIElement searchRoot = window.getModel();
+		return modelService.find(BOTTOM_TRIM_ID, searchRoot);
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/WidgetMethodHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/WidgetMethodHandler.java
new file mode 100644
index 0000000..6ba9bf9
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/WidgetMethodHandler.java
@@ -0,0 +1,310 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Bruno Haible haible@ilog.fr - bug 228890
+ *******************************************************************************/
+package org.eclipse.ui.internal.handlers;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExecutableExtension;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.ui.internal.ExceptionHandler;
+
+/**
+ * Handles the cut command in both dialogs and windows. This handler is enabled
+ * if the focus control supports the "cut" method.
+ *
+ * @since 3.0
+ */
+public class WidgetMethodHandler extends AbstractHandler implements
+		IExecutableExtension {
+
+	/**
+	 * The parameters to pass to the method this handler invokes. This handler
+	 * always passes no parameters.
+	 */
+	protected static final Class[] NO_PARAMETERS = new Class[0];
+
+	public WidgetMethodHandler() {
+		display = Display.getCurrent();
+		if (display != null) {
+			focusListener = event -> updateEnablement();
+			display.addFilter(SWT.FocusIn, focusListener);
+		}
+	}
+
+	void updateEnablement() {
+		boolean rc = isHandled();
+		if (rc != isEnabled()) {
+			setBaseEnabled(rc);
+		}
+	}
+
+	/**
+	 * The name of the method to be invoked by this handler. This value should
+	 * never be <code>null</code>.
+	 */
+	protected String methodName;
+	private Listener focusListener;
+	private Display display;
+
+	@Override
+	public Object execute(final ExecutionEvent event) throws ExecutionException {
+		final Method methodToExecute = getMethodToExecute();
+		if (methodToExecute != null) {
+			try {
+				final Control focusControl = Display.getCurrent()
+						.getFocusControl();
+				if ((focusControl instanceof Composite)
+//						&& ((((Composite) focusControl).getStyle() & SWT.EMBEDDED) != 0)
+						) 
+				{
+					/*
+					 * Okay. Have a seat. Relax a while. This is going to be a
+                     * bumpy ride. If it is an embedded widget, then it *might*
+                     * be a Swing widget. At the point where this handler is
+					 * executing, the key event is already bound to be
+					 * swallowed. If I don't do something, then the key will be
+					 * gone for good. So, I will try to forward the event to the
+					 * Swing widget. Unfortunately, we can't even count on the
+					 * Swing libraries existing, so I need to use reflection
+					 * everywhere. And, to top it off, I need to dispatch the
+					 * event on the Swing event queue, which means that it will
+					 * be carried out asynchronously to the SWT event queue.
+					 */
+					try {
+						final Object focusComponent = getFocusComponent();
+						if (focusComponent != null) {
+							Runnable methodRunnable = () -> {
+								try {
+									methodToExecute.invoke(focusComponent);
+								} catch (final IllegalAccessException e1) {
+									// The method is protected, so do
+									// nothing.
+								} catch (final InvocationTargetException e2) {
+									/*
+									 * I would like to log this exception --
+									 * and possibly show a dialog to the
+									 * user -- but I have to go back to the
+									 * SWT event loop to do this. So, back
+									 * we go....
+									 */
+									focusControl.getDisplay().asyncExec(
+											() -> ExceptionHandler
+													.getInstance()
+													.handleException(
+															new ExecutionException(
+																	"An exception occurred while executing " //$NON-NLS-1$
+																			+ methodToExecute
+																					.getName(),
+																	e2
+																			.getTargetException())));
+								}
+							};
+
+							swingInvokeLater(methodRunnable);
+						}
+					} catch (final ClassNotFoundException e) {
+						// There is no Swing support, so do nothing.
+
+					} catch (final NoSuchMethodException e) {
+						// The API has changed, which seems amazingly unlikely.
+						throw new Error("Something is seriously wrong here"); //$NON-NLS-1$
+					}
+
+				} else {
+
+					methodToExecute.invoke(focusControl);
+				}
+
+			} catch (IllegalAccessException e) {
+				// The method is protected, so do nothing.
+
+			} catch (InvocationTargetException e) {
+				throw new ExecutionException(
+						"An exception occurred while executing " //$NON-NLS-1$
+								+ methodToExecute.getName(), e
+								.getTargetException());
+
+			}
+		}
+
+		return null;
+	}
+
+	/**
+	 * Invoke a runnable on the swing EDT.
+	 *
+	 * @param methodRunnable
+	 * @throws ClassNotFoundException
+	 * @throws NoSuchMethodException
+	 * @throws IllegalAccessException
+	 * @throws InvocationTargetException
+	 */
+	protected void swingInvokeLater(Runnable methodRunnable)
+			throws ClassNotFoundException, NoSuchMethodException,
+			IllegalAccessException, InvocationTargetException {
+		final Class swingUtilitiesClass = Class
+				.forName("javax.swing.SwingUtilities"); //$NON-NLS-1$
+		final Method swingUtilitiesInvokeLaterMethod = swingUtilitiesClass
+				.getMethod("invokeLater", //$NON-NLS-1$
+						new Class[] { Runnable.class });
+		swingUtilitiesInvokeLaterMethod.invoke(swingUtilitiesClass,
+				new Object[] { methodRunnable });
+	}
+
+	/**
+	 * Find the swing focus component, if it is available.
+	 *
+	 * @return Hopefully, the swing focus component, but it can return
+	 * 	<code>null</code>.
+	 * @throws ClassNotFoundException
+	 * @throws NoSuchMethodException
+	 * @throws IllegalAccessException
+	 * @throws InvocationTargetException
+	 */
+	protected Object getFocusComponent() throws ClassNotFoundException,
+			NoSuchMethodException, IllegalAccessException,
+			InvocationTargetException {
+		/*
+		 * Before JRE 1.4, one has to use
+		 * javax.swing.FocusManager.getCurrentManager().getFocusOwner(). Since
+		 * JRE 1.4, one has to use
+		 * java.awt.KeyboardFocusManager.getCurrentKeyboardFocusManager
+		 * ().getFocusOwner(); the use of the older API would install a
+		 * LegacyGlueFocusTraversalPolicy which causes endless recursions in
+		 * some situations.
+		 */
+		Class keyboardFocusManagerClass = null;
+		try {
+			keyboardFocusManagerClass = Class
+					.forName("java.awt.KeyboardFocusManager"); //$NON-NLS-1$
+		} catch (ClassNotFoundException e) {
+			// switch to the old guy
+		}
+		if (keyboardFocusManagerClass != null) {
+			// Use JRE 1.4 API
+			final Method keyboardFocusManagerGetCurrentKeyboardFocusManagerMethod = keyboardFocusManagerClass
+					.getMethod("getCurrentKeyboardFocusManager"); //$NON-NLS-1$
+			final Object keyboardFocusManager = keyboardFocusManagerGetCurrentKeyboardFocusManagerMethod
+					.invoke(keyboardFocusManagerClass);
+			final Method keyboardFocusManagerGetFocusOwner = keyboardFocusManagerClass
+					.getMethod("getFocusOwner"); //$NON-NLS-1$
+			final Object focusComponent = keyboardFocusManagerGetFocusOwner
+					.invoke(keyboardFocusManager);
+			return focusComponent;
+		}
+		// Use JRE 1.3 API
+		final Class focusManagerClass = Class
+				.forName("javax.swing.FocusManager"); //$NON-NLS-1$
+		final Method focusManagerGetCurrentManagerMethod = focusManagerClass
+				.getMethod("getCurrentManager"); //$NON-NLS-1$
+		final Object focusManager = focusManagerGetCurrentManagerMethod
+		        .invoke(focusManagerClass);
+		final Method focusManagerGetFocusOwner = focusManagerClass
+		        .getMethod("getFocusOwner"); //$NON-NLS-1$
+		final Object focusComponent = focusManagerGetFocusOwner
+		        .invoke(focusManager);
+		return focusComponent;
+
+	}
+
+	@Override
+	public final boolean isHandled() {
+		return getMethodToExecute() != null;
+	}
+
+	/**
+	 * Looks up the method on the focus control.
+	 *
+	 * @return The method on the focus control; <code>null</code> if none.
+	 */
+	protected Method getMethodToExecute() {
+		Display display = Display.getCurrent();
+		if (display == null)
+			return null;
+		final Control focusControl = display.getFocusControl();
+		Method method = null;
+
+		if (focusControl != null) {
+			final Class clazz = focusControl.getClass();
+			try {
+				method = clazz.getMethod(methodName, NO_PARAMETERS);
+			} catch (NoSuchMethodException e) {
+				// Fall through...
+			}
+		}
+
+		if ((method == null)
+				&& (focusControl instanceof Composite)
+//				&& ((((Composite) focusControl).getStyle() & SWT.EMBEDDED) != 0)
+				) {
+			/*
+			 * We couldn't find the appropriate method on the current focus
+			 * control. It is possible that the current focus control is an
+			 * embedded SWT composite, which could be containing some Swing
+			 * components. If this is the case, then we should try to pass
+			 * through to the underlying Swing component hierarchy. Insha'allah,
+			 * this will work.
+			 */
+			try {
+				final Object focusComponent = getFocusComponent();
+				if (focusComponent != null) {
+					final Class clazz = focusComponent.getClass();
+
+					try {
+						method = clazz.getMethod(methodName, NO_PARAMETERS);
+					} catch (NoSuchMethodException e) {
+						// Do nothing.
+					}
+				}
+			} catch (final ClassNotFoundException e) {
+				// There is no Swing support, so do nothing.
+
+			} catch (final NoSuchMethodException e) {
+				// The API has changed, which seems amazingly unlikely.
+				throw new Error("Something is seriously wrong here"); //$NON-NLS-1$
+			} catch (IllegalAccessException e) {
+				// The API has changed, which seems amazingly unlikely.
+				throw new Error("Something is seriously wrong here"); //$NON-NLS-1$
+			} catch (InvocationTargetException e) {
+				// The API has changed, which seems amazingly unlikely.
+				throw new Error("Something is seriously wrong here"); //$NON-NLS-1$
+			}
+		}
+
+		return method;
+	}
+
+	@Override
+	public void setInitializationData(IConfigurationElement config,
+			String propertyName, Object data) {
+		// The data is really just a string (i.e., the method name).
+		methodName = data.toString();
+	}
+
+	@Override
+	public void dispose() {
+		if (display!=null && !display.isDisposed()) {
+			display.removeFilter(SWT.FocusIn, focusListener);
+		}
+		display = null;
+		focusListener = null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/WizardHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/WizardHandler.java
new file mode 100644
index 0000000..fb93c78
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/WizardHandler.java
@@ -0,0 +1,369 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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
+ *     Remy Chi Jian Suen <remy.suen@gmail.com> - Bug 202170 [Wizards] Empy Source Folder and Package in New Class Wizard
+ *******************************************************************************/
+package org.eclipse.ui.internal.handlers;
+
+import java.util.Map;
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.IWorkbenchWizard;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.commands.IElementUpdater;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.LegacyResourceSupport;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.dialogs.ImportExportWizard;
+import org.eclipse.ui.internal.dialogs.NewWizard;
+import org.eclipse.ui.menus.UIElement;
+import org.eclipse.ui.wizards.IWizardDescriptor;
+import org.eclipse.ui.wizards.IWizardRegistry;
+
+/**
+ * Abstract handler for commands that launch the import, export and new wizards.
+ * <p>
+ * This class is only intended to be extended by the three inner classes (<code>Export</code>,
+ * <code>Import</code> and <code>New</code>) defined here.
+ * </p>
+ *
+ * @since 3.2
+ */
+public abstract class WizardHandler extends AbstractHandler implements IElementUpdater {
+
+	/**
+	 * Default handler for launching export wizards.
+	 */
+	public static final class Export extends WizardHandler {
+	    private static final int SIZING_WIZARD_WIDTH = 470;
+	    private static final int SIZING_WIZARD_HEIGHT = 550;
+
+		@Override
+		protected String getWizardIdParameterId() {
+			return IWorkbenchCommandConstants.FILE_EXPORT_PARM_WIZARDID;
+		}
+
+		@Override
+		protected IWizardRegistry getWizardRegistry() {
+			return PlatformUI.getWorkbench().getExportWizardRegistry();
+		}
+
+		@Override
+		protected void executeHandler(ExecutionEvent event) {
+			IWorkbenchWindow activeWorkbenchWindow = HandlerUtil
+					.getActiveWorkbenchWindow(event);
+			if (activeWorkbenchWindow == null) {
+				// action has been disposed
+				return;
+			}
+			ImportExportWizard wizard = new ImportExportWizard(
+					ImportExportWizard.EXPORT);
+			IStructuredSelection selectionToPass = getSelectionToUse(event);
+
+			wizard.init(activeWorkbenchWindow.getWorkbench(), selectionToPass);
+			IDialogSettings workbenchSettings = WorkbenchPlugin.getDefault()
+					.getDialogSettings();
+			IDialogSettings wizardSettings = workbenchSettings
+					.getSection("ImportExportAction"); //$NON-NLS-1$
+			if (wizardSettings == null) {
+				wizardSettings = workbenchSettings
+						.addNewSection("ImportExportAction"); //$NON-NLS-1$
+			}
+			wizard.setDialogSettings(wizardSettings);
+			wizard.setForcePreviousAndNextButtons(true);
+
+			Shell parent = activeWorkbenchWindow.getShell();
+			WizardDialog dialog = new WizardDialog(parent, wizard);
+			dialog.create();
+			dialog.getShell().setSize(
+					Math.max(SIZING_WIZARD_WIDTH, dialog.getShell()
+							.getSize().x), SIZING_WIZARD_HEIGHT);
+			activeWorkbenchWindow.getWorkbench().getHelpSystem().setHelp(
+					dialog.getShell(), IWorkbenchHelpContextIds.EXPORT_WIZARD);
+			dialog.open();
+		}
+
+	}
+
+	/**
+	 * Default handler for launching import wizards.
+	 */
+	public static final class Import extends WizardHandler {
+	    private static final int SIZING_WIZARD_WIDTH = 470;
+	    private static final int SIZING_WIZARD_HEIGHT = 550;
+
+		@Override
+		protected String getWizardIdParameterId() {
+			return IWorkbenchCommandConstants.FILE_IMPORT_PARM_WIZARDID;
+		}
+
+		@Override
+		protected IWizardRegistry getWizardRegistry() {
+			return PlatformUI.getWorkbench().getImportWizardRegistry();
+		}
+
+		@Override
+		protected void executeHandler(ExecutionEvent event) {
+			IWorkbenchWindow activeWorkbenchWindow = HandlerUtil.getActiveWorkbenchWindow(event);
+	        if (activeWorkbenchWindow == null) {
+	            // action has been disposed
+	            return;
+	        }
+	        ImportExportWizard wizard = new ImportExportWizard(ImportExportWizard.IMPORT);
+			IStructuredSelection selectionToPass = getSelectionToUse(event);
+
+	        wizard.init(activeWorkbenchWindow.getWorkbench(), selectionToPass);
+	        IDialogSettings workbenchSettings = WorkbenchPlugin.getDefault()
+	                .getDialogSettings();
+	        IDialogSettings wizardSettings = workbenchSettings
+	                .getSection("ImportExportAction"); //$NON-NLS-1$
+	        if (wizardSettings == null) {
+				wizardSettings = workbenchSettings
+	                    .addNewSection("ImportExportAction"); //$NON-NLS-1$
+			}
+	        wizard.setDialogSettings(wizardSettings);
+	        wizard.setForcePreviousAndNextButtons(true);
+
+	        Shell parent = activeWorkbenchWindow.getShell();
+	        WizardDialog dialog = new WizardDialog(parent, wizard);
+	        dialog.create();
+	        dialog.getShell().setSize(
+	                Math.max(SIZING_WIZARD_WIDTH, dialog.getShell().getSize().x),
+	                SIZING_WIZARD_HEIGHT);
+	        activeWorkbenchWindow.getWorkbench().getHelpSystem().setHelp(
+					dialog.getShell(), IWorkbenchHelpContextIds.IMPORT_WIZARD);
+	        dialog.open();
+		}
+
+	}
+
+	/**
+	 * Default handler for launching new wizards.
+	 */
+	public static final class New extends WizardHandler {
+
+		/**
+	     * The wizard dialog width
+	     */
+	    private static final int SIZING_WIZARD_WIDTH = 500;
+
+	    /**
+	     * The wizard dialog height
+	     */
+	    private static final int SIZING_WIZARD_HEIGHT = 500;
+
+	    /**
+	     * The id of the category to show or <code>null</code> to
+	     * show all the categories.
+	     */
+	    private String categoryId = null;
+
+		@Override
+		protected String getWizardIdParameterId() {
+			return IWorkbenchCommandConstants.FILE_NEW_PARM_WIZARDID;
+		}
+
+		@Override
+		protected IWizardRegistry getWizardRegistry() {
+			return PlatformUI.getWorkbench().getNewWizardRegistry();
+		}
+
+	    /**
+	     * Returns the id of the category of wizards to show
+	     * or <code>null</code> to show all categories.
+	     * @return String
+	     */
+	    public String getCategoryId() {
+	        return categoryId;
+	    }
+
+	    /**
+	     * Sets the id of the category of wizards to show
+	     * or <code>null</code> to show all categories.
+	     * @param id
+	     */
+	    public void setCategoryId(String id) {
+	        categoryId = id;
+	    }
+
+	    @Override
+		protected IStructuredSelection getSelectionToUse(ExecutionEvent event) {
+	        ISelection selection = HandlerUtil.getCurrentSelection(event);
+	        IStructuredSelection selectionToPass = StructuredSelection.EMPTY;
+	        if (selection instanceof IStructuredSelection) {
+	            selectionToPass = (IStructuredSelection) selection;
+	        } else {
+	            // @issue the following is resource-specific legacy code
+	            // Build the selection from the IFile of the editor
+	            Class resourceClass = LegacyResourceSupport.getResourceClass();
+	            if (resourceClass != null) {
+	            	IWorkbenchWindow activeWorkbenchWindow = HandlerUtil.getActiveWorkbenchWindow(event);
+	                IWorkbenchPart part = activeWorkbenchWindow.getPartService()
+	                        .getActivePart();
+	                if (part instanceof IEditorPart) {
+	                    IEditorInput input = ((IEditorPart) part).getEditorInput();
+						Object resource = Adapters.adapt(input, resourceClass);
+	                    if (resource != null) {
+	                        selectionToPass = new StructuredSelection(resource);
+	                    }
+	                }
+	            }
+	        }
+	        return selectionToPass;
+	    }
+
+		@Override
+		protected void executeHandler(ExecutionEvent event) {
+			IWorkbenchWindow activeWorkbenchWindow = HandlerUtil.getActiveWorkbenchWindow(event);
+	        if (activeWorkbenchWindow == null) {
+	            // action has been disposed
+	            return;
+	        }
+	        NewWizard wizard = new NewWizard();
+	        wizard.setCategoryId(categoryId);
+
+			IStructuredSelection selectionToPass = getSelectionToUse(event);
+	        wizard.init(activeWorkbenchWindow.getWorkbench(), selectionToPass);
+
+	        IDialogSettings workbenchSettings = WorkbenchPlugin.getDefault()
+	                .getDialogSettings();
+	        IDialogSettings wizardSettings = workbenchSettings
+	                .getSection("NewWizardAction"); //$NON-NLS-1$
+	        if (wizardSettings == null) {
+				wizardSettings = workbenchSettings.addNewSection("NewWizardAction"); //$NON-NLS-1$
+			}
+	        wizard.setDialogSettings(wizardSettings);
+	        wizard.setForcePreviousAndNextButtons(true);
+
+	        Shell parent = activeWorkbenchWindow.getShell();
+	        WizardDialog dialog = new WizardDialog(parent, wizard);
+	        dialog.create();
+	        dialog.getShell().setSize(
+	                Math.max(SIZING_WIZARD_WIDTH, dialog.getShell().getSize().x),
+	                SIZING_WIZARD_HEIGHT);
+	        activeWorkbenchWindow.getWorkbench().getHelpSystem().setHelp(
+					dialog.getShell(), IWorkbenchHelpContextIds.NEW_WIZARD);
+	        dialog.open();
+		}
+
+	}
+
+
+	/**
+	 * This is the execution of the handler to open a wizard dialog.
+	 * @param event
+	 */
+	protected abstract void executeHandler(ExecutionEvent event);
+
+	@Override
+	public Object execute(ExecutionEvent event) throws ExecutionException {
+
+		String wizardId = event.getParameter(getWizardIdParameterId());
+
+		IWorkbenchWindow activeWindow = HandlerUtil
+				.getActiveWorkbenchWindowChecked(event);
+
+		if (wizardId == null) {
+			executeHandler(event);
+		} else {
+
+			IWizardRegistry wizardRegistry = getWizardRegistry();
+			IWizardDescriptor wizardDescriptor = wizardRegistry
+					.findWizard(wizardId);
+			if (wizardDescriptor == null) {
+				throw new ExecutionException("unknown wizard: " + wizardId); //$NON-NLS-1$
+			}
+
+			try {
+				IWorkbenchWizard wizard = wizardDescriptor.createWizard();
+				wizard.init(PlatformUI.getWorkbench(), getSelectionToUse(event));
+
+				if (wizardDescriptor.canFinishEarly() && !wizardDescriptor.hasPages()) {
+					wizard.performFinish();
+					return null;
+				}
+
+				Shell parent = activeWindow.getShell();
+				WizardDialog dialog = new WizardDialog(parent, wizard);
+				dialog.create();
+				dialog.open();
+
+			} catch (CoreException ex) {
+				throw new ExecutionException("error creating wizard", ex); //$NON-NLS-1$
+			}
+
+		}
+
+		return null;
+	}
+
+	/**
+	 * Returns a structured selection based on the event to initialize the
+	 * wizard with.
+	 * @param event the event object containing information about the current state of the application
+	 * @return the current structured selection of the application
+	 */
+	protected IStructuredSelection getSelectionToUse(ExecutionEvent event) {
+		ISelection selection = HandlerUtil.getCurrentSelection(event);
+		if (selection instanceof IStructuredSelection) {
+			return (IStructuredSelection) selection;
+		}
+		return StructuredSelection.EMPTY;
+	}
+
+	@Override
+	public void updateElement(UIElement element, Map parameters) {
+
+		String wizardId = (String) parameters.get(getWizardIdParameterId());
+		if (wizardId == null)
+			return;
+		IWizardDescriptor wizard = getWizardRegistry().findWizard(wizardId);
+		if (wizard != null) {
+			element.setText(NLS.bind(WorkbenchMessages.get().WizardHandler_menuLabel, wizard.getLabel()));
+			element.setTooltip(wizard.getDescription());
+			element.setIcon(wizard.getImageDescriptor());
+		}
+	}
+
+	/**
+	 * Returns the id of the parameter used to indicate which wizard this
+	 * command should launch.
+	 *
+	 * @return The id of the parameter used to indicate which wizard this
+	 *         command should launch.
+	 */
+	protected abstract String getWizardIdParameterId();
+
+	/**
+	 * Returns the wizard registry for the concrete <code>WizardHandler</code>
+	 * implementation class.
+	 *
+	 * @return The wizard registry for the concrete <code>WizardHandler</code>
+	 *         implementation class.
+	 */
+	protected abstract IWizardRegistry getWizardRegistry();
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/WorkbenchWindowHandlerDelegate.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/WorkbenchWindowHandlerDelegate.java
new file mode 100644
index 0000000..b34d5cf
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/handlers/WorkbenchWindowHandlerDelegate.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.handlers;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.ui.IWorkbenchWindow;
+
+/**
+ * A handler that can be used to imitate a IWorkbenchWindowActionDelegate.
+ *
+ * @since 3.1
+ */
+public abstract class WorkbenchWindowHandlerDelegate extends
+		ExecutableExtensionHandler implements IWorkbenchWindowHandlerDelegate {
+
+	/**
+	 * By default, this will do nothing. Subclasses may override.
+	 *
+	 * @param window
+	 *            the window that provides the context for this delegate
+	 * @see org.eclipse.ui.IWorkbenchWindowActionDelegate#init(IWorkbenchWindow)
+	 */
+	@Override
+	public void init(final IWorkbenchWindow window) {
+		// Do nothing by default.
+	}
+
+	/**
+	 * This simply calls execute with a <code>null</code> map of parameter
+	 * values. If an <code>ExecutionException</code> occurs, then this should
+	 * be handle somehow. It's not clear what we'll do yet.
+	 *
+	 * @param action
+	 *            The action proxy that handles the presentation portion of the
+	 *            action
+	 * @see org.eclipse.ui.IActionDelegate#run(IAction)
+	 */
+	@Override
+	public void run(final IAction action) {
+		try {
+			execute(new ExecutionEvent());
+		} catch (final ExecutionException e) {
+			// TODO Do something meaningful and poignant.
+		}
+	}
+
+	/**
+	 * By default, this will do nothing. Subclasses may override.
+	 *
+	 * @param action
+	 *            The action proxy that handles presentation portion of the
+	 *            action
+	 * @param selection
+	 *            The current selection, or <code>null</code> if there is no
+	 *            selection.
+	 *
+	 * @see org.eclipse.ui.IActionDelegate#selectionChanged(IAction, ISelection)
+	 */
+	@Override
+	public void selectionChanged(IAction action, ISelection selection) {
+		// Do nothing be default.
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/help/CommandHelpServiceImpl.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/help/CommandHelpServiceImpl.java
new file mode 100644
index 0000000..d610f98
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/help/CommandHelpServiceImpl.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (c) 2014, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ ******************************************************************************/
+package org.eclipse.ui.internal.help;
+
+import java.util.Map;
+import java.util.WeakHashMap;
+import javax.inject.Inject;
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.core.internal.commands.util.Util;
+import org.eclipse.e4.core.commands.ECommandService;
+import org.eclipse.e4.core.commands.internal.HandlerServiceImpl;
+import org.eclipse.e4.core.commands.internal.ICommandHelpService;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.di.annotations.Optional;
+import org.eclipse.e4.core.services.log.Logger;
+import org.eclipse.ui.internal.handlers.E4HandlerProxy;
+
+/**
+ * @since 3.5
+ */
+@SuppressWarnings("restriction")
+public class CommandHelpServiceImpl implements ICommandHelpService {
+
+	@Inject
+	private ECommandService commandService;
+
+	@Inject
+	@Optional
+	private Logger logger;
+
+	private Map<IHandler, String> helpContextIdsByHandler = new WeakHashMap<>();
+
+	@Override
+	public String getHelpContextId(String commandId, IEclipseContext context) {
+		if (commandId == null || context == null) {
+			return null;
+		}
+
+		Command command = commandService.getCommand(commandId);
+		if (!command.isDefined()) {
+			if (logger != null) {
+				logger.error("The command " + commandId //$NON-NLS-1$
+						+ " is not defined. Help context ID cannot be determined."); //$NON-NLS-1$
+			}
+			return null;
+		}
+
+		IHandler handler = null;
+		Object obj = HandlerServiceImpl.lookUpHandler(context, commandId);
+		if (obj instanceof IHandler) {
+			handler = (IHandler) obj;
+		}
+		if (handler instanceof E4HandlerProxy) {
+			handler = ((E4HandlerProxy) handler).getHandler();
+		}
+		String contextId = null;
+		if (handler != null) {
+			contextId = helpContextIdsByHandler.get(handler);
+		}
+		if (contextId == null) {
+			contextId = Util.getHelpContextId(command);
+		}
+		return contextId;
+	}
+
+	@Override
+	public void setHelpContextId(IHandler handler, String contextId) {
+		helpContextIdsByHandler.put(handler, contextId);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/help/HelpServiceImpl.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/help/HelpServiceImpl.java
new file mode 100644
index 0000000..c451ee8
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/help/HelpServiceImpl.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2014, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 445723, 445600
+ ******************************************************************************/
+
+package org.eclipse.ui.internal.help;
+
+import org.eclipse.e4.ui.services.help.EHelpService;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+
+public class HelpServiceImpl implements EHelpService {
+
+	@Override
+	public void displayHelp(String contextId) {
+		if (contextId != null) {
+			WorkbenchHelpSystem.getInstance().displayHelp(contextId);
+		}
+	}
+
+	/**
+	 * IDE implementation delegates to {@link WorkbenchHelpSystem}
+	 */
+	@Override
+	public void setHelp(Object helpTarget, String helpContextId) {
+		if (helpTarget instanceof Control) {
+			WorkbenchHelpSystem.getInstance().setHelp((Control) helpTarget, helpContextId);
+		} else if (helpTarget instanceof IAction) {
+			WorkbenchHelpSystem.getInstance().setHelp((IAction) helpTarget, helpContextId);
+		} else if (helpTarget instanceof Menu) {
+			WorkbenchHelpSystem.getInstance().setHelp((Menu) helpTarget, helpContextId);
+		} else if (helpTarget instanceof MenuItem) {
+			WorkbenchHelpSystem.getInstance().setHelp((MenuItem) helpTarget, helpContextId);
+		}
+
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/help/WorkbenchHelpSystem.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/help/WorkbenchHelpSystem.java
new file mode 100644
index 0000000..960354a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/help/WorkbenchHelpSystem.java
@@ -0,0 +1,1031 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2016 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
+ *     Chris Austin (IBM) - Fix for bug 296042
+ *******************************************************************************/
+package org.eclipse.ui.internal.help;
+
+import java.net.URL;
+import java.util.Hashtable;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
+import org.eclipse.help.HelpSystem;
+import org.eclipse.help.IContext;
+import org.eclipse.help.IContext2;
+import org.eclipse.help.IHelp;
+import org.eclipse.help.IHelpResource;
+import org.eclipse.help.IToc;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.LegacyActionTools;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.swt.events.HelpEvent;
+import org.eclipse.swt.events.HelpListener;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.commands.ICommand;
+import org.eclipse.ui.help.AbstractHelpUI;
+import org.eclipse.ui.help.IContextComputer;
+import org.eclipse.ui.help.IWorkbenchHelpSystem;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+
+/**
+ * This class represents a refactoring of the functionality previously contained
+ * in <code>WorkbenchHelp</code>.
+ *
+ * @since 3.1
+ */
+public final class WorkbenchHelpSystem implements IWorkbenchHelpSystem {
+
+	/**
+	 * Key used for stashing help-related data on SWT widgets.
+	 *
+	 * @see org.eclipse.swt.widgets.Widget#getData(java.lang.String)
+	 */
+	public static final String HELP_KEY = "org.eclipse.ui.help";//$NON-NLS-1$
+
+	/**
+     * Id of extension point where the help UI is contributed.
+     */
+     // RAP [bm] namespace
+//  private static final String HELP_SYSTEM_EXTENSION_ID = PlatformUI.PLUGIN_ID + '.' + IWorkbenchRegistryConstants.PL_HELPSUPPORT;  
+    private static final String HELP_SYSTEM_EXTENSION_ID = PlatformUI.PLUGIN_EXTENSION_NAME_SPACE + '.' + IWorkbenchRegistryConstants.PL_HELPSUPPORT;
+
+	/**
+	 * Attribute id for class attribute of help UI extension point.
+	 */
+	private static final String HELP_SYSTEM_CLASS_ATTRIBUTE = "class";//$NON-NLS-1$
+
+	/**
+	 * Singleton.
+	 */
+	private static WorkbenchHelpSystem instance;
+
+	/**
+	 * The help listener.
+	 */
+	private static class WorkbenchHelpListener implements HelpListener {
+		@Override
+		public void helpRequested(HelpEvent event) {
+
+			if (getInstance().getHelpUI() == null) {
+				return;
+			}
+
+			// get the help context from the widget
+			Object object = event.widget.getData(HELP_KEY);
+
+			// Since 2.0 we can expect that object is a String, however
+			// for backward compatability we handle context computers and
+			// arrays.
+			IContext context = null;
+			if (object instanceof String) {
+				// context id - this is the norm
+				context = HelpSystem.getContext((String) object);
+			} else if (object instanceof IContext) {
+				// already resolved context (pre 2.0)
+				context = (IContext) object;
+			} else if (object instanceof IContextComputer) {
+				// a computed context (pre 2.0) - compute it now
+				Object[] helpContexts = ((IContextComputer) object)
+						.computeContexts(event);
+				// extract the first entry
+				if (helpContexts != null && helpContexts.length > 0) {
+					Object primaryEntry = helpContexts[0];
+					if (primaryEntry instanceof String) {
+						context = HelpSystem.getContext((String) primaryEntry);
+					} else if (primaryEntry instanceof IContext) {
+						context = (IContext) primaryEntry;
+					}
+				}
+			} else if (object instanceof Object[]) {
+				// mixed array of String or IContext (pre 2.0) - extract the
+				// first entry
+				Object[] helpContexts = (Object[]) object;
+				// extract the first entry
+				if (helpContexts.length > 0) {
+					Object primaryEntry = helpContexts[0];
+					if (primaryEntry instanceof String) {
+						context = HelpSystem.getContext((String) primaryEntry);
+					} else if (primaryEntry instanceof IContext) {
+						context = (IContext) primaryEntry;
+					}
+				}
+			}
+
+			/*
+			 * If can't find it, show the "context is missing" context.
+			 */
+			if (context == null) {
+				context = HelpSystem.getContext(IWorkbenchHelpContextIds.MISSING);
+			}
+
+			if (context != null) {
+				// determine a location in the upper right corner of the
+				// widget
+				Point point = computePopUpLocation(event.widget.getDisplay());
+				// display the help
+				getInstance().displayContext(context, point.x, point.y);
+			}
+		}
+	}
+
+	/**
+	 * Whether the help system has been initialized.
+	 */
+	private boolean isInitialized;
+
+	/**
+	 * Pluggable help UI, or <code>null</code> if none (or unknown).
+	 */
+	private AbstractHelpUI pluggableHelpUI = null;
+
+	/**
+	 * The id of the help extension that should be used. This is used only for
+	 * debugging purposes.
+	 */
+	private String desiredHelpSystemId;
+
+	/**
+	 * Table for tracing registered context ids. This is used only for debugging
+	 * purposes.
+	 *
+	 */
+	private Hashtable registeredIDTable;
+
+	/**
+	 * Handles dynamic removal of the help system.
+	 *
+	 * @since 3.1
+	 */
+    private IExtensionChangeHandler handler = new IExtensionChangeHandler() {
+
+    	@Override
+		public void addExtension(IExtensionTracker tracker,IExtension extension) {
+            //Do nothing
+        }
+
+        @Override
+		public void removeExtension(IExtension source, Object[] objects) {
+            for (Object object : objects) {
+                if (object == pluggableHelpUI) {
+                    isInitialized = false;
+                    pluggableHelpUI = null;
+                    helpCompatibilityWrapper = null;
+                    // remove ourselves - we'll be added again in initalize if
+                    // needed
+                    PlatformUI.getWorkbench().getExtensionTracker()
+							.unregisterHandler(handler);
+                }
+            }
+        }
+    };
+
+	/**
+	 * Compatibility implementation of old IHelp interface.
+	 * WorkbenchHelp.getHelpSupport and IHelp were deprecated in 3.0.
+	 */
+	private class CompatibilityIHelpImplementation implements IHelp {
+
+		/** @deprecated */
+		@Deprecated
+		@Override
+		public void displayHelp() {
+			// real method - forward to help UI if available
+			AbstractHelpUI helpUI = getHelpUI();
+			if (helpUI != null) {
+				helpUI.displayHelp();
+			}
+		}
+
+		/** @deprecated */
+		@Deprecated
+		@Override
+		public void displayContext(IContext context, int x, int y) {
+			// real method - forward to help UI if available
+			AbstractHelpUI helpUI = getHelpUI();
+			if (helpUI != null) {
+				helpUI.displayContext(context, x, y);
+			}
+		}
+
+		/** @deprecated */
+		@Deprecated
+		@Override
+		public void displayContext(String contextId, int x, int y) {
+			// convenience method - funnel through the real method
+			IContext context = HelpSystem.getContext(contextId);
+			if (context != null) {
+				displayContext(context, x, y);
+			}
+		}
+
+		/** @deprecated */
+		@Deprecated
+		@Override
+		public void displayHelpResource(String href) {
+			// real method - forward to help UI if available
+			AbstractHelpUI helpUI = getHelpUI();
+			if (helpUI != null) {
+				helpUI.displayHelpResource(href);
+			}
+		}
+
+		/** @deprecated */
+		@Deprecated
+		@Override
+		public void displayHelpResource(IHelpResource helpResource) {
+			// convenience method - funnel through the real method
+			displayHelpResource(helpResource.getHref());
+		}
+
+		/** @deprecated */
+		@Deprecated
+		@Override
+		public void displayHelp(String toc) {
+			// deprecated method - funnel through the real method
+			displayHelpResource(toc);
+		}
+
+		/** @deprecated */
+		@Deprecated
+		@Override
+		public void displayHelp(String toc, String selectedTopic) {
+			// deprecated method - funnel through the real method
+			displayHelpResource(selectedTopic);
+		}
+
+		/** @deprecated */
+		@Deprecated
+		@Override
+		public void displayHelp(String contextId, int x, int y) {
+			// deprecated method - funnel through the real method
+			displayContext(contextId, x, y);
+		}
+
+		/** @deprecated */
+		@Deprecated
+		@Override
+		public void displayHelp(IContext context, int x, int y) {
+			// deprecated method - funnel through the real method
+			displayContext(context, x, y);
+		}
+
+		/** @deprecated */
+		@Deprecated
+		@Override
+		public IContext getContext(String contextId) {
+			// non-UI method - forward to HelpSystem
+			return HelpSystem.getContext(contextId);
+		}
+
+		/** @deprecated */
+		@Deprecated
+		@Override
+		public IToc[] getTocs() {
+			// non-UI method - forward to HelpSystem
+			return HelpSystem.getTocs();
+		}
+
+		/** @deprecated */
+		@Deprecated
+		@Override
+		public boolean isContextHelpDisplayed() {
+			// real method - forward to pluggedhelp UI
+			return WorkbenchHelpSystem.this.isContextHelpDisplayed();
+		}
+	}
+
+	/**
+	 * A wrapper for action help context that passes the action
+	 * text to be used as a title.
+	 * @since 3.1
+	 */
+	private static class ContextWithTitle implements IContext2 {
+		private IContext context;
+		private String title;
+
+		ContextWithTitle(IContext context, String title) {
+			this.context = context;
+			this.title = title;
+		}
+
+		@Override
+		public String getTitle() {
+			if (context instanceof IContext2) {
+				String ctitle = ((IContext2)context).getTitle();
+				if (ctitle!=null) {
+					return ctitle;
+				}
+			}
+			return title;
+		}
+
+		@Override
+		public String getStyledText() {
+			if (context instanceof IContext2) {
+				return ((IContext2)context).getStyledText();
+			}
+			return context.getText();
+		}
+
+		@Override
+		public String getCategory(IHelpResource topic) {
+			if (context instanceof IContext2) {
+				return ((IContext2)context).getCategory(topic);
+			}
+			return null;
+		}
+
+		@Override
+		public IHelpResource[] getRelatedTopics() {
+			return context.getRelatedTopics();
+		}
+
+		@Override
+		public String getText() {
+			return context.getText();
+		}
+	}
+
+	/**
+	 * Compatibility wrapper, or <code>null</code> if none. Do not access
+	 * directly; see getHelpSupport().
+	 */
+	private IHelp helpCompatibilityWrapper = null;
+
+	/**
+	 * The listener to attach to various widgets.
+	 */
+	private static HelpListener helpListener;
+
+	/**
+	 * For debug purposes only.
+	 *
+	 * @return the desired help system id
+	 */
+	public String getDesiredHelpSystemId() {
+		return desiredHelpSystemId;
+	}
+
+	/**
+	 * For debug purposes only.
+	 *
+	 * @param desiredHelpSystemId the desired help system id
+	 */
+	public void setDesiredHelpSystemId(String desiredHelpSystemId) {
+		dispose(); // prep for a new help system
+		this.desiredHelpSystemId = desiredHelpSystemId;
+	}
+
+	/**
+	 * Singleton Constructor.
+	 */
+	private WorkbenchHelpSystem() {
+	}
+
+	/**
+	 * Return the singleton instance of this class.
+	 *
+	 * @return the singleton instance
+	 */
+	public static WorkbenchHelpSystem getInstance() {
+		if (instance == null) {
+			instance = new WorkbenchHelpSystem();
+		}
+
+		return instance;
+	}
+
+	/**
+	 * Disposed of the singleton of this class if it has been created.
+	 */
+	public static void disposeIfNecessary() {
+		if (instance != null) {
+			instance.dispose();
+			instance = null;
+		}
+	}
+
+	/**
+	 * Dispose of any resources allocated by this instance.
+	 */
+	public void dispose() {
+		pluggableHelpUI = null;
+		helpCompatibilityWrapper = null;
+		isInitialized = false;
+		PlatformUI.getWorkbench().getExtensionTracker()
+				.unregisterHandler(handler);
+	}
+
+	/**
+	 * Returns the help UI for the platform, if available. This method will
+	 * initialize the help UI if necessary.
+	 *
+	 * @return the help UI, or <code>null</code> if none
+	 */
+	private AbstractHelpUI getHelpUI() {
+		if (!isInitialized) {
+			isInitialized = initializePluggableHelpUI();
+		}
+		return pluggableHelpUI;
+	}
+
+	/**
+	 * Initializes the pluggable help UI by getting an instance via the
+	 * extension point.
+	 */
+	private boolean initializePluggableHelpUI() {
+		final boolean[] ret = new boolean[] { false };
+
+		BusyIndicator.showWhile(Display.getCurrent(), new Runnable() {
+
+			@Override
+			public void run() {
+				// get the help UI extension from the registry
+				IExtensionPoint point = Platform.getExtensionRegistry()
+						.getExtensionPoint(HELP_SYSTEM_EXTENSION_ID);
+				if (point == null) {
+					// our extension point is missing (!) - act like there was
+					// no help UI
+					return;
+				}
+				IExtension[] extensions = point.getExtensions();
+				if (extensions.length == 0) {
+					// no help UI present
+					return;
+				}
+
+				IConfigurationElement elementToUse = null;
+				if (desiredHelpSystemId == null) {
+					elementToUse = getFirstElement(extensions);
+				} else {
+					elementToUse = findElement(desiredHelpSystemId, extensions);
+				}
+
+				if (elementToUse != null) {
+					ret[0] = initializePluggableHelpUI(elementToUse);
+				}
+			}
+
+			private IConfigurationElement findElement(
+					String desiredHelpSystemId, IExtension[] extensions) {
+				for (IExtension extension : extensions) {
+					if (desiredHelpSystemId.equals(extension.getUniqueIdentifier())) {
+						IConfigurationElement[] elements = extension
+								.getConfigurationElements();
+						if (elements.length == 0) {
+							// help UI present but mangled - act like there was
+							// no help
+							// UI
+							return null;
+						}
+						return elements[0];
+					}
+
+				}
+				return null;
+			}
+
+			private IConfigurationElement getFirstElement(
+					IExtension[] extensions) {
+				// There should only be one extension/config element so we just
+				// take the first
+				IConfigurationElement[] elements = extensions[0]
+						.getConfigurationElements();
+				if (elements.length == 0) {
+					// help UI present but mangled - act like there was no help
+					// UI
+					return null;
+				}
+				return elements[0];
+			}
+
+			private boolean initializePluggableHelpUI(
+					IConfigurationElement element) {
+				// Instantiate the help UI
+				try {
+					pluggableHelpUI = (AbstractHelpUI) WorkbenchPlugin
+							.createExtension(element,
+									HELP_SYSTEM_CLASS_ATTRIBUTE);
+					// start listening for removals
+					PlatformUI.getWorkbench().getExtensionTracker()
+							.registerHandler(handler, null);
+					// register the new help UI for removal notification
+					PlatformUI
+							.getWorkbench()
+							.getExtensionTracker()
+							.registerObject(element.getDeclaringExtension(),
+									pluggableHelpUI, IExtensionTracker.REF_WEAK);
+					return true;
+				} catch (CoreException e) {
+					WorkbenchPlugin.log(
+							"Unable to instantiate help UI" + e.getStatus(), e);//$NON-NLS-1$
+				}
+				return false;
+			}
+
+		});
+		return ret[0];
+	}
+
+	/**
+	 * Determines the location for the help popup shell given the widget which
+	 * orginated the request for help.
+	 *
+	 * @param display
+	 *            the display where the help will appear
+	 */
+	private static Point computePopUpLocation(Display display) {
+		Point point = display.getCursorLocation();
+		return new Point(point.x + 15, point.y);
+	}
+
+	/**
+	 * Returns the help listener which activates the help support system.
+	 *
+	 * @return the help listener
+	 */
+	private HelpListener getHelpListener() {
+		if (helpListener == null) {
+			helpListener = new WorkbenchHelpListener();
+		}
+		return helpListener;
+	}
+
+	/**
+	 * Returns the help support system for the platform, if available.
+	 *
+	 * @return the help support system, or <code>null</code> if none
+	 * @deprecated Use the static methods on this class and on
+	 *             {@link org.eclipse.help.HelpSystem HelpSystem}instead of the
+	 *             IHelp methods on the object returned by this method.
+	 */
+	@Deprecated
+	public IHelp getHelpSupport() {
+		AbstractHelpUI helpUI = getHelpUI();
+		if (helpUI != null && helpCompatibilityWrapper == null) {
+			// create instance only once, and only if needed
+			helpCompatibilityWrapper = new CompatibilityIHelpImplementation();
+		}
+		return helpCompatibilityWrapper;
+
+	}
+
+	/**
+	 * Sets the given help contexts on the given action.
+	 * <p>
+	 * Use this method when the list of help contexts is known in advance. Help
+	 * contexts can either supplied as a static list, or calculated with a
+	 * context computer (but not both).
+	 * </p>
+	 *
+	 * @param action
+	 *            the action on which to register the computer
+	 * @param contexts
+	 *            the contexts to use when F1 help is invoked; a mixed-type
+	 *            array of context ids (type <code>String</code>) and/or help
+	 *            contexts (type <code>IContext</code>)
+	 * @deprecated use setHelp with a single context id parameter
+	 */
+	@Deprecated
+	public void setHelp(IAction action, final Object[] contexts) {
+		for (Object context : contexts) {
+			Assert.isTrue(context instanceof String
+					|| context instanceof IContext);
+		}
+		action.setHelpListener(event -> {
+			if (contexts != null && contexts.length > 0
+					&& getHelpUI() != null) {
+				// determine the context
+				IContext context = null;
+				if (contexts[0] instanceof String) {
+					context = HelpSystem.getContext((String) contexts[0]);
+				} else if (contexts[0] instanceof IContext) {
+					context = (IContext) contexts[0];
+				}
+				if (context != null) {
+					Point point = computePopUpLocation(event.widget
+							.getDisplay());
+					displayContext(context, point.x, point.y);
+				}
+			}
+		});
+	}
+
+	/**
+	 * Sets the given help context computer on the given action.
+	 * <p>
+	 * Use this method when the help contexts cannot be computed in advance.
+	 * Help contexts can either supplied as a static list, or calculated with a
+	 * context computer (but not both).
+	 * </p>
+	 *
+	 * @param action
+	 *            the action on which to register the computer
+	 * @param computer
+	 *            the computer to determine the help contexts for the control
+	 *            when F1 help is invoked
+	 * @deprecated context computers are no longer supported, clients should
+	 *             implement their own help listener
+	 */
+	@Deprecated
+	public void setHelp(IAction action, final IContextComputer computer) {
+		action.setHelpListener(event -> {
+			Object[] helpContexts = computer.computeContexts(event);
+			if (helpContexts != null && helpContexts.length > 0
+					&& getHelpUI() != null) {
+				// determine the context
+				IContext context = null;
+				if (helpContexts[0] instanceof String) {
+					context = HelpSystem
+							.getContext((String) helpContexts[0]);
+				} else if (helpContexts[0] instanceof IContext) {
+					context = (IContext) helpContexts[0];
+				}
+				if (context != null) {
+					Point point = computePopUpLocation(event.widget
+							.getDisplay());
+					displayContext(context, point.x, point.y);
+				}
+			}
+		});
+	}
+
+	/**
+	 * Sets the given help contexts on the given control.
+	 * <p>
+	 * Use this method when the list of help contexts is known in advance. Help
+	 * contexts can either supplied as a static list, or calculated with a
+	 * context computer (but not both).
+	 * </p>
+	 *
+	 * @param control
+	 *            the control on which to register the contexts
+	 * @param contexts
+	 *            the contexts to use when F1 help is invoked; a mixed-type
+	 *            array of context ids (type <code>String</code>) and/or help
+	 *            contexts (type <code>IContext</code>)
+	 * @deprecated use setHelp with single context id parameter
+	 */
+	@Deprecated
+	public void setHelp(Control control, Object[] contexts) {
+		for (Object context : contexts) {
+			Assert.isTrue(context instanceof String
+					|| context instanceof IContext);
+		}
+
+		control.setData(HELP_KEY, contexts);
+		// ensure that the listener is only registered once
+		control.removeHelpListener(getHelpListener());
+		control.addHelpListener(getHelpListener());
+	}
+
+	/**
+	 * Sets the given help context computer on the given control.
+	 * <p>
+	 * Use this method when the help contexts cannot be computed in advance.
+	 * Help contexts can either supplied as a static list, or calculated with a
+	 * context computer (but not both).
+	 * </p>
+	 *
+	 * @param control
+	 *            the control on which to register the computer
+	 * @param computer
+	 *            the computer to determine the help contexts for the control
+	 *            when F1 help is invoked
+	 * @deprecated context computers are no longer supported, clients should
+	 *             implement their own help listener
+	 */
+	@Deprecated
+	public void setHelp(Control control, IContextComputer computer) {
+		control.setData(HELP_KEY, computer);
+		// ensure that the listener is only registered once
+		control.removeHelpListener(getHelpListener());
+		control.addHelpListener(getHelpListener());
+	}
+
+	/**
+	 * Sets the given help contexts on the given menu.
+	 * <p>
+	 * Use this method when the list of help contexts is known in advance. Help
+	 * contexts can either supplied as a static list, or calculated with a
+	 * context computer (but not both).
+	 * </p>
+	 *
+	 * @param menu
+	 *            the menu on which to register the context
+	 * @param contexts
+	 *            the contexts to use when F1 help is invoked; a mixed-type
+	 *            array of context ids (type <code>String</code>) and/or help
+	 *            contexts (type <code>IContext</code>)
+	 * @deprecated use setHelp with single context id parameter
+	 */
+	@Deprecated
+	public void setHelp(Menu menu, Object[] contexts) {
+		for (Object context : contexts) {
+			Assert.isTrue(context instanceof String
+					|| context instanceof IContext);
+		}
+		menu.setData(HELP_KEY, contexts);
+		// ensure that the listener is only registered once
+		menu.removeHelpListener(getHelpListener());
+		menu.addHelpListener(getHelpListener());
+	}
+
+	/**
+	 * Sets the given help context computer on the given menu.
+	 * <p>
+	 * Use this method when the help contexts cannot be computed in advance.
+	 * Help contexts can either supplied as a static list, or calculated with a
+	 * context computer (but not both).
+	 * </p>
+	 *
+	 * @param menu
+	 *            the menu on which to register the computer
+	 * @param computer
+	 *            the computer to determine the help contexts for the control
+	 *            when F1 help is invoked
+	 * @deprecated context computers are no longer supported, clients should
+	 *             implement their own help listener
+	 */
+	@Deprecated
+	public void setHelp(Menu menu, IContextComputer computer) {
+		menu.setData(HELP_KEY, computer);
+		// ensure that the listener is only registered once
+		menu.removeHelpListener(getHelpListener());
+		menu.addHelpListener(getHelpListener());
+	}
+
+	/**
+	 * Sets the given help contexts on the given menu item.
+	 * <p>
+	 * Use this method when the list of help contexts is known in advance. Help
+	 * contexts can either supplied as a static list, or calculated with a
+	 * context computer (but not both).
+	 * </p>
+	 *
+	 * @param item
+	 *            the menu item on which to register the context
+	 * @param contexts
+	 *            the contexts to use when F1 help is invoked; a mixed-type
+	 *            array of context ids (type <code>String</code>) and/or help
+	 *            contexts (type <code>IContext</code>)
+	 * @deprecated use setHelp with single context id parameter
+	 */
+	@Deprecated
+	public void setHelp(MenuItem item, Object[] contexts) {
+		for (Object context : contexts) {
+			Assert.isTrue(context instanceof String
+					|| context instanceof IContext);
+		}
+		item.setData(HELP_KEY, contexts);
+		// ensure that the listener is only registered once
+		item.removeHelpListener(getHelpListener());
+		item.addHelpListener(getHelpListener());
+	}
+
+	/**
+	 * Sets the given help context computer on the given menu item.
+	 * <p>
+	 * Use this method when the help contexts cannot be computed in advance.
+	 * Help contexts can either supplied as a static list, or calculated with a
+	 * context computer (but not both).
+	 * </p>
+	 *
+	 * @param item
+	 *            the menu item on which to register the computer
+	 * @param computer
+	 *            the computer to determine the help contexts for the control
+	 *            when F1 help is invoked
+	 * @deprecated context computers are no longer supported, clients should
+	 *             implement their own help listener
+	 */
+	@Deprecated
+	public void setHelp(MenuItem item, IContextComputer computer) {
+		item.setData(HELP_KEY, computer);
+		// ensure that the listener is only registered once
+		item.removeHelpListener(getHelpListener());
+		item.addHelpListener(getHelpListener());
+	}
+
+    /**
+     * Creates a new help listener for the given command. This retrieves the
+     * help context ID from the command, and creates an appropriate listener
+     * based on this.
+     *
+     * @param command
+     *            The command for which the listener should be created; must
+     *            not be <code>null</code>.
+     * @return A help listener; never <code>null</code>.
+     */
+	public HelpListener createHelpListener(ICommand command) {
+		// TODO Need a help ID from the context
+		// final String contextId = command.getHelpId();
+		final String contextId = ""; //$NON-NLS-1$
+		return event -> {
+			if (getHelpUI() != null) {
+				IContext context = HelpSystem.getContext(contextId);
+				if (context != null) {
+					Point point = computePopUpLocation(event.widget
+							.getDisplay());
+					displayContext(context, point.x, point.y);
+				}
+			}
+		};
+	}
+
+	@Override
+	public void displayHelp() {
+		AbstractHelpUI helpUI = getHelpUI();
+		if (helpUI != null) {
+			helpUI.displayHelp();
+		}
+	}
+
+	@Override
+	public void displaySearch() {
+		AbstractHelpUI helpUI = getHelpUI();
+		if (helpUI != null) {
+			helpUI.displaySearch();
+		}
+	}
+
+	@Override
+	public void displayDynamicHelp() {
+		AbstractHelpUI helpUI = getHelpUI();
+		if (helpUI != null) {
+			helpUI.displayDynamicHelp();
+		}
+	}
+
+	@Override
+	public void search(String expression) {
+		AbstractHelpUI helpUI = getHelpUI();
+		if (helpUI != null) {
+			helpUI.search(expression);
+		}
+	}
+
+	@Override
+	public URL resolve(String href, boolean documentOnly) {
+		AbstractHelpUI helpUI = getHelpUI();
+		if (helpUI != null) {
+			return helpUI.resolve(href, documentOnly);
+		}
+		return null;
+	}
+
+	@Override
+	public void displayContext(IContext context, int x, int y) {
+		if (context == null) {
+			throw new IllegalArgumentException();
+		}
+		AbstractHelpUI helpUI = getHelpUI();
+		if (helpUI != null) {
+			helpUI.displayContext(context, x, y);
+		}
+	}
+
+	@Override
+	public void displayHelpResource(String href) {
+		if (href == null) {
+			throw new IllegalArgumentException();
+		}
+		AbstractHelpUI helpUI = getHelpUI();
+		if (helpUI != null) {
+			helpUI.displayHelpResource(href);
+		}
+	}
+
+	@Override
+	public void displayHelp(String contextId) {
+		IContext context = HelpSystem.getContext(contextId);
+		if (context != null) {
+			Point point = computePopUpLocation(Display.getCurrent());
+			displayContext(context, point.x, point.y);
+		}
+	}
+
+	@Override
+	public void displayHelp(IContext context) {
+		Point point = computePopUpLocation(Display.getCurrent());
+		AbstractHelpUI helpUI = getHelpUI();
+		if (helpUI != null) {
+			helpUI.displayContext(context, point.x, point.y);
+		}
+	}
+
+	@Override
+	public boolean isContextHelpDisplayed() {
+		if (!isInitialized) {
+			return false;
+		}
+		AbstractHelpUI helpUI = getHelpUI();
+		return helpUI != null && helpUI.isContextHelpDisplayed();
+	}
+
+	@Override
+	public void setHelp(final IAction action, final String contextId) {
+		if (WorkbenchPlugin.DEBUG)
+			setHelpTrace(contextId);
+		action.setHelpListener(event -> {
+			if (getHelpUI() != null) {
+				IContext context = HelpSystem.getContext(contextId);
+				if (context != null) {
+					Point point = computePopUpLocation(event.widget
+							.getDisplay());
+					String title = LegacyActionTools.removeMnemonics(action.getText());
+					displayContext(new ContextWithTitle(context, title), point.x, point.y);
+				}
+			}
+		});
+	}
+
+	@Override
+	public void setHelp(Control control, String contextId) {
+		if (WorkbenchPlugin.DEBUG)
+			setHelpTrace(contextId);
+		control.setData(HELP_KEY, contextId);
+		// ensure that the listener is only registered once
+		control.removeHelpListener(getHelpListener());
+		control.addHelpListener(getHelpListener());
+	}
+
+	@Override
+	public void setHelp(Menu menu, String contextId) {
+		if (WorkbenchPlugin.DEBUG)
+			setHelpTrace(contextId);
+		menu.setData(HELP_KEY, contextId);
+		// ensure that the listener is only registered once
+		menu.removeHelpListener(getHelpListener());
+		menu.addHelpListener(getHelpListener());
+	}
+
+	@Override
+	public void setHelp(MenuItem item, String contextId) {
+
+		if (WorkbenchPlugin.DEBUG)
+			setHelpTrace(contextId);
+
+		item.setData(HELP_KEY, contextId);
+		// ensure that the listener is only registered once
+		item.removeHelpListener(getHelpListener());
+		item.addHelpListener(getHelpListener());
+	}
+
+	/*
+	 * Traces all calls to the setHelp method in an attempt to find and report
+	 * duplicated context IDs.
+	 */
+	private void setHelpTrace(String contextId) {
+		// Create an unthrown exception to capture the stack trace
+		RuntimeException e = new RuntimeException();
+		StackTraceElement[] stackTrace = e.getStackTrace();
+		StackTraceElement currentElement = null;
+		for (int s = 0; s < stackTrace.length; s++) {
+			if (stackTrace[s].getMethodName().equals("setHelp") && s + 1 < stackTrace.length) //$NON-NLS-1$
+			{
+				currentElement = stackTrace[s + 1];
+				break;
+			}
+		}
+
+		if (registeredIDTable == null)
+			registeredIDTable = new Hashtable();
+
+		if (!registeredIDTable.containsKey(contextId))
+			registeredIDTable.put(contextId, currentElement);
+		else if (!registeredIDTable.get(contextId).equals(currentElement)) {
+			StackTraceElement initialElement = (StackTraceElement) registeredIDTable
+					.get(contextId);
+			String error = "UI Duplicate Context ID found: '" + contextId + "'\n" + //$NON-NLS-1$ //$NON-NLS-2$
+					" 1 at " + initialElement + '\n' + //$NON-NLS-1$
+					" 2 at " + currentElement; //$NON-NLS-1$
+
+			System.out.println(error);
+		}
+	}
+
+	@Override
+	public boolean hasHelpUI() {
+		return getHelpUI() != null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/intro/IIntroConstants.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/intro/IIntroConstants.java
new file mode 100644
index 0000000..6591807
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/intro/IIntroConstants.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.intro;
+
+/**
+ * Contains constants used by the intro implementation
+ *
+ * @since 3.0
+ */
+public interface IIntroConstants {
+
+    /**
+     * The id of the view that is used as the intro host.
+     */
+    public static final String INTRO_VIEW_ID = "org.eclipse.ui.internal.introview"; //$NON-NLS-1$
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/intro/IIntroDescriptor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/intro/IIntroDescriptor.java
new file mode 100644
index 0000000..0bc283d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/intro/IIntroDescriptor.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.intro;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.intro.IIntroPart;
+
+/**
+ * Describes an introduction extension.
+ *
+ * @since 3.0
+ */
+public interface IIntroDescriptor {
+
+    /**
+     * Creates an instance of the intro part defined in the descriptor.
+     */
+    IIntroPart createIntro() throws CoreException;
+
+    /**
+     * Returns the part id.
+     *
+     * @return the id of the part
+     */
+    public String getId();
+
+    /**
+     * Returns the descriptor of the image for this part.
+     *
+     * @return the descriptor of the image to display next to this part
+     */
+    public ImageDescriptor getImageDescriptor();
+
+    /**
+	 * Return the label override string for this part.
+	 *
+	 * @return the label override string or <code>null</code> if one has not
+	 *         been specified
+     * @since 3.2
+	 */
+	public String getLabelOverride();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/intro/IIntroRegistry.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/intro/IIntroRegistry.java
new file mode 100644
index 0000000..c92acb4
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/intro/IIntroRegistry.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.intro;
+
+/**
+ * Registry for introduction elements.
+ *
+ * @since 3.0
+ */
+public interface IIntroRegistry {
+
+    /**
+     * Return the number of introduction extensions known by this registry.
+     *
+     * @return the number of introduction extensions known by this registry
+     */
+    int getIntroCount();
+
+    /**
+     * Return the introduction extensions known by this registry.
+     *
+     * @return the introduction extensions known by this registry
+     */
+    IIntroDescriptor[] getIntros();
+
+    // RAP [bm]: no product support - using branding instead
+//  /**
+//   * Return the introduction extension that is bound to the given product.
+//   * 
+//   * @param productId the product identifier
+//   * @return the introduction extension that is bound to the given product, 
+//   * or <code>null</code> if there is no such binding
+//   */
+//  IIntroDescriptor getIntroForProduct(String productId);
+    /**
+     * Return the introduction extension that is bound to the given branding.
+     * 
+     * @param brandingId the product identifier
+     * @return the introduction extension that is bound to the given branding, 
+     * or <code>null</code> if there is no such binding
+     */
+    IIntroDescriptor getIntroForBranding(String brandingId);
+
+    // ENDRAP
+
+    /**
+     * Find an intro descriptor with the given identifier.
+     *
+     * @param id the id
+     * @return the intro descriptor, or <code>null</code>
+     */
+    IIntroDescriptor getIntro(String id);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/intro/IntroDescriptor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/intro/IntroDescriptor.java
new file mode 100644
index 0000000..01669de
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/intro/IntroDescriptor.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.intro;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.IPluginContribution;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.intro.IIntroPart;
+import org.eclipse.ui.intro.IntroContentDetector;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+/**
+ * Describes an introduction extension.
+ *
+ * @since 3.0
+ */
+public class IntroDescriptor implements IIntroDescriptor, IPluginContribution {
+
+
+    private IConfigurationElement element;
+
+    private ImageDescriptor imageDescriptor;
+
+    /**
+     * Create a new IntroDescriptor for an extension.
+     */
+    public IntroDescriptor(IConfigurationElement configElement)
+            throws CoreException {
+    	element = configElement;
+
+    	if (configElement.getAttribute(IWorkbenchRegistryConstants.ATT_CLASS) == null) {
+            throw new CoreException(new Status(IStatus.ERROR, configElement
+                    .getNamespace(), 0,
+                    "Invalid extension (Missing class name): " + getId(), //$NON-NLS-1$
+                    null));
+        }
+    }
+
+    @Override
+	public IIntroPart createIntro() throws CoreException {
+    	return (IIntroPart) element.createExecutableExtension(IWorkbenchRegistryConstants.ATT_CLASS);
+    }
+
+    public IntroContentDetector getIntroContentDetector() throws CoreException {
+    	if (element.getAttribute(IWorkbenchRegistryConstants.ATT_CONTENT_DETECTOR) == null) {
+    		return null;
+    	}
+    	return (IntroContentDetector) element.createExecutableExtension(IWorkbenchRegistryConstants.ATT_CONTENT_DETECTOR);
+    }
+
+    @Override
+	public String getId() {
+        return element.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+    }
+
+    @Override
+	public ImageDescriptor getImageDescriptor() {
+        if (imageDescriptor != null) {
+			return imageDescriptor;
+		}
+		String iconName = element.getAttribute(IWorkbenchRegistryConstants.ATT_ICON);
+		if (iconName == null) {
+			return null;
+		}
+
+        imageDescriptor = AbstractUIPlugin.imageDescriptorFromPlugin(element
+                .getNamespace(), iconName);
+        return imageDescriptor;
+    }
+
+    @Override
+	public String getLocalId() {
+        return element.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+    }
+
+    @Override
+	public String getPluginId() {
+        return element.getNamespace();
+    }
+
+    /**
+     * Returns the configuration element.
+     *
+     * @return the configuration element
+     * @since 3.1
+     */
+    public IConfigurationElement getConfigurationElement() {
+    	return element;
+    }
+
+	@Override
+	public String getLabelOverride() {
+		return element.getAttribute(IWorkbenchRegistryConstants.ATT_LABEL);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/intro/IntroMessages.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/intro/IntroMessages.java
new file mode 100644
index 0000000..1ad8996
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/intro/IntroMessages.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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 - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ui.internal.intro;
+
+import org.eclipse.osgi.util.NLS;
+
+
+/**
+ * The IntroMessages are the messages used in the intro support.
+ */
+public class IntroMessages extends NLS {
+	private static final String BUNDLE_NAME = "org.eclipse.ui.internal.intro.intro";//$NON-NLS-1$
+
+	public static String Intro_could_not_create_part;
+	public static String Intro_could_not_create_proxy;
+	public static String Intro_could_not_create_descriptor;
+	public static String Intro_action_text;
+	public static String Intro_default_title;
+    public static String Intro_missing_product_title;
+    public static String Intro_missing_product_message;
+
+	static {
+		// load message values from bundle file
+		NLS.initializeMessages(BUNDLE_NAME, IntroMessages.class);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/intro/IntroRegistry.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/intro/IntroRegistry.java
new file mode 100644
index 0000000..6ed9504
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/intro/IntroRegistry.java
@@ -0,0 +1,245 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.intro;
+
+import java.util.ArrayList;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.registry.RegistryReader;
+
+/**
+ * Registry for introduction elements.
+ *
+ * @since 3.0
+ */
+public class IntroRegistry implements IIntroRegistry {
+	private static final String TAG_INTRO = "intro";//$NON-NLS-1$
+
+	// RAP [bm]: no product support - replaced with branding
+//  private static final String TAG_INTROPRODUCTBINDING = "introProductBinding";//$NON-NLS-1$
+    private static final String TAG_INTROBRANDINGBINDING = "introBrandingBinding";//$NON-NLS-1$
+
+	private static final String ATT_INTROID = "introId"; //$NON-NLS-1$
+
+	// RAP [bm]: no product support - replaced with branding
+//  private static final String ATT_PRODUCTID = "productId"; //$NON-NLS-1$
+    private static final String ATT_BRANDINGID = "brandingId"; //$NON-NLS-1$
+
+	@Override
+	public int getIntroCount() {
+		return getIntros().length;
+	}
+
+	@Override
+	public IIntroDescriptor[] getIntros() {
+	 // RAP [bm]: replaced namespace
+//      IExtensionPoint point = Platform.getExtensionRegistry()
+//              .getExtensionPoint(PlatformUI.PLUGIN_ID,
+//                      IWorkbenchRegistryConstants.PL_INTRO);
+        IExtensionPoint point = Platform.getExtensionRegistry()
+        .getExtensionPoint(PlatformUI.PLUGIN_EXTENSION_NAME_SPACE,
+                IWorkbenchRegistryConstants.PL_INTRO);
+        // RAPEND: [bm]
+        
+        if (point == null) {
+			return new IIntroDescriptor[0];
+		}
+
+		IExtension[] extensions = point.getExtensions();
+		extensions = RegistryReader.orderExtensions(extensions);
+
+		ArrayList list = new ArrayList(extensions.length);
+		for (IExtension extension : extensions) {
+			IConfigurationElement[] elements = extension
+					.getConfigurationElements();
+			for (IConfigurationElement element : elements) {
+				if (element.getName().equals(TAG_INTRO)) {
+					try {
+						IIntroDescriptor descriptor = new IntroDescriptor(
+								element);
+						list.add(descriptor);
+					} catch (CoreException e) {
+						// log an error since its not safe to open a dialog here
+						WorkbenchPlugin
+								.log(
+										IntroMessages.Intro_could_not_create_descriptor, e.getStatus());
+					}
+				}
+			}
+		}
+
+		return (IIntroDescriptor[]) list.toArray(new IIntroDescriptor[list
+				.size()]);
+	}
+
+	// RAP [bm]: no product support - replaced with branding
+//	@Override
+//	public IIntroDescriptor getIntroForProduct(String targetProductId) {
+//	 // RAP [bm]: 
+//		IExtensionPoint point = Platform.getExtensionRegistry()
+//				.getExtensionPoint(PlatformUI.PLUGIN_ID,
+//						IWorkbenchRegistryConstants.PL_INTRO);
+//		if (point == null) {
+//			return null;
+//		}
+//
+//		IExtension[] extensions = point.getExtensions();
+//		extensions = RegistryReader.orderExtensions(extensions);
+//
+//		String targetIntroId = getIntroForProduct(targetProductId, extensions);
+//		if (targetIntroId == null) {
+//			return null;
+//		}
+//
+//		IIntroDescriptor descriptor = null;
+//
+//		IIntroDescriptor[] intros = getIntros();
+//		for (IIntroDescriptor intro : intros) {
+//			if (intro.getId().equals(targetIntroId)) {
+//				descriptor = intro;
+//				break;
+//			}
+//		}
+//
+//		return descriptor;
+//	}
+	// RAP [bm] same as getIntroForProduct() but with a branding
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.eclipse.ui.internal.intro.IIntroRegistry#getIntroForProduct(java.lang.String)
+     */
+    public IIntroDescriptor getIntroForBranding(String targetBrandingId) {
+        // RAP [bm]: replaced namespace
+//      IExtensionPoint point = Platform.getExtensionRegistry()
+//              .getExtensionPoint(PlatformUI.PLUGIN_ID,
+//                      IWorkbenchRegistryConstants.PL_INTRO);
+        IExtensionPoint point = Platform.getExtensionRegistry()
+        .getExtensionPoint(PlatformUI.PLUGIN_EXTENSION_NAME_SPACE,
+                IWorkbenchRegistryConstants.PL_INTRO);
+        // RAPEND: [bm] 
+        if (point == null) {
+            return null;
+        }
+
+        IExtension[] extensions = point.getExtensions();
+        extensions = RegistryReader.orderExtensions(extensions);
+
+        String targetIntroId = getIntroForBranding(targetBrandingId, extensions);
+        if (targetIntroId == null) {
+            return null;
+        }
+
+        IIntroDescriptor descriptor = null;
+
+        IIntroDescriptor[] intros = getIntros();
+        for (int i = 0; i < intros.length; i++) {
+            if (intros[i].getId().equals(targetIntroId)) {
+                descriptor = intros[i];
+                break;
+            }
+        }
+
+        return descriptor;
+    }
+
+    // RAP [bm]: no product support - using branding instead
+//	/**
+//	 * @param targetProductId
+//	 * @param extensions
+//	 * @return
+//	 */
+//	private String getIntroForProduct(String targetProductId,
+//			IExtension[] extensions) {
+//		for (IExtension extension : extensions) {
+//			IConfigurationElement[] elements = extension
+//					.getConfigurationElements();
+//			for (IConfigurationElement element : elements) {
+//				if (element.getName().equals(TAG_INTROPRODUCTBINDING)) {
+//					String introId = element.getAttribute(ATT_INTROID);
+//					String productId = element.getAttribute(ATT_PRODUCTID);
+//
+//					if (introId == null || productId == null) {
+//						IStatus status = new Status(
+//								IStatus.ERROR,
+//								element.getDeclaringExtension()
+//										.getNamespace(),
+//								IStatus.ERROR,
+//								"introId and productId must be defined.", new IllegalArgumentException()); //$NON-NLS-1$
+//						WorkbenchPlugin.log("Invalid intro binding", status); //$NON-NLS-1$
+//						continue;
+//					}
+//
+//					if (targetProductId.equals(productId)) {
+//						return introId;
+//					}
+//				}
+//			}
+//		}
+//		return null;
+//	}
+    /**
+     * @param targetBrandingId
+     * @param extensions
+     * @return
+     */
+    private String getIntroForBranding(String targetBrandingId,
+            IExtension[] extensions) {
+        for (int i = 0; i < extensions.length; i++) {
+            IConfigurationElement[] elements = extensions[i]
+                    .getConfigurationElements();
+            for (int j = 0; j < elements.length; j++) {
+                if (elements[j].getName().equals(TAG_INTROBRANDINGBINDING)) {
+                    String introId = elements[j].getAttribute(ATT_INTROID);
+                    String brandingId = elements[j].getAttribute(ATT_BRANDINGID);
+
+                    if (introId == null || brandingId == null) {
+                        IStatus status = new Status(
+                                IStatus.ERROR,
+                                elements[j].getDeclaringExtension()
+                                        .getNamespace(),
+                                IStatus.ERROR,
+                                "introId and brandingId must be defined.", new IllegalArgumentException()); //$NON-NLS-1$
+                        WorkbenchPlugin.log("Invalid intro binding", status); //$NON-NLS-1$
+                        continue;
+                    }
+
+                    if (targetBrandingId.equals(brandingId)) {
+                        return introId;
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    // ENDRAP 
+
+	@Override
+	public IIntroDescriptor getIntro(String id) {
+		IIntroDescriptor[] intros = getIntros();
+		for (IIntroDescriptor desc : intros) {
+			if (desc.getId().equals(id)) {
+				return desc;
+			}
+		}
+		return null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/intro/intro.properties b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/intro/intro.properties
new file mode 100644
index 0000000..0bc2e14
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/intro/intro.properties
@@ -0,0 +1,18 @@
+###############################################################################
+# Copyright (c) 2003, 2006 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
+###############################################################################
+
+Intro_could_not_create_part=Could not create intro part.
+Intro_could_not_create_proxy=Could not create intro view proxy.
+Intro_could_not_create_descriptor=Unable to create intro descriptor.
+Intro_action_text=&Welcome
+Intro_default_title=Welcome
+Intro_missing_product_title=No Welcome Content Found
+Intro_missing_product_message=There is no welcome content suitable for display in this application.
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/AbstractKeyFormatter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/AbstractKeyFormatter.java
new file mode 100644
index 0000000..86acfbf
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/AbstractKeyFormatter.java
@@ -0,0 +1,131 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.keys;
+
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.ResourceBundle;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.eclipse.ui.internal.util.Util;
+import org.eclipse.ui.keys.IKeyFormatter;
+import org.eclipse.ui.keys.Key;
+import org.eclipse.ui.keys.KeySequence;
+import org.eclipse.ui.keys.KeyStroke;
+import org.eclipse.ui.keys.ModifierKey;
+import org.eclipse.ui.keys.NaturalKey;
+
+/**
+ * An abstract implementation of a key formatter that provides a lot of common
+ * key formatting functionality. It is recommended that those people
+ * implementing their own key formatters subclass from here, rather than
+ * implementing <code>KeyFormatter</code> directly.
+ *
+ * @since 3.0
+ */
+public abstract class AbstractKeyFormatter implements IKeyFormatter {
+
+    /**
+     * The key for the delimiter between keys. This is used in the
+     * internationalization bundles.
+     */
+    protected final static String KEY_DELIMITER_KEY = "KEY_DELIMITER"; //$NON-NLS-1$
+
+    /**
+     * The key for the delimiter between key strokes. This is used in the
+     * internationalization bundles.
+     */
+    protected final static String KEY_STROKE_DELIMITER_KEY = "KEY_STROKE_DELIMITER"; //$NON-NLS-1$
+
+    /**
+     * The bundle in which to look up the internationalized text for all of the
+     * individual keys in the system. This is the platform-agnostic version of
+     * the internationalized strings. Some platforms (namely Carbon) provide
+     * special Unicode characters and glyphs for some keys.
+     */
+    private final static ResourceBundle RESOURCE_BUNDLE = ResourceBundle
+            .getBundle(AbstractKeyFormatter.class.getName());
+
+    @Override
+	public String format(Key key) {
+        String name = key.toString();
+        return Util.translateString(RESOURCE_BUNDLE, name, name, false, false);
+    }
+
+    @Override
+	public String format(KeySequence keySequence) {
+        StringBuffer stringBuffer = new StringBuffer();
+
+        Iterator keyStrokeItr = keySequence.getKeyStrokes().iterator();
+        while (keyStrokeItr.hasNext()) {
+            stringBuffer.append(format((KeyStroke) keyStrokeItr.next()));
+
+            if (keyStrokeItr.hasNext()) {
+                stringBuffer.append(getKeyStrokeDelimiter());
+            }
+        }
+
+        return stringBuffer.toString();
+    }
+
+    @Override
+	public String format(KeyStroke keyStroke) {
+        String keyDelimiter = getKeyDelimiter();
+
+        // Format the modifier keys, in sorted order.
+        SortedSet modifierKeys = new TreeSet(getModifierKeyComparator());
+        modifierKeys.addAll(keyStroke.getModifierKeys());
+        StringBuffer stringBuffer = new StringBuffer();
+        Iterator modifierKeyItr = modifierKeys.iterator();
+        while (modifierKeyItr.hasNext()) {
+            stringBuffer.append(format((ModifierKey) modifierKeyItr.next()));
+            stringBuffer.append(keyDelimiter);
+        }
+
+        // Format the natural key, if any.
+        NaturalKey naturalKey = keyStroke.getNaturalKey();
+        if (naturalKey != null) {
+            stringBuffer.append(format(naturalKey));
+        }
+
+        return stringBuffer.toString();
+
+    }
+
+    /**
+     * An accessor for the delimiter you wish to use between keys. This is used
+     * by the default format implementations to determine the key delimiter.
+     *
+     * @return The delimiter to use between keys; should not be <code>null</code>.
+     */
+    protected abstract String getKeyDelimiter();
+
+    /**
+     * An accessor for the delimiter you wish to use between key strokes. This
+     * used by the default format implementations to determine the key stroke
+     * delimiter.
+     *
+     * @return The delimiter to use between key strokes; should not be <code>null</code>.
+     */
+    protected abstract String getKeyStrokeDelimiter();
+
+    /**
+     * An accessor for the comparator to use for sorting modifier keys. This is
+     * used by the default format implementations to sort the modifier keys
+     * before formatting them into a string.
+     *
+     * @return The comparator to use to sort modifier keys; must not be <code>null</code>.
+     */
+    protected abstract Comparator getModifierKeyComparator();
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/AbstractKeyFormatter.properties b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/AbstractKeyFormatter.properties
new file mode 100644
index 0000000..63cbb2f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/AbstractKeyFormatter.properties
@@ -0,0 +1,82 @@
+###############################################################################
+# Copyright (c) 2000, 2010 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
+###############################################################################
+
+# Modifier keys
+ALT=Alt
+COMMAND=Command
+CTRL=Ctrl
+SHIFT=Shift
+
+# Special keys
+ARROW_DOWN=Down
+ARROW_LEFT=Left
+ARROW_RIGHT=Right
+ARROW_UP=Up
+BREAK=Break
+CAPS_LOCK=CapsLock
+END=End
+F1=F1
+F10=F10
+F11=F11
+F12=F12
+F13=F13
+F14=F14
+F15=F15
+F16=F16
+F17=F17
+F18=F18
+F19=F19
+F2=F2
+F20=F20
+F3=F3
+F4=F4
+F5=F5
+F6=F6
+F7=F7
+F8=F8
+F9=F9
+HOME=Home
+INSERT=Insert
+NUM_LOCK=NumLock
+NUMPAD_0=Numpad_0
+NUMPAD_1=Numpad_1
+NUMPAD_2=Numpad_2
+NUMPAD_3=Numpad_3
+NUMPAD_4=Numpad_4
+NUMPAD_5=Numpad_5
+NUMPAD_6=Numpad_6
+NUMPAD_7=Numpad_7
+NUMPAD_8=Numpad_8
+NUMPAD_9=Numpad_9
+NUMPAD_ADD=Numpad_Add
+NUMPAD_DECIMAL=Numpad_Decimal
+NUMPAD_DIVIDE=Numpad_Divide
+NUMPAD_ENTER=Numpad_Enter
+NUMPAD_EQUAL=Numpad_Equal
+NUMPAD_MULTIPLY=Numpad_Multiply
+NUMPAD_SUBTRACT=Numpad_Subtract
+PAGE_DOWN=PageDown
+PAGE_UP=PageUp
+PAUSE=Pause
+PRINT_SCREEN=PrintScreen
+SCROLL_LOCK=ScrollLock
+
+# Character keys
+BS=Backspace
+CR=Enter
+DEL=Delete
+ESC=Esc
+FF=FormFeed
+LF=LineFeed
+NUL=Null
+SPACE=Space
+TAB=Tab
+VT=VerticalTab
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/AbstractModifierKeyComparator.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/AbstractModifierKeyComparator.java
new file mode 100644
index 0000000..23465c4
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/AbstractModifierKeyComparator.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2014 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.ui.internal.keys;
+
+import java.util.Comparator;
+
+import org.eclipse.ui.keys.ModifierKey;
+
+abstract class AbstractModifierKeyComparator implements Comparator {
+
+    @Override
+	public int compare(Object left, Object right) {
+        ModifierKey modifierKeyLeft = (ModifierKey) left;
+        ModifierKey modifierKeyRight = (ModifierKey) right;
+        int modifierKeyLeftRank = rank(modifierKeyLeft);
+        int modifierKeyRightRank = rank(modifierKeyRight);
+
+        if (modifierKeyLeftRank != modifierKeyRightRank) {
+			return modifierKeyLeftRank - modifierKeyRightRank;
+		} else {
+			return modifierKeyLeft.compareTo(modifierKeyRight);
+		}
+    }
+
+    protected abstract int rank(ModifierKey modifierKey);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/AlphabeticModifierKeyComparator.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/AlphabeticModifierKeyComparator.java
new file mode 100644
index 0000000..e493a54
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/AlphabeticModifierKeyComparator.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.keys;
+
+import java.util.Comparator;
+
+import org.eclipse.ui.keys.ModifierKey;
+
+/**
+ * Compares modifier keys lexicographically by the name of the key.
+ *
+ * @since 3.0
+ */
+public class AlphabeticModifierKeyComparator implements Comparator {
+
+    @Override
+	public int compare(Object left, Object right) {
+        ModifierKey modifierKeyLeft = (ModifierKey) left;
+        ModifierKey modifierKeyRight = (ModifierKey) right;
+        return modifierKeyLeft.toString()
+                .compareTo(modifierKeyRight.toString());
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/BindingPersistence.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/BindingPersistence.java
new file mode 100644
index 0000000..ed15530
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/BindingPersistence.java
@@ -0,0 +1,1379 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.keys;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.StringTokenizer;
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.CommandManager;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.commands.common.HandleObject;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.core.commands.util.Tracing;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionDelta;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.IRegistryChangeEvent;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.bindings.Binding;
+import org.eclipse.jface.bindings.BindingManager;
+import org.eclipse.jface.bindings.Scheme;
+import org.eclipse.jface.bindings.keys.IKeyLookup;
+import org.eclipse.jface.bindings.keys.KeyBinding;
+import org.eclipse.jface.bindings.keys.KeyLookupFactory;
+import org.eclipse.jface.bindings.keys.KeySequence;
+import org.eclipse.jface.bindings.keys.KeyStroke;
+import org.eclipse.jface.bindings.keys.ParseException;
+import org.eclipse.jface.bindings.keys.SWTKeySupport;
+import org.eclipse.jface.contexts.IContextIds;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.jface.util.Util;
+import org.eclipse.swt.SWT;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IWorkbenchPreferenceConstants;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.WorkbenchException;
+import org.eclipse.ui.XMLMemento;
+import org.eclipse.ui.internal.ShowViewMenu;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.misc.Policy;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.services.PreferencePersistence;
+import org.eclipse.ui.keys.IBindingService;
+
+/**
+ * <p>
+ * A static class for accessing the registry and the preference store.
+ * </p>
+ *
+ * @since 3.1
+ */
+public class BindingPersistence extends PreferencePersistence {
+
+	/**
+	 * Whether this class should print out debugging information when it reads
+	 * in data, or writes to the preference store.
+	 */
+	private static final boolean DEBUG = Policy.DEBUG_KEY_BINDINGS;
+
+	/**
+	 * The index of the active scheme configuration elements in the indexed
+	 * array.
+	 *
+	 * @see BindingPersistence#read()
+	 */
+	private static final int INDEX_ACTIVE_SCHEME = 0;
+
+	/**
+	 * The index of the binding definition configuration elements in the indexed
+	 * array.
+	 *
+	 * @see BindingPersistence#read()
+	 */
+	private static final int INDEX_BINDING_DEFINITIONS = 1;
+
+	/**
+	 * The index of the scheme definition configuration elements in the indexed
+	 * array.
+	 *
+	 * @see BindingPersistence#read()
+	 */
+	private static final int INDEX_SCHEME_DEFINITIONS = 2;
+
+	/**
+	 * The name of the default scope in 2.1.x.
+	 */
+	private static final String LEGACY_DEFAULT_SCOPE = "org.eclipse.ui.globalScope"; //$NON-NLS-1$
+
+	/**
+	 * A look-up map for 2.1.x style <code>string</code> keys on a
+	 * <code>keyBinding</code> element.
+	 */
+	private static final Map r2_1KeysByName = new HashMap();
+
+	static {
+		final IKeyLookup lookup = KeyLookupFactory.getDefault();
+		r2_1KeysByName.put(IKeyLookup.BACKSPACE_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.BACKSPACE_NAME));
+		r2_1KeysByName.put(IKeyLookup.TAB_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.TAB_NAME));
+		r2_1KeysByName.put(IKeyLookup.RETURN_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.RETURN_NAME));
+		r2_1KeysByName.put(IKeyLookup.ENTER_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.ENTER_NAME));
+		r2_1KeysByName.put(IKeyLookup.ESCAPE_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.ESCAPE_NAME));
+		r2_1KeysByName.put(IKeyLookup.ESC_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.ESC_NAME));
+		r2_1KeysByName.put(IKeyLookup.DELETE_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.DELETE_NAME));
+		r2_1KeysByName.put(IKeyLookup.SPACE_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.SPACE_NAME));
+		r2_1KeysByName.put(IKeyLookup.ARROW_UP_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.ARROW_UP_NAME));
+		r2_1KeysByName.put(IKeyLookup.ARROW_DOWN_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.ARROW_DOWN_NAME));
+		r2_1KeysByName.put(IKeyLookup.ARROW_LEFT_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.ARROW_LEFT_NAME));
+		r2_1KeysByName.put(IKeyLookup.ARROW_RIGHT_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.ARROW_RIGHT_NAME));
+		r2_1KeysByName.put(IKeyLookup.PAGE_UP_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.PAGE_UP_NAME));
+		r2_1KeysByName.put(IKeyLookup.PAGE_DOWN_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.PAGE_DOWN_NAME));
+		r2_1KeysByName.put(IKeyLookup.HOME_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.HOME_NAME));
+		r2_1KeysByName.put(IKeyLookup.END_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.END_NAME));
+		r2_1KeysByName.put(IKeyLookup.INSERT_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.INSERT_NAME));
+		r2_1KeysByName.put(IKeyLookup.F1_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.F1_NAME));
+		r2_1KeysByName.put(IKeyLookup.F2_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.F2_NAME));
+		r2_1KeysByName.put(IKeyLookup.F3_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.F3_NAME));
+		r2_1KeysByName.put(IKeyLookup.F4_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.F4_NAME));
+		r2_1KeysByName.put(IKeyLookup.F5_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.F5_NAME));
+		r2_1KeysByName.put(IKeyLookup.F6_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.F6_NAME));
+		r2_1KeysByName.put(IKeyLookup.F7_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.F7_NAME));
+		r2_1KeysByName.put(IKeyLookup.F8_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.F8_NAME));
+		r2_1KeysByName.put(IKeyLookup.F9_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.F9_NAME));
+		r2_1KeysByName.put(IKeyLookup.F10_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.F10_NAME));
+		r2_1KeysByName.put(IKeyLookup.F11_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.F11_NAME));
+		r2_1KeysByName.put(IKeyLookup.F12_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.F12_NAME));
+		r2_1KeysByName.put(IKeyLookup.F13_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.F13_NAME));
+		r2_1KeysByName.put(IKeyLookup.F14_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.F14_NAME));
+		r2_1KeysByName.put(IKeyLookup.F15_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.F15_NAME));
+		r2_1KeysByName.put(IKeyLookup.F16_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.F16_NAME));
+		r2_1KeysByName.put(IKeyLookup.F17_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.F17_NAME));
+		r2_1KeysByName.put(IKeyLookup.F18_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.F18_NAME));
+		r2_1KeysByName.put(IKeyLookup.F19_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.F19_NAME));
+		r2_1KeysByName.put(IKeyLookup.F20_NAME, lookup
+				.formalKeyLookupInteger(IKeyLookup.F20_NAME));
+	}
+
+	/**
+	 * Converts a 2.1.x style key sequence (as parsed from the
+	 * <code>string</code> attribute of the <code>keyBinding</code>) to a
+	 * 3.1 key sequence.
+	 *
+	 * @param r21KeySequence
+	 *            The sequence of 2.1.x key strokes that should be converted
+	 *            into a 3.1 key sequence; never <code>null</code>.
+	 * @return A 3.1 key sequence; never <code>null</code>.
+	 */
+	private static final KeySequence convert2_1Sequence(int[] r21KeySequence) {
+		final int r21KeySequenceLength = r21KeySequence.length;
+		final KeyStroke[] keyStrokes = new KeyStroke[r21KeySequenceLength];
+		for (int i = 0; i < r21KeySequenceLength; i++) {
+			keyStrokes[i] = convert2_1Stroke(r21KeySequence[i]);
+		}
+
+		return KeySequence.getInstance(keyStrokes);
+	}
+
+	/**
+	 * Converts a 2.1.x style key stroke (as parsed from the <code>string</code>
+	 * attribute of the <code>keyBinding</code> to a 3.1 key stroke.
+	 *
+	 * @param r21Stroke
+	 *            The 2.1.x stroke to convert; must never be <code>null</code>.
+	 * @return A 3.1 key stroke; never <code>null</code>.
+	 */
+	private static final KeyStroke convert2_1Stroke(final int r21Stroke) {
+		return SWTKeySupport.convertAcceleratorToKeyStroke(r21Stroke);
+	}
+
+	/**
+	 * Returns the default scheme identifier for the currently running
+	 * application.
+	 *
+	 * @return The default scheme identifier (<code>String</code>); never
+	 *         <code>null</code>, but may be empty or point to an undefined
+	 *         scheme.
+	 */
+	public static final String getDefaultSchemeId() {
+		final IPreferenceStore store = PlatformUI.getPreferenceStore();
+		return store
+				.getDefaultString(IWorkbenchPreferenceConstants.KEY_CONFIGURATION_ID);
+	}
+
+	/**
+	 * Parses a 2.1.x <code>string</code> attribute of the
+	 * <code>keyBinding</code> element.
+	 *
+	 * @param string
+	 *            The string to parse; must not be <code>null</code>.
+	 * @return An array of integer values -- each integer representing a single
+	 *         key stroke. This array may be empty, but it is never
+	 *         <code>null</code>.
+	 */
+	private static final int[] parse2_1Sequence(final String string) {
+		final StringTokenizer stringTokenizer = new StringTokenizer(string);
+		final int length = stringTokenizer.countTokens();
+		final int[] strokes = new int[length];
+
+		for (int i = 0; i < length; i++) {
+			strokes[i] = parse2_1Stroke(stringTokenizer.nextToken());
+		}
+
+		return strokes;
+	}
+
+	/**
+	 * Parses a single 2.1.x key stroke string, as provided by
+	 * <code>parse2_1Sequence</code>.
+	 *
+	 * @param string
+	 *            The string to parse; must not be <code>null</code>.
+	 * @return An single integer value representing this key stroke.
+	 */
+	private static final int parse2_1Stroke(final String string) {
+		final StringTokenizer stringTokenizer = new StringTokenizer(string,
+				KeyStroke.KEY_DELIMITER, true);
+
+		// Copy out the tokens so we have random access.
+		final int size = stringTokenizer.countTokens();
+		final String[] tokens = new String[size];
+		for (int i = 0; stringTokenizer.hasMoreTokens(); i++) {
+			tokens[i] = stringTokenizer.nextToken();
+		}
+
+		int value = 0;
+		if (size % 2 == 1) {
+			String token = tokens[size - 1];
+			final Integer integer = (Integer) r2_1KeysByName.get(token
+					.toUpperCase(Locale.ENGLISH));
+
+			if (integer != null) {
+				value = integer.intValue();
+			} else if (token.length() == 1) {
+				value = token.toUpperCase().charAt(0);
+			}
+
+			if (value != 0) {
+				for (int i = 0; i < size - 1; i++) {
+					token = tokens[i];
+
+					if (i % 2 == 0) {
+						if (token.equalsIgnoreCase(IKeyLookup.CTRL_NAME)) {
+							if ((value & SWT.CTRL) != 0) {
+								return 0;
+							}
+
+							value |= SWT.CTRL;
+
+						} else if (token.equalsIgnoreCase(IKeyLookup.ALT_NAME)) {
+							if ((value & SWT.ALT) != 0) {
+								return 0;
+							}
+
+							value |= SWT.ALT;
+
+						} else if (token
+								.equalsIgnoreCase(IKeyLookup.SHIFT_NAME)) {
+							if ((value & SWT.SHIFT) != 0) {
+								return 0;
+							}
+
+							value |= SWT.SHIFT;
+
+						} else if (token
+								.equalsIgnoreCase(IKeyLookup.COMMAND_NAME)) {
+							if ((value & SWT.COMMAND) != 0) {
+								return 0;
+							}
+
+							value |= SWT.COMMAND;
+
+						} else {
+							return 0;
+
+						}
+
+					} else if (!KeyStroke.KEY_DELIMITER.equals(token)) {
+						return 0;
+					}
+				}
+			}
+		}
+
+		return value;
+	}
+
+	/**
+	 * <p>
+	 * Reads the registry and the preference store, and determines the
+	 * identifier for the scheme that should be active. There is a complicated
+	 * order of priorities for this. The registry will only be read if there is
+	 * no user preference, and the default active scheme id is different than
+	 * the default default active scheme id.
+	 * </p>
+	 * <ol>
+	 * <li>A non-default preference.</li>
+	 * <li>The legacy preference XML memento.</li>
+	 * <li>A default preference value that is different than the default
+	 * default active scheme id.</li>
+	 * <li>The registry.</li>
+	 * <li>The default default active scheme id.</li>
+	 * </ol>
+	 *
+	 * @param configurationElements
+	 *            The configuration elements from the commands extension point;
+	 *            must not be <code>null</code>.
+	 * @param configurationElementCount
+	 *            The number of configuration elements that are really in the
+	 *            array.
+	 * @param preferences
+	 *            The memento wrapping the commands preference key; may be
+	 *            <code>null</code>.
+	 * @param bindingManager
+	 *            The binding manager that should be updated with the active
+	 *            scheme. This binding manager must already have its schemes
+	 *            defined. This value must not be <code>null</code>.
+	 */
+	private static final void readActiveScheme(
+			final IConfigurationElement[] configurationElements,
+			final int configurationElementCount, final IMemento preferences,
+			final BindingManager bindingManager) {
+		// A non-default preference.
+		final IPreferenceStore store = PlatformUI.getPreferenceStore();
+		final String defaultActiveSchemeId = store
+				.getDefaultString(IWorkbenchPreferenceConstants.KEY_CONFIGURATION_ID);
+		final String preferenceActiveSchemeId = store
+				.getString(IWorkbenchPreferenceConstants.KEY_CONFIGURATION_ID);
+		if ((preferenceActiveSchemeId != null)
+				&& (!preferenceActiveSchemeId.equals(defaultActiveSchemeId))) {
+			try {
+				bindingManager.setActiveScheme(bindingManager
+						.getScheme(preferenceActiveSchemeId));
+				return;
+			} catch (final NotDefinedException e) {
+				// Let's keep looking....
+			}
+		}
+
+		// A legacy preference XML memento.
+		if (preferences != null) {
+			final IMemento[] preferenceMementos = preferences
+					.getChildren(TAG_ACTIVE_KEY_CONFIGURATION);
+			int preferenceMementoCount = preferenceMementos.length;
+			for (int i = preferenceMementoCount - 1; i >= 0; i--) {
+				final IMemento memento = preferenceMementos[i];
+				String id = memento.getString(ATT_KEY_CONFIGURATION_ID);
+				if (id != null) {
+					try {
+						bindingManager.setActiveScheme(bindingManager
+								.getScheme(id));
+						return;
+					} catch (final NotDefinedException e) {
+						// Let's keep looking....
+					}
+				}
+			}
+		}
+
+		// A default preference value that is different than the default.
+		if ((defaultActiveSchemeId != null && defaultActiveSchemeId.length() > 0)
+				&& (!defaultActiveSchemeId
+						.equals(IBindingService.DEFAULT_DEFAULT_ACTIVE_SCHEME_ID))) {
+			try {
+				bindingManager.setActiveScheme(bindingManager
+						.getScheme(defaultActiveSchemeId));
+				return;
+			} catch (final NotDefinedException e) {
+				// Let's keep looking....
+			}
+		}
+
+		// The registry.
+		for (int i = configurationElementCount - 1; i >= 0; i--) {
+			final IConfigurationElement configurationElement = configurationElements[i];
+
+			String id = configurationElement
+					.getAttribute(ATT_KEY_CONFIGURATION_ID);
+			if (id != null) {
+				try {
+					bindingManager
+							.setActiveScheme(bindingManager.getScheme(id));
+					return;
+				} catch (final NotDefinedException e) {
+					// Let's keep looking....
+				}
+			}
+
+			id = configurationElement.getAttribute(ATT_VALUE);
+			if (id != null) {
+				try {
+					bindingManager
+							.setActiveScheme(bindingManager.getScheme(id));
+					return;
+				} catch (final NotDefinedException e) {
+					// Let's keep looking....
+				}
+			}
+		}
+
+		// The default default active scheme id.
+		try {
+			bindingManager
+					.setActiveScheme(bindingManager
+							.getScheme(IBindingService.DEFAULT_DEFAULT_ACTIVE_SCHEME_ID));
+		} catch (final NotDefinedException e) {
+			//this is bad - the default default scheme should always exist
+			throw new Error(
+					"The default default active scheme id is not defined."); //$NON-NLS-1$
+		}
+	}
+
+	/**
+	 * Reads all of the binding definitions from the preferences.
+	 *
+	 * @param preferences
+	 *            The memento for the commands preferences key.
+	 * @param bindingManager
+	 *            The binding manager to which the bindings should be added;
+	 *            must not be <code>null</code>.
+	 * @param commandService
+	 *            The command service for the workbench; must not be
+	 *            <code>null</code>.
+	 */
+	private static final void readBindingsFromPreferences(final IMemento preferences,
+			final BindingManager bindingManager, final CommandManager commandService) {
+		List warningsToLog = new ArrayList(1);
+
+		if (preferences != null) {
+			final IMemento[] preferenceMementos = preferences
+					.getChildren(TAG_KEY_BINDING);
+			int preferenceMementoCount = preferenceMementos.length;
+			for (int i = preferenceMementoCount - 1; i >= 0; i--) {
+				final IMemento memento = preferenceMementos[i];
+
+				// Read out the command id.
+				String commandId = readOptional(memento, ATT_COMMAND_ID);
+				if (commandId == null) {
+					commandId = readOptional(memento, ATT_COMMAND);
+				}
+				final Command command;
+				if (commandId != null) {
+					command = commandService.getCommand(commandId);
+				} else {
+					command = null;
+				}
+
+				// Read out the scheme id.
+				String schemeId = readOptional(memento,
+						ATT_KEY_CONFIGURATION_ID);
+				if (schemeId == null) {
+					schemeId = readRequired(memento, ATT_CONFIGURATION,
+							warningsToLog,
+							"Key bindings need a scheme or key configuration"); //$NON-NLS-1$
+					if (schemeId == null) {
+						continue;
+					}
+				}
+
+				// Read out the context id.
+				String contextId = readOptional(memento, ATT_CONTEXT_ID);
+				if (contextId == null) {
+					contextId = readOptional(memento, ATT_SCOPE);
+				}
+				if (LEGACY_DEFAULT_SCOPE.equals(contextId)) {
+					contextId = null;
+				}
+				if (contextId == null) {
+					contextId = IContextIds.CONTEXT_ID_WINDOW;
+				}
+
+				// Read out the key sequence.
+				String keySequenceText = readOptional(memento, ATT_KEY_SEQUENCE);
+				KeySequence keySequence = null;
+				if (keySequenceText == null) {
+					keySequenceText = readRequired(memento, ATT_STRING,
+							warningsToLog,
+							"Key bindings need a key sequence or string"); //$NON-NLS-1$
+					if (keySequenceText == null) {
+						continue;
+					}
+
+					// The key sequence is in the old-style format.
+					keySequence = convert2_1Sequence(parse2_1Sequence(keySequenceText));
+
+				} else {
+					// The key sequence is in the new-style format.
+					try {
+						keySequence = KeySequence.getInstance(keySequenceText);
+					} catch (final ParseException e) {
+						addWarning(warningsToLog, "Could not parse", null, //$NON-NLS-1$
+								commandId, "keySequence", keySequenceText); //$NON-NLS-1$
+						continue;
+					}
+					if (keySequence.isEmpty() || !keySequence.isComplete()) {
+						addWarning(
+								warningsToLog,
+								"Key bindings cannot use an empty or incomplete key sequence", //$NON-NLS-1$
+								null, commandId, "keySequence", keySequence //$NON-NLS-1$
+										.toString());
+						continue;
+					}
+
+				}
+
+				// Read out the locale and platform.
+				final String locale = readOptional(memento, ATT_LOCALE);
+				final String platform = readOptional(memento, ATT_PLATFORM);
+
+				// Read out the parameters
+				final ParameterizedCommand parameterizedCommand = command != null ? readParameters(
+						memento, warningsToLog, command) : null;
+
+				final Binding binding = new KeyBinding(keySequence,
+						parameterizedCommand, schemeId, contextId, locale,
+						platform, null, Binding.USER);
+				bindingManager.addBinding(binding);
+			}
+		}
+
+		// If there were any warnings, then log them now.
+		logWarnings(warningsToLog,
+				"Warnings while parsing the key bindings from the preference store"); //$NON-NLS-1$
+	}
+
+	/**
+	 * Reads all of the binding definitions from the commands extension point.
+	 *
+	 * @param configurationElements
+	 *            The configuration elements in the commands extension point;
+	 *            must not be <code>null</code>, but may be empty.
+	 * @param configurationElementCount
+	 *            The number of configuration elements that are really in the
+	 *            array.
+	 * @param bindingManager
+	 *            The binding manager to which the bindings should be added;
+	 *            must not be <code>null</code>.
+	 * @param commandService
+	 *            The command service for the workbench; must not be
+	 *            <code>null</code>.
+	 */
+	private static final void readBindingsFromRegistry(
+			final IConfigurationElement[] configurationElements,
+			final int configurationElementCount,
+			final BindingManager bindingManager,
+			final CommandManager commandService) {
+		final Collection bindings = new ArrayList(configurationElementCount);
+		final List warningsToLog = new ArrayList(1);
+
+		HashSet cocoaTempList = new HashSet();
+		// IViewRegistry viewRegistry =
+		// PlatformUI.getWorkbench().getViewRegistry();
+
+		// the local cache for the sequence modifiers
+		IConfigurationElement[] sequenceModifiers = new IConfigurationElement[0];
+		if(configurationElementCount >0)
+			sequenceModifiers =  getSequenceModifierElements(configurationElements[0]);
+
+		for (int i = 0; i < configurationElementCount; i++) {
+			final IConfigurationElement configurationElement = configurationElements[i];
+
+			// different extension. update the cache ...
+			if( i>0 && !configurationElement.getDeclaringExtension().equals(configurationElements[i-1].getDeclaringExtension()))
+				sequenceModifiers = getSequenceModifierElements(configurationElement);
+
+			/*
+			 * Read out the command id. Doing this before determining if the key
+			 * binding is actually valid is a bit wasteful. However, it is
+			 * helpful to have the command identifier when logging syntax
+			 * errors.
+			 */
+			String commandId = readCommandId(configurationElement);
+
+			String viewParameter = null;
+			final Command command;
+			if (commandId != null) {
+				// TODO should we still try processing keybindings to viewIds?
+				// if (viewRegistry.find(commandId) == null) {
+				command = commandService.getCommand(commandId);
+				if (!command.isDefined()) {
+					// Reference to an undefined command. This is invalid.
+					addWarning(warningsToLog, "Cannot bind to an undefined command", //$NON-NLS-1$
+							configurationElement, commandId);
+					continue;
+				}
+			} else {
+				command = null;
+			}
+
+			// Read out the scheme id.
+			String schemeId = readSchemeId(configurationElement, warningsToLog, commandId);
+			if(isEmpty(schemeId))
+				continue;
+
+			// Read out the context id.
+			String contextId = readContextId(configurationElement);
+
+			String keySequenceText = readKeySequenceText(configurationElement);
+			if(isEmpty(keySequenceText)) {
+				// The key sequence should never be null. This is pointless
+				addWarning(
+						warningsToLog,
+						"Defining a key binding with no key sequence has no effect", //$NON-NLS-1$
+						configurationElement, commandId);
+				continue;
+			}
+
+
+
+			// Read out the key sequence.
+			KeySequence keySequence = readKeySequence(configurationElement, warningsToLog, commandId, keySequenceText);
+			if(keySequence == null)
+				continue;
+
+			// Read out the locale and platform.
+
+			String locale = readNonEmptyAttribute(configurationElement, ATT_LOCALE);
+			String platform = readNonEmptyAttribute(configurationElement, ATT_PLATFORM);
+
+			// Read out the parameters, if any.
+			ParameterizedCommand parameterizedCommand =
+				readParameterizedCommand(warningsToLog, configurationElement, viewParameter, command);
+
+			List modifiedBindings = applyModifiers(keySequence, keySequenceText, platform, sequenceModifiers, parameterizedCommand, schemeId, contextId, locale, warningsToLog);
+
+			KeyBinding binding = (KeyBinding) modifiedBindings.get(0);
+			if(modifiedBindings.size() > 1) {
+				for (int j = 1; j < modifiedBindings.size(); j++) {
+					bindings.add(modifiedBindings.get(j));
+				}
+			}
+
+			if (Util.WS_COCOA.equals(platform)) {
+				cocoaTempList.add(binding);
+			} else if (Util.WS_CARBON.equals(platform)) {
+				bindings.add(binding);
+				// temp work around ... simply honour the carbon
+				// bindings for cocoa.
+				cocoaTempList.add(new KeyBinding(keySequence,
+						parameterizedCommand, schemeId, contextId, locale,
+						Util.WS_COCOA, null, Binding.SYSTEM));
+			} else {
+				bindings.add(binding);
+			}
+		}
+		if (cocoaTempList.size() > 0) {
+			bindings.addAll(cocoaTempList);
+		}
+
+		final Binding[] bindingArray = (Binding[]) bindings
+				.toArray(new Binding[bindings.size()]);
+		bindingManager.setBindings(bindingArray);
+
+		logWarnings(
+				warningsToLog,
+				"Warnings while parsing the key bindings from the 'org.eclipse.ui.commands' and 'org.eclipse.ui.bindings' extension point"); //$NON-NLS-1$
+	}
+
+	private static List applyModifiers(KeySequence keySequence, String keySequenceText,
+			String platform, IConfigurationElement[] sequenceModifiers,
+			ParameterizedCommand parameterizedCommand, String schemeId,
+			String contextId, String locale, List warningsToLog) {
+
+		List bindings = new ArrayList();
+
+		for (IConfigurationElement sequenceModifier : sequenceModifiers) {
+
+			String findSequence = sequenceModifier.getAttribute(ATT_FIND);
+
+			if (keySequenceText.startsWith(findSequence)) {
+				String replaceSequence = sequenceModifier.getAttribute(ATT_REPLACE);
+				String modifiedSequence = replaceSequence + keySequenceText.substring(findSequence.length());
+				String platformsString = sequenceModifier.getAttribute(ATT_PLATFORMS);
+
+				String[] platforms = parseCommaSeparatedString(platformsString);
+
+				try {
+					if (platform == null) {
+						addGenericBindings(keySequence, parameterizedCommand, schemeId, contextId, locale,
+								bindings, modifiedSequence, platforms);
+
+					} else {
+						getBindingForPlatform(keySequence, platform,
+								parameterizedCommand, schemeId, contextId, locale,
+								bindings, modifiedSequence, platforms);
+					}
+				}catch(ParseException e) {
+					bindings.clear();
+					addWarning(
+							warningsToLog,
+							"Cannot create modified sequence for key binding", //$NON-NLS-1$
+							sequenceModifier, parameterizedCommand.getId(), ATT_REPLACE,
+							replaceSequence);
+
+				}
+				break;
+			}
+		}
+
+		if(bindings.size() == 0) {
+			// no modifier was applied/error occurred  ...
+			KeyBinding binding = new KeyBinding(keySequence,
+					parameterizedCommand, schemeId, contextId, locale,
+					platform, null, Binding.SYSTEM);
+			bindings.add(binding);
+		}
+
+		return bindings;
+	}
+
+	private static void getBindingForPlatform(KeySequence keySequence,
+			String platform, ParameterizedCommand parameterizedCommand,
+			String schemeId, String contextId, String locale, List bindings,
+			String modifiedSequence, String[] platforms) throws ParseException {
+
+		int j = 0;
+		for (; j < platforms.length; j++) {
+			if(platforms[j].equals(SWT.getPlatform())) {
+				KeyBinding newBinding = new KeyBinding(KeySequence
+						.getInstance(modifiedSequence),
+						parameterizedCommand, schemeId, contextId,
+						locale, platforms[j], null, Binding.SYSTEM);
+				bindings.add(newBinding);
+				break;
+			}
+		}
+		if(j == platforms.length) {
+			// platform doesn't match. use the unmodified sequence
+			KeyBinding newBinding = new KeyBinding(keySequence,
+					parameterizedCommand, schemeId, contextId,
+					locale, null, null, Binding.SYSTEM);
+			bindings.add(newBinding);
+		}
+	}
+
+	private static void addGenericBindings(KeySequence keySequence, ParameterizedCommand parameterizedCommand,
+			String schemeId, String contextId, String locale, List bindings,
+			String modifiedSequence, String[] platforms) throws ParseException {
+
+
+		KeyBinding originalBinding = new KeyBinding(keySequence,
+				parameterizedCommand, schemeId, contextId, locale, null, null,
+				Binding.SYSTEM);
+		bindings.add(originalBinding);
+
+		String platform = SWT.getPlatform();
+		boolean modifierExists = false;
+		for (String currentPlatform : platforms) {
+			if(currentPlatform.equals(platform)) {
+				modifierExists = true;
+				break;
+			}
+		}
+
+		if(modifierExists) {
+			KeyBinding newBinding = new KeyBinding(KeySequence.getInstance(modifiedSequence),
+					parameterizedCommand, schemeId, contextId,
+					locale, SWT.getPlatform(), null, Binding.SYSTEM);
+
+			KeyBinding deleteBinding = new KeyBinding(keySequence,
+					null, schemeId, contextId,
+					locale, SWT.getPlatform(), null, Binding.SYSTEM);
+
+			bindings.add(newBinding);
+			bindings.add(deleteBinding);
+		}
+
+	}
+
+	private static IConfigurationElement[] getSequenceModifierElements(IConfigurationElement configurationElement) {
+
+		IExtension extension = configurationElement.getDeclaringExtension();
+		List modifierElements = new ArrayList();
+		for (final IConfigurationElement configElement : extension.getConfigurationElements()) {
+			if(TAG_SEQUENCE_MODIFIER.equals(configElement.getName()))
+				modifierElements.add(configElement);
+		}
+		return (IConfigurationElement[]) modifierElements.toArray(new IConfigurationElement[modifierElements.size()]);
+	}
+
+	public static String[] parseCommaSeparatedString(String commaSeparatedString) {
+			StringTokenizer tokenizer = new StringTokenizer(commaSeparatedString, ", "); //$NON-NLS-1$
+			int count = tokenizer.countTokens();
+			String[] tokens = new String[count];
+			for (int i = 0; i < tokens.length; i++) {
+				tokens[i] = tokenizer.nextToken();
+			}
+			return tokens;
+	}
+
+
+	private static String readKeySequenceText(IConfigurationElement configurationElement) {
+
+		String keySequenceText = configurationElement.getAttribute(ATT_SEQUENCE);
+		if (isEmpty(keySequenceText)) {
+			keySequenceText = configurationElement.getAttribute(ATT_KEY_SEQUENCE);
+		}
+		if (isEmpty(keySequenceText))
+			keySequenceText = configurationElement.getAttribute(ATT_STRING);
+
+		return keySequenceText;
+
+	}
+
+	private static KeySequence readKeySequence(IConfigurationElement configurationElement, List warningsToLog, String commandId, String keySequenceText) {
+
+		KeySequence keySequence = null;
+		if(keySequenceText.equals(configurationElement.getAttribute(ATT_STRING))){
+			// The key sequence is in the old-style format.
+			try {
+				keySequence = convert2_1Sequence(parse2_1Sequence(keySequenceText));
+			} catch (final IllegalArgumentException e) {
+				addWarning(warningsToLog, "Could not parse key sequence", //$NON-NLS-1$
+						configurationElement, commandId, "keySequence", //$NON-NLS-1$
+						keySequenceText);
+				return null;
+			}
+		} else {
+			// The key sequence is in the new-style format.
+			try {
+				keySequence = KeySequence.getInstance(keySequenceText);
+			} catch (final ParseException e) {
+				addWarning(warningsToLog, "Could not parse key sequence", //$NON-NLS-1$
+						configurationElement, commandId, "keySequence", //$NON-NLS-1$
+						keySequenceText);
+				return null;
+			}
+			if (keySequence.isEmpty() || !keySequence.isComplete()) {
+				addWarning(
+						warningsToLog,
+						"Key bindings should not have an empty or incomplete key sequence", //$NON-NLS-1$
+						configurationElement, commandId, "keySequence", //$NON-NLS-1$
+						keySequence.toString());
+				return null;
+			}
+
+		}
+		return keySequence;
+	}
+
+	private static ParameterizedCommand readParameterizedCommand(
+			final List warningsToLog,
+			final IConfigurationElement configurationElement,
+			String viewParameter, final Command command) {
+		final ParameterizedCommand parameterizedCommand;
+		if (command == null) {
+			parameterizedCommand = null;
+		} else if (viewParameter != null) {
+			HashMap parms = new HashMap();
+			parms.put(ShowViewMenu.VIEW_ID_PARM, viewParameter);
+			parameterizedCommand = ParameterizedCommand.generateCommand(command, parms);
+		} else {
+			parameterizedCommand = readParameters(configurationElement,
+					warningsToLog, command);
+		}
+		return parameterizedCommand;
+	}
+
+	/**
+	 *  Reads the specified attribute from the configuration element.
+	 *  If the value is an empty string, will return null.
+	 *
+	 * @param configurationElement
+	 * @return the attribute value
+	 */
+	private static String readNonEmptyAttribute(IConfigurationElement configurationElement, String attribute) {
+		String attributeValue = configurationElement.getAttribute(attribute);
+		if ((attributeValue != null) && (attributeValue.length() == 0)) {
+			attributeValue = null;
+		}
+		return attributeValue;
+	}
+
+
+	private static String readContextId(
+			final IConfigurationElement configurationElement) {
+		String contextId = configurationElement
+				.getAttribute(ATT_CONTEXT_ID);
+		if (LEGACY_DEFAULT_SCOPE.equals(contextId)) {
+			contextId = null;
+		} else if ((contextId == null) || (contextId.length() == 0)) {
+			contextId = configurationElement.getAttribute(ATT_SCOPE);
+			if (LEGACY_DEFAULT_SCOPE.equals(contextId)) {
+				contextId = null;
+			}
+		}
+		if ((contextId == null) || (contextId.length() == 0)) {
+			contextId = IContextIds.CONTEXT_ID_WINDOW;
+		}
+		return contextId;
+	}
+
+
+	private static String readSchemeId(IConfigurationElement configurationElement, List warningsToLog, String commandId) {
+
+		String schemeId = configurationElement.getAttribute(ATT_SCHEME_ID);
+		if ((schemeId == null) || (schemeId.length() == 0)) {
+			schemeId = configurationElement
+					.getAttribute(ATT_KEY_CONFIGURATION_ID);
+			if ((schemeId == null) || (schemeId.length() == 0)) {
+				schemeId = configurationElement
+						.getAttribute(ATT_CONFIGURATION);
+				if ((schemeId == null) || (schemeId.length() == 0)) {
+					// The scheme id should never be null. This is invalid.
+					addWarning(warningsToLog, "Key bindings need a scheme", //$NON-NLS-1$
+							configurationElement, commandId);
+				}
+			}
+		}
+		return schemeId;
+	}
+
+	private static String readCommandId(
+			final IConfigurationElement configurationElement) {
+		String commandId = configurationElement
+				.getAttribute(ATT_COMMAND_ID);
+		if ((commandId == null) || (commandId.length() == 0)) {
+			commandId = configurationElement.getAttribute(ATT_COMMAND);
+		}
+		if ((commandId != null) && (commandId.length() == 0)) {
+			commandId = null;
+		}
+		return commandId;
+	}
+
+	private static boolean isEmpty(String string) {
+		return string == null || string.length() == 0;
+	}
+
+	/**
+	 * Reads all of the scheme definitions from the registry.
+	 *
+	 * @param configurationElements
+	 *            The configuration elements in the commands extension point;
+	 *            must not be <code>null</code>, but may be empty.
+	 * @param configurationElementCount
+	 *            The number of configuration elements that are really in the
+	 *            array.
+	 * @param bindingManager
+	 *            The binding manager to which the schemes should be added; must
+	 *            not be <code>null</code>.
+	 */
+	private static final void readSchemesFromRegistry(
+			final IConfigurationElement[] configurationElements,
+			final int configurationElementCount,
+			final BindingManager bindingManager) {
+		// Undefine all the previous handle objects.
+		final HandleObject[] handleObjects = bindingManager.getDefinedSchemes();
+		if (handleObjects != null) {
+			for (HandleObject handleObject : handleObjects) {
+				handleObject.undefine();
+			}
+		}
+
+		final List warningsToLog = new ArrayList(1);
+
+		for (int i = 0; i < configurationElementCount; i++) {
+			final IConfigurationElement configurationElement = configurationElements[i];
+
+			// Read out the attributes.
+			final String id = readRequired(configurationElement, ATT_ID,
+					warningsToLog, "Schemes need an id"); //$NON-NLS-1$
+			if (id == null) {
+				continue;
+			}
+			final String name = readRequired(configurationElement, ATT_NAME,
+					warningsToLog, "A scheme needs a name", id); //$NON-NLS-1$
+			if (name == null) {
+				continue;
+			}
+			final String description = readOptional(configurationElement,
+					ATT_DESCRIPTION);
+
+			String parentId = configurationElement.getAttribute(ATT_PARENT_ID);
+			if ((parentId != null) && (parentId.length() == 0)) {
+				parentId = configurationElement.getAttribute(ATT_PARENT);
+				if ((parentId != null) && (parentId.length() == 0)) {
+					parentId = null;
+				}
+			}
+
+			// Define the scheme.
+			final Scheme scheme = bindingManager.getScheme(id);
+			scheme.define(name, description, parentId);
+		}
+
+		logWarnings(
+				warningsToLog,
+				"Warnings while parsing the key bindings from the 'org.eclipse.ui.bindings', 'org.eclipse.ui.acceleratorConfigurations' and 'org.eclipse.ui.commands' extension point"); //$NON-NLS-1$
+	}
+
+	/**
+	 * Writes the given active scheme and bindings to the preference store. Only
+	 * bindings that are of the <code>Binding.USER</code> type will be
+	 * written; the others will be ignored.
+	 *
+	 * @param activeScheme
+	 *            The scheme which should be persisted; may be <code>null</code>.
+	 * @param bindings
+	 *            The bindings which should be persisted; may be
+	 *            <code>null</code>
+	 * @throws IOException
+	 *             If something happens while trying to write to the workbench
+	 *             preference store.
+	 */
+	static final void write(final Scheme activeScheme, final Binding[] bindings)
+			throws IOException {
+		// Print out debugging information, if requested.
+		if (DEBUG) {
+			Tracing.printTrace("BINDINGS", "Persisting active scheme '" //$NON-NLS-1$ //$NON-NLS-2$
+					+ activeScheme.getId() + '\'');
+			Tracing.printTrace("BINDINGS", "Persisting bindings"); //$NON-NLS-1$ //$NON-NLS-2$
+		}
+
+		// Write the simple preference key to the UI preference store.
+		writeActiveScheme(activeScheme);
+
+		// Build the XML block for writing the bindings and active scheme.
+		final XMLMemento xmlMemento = XMLMemento
+				.createWriteRoot(EXTENSION_COMMANDS);
+		if (activeScheme != null) {
+			writeActiveSchemeToPreferences(xmlMemento, activeScheme);
+		}
+		if (bindings != null) {
+			final int bindingsLength = bindings.length;
+			for (int i = 0; i < bindingsLength; i++) {
+				final Binding binding = bindings[i];
+				if (binding.getType() == Binding.USER) {
+					writeBindingToPreferences(xmlMemento, binding);
+				}
+			}
+		}
+
+		// Write the XML block to the workbench preference store.
+		final IPreferenceStore preferenceStore = WorkbenchPlugin.getDefault()
+				.getPreferenceStore();
+		final Writer writer = new StringWriter();
+		try {
+			xmlMemento.save(writer);
+			preferenceStore.setValue(EXTENSION_COMMANDS, writer.toString());
+		} finally {
+			writer.close();
+		}
+	}
+
+	/**
+	 * Writes the active scheme to its own preference key. This key is used by
+	 * RCP applications as part of their plug-in customization.
+	 *
+	 * @param scheme
+	 *            The scheme to write to the preference store. If the scheme is
+	 *            <code>null</code>, then it is removed.
+	 */
+	private static final void writeActiveScheme(final Scheme scheme) {
+		final IPreferenceStore store = PlatformUI.getPreferenceStore();
+		final String schemeId = (scheme == null) ? null : scheme.getId();
+		final String defaultSchemeId = store
+				.getDefaultString(IWorkbenchPreferenceConstants.KEY_CONFIGURATION_ID);
+		if ((defaultSchemeId == null) ? (scheme != null) : (!defaultSchemeId
+				.equals(schemeId))) {
+			store.setValue(IWorkbenchPreferenceConstants.KEY_CONFIGURATION_ID,
+					scheme.getId());
+		} else {
+			store
+					.setToDefault(IWorkbenchPreferenceConstants.KEY_CONFIGURATION_ID);
+		}
+	}
+
+	/**
+	 * Writes the active scheme to the memento. If the scheme is
+	 * <code>null</code>, then all schemes in the memento are removed.
+	 *
+	 * @param memento
+	 *            The memento to which the scheme should be written; must not be
+	 *            <code>null</code>.
+	 * @param scheme
+	 *            The scheme that should be written; must not be
+	 *            <code>null</code>.
+	 */
+	private static final void writeActiveSchemeToPreferences(
+			final IMemento memento, final Scheme scheme) {
+		// Add this active scheme, if it is not the default.
+		final IPreferenceStore store = PlatformUI.getPreferenceStore();
+		final String schemeId = scheme.getId();
+		final String defaultSchemeId = store
+				.getDefaultString(IWorkbenchPreferenceConstants.KEY_CONFIGURATION_ID);
+		if ((defaultSchemeId == null) ? (schemeId != null) : (!defaultSchemeId
+				.equals(schemeId))) {
+			final IMemento child = memento
+					.createChild(TAG_ACTIVE_KEY_CONFIGURATION);
+			child.putString(ATT_KEY_CONFIGURATION_ID, schemeId);
+		}
+	}
+
+	/**
+	 * Writes the binding to the memento. This creates a new child element on
+	 * the memento, and places the properties of the binding as its attributes.
+	 *
+	 * @param parent
+	 *            The parent memento for the binding element; must not be
+	 *            <code>null</code>.
+	 * @param binding
+	 *            The binding to write; must not be <code>null</code>.
+	 */
+	private static final void writeBindingToPreferences(final IMemento parent,
+			final Binding binding) {
+		final IMemento element = parent.createChild(TAG_KEY_BINDING);
+		element.putString(ATT_CONTEXT_ID, binding.getContextId());
+		final ParameterizedCommand parameterizedCommand = binding
+				.getParameterizedCommand();
+		final String commandId = (parameterizedCommand == null) ? null
+				: parameterizedCommand.getId();
+		element.putString(ATT_COMMAND_ID, commandId);
+		element.putString(ATT_KEY_CONFIGURATION_ID, binding.getSchemeId());
+		element.putString(ATT_KEY_SEQUENCE, binding.getTriggerSequence()
+				.toString());
+		element.putString(ATT_LOCALE, binding.getLocale());
+		element.putString(ATT_PLATFORM, binding.getPlatform());
+		if (parameterizedCommand != null) {
+			final Map parameterizations = parameterizedCommand
+					.getParameterMap();
+			final Iterator parameterizationItr = parameterizations.entrySet()
+					.iterator();
+			while (parameterizationItr.hasNext()) {
+				final Map.Entry entry = (Map.Entry) parameterizationItr.next();
+				final String id = (String) entry.getKey();
+				final String value = (String) entry.getValue();
+				final IMemento parameterElement = element
+						.createChild(TAG_PARAMETER);
+				parameterElement.putString(ATT_ID, id);
+				parameterElement.putString(ATT_VALUE, value);
+			}
+		}
+	}
+
+	/**
+	 * The binding manager which should be populated with the values from the
+	 * registry and preference store; must not be <code>null</code>.
+	 */
+	private final BindingManager bindingManager;
+
+	/**
+	 * The command service for the workbench; must not be <code>null</code>.
+	 */
+	private final CommandManager commandManager;
+
+	/**
+	 * Constructs a new instance of <code>BindingPersistence</code>.
+	 *
+	 * @param bindingManager
+	 *            The binding manager which should be populated with the values
+	 *            from the registry and preference store; must not be
+	 *            <code>null</code>.
+	 * @param commandService
+	 *            The command service for the workbench; must not be
+	 *            <code>null</code>.
+	 */
+	public BindingPersistence(final BindingManager bindingManager,
+			final CommandManager commandManager) {
+		this.bindingManager = bindingManager;
+		this.commandManager = commandManager;
+		// HACK.  Calling super.read() installs a required preferences change listener.
+		// See bug 266604.
+		super.read();
+	}
+
+	@Override
+	protected final boolean isChangeImportant(final IRegistryChangeEvent event) {
+		return false;
+	}
+
+	public boolean bindingsNeedUpdating(final IRegistryChangeEvent event) {
+		final IExtensionDelta[] acceleratorConfigurationDeltas = event
+				.getExtensionDeltas(
+						PlatformUI.PLUGIN_ID,
+						IWorkbenchRegistryConstants.PL_ACCELERATOR_CONFIGURATIONS);
+		if (acceleratorConfigurationDeltas.length == 0) {
+			final IExtensionDelta[] bindingDeltas = event.getExtensionDeltas(
+					PlatformUI.PLUGIN_ID,
+					IWorkbenchRegistryConstants.PL_BINDINGS);
+			if (bindingDeltas.length == 0) {
+				final IExtensionDelta[] commandDeltas = event
+						.getExtensionDeltas(PlatformUI.PLUGIN_ID,
+								IWorkbenchRegistryConstants.PL_COMMANDS);
+				if (commandDeltas.length == 0) {
+					final IExtensionDelta[] acceleratorScopeDeltas = event
+							.getExtensionDeltas(
+									PlatformUI.PLUGIN_ID,
+									IWorkbenchRegistryConstants.PL_ACCELERATOR_SCOPES);
+					if (acceleratorScopeDeltas.length == 0) {
+						final IExtensionDelta[] contextDeltas = event
+								.getExtensionDeltas(PlatformUI.PLUGIN_ID,
+										IWorkbenchRegistryConstants.PL_CONTEXTS);
+						if (contextDeltas.length == 0) {
+							final IExtensionDelta[] actionDefinitionDeltas = event
+									.getExtensionDeltas(
+											PlatformUI.PLUGIN_ID,
+											IWorkbenchRegistryConstants.PL_ACTION_DEFINITIONS);
+							if (actionDefinitionDeltas.length == 0) {
+								return false;
+							}
+						}
+					}
+				}
+			}
+		}
+
+		return true;
+	}
+
+	@Override
+	protected final boolean isChangeImportant(final PropertyChangeEvent event) {
+		return EXTENSION_COMMANDS.equals(event.getProperty());
+	}
+
+	/**
+	 * Reads all of the binding information from the registry and from the
+	 * preference store.
+	 */
+	@Override
+	public final void read() {
+		super.read();
+		reRead();
+	}
+
+	public void reRead() {
+		// Create the extension registry mementos.
+		final IExtensionRegistry registry = Platform.getExtensionRegistry();
+		int activeSchemeElementCount = 0;
+		int bindingDefinitionCount = 0;
+		int schemeDefinitionCount = 0;
+		final IConfigurationElement[][] indexedConfigurationElements = new IConfigurationElement[3][];
+
+		// Sort the bindings extension point based on element name.
+		final IConfigurationElement[] bindingsExtensionPoint = registry
+				.getConfigurationElementsFor(EXTENSION_BINDINGS);
+		for (final IConfigurationElement configurationElement : bindingsExtensionPoint) {
+			final String name = configurationElement.getName();
+
+			// Check if it is a binding definition.
+			if (TAG_KEY.equals(name)) {
+				addElementToIndexedArray(configurationElement,
+						indexedConfigurationElements,
+						INDEX_BINDING_DEFINITIONS, bindingDefinitionCount++);
+			} else
+			// Check to see if it is a scheme definition.
+			if (TAG_SCHEME.equals(name)) {
+				addElementToIndexedArray(configurationElement,
+						indexedConfigurationElements, INDEX_SCHEME_DEFINITIONS,
+						schemeDefinitionCount++);
+			}
+
+		}
+
+		// Sort the commands extension point based on element name.
+		final IConfigurationElement[] commandsExtensionPoint = registry
+				.getConfigurationElementsFor(EXTENSION_COMMANDS);
+		for (final IConfigurationElement configurationElement : commandsExtensionPoint) {
+			final String name = configurationElement.getName();
+
+			// Check if it is a binding definition.
+			if (TAG_KEY_BINDING.equals(name)) {
+				addElementToIndexedArray(configurationElement,
+						indexedConfigurationElements,
+						INDEX_BINDING_DEFINITIONS, bindingDefinitionCount++);
+
+				// Check if it is a scheme defintion.
+			} else if (TAG_KEY_CONFIGURATION.equals(name)) {
+				addElementToIndexedArray(configurationElement,
+						indexedConfigurationElements, INDEX_SCHEME_DEFINITIONS,
+						schemeDefinitionCount++);
+
+				// Check if it is an active scheme identifier.
+			} else if (TAG_ACTIVE_KEY_CONFIGURATION.equals(name)) {
+				addElementToIndexedArray(configurationElement,
+						indexedConfigurationElements, INDEX_ACTIVE_SCHEME,
+						activeSchemeElementCount++);
+			}
+		}
+
+		/*
+		 * Sort the accelerator configuration extension point into the scheme
+		 * definitions.
+		 */
+		final IConfigurationElement[] acceleratorConfigurationsExtensionPoint = registry
+				.getConfigurationElementsFor(EXTENSION_ACCELERATOR_CONFIGURATIONS);
+		for (final IConfigurationElement configurationElement : acceleratorConfigurationsExtensionPoint) {
+			final String name = configurationElement.getName();
+
+			// Check if the name matches the accelerator configuration element
+			if (TAG_ACCELERATOR_CONFIGURATION.equals(name)) {
+				addElementToIndexedArray(configurationElement,
+						indexedConfigurationElements, INDEX_SCHEME_DEFINITIONS,
+						schemeDefinitionCount++);
+			}
+		}
+
+		// Create the preference memento.
+		final IPreferenceStore store = WorkbenchPlugin.getDefault()
+				.getPreferenceStore();
+		final String preferenceString = store.getString(EXTENSION_COMMANDS);
+		IMemento preferenceMemento = null;
+		if ((preferenceString != null) && (preferenceString.length() > 0)) {
+			final Reader reader = new StringReader(preferenceString);
+			try {
+				preferenceMemento = XMLMemento.createReadRoot(reader);
+			} catch (final WorkbenchException e) {
+				// Could not initialize the preference memento.
+			}
+		}
+
+		// Read the scheme definitions.
+		readSchemesFromRegistry(
+				indexedConfigurationElements[INDEX_SCHEME_DEFINITIONS],
+				schemeDefinitionCount, bindingManager);
+		readActiveScheme(indexedConfigurationElements[INDEX_ACTIVE_SCHEME],
+				activeSchemeElementCount, preferenceMemento, bindingManager);
+		readBindingsFromRegistry(
+				indexedConfigurationElements[INDEX_BINDING_DEFINITIONS],
+				bindingDefinitionCount, bindingManager, commandManager);
+		readBindingsFromPreferences(preferenceMemento, bindingManager,
+				commandManager);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/BindingService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/BindingService.java
new file mode 100644
index 0000000..5111a4c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/BindingService.java
@@ -0,0 +1,767 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ *     Patrik Suzzi <psuzzi@gmail.com> - Bug 479181
+ *******************************************************************************/
+package org.eclipse.ui.internal.keys;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+import org.eclipse.core.commands.CommandManager;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.e4.core.commands.ECommandService;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.di.annotations.Optional;
+import org.eclipse.e4.ui.bindings.EBindingService;
+import org.eclipse.e4.ui.bindings.internal.BindingTable;
+import org.eclipse.e4.ui.bindings.internal.BindingTableManager;
+import org.eclipse.e4.ui.bindings.keys.KeyBindingDispatcher;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.commands.MBindingContext;
+import org.eclipse.e4.ui.model.application.commands.MBindingTable;
+import org.eclipse.e4.ui.model.application.commands.MCommand;
+import org.eclipse.e4.ui.model.application.commands.MCommandsFactory;
+import org.eclipse.e4.ui.model.application.commands.MKeyBinding;
+import org.eclipse.e4.ui.model.application.commands.MParameter;
+import org.eclipse.e4.ui.model.application.commands.impl.CommandsFactoryImpl;
+import org.eclipse.jface.bindings.Binding;
+import org.eclipse.jface.bindings.BindingManager;
+import org.eclipse.jface.bindings.IBindingManagerListener;
+import org.eclipse.jface.bindings.Scheme;
+import org.eclipse.jface.bindings.TriggerSequence;
+import org.eclipse.jface.bindings.keys.KeySequence;
+import org.eclipse.jface.bindings.keys.ParseException;
+import org.eclipse.jface.util.Util;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.keys.IBindingService;
+
+/**
+ * <p>
+ * Provides services related to the binding architecture (e.g., keyboard
+ * shortcuts) within the workbench. This service can be used to access the
+ * currently active bindings, as well as the current state of the binding
+ * architecture.
+ * </p>
+ *
+ * @since 3.1
+ */
+public final class BindingService implements IBindingService {
+
+	@Inject
+	private MApplication application;
+
+	@Inject
+	private EBindingService bindingService;
+
+	@Inject
+	private ECommandService commandService;
+
+	@Inject
+	private CommandManager commandManager;
+
+	@Inject
+	private BindingManager manager;
+
+	@Inject
+	private BindingTableManager tableManager;
+
+	@Inject
+	@Optional
+	private KeyBindingDispatcher dispatcher;
+
+	private BindingPersistence bp;
+
+	private Map<String, MBindingContext> bindingContexts = new HashMap<>();
+
+	private String[] activeSchemeIds;
+
+	/**
+	 * Key assist dialog for workbench key bindings, lazily created and cached
+	 */
+	private GlobalKeyAssistDialog keyAssistDialog;
+
+	private IEclipseContext context;
+
+	@PostConstruct
+	void init() {
+		final Scheme activeScheme = manager.getActiveScheme();
+		if (activeScheme != null) {
+			activeSchemeIds = getSchemeIds(activeScheme.getId());
+			tableManager.setActiveSchemes(activeSchemeIds);
+		}
+		// Initialize BindingPersistence, its needed to install
+		// a preferences change listener. See bug 266604.
+		bp = new BindingPersistence(manager, commandManager) {
+			@Override
+			public void reRead() {
+				super.reRead();
+				// after having read the registry and preferences, persist
+				// and update the model
+				persistToModel(manager.getActiveScheme());
+			}
+		};
+	}
+
+	@Override
+	public void dispose() {
+		if (bp != null) {
+			bp.dispose();
+		}
+	}
+
+	@Inject
+	public void setContext(IEclipseContext context) {
+		this.context = context;
+	}
+
+	@Override
+	public void addBindingManagerListener(IBindingManagerListener listener) {
+		manager.addBindingManagerListener(listener);
+	}
+
+	@Override
+	public void removeBindingManagerListener(IBindingManagerListener listener) {
+		manager.removeBindingManagerListener(listener);
+	}
+
+	@Override
+	public TriggerSequence[] getActiveBindingsFor(ParameterizedCommand parameterizedCommand) {
+		Collection<TriggerSequence> seq = bindingService.getSequencesFor(parameterizedCommand);
+		return seq.toArray(new TriggerSequence[seq.size()]);
+	}
+
+	@Override
+	public TriggerSequence[] getActiveBindingsFor(String commandId) {
+		return getActiveBindingsFor(commandService.createCommand(commandId, null));
+	}
+
+	@Override
+	public Scheme getActiveScheme() {
+		return manager.getActiveScheme();
+	}
+
+	@Override
+	public TriggerSequence getBestActiveBindingFor(ParameterizedCommand command) {
+		TriggerSequence seq = bindingService.getBestSequenceFor(command);
+		return seq;
+	}
+
+	@Override
+	public TriggerSequence getBestActiveBindingFor(String commandId) {
+		ParameterizedCommand cmd = commandService.createCommand(commandId, null);
+		return bindingService.getBestSequenceFor(cmd);
+	}
+
+	@Override
+	public String getBestActiveBindingFormattedFor(String commandId) {
+		TriggerSequence sequence = bindingService.getBestSequenceFor(commandService.createCommand(
+				commandId, null));
+		return sequence == null ? null : sequence.format();
+	}
+
+	@Override
+	public Binding[] getBindings() {
+		return manager.getBindings();
+	}
+
+	@Override
+	public TriggerSequence getBuffer() {
+		if (dispatcher == null) {
+			return KeySequence.getInstance();
+		}
+		return dispatcher.getBuffer();
+	}
+
+	@Override
+	public String getDefaultSchemeId() {
+		return BindingPersistence.getDefaultSchemeId();
+	}
+
+	@Override
+	public Scheme[] getDefinedSchemes() {
+		return manager.getDefinedSchemes();
+	}
+
+	@Override
+	public String getLocale() {
+		return manager.getLocale();
+	}
+
+	@Override
+	public Map getPartialMatches(TriggerSequence trigger) {
+		final Collection<Binding> partialMatches = bindingService.getPartialMatches(trigger);
+		final Map<TriggerSequence, Binding> result = new HashMap<>(
+				partialMatches.size());
+
+		for (Binding binding : partialMatches) {
+			result.put(binding.getTriggerSequence(), binding);
+		}
+
+		return result;
+	}
+
+	@Override
+	public Binding getPerfectMatch(TriggerSequence trigger) {
+		return bindingService.getPerfectMatch(trigger);
+	}
+
+	@Override
+	public String getPlatform() {
+		return Util.getWS();
+	}
+
+	@Override
+	public Scheme getScheme(String schemeId) {
+		return manager.getScheme(schemeId);
+	}
+
+	@Override
+	public boolean isKeyFilterEnabled() {
+		return dispatcher == null ? false : dispatcher.getKeyDownFilter().isEnabled();
+	}
+
+	@Override
+	public boolean isPartialMatch(TriggerSequence trigger) {
+		return bindingService.isPartialMatch(trigger);
+	}
+
+	@Override
+	public boolean isPerfectMatch(TriggerSequence trigger) {
+		return bindingService.isPerfectMatch(trigger);
+	}
+
+	@Override
+	public void openKeyAssistDialog() {
+		if (keyAssistDialog == null) {
+			Display.getCurrent();
+			keyAssistDialog = new GlobalKeyAssistDialog(context, dispatcher);
+		}
+		if (keyAssistDialog.getShell() == null) {
+			keyAssistDialog.setParentShell(Display.getCurrent().getActiveShell());
+		}
+		keyAssistDialog.open();
+	}
+
+	@Override
+	public void readRegistryAndPreferences(ICommandService commandService) {
+		bp.read();
+	}
+
+	private void saveLegacyPreferences(Scheme activeScheme, Binding[] bindings) throws IOException {
+		BindingPersistence.write(activeScheme, bindings);
+		try {
+			manager.setActiveScheme(activeScheme);
+		} catch (final NotDefinedException e) {
+			WorkbenchPlugin.log("The active scheme is not currently defined.", //$NON-NLS-1$
+					WorkbenchPlugin.getStatus(e));
+		}
+		manager.setBindings(bindings);
+	}
+
+	@Override
+	public void savePreferences(Scheme activeScheme, Binding[] bindings) throws IOException {
+		saveLegacyPreferences(activeScheme, bindings);
+		persistToModel(activeScheme);
+	}
+
+	private void persistToModel(Scheme activeScheme) {
+		// save the active scheme to the model
+		writeSchemeToModel(activeScheme);
+		activeSchemeIds = getSchemeIds(activeScheme.getId());
+		tableManager.setActiveSchemes(activeSchemeIds);
+
+		// weeds out any of the deleted system bindings using the binding
+		// manager
+		HashSet<Binding> activeBindings = new HashSet<Binding>(manager.getActiveBindingsDisregardingContextFlat());
+
+		// get all of the (active) model bindings that point to the actual runtime
+		// bindings
+		HashMap<Binding, MKeyBinding> bindingToKey = new HashMap<>();
+		for (MBindingTable table : application.getBindingTables()) {
+			for (MKeyBinding modelBinding : table.getBindings()) {
+				final Object obj = modelBinding.getTransientData().get(
+						EBindingService.MODEL_TO_BINDING_KEY);
+				if (obj instanceof Binding) {
+					bindingToKey.put((Binding) obj, modelBinding);
+				}
+			}
+		}
+
+		// go through each of the (active) bindings in the model to see if there are any
+		// bindings that we should remove
+		final HashSet<Binding> deleted = new HashSet<>(bindingToKey.keySet());
+		deleted.removeAll(activeBindings);
+		for (Binding binding : deleted) {
+			if (binding.getType() == Binding.USER) {
+				removeBinding(binding);
+			} else {
+				final MKeyBinding model = bindingToKey.get(binding);
+				if (!model.getTags().contains(EBindingService.DELETED_BINDING_TAG)) {
+					model.getTags().add(EBindingService.DELETED_BINDING_TAG);
+				}
+			}
+		}
+
+		// go through each of the active bindings (from the binding manager) to
+		// see if there are any bindings that we should add to the runtime
+		for (Binding binding : activeBindings) {
+			final MKeyBinding model = bindingToKey.get(binding);
+			MKeyBinding toAddModel = model;
+			Binding toAddBinding = binding;
+
+			// if we've switched schemes then we need to check to see if we
+			// should override any of the old bindings
+			final Binding conflict = findPotentialConflict(binding);
+
+			if (conflict != null && conflict.getContextId().equals(binding.getContextId())) {
+				final int rc = compareTo(conflict, binding);
+				if (rc < 0) {
+					// we need to delete the existing binding
+					final MKeyBinding conflictModel = bindingToKey.get(conflict);
+					if (conflict.getType() == Binding.USER) {
+						removeBinding(conflict);
+					} else if (conflictModel != null) {
+						if (!conflictModel.getTags().contains(EBindingService.DELETED_BINDING_TAG)) {
+							conflictModel.getTags().add(EBindingService.DELETED_BINDING_TAG);
+						}
+					}
+				} else if (rc > 0) {
+					// the existing binding is correct
+					// we need to delete the new binding
+					if (binding.getType() == Binding.USER) {
+						removeBinding(binding);
+					} else if (model != null) {
+						if (!model.getTags().contains(EBindingService.DELETED_BINDING_TAG)) {
+							model.getTags().add(EBindingService.DELETED_BINDING_TAG);
+						}
+					}
+					// make sure we don't re-add them
+					toAddModel = null;
+					toAddBinding = null;
+				}
+			}
+			if (toAddModel != null) {
+				if (toAddModel.getTags().contains(EBindingService.DELETED_BINDING_TAG)) {
+					toAddModel.getTags().remove(EBindingService.DELETED_BINDING_TAG);
+				}
+			} else if (toAddBinding != null) {
+				addBinding(toAddBinding);
+			}
+
+		}
+	}
+
+	private Binding findPotentialConflict(Binding binding) {
+		BindingTable table = tableManager.getTable(binding.getContextId());
+		if (table != null) {
+			Binding perfectMatch = table.getPerfectMatch(binding.getTriggerSequence());
+			if (perfectMatch != null) {
+				return perfectMatch;
+			}
+		}
+		return bindingService.getPerfectMatch(binding.getTriggerSequence());
+	}
+
+	private final String[] getSchemeIds(String schemeId) {
+		final List<String> strings = new ArrayList<>();
+		while (schemeId != null) {
+			strings.add(schemeId);
+			try {
+				schemeId = getScheme(schemeId).getParentId();
+			} catch (final NotDefinedException e) {
+				return new String[0];
+			}
+		}
+
+		return strings.toArray(new String[strings.size()]);
+	}
+
+	/*
+	 * Copied from
+	 * org.eclipse.jface.bindings.BindingManager.compareSchemes(String, String)
+	 *
+	 * Returns an in based on scheme 1 < scheme 2
+	 */
+	private final int compareSchemes(final String schemeId1, final String schemeId2) {
+		if (activeSchemeIds == null) {
+			return 0;
+		}
+		if (!schemeId2.equals(schemeId1)) {
+			for (final String schemePointer : activeSchemeIds) {
+				if (schemeId2.equals(schemePointer)) {
+					return 1;
+				} else if (schemeId1.equals(schemePointer)) {
+					return -1;
+				}
+			}
+		}
+		return 0;
+	}
+
+	/**
+	 * Compare 2 bindings, taking into account Scheme and type.
+	 *
+	 * @param current
+	 *            the existing binding
+	 * @param addition
+	 *            the incoming binding
+	 * @return an int indicating current > addition
+	 */
+	private int compareTo(Binding current, Binding addition) {
+		final Scheme s1 = manager.getScheme(current.getSchemeId());
+		final Scheme s2 = manager.getScheme(addition.getSchemeId());
+		if (!s1.equals(s2)) {
+			int rc = compareSchemes(s1.getId(), s2.getId());
+			if (rc != 0) {
+				// this is because the compare is inverted
+				return rc > 0 ? -1 : 1;
+			}
+		}
+		return current.getType() - addition.getType();
+	}
+
+
+	private void writeSchemeToModel(Scheme activeScheme) {
+		List<String> tags = application.getTags();
+		boolean found = false;
+		// replace the old scheme id
+		Iterator<String> i = tags.iterator();
+		while (i.hasNext() && !found) {
+			String tag = i.next();
+			if (tag.startsWith(EBindingService.ACTIVE_SCHEME_TAG)) {
+				i.remove();
+				found = true;
+			}
+		}
+		tags.add(EBindingService.ACTIVE_SCHEME_TAG + ":" + activeScheme.getId()); //$NON-NLS-1$
+	}
+
+	@Override
+	public void setKeyFilterEnabled(boolean enabled) {
+		if (dispatcher != null) {
+			dispatcher.getKeyDownFilter().setEnabled(enabled);
+		}
+	}
+
+	@Override
+	public Collection<Binding> getConflictsFor(TriggerSequence sequence) {
+		return bindingService.getConflictsFor(sequence);
+	}
+
+	public MBindingContext getBindingContext(String id) {
+		// cache
+		MBindingContext result = bindingContexts.get(id);
+		if (result == null) {
+			// search
+			result = searchContexts(id, application.getRootContext());
+			if (result == null) {
+				// create
+				result = MCommandsFactory.INSTANCE.createBindingContext();
+				result.setElementId(id);
+				result.setName("Auto::" + id); //$NON-NLS-1$
+				application.getRootContext().add(result);
+			}
+			if (result != null) {
+				bindingContexts.put(id, result);
+			}
+		}
+		return result;
+	}
+
+	/**
+	 * @param id
+	 * @param rootContext
+	 * @return
+	 */
+	private MBindingContext searchContexts(String id, List<MBindingContext> rootContext) {
+		for (MBindingContext context : rootContext) {
+			if (context.getElementId().equals(id)) {
+				return context;
+			}
+			MBindingContext result = searchContexts(id, context.getChildren());
+			if (result != null) {
+				return result;
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * TODO Promote this method to API.
+	 * <p>
+	 * Adds a single new binding to the existing array of bindings. If the array
+	 * is currently <code>null</code>, then a new array is created and this
+	 * binding is added to it. This method does not detect duplicates.
+	 * </p>
+	 * <p>
+	 * This method completes in amortized <code>O(1)</code>.
+	 * </p>
+	 *
+	 * @param binding
+	 *            The binding to be added; must not be <code>null</code>.
+	 */
+	public final void addBinding(final Binding binding) {
+		MBindingTable table = getMTable(binding.getContextId());
+		createORupdateMKeyBinding(application, table, binding);
+	}
+
+	/**
+	 * @param contextId
+	 * @return
+	 */
+	private MBindingTable getMTable(String contextId) {
+		for (MBindingTable bt : application.getBindingTables()) {
+			if (bt.getBindingContext().getElementId().equals(contextId)) {
+				return bt;
+			}
+		}
+		// create a new table if we couldn't find one
+		MBindingTable table = CommandsFactoryImpl.eINSTANCE.createBindingTable();
+		table.setBindingContext(getBindingContext(contextId));
+		table.setElementId(contextId);
+		application.getBindingTables().add(table);
+		return table;
+
+	}
+
+	static private boolean isSameBinding(MKeyBinding existingBinding, MCommand cmd, Binding binding) {
+		// see org.eclipse.jface.bindings.Binding#equals(final Object object)
+		if (!cmd.equals(existingBinding.getCommand()))
+			return false;
+		String existingKeySequence = existingBinding.getKeySequence();
+		if (existingKeySequence == null)
+			return false;
+		try {
+			final KeySequence existingSequence = KeySequence.getInstance(existingKeySequence);
+			if (!existingSequence.equals(binding.getTriggerSequence()))
+				return false;
+		} catch (ParseException e) {
+			return false;
+		}
+
+		// tags to look for:
+		final List<String> modelTags = existingBinding.getTags();
+
+		String schemeId = binding.getSchemeId();
+		if (schemeId != null && !schemeId.equals(BindingPersistence.getDefaultSchemeId())) {
+			if (!modelTags.contains(EBindingService.SCHEME_ID_ATTR_TAG + ":" + schemeId)) //$NON-NLS-1$
+				return false;
+		}
+		String locale = binding.getLocale();
+		if (locale != null) {
+			if (!modelTags.contains(EBindingService.LOCALE_ATTR_TAG + ":" + locale)) //$NON-NLS-1$
+				return false;
+		}
+		String platform = binding.getPlatform();
+		if (platform != null) {
+			if (!modelTags.contains(EBindingService.PLATFORM_ATTR_TAG + ":" + platform)) //$NON-NLS-1$
+				return false;
+		}
+		if (binding.getType() == Binding.USER) {
+			if (!modelTags.contains(EBindingService.TYPE_ATTR_TAG + ":user")) //$NON-NLS-1$
+				return false;
+		}
+		return true;
+	}
+
+	// TBD the "update" procedure should not typically be run.
+	// Add some sort of timestamp on the source files and update
+	// only when it changes
+	// TBD placement: this should be in the "3.x bridge" code
+	static public MKeyBinding createORupdateMKeyBinding(MApplication application,
+			MBindingTable table,
+			Binding binding) {
+		boolean addToTable = false;
+
+		ParameterizedCommand parmCmd = binding.getParameterizedCommand();
+
+		String id = parmCmd.getId();
+		MCommand cmd = application.getCommand(id);
+		if (cmd == null) {
+			return null;
+		}
+
+		MKeyBinding keyBinding = null;
+		for (MKeyBinding existingBinding : table.getBindings()) {
+			Binding b = (Binding) existingBinding.getTransientData().get(
+					EBindingService.MODEL_TO_BINDING_KEY);
+			if (binding.equals(b)) {
+				keyBinding = existingBinding;
+				break;
+			}
+			if (isSameBinding(existingBinding, cmd, binding)) {
+				keyBinding = existingBinding;
+				break;
+			}
+		}
+
+		if (keyBinding == null) {
+			addToTable = true;
+			keyBinding = CommandsFactoryImpl.eINSTANCE.createKeyBinding();
+			keyBinding.setCommand(cmd);
+			keyBinding.setKeySequence(binding.getTriggerSequence().toString());
+
+			for (Object obj : parmCmd.getParameterMap().entrySet()) {
+				@SuppressWarnings({ "unchecked" })
+				Map.Entry<String, String> entry = (Map.Entry<String, String>) obj;
+
+				String paramID = entry.getKey();
+				if (paramID == null)
+					continue;
+				List<MParameter> bindingParams = keyBinding.getParameters();
+				MParameter p = null;
+				for (MParameter param : bindingParams) {
+					if (paramID.equals(param.getElementId())) {
+						p = param;
+						break;
+					}
+				}
+				if (p == null) {
+					p = CommandsFactoryImpl.eINSTANCE.createParameter();
+					p.setElementId(entry.getKey());
+					keyBinding.getParameters().add(p);
+				}
+				p.setName(entry.getKey());
+				p.setValue(entry.getValue());
+			}
+
+			List<String> tags = keyBinding.getTags();
+			// just add the 'schemeId' tag if the binding is for anything other
+			// than
+			// the default scheme
+			if (binding.getSchemeId() != null
+					&& !binding.getSchemeId().equals(BindingPersistence.getDefaultSchemeId())) {
+				tags.add(EBindingService.SCHEME_ID_ATTR_TAG + ":" + binding.getSchemeId()); //$NON-NLS-1$
+			}
+			if (binding.getLocale() != null) {
+				tags.add(EBindingService.LOCALE_ATTR_TAG + ":" + binding.getLocale()); //$NON-NLS-1$
+			}
+			if (binding.getPlatform() != null) {
+				tags.add(EBindingService.PLATFORM_ATTR_TAG + ":" + binding.getPlatform()); //$NON-NLS-1$
+			}
+			// just add the 'type' tag if it's a user binding
+			if (binding.getType() == Binding.USER) {
+				tags.add(EBindingService.TYPE_ATTR_TAG + ":user"); //$NON-NLS-1$
+			}
+		}
+
+		keyBinding.getTransientData().put(EBindingService.MODEL_TO_BINDING_KEY, binding);
+		if (addToTable) {
+			table.getBindings().add(keyBinding);
+		}
+		return keyBinding;
+	}
+
+	private MKeyBinding findMKeyBinding(MBindingTable table, Binding binding) {
+		List<MKeyBinding> mBindings = table.getBindings();
+
+		String bindingSchemeId = binding.getSchemeId() == null ? IBindingService.DEFAULT_DEFAULT_ACTIVE_SCHEME_ID
+				: binding.getSchemeId();
+
+		if (binding.getParameterizedCommand() != null) {
+			String commandId = binding.getParameterizedCommand().getId();
+
+			for (MKeyBinding curr : mBindings) {
+				Binding transientBinding = (Binding) curr.getTransientData().get(
+						EBindingService.MODEL_TO_BINDING_KEY);
+				if (transientBinding != null) {
+					if (binding.equals(transientBinding)) {
+						return curr;
+					}
+					continue;
+				}
+				// check equality
+				if (curr.getKeySequence().equals(binding.getTriggerSequence().toString())
+						&& curr.getCommand() != null
+						&& curr.getCommand().getElementId().equals(commandId)) {
+
+					String schemeId = IBindingService.DEFAULT_DEFAULT_ACTIVE_SCHEME_ID;
+					List<String> tags = curr.getTags();
+					// grab the scheme id from the tags
+					for (String tag : tags) {
+						if (tag.startsWith(EBindingService.SCHEME_ID_ATTR_TAG)) {
+							schemeId = tag.substring(9);
+							break;
+						}
+					}
+					// if the scheme ids are the same, then we found the
+					// MKeyBinding
+					if (schemeId.equals(bindingSchemeId)) {
+						return curr;
+					}
+				}
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Remove the specific binding by identity. Does nothing if the binding is
+	 * not in the manager.
+	 *
+	 * @param binding
+	 *            The binding to be removed; must not be <code>null</code>.
+	 */
+	public final void removeBinding(final Binding binding) {
+		MKeyBinding mKeyBinding;
+		MBindingTable table = null;
+		for (MBindingTable bt : application.getBindingTables()) {
+			if (bt.getBindingContext().getElementId().equals(binding.getContextId())) {
+				table = bt;
+				break;
+			}
+		}
+		if (table == null) {
+			return;
+		}
+
+		// if we're removing a user binding, just remove it from the model and
+		// the listeners will take care of removing the binding from the runtime
+		// system
+		if (binding.getType() == Binding.USER) {
+			mKeyBinding = this.findMKeyBinding(table, binding);
+			if (mKeyBinding != null) {
+				table.getBindings().remove(mKeyBinding);
+			}
+		}
+		// if we're removing a system binding, then find the model binding, add
+		// a 'deleted' tag, and explicitly remove the binding from the runtime
+		// system
+		else {
+			mKeyBinding = this.findMKeyBinding(table, binding);
+			if (mKeyBinding != null) {
+				mKeyBinding.getTags().add(EBindingService.DELETED_BINDING_TAG);
+			}
+		}
+	}
+
+	public BindingManager getBindingManager() {
+		return manager;
+	}
+
+	public Collection<Binding> getActiveBindings() {
+		return bindingService.getActiveBindings();
+	}
+
+	public WorkbenchKeyboard getKeyboard() {
+		return new WorkbenchKeyboard(dispatcher);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/CancelOnModifyListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/CancelOnModifyListener.java
new file mode 100644
index 0000000..a448fce
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/CancelOnModifyListener.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.keys;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Widget;
+
+/**
+ * A listener that removes the out-of-order listener if a modification occurs
+ * before reaching it. This is a workaround for Bug 53497.
+ *
+ * @since 3.0
+ */
+final class CancelOnModifyListener implements Listener {
+
+    /**
+     * The listener to remove when this listener catches any event. This value
+     * should not be <code>null</code>.
+     */
+    private final Listener chainedListener;
+
+    /**
+     * Constructs a new instance of <code>CancelOnModifyListener</code>
+     *
+     * @param listener
+     *            The listener which should be removed in the event of a
+     *            modification event arriving; should not be <code>null</code>.
+     */
+    CancelOnModifyListener(Listener listener) {
+        chainedListener = listener;
+    }
+
+    @Override
+	public void handleEvent(Event event) {
+        Widget widget = event.widget;
+        widget.removeListener(SWT.Modify, this);
+        widget.removeListener(SWT.KeyDown, chainedListener);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/CategoryPatternFilter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/CategoryPatternFilter.java
new file mode 100644
index 0000000..717f379
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/CategoryPatternFilter.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal.keys;
+
+import org.eclipse.core.commands.Category;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.jface.bindings.Binding;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.ui.dialogs.PatternFilter;
+import org.eclipse.ui.internal.keys.model.BindingElement;
+
+class CategoryPatternFilter extends PatternFilter {
+	private boolean filterCategories;
+	final Category uncategorized;
+
+	public CategoryPatternFilter(boolean filterCategories, Category c) {
+		uncategorized = c;
+		filterCategories(filterCategories);
+	}
+
+	public void filterCategories(boolean b) {
+		filterCategories = b;
+		if (filterCategories) {
+			setPattern("org.eclipse.ui.keys.optimization.false"); //$NON-NLS-1$
+		} else {
+			setPattern("org.eclipse.ui.keys.optimization.true"); //$NON-NLS-1$
+		}
+	}
+
+	public boolean isFilteringCategories() {
+		return filterCategories;
+	}
+
+	@Override
+	protected boolean isLeafMatch(Viewer viewer, Object element) {
+		if (filterCategories) {
+			final ParameterizedCommand cmd = getCommand(element);
+			try {
+				if (cmd != null
+						&& cmd.getCommand().getCategory() == uncategorized) {
+					return false;
+				}
+			} catch (NotDefinedException e) {
+				return false;
+			}
+		}
+		return super.isLeafMatch(viewer, element);
+	}
+
+	private ParameterizedCommand getCommand(Object element) {
+		if (element instanceof BindingElement) {
+			Object modelObject = ((BindingElement) element).getModelObject();
+			if (modelObject instanceof Binding) {
+				return ((Binding) modelObject).getParameterizedCommand();
+			} else if (modelObject instanceof ParameterizedCommand) {
+				return (ParameterizedCommand) modelObject;
+			}
+		}
+		return null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/CompactKeyFormatter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/CompactKeyFormatter.java
new file mode 100644
index 0000000..d4573c6
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/CompactKeyFormatter.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.keys;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.eclipse.ui.keys.KeySequence;
+import org.eclipse.ui.keys.KeyStroke;
+import org.eclipse.ui.keys.ModifierKey;
+import org.eclipse.ui.keys.NaturalKey;
+
+/**
+ * A key formatter providing a special compact format for displaying key
+ * bindings.
+ *
+ * @since 3.0
+ */
+public class CompactKeyFormatter extends NativeKeyFormatter {
+
+    @Override
+	public String format(KeySequence keySequence) {
+        StringBuffer stringBuffer = new StringBuffer();
+
+        List keyStrokes = keySequence.getKeyStrokes();
+        KeyStroke[] keyStrokeArray = (KeyStroke[]) keyStrokes
+                .toArray(new KeyStroke[keyStrokes.size()]);
+        Set previousModifierKeys = Collections.EMPTY_SET;
+        List naturalKeys = new ArrayList();
+        for (int i = 0; i < keyStrokeArray.length; i++) {
+            KeyStroke keyStroke = keyStrokeArray[i];
+            Set currentModifierKeys = keyStroke.getModifierKeys();
+
+            if (!previousModifierKeys.equals(currentModifierKeys)) {
+                // End the old sequence fragment.
+                if (i > 0) {
+                    stringBuffer.append(formatKeyStrokes(previousModifierKeys,
+                            naturalKeys));
+                    stringBuffer.append(getKeyStrokeDelimiter());
+                }
+
+                // Start a new one.
+                previousModifierKeys = currentModifierKeys;
+                naturalKeys.clear();
+
+            }
+
+            naturalKeys.add(keyStroke.getNaturalKey());
+        }
+
+        stringBuffer
+                .append(formatKeyStrokes(previousModifierKeys, naturalKeys));
+
+        return stringBuffer.toString();
+    }
+
+    public String formatKeyStrokes(Set modifierKeys, List naturalKeys) {
+        StringBuffer stringBuffer = new StringBuffer();
+        String keyDelimiter = getKeyDelimiter();
+
+        // Format the modifier keys, in sorted order.
+        SortedSet sortedModifierKeys = new TreeSet(getModifierKeyComparator());
+        sortedModifierKeys.addAll(modifierKeys);
+        Iterator sortedModifierKeyItr = sortedModifierKeys.iterator();
+        while (sortedModifierKeyItr.hasNext()) {
+            stringBuffer.append(format((ModifierKey) sortedModifierKeyItr
+                    .next()));
+            stringBuffer.append(keyDelimiter);
+        }
+
+        // Format the natural key, if any.
+        Iterator naturalKeyItr = naturalKeys.iterator();
+        while (naturalKeyItr.hasNext()) {
+            Object naturalKey = naturalKeyItr.next();
+            if (naturalKey instanceof NaturalKey) {
+                stringBuffer.append(format((NaturalKey) naturalKey));
+                if (naturalKeyItr.hasNext()) {
+                    stringBuffer.append(keyDelimiter);
+                }
+            }
+        }
+
+        return stringBuffer.toString();
+
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/EmacsKeyFormatter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/EmacsKeyFormatter.java
new file mode 100644
index 0000000..19b9d6a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/EmacsKeyFormatter.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.keys;
+
+import java.util.Comparator;
+import java.util.ResourceBundle;
+
+import org.eclipse.ui.internal.util.Util;
+import org.eclipse.ui.keys.Key;
+import org.eclipse.ui.keys.KeySequence;
+import org.eclipse.ui.keys.KeyStroke;
+import org.eclipse.ui.keys.ModifierKey;
+
+/**
+ * A key formatter providing the Emacs-style accelerators using single letters
+ * to represent the modifier keys.
+ *
+ * @since 3.0
+ */
+public class EmacsKeyFormatter extends AbstractKeyFormatter {
+
+    /**
+     * A comparator that guarantees that modifier keys will be sorted the same
+     * across different platforms.
+     */
+    private static final Comparator EMACS_MODIFIER_KEY_COMPARATOR = new AlphabeticModifierKeyComparator();
+
+    /**
+     * The resource bundle used by <code>format()</code> to translate formal
+     * string representations by locale.
+     */
+    private final static ResourceBundle RESOURCE_BUNDLE = ResourceBundle
+            .getBundle(EmacsKeyFormatter.class.getName());
+
+    /**
+     * Formats an individual key into a human readable format. This converts
+     * the key into a format similar to Xemacs.
+     *
+     * @param key
+     *            The key to format; must not be <code>null</code>.
+     * @return The key formatted as a string; should not be <code>null</code>.
+     */
+    @Override
+	public String format(Key key) {
+        if (key instanceof ModifierKey) {
+            String formattedName = Util.translateString(RESOURCE_BUNDLE, key
+                    .toString(), null, false, false);
+            if (formattedName != null) {
+                return formattedName;
+            }
+        }
+
+        return super.format(key).toLowerCase();
+    }
+
+    @Override
+	protected String getKeyDelimiter() {
+        return Util.translateString(RESOURCE_BUNDLE, KEY_DELIMITER_KEY,
+                KeyStroke.KEY_DELIMITER, false, false);
+    }
+
+    @Override
+	protected String getKeyStrokeDelimiter() {
+        return Util.translateString(RESOURCE_BUNDLE, KEY_STROKE_DELIMITER_KEY,
+                KeySequence.KEY_STROKE_DELIMITER, false, false);
+    }
+
+    @Override
+	protected Comparator getModifierKeyComparator() {
+        return EMACS_MODIFIER_KEY_COMPARATOR;
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/EmacsKeyFormatter.properties b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/EmacsKeyFormatter.properties
new file mode 100644
index 0000000..5d6e98f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/EmacsKeyFormatter.properties
@@ -0,0 +1,19 @@
+###############################################################################
+# Copyright (c) 2000, 2006 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
+###############################################################################
+
+# Modifier keys
+ALT=M
+COMMAND=D
+CTRL=C
+SHIFT=S
+
+# Delimiters
+KEY_DELIMITER=-
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/FormalKeyFormatter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/FormalKeyFormatter.java
new file mode 100644
index 0000000..d6dc625
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/FormalKeyFormatter.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.keys;
+
+import java.util.Comparator;
+
+import org.eclipse.ui.keys.Key;
+import org.eclipse.ui.keys.KeySequence;
+import org.eclipse.ui.keys.KeyStroke;
+
+/**
+ * Formats the keys in the internal key sequence grammar. This is used for
+ * persistence, and is not really intended for display to the user.
+ *
+ * @since 3.0
+ */
+public class FormalKeyFormatter extends AbstractKeyFormatter {
+
+    /**
+     * A comparator that guarantees that modifier keys will be sorted the same
+     * across different platforms.
+     */
+    private static final Comparator FORMAL_MODIFIER_KEY_COMPARATOR = new AlphabeticModifierKeyComparator();
+
+    @Override
+	public String format(Key key) {
+        return key.toString();
+    }
+
+    @Override
+	protected String getKeyDelimiter() {
+        return KeyStroke.KEY_DELIMITER;
+    }
+
+    @Override
+	protected String getKeyStrokeDelimiter() {
+        return KeySequence.KEY_STROKE_DELIMITER;
+    }
+
+    @Override
+	protected Comparator getModifierKeyComparator() {
+        return FORMAL_MODIFIER_KEY_COMPARATOR;
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/GlobalKeyAssistDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/GlobalKeyAssistDialog.java
new file mode 100644
index 0000000..1a9733f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/GlobalKeyAssistDialog.java
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * Copyright (c) 2012, 2015 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.ui.internal.keys;
+
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.e4.core.commands.ECommandService;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.ui.bindings.EBindingService;
+import org.eclipse.e4.ui.bindings.internal.KeyAssistDialog;
+import org.eclipse.e4.ui.bindings.keys.KeyBindingDispatcher;
+import org.eclipse.jface.bindings.TriggerSequence;
+import org.eclipse.jface.preference.PreferenceDialog;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.dialogs.PreferencesUtil;
+
+/**
+ * Extends the key conflict popup dialog to provide a full list of global key
+ * bindings for the workbench. If {@link #open()} is called while this dialog is
+ * still open, the keys preference page is opened.
+ *
+ *
+ */
+public class GlobalKeyAssistDialog extends KeyAssistDialog {
+
+	/**
+	 * Context for this dialog, used to open services
+	 */
+	private IEclipseContext context;
+
+	/**
+	 * ID of the key binding preference page
+	 */
+	private final String keysPageId = "org.eclipse.ui.preferencePages.Keys"; //$NON-NLS-1$
+
+	/**
+	 * Whether this dialog is currently open, if the dialog is opened again, we
+	 * open the preference page instead
+	 */
+	private boolean isOpen;
+
+	/**
+	 * @param context
+	 * @param associatedKeyboard
+	 * @param associatedState
+	 */
+	public GlobalKeyAssistDialog(IEclipseContext context, KeyBindingDispatcher associatedKeyboard) {
+		super(context, associatedKeyboard);
+		this.context = context;
+		setInfoText(getInfoText());
+	}
+
+	@Override
+	public int open() {
+		if (isOpen) {
+			return openPreferencePage();
+		}
+		isOpen = true;
+		return super.open();
+	}
+
+	@Override
+	public boolean close() {
+		isOpen = false;
+		return super.close();
+	}
+
+	/**
+	 * Determines what keybinding was used to open this dialog and returns an
+	 * info string using that binding. ex:
+	 * "Press 'Ctrl-Shift-L') to open the preference page";
+	 *
+	 * @return info text for this dialog
+	 */
+	private String getInfoText() {
+		ECommandService commandService = context.getActiveLeaf().get(ECommandService.class);
+		Command cmd = commandService.getCommand(IWorkbenchCommandConstants.WINDOW_SHOW_KEY_ASSIST);
+
+		if (cmd != null) {
+			EBindingService bindingService = context.getActiveLeaf().get(EBindingService.class);
+			TriggerSequence keySeq = bindingService.getBestSequenceFor(new ParameterizedCommand(
+					cmd, null));
+
+			if (keySeq != null) {
+				return NLS.bind(KeyAssistMessages.openPreferencePage, keySeq.format());
+			}
+		}
+
+		return ""; //$NON-NLS-1$
+	}
+
+	/**
+	 * Opens the key binding preference page, closes this dialog
+	 */
+	private int openPreferencePage() {
+		// Create a preference dialog on the keys preference page.
+
+		Shell shell = getShell();
+		if (shell.getParent() != null) {
+			shell = shell.getParent().getShell();
+		}
+
+		PreferenceDialog dialog = PreferencesUtil.createPreferenceDialogOn(shell,
+				keysPageId, null, getSelectedBinding());
+		close();
+		return dialog.open();
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/GnomeKeyFormatter.properties b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/GnomeKeyFormatter.properties
new file mode 100644
index 0000000..e78770b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/GnomeKeyFormatter.properties
@@ -0,0 +1,10 @@
+###############################################################################
+# Copyright (c) 2000, 2006 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
+###############################################################################
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/ImageFactory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/ImageFactory.java
new file mode 100644
index 0000000..33004fb
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/ImageFactory.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 422040
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.keys;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.util.ImageSupport;
+
+final class ImageFactory {
+
+	private static ImageRegistry imageRegistry = new ImageRegistry();
+	private static Map map = new HashMap();
+
+	static {
+		put("blank", "$nl$/icons/full/obj16/blank.png"); //$NON-NLS-1$//$NON-NLS-2$
+		put("change", "$nl$/icons/full/obj16/change_obj.png"); //$NON-NLS-1$//$NON-NLS-2$
+
+		/*
+		 * TODO Remove these images from the registry if they are no longer
+		 * needed.
+		 */
+		put("minus", "$nl$/icons/full/obj16/delete_obj.png"); //$NON-NLS-1$//$NON-NLS-2$
+		put("plus", "$nl$/icons/full/obj16/add_obj.png"); //$NON-NLS-1$//$NON-NLS-2$
+	}
+
+	static Image getImage(String key) {
+		Image image = imageRegistry.get(key);
+
+		if (image == null) {
+			ImageDescriptor imageDescriptor = getImageDescriptor(key);
+
+			if (imageDescriptor != null) {
+				image = imageDescriptor.createImage(false);
+
+				if (image == null) {
+					WorkbenchPlugin.log(ImageFactory.class +": error creating image for " + key); //$NON-NLS-1$
+				}
+
+				imageRegistry.put(key, image);
+			}
+		}
+
+		return image;
+	}
+
+	static ImageDescriptor getImageDescriptor(String key) {
+		ImageDescriptor imageDescriptor = (ImageDescriptor) map.get(key);
+
+		if (imageDescriptor == null) {
+			WorkbenchPlugin.log(ImageFactory.class +": no image descriptor for " + key); //$NON-NLS-1$
+		}
+
+		return imageDescriptor;
+	}
+
+	private static void put(String key, String value) {
+		map.put(key, ImageSupport.getImageDescriptor(value));
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/KdeKeyFormatter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/KdeKeyFormatter.java
new file mode 100644
index 0000000..fc72a35
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/KdeKeyFormatter.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2014 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.ui.internal.keys;
+
+import java.util.Comparator;
+import java.util.ResourceBundle;
+
+import org.eclipse.ui.internal.util.Util;
+import org.eclipse.ui.keys.KeySequence;
+import org.eclipse.ui.keys.KeyStroke;
+import org.eclipse.ui.keys.ModifierKey;
+
+public final class KdeKeyFormatter extends AbstractKeyFormatter {
+
+    private final static class KdeModifierKeyComparator extends
+            AbstractModifierKeyComparator {
+
+        @Override
+		protected int rank(ModifierKey modifierKey) {
+            if (ModifierKey.ALT.equals(modifierKey)) {
+                return 0;
+            }
+
+            if (ModifierKey.CTRL.equals(modifierKey)) {
+                return 1;
+            }
+
+            if (ModifierKey.SHIFT.equals(modifierKey)) {
+                return 2;
+            }
+
+            return Integer.MAX_VALUE;
+        }
+    }
+
+    private final static Comparator MODIFIER_KEY_COMPARATOR = new KdeModifierKeyComparator();
+
+    private final static ResourceBundle RESOURCE_BUNDLE = ResourceBundle
+            .getBundle(KdeKeyFormatter.class.getName());
+
+    @Override
+	protected String getKeyDelimiter() {
+        return Util.translateString(RESOURCE_BUNDLE, KEY_DELIMITER_KEY,
+                KeyStroke.KEY_DELIMITER, false, false);
+    }
+
+    @Override
+	protected String getKeyStrokeDelimiter() {
+        return Util.translateString(RESOURCE_BUNDLE, KEY_STROKE_DELIMITER_KEY,
+                KeySequence.KEY_STROKE_DELIMITER, false, false);
+    }
+
+    @Override
+	protected Comparator getModifierKeyComparator() {
+        return MODIFIER_KEY_COMPARATOR;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/KdeKeyFormatter.properties b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/KdeKeyFormatter.properties
new file mode 100644
index 0000000..e78770b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/KdeKeyFormatter.properties
@@ -0,0 +1,10 @@
+###############################################################################
+# Copyright (c) 2000, 2006 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
+###############################################################################
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/KeyAssistDialog.properties b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/KeyAssistDialog.properties
new file mode 100644
index 0000000..f5cb75c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/KeyAssistDialog.properties
@@ -0,0 +1,13 @@
+###############################################################################
+# Copyright (c) 2000, 2013 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
+###############################################################################
+
+NoMatches_Message=No Matches Found
+openPreferencePage=Press "{0}" to open the preference page.
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/KeyAssistMessages.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/KeyAssistMessages.java
new file mode 100644
index 0000000..589f7b6
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/KeyAssistMessages.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.keys;
+
+import org.eclipse.osgi.util.NLS;
+
+
+
+/**
+ * The KeyAssistMessages class is the class that manages the messages
+ * used in the KeyAssistDialog.
+ *
+ */
+public class KeyAssistMessages extends NLS {
+	private static final String BUNDLE_NAME = "org.eclipse.ui.internal.keys.KeyAssistDialog";//$NON-NLS-1$
+
+	public static String NoMatches_Message;
+	public static String openPreferencePage;
+
+
+	static {
+		// load message values from bundle file
+		NLS.initializeMessages(BUNDLE_NAME, KeyAssistMessages.class);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/KeyBindingState.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/KeyBindingState.java
new file mode 100644
index 0000000..6437df5
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/KeyBindingState.java
@@ -0,0 +1,172 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.keys;
+
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.IStatusLineManager;
+import org.eclipse.jface.action.StatusLineContributionItem;
+import org.eclipse.jface.bindings.keys.KeySequence;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.internal.WorkbenchWindow;
+
+/**
+ * <p>
+ * The mutable state of the key binding architecture. This is the only piece of
+ * the key binding architecture that changes (internally). It keeps track of
+ * what partial key strokes the user has entered. In the case of functional
+ * groups of key bindings, it allows the user to keep part of the key sequence
+ * even after a match has been made. Only after releasing all of the modifier
+ * keys would the sequence reset itself.
+ * </p>
+ * <p>
+ * In the current implementation, a partial reset results in only one key
+ * stroke being left in the sequence. However, this may change in the future.
+ * </p>
+ *
+ * @since 3.0
+ */
+class KeyBindingState {
+
+    /**
+     * The workbench window associated with this state. The state can only
+     * exist for one window. When the focus leaves this window then the mode
+     * must automatically be reset.
+     */
+    private IWorkbenchWindow associatedWindow;
+
+    /**
+     * This is the current extent of the sequence entered by the user. In an
+     * application with only single-stroke key bindings, this will also be
+     * empty. However, in applications with multi-stroke key bindings, this is
+     * the sequence entered by the user that partially matches another one of
+     * the application's active key bindings.
+     */
+    private KeySequence currentSequence;
+
+    /**
+     * The workbench that should be notified of changes to the key binding
+     * state. This is done by updating one of the contribution items on the
+     * status line.
+     */
+    private final IWorkbench workbench;
+
+    /**
+     * Constructs a new instance of <code>KeyBindingState</code> with an
+     * empty key sequence, set to reset fully.
+     *
+     * @param workbenchToNotify
+     *            The workbench that this state should keep advised of changes
+     *            to the key binding state; must not be <code>null</code>.
+     */
+    KeyBindingState(IWorkbench workbenchToNotify) {
+        currentSequence = KeySequence.getInstance();
+        workbench = workbenchToNotify;
+        associatedWindow = workbench.getActiveWorkbenchWindow();
+    }
+
+    /**
+     * An accessor for the workbench window associated with this state. This
+     * should never be <code>null</code>, as the setting follows the last
+     * workbench window to have focus.
+     *
+     * @return The workbench window to which the key binding architecture is
+     *         currently attached; should never be <code>null</code>.
+     */
+    IWorkbenchWindow getAssociatedWindow() {
+        return associatedWindow;
+    }
+
+    /**
+     * An accessor for the current key sequence waiting for completion.
+     *
+     * @return The current incomplete key sequence; never <code>null</code>,
+     *         but may be empty.
+     */
+    KeySequence getCurrentSequence() {
+        return currentSequence;
+    }
+
+    /**
+     * Gets the status line contribution item which the key binding
+     * architecture uses to keep the user up-to-date as to the current state.
+     *
+     * @return The status line contribution item, if any; <code>null</code>,
+     *         if none.
+     */
+    StatusLineContributionItem getStatusLine() {
+        if (associatedWindow instanceof WorkbenchWindow) {
+            WorkbenchWindow window = (WorkbenchWindow) associatedWindow;
+            IStatusLineManager statusLine = window.getStatusLineManager();
+            // TODO implicit dependency on IDE's action builder
+            // @issue implicit dependency on IDE's action builder
+            if (statusLine != null) { // this can be null if we're exiting
+                IContributionItem item = statusLine
+                        .find("ModeContributionItem"); //$NON-NLS-1$
+                if (item instanceof StatusLineContributionItem) {
+                    return ((StatusLineContributionItem) item);
+                }
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * <p>
+     * Resets the state based on the current properties. If the state is to
+     * collapse fully or if there are no key strokes, then it sets the state to
+     * have an empty key sequence. Otherwise, it leaves the first key stroke in
+     * the sequence.
+     * </p>
+     * <p>
+     * The workbench's status lines are updated, if appropriate.
+     * </p>
+     */
+    void reset() {
+        currentSequence = KeySequence.getInstance();
+        updateStatusLines();
+    }
+
+    /**
+     * A mutator for the workbench window to which this state is associated.
+     *
+     * @param window
+     *            The workbench window to associated; should never be <code>null</code>.
+     */
+    void setAssociatedWindow(IWorkbenchWindow window) {
+        associatedWindow = window;
+    }
+
+    /**
+     * A mutator for the partial sequence entered by the user.
+     *
+     * @param sequence
+     *            The current key sequence; should not be <code>null</code>,
+     *            but may be empty.
+     */
+    void setCurrentSequence(KeySequence sequence) {
+        currentSequence = sequence;
+        updateStatusLines();
+    }
+
+    /**
+     * Updates the text of the status line of the associated shell with the
+     * current sequence.
+     */
+    private void updateStatusLines() {
+        StatusLineContributionItem statusLine = getStatusLine();
+        if (statusLine != null) {
+            statusLine.setText(getCurrentSequence().format());
+        }
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/KeySequenceBinding.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/KeySequenceBinding.java
new file mode 100644
index 0000000..6917450
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/KeySequenceBinding.java
@@ -0,0 +1,117 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.keys;
+
+import org.eclipse.ui.commands.IKeySequenceBinding;
+import org.eclipse.ui.internal.util.Util;
+import org.eclipse.ui.keys.KeySequence;
+
+public final class KeySequenceBinding implements IKeySequenceBinding {
+
+    /**
+     * This is the identifier for the default context.  This is used wherever
+     * some default is needed.  For example, this is the context that is used
+     * for key bindings that specify no context.  This is also used to select a
+     * default context in the keys preference page.
+     */
+    public static final String DEFAULT_CONTEXT_ID = "org.eclipse.ui.contexts.window"; //$NON-NLS-1$
+
+    private final static int HASH_FACTOR = 89;
+
+    private final static int HASH_INITIAL = KeySequenceBinding.class.getName()
+            .hashCode();
+
+    private transient int hashCode;
+
+    private transient boolean hashCodeComputed;
+
+    private KeySequence keySequence;
+
+    private int match;
+
+    private transient String string;
+
+    public KeySequenceBinding(KeySequence keySequence, int match) {
+        if (keySequence == null) {
+			throw new NullPointerException();
+		}
+
+        if (match < 0) {
+			throw new IllegalArgumentException();
+		}
+
+        this.keySequence = keySequence;
+        this.match = match;
+    }
+
+    @Override
+	public int compareTo(Object object) {
+        KeySequenceBinding castedObject = (KeySequenceBinding) object;
+        int compareTo = Util.compare(match, castedObject.match);
+
+        if (compareTo == 0) {
+			compareTo = Util.compare(keySequence, castedObject.keySequence);
+		}
+
+        return compareTo;
+    }
+
+    @Override
+	public boolean equals(Object object) {
+        if (!(object instanceof KeySequenceBinding)) {
+			return false;
+		}
+
+        final KeySequenceBinding castedObject = (KeySequenceBinding) object;
+        if (!Util.equals(keySequence, castedObject.keySequence)) {
+            return false;
+        }
+
+        return Util.equals(match, castedObject.match);
+    }
+
+    @Override
+	public KeySequence getKeySequence() {
+        return keySequence;
+    }
+
+    public int getMatch() {
+        return match;
+    }
+
+    @Override
+	public int hashCode() {
+        if (!hashCodeComputed) {
+            hashCode = HASH_INITIAL;
+            hashCode = hashCode * HASH_FACTOR + Util.hashCode(keySequence);
+            hashCode = hashCode * HASH_FACTOR + Util.hashCode(match);
+            hashCodeComputed = true;
+        }
+
+        return hashCode;
+    }
+
+    @Override
+	public String toString() {
+        if (string == null) {
+            final StringBuffer stringBuffer = new StringBuffer();
+            stringBuffer.append('[');
+            stringBuffer.append(keySequence);
+            stringBuffer.append(',');
+            stringBuffer.append(match);
+            stringBuffer.append(']');
+            string = stringBuffer.toString();
+        }
+
+        return string;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/KeysPreferenceFiltersDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/KeysPreferenceFiltersDialog.java
new file mode 100644
index 0000000..7250ca1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/KeysPreferenceFiltersDialog.java
@@ -0,0 +1,127 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal.keys;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.preferences.ViewSettingsDialog;
+
+/**
+ * Creates a dialog box for applying filter selection of When combo box in
+ * NewKeysPreferencePage
+ *
+ * @since 3.3
+ *
+ */
+public class KeysPreferenceFiltersDialog extends ViewSettingsDialog {
+
+	private Button actionSetFilterCheckBox;
+	private Button internalFilterCheckBox;
+	private Button uncategorizedFilterCheckBox;
+
+	private boolean filterActionSet;
+	private boolean filterInternal;
+	private boolean filterUncategorized;
+	private boolean filterShowUnboundCommands;
+
+	void setFilterActionSet(boolean b) {
+		filterActionSet = b;
+	}
+
+	void setFilterInternal(boolean b) {
+		filterInternal = b;
+	}
+
+	void setFilterUncategorized(boolean b) {
+		filterUncategorized = b;
+	}
+
+	boolean getFilterActionSet() {
+		return filterActionSet;
+	}
+
+	boolean getFilterInternal() {
+		return filterInternal;
+	}
+
+	boolean getFilterUncategorized() {
+		return filterUncategorized;
+	}
+
+	/**
+	 * @param parentShell
+	 */
+	public KeysPreferenceFiltersDialog(Shell parentShell) {
+		super(parentShell);
+	}
+
+	@Override
+	protected void performDefaults() {
+		actionSetFilterCheckBox.setSelection(true);
+		internalFilterCheckBox.setSelection(true);
+		uncategorizedFilterCheckBox.setSelection(true);
+		super.performDefaults();
+	}
+
+	@Override
+	protected Control createDialogArea(Composite parent) {
+		Composite topComposite = (Composite) super.createDialogArea(parent);
+		GridLayout layout = new GridLayout(1, false);
+		topComposite.setLayout(layout);
+		topComposite.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL));
+		actionSetFilterCheckBox = new Button(topComposite, SWT.CHECK);
+		actionSetFilterCheckBox
+				.setText(NewKeysPreferenceMessages.ActionSetFilterCheckBox_Text);
+		internalFilterCheckBox = new Button(topComposite, SWT.CHECK);
+		internalFilterCheckBox
+				.setText(NewKeysPreferenceMessages.InternalFilterCheckBox_Text);
+		uncategorizedFilterCheckBox = new Button(topComposite, SWT.CHECK);
+		uncategorizedFilterCheckBox
+				.setText(NewKeysPreferenceMessages.UncategorizedFilterCheckBox_Text);
+
+		actionSetFilterCheckBox.setSelection(filterActionSet);
+		internalFilterCheckBox.setSelection(filterInternal);
+		uncategorizedFilterCheckBox.setSelection(filterUncategorized);
+		applyDialogFont(topComposite);
+
+		return topComposite;
+	}
+
+	@Override
+	protected void okPressed() {
+		filterActionSet = actionSetFilterCheckBox.getSelection();
+		filterInternal = internalFilterCheckBox.getSelection();
+		filterUncategorized = uncategorizedFilterCheckBox.getSelection();
+		super.okPressed();
+	}
+
+	@Override
+	protected void configureShell(Shell newShell) {
+		super.configureShell(newShell);
+		newShell
+				.setText(NewKeysPreferenceMessages.KeysPreferenceFilterDialog_Title);
+	}
+
+	boolean getFilterShowUnboundCommands() {
+		return filterShowUnboundCommands;
+	}
+
+	void setFilterUnboundCommands(boolean filterUnboundCommands) {
+		this.filterShowUnboundCommands = filterUnboundCommands;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/KeysPreferencePage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/KeysPreferencePage.java
new file mode 100644
index 0000000..191e7e6
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/KeysPreferencePage.java
@@ -0,0 +1,2462 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *     Patrik Suzzi <psuzzi@gmail.com> - Bug 489250
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.keys;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.ResourceBundle;
+import java.util.Set;
+
+import org.eclipse.core.commands.Category;
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.CommandManager;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.core.commands.contexts.Context;
+import org.eclipse.core.commands.contexts.ContextManager;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.bindings.Binding;
+import org.eclipse.jface.bindings.BindingManager;
+import org.eclipse.jface.bindings.Scheme;
+import org.eclipse.jface.bindings.TriggerSequence;
+import org.eclipse.jface.bindings.keys.KeyBinding;
+import org.eclipse.jface.bindings.keys.KeySequence;
+import org.eclipse.jface.bindings.keys.KeySequenceText;
+import org.eclipse.jface.bindings.keys.KeyStroke;
+import org.eclipse.jface.contexts.IContextIds;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+//import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.swt.widgets.TabFolder;
+import org.eclipse.swt.widgets.TabItem;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.activities.IActivityManager;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.contexts.IContextService;
+import org.eclipse.ui.internal.IPreferenceConstants;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.internal.util.PrefUtil;
+import org.eclipse.ui.internal.util.Util;
+import org.eclipse.ui.keys.IBindingService;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+import com.ibm.icu.text.Collator;
+import com.ibm.icu.text.MessageFormat;
+
+/**
+ * The preference page for defining keyboard shortcuts. While some of its
+ * underpinning have been made generic to "bindings" rather than "key bindings",
+ * it will still take some work to remove the link entirely.
+ *
+ * @since 3.0
+ */
+public final class KeysPreferencePage extends PreferencePage implements
+		IWorkbenchPreferencePage {
+
+	/**
+	 * A selection listener to be used on the columns in the table on the view
+	 * tab. This selection listener modifies the sort order so that the
+	 * appropriate column is in the first position.
+	 *
+	 * @since 3.1
+	 */
+	private class SortOrderSelectionListener extends SelectionAdapter {
+
+		/**
+		 * The column to be put in the first position. This value should be one
+		 * of the constants defined by <code>SORT_COLUMN_</code>.
+		 */
+		private final int columnSelected;
+
+		/**
+		 * Constructs a new instance of <code>SortOrderSelectionListener</code>.
+		 *
+		 * @param columnSelected
+		 *            The column to be given first priority in the sort order;
+		 *            this value should be one of the constants defined as
+		 *            <code>SORT_COLUMN_</code>.
+		 */
+		private SortOrderSelectionListener(final int columnSelected) {
+			this.columnSelected = columnSelected;
+		}
+
+		@Override
+		public void widgetSelected(SelectionEvent e) {
+			// Change the column titles.
+			final int oldSortIndex = sortOrder[0];
+			final TableColumn oldSortColumn = tableBindings
+					.getColumn(oldSortIndex);
+			oldSortColumn.setText(UNSORTED_COLUMN_NAMES[oldSortIndex]);
+			final TableColumn newSortColumn = tableBindings
+					.getColumn(columnSelected);
+			newSortColumn.setText(SORTED_COLUMN_NAMES[columnSelected]);
+
+			// Change the sort order.
+			boolean columnPlaced = false;
+			boolean enoughRoom = false;
+			int bumpedColumn = -1;
+			for (int i = 0; i < sortOrder.length; i++) {
+				if (sortOrder[i] == columnSelected) {
+					/*
+					 * We've found the place where the column existing in the
+					 * old sort order. No matter what at this point, we have
+					 * completed the reshuffling.
+					 */
+					enoughRoom = true;
+					if (bumpedColumn != -1) {
+						// We have already started bumping things around, so
+						// drop the last bumped column here.
+						sortOrder[i] = bumpedColumn;
+					} else {
+						// The order has not changed.
+						columnPlaced = true;
+					}
+					break;
+
+				} else if (columnPlaced) {
+					// We are currently bumping, so just bump another.
+					int temp = sortOrder[i];
+					sortOrder[i] = bumpedColumn;
+					bumpedColumn = temp;
+
+				} else {
+					/*
+					 * We are not currently bumping, so drop the column and
+					 * start bumping.
+					 */
+					bumpedColumn = sortOrder[i];
+					sortOrder[i] = columnSelected;
+					columnPlaced = true;
+				}
+			}
+
+			// Grow the sort order.
+			if (!enoughRoom) {
+				final int[] newSortOrder = new int[sortOrder.length + 1];
+				System.arraycopy(sortOrder, 0, newSortOrder, 0,
+						sortOrder.length);
+				newSortOrder[sortOrder.length] = bumpedColumn;
+				sortOrder = newSortOrder;
+			}
+
+			// Update the view tab.
+			updateViewTab();
+		}
+	}
+
+	/**
+	 * The data key for the binding stored on an SWT widget. The key is a
+	 * fully-qualified name, but in reverse order. This is so that the equals
+	 * method will detect misses faster.
+	 */
+	private static final String BINDING_KEY = "Binding.bindings.jface.eclipse.org"; //$NON-NLS-1$
+
+	/**
+	 * The image associate with a binding that exists as part of the system
+	 * definition.
+	 */
+	private static final Image IMAGE_BLANK = ImageFactory.getImage("blank"); //$NON-NLS-1$
+
+	/**
+	 * The image associated with a binding changed by the user.
+	 */
+	private static final Image IMAGE_CHANGE = ImageFactory.getImage("change"); //$NON-NLS-1$
+
+	/**
+	 * The data key at which the <code>Binding</code> instance for a table
+	 * item is stored.
+	 */
+	private static final String ITEM_DATA_KEY = "org.eclipse.jface.bindings"; //$NON-NLS-1$
+
+	/**
+	 * The number of items to show in the combo boxes.
+	 */
+	private static final int ITEMS_TO_SHOW = 9;
+
+	/**
+	 * The resource bundle from which translations can be retrieved.
+	 */
+	private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle
+			.getBundle(KeysPreferencePage.class.getName());
+
+	/**
+	 * The total number of columns on the view tab.
+	 */
+	private static final int VIEW_TOTAL_COLUMNS = 4;
+
+	/**
+	 * The translated names for the columns when they are the primary sort key
+	 * (e.g., ">Category<").
+	 */
+	private static final String[] SORTED_COLUMN_NAMES = new String[VIEW_TOTAL_COLUMNS];
+
+	/**
+	 * The index of the modify tab.
+	 *
+	 * @since 3.1
+	 */
+	private static final int TAB_INDEX_MODIFY = 1;
+
+	/**
+	 * The translated names for the columns when they are not the primary sort
+	 * key (e.g., "Category").
+	 */
+	private static final String[] UNSORTED_COLUMN_NAMES = new String[VIEW_TOTAL_COLUMNS];
+
+	/**
+	 * The index of the column on the view tab containing the category name.
+	 */
+	private static final int VIEW_CATEGORY_COLUMN_INDEX = 0;
+
+	/**
+	 * The index of the column on the view tab containing the command name.
+	 */
+	private static final int VIEW_COMMAND_COLUMN_INDEX = 1;
+
+	/**
+	 * The index of the column on the view tab containing the context name.
+	 */
+	private static final int VIEW_CONTEXT_COLUMN_INDEX = 3;
+
+	/**
+	 * The index of the column on the view tab containing the key sequence.
+	 */
+	private static final int VIEW_KEY_SEQUENCE_COLUMN_INDEX = 2;
+
+	static {
+		UNSORTED_COLUMN_NAMES[VIEW_CATEGORY_COLUMN_INDEX] = Util
+				.translateString(RESOURCE_BUNDLE, "tableColumnCategory"); //$NON-NLS-1$
+		UNSORTED_COLUMN_NAMES[VIEW_COMMAND_COLUMN_INDEX] = Util
+				.translateString(RESOURCE_BUNDLE, "tableColumnCommand"); //$NON-NLS-1$
+		UNSORTED_COLUMN_NAMES[VIEW_KEY_SEQUENCE_COLUMN_INDEX] = Util
+				.translateString(RESOURCE_BUNDLE, "tableColumnKeySequence"); //$NON-NLS-1$
+		UNSORTED_COLUMN_NAMES[VIEW_CONTEXT_COLUMN_INDEX] = Util
+				.translateString(RESOURCE_BUNDLE, "tableColumnContext"); //$NON-NLS-1$
+
+		SORTED_COLUMN_NAMES[VIEW_CATEGORY_COLUMN_INDEX] = Util.translateString(
+				RESOURCE_BUNDLE, "tableColumnCategorySorted"); //$NON-NLS-1$
+		SORTED_COLUMN_NAMES[VIEW_COMMAND_COLUMN_INDEX] = Util.translateString(
+				RESOURCE_BUNDLE, "tableColumnCommandSorted"); //$NON-NLS-1$
+		SORTED_COLUMN_NAMES[VIEW_KEY_SEQUENCE_COLUMN_INDEX] = Util
+				.translateString(RESOURCE_BUNDLE,
+						"tableColumnKeySequenceSorted"); //$NON-NLS-1$
+		SORTED_COLUMN_NAMES[VIEW_CONTEXT_COLUMN_INDEX] = Util.translateString(
+				RESOURCE_BUNDLE, "tableColumnContextSorted"); //$NON-NLS-1$
+	}
+
+	/**
+	 * The workbench's activity manager. This activity manager is used to see if
+	 * certain commands should be filtered from the user interface.
+	 */
+	private IActivityManager activityManager;
+
+	/**
+	 * The workbench's binding service. This binding service is used to access
+	 * the current set of bindings, and to persist changes.
+	 */
+	private IBindingService bindingService;
+
+	/**
+	 * The add button located on the bottom left of the preference page. This
+	 * button adds the current trigger sequence to the currently selected
+	 * command.
+	 */
+	private Button buttonAdd;
+
+	/**
+	 * The remove button located on the bottom left of the preference page. This
+	 * button removes the current trigger sequence from the current command.
+	 */
+	private Button buttonRemove;
+
+	/**
+	 * The restore button located on the bottom left of the preference page.
+	 * This button attempts to restore the currently trigger sequence to its
+	 * initial (i.e., Binding.SYSTEM) state -- undoing all user modifications.
+	 */
+	private Button buttonRestore;
+
+	/**
+	 * A map of all the category identifiers indexed by the names that appear in
+	 * the user interface. This look-up table is built during initialization.
+	 */
+	private Map categoryIdsByUniqueName;
+
+	/**
+	 * A map of all the category names in the user interface indexed by their
+	 * identifiers. This look-up table is built during initialization.
+	 */
+	private Map categoryUniqueNamesById;
+
+	/**
+	 * The combo box containing the list of all categories for commands.
+	 */
+	private Combo comboCategory;
+
+	/**
+	 * The combo box containing the list of commands relevent for the currently
+	 * selected category.
+	 */
+	private Combo comboCommand;
+
+	/**
+	 * The combo box containing the list of contexts in the system.
+	 */
+	private Combo comboContext;
+
+	/**
+	 * The combo box containing the list of schemes in the system.
+	 */
+	private Combo comboScheme;
+
+	/**
+	 * A map of all the command identifiers indexed by the categories to which
+	 * they belong. This look-up table is built during initialization.
+	 */
+	private Map commandIdsByCategoryId;
+
+	/**
+	 * The parameterized commands corresponding to the current contents of
+	 * <code>comboCommand</code>. The commands in this array are in the same
+	 * order as in the combo. This value can be <code>null</code> if nothing
+	 * is selected in the combo.
+	 */
+	private ParameterizedCommand[] commands = null;
+
+	/**
+	 * The workbench's command service. This command service is used to access
+	 * the list of commands.
+	 */
+	private ICommandService commandService;
+
+	/**
+	 * A map of all the context identifiers indexed by the names that appear in
+	 * the user interface. This look-up table is built during initialization.
+	 */
+	private Map contextIdsByUniqueName;
+
+	/**
+	 * The workbench's context service. This context service is used to access
+	 * the list of contexts.
+	 */
+	private IContextService contextService;
+
+	/**
+	 * A map of all the category names in the user interface indexed by their
+	 * identifiers. This look-up table is built during initialization.
+	 */
+	private Map contextUniqueNamesById;
+
+	/**
+	 * The workbench's help system. This is used to register the page with the
+	 * help system.
+	 *
+	 * TODO Add a help context
+	 */
+	// private IWorkbenchHelpSystem helpSystem;
+	/**
+	 * This is the label next to the table showing the bindings matching a
+	 * particular command. The label is disabled if there isn't a selected
+	 * command identifier.
+	 */
+	private Label labelBindingsForCommand;
+
+	/**
+	 * This is the label next to the table showing the bindings matching a
+	 * particular trigger sequence. The label is disabled if there isn't a
+	 * current key sequence.
+	 */
+	private Label labelBindingsForTriggerSequence;
+
+	/**
+	 * The label next to the context combo box. This label indicates whether the
+	 * context is a child of another context. If the current context is not a
+	 * child, then this label is blank.
+	 */
+	private Label labelContextExtends;
+
+	/**
+	 * The label next to the scheme combo box. This label indicates whether the
+	 * scheme is a child of another scheme. If the current scheme is not a
+	 * child, then this label is blank.
+	 */
+	private Label labelSchemeExtends;
+
+	/**
+	 * A binding manager local to this preference page. When the page is
+	 * initialized, the current bindings are read out from the binding service
+	 * and placed in this manager. This manager is then updated as the user
+	 * makes changes. When the user has finished, the contents of this manager
+	 * are compared with the contents of the binding service. The changes are
+	 * then persisted.
+	 */
+	private final BindingManager localChangeManager = new BindingManager(
+			new ContextManager(), new CommandManager());
+
+	/**
+	 * A map of all the scheme identifiers indexed by the names that appear in
+	 * the user interface. This look-up table is built during initialization.
+	 */
+	private Map schemeIdsByUniqueName;
+
+	/**
+	 * A map of all the scheme names in the user interface indexed by their
+	 * identifiers. This look-up table is built during initialization.
+	 */
+	private Map schemeUniqueNamesById;
+
+	/**
+	 * The sort order to be used on the view tab to display all of the key
+	 * bindings. This sort order can be changed by the user. This array is never
+	 * <code>null</code>, but may be empty.
+	 */
+	private int[] sortOrder = { VIEW_CATEGORY_COLUMN_INDEX,
+			VIEW_COMMAND_COLUMN_INDEX, VIEW_KEY_SEQUENCE_COLUMN_INDEX,
+			VIEW_CONTEXT_COLUMN_INDEX };
+
+	/**
+	 * The top-most tab folder for the preference page -- containing a view and
+	 * a modify tab.
+	 */
+	private TabFolder tabFolder;
+
+	/**
+	 * A table of the key bindings currently defined. This table appears on the
+	 * view tab; it is intended to be an easy way for users to learn the key
+	 * bindings in Eclipse. This value is only <code>null</code> until the
+	 * controls are first created.
+	 */
+	private Table tableBindings;
+
+	/**
+	 * The table containing all of the bindings matching the selected command.
+	 */
+	private Table tableBindingsForCommand;
+
+	/**
+	 * The table containing all of the bindings matching the current trigger
+	 * sequence.
+	 */
+	private Table tableBindingsForTriggerSequence;
+
+	/**
+	 * The text widget where keys are entered. This widget is managed by
+	 * <code>textTriggerSequenceManager</code>, which provides its special
+	 * behaviour.
+	 */
+	private Text textTriggerSequence;
+
+	/**
+	 * The manager for the text widget that traps incoming key events. This
+	 * manager should be used to access the widget, rather than accessing the
+	 * widget directly.
+	 */
+	private KeySequenceText textTriggerSequenceManager;
+
+
+	@Override
+	public void applyData(Object data) {
+		if(data instanceof Binding) {
+			editBinding((Binding) data);
+		}
+	}
+	@Override
+	protected final Control createContents(final Composite parent) {
+
+		PlatformUI.getWorkbench().getHelpSystem()
+			.setHelp(parent, IWorkbenchHelpContextIds.KEYS_PREFERENCE_PAGE);
+
+		tabFolder = new TabFolder(parent, SWT.NULL);
+
+		// View tab
+		final TabItem viewTab = new TabItem(tabFolder, SWT.NULL);
+		viewTab.setText(Util.translateString(RESOURCE_BUNDLE, "viewTab.Text")); //$NON-NLS-1$
+		viewTab.setControl(createViewTab(tabFolder));
+
+		// Modify tab
+		final TabItem modifyTab = new TabItem(tabFolder, SWT.NULL);
+		modifyTab.setText(Util.translateString(RESOURCE_BUNDLE,
+				"modifyTab.Text")); //$NON-NLS-1$
+		modifyTab.setControl(createModifyTab(tabFolder));
+
+		// Do some fancy stuff.
+		applyDialogFont(tabFolder);
+		final IPreferenceStore store = getPreferenceStore();
+		final int selectedTab = store
+				.getInt(IPreferenceConstants.KEYS_PREFERENCE_SELECTED_TAB);
+		if ((tabFolder.getItemCount() > selectedTab) && (selectedTab > 0)) {
+			tabFolder.setSelection(selectedTab);
+		}
+
+		return tabFolder;
+	}
+
+	/**
+	 * Creates the tab that allows the user to change the keyboard shortcuts.
+	 *
+	 * @param parent
+	 *            The tab folder in which the tab should be created; must not be
+	 *            <code>null</code>.
+	 * @return The composite which represents the contents of the tab; never
+	 *         <code>null</code>.
+	 */
+	private final Composite createModifyTab(final TabFolder parent) {
+		final Composite composite = new Composite(parent, SWT.NULL);
+		composite.setLayout(new GridLayout());
+		GridData gridData = new GridData(GridData.FILL_BOTH);
+		composite.setLayoutData(gridData);
+		final Composite compositeKeyConfiguration = new Composite(composite,
+				SWT.NULL);
+		GridLayout gridLayout = new GridLayout();
+		gridLayout.numColumns = 3;
+		compositeKeyConfiguration.setLayout(gridLayout);
+		gridData = new GridData(GridData.FILL_HORIZONTAL);
+		compositeKeyConfiguration.setLayoutData(gridData);
+		final Label labelKeyConfiguration = new Label(
+				compositeKeyConfiguration, SWT.LEFT);
+		labelKeyConfiguration.setText(Util.translateString(RESOURCE_BUNDLE,
+				"labelScheme")); //$NON-NLS-1$
+		comboScheme = new Combo(compositeKeyConfiguration, SWT.READ_ONLY);
+		gridData = new GridData();
+		gridData.widthHint = 200;
+		comboScheme.setLayoutData(gridData);
+		comboScheme.setVisibleItemCount(ITEMS_TO_SHOW);
+
+		comboScheme.addSelectionListener(new SelectionAdapter()
+        {
+		    public void widgetSelected(SelectionEvent e) {
+		        selectedComboScheme();
+		    }
+        });
+
+		labelSchemeExtends = new Label(compositeKeyConfiguration, SWT.LEFT);
+		gridData = new GridData(GridData.FILL_HORIZONTAL);
+		labelSchemeExtends.setLayoutData(gridData);
+		final Control spacer = new Composite(composite, SWT.NULL);
+		gridData = new GridData();
+		gridData.heightHint = 10;
+		gridData.widthHint = 10;
+		spacer.setLayoutData(gridData);
+		final Group groupCommand = new Group(composite, SWT.SHADOW_NONE);
+		gridLayout = new GridLayout();
+		gridLayout.numColumns = 3;
+		groupCommand.setLayout(gridLayout);
+		gridData = new GridData(GridData.FILL_BOTH);
+		groupCommand.setLayoutData(gridData);
+		groupCommand.setText(Util.translateString(RESOURCE_BUNDLE,
+				"groupCommand")); //$NON-NLS-1$
+		final Label labelCategory = new Label(groupCommand, SWT.LEFT);
+		gridData = new GridData();
+		labelCategory.setLayoutData(gridData);
+		labelCategory.setText(Util.translateString(RESOURCE_BUNDLE,
+				"labelCategory")); //$NON-NLS-1$
+		comboCategory = new Combo(groupCommand, SWT.READ_ONLY);
+		gridData = new GridData();
+		gridData.horizontalSpan = 2;
+		gridData.widthHint = 200;
+		comboCategory.setLayoutData(gridData);
+		comboCategory.setVisibleItemCount(ITEMS_TO_SHOW);
+
+		comboCategory.addSelectionListener(new SelectionAdapter()
+        {
+		    public void widgetSelected(SelectionEvent e) {
+		        update();
+		    }
+        });
+
+		final Label labelCommand = new Label(groupCommand, SWT.LEFT);
+		gridData = new GridData();
+		labelCommand.setLayoutData(gridData);
+		labelCommand.setText(Util.translateString(RESOURCE_BUNDLE,
+				"labelCommand")); //$NON-NLS-1$
+		comboCommand = new Combo(groupCommand, SWT.READ_ONLY);
+		gridData = new GridData();
+		gridData.horizontalSpan = 2;
+		gridData.widthHint = 300;
+		comboCommand.setLayoutData(gridData);
+		comboCommand.setVisibleItemCount(9);
+
+		comboCommand.addSelectionListener(new SelectionAdapter()
+        {
+		    /** {@inheritDoc} */
+		    @Override
+		    public void widgetSelected(SelectionEvent e)
+		    {
+		        update();
+		    }
+        });
+
+		labelBindingsForCommand = new Label(groupCommand, SWT.LEFT);
+		gridData = new GridData(GridData.VERTICAL_ALIGN_BEGINNING);
+		gridData.verticalAlignment = GridData.FILL_VERTICAL;
+		labelBindingsForCommand.setLayoutData(gridData);
+		labelBindingsForCommand.setText(Util.translateString(RESOURCE_BUNDLE,
+				"labelAssignmentsForCommand")); //$NON-NLS-1$
+		tableBindingsForCommand = new Table(groupCommand, SWT.BORDER
+				| SWT.FULL_SELECTION | SWT.H_SCROLL | SWT.V_SCROLL);
+		tableBindingsForCommand.setHeaderVisible(true);
+		gridData = new GridData(GridData.FILL_BOTH);
+		gridData.heightHint = 60;
+		gridData.horizontalSpan = 2;
+		boolean isMac = org.eclipse.jface.util.Util.isMac();
+		gridData.widthHint =  isMac ? 620 : 520;
+		tableBindingsForCommand.setLayoutData(gridData);
+		TableColumn tableColumnDelta = new TableColumn(tableBindingsForCommand,
+				SWT.NULL, 0);
+		tableColumnDelta.setResizable(false);
+		tableColumnDelta.setText(Util.ZERO_LENGTH_STRING);
+		tableColumnDelta.setWidth(20);
+		TableColumn tableColumnContext = new TableColumn(
+				tableBindingsForCommand, SWT.NULL, 1);
+		tableColumnContext.setResizable(true);
+		tableColumnContext.setText(Util.translateString(RESOURCE_BUNDLE,
+				"tableColumnContext")); //$NON-NLS-1$
+		tableColumnContext.pack();
+		tableColumnContext.setWidth(200);
+		final TableColumn tableColumnKeySequence = new TableColumn(
+				tableBindingsForCommand, SWT.NULL, 2);
+		tableColumnKeySequence.setResizable(true);
+		tableColumnKeySequence.setText(Util.translateString(RESOURCE_BUNDLE,
+				"tableColumnKeySequence")); //$NON-NLS-1$
+		tableColumnKeySequence.pack();
+		tableColumnKeySequence.setWidth(300);
+
+		tableBindingsForCommand.addMouseListener(new MouseAdapter() {
+
+			@Override
+			public void mouseDoubleClick(MouseEvent mouseEvent) {
+				update();
+			}
+		});
+
+		tableBindingsForCommand.addSelectionListener(new SelectionAdapter()
+        {
+		    public void widgetSelected(SelectionEvent e) {
+		        selectedTableBindingsForCommand();
+		    }
+        });
+
+		final Group groupKeySequence = new Group(composite, SWT.SHADOW_NONE);
+		gridLayout = new GridLayout();
+		gridLayout.numColumns = 4;
+		groupKeySequence.setLayout(gridLayout);
+		gridData = new GridData(GridData.FILL_BOTH);
+		groupKeySequence.setLayoutData(gridData);
+		groupKeySequence.setText(Util.translateString(RESOURCE_BUNDLE,
+				"groupKeySequence")); //$NON-NLS-1$
+		final Label labelKeySequence = new Label(groupKeySequence, SWT.LEFT);
+		gridData = new GridData();
+		labelKeySequence.setLayoutData(gridData);
+		labelKeySequence.setText(Util.translateString(RESOURCE_BUNDLE,
+				"labelKeySequence")); //$NON-NLS-1$
+
+		// The text widget into which the key strokes will be entered.
+		textTriggerSequence = new Text(groupKeySequence, SWT.BORDER);
+		// On MacOS X, this font will be changed by KeySequenceText
+		textTriggerSequence.setFont(groupKeySequence.getFont());
+		gridData = new GridData();
+		gridData.horizontalSpan = 2;
+		gridData.widthHint = 300;
+		textTriggerSequence.setLayoutData(gridData);
+		textTriggerSequence.addModifyListener(e -> update());
+		textTriggerSequence.addFocusListener(new FocusListener() {
+			@Override
+			public void focusGained(FocusEvent e) {
+				bindingService.setKeyFilterEnabled(false);
+			}
+
+			@Override
+			public void focusLost(FocusEvent e) {
+				bindingService.setKeyFilterEnabled(true);
+			}
+		});
+		textTriggerSequence.addDisposeListener(e -> {
+			if (!bindingService.isKeyFilterEnabled()) {
+				bindingService.setKeyFilterEnabled(true);
+			}
+		});
+
+		// The manager for the key sequence text widget.
+		textTriggerSequenceManager = new KeySequenceText(textTriggerSequence);
+		textTriggerSequenceManager.setKeyStrokeLimit(4);
+
+		// Button for adding trapped key strokes
+		final Button buttonAddKey = new Button(groupKeySequence, SWT.LEFT
+				| SWT.ARROW);
+		buttonAddKey.setToolTipText(Util.translateString(RESOURCE_BUNDLE,
+				"buttonAddKey.ToolTipText")); //$NON-NLS-1$
+		gridData = new GridData();
+		gridData.heightHint = comboCategory.getTextHeight();
+		buttonAddKey.setLayoutData(gridData);
+
+		// Arrow buttons aren't normally added to the tab list. Let's fix that.
+		final Control[] tabStops = groupKeySequence.getTabList();
+		final ArrayList newTabStops = new ArrayList();
+		for (Control tabStop : tabStops) {
+			newTabStops.add(tabStop);
+			if (textTriggerSequence.equals(tabStop)) {
+				newTabStops.add(buttonAddKey);
+			}
+		}
+		final Control[] newTabStopArray = (Control[]) newTabStops
+				.toArray(new Control[newTabStops.size()]);
+		groupKeySequence.setTabList(newTabStopArray);
+
+		// Construct the menu to attach to the above button.
+		final Menu menuButtonAddKey = new Menu(buttonAddKey);
+		final Iterator trappedKeyItr = KeySequenceText.TRAPPED_KEYS.iterator();
+		while (trappedKeyItr.hasNext()) {
+			final KeyStroke trappedKey = (KeyStroke) trappedKeyItr.next();
+			final MenuItem menuItem = new MenuItem(menuButtonAddKey, SWT.PUSH);
+			menuItem.setText(trappedKey.format());
+			menuItem.addSelectionListener(new SelectionAdapter()
+            {
+			    public void widgetSelected(SelectionEvent e) {
+			        textTriggerSequenceManager.insert(trappedKey);
+	                textTriggerSequence.setFocus();
+	                textTriggerSequence.setSelection(textTriggerSequence.getTextLimit());
+			    }
+            });
+		}
+		buttonAddKey.addSelectionListener(new SelectionAdapter()
+        {
+		    public void widgetSelected(SelectionEvent e) {
+		        Point buttonLocation = buttonAddKey.getLocation();
+	            buttonLocation = groupKeySequence.toDisplay(buttonLocation.x, buttonLocation.y);
+	            Point buttonSize = buttonAddKey.getSize();
+	            menuButtonAddKey.setLocation(buttonLocation.x, buttonLocation.y + buttonSize.y);
+	            menuButtonAddKey.setVisible(true);
+		    }
+        });
+
+		labelBindingsForTriggerSequence = new Label(groupKeySequence, SWT.LEFT);
+		gridData = new GridData(GridData.VERTICAL_ALIGN_BEGINNING);
+		gridData.verticalAlignment = GridData.FILL_VERTICAL;
+		labelBindingsForTriggerSequence.setLayoutData(gridData);
+		labelBindingsForTriggerSequence.setText(Util.translateString(
+				RESOURCE_BUNDLE, "labelAssignmentsForKeySequence")); //$NON-NLS-1$
+		tableBindingsForTriggerSequence = new Table(groupKeySequence,
+				SWT.BORDER | SWT.FULL_SELECTION | SWT.H_SCROLL | SWT.V_SCROLL);
+		tableBindingsForTriggerSequence.setHeaderVisible(true);
+		gridData = new GridData(GridData.FILL_BOTH);
+		gridData.heightHint = 60;
+		gridData.horizontalSpan = 3;
+		gridData.widthHint = isMac ? 620 : 520;
+		tableBindingsForTriggerSequence.setLayoutData(gridData);
+		tableColumnDelta = new TableColumn(tableBindingsForTriggerSequence,
+				SWT.NULL, 0);
+		tableColumnDelta.setResizable(false);
+		tableColumnDelta.setText(Util.ZERO_LENGTH_STRING);
+		tableColumnDelta.setWidth(20);
+		tableColumnContext = new TableColumn(tableBindingsForTriggerSequence,
+				SWT.NULL, 1);
+		tableColumnContext.setResizable(true);
+		tableColumnContext.setText(Util.translateString(RESOURCE_BUNDLE,
+				"tableColumnContext")); //$NON-NLS-1$
+		tableColumnContext.pack();
+		tableColumnContext.setWidth(200);
+		final TableColumn tableColumnCommand = new TableColumn(
+				tableBindingsForTriggerSequence, SWT.NULL, 2);
+		tableColumnCommand.setResizable(true);
+		tableColumnCommand.setText(Util.translateString(RESOURCE_BUNDLE,
+				"tableColumnCommand")); //$NON-NLS-1$
+		tableColumnCommand.pack();
+		tableColumnCommand.setWidth(300);
+
+		tableBindingsForTriggerSequence.addMouseListener(new MouseAdapter() {
+
+			@Override
+			public void mouseDoubleClick(MouseEvent mouseEvent) {
+				update();
+			}
+		});
+
+		tableBindingsForTriggerSequence
+				.addSelectionListener(new SelectionAdapter()
+                {
+				    public void widgetSelected(SelectionEvent e) {
+				        selectedTableBindingsForTriggerSequence();
+				    }
+                });
+
+		final Composite compositeContext = new Composite(composite, SWT.NULL);
+		gridLayout = new GridLayout();
+		gridLayout.numColumns = 3;
+		compositeContext.setLayout(gridLayout);
+		gridData = new GridData(GridData.FILL_HORIZONTAL);
+		compositeContext.setLayoutData(gridData);
+		final Label labelContext = new Label(compositeContext, SWT.LEFT);
+		labelContext.setText(Util.translateString(RESOURCE_BUNDLE,
+				"labelContext")); //$NON-NLS-1$
+		comboContext = new Combo(compositeContext, SWT.READ_ONLY);
+		gridData = new GridData();
+		gridData.widthHint = 250;
+		comboContext.setLayoutData(gridData);
+		comboContext.setVisibleItemCount(ITEMS_TO_SHOW);
+
+		comboContext.addSelectionListener(new SelectionAdapter()
+        {
+		    public void widgetSelected(SelectionEvent e) {
+		        update();
+		    }
+        });
+
+		labelContextExtends = new Label(compositeContext, SWT.LEFT);
+		gridData = new GridData(GridData.FILL_HORIZONTAL);
+		labelContextExtends.setLayoutData(gridData);
+		final Composite compositeButton = new Composite(composite, SWT.NULL);
+		gridLayout = new GridLayout();
+		gridLayout.marginHeight = 20;
+		gridLayout.marginWidth = 0;
+		gridLayout.numColumns = 3;
+		compositeButton.setLayout(gridLayout);
+		gridData = new GridData();
+		compositeButton.setLayoutData(gridData);
+		buttonAdd = new Button(compositeButton, SWT.CENTER | SWT.PUSH);
+		gridData = new GridData();
+		int widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
+		buttonAdd.setText(Util.translateString(RESOURCE_BUNDLE, "buttonAdd")); //$NON-NLS-1$
+		gridData.widthHint = Math.max(widthHint, buttonAdd.computeSize(
+				SWT.DEFAULT, SWT.DEFAULT, true).x) + 5;
+		buttonAdd.setLayoutData(gridData);
+
+		buttonAdd.addSelectionListener(new SelectionAdapter()
+        {
+		    public void widgetSelected(SelectionEvent e) {
+		        selectedButtonAdd();
+		    }
+        });
+
+		buttonRemove = new Button(compositeButton, SWT.CENTER | SWT.PUSH);
+		gridData = new GridData();
+		widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
+		buttonRemove.setText(Util.translateString(RESOURCE_BUNDLE,
+				"buttonRemove")); //$NON-NLS-1$
+		gridData.widthHint = Math.max(widthHint, buttonRemove.computeSize(
+				SWT.DEFAULT, SWT.DEFAULT, true).x) + 5;
+		buttonRemove.setLayoutData(gridData);
+
+		buttonRemove.addSelectionListener(new SelectionAdapter()
+        {
+		    public void widgetSelected(SelectionEvent e) {
+		        selectedButtonRemove();
+		    }
+        });
+
+		buttonRestore = new Button(compositeButton, SWT.CENTER | SWT.PUSH);
+		gridData = new GridData();
+		widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
+		buttonRestore.setText(Util.translateString(RESOURCE_BUNDLE,
+				"buttonRestore")); //$NON-NLS-1$
+		gridData.widthHint = Math.max(widthHint, buttonRestore.computeSize(
+				SWT.DEFAULT, SWT.DEFAULT, true).x) + 5;
+		buttonRestore.setLayoutData(gridData);
+
+		buttonRestore.addSelectionListener(new SelectionAdapter()
+        {
+		    public void widgetSelected(SelectionEvent e) {
+		        selectedButtonRestore();
+		    }
+        });
+
+		return composite;
+	}
+
+	/**
+	 * Creates a tab on the main page for displaying an uneditable list of the
+	 * current key bindings. This is intended as a discovery tool for new users.
+	 * It shows all of the key bindings for the current key configuration,
+	 * platform and locale.
+	 *
+	 * @param parent
+	 *            The tab folder in which the tab should be created; must not be
+	 *            <code>null</code>.
+	 * @return The newly created composite containing all of the controls; never
+	 *         <code>null</code>.
+	 * @since 3.1
+	 */
+	private final Composite createViewTab(final TabFolder parent) {
+		GridData gridData = null;
+		int widthHint;
+
+		// Create the composite for the tab.
+		final Composite composite = new Composite(parent, SWT.NONE);
+		composite.setLayoutData(new GridData(GridData.FILL_BOTH));
+		composite.setLayout(new GridLayout());
+
+		// Place a table inside the tab.
+		tableBindings = new Table(composite, SWT.BORDER | SWT.FULL_SELECTION
+				| SWT.H_SCROLL | SWT.V_SCROLL);
+		tableBindings.setHeaderVisible(true);
+		gridData = new GridData(GridData.FILL_BOTH);
+		gridData.heightHint = 400;
+		gridData.horizontalSpan = 2;
+		tableBindings.setLayoutData(gridData);
+		final TableColumn tableColumnCategory = new TableColumn(tableBindings,
+				SWT.NONE, VIEW_CATEGORY_COLUMN_INDEX);
+		tableColumnCategory
+				.setText(SORTED_COLUMN_NAMES[VIEW_CATEGORY_COLUMN_INDEX]);
+		tableColumnCategory
+				.addSelectionListener(new SortOrderSelectionListener(
+						VIEW_CATEGORY_COLUMN_INDEX));
+		final TableColumn tableColumnCommand = new TableColumn(tableBindings,
+				SWT.NONE, VIEW_COMMAND_COLUMN_INDEX);
+		tableColumnCommand
+				.setText(UNSORTED_COLUMN_NAMES[VIEW_COMMAND_COLUMN_INDEX]);
+		tableColumnCommand.addSelectionListener(new SortOrderSelectionListener(
+				VIEW_COMMAND_COLUMN_INDEX));
+		final TableColumn tableColumnKeySequence = new TableColumn(
+				tableBindings, SWT.NONE, VIEW_KEY_SEQUENCE_COLUMN_INDEX);
+		tableColumnKeySequence
+				.setText(UNSORTED_COLUMN_NAMES[VIEW_KEY_SEQUENCE_COLUMN_INDEX]);
+		tableColumnKeySequence
+				.addSelectionListener(new SortOrderSelectionListener(
+						VIEW_KEY_SEQUENCE_COLUMN_INDEX));
+		final TableColumn tableColumnContext = new TableColumn(tableBindings,
+				SWT.NONE, VIEW_CONTEXT_COLUMN_INDEX);
+		tableColumnContext
+				.setText(UNSORTED_COLUMN_NAMES[VIEW_CONTEXT_COLUMN_INDEX]);
+		tableColumnContext.addSelectionListener(new SortOrderSelectionListener(
+				VIEW_CONTEXT_COLUMN_INDEX));
+		tableBindings.addSelectionListener(new SelectionAdapter()
+        {
+		    /** {@inheritDoc} */
+		    @Override
+		    public void widgetDefaultSelected(SelectionEvent e)
+		    {
+		        selectedTableKeyBindings();
+		    }
+        });
+
+		// A composite for the buttons.
+		final Composite buttonBar = new Composite(composite, SWT.NONE);
+		buttonBar.setLayout(new GridLayout(2, false));
+		gridData = new GridData();
+		gridData.horizontalAlignment = GridData.END;
+		buttonBar.setLayoutData(gridData);
+
+		// A button for editing the current selection.
+		final Button editButton = new Button(buttonBar, SWT.PUSH);
+		gridData = new GridData();
+		widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
+		editButton.setText(Util.translateString(RESOURCE_BUNDLE, "buttonEdit")); //$NON-NLS-1$
+		gridData.widthHint = Math.max(widthHint, editButton.computeSize(
+				SWT.DEFAULT, SWT.DEFAULT, true).x) + 5;
+		editButton.setLayoutData(gridData);
+		editButton.addSelectionListener(new SelectionListener() {
+
+			@Override
+			public final void widgetDefaultSelected(final SelectionEvent event) {
+				selectedTableKeyBindings();
+			}
+
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				widgetDefaultSelected(e);
+			}
+		});
+
+		// A button for exporting the contents to a file.
+		final Button buttonExport = new Button(buttonBar, SWT.PUSH);
+		gridData = new GridData();
+		widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
+		buttonExport.setText(Util.translateString(RESOURCE_BUNDLE,
+				"buttonExport")); //$NON-NLS-1$
+		gridData.widthHint = Math.max(widthHint, buttonExport.computeSize(
+				SWT.DEFAULT, SWT.DEFAULT, true).x) + 5;
+		buttonExport.setLayoutData(gridData);
+		buttonExport.addSelectionListener(new SelectionListener() {
+
+			@Override
+			public final void widgetDefaultSelected(final SelectionEvent event) {
+				// RAP
+//				selectedButtonExport();
+			}
+
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				widgetDefaultSelected(e);
+			}
+		});
+
+		return composite;
+	}
+
+	@Override
+	protected IPreferenceStore doGetPreferenceStore() {
+		return PrefUtil.getInternalPreferenceStore();
+	}
+
+	/**
+	 * Allows the user to change the key bindings for a particular command.
+	 * Switches the tab to the modify tab, and then selects the category and
+	 * command that corresponds with the given command name. It then selects the
+	 * given key sequence and gives focus to the key sequence text widget.
+	 *
+	 * @param binding
+	 *            The binding to be edited; if <code>null</code>, then just
+	 *            switch to the modify tab. If the <code>binding</code> does
+	 *            not correspond to anything in the keys preference page, then
+	 *            this also just switches to the modify tab.
+	 * @since 3.1
+	 */
+	public final void editBinding(final Binding binding) {
+		// Switch to the modify tab.
+		tabFolder.setSelection(TAB_INDEX_MODIFY);
+
+		// If there is no command name, stop here.
+		if (binding == null) {
+			return;
+		}
+
+		/*
+		 * Get the corresponding category and command names. If either is
+		 * undefined, then we can just stop now. We won't be able to find their
+		 * name.
+		 */
+		final ParameterizedCommand command = binding.getParameterizedCommand();
+		String categoryName = null;
+		String commandName = null;
+		try {
+			categoryName = command.getCommand().getCategory().getName();
+			commandName = command.getName();
+		} catch (final NotDefinedException e) {
+			return; // no name
+		}
+
+		// Update the category combo box.
+		final String[] categoryNames = comboCategory.getItems();
+		int i = 0;
+		for (; i < categoryNames.length; i++) {
+			if (categoryName.equals(categoryNames[i])) {
+				break;
+			}
+		}
+		if (i >= comboCategory.getItemCount()) {
+			// Couldn't find the category, so abort.
+			return;
+		}
+		comboCategory.select(i);
+
+		// Update the commands combo box.
+		updateComboCommand();
+
+		// Update the command combo box.
+		final String[] commandNames = comboCommand.getItems();
+		int j = 0;
+		for (; j < commandNames.length; j++) {
+			if (commandName.equals(commandNames[j])) {
+				if (comboCommand.getSelectionIndex() != j) {
+					comboCommand.select(j);
+				}
+				break;
+			}
+		}
+		if (j >= comboCommand.getItemCount()) {
+			// Couldn't find the command, so just select the first and then stop
+			if (comboCommand.getSelectionIndex() != 0) {
+				comboCommand.select(0);
+			}
+			update();
+			return;
+		}
+
+		/*
+		 * Update and validate the state of the modify tab in response to these
+		 * selection changes.
+		 */
+		update();
+
+		// Select the right key binding, if possible.
+		final TableItem[] items = tableBindingsForCommand.getItems();
+		int k = 0;
+		for (; k < items.length; k++) {
+			final String currentKeySequence = items[k].getText(2);
+			if (binding.getTriggerSequence().format()
+					.equals(currentKeySequence)) {
+				break;
+			}
+		}
+		if (k < tableBindingsForCommand.getItemCount()) {
+			tableBindingsForCommand.select(k);
+			tableBindingsForCommand.notifyListeners(SWT.Selection, null);
+			textTriggerSequence.setFocus();
+		}
+	}
+
+	/**
+	 * Returns the identifier for the currently selected category.
+	 *
+	 * @return The selected category; <code>null</code> if none.
+	 */
+	private final String getCategoryId() {
+		return !commandIdsByCategoryId.containsKey(null)
+				|| comboCategory.getSelectionIndex() > 0 ? (String) categoryIdsByUniqueName
+				.get(comboCategory.getText())
+				: null;
+	}
+
+	/**
+	 * Returns the identifier for the currently selected context.
+	 *
+	 * @return The selected context; <code>null</code> if none.
+	 */
+	private final String getContextId() {
+		return comboContext.getSelectionIndex() >= 0 ? (String) contextIdsByUniqueName
+				.get(comboContext.getText())
+				: null;
+	}
+
+	/**
+	 * Returns the current trigger sequence.
+	 *
+	 * @return The trigger sequence; may be empty, but never <code>null</code>.
+	 */
+	private final KeySequence getKeySequence() {
+		return textTriggerSequenceManager.getKeySequence();
+	}
+
+	/**
+	 * Returns the currently-selected fully-parameterized command.
+	 *
+	 * @return The selected fully-parameterized command; <code>null</code> if
+	 *         none.
+	 */
+	private final ParameterizedCommand getParameterizedCommand() {
+		final int selectionIndex = comboCommand.getSelectionIndex();
+		if ((selectionIndex >= 0) && (commands != null)
+				&& (selectionIndex < commands.length)) {
+			return commands[selectionIndex];
+		}
+
+		return null;
+	}
+
+	/**
+	 * Returns the identifier for the currently selected scheme.
+	 *
+	 * @return The selected scheme; <code>null</code> if none.
+	 */
+	private final String getSchemeId() {
+		return comboScheme.getSelectionIndex() >= 0 ? (String) schemeIdsByUniqueName
+				.get(comboScheme.getText())
+				: null;
+	}
+
+	@Override
+	public final void init(final IWorkbench workbench) {
+		activityManager = workbench.getActivitySupport().getActivityManager();
+		bindingService = workbench.getService(IBindingService.class);
+		commandService = workbench.getService(ICommandService.class);
+		contextService = workbench.getService(IContextService.class);
+	}
+
+	/**
+	 * Checks whether the activity manager knows anything about this command
+	 * identifier. If the activity manager is currently filtering this command,
+	 * then it does not appear in the user interface.
+	 *
+	 * @param command
+	 *            The command which should be checked against the activities;
+	 *            must not be <code>null</code>.
+	 * @return <code>true</code> if the command identifier is not filtered;
+	 *         <code>false</code> if it is
+	 */
+	private final boolean isActive(final Command command) {
+		return activityManager.getIdentifier(command.getId()).isEnabled();
+	}
+
+	/**
+	 * Logs the given exception, and opens an error dialog saying that something
+	 * went wrong. The exception is assumed to have something to do with the
+	 * preference store.
+	 *
+	 * @param exception
+	 *            The exception to be logged; must not be <code>null</code>.
+	 */
+	private final void logPreferenceStoreException(final Throwable exception) {
+		final String message = Util.translateString(RESOURCE_BUNDLE,
+				"PreferenceStoreError.Message"); //$NON-NLS-1$
+		String exceptionMessage = exception.getMessage();
+		if (exceptionMessage == null) {
+			exceptionMessage = message;
+		}
+		final IStatus status = new Status(IStatus.ERROR,
+				WorkbenchPlugin.PI_WORKBENCH, 0, exceptionMessage, exception);
+		WorkbenchPlugin.log(message, status);
+		StatusUtil.handleStatus(message, exception, StatusManager.SHOW);
+	}
+
+	@Override
+	public final boolean performCancel() {
+		// Save the selected tab for future reference.
+		persistSelectedTab();
+
+		return super.performCancel();
+	}
+
+	@Override
+	protected final void performDefaults() {
+		// Ask the user to confirm
+		final String title = Util.translateString(RESOURCE_BUNDLE,
+				"restoreDefaultsMessageBoxText"); //$NON-NLS-1$
+		final String message = Util.translateString(RESOURCE_BUNDLE,
+				"restoreDefaultsMessageBoxMessage"); //$NON-NLS-1$
+		final boolean confirmed = MessageDialog.open(MessageDialog.CONFIRM,
+				getShell(), title, message, SWT.SHEET);
+
+		if (confirmed) {
+			// Fix the scheme in the local changes.
+			final String defaultSchemeId = bindingService.getDefaultSchemeId();
+			final Scheme defaultScheme = localChangeManager
+					.getScheme(defaultSchemeId);
+			try {
+				localChangeManager.setActiveScheme(defaultScheme);
+			} catch (final NotDefinedException e) {
+				// At least we tried....
+			}
+
+			// Fix the bindings in the local changes.
+			final Binding[] currentBindings = localChangeManager.getBindings();
+			final int currentBindingsLength = currentBindings.length;
+			final Set trimmedBindings = new HashSet();
+			for (int i = 0; i < currentBindingsLength; i++) {
+				final Binding binding = currentBindings[i];
+				if (binding.getType() != Binding.USER) {
+					trimmedBindings.add(binding);
+				}
+			}
+			final Binding[] trimmedBindingArray = (Binding[]) trimmedBindings
+					.toArray(new Binding[trimmedBindings.size()]);
+			localChangeManager.setBindings(trimmedBindingArray);
+
+			// Apply the changes.
+			try {
+				bindingService.savePreferences(defaultScheme,
+						trimmedBindingArray);
+			} catch (final IOException e) {
+				logPreferenceStoreException(e);
+			}
+		}
+
+		setScheme(localChangeManager.getActiveScheme()); // update the scheme
+		update(true);
+		super.performDefaults();
+	}
+
+	@Override
+	public final boolean performOk() {
+		// Save the preferences.
+		try {
+			bindingService.savePreferences(
+					localChangeManager.getActiveScheme(), localChangeManager
+							.getBindings());
+		} catch (final IOException e) {
+			logPreferenceStoreException(e);
+		}
+
+		// Save the selected tab for future reference.
+		persistSelectedTab();
+
+		return super.performOk();
+	}
+
+	/**
+	 * Remembers the currently selected tab for when the preference page next
+	 * opens.
+	 */
+	private final void persistSelectedTab() {
+		final IPreferenceStore store = getPreferenceStore();
+		store.setValue(IPreferenceConstants.KEYS_PREFERENCE_SELECTED_TAB,
+				tabFolder.getSelectionIndex());
+	}
+
+	/**
+	 * Handles the selection event on the add button. This removes all
+	 * user-defined bindings matching the given key sequence, scheme and
+	 * context. It then adds a new binding with the current selections.
+	 */
+	private final void selectedButtonAdd() {
+		final ParameterizedCommand command = getParameterizedCommand();
+		final String contextId = getContextId();
+		final String schemeId = getSchemeId();
+		final KeySequence keySequence = getKeySequence();
+		localChangeManager.removeBindings(keySequence, schemeId, contextId,
+				null, null, null, Binding.USER);
+		localChangeManager.addBinding(new KeyBinding(keySequence, command,
+				schemeId, contextId, null, null, null, Binding.USER));
+		update(true);
+	}
+
+	// RAP
+//	/**
+//	 * Provides a facility for exporting the viewable list of key bindings to a
+//	 * file. Currently, this only supports exporting to a list of
+//	 * comma-separated values. The user is prompted for which file should
+//	 * receive our bounty.
+//	 *
+//	 * @since 3.1
+//	 */
+//	private final void selectedButtonExport() {
+//		final FileDialog fileDialog = new FileDialog(getShell(), SWT.SAVE
+//				| SWT.SHEET);
+//		fileDialog.setFilterExtensions(new String[] { "*.csv" }); //$NON-NLS-1$
+//		fileDialog.setFilterNames(new String[] { Util.translateString(
+//				RESOURCE_BUNDLE, "csvFilterName") }); //$NON-NLS-1$
+//		final String filePath = fileDialog.open();
+//		if (filePath == null) {
+//			return;
+//		}
+//
+//		final SafeRunnable runnable = new SafeRunnable() {
+//			@Override
+//			public final void run() throws IOException {
+//				Writer fileWriter = null;
+//				try {
+//					fileWriter = new BufferedWriter(new FileWriter(filePath));
+//					final TableItem[] items = tableBindings.getItems();
+//					final int numColumns = tableBindings.getColumnCount();
+//					for (final TableItem item : items) {
+//						for (int j = 0; j < numColumns; j++) {
+//							String buf = Util.replaceAll(item.getText(j), "\"", //$NON-NLS-1$
+//									"\"\""); //$NON-NLS-1$
+//							fileWriter.write("\"" + buf + "\"");  //$NON-NLS-1$//$NON-NLS-2$
+//							if (j < numColumns - 1) {
+//								fileWriter.write(',');
+//							}
+//						}
+//						fileWriter.write(System.getProperty("line.separator")); //$NON-NLS-1$
+//					}
+//
+//				} finally {
+//					if (fileWriter != null) {
+//						try {
+//							fileWriter.close();
+//						} catch (final IOException e) {
+//							// At least I tried.
+//						}
+//					}
+//
+//				}
+//			}
+//		};
+//		SafeRunner.run(runnable);
+//	}
+
+	/**
+	 * Handles the selection event on the remove button. This removes all
+	 * user-defined bindings matching the given key sequence, scheme and
+	 * context. It then adds a new deletion binding for the selected trigger
+	 * sequence.
+	 */
+	private final void selectedButtonRemove() {
+		final String contextId = getContextId();
+		final String schemeId = getSchemeId();
+		final KeySequence keySequence = getKeySequence();
+		localChangeManager.removeBindings(keySequence, schemeId, contextId,
+				null, null, null, Binding.USER);
+		localChangeManager.addBinding(new KeyBinding(keySequence, null,
+				schemeId, contextId, null, null, null, Binding.USER));
+		update(true);
+	}
+
+	/**
+	 * Handles the selection event on the restore button. This removes all
+	 * user-defined bindings matching the given key sequence, scheme and
+	 * context.
+	 */
+	private final void selectedButtonRestore() {
+		String contextId = getContextId();
+		String schemeId = getSchemeId();
+		KeySequence keySequence = getKeySequence();
+		localChangeManager.removeBindings(keySequence, schemeId, contextId,
+				null, null, null, Binding.USER);
+		update(true);
+	}
+
+	/**
+	 * Updates the local managers active scheme, and then updates the interface.
+	 */
+	private final void selectedComboScheme() {
+		final String activeSchemeId = getSchemeId();
+		final Scheme activeScheme = localChangeManager
+				.getScheme(activeSchemeId);
+		try {
+			localChangeManager.setActiveScheme(activeScheme);
+		} catch (final NotDefinedException e) {
+			// Oh, well.
+		}
+		update(true);
+	}
+
+	/**
+	 * Handles the selection event on the table containing the bindings for a
+	 * particular command. This updates the context and trigger sequence based
+	 * on the selected binding.
+	 */
+	private final void selectedTableBindingsForCommand() {
+		final int selection = tableBindingsForCommand.getSelectionIndex();
+		if ((selection >= 0)
+				&& (selection < tableBindingsForCommand.getItemCount())) {
+			final TableItem item = tableBindingsForCommand.getItem(selection);
+			final KeyBinding binding = (KeyBinding) item.getData(ITEM_DATA_KEY);
+			setContextId(binding.getContextId());
+			setKeySequence(binding.getKeySequence());
+		}
+
+		update();
+	}
+
+	/**
+	 * Handles the selection event on the table containing the bindings for a
+	 * particular trigger sequence. This updates the context based on the
+	 * selected binding.
+	 */
+	private final void selectedTableBindingsForTriggerSequence() {
+		final int selection = tableBindingsForTriggerSequence
+				.getSelectionIndex();
+		if ((selection >= 0)
+				&& (selection < tableBindingsForTriggerSequence.getItemCount())) {
+			final TableItem item = tableBindingsForTriggerSequence
+					.getItem(selection);
+			final Binding binding = (Binding) item.getData(ITEM_DATA_KEY);
+			setContextId(binding.getContextId());
+		}
+
+		update();
+	}
+
+	/**
+	 * Responds to some kind of trigger on the View tab by taking the current
+	 * selection on the key bindings table and selecting the appropriate items
+	 * in the Modify tab.
+	 *
+	 * @since 3.1
+	 */
+	private final void selectedTableKeyBindings() {
+		final int selectionIndex = tableBindings.getSelectionIndex();
+		if (selectionIndex != -1) {
+			final TableItem item = tableBindings.getItem(selectionIndex);
+			final Binding binding = (Binding) item.getData(BINDING_KEY);
+			editBinding(binding);
+
+		} else {
+			editBinding(null);
+		}
+	}
+
+	/**
+	 * Changes the selected context name in the context combo box. The context
+	 * selected is either the one matching the identifier provided (if
+	 * possible), or the default context identifier. If no matching name can be
+	 * found in the combo, then the first item is selected.
+	 *
+	 * @param contextId
+	 *            The context identifier for the context to be selected in the
+	 *            combo box; may be <code>null</code>.
+	 */
+	private final void setContextId(final String contextId) {
+		// Clear the current selection.
+		comboContext.clearSelection();
+		comboContext.deselectAll();
+
+		// Figure out which name to look for.
+		String contextName = (String) contextUniqueNamesById.get(contextId);
+		if (contextName == null) {
+			contextName = (String) contextUniqueNamesById
+					.get(IContextIds.CONTEXT_ID_WINDOW);
+		}
+		if (contextName == null) {
+			contextName = Util.ZERO_LENGTH_STRING;
+		}
+
+		// Scan the list for the selection we're looking for.
+		final String[] items = comboContext.getItems();
+		boolean found = false;
+		for (int i = 0; i < items.length; i++) {
+			if (contextName.equals(items[i])) {
+				comboContext.select(i);
+				found = true;
+				break;
+			}
+		}
+
+		// If we didn't find an item, then set the first item as selected.
+		if ((!found) && (items.length > 0)) {
+			comboContext.select(0);
+		}
+	}
+
+	/**
+	 * Sets the current trigger sequence.
+	 *
+	 * @param keySequence
+	 *            The trigger sequence; may be <code>null</code>.
+	 */
+	private final void setKeySequence(final KeySequence keySequence) {
+		textTriggerSequenceManager.setKeySequence(keySequence);
+	}
+
+	/**
+	 * Changes the selection in the command combo box.
+	 *
+	 * @param command
+	 *            The fully-parameterized command to select; may be
+	 *            <code>null</code>.
+	 */
+	private final void setParameterizedCommand(
+			final ParameterizedCommand command) {
+		int i = 0;
+		if (commands != null) {
+			final int commandCount = commands.length;
+			for (; i < commandCount; i++) {
+				if (commands[i].equals(command)) {
+					if ((comboCommand.getSelectionIndex() != i)
+							&& (i < comboCommand.getItemCount())) {
+						comboCommand.select(i);
+					}
+					break;
+				}
+			}
+			if ((i >= comboCommand.getItemCount())
+					&& (comboCommand.getSelectionIndex() != 0)) {
+				comboCommand.select(0);
+			}
+		}
+	}
+
+	/**
+	 * Sets the currently selected scheme
+	 *
+	 * @param scheme
+	 *            The scheme to select; may be <code>null</code>.
+	 */
+	private final void setScheme(final Scheme scheme) {
+		comboScheme.clearSelection();
+		comboScheme.deselectAll();
+		final String schemeUniqueName = (String) schemeUniqueNamesById
+				.get(scheme.getId());
+
+		if (schemeUniqueName != null) {
+			final String items[] = comboScheme.getItems();
+
+			for (int i = 0; i < items.length; i++) {
+				if (schemeUniqueName.equals(items[i])) {
+					comboScheme.select(i);
+					break;
+				}
+			}
+		}
+	}
+
+	/**
+	 * Builds the internal look-up tables before allowing the page to become
+	 * visible.
+	 */
+	@Override
+	public final void setVisible(final boolean visible) {
+		if (visible == true) {
+			Map contextsByName = new HashMap();
+
+			for (Iterator iterator = contextService.getDefinedContextIds()
+					.iterator(); iterator.hasNext();) {
+				Context context = contextService.getContext((String) iterator
+						.next());
+				try {
+					String name = context.getName();
+					Collection contexts = (Collection) contextsByName.get(name);
+
+					if (contexts == null) {
+						contexts = new HashSet();
+						contextsByName.put(name, contexts);
+					}
+
+					contexts.add(context);
+				} catch (final NotDefinedException e) {
+					// Do nothing.
+				}
+			}
+
+			Map commandsByName = new HashMap();
+
+			for (Iterator iterator = commandService.getDefinedCommandIds()
+					.iterator(); iterator.hasNext();) {
+				Command command = commandService.getCommand((String) iterator
+						.next());
+				if (!isActive(command)) {
+					continue;
+				}
+
+				try {
+					String name = command.getName();
+					Collection commands = (Collection) commandsByName.get(name);
+
+					if (commands == null) {
+						commands = new HashSet();
+						commandsByName.put(name, commands);
+					}
+
+					commands.add(command);
+				} catch (NotDefinedException eNotDefined) {
+					// Do nothing
+				}
+			}
+
+			// moved here to allow us to remove any empty categories
+			commandIdsByCategoryId = new HashMap();
+
+			for (Iterator iterator = commandService.getDefinedCommandIds()
+					.iterator(); iterator.hasNext();) {
+				final Command command = commandService
+						.getCommand((String) iterator.next());
+				if (!isActive(command)) {
+					continue;
+				}
+
+				try {
+					String categoryId = command.getCategory().getId();
+					Collection commandIds = (Collection) commandIdsByCategoryId
+							.get(categoryId);
+
+					if (commandIds == null) {
+						commandIds = new HashSet();
+						commandIdsByCategoryId.put(categoryId, commandIds);
+					}
+
+					commandIds.add(command.getId());
+				} catch (NotDefinedException eNotDefined) {
+					// Do nothing
+				}
+			}
+
+			Map categoriesByName = new HashMap();
+
+			for (Iterator iterator = commandService.getDefinedCategoryIds()
+					.iterator(); iterator.hasNext();) {
+				Category category = commandService
+						.getCategory((String) iterator.next());
+
+				try {
+					if (commandIdsByCategoryId.containsKey(category.getId())) {
+						String name = category.getName();
+						Collection categories = (Collection) categoriesByName
+								.get(name);
+
+						if (categories == null) {
+							categories = new HashSet();
+							categoriesByName.put(name, categories);
+						}
+
+						categories.add(category);
+					}
+				} catch (NotDefinedException eNotDefined) {
+					// Do nothing
+				}
+			}
+
+			Map schemesByName = new HashMap();
+
+			final Scheme[] definedSchemes = bindingService.getDefinedSchemes();
+			for (final Scheme scheme : definedSchemes) {
+				try {
+					String name = scheme.getName();
+					Collection schemes = (Collection) schemesByName.get(name);
+
+					if (schemes == null) {
+						schemes = new HashSet();
+						schemesByName.put(name, schemes);
+					}
+
+					schemes.add(scheme);
+				} catch (final NotDefinedException e) {
+					// Do nothing.
+				}
+			}
+
+			contextIdsByUniqueName = new HashMap();
+			contextUniqueNamesById = new HashMap();
+
+			for (Iterator iterator = contextsByName.entrySet().iterator(); iterator
+					.hasNext();) {
+				Map.Entry entry = (Map.Entry) iterator.next();
+				String name = (String) entry.getKey();
+				Set contexts = (Set) entry.getValue();
+				Iterator iterator2 = contexts.iterator();
+
+				if (contexts.size() == 1) {
+					Context context = (Context) iterator2.next();
+					contextIdsByUniqueName.put(name, context.getId());
+					contextUniqueNamesById.put(context.getId(), name);
+				} else {
+					while (iterator2.hasNext()) {
+						Context context = (Context) iterator2.next();
+						String uniqueName = MessageFormat.format(
+								Util.translateString(RESOURCE_BUNDLE, "uniqueName"), //$NON-NLS-1$
+								name, context.getId());
+						contextIdsByUniqueName.put(uniqueName, context.getId());
+						contextUniqueNamesById.put(context.getId(), uniqueName);
+					}
+				}
+			}
+
+			categoryIdsByUniqueName = new HashMap();
+			categoryUniqueNamesById = new HashMap();
+
+			for (Iterator iterator = categoriesByName.entrySet().iterator(); iterator
+					.hasNext();) {
+				Map.Entry entry = (Map.Entry) iterator.next();
+				String name = (String) entry.getKey();
+				Set categories = (Set) entry.getValue();
+				Iterator iterator2 = categories.iterator();
+
+				if (categories.size() == 1) {
+					Category category = (Category) iterator2.next();
+					categoryIdsByUniqueName.put(name, category.getId());
+					categoryUniqueNamesById.put(category.getId(), name);
+				} else {
+					while (iterator2.hasNext()) {
+						Category category = (Category) iterator2.next();
+						String uniqueName = MessageFormat.format(
+								Util.translateString(RESOURCE_BUNDLE,
+										"uniqueName"), new Object[] { name, //$NON-NLS-1$
+										category.getId() });
+						categoryIdsByUniqueName.put(uniqueName, category
+								.getId());
+						categoryUniqueNamesById.put(category.getId(),
+								uniqueName);
+					}
+				}
+			}
+
+			schemeIdsByUniqueName = new HashMap();
+			schemeUniqueNamesById = new HashMap();
+
+			for (Iterator iterator = schemesByName.entrySet().iterator(); iterator
+					.hasNext();) {
+				Map.Entry entry = (Map.Entry) iterator.next();
+				String name = (String) entry.getKey();
+				Set keyConfigurations = (Set) entry.getValue();
+				Iterator iterator2 = keyConfigurations.iterator();
+
+				if (keyConfigurations.size() == 1) {
+					Scheme scheme = (Scheme) iterator2.next();
+					schemeIdsByUniqueName.put(name, scheme.getId());
+					schemeUniqueNamesById.put(scheme.getId(), name);
+				} else {
+					while (iterator2.hasNext()) {
+						Scheme scheme = (Scheme) iterator2.next();
+						String uniqueName = MessageFormat.format(
+								Util.translateString(RESOURCE_BUNDLE,
+										"uniqueName"), new Object[] { name, //$NON-NLS-1$
+										scheme.getId() });
+						schemeIdsByUniqueName.put(uniqueName, scheme.getId());
+						schemeUniqueNamesById.put(scheme.getId(), uniqueName);
+					}
+				}
+			}
+
+			Scheme activeScheme = bindingService.getActiveScheme();
+
+			// Make an internal copy of the binding manager, for local changes.
+			try {
+				for (final Scheme scheme : definedSchemes) {
+					final Scheme copy = localChangeManager.getScheme(scheme
+							.getId());
+					copy.define(scheme.getName(), scheme.getDescription(),
+							scheme.getParentId());
+				}
+				localChangeManager.setActiveScheme(bindingService
+						.getActiveScheme());
+			} catch (final NotDefinedException e) {
+				throw new Error(
+						"There is a programmer error in the keys preference page"); //$NON-NLS-1$
+			}
+			localChangeManager.setLocale(bindingService.getLocale());
+			localChangeManager.setPlatform(bindingService.getPlatform());
+			localChangeManager.setBindings(bindingService.getBindings());
+
+			// Populate the category combo box.
+			List categoryNames = new ArrayList(categoryIdsByUniqueName.keySet());
+			Collections.sort(categoryNames, Collator.getInstance());
+			if (commandIdsByCategoryId.containsKey(null)) {
+				categoryNames.add(0, Util.translateString(RESOURCE_BUNDLE,
+						"other")); //$NON-NLS-1$
+			}
+			comboCategory.setItems((String[]) categoryNames
+					.toArray(new String[categoryNames.size()]));
+			comboCategory.clearSelection();
+			comboCategory.deselectAll();
+			if (commandIdsByCategoryId.containsKey(null)
+					|| !categoryNames.isEmpty()) {
+				comboCategory.select(0);
+			}
+
+			// Populate the scheme combo box.
+			List schemeNames = new ArrayList(schemeIdsByUniqueName.keySet());
+			Collections.sort(schemeNames, Collator.getInstance());
+			comboScheme.setItems((String[]) schemeNames
+					.toArray(new String[schemeNames.size()]));
+			setScheme(activeScheme);
+
+			// Update the entire page.
+			update(true);
+		}
+
+		super.setVisible(visible);
+	}
+
+	/**
+	 * Updates the entire preference page -- except the view tab -- based on
+	 * current selection sate. This preference page is written so that
+	 * everything can be made consistent simply by inspecting the state of its
+	 * widgets. A change is triggered by the user, and an event is fired. The
+	 * event triggers an update. It is possible for extra work to be done by
+	 * this page before calling update.
+	 */
+	private final void update() {
+		update(false);
+	}
+
+	/**
+	 * Updates the entire preference page based on current changes. This
+	 * preference page is written so that everything can be made consistent
+	 * simply by inspecting the state of its widgets. A change is triggered by
+	 * the user, and an event is fired. The event triggers an update. It is
+	 * possible for extra work to be done by this page before calling update.
+	 *
+	 * @param updateViewTab
+	 *            Whether the view tab should be updated as well.
+	 */
+	private final void update(final boolean updateViewTab) {
+		if (updateViewTab) {
+			updateViewTab();
+		}
+		updateComboCommand();
+		updateComboContext();
+		final TriggerSequence triggerSequence = getKeySequence();
+		updateTableBindingsForTriggerSequence(triggerSequence);
+		final ParameterizedCommand command = getParameterizedCommand();
+		updateTableBindingsForCommand(command);
+		final String contextId = getContextId();
+		updateSelection(tableBindingsForTriggerSequence, contextId,
+				triggerSequence);
+		updateSelection(tableBindingsForCommand, contextId, triggerSequence);
+		updateLabelSchemeExtends();
+		updateLabelContextExtends();
+		updateEnabled(triggerSequence, command);
+	}
+
+	/**
+	 * Updates the contents of the commands combo box, based on the current
+	 * selection in the category combo box.
+	 */
+	private final void updateComboCommand() {
+		// Remember the current selection, so we can restore it later.
+		final ParameterizedCommand command = getParameterizedCommand();
+
+		// Figure out where command identifiers apply to the selected category.
+		final String categoryId = getCategoryId();
+		Set commandIds = (Set) commandIdsByCategoryId.get(categoryId);
+		if (commandIds==null) {
+			commandIds = Collections.EMPTY_SET;
+		}
+
+		/*
+		 * Generate an array of parameterized commands based on these
+		 * identifiers. The parameterized commands will be sorted based on their
+		 * names.
+		 */
+		List commands = new ArrayList();
+		final Iterator commandIdItr = commandIds.iterator();
+		while (commandIdItr.hasNext()) {
+			final String currentCommandId = (String) commandIdItr.next();
+			final Command currentCommand = commandService
+					.getCommand(currentCommandId);
+			try {
+				commands.addAll(ParameterizedCommand
+						.generateCombinations(currentCommand));
+			} catch (final NotDefinedException e) {
+				// It is safe to just ignore undefined commands.
+			}
+		}
+
+		// sort the commands with a collator, so they appear in the
+		// combo correctly
+		commands = sortParameterizedCommands(commands);
+
+		final int commandCount = commands.size();
+		this.commands = (ParameterizedCommand[]) commands
+				.toArray(new ParameterizedCommand[commandCount]);
+
+		/*
+		 * Generate an array of command names based on this array of
+		 * parameterized commands.
+		 */
+		final String[] commandNames = new String[commandCount];
+		for (int i = 0; i < commandCount; i++) {
+			try {
+				commandNames[i] = this.commands[i].getName();
+			} catch (final NotDefinedException e) {
+				throw new Error(
+						"Concurrent modification of the command's defined state"); //$NON-NLS-1$
+			}
+		}
+
+		/*
+		 * Copy the command names into the combo box, but only if they've
+		 * changed. We do this to try to avoid unnecessary calls out to the
+		 * operating system, as well as to defend against bugs in SWT's event
+		 * mechanism.
+		 */
+		final String[] currentItems = comboCommand.getItems();
+		if (!Arrays.equals(currentItems, commandNames)) {
+			comboCommand.setItems(commandNames);
+		}
+
+		// Try to restore the selection.
+		setParameterizedCommand(command);
+
+		/*
+		 * Just to be extra careful, make sure that we have a selection at this
+		 * point. This line could probably be removed, but it makes the code a
+		 * bit more robust.
+		 */
+		if ((comboCommand.getSelectionIndex() == -1) && (commandCount > 0)) {
+			comboCommand.select(0);
+		}
+	}
+
+	/**
+	 * Sort the commands using the correct language.
+	 * @param commands the List of ParameterizedCommands
+	 * @return The sorted List
+	 */
+	private List sortParameterizedCommands(List commands) {
+		final Collator collator = Collator.getInstance();
+
+		// this comparator is based on the ParameterizedCommands#compareTo(*)
+		// method, but uses the collator.
+		Comparator comparator = (o1, o2) -> {
+			String name1 = null;
+			String name2 = null;
+			try {
+				name1 = ((ParameterizedCommand) o1).getName();
+			} catch (NotDefinedException e1) {
+				return -1;
+			}
+			try {
+				name2 = ((ParameterizedCommand) o2).getName();
+			} catch (NotDefinedException e2) {
+				return 1;
+			}
+			int rc = collator.compare(name1, name2);
+			if (rc != 0) {
+				return rc;
+			}
+
+			String id1 = ((ParameterizedCommand) o1).getId();
+			String id2 = ((ParameterizedCommand) o2).getId();
+			return collator.compare(id1, id2);
+		};
+		Collections.sort(commands, comparator);
+		return commands;
+	}
+
+	/**
+	 * Updates the contents of the context combo box, as well as its selection.
+	 */
+	private final void updateComboContext() {
+		final String contextId = getContextId();
+		final Map contextIdsByName = new HashMap(contextIdsByUniqueName);
+
+		final List contextNames = new ArrayList(contextIdsByName.keySet());
+		Collections.sort(contextNames, Collator.getInstance());
+
+		comboContext.setItems((String[]) contextNames
+				.toArray(new String[contextNames.size()]));
+		setContextId(contextId);
+
+		if (comboContext.getSelectionIndex() == -1 && !contextNames.isEmpty()) {
+			comboContext.select(0);
+		}
+	}
+
+	/**
+	 * Updates the enabled state of the various widgets on this page. The
+	 * decision is based on the current trigger sequence and the currently
+	 * selected command.
+	 *
+	 * @param triggerSequence
+	 *            The current trigger sequence; may be empty, but never
+	 *            <code>null</code>.
+	 * @param command
+	 *            The currently selected command, if any; <code>null</code>
+	 *            otherwise.
+	 */
+	private final void updateEnabled(final TriggerSequence triggerSequence,
+			final ParameterizedCommand command) {
+		final boolean commandSelected = command != null;
+		labelBindingsForCommand.setEnabled(commandSelected);
+		tableBindingsForCommand.setEnabled(commandSelected);
+
+		final boolean triggerSequenceSelected = !triggerSequence.isEmpty();
+		labelBindingsForTriggerSequence.setEnabled(triggerSequenceSelected);
+		tableBindingsForTriggerSequence.setEnabled(triggerSequenceSelected);
+
+		/*
+		 * TODO Do some better button enablement.
+		 */
+		final boolean buttonsEnabled = commandSelected
+				&& triggerSequenceSelected;
+		buttonAdd.setEnabled(buttonsEnabled);
+		buttonRemove.setEnabled(buttonsEnabled);
+		buttonRestore.setEnabled(buttonsEnabled);
+	}
+
+	/**
+	 * Updates the label next to the context that says "extends" if the context
+	 * is a child of another context. If the context is not a child of another
+	 * context, then the label is simply blank.
+	 */
+	private final void updateLabelContextExtends() {
+		final String contextId = getContextId();
+
+		if (contextId != null) {
+			final Context context = contextService.getContext(getContextId());
+			if (context.isDefined()) {
+				try {
+					final String parentId = context.getParentId();
+					if (parentId != null) {
+						final String name = (String) contextUniqueNamesById
+								.get(parentId);
+						if (name != null) {
+							labelContextExtends.setText(MessageFormat.format(
+									Util.translateString(RESOURCE_BUNDLE, "extends"), //$NON-NLS-1$
+									name));
+							return;
+						}
+					}
+				} catch (final NotDefinedException e) {
+					// Do nothing
+				}
+			}
+		}
+
+		labelContextExtends.setText(Util.ZERO_LENGTH_STRING);
+	}
+
+	/**
+	 * Updates the label next to the scheme that says "extends" if the scheme is
+	 * a child of another scheme. If the scheme is not a child of another
+	 * scheme, then the label is simply blank.
+	 */
+	private final void updateLabelSchemeExtends() {
+		final String schemeId = getSchemeId();
+
+		if (schemeId != null) {
+			final Scheme scheme = bindingService.getScheme(schemeId);
+			try {
+				final String name = (String) schemeUniqueNamesById.get(scheme
+						.getParentId());
+				if (name != null) {
+					labelSchemeExtends.setText(MessageFormat.format(Util
+							.translateString(RESOURCE_BUNDLE, "extends"), //$NON-NLS-1$
+							name));
+					return;
+				}
+			} catch (final NotDefinedException e) {
+				// Do nothing
+			}
+		}
+
+		labelSchemeExtends.setText(Util.ZERO_LENGTH_STRING);
+	}
+
+	/**
+	 * Tries to select the correct entry in table based on the currently
+	 * selected context and trigger sequence. If the table hasn't really
+	 * changed, then this method is essentially trying to restore the selection.
+	 * If it has changed, then it is trying to select the most entry based on
+	 * the context.
+	 *
+	 * @param table
+	 *            The table to be changed; must not be <code>null</code>.
+	 * @param contextId
+	 *            The currently selected context; should not be
+	 *            <code>null</code>.
+	 * @param triggerSequence
+	 *            The current trigger sequence; should not be <code>null</code>.
+	 */
+	private final void updateSelection(final Table table,
+			final String contextId, final TriggerSequence triggerSequence) {
+		if (table.getSelectionCount() > 1) {
+			table.deselectAll();
+		}
+
+		final TableItem[] items = table.getItems();
+		int selection = -1;
+		for (int i = 0; i < items.length; i++) {
+			final Binding binding = (Binding) items[i].getData(ITEM_DATA_KEY);
+			if ((Util.equals(contextId, binding.getContextId()))
+					&& (Util.equals(triggerSequence, binding
+							.getTriggerSequence()))) {
+				selection = i;
+				break;
+			}
+		}
+
+		if (selection != -1) {
+			table.select(selection);
+		}
+	}
+
+	/**
+	 * Updates the contents of the table showing the bindings for the currently
+	 * selected command. The selection is destroyed by this process.
+	 *
+	 * @param parameterizedCommand
+	 *            The currently selected fully-parameterized command; may be
+	 *            <code>null</code>.
+	 */
+	private final void updateTableBindingsForCommand(
+			final ParameterizedCommand parameterizedCommand) {
+		// Clear the table of existing items.
+		tableBindingsForCommand.removeAll();
+
+		// Add each of the bindings, if the command identifier matches.
+		final Collection bindings = localChangeManager
+				.getActiveBindingsDisregardingContextFlat();
+		final Iterator bindingItr = bindings.iterator();
+		while (bindingItr.hasNext()) {
+			final Binding binding = (Binding) bindingItr.next();
+			if (!Util.equals(parameterizedCommand, binding
+					.getParameterizedCommand())) {
+				continue; // binding does not match
+			}
+
+			final TableItem tableItem = new TableItem(tableBindingsForCommand,
+					SWT.NULL);
+			tableItem.setData(ITEM_DATA_KEY, binding);
+
+			/*
+			 * Set the associated image based on the type of binding. Either it
+			 * is a user binding or a system binding.
+			 *
+			 * TODO Identify more image types.
+			 */
+			if (binding.getType() == Binding.SYSTEM) {
+				tableItem.setImage(0, IMAGE_BLANK);
+			} else {
+				tableItem.setImage(0, IMAGE_CHANGE);
+			}
+
+			String contextName = (String) contextUniqueNamesById.get(binding
+					.getContextId());
+			if (contextName == null) {
+				contextName = Util.ZERO_LENGTH_STRING;
+			}
+			tableItem.setText(1, contextName);
+			tableItem.setText(2, binding.getTriggerSequence().format());
+		}
+	}
+
+	/**
+	 * Updates the contents of the table showing the bindings for the current
+	 * trigger sequence. The selection is destroyed by this process.
+	 *
+	 * @param triggerSequence
+	 *            The current trigger sequence; may be <code>null</code> or
+	 *            empty.
+	 */
+	private final void updateTableBindingsForTriggerSequence(
+			final TriggerSequence triggerSequence) {
+		// Clear the table of its existing items.
+		tableBindingsForTriggerSequence.removeAll();
+
+		// Get the collection of bindings for the current command.
+		final Map activeBindings = localChangeManager
+				.getActiveBindingsDisregardingContext();
+		final Collection bindings = (Collection) activeBindings
+				.get(triggerSequence);
+		if (bindings == null) {
+			return;
+		}
+
+		// Add each of the bindings.
+		final Iterator bindingItr = bindings.iterator();
+		while (bindingItr.hasNext()) {
+			final Binding binding = (Binding) bindingItr.next();
+			final Context context = contextService.getContext(binding
+					.getContextId());
+			final ParameterizedCommand parameterizedCommand = binding
+					.getParameterizedCommand();
+			final Command command = parameterizedCommand.getCommand();
+			if ((!context.isDefined()) && (!command.isDefined())) {
+				continue;
+			}
+
+			final TableItem tableItem = new TableItem(
+					tableBindingsForTriggerSequence, SWT.NULL);
+			tableItem.setData(ITEM_DATA_KEY, binding);
+
+			/*
+			 * Set the associated image based on the type of binding. Either it
+			 * is a user binding or a system binding.
+			 *
+			 * TODO Identify more image types.
+			 */
+			if (binding.getType() == Binding.SYSTEM) {
+				tableItem.setImage(0, IMAGE_BLANK);
+			} else {
+				tableItem.setImage(0, IMAGE_CHANGE);
+			}
+
+			try {
+				tableItem.setText(1, context.getName());
+				tableItem.setText(2, parameterizedCommand.getName());
+			} catch (final NotDefinedException e) {
+				throw new Error(
+						"Context or command became undefined on a non-UI thread while the UI thread was processing."); //$NON-NLS-1$
+			}
+		}
+	}
+
+	/**
+	 * Updates the contents of the view tab. This queries the command manager
+	 * for a list of key sequence binding definitions, and these definitions are
+	 * then added to the table.
+	 *
+	 * @since 3.1
+	 */
+	private final void updateViewTab() {
+		// Clear out the existing table contents.
+		tableBindings.removeAll();
+
+		// Get a sorted list of key binding contents.
+		final List bindings = new ArrayList(localChangeManager
+				.getActiveBindingsDisregardingContextFlat());
+		Collections.sort(bindings, new Comparator() {
+			/**
+			 * Compares two instances of <code>Binding</code> based on the
+			 * current sort order.
+			 *
+			 * @param object1
+			 *            The first object to compare; must be an instance of
+			 *            <code>Binding</code> (i.e., not <code>null</code>).
+			 * @param object2
+			 *            The second object to compare; must be an instance of
+			 *            <code>Binding</code> (i.e., not <code>null</code>).
+			 * @return The integer value representing the comparison. The
+			 *         comparison is based on the current sort order.
+			 * @since 3.1
+			 */
+			@Override
+			public final int compare(final Object object1, final Object object2) {
+				final Binding binding1 = (Binding) object1;
+				final Binding binding2 = (Binding) object2;
+
+				/*
+				 * Get the category name, command name, formatted key sequence
+				 * and context name for the first binding.
+				 */
+				final Command command1 = binding1.getParameterizedCommand()
+						.getCommand();
+				String categoryName1 = Util.ZERO_LENGTH_STRING;
+				String commandName1 = Util.ZERO_LENGTH_STRING;
+				try {
+					commandName1 = command1.getName();
+					categoryName1 = command1.getCategory().getName();
+				} catch (final NotDefinedException e) {
+					// Just use the zero-length string.
+				}
+				final String triggerSequence1 = binding1.getTriggerSequence()
+						.format();
+				final String contextId1 = binding1.getContextId();
+				String contextName1 = Util.ZERO_LENGTH_STRING;
+				if (contextId1 != null) {
+					final Context context = contextService
+							.getContext(contextId1);
+					try {
+						contextName1 = context.getName();
+					} catch (final org.eclipse.core.commands.common.NotDefinedException e) {
+						// Just use the zero-length string.
+					}
+				}
+
+				/*
+				 * Get the category name, command name, formatted key sequence
+				 * and context name for the first binding.
+				 */
+				final Command command2 = binding2.getParameterizedCommand()
+						.getCommand();
+				String categoryName2 = Util.ZERO_LENGTH_STRING;
+				String commandName2 = Util.ZERO_LENGTH_STRING;
+				try {
+					commandName2 = command2.getName();
+					categoryName2 = command2.getCategory().getName();
+				} catch (final org.eclipse.core.commands.common.NotDefinedException e) {
+					// Just use the zero-length string.
+				}
+				final String keySequence2 = binding2.getTriggerSequence()
+						.format();
+				final String contextId2 = binding2.getContextId();
+				String contextName2 = Util.ZERO_LENGTH_STRING;
+				if (contextId2 != null) {
+					final Context context = contextService
+							.getContext(contextId2);
+					try {
+						contextName2 = context.getName();
+					} catch (final org.eclipse.core.commands.common.NotDefinedException e) {
+						// Just use the zero-length string.
+					}
+				}
+
+				// Compare the items in the current sort order.
+				int compare = 0;
+				for (int element : sortOrder) {
+					switch (element) {
+					case VIEW_CATEGORY_COLUMN_INDEX:
+						compare = Util.compare(categoryName1, categoryName2);
+						if (compare != 0) {
+							return compare;
+						}
+						break;
+					case VIEW_COMMAND_COLUMN_INDEX:
+						compare = Util.compare(commandName1, commandName2);
+						if (compare != 0) {
+							return compare;
+						}
+						break;
+					case VIEW_KEY_SEQUENCE_COLUMN_INDEX:
+						compare = Util.compare(triggerSequence1, keySequence2);
+						if (compare != 0) {
+							return compare;
+						}
+						break;
+					case VIEW_CONTEXT_COLUMN_INDEX:
+						compare = Util.compare(contextName1, contextName2);
+						if (compare != 0) {
+							return compare;
+						}
+						break;
+					default:
+						throw new Error(
+								"Programmer error: added another sort column without modifying the comparator."); //$NON-NLS-1$
+					}
+				}
+
+				return compare;
+			}
+
+			/**
+			 * @see Object#equals(java.lang.Object)
+			 */
+			@Override
+			public final boolean equals(final Object object) {
+				return super.equals(object);
+			}
+		});
+
+		// Add a table item for each item in the list.
+		final Iterator keyBindingItr = bindings.iterator();
+		while (keyBindingItr.hasNext()) {
+			final Binding binding = (Binding) keyBindingItr.next();
+
+			// Get the command and category name.
+			final ParameterizedCommand command = binding
+					.getParameterizedCommand();
+			String commandName = Util.ZERO_LENGTH_STRING;
+			String categoryName = Util.ZERO_LENGTH_STRING;
+			try {
+				commandName = command.getName();
+				categoryName = command.getCommand().getCategory().getName();
+			} catch (final org.eclipse.core.commands.common.NotDefinedException e) {
+				// Just use the zero-length string.
+			}
+
+			// Ignore items with a meaningless command name.
+			if ((commandName == null) || (commandName.length() == 0)) {
+				continue;
+			}
+
+			// Get the context name.
+			final String contextId = binding.getContextId();
+			String contextName = Util.ZERO_LENGTH_STRING;
+			if (contextId != null) {
+				final Context context = contextService.getContext(contextId);
+				try {
+					contextName = context.getName();
+				} catch (final org.eclipse.core.commands.common.NotDefinedException e) {
+					// Just use the zero-length string.
+				}
+			}
+
+			// Create the table item.
+			final TableItem item = new TableItem(tableBindings, SWT.NONE);
+			item.setText(VIEW_CATEGORY_COLUMN_INDEX, categoryName);
+			item.setText(VIEW_COMMAND_COLUMN_INDEX, commandName);
+			item.setText(VIEW_KEY_SEQUENCE_COLUMN_INDEX, binding
+					.getTriggerSequence().format());
+			item.setText(VIEW_CONTEXT_COLUMN_INDEX, contextName);
+			item.setData(BINDING_KEY, binding);
+		}
+
+		// Pack the columns.
+		for (int i = 0; i < tableBindings.getColumnCount(); i++) {
+			tableBindings.getColumn(i).pack();
+		}
+	}
+
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/KeysPreferencePage.properties b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/KeysPreferencePage.properties
new file mode 100644
index 0000000..9dbc671
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/KeysPreferencePage.properties
@@ -0,0 +1,62 @@
+###############################################################################
+# Copyright (c) 2000, 2007 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
+###############################################################################
+
+advancedTab.Text=Ad&vanced
+modifyTab.Text=M&odify
+viewTab.Text=V&iew
+buttonAdd=Add
+buttonAddKey.ToolTipText=Insert Special Key
+buttonEdit=Edi&t
+buttonExport=E&xport...
+buttonRemove=&Remove
+buttonRestore=R&estore
+checkBoxMultiKeyAssist.Text=&Help Me With Multi-Stroke Keyboard Shortcuts
+checkBoxMultiKeyAssist.ToolTipText=Display a little assistant if you pause while entering a multi-stroke keyboard shortcut
+commandConflict=[conflict]
+commandNothing=[do nothing]
+commandUndefined=[undefined]
+csvFilterName=CSV Files (*.csv)
+exportErrorMessage=Failed to write to file:
+exportErrorTitle=Export Failed
+extends=(extends "{0}")
+extendsGeneral=(extends In General)
+extendsStandard=(extends Standard)
+general=In General
+groupCommand=Command
+groupKeySequence=Key Sequence
+labelAssignmentsForCommand=A&ssignments:
+labelAssignmentsForKeySequence=Assi&gnments:
+labelCategory=Ca&tegory:
+labelCommand=&Name:
+labelContext=&When:
+labelDescription=Description:
+labelScheme=S&cheme:
+labelKeySequence=Na&me:
+now=(now: {0})
+other=Other
+restoreDefaultsMessageBoxMessage=This will restore all keys to the default settings.\r\nAre you sure you want to do this?
+restoreDefaultsMessageBoxText=Restore Keyboard Defaults
+standard=Standard
+tableColumnCategory=Category
+tableColumnCategorySorted=>Category<
+tableColumnCommand=Command
+tableColumnCommandSorted=>Command<
+tableColumnContext=When
+tableColumnContextSorted=>When<
+tableColumnKeySequence=Key Sequence
+tableColumnKeySequenceSorted=>Key Sequence<
+textMultiKeyAssistTime.ErrorMessage=Delay time must be an integer value greater than zero
+textMultiKeyAssistTime.Text=Dela&y (milliseconds):
+uniqueName={0} ({1})
+was=(was: {0})
+
+PreferenceStoreError.Title=Error
+PreferenceStoreError.Message=Could not access the preference store
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/LegacySchemeListenerWrapper.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/LegacySchemeListenerWrapper.java
new file mode 100644
index 0000000..2384600
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/LegacySchemeListenerWrapper.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.keys;
+
+import org.eclipse.jface.bindings.BindingManager;
+import org.eclipse.jface.bindings.ISchemeListener;
+import org.eclipse.jface.bindings.SchemeEvent;
+import org.eclipse.ui.commands.IKeyConfiguration;
+import org.eclipse.ui.commands.IKeyConfigurationListener;
+import org.eclipse.ui.commands.KeyConfigurationEvent;
+
+/**
+ * A wrapper for old-style listeners to be hooked on to new style schemes.
+ *
+ * @since 3.1
+ */
+final class LegacySchemeListenerWrapper implements ISchemeListener {
+
+	/**
+	 * The binding manager; never <code>null</code>.
+	 */
+	private final BindingManager bindingManager;
+
+	/**
+	 * The listener that is being wrapped. This value is never <code>null</code>.
+	 */
+	private final IKeyConfigurationListener listener;
+
+	/**
+	 * Constructs a new instance of <code>SchemeListenerWrapper</code> with
+	 * the given listener.
+	 *
+	 * @param listener
+	 *            The listener to be wrapped; must mot be <code>null</code>.
+	 */
+	LegacySchemeListenerWrapper(final IKeyConfigurationListener listener,
+			final BindingManager bindingManager) {
+		if (listener == null) {
+			throw new NullPointerException("Cannot wrap a null listener"); //$NON-NLS-1$
+		}
+
+		if (bindingManager == null) {
+			throw new NullPointerException(
+					"Cannot wrap a listener without a binding manager"); //$NON-NLS-1$
+		}
+
+		this.listener = listener;
+		this.bindingManager = bindingManager;
+	}
+
+	@Override
+	public final boolean equals(final Object object) {
+		if (object instanceof LegacySchemeListenerWrapper) {
+			final LegacySchemeListenerWrapper wrapper = (LegacySchemeListenerWrapper) object;
+			return listener.equals(wrapper.listener);
+		}
+
+		if (object instanceof IKeyConfigurationListener) {
+			final IKeyConfigurationListener other = (IKeyConfigurationListener) object;
+			return listener.equals(other);
+		}
+
+		return false;
+	}
+
+	@Override
+	public final int hashCode() {
+		return listener.hashCode();
+	}
+
+	@Override
+	public final void schemeChanged(final SchemeEvent schemeEvent) {
+		final IKeyConfiguration keyConfiguration = new SchemeLegacyWrapper(
+				schemeEvent.getScheme(), bindingManager);
+		final boolean definedChanged = schemeEvent.isDefinedChanged();
+		final boolean nameChanged = schemeEvent.isNameChanged();
+		final boolean parentIdChanged = schemeEvent.isParentIdChanged();
+
+		listener.keyConfigurationChanged(new KeyConfigurationEvent(
+				keyConfiguration, false, definedChanged, nameChanged,
+				parentIdChanged));
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/MacKeyFormatter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/MacKeyFormatter.java
new file mode 100644
index 0000000..cc49c5e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/MacKeyFormatter.java
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2014 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.ui.internal.keys;
+
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.ResourceBundle;
+
+import org.eclipse.ui.internal.util.Util;
+import org.eclipse.ui.keys.CharacterKey;
+import org.eclipse.ui.keys.Key;
+import org.eclipse.ui.keys.KeySequence;
+import org.eclipse.ui.keys.ModifierKey;
+import org.eclipse.ui.keys.SpecialKey;
+
+public final class MacKeyFormatter extends AbstractKeyFormatter {
+
+    private final static class MacModifierKeyComparator extends
+            AbstractModifierKeyComparator {
+
+        @Override
+		protected int rank(ModifierKey modifierKey) {
+            if (ModifierKey.SHIFT.equals(modifierKey)) {
+                return 0;
+            }
+
+            if (ModifierKey.CTRL.equals(modifierKey)) {
+                return 1;
+            }
+
+            if (ModifierKey.ALT.equals(modifierKey)) {
+                return 2;
+            }
+
+            if (ModifierKey.COMMAND.equals(modifierKey)) {
+                return 3;
+            }
+
+            return Integer.MAX_VALUE;
+        }
+    }
+
+    private final static HashMap KEY_LOOKUP = new HashMap();
+
+    private final static Comparator MODIFIER_KEY_COMPARATOR = new MacModifierKeyComparator();
+
+    private final static ResourceBundle RESOURCE_BUNDLE = ResourceBundle
+            .getBundle(MacKeyFormatter.class.getName());
+
+    static {
+        KEY_LOOKUP
+                .put(CharacterKey.BS.toString(), "\u232B");  //$NON-NLS-1$
+        KEY_LOOKUP
+                .put(CharacterKey.CR.toString(), "\u21A9");  //$NON-NLS-1$
+        KEY_LOOKUP.put(CharacterKey.DEL.toString(), "\u2326");  //$NON-NLS-1$
+        KEY_LOOKUP.put(CharacterKey.SPACE.toString(), "\u2423");  //$NON-NLS-1$
+        KEY_LOOKUP
+                .put(ModifierKey.ALT.toString(), "\u2325");  //$NON-NLS-1$
+        KEY_LOOKUP.put(ModifierKey.COMMAND.toString(), "\u2318");  //$NON-NLS-1$
+        KEY_LOOKUP.put(ModifierKey.CTRL.toString(), "\u2303");  //$NON-NLS-1$
+        KEY_LOOKUP.put(ModifierKey.SHIFT.toString(), "\u21E7");  //$NON-NLS-1$
+        KEY_LOOKUP.put(SpecialKey.ARROW_DOWN.toString(), "\u2193");  //$NON-NLS-1$
+        KEY_LOOKUP.put(SpecialKey.ARROW_LEFT.toString(), "\u2190");  //$NON-NLS-1$
+        KEY_LOOKUP.put(SpecialKey.ARROW_RIGHT.toString(), "\u2192");  //$NON-NLS-1$
+        KEY_LOOKUP.put(SpecialKey.ARROW_UP.toString(), "\u2191");  //$NON-NLS-1$
+        KEY_LOOKUP.put(SpecialKey.END.toString(), "\u2198");  //$NON-NLS-1$
+        KEY_LOOKUP.put(SpecialKey.NUMPAD_ENTER.toString(), "\u2324");  //$NON-NLS-1$
+        KEY_LOOKUP
+                .put(SpecialKey.HOME.toString(), "\u2196");  //$NON-NLS-1$
+        KEY_LOOKUP.put(SpecialKey.PAGE_DOWN.toString(), "\u21DF");  //$NON-NLS-1$
+        KEY_LOOKUP.put(SpecialKey.PAGE_UP.toString(), "\u21DE");  //$NON-NLS-1$
+    }
+
+    @Override
+	public String format(Key key) {
+        String string = (String) KEY_LOOKUP.get(key.toString());
+        return string != null ? string : super.format(key);
+    }
+
+    @Override
+	protected String getKeyDelimiter() {
+        return Util.translateString(RESOURCE_BUNDLE, KEY_DELIMITER_KEY,
+                Util.ZERO_LENGTH_STRING, false, false);
+    }
+
+    @Override
+	protected String getKeyStrokeDelimiter() {
+        return Util.translateString(RESOURCE_BUNDLE, KEY_STROKE_DELIMITER_KEY,
+                KeySequence.KEY_STROKE_DELIMITER, false, false);
+    }
+
+    @Override
+	protected Comparator getModifierKeyComparator() {
+        return MODIFIER_KEY_COMPARATOR;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/MacKeyFormatter.properties b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/MacKeyFormatter.properties
new file mode 100644
index 0000000..e78770b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/MacKeyFormatter.properties
@@ -0,0 +1,10 @@
+###############################################################################
+# Copyright (c) 2000, 2006 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
+###############################################################################
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/NativeKeyFormatter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/NativeKeyFormatter.java
new file mode 100644
index 0000000..64ff46c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/NativeKeyFormatter.java
@@ -0,0 +1,142 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.keys;
+
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.ResourceBundle;
+
+import org.eclipse.ui.internal.util.Util;
+import org.eclipse.ui.keys.CharacterKey;
+import org.eclipse.ui.keys.Key;
+import org.eclipse.ui.keys.KeySequence;
+import org.eclipse.ui.keys.KeyStroke;
+import org.eclipse.ui.keys.ModifierKey;
+import org.eclipse.ui.keys.SpecialKey;
+
+/**
+ * Formats the key sequences and key strokes into the native human-readable
+ * format. This is typically what you would see on the menus for the given
+ * platform and locale.
+ *
+ * @since 3.0
+ */
+public class NativeKeyFormatter extends AbstractKeyFormatter {
+
+    /**
+     * The key into the internationalization resource bundle for the delimiter
+     * to use between keys (on the Carbon platform).
+     */
+    private final static String CARBON_KEY_DELIMITER_KEY = "CARBON_KEY_DELIMITER"; //$NON-NLS-1$
+
+    /**
+     * A look-up table for the string representations of various carbon keys.
+     */
+    private final static HashMap CARBON_KEY_LOOK_UP = new HashMap();
+
+    /**
+     * A comparator to sort modifier keys in the order that they would be
+     * displayed to a user. This comparator is platform-specific.
+     */
+    private final static Comparator MODIFIER_KEY_COMPARATOR = new NativeModifierKeyComparator();
+
+    /**
+     * The resource bundle used by <code>format()</code> to translate formal
+     * string representations by locale.
+     */
+    private final static ResourceBundle RESOURCE_BUNDLE;
+
+    /**
+     * The key into the internationalization resource bundle for the delimiter
+     * to use between key strokes (on the Win32 platform).
+     */
+    private final static String WIN32_KEY_STROKE_DELIMITER_KEY = "WIN32_KEY_STROKE_DELIMITER"; //$NON-NLS-1$
+
+    static {
+        RESOURCE_BUNDLE = ResourceBundle.getBundle(NativeKeyFormatter.class
+                .getName());
+
+        CARBON_KEY_LOOK_UP.put(CharacterKey.BS.toString(), "\u232B");  //$NON-NLS-1$
+        CARBON_KEY_LOOK_UP.put(CharacterKey.CR.toString(), "\u21A9");  //$NON-NLS-1$
+        CARBON_KEY_LOOK_UP.put(CharacterKey.DEL.toString(), "\u2326");  //$NON-NLS-1$
+        CARBON_KEY_LOOK_UP.put(CharacterKey.SPACE.toString(), "\u2423");  //$NON-NLS-1$
+        CARBON_KEY_LOOK_UP.put(ModifierKey.ALT.toString(), "\u2325");  //$NON-NLS-1$
+        CARBON_KEY_LOOK_UP.put(ModifierKey.COMMAND.toString(), "\u2318");  //$NON-NLS-1$
+        CARBON_KEY_LOOK_UP.put(ModifierKey.CTRL.toString(), "\u2303");  //$NON-NLS-1$
+        CARBON_KEY_LOOK_UP.put(ModifierKey.SHIFT.toString(), "\u21E7");  //$NON-NLS-1$
+        CARBON_KEY_LOOK_UP.put(SpecialKey.ARROW_DOWN.toString(), "\u2193");  //$NON-NLS-1$
+        CARBON_KEY_LOOK_UP.put(SpecialKey.ARROW_LEFT.toString(), "\u2190");  //$NON-NLS-1$
+        CARBON_KEY_LOOK_UP.put(SpecialKey.ARROW_RIGHT.toString(), "\u2192");  //$NON-NLS-1$
+        CARBON_KEY_LOOK_UP.put(SpecialKey.ARROW_UP.toString(), "\u2191");  //$NON-NLS-1$
+        CARBON_KEY_LOOK_UP.put(SpecialKey.END.toString(), "\u2198");  //$NON-NLS-1$
+        CARBON_KEY_LOOK_UP.put(SpecialKey.NUMPAD_ENTER.toString(), "\u2324");  //$NON-NLS-1$
+        CARBON_KEY_LOOK_UP.put(SpecialKey.HOME.toString(), "\u2196");  //$NON-NLS-1$
+        CARBON_KEY_LOOK_UP.put(SpecialKey.PAGE_DOWN.toString(), "\u21DF");  //$NON-NLS-1$
+        CARBON_KEY_LOOK_UP.put(SpecialKey.PAGE_UP.toString(), "\u21DE");  //$NON-NLS-1$
+    }
+
+    /**
+     * Formats an individual key into a human readable format. This uses an
+     * internationalization resource bundle to look up the key. This does the
+     * platform-specific formatting for Carbon.
+     *
+     * @param key
+     *            The key to format; must not be <code>null</code>.
+     * @return The key formatted as a string; should not be <code>null</code>.
+     */
+    @Override
+	public String format(Key key) {
+        String name = key.toString();
+
+        // TODO consider platform-specific resource bundles
+        if (org.eclipse.jface.util.Util.isMac()) {
+            String formattedName = (String) CARBON_KEY_LOOK_UP.get(name);
+            if (formattedName != null) {
+                return formattedName;
+            }
+        }
+
+        return super.format(key);
+    }
+
+    @Override
+	protected String getKeyDelimiter() {
+        // We must do the look up every time, as our locale might change.
+        if (org.eclipse.jface.util.Util.isMac()) {
+            return Util.translateString(RESOURCE_BUNDLE,
+                    CARBON_KEY_DELIMITER_KEY, Util.ZERO_LENGTH_STRING, false,
+                    false);
+        } else {
+            return Util.translateString(RESOURCE_BUNDLE, KEY_DELIMITER_KEY,
+                    KeyStroke.KEY_DELIMITER, false, false);
+        }
+    }
+
+    @Override
+	protected String getKeyStrokeDelimiter() {
+        // We must do the look up every time, as our locale might change.
+        if (org.eclipse.jface.util.Util.isWindows()) {
+            return Util.translateString(RESOURCE_BUNDLE,
+                    WIN32_KEY_STROKE_DELIMITER_KEY,
+                    KeySequence.KEY_STROKE_DELIMITER, false, false);
+        } else {
+            return Util.translateString(RESOURCE_BUNDLE,
+                    KEY_STROKE_DELIMITER_KEY, KeySequence.KEY_STROKE_DELIMITER,
+                    false, false);
+        }
+    }
+
+    @Override
+	protected Comparator getModifierKeyComparator() {
+        return MODIFIER_KEY_COMPARATOR;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/NativeKeyFormatter.properties b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/NativeKeyFormatter.properties
new file mode 100644
index 0000000..bec9647
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/NativeKeyFormatter.properties
@@ -0,0 +1,14 @@
+###############################################################################
+# Copyright (c) 2000, 2013 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
+###############################################################################
+
+KEY_DELIMITER=+
+CARBON_KEY_DELIMITER=
+WIN32_KEY_STROKE_DELIMITER=, 
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/NativeModifierKeyComparator.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/NativeModifierKeyComparator.java
new file mode 100644
index 0000000..4156a7d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/NativeModifierKeyComparator.java
@@ -0,0 +1,182 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.keys;
+
+import java.util.Comparator;
+
+import org.eclipse.jface.util.Util;
+import org.eclipse.ui.keys.ModifierKey;
+
+/**
+ * A comparator that sorts the modifier keys based on the native environment.
+ * Currently, this is only the windowing toolkit, but in the future it might
+ * expand to include the window manager.
+ *
+ * @since 3.0
+ */
+class NativeModifierKeyComparator implements Comparator {
+
+    /**
+     * The sort order value to use when the modifier key is not recognized.
+     */
+    private final static int UNKNOWN_KEY = Integer.MAX_VALUE;
+
+    @Override
+	public int compare(Object left, Object right) {
+        ModifierKey modifierKeyLeft = (ModifierKey) left;
+        ModifierKey modifierKeyRight = (ModifierKey) right;
+        int modifierKeyLeftRank = rank(modifierKeyLeft);
+        int modifierKeyRightRank = rank(modifierKeyRight);
+
+        if (modifierKeyLeftRank != modifierKeyRightRank) {
+            return modifierKeyLeftRank - modifierKeyRightRank;
+        } else {
+            return modifierKeyLeft.compareTo(modifierKeyRight);
+        }
+    }
+
+    /**
+     * Calculates a rank for a given modifier key.
+     *
+     * @param modifierKey
+     *            The modifier key to rank; may be <code>null</code>.
+     * @return The rank of this modifier key. This is a non-negative number
+     *         where a lower number suggests a higher rank.
+     */
+    private int rank(ModifierKey modifierKey) {
+
+        if (Util.isWindows()) {
+            return rankWindows(modifierKey);
+        }
+
+        if (Util.isGtk()) {
+            // TODO Do a look-up on window manager.
+            return rankGNOME(modifierKey);
+        }
+
+        if (Util.isMac()) {
+            return rankMacOSX(modifierKey);
+        }
+
+        if (Util.isMotif()) {
+            // TODO Do a look-up on window manager.
+            return rankGNOME(modifierKey);
+        }
+
+        return UNKNOWN_KEY;
+    }
+
+    /**
+     * Provides a ranking for the modifier key based on the modifier key
+     * ordering used in the GNOME window manager.
+     *
+     * @param modifierKey
+     *            The modifier key to rank; may be <code>null</code>.
+     * @return The rank of this modifier key. This is a non-negative number
+     *         where a lower number suggests a higher rank.
+     */
+    private final int rankGNOME(ModifierKey modifierKey) {
+        if (ModifierKey.SHIFT.equals(modifierKey)) {
+            return 0;
+        }
+
+        if (ModifierKey.CTRL.equals(modifierKey)) {
+            return 1;
+        }
+
+        if (ModifierKey.ALT.equals(modifierKey)) {
+            return 2;
+        }
+
+        return UNKNOWN_KEY;
+
+    }
+
+    /**
+     * Provides a ranking for the modifier key based on the modifier key
+     * ordering used in the KDE window manager.
+     *
+     * @param modifierKey
+     *            The modifier key to rank; may be <code>null</code>.
+     * @return The rank of this modifier key. This is a non-negative number
+     *         where a lower number suggests a higher rank.
+     */
+//    private final int rankKDE(ModifierKey modifierKey) {
+//        if (ModifierKey.ALT.equals(modifierKey)) {
+//            return 0;
+//        }
+//
+//        if (ModifierKey.CTRL.equals(modifierKey)) {
+//            return 1;
+//        }
+//
+//        if (ModifierKey.SHIFT.equals(modifierKey)) {
+//            return 2;
+//        }
+//
+//        return UNKNOWN_KEY;
+//    }
+
+    /**
+     * Provides a ranking for the modifier key based on the modifier key
+     * ordering used in the MacOS X operating system.
+     *
+     * @param modifierKey
+     *            The modifier key to rank; may be <code>null</code>.
+     * @return The rank of this modifier key. This is a non-negative number
+     *         where a lower number suggests a higher rank.
+     */
+    private final int rankMacOSX(ModifierKey modifierKey) {
+        if (ModifierKey.SHIFT.equals(modifierKey)) {
+            return 0;
+        }
+
+        if (ModifierKey.CTRL.equals(modifierKey)) {
+            return 1;
+        }
+
+        if (ModifierKey.ALT.equals(modifierKey)) {
+            return 2;
+        }
+
+        if (ModifierKey.COMMAND.equals(modifierKey)) {
+            return 3;
+        }
+
+        return UNKNOWN_KEY;
+    }
+
+    /**
+     * Provides a ranking for the modifier key based on the modifier key
+     * ordering used in the Windows operating system.
+     *
+     * @param modifierKey
+     *            The modifier key to rank; may be <code>null</code>.
+     * @return The rank of this modifier key. This is a non-negative number
+     *         where a lower number suggests a higher rank.
+     */
+    private final int rankWindows(ModifierKey modifierKey) {
+        if (ModifierKey.CTRL.equals(modifierKey)) {
+            return 0;
+        }
+
+        if (ModifierKey.ALT.equals(modifierKey)) {
+            return 1;
+        }
+
+        if (ModifierKey.SHIFT.equals(modifierKey)) {
+            return 2;
+        }
+
+        return UNKNOWN_KEY;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/NewKeysPreferenceMessages.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/NewKeysPreferenceMessages.java
new file mode 100644
index 0000000..28e3ff5
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/NewKeysPreferenceMessages.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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
+ *     Remy Chi Jian Suen <remy.suen@gmail.com> - Bug 186522 - [KeyBindings] New Keys preference page does not resort by binding with conflicts
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.keys;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * Messages used in the New Keys Preference page.
+ *
+ * @since 3.2
+ *
+ */
+public class NewKeysPreferenceMessages extends NLS {
+	private static final String BUNDLE_NAME = "org.eclipse.ui.internal.keys.NewKeysPreferencePage";//$NON-NLS-1$
+
+	public static String AddBindingButton_Text;
+	public static String AddKeyButton_ToolTipText;
+	public static String FiltersButton_Text;
+	public static String ExportButton_Text;
+	public static String BindingLabel_Text;
+	public static String CommandNameColumn_Text;
+	public static String CategoryColumn_Text;
+	public static String UserColumn_Text;
+	public static String CommandNameLabel_Text;
+	public static String CommandDescriptionLabel_Text;
+	public static String DeleteSchemeButton_Text;
+	public static String ConflictsLabel_Text;
+	public static String RemoveBindingButton_Text;
+	public static String RestoreBindingButton_Text;
+	public static String SchemeLabel_Text;
+	public static String TriggerSequenceColumn_Text;
+	public static String WhenColumn_Text;
+	public static String WhenLabel_Text;
+	public static String Asterisk_Text;
+
+	public static String GroupingCombo_Label;
+	public static String GroupingCombo_Category_Text;
+	public static String GroupingCombo_None_Text;
+	public static String GroupingCombo_When_Text;
+
+	public static String PreferenceStoreError_Message;
+	public static String PreferenceStoreError_Title;
+
+	public static String RestoreDefaultsMessageBoxText;
+	public static String RestoreDefaultsMessageBoxMessage;
+
+	public static String Undefined_Command;
+	public static String Unavailable_Category;
+	public static String Undefined_Context;
+
+	public static String KeysPreferenceFilterDialog_Title;
+	public static String ActionSetFilterCheckBox_Text;
+	public static String InternalFilterCheckBox_Text;
+	public static String UncategorizedFilterCheckBox_Text;
+
+	static {
+		// load message values from bundle file
+		NLS.initializeMessages(BUNDLE_NAME, NewKeysPreferenceMessages.class);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/NewKeysPreferencePage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/NewKeysPreferencePage.java
new file mode 100644
index 0000000..07faf05
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/NewKeysPreferencePage.java
@@ -0,0 +1,1236 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2016 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
+ *     Remy Chi Jian Suen <remy.suen@gmail.com> -
+ *     		Bug 186522 - [KeyBindings] New Keys preference page does not resort by binding with conflicts
+ *     		Bug 226342 - [KeyBindings] Keys preference page conflict table is hard to read
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 440810, 491393
+ *     Cornel Izbasa <cizbasa@info.uvt.ro> - Bug 442215
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.keys;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Map;
+
+import org.eclipse.core.commands.Category;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.commands.util.Tracing;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.bindings.Binding;
+import org.eclipse.jface.bindings.TriggerSequence;
+import org.eclipse.jface.bindings.keys.KeySequence;
+import org.eclipse.jface.bindings.keys.KeySequenceText;
+import org.eclipse.jface.bindings.keys.KeyStroke;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.jface.resource.DeviceResourceException;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.viewers.ColumnWeightData;
+import org.eclipse.jface.viewers.ComboViewer;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableLayout;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.FontMetrics;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeColumn;
+import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.commands.ICommandImageService;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.dialogs.FilteredTree;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.keys.model.BindingElement;
+import org.eclipse.ui.internal.keys.model.BindingModel;
+import org.eclipse.ui.internal.keys.model.CommonModel;
+import org.eclipse.ui.internal.keys.model.ConflictModel;
+import org.eclipse.ui.internal.keys.model.ContextElement;
+import org.eclipse.ui.internal.keys.model.ContextModel;
+import org.eclipse.ui.internal.keys.model.KeyController;
+import org.eclipse.ui.internal.keys.model.ModelElement;
+import org.eclipse.ui.internal.keys.model.SchemeElement;
+import org.eclipse.ui.internal.keys.model.SchemeModel;
+import org.eclipse.ui.internal.misc.Policy;
+import org.eclipse.ui.internal.util.Util;
+import org.eclipse.ui.keys.IBindingService;
+
+/**
+ * <p>
+ * A preference page that is capable of displaying and editing the bindings
+ * between commands and user input events. These are typically things like
+ * keyboard shortcuts.
+ * </p>
+ * <p>
+ * This preference page has four general types of methods. Create methods are
+ * called when the page is first made visible. They are responsible for creating
+ * all of the widgets, and laying them out within the preference page. Fill
+ * methods populate the contents of the widgets that contain collections of data
+ * from which items can be selected. The select methods respond to selection
+ * events from the user, such as a button press or a table selection. The update
+ * methods update the contents of various widgets based on the current state of
+ * the user interface. For example, the command name label will always try to
+ * match the current select in the binding table.
+ * </p>
+ * <p>
+ * Updated in 3.4 to work with a model backed by the real KeyBinding and
+ * ParameterizedCommand objects.
+ * </p>
+ *
+ * @since 3.2
+ */
+public class NewKeysPreferencePage extends PreferencePage implements IWorkbenchPreferencePage {
+
+	private static boolean DEBUG = Policy.DEBUG_KEY_BINDINGS;
+
+	private static final String TRACING_COMPONENT = "NewKeysPref"; //$NON-NLS-1$
+
+	public final static String TAG_DIALOG_SECTION = "org.eclipse.ui.preferences.keysPreferencePage"; //$NON-NLS-1$
+
+	private static final String TAG_FILTER_ACTION_SETS = "actionSetFilter"; //$NON-NLS-1$
+
+	private static final String TAG_FILTER_INTERNAL = "internalFilter"; //$NON-NLS-1$
+
+	private static final String TAG_FILTER_UNCAT = "uncategorizedFilter"; //$NON-NLS-1$
+
+	/**
+	 * The number of items to show in the bindings table tree.
+	 */
+	private static final int ITEMS_TO_SHOW = 12;
+
+	private static final int COMMAND_NAME_COLUMN = 0;
+	private static final int KEY_SEQUENCE_COLUMN = 1;
+	private static final int CONTEXT_COLUMN = 2;
+	private static final int CATEGORY_COLUMN = 3;
+	private static final int USER_DELTA_COLUMN = 4;
+	private static int NUM_OF_COLUMNS = USER_DELTA_COLUMN + 1;
+
+	private ComboViewer fSchemeCombo;
+
+	private CategoryPatternFilter fPatternFilter;
+
+	private CategoryFilterTree fFilteredTree;
+
+	private boolean fFilterActionSetContexts = true;
+
+	private boolean fFilterInternalContexts = true;
+
+	private KeyController keyController;
+
+	private Category fDefaultCategory;
+
+	private Label commandNameValueLabel;
+
+	private Text fBindingText;
+
+	private Text fDescriptionText;
+
+	private ComboViewer fWhenCombo;
+
+	private IBindingService fBindingService;
+
+	private KeySequenceText fKeySequenceText;
+
+	private TableViewer conflictViewer;
+
+	private ICommandImageService commandImageService;
+
+	private ICommandService commandService;
+
+	/**
+	 * A FilteredTree that provides a combo which is used to organize and
+	 * display elements in the tree according to the selected criteria.
+	 *
+	 */
+	protected class CategoryFilterTree extends FilteredTree {
+
+		private CategoryPatternFilter filter;
+
+		/**
+		 * Constructor for PatternFilteredTree.
+		 *
+		 * @param parent
+		 * @param treeStyle
+		 * @param filter
+		 */
+		protected CategoryFilterTree(Composite parent, int treeStyle, CategoryPatternFilter filter) {
+			super(parent, treeStyle, filter, true);
+			this.filter = filter;
+			setQuickSelectionMode(true);
+		}
+
+		public void filterCategories(boolean b) {
+			filter.filterCategories(b);
+			textChanged();
+		}
+
+		public boolean isFilteringCategories() {
+			return filter.isFilteringCategories();
+		}
+	}
+
+	private final class BindingModelComparator extends ViewerComparator {
+		private LinkedList<Integer> sortColumns = new LinkedList<>();
+		private boolean ascending = true;
+
+		public BindingModelComparator() {
+			for (int i = 0; i < NUM_OF_COLUMNS; i++) {
+				sortColumns.add(Integer.valueOf(i));
+			}
+		}
+
+		public int getSortColumn() {
+			return sortColumns.getFirst().intValue();
+		}
+
+		public void setSortColumn(int column) {
+			if (column == getSortColumn()) {
+				return;
+			}
+			Integer sortColumn = Integer.valueOf(column);
+			sortColumns.remove(sortColumn);
+			sortColumns.addFirst(sortColumn);
+		}
+
+		/**
+		 * @return Returns the ascending.
+		 */
+		public boolean isAscending() {
+			return ascending;
+		}
+
+		/**
+		 * @param ascending
+		 *            The ascending to set.
+		 */
+		public void setAscending(boolean ascending) {
+			this.ascending = ascending;
+		}
+
+		@Override
+		public final int compare(final Viewer viewer, final Object a,
+				final Object b) {
+			int result = 0;
+			Iterator<Integer> i = sortColumns.iterator();
+			while (i.hasNext() && result == 0) {
+				int column = i.next().intValue();
+				result = compareColumn(viewer, a, b, column);
+			}
+			return ascending ? result : (-1) * result;
+		}
+
+		private int compareColumn(final Viewer viewer, final Object a,
+				final Object b, final int columnNumber) {
+			if (columnNumber == USER_DELTA_COLUMN) {
+				return sortUser(a, b);
+			}
+			IBaseLabelProvider baseLabel = ((TreeViewer) viewer).getLabelProvider();
+			if (baseLabel instanceof ITableLabelProvider) {
+				ITableLabelProvider tableProvider = (ITableLabelProvider) baseLabel;
+				String e1p = tableProvider.getColumnText(a, columnNumber);
+				String e2p = tableProvider.getColumnText(b, columnNumber);
+				if (e1p != null && e2p != null) {
+					return getComparator().compare(e1p, e2p);
+				}
+			}
+			return 0;
+		}
+
+		private int sortUser(final Object a, final Object b) {
+			int typeA = ((BindingElement) a).getUserDelta().intValue();
+			int typeB = ((BindingElement) b).getUserDelta().intValue();
+			int result = typeA - typeB;
+			return result;
+		}
+
+	}
+
+	private final class ResortColumn extends SelectionAdapter {
+		private final BindingModelComparator comparator;
+		private final TreeColumn treeColumn;
+		private final TreeViewer viewer;
+		private final int column;
+
+		private ResortColumn(BindingModelComparator comparator, TreeColumn treeColumn, TreeViewer viewer, int column) {
+			this.comparator = comparator;
+			this.treeColumn = treeColumn;
+			this.viewer = viewer;
+			this.column = column;
+		}
+
+		@Override
+		public void widgetSelected(SelectionEvent e) {
+			if (comparator.getSortColumn() == column) {
+				comparator.setAscending(!comparator.isAscending());
+				viewer.getTree().setSortDirection(
+						comparator.isAscending() ? SWT.UP : SWT.DOWN);
+			} else {
+				viewer.getTree().setSortColumn(treeColumn);
+				comparator.setSortColumn(column);
+			}
+			try {
+				viewer.getTree().setRedraw(false);
+				viewer.refresh();
+			} finally {
+				viewer.getTree().setRedraw(true);
+			}
+		}
+	}
+
+	private static class ListLabelProvider extends LabelProvider {
+		@Override
+		public String getText(Object element) {
+			return ((ModelElement) element).getName();
+		}
+	}
+
+	private class BindingElementLabelProvider extends LabelProvider implements ITableLabelProvider {
+		/**
+		 * A resource manager for this preference page.
+		 */
+		private final LocalResourceManager localResourceManager = new LocalResourceManager(
+				JFaceResources.getResources());
+
+		@Override
+		public final void dispose() {
+			super.dispose();
+			localResourceManager.dispose();
+		}
+
+		@Override
+		public String getText(Object element) {
+			String rc = getColumnText(element, 0);
+			if (rc == null) {
+				rc = super.getText(element);
+			}
+			StringBuffer buf = new StringBuffer(rc);
+			for (int i = 1; i < USER_DELTA_COLUMN; i++) {
+				String text = getColumnText(element, i);
+				if (text != null) {
+					buf.append(' ');
+					buf.append(text);
+				}
+			}
+			return buf.toString();
+		}
+
+		@Override
+		public String getColumnText(Object element, int index) {
+			BindingElement bindingElement = ((BindingElement) element);
+			switch (index) {
+			case COMMAND_NAME_COLUMN: // name
+				return bindingElement.getName();
+			case KEY_SEQUENCE_COLUMN: // keys
+				TriggerSequence seq = bindingElement.getTrigger();
+				return seq == null ? Util.ZERO_LENGTH_STRING : seq.format();
+			case CONTEXT_COLUMN: // when
+				ModelElement context = bindingElement.getContext();
+				return context == null ? Util.ZERO_LENGTH_STRING : context
+						.getName();
+			case CATEGORY_COLUMN: // category
+				return bindingElement.getCategory();
+			case USER_DELTA_COLUMN: // user
+				if (bindingElement.getUserDelta().intValue() == Binding.USER) {
+					if (bindingElement.getConflict().equals(Boolean.TRUE)) {
+						return "CU"; //$NON-NLS-1$
+					}
+					return " U"; //$NON-NLS-1$
+				}
+				if (bindingElement.getConflict().equals(Boolean.TRUE)) {
+					return "C "; //$NON-NLS-1$
+				}
+				return "  "; //$NON-NLS-1$
+			}
+			return null;
+		}
+
+		@Override
+		public Image getColumnImage(Object element, int index) {
+			BindingElement be = (BindingElement) element;
+			switch (index) {
+			case COMMAND_NAME_COLUMN:
+				final String commandId = be.getId();
+				final ImageDescriptor imageDescriptor = commandImageService
+						.getImageDescriptor(commandId);
+				if (imageDescriptor == null) {
+					return null;
+				}
+				try {
+					return localResourceManager.createImage(imageDescriptor);
+				} catch (final DeviceResourceException e) {
+					final String message = "Problem retrieving image for a command '" //$NON-NLS-1$
+							+ commandId + '\'';
+					final IStatus status = new Status(IStatus.ERROR,
+							WorkbenchPlugin.PI_WORKBENCH, 0, message, e);
+					WorkbenchPlugin.log(message, status);
+				}
+				return null;
+
+			}
+
+			return null;
+		}
+	}
+
+	class ModelContentProvider implements ITreeContentProvider {
+		@Override
+		public Object[] getChildren(Object parentElement) {
+			if (parentElement instanceof BindingModel) {
+				return ((BindingModel) parentElement).getBindings().toArray();
+			}
+			if (parentElement instanceof ContextModel) {
+				return ((ContextModel) parentElement).getContexts().toArray();
+			}
+			if (parentElement instanceof SchemeModel) {
+				return ((SchemeModel) parentElement).getSchemes().toArray();
+			}
+			return new Object[0];
+		}
+
+		@Override
+		public Object getParent(Object element) {
+			return ((ModelElement) element).getParent();
+		}
+
+		@Override
+		public boolean hasChildren(Object element) {
+			return (element instanceof BindingModel) || (element instanceof ContextModel)
+					|| (element instanceof SchemeModel);
+		}
+
+		@Override
+		public Object[] getElements(Object inputElement) {
+			return getChildren(inputElement);
+		}
+		
+		@Override
+        public void dispose() {
+        }
+		
+		@Override
+        public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+        }
+
+	}
+
+	@Override
+	protected Control createContents(Composite parent) {
+		PlatformUI.getWorkbench().getHelpSystem().setHelp(parent, IWorkbenchHelpContextIds.KEYS_PREFERENCE_PAGE);
+		final Composite page = new Composite(parent, SWT.NONE);
+		GridLayout layout = new GridLayout(1, false);
+		layout.marginWidth = 0;
+		page.setLayout(layout);
+
+		IDialogSettings settings = getDialogSettings();
+
+		fPatternFilter = new CategoryPatternFilter(true, commandService.getCategory(null));
+		if (settings.get(TAG_FILTER_UNCAT) != null) {
+			fPatternFilter.filterCategories(settings.getBoolean(TAG_FILTER_UNCAT));
+		}
+
+		createSchemeControls(page);
+		createTree(page);
+		createTreeControls(page);
+		createDataControls(page);
+
+		fill();
+
+		applyDialogFont(page);
+
+		// we want the description text control to span four lines, but because
+		// we need the dialog's font for this information, we have to set it here
+		// after the dialog font has been applied
+		GC gc = new GC(fDescriptionText);
+		gc.setFont(fDescriptionText.getFont());
+		FontMetrics metrics = gc.getFontMetrics();
+		gc.dispose();
+		int height = metrics.getHeight() * 5 / 2;
+
+		GridData gridData = new GridData();
+		gridData.grabExcessHorizontalSpace = true;
+		gridData.horizontalAlignment = SWT.FILL;
+		gridData.horizontalSpan = 2;
+		gridData.heightHint = height;
+		fDescriptionText.setLayoutData(gridData);
+
+		return page;
+	}
+
+	/**
+	 * Creates the button bar with "Filters..." and "Export CVS..." buttons.
+	 *
+	 * @param parent
+	 *            The composite in which the button bar should be placed; never
+	 *            <code>null</code>.
+	 * @return The button bar composite; never <code>null</code>.
+	 */
+	private final Control createButtonBar(final Composite parent) {
+		GridLayout layout;
+		GridData gridData;
+		int widthHint;
+
+		// Create the composite to house the button bar.
+		final Composite buttonBar = new Composite(parent, SWT.NONE);
+		layout = new GridLayout(2, false);
+		layout.marginWidth = 0;
+		buttonBar.setLayout(layout);
+		gridData = new GridData();
+		gridData.horizontalAlignment = SWT.END;
+		gridData.grabExcessHorizontalSpace = true;
+		buttonBar.setLayoutData(gridData);
+
+		// Advanced button.
+		final Button filtersButton = new Button(buttonBar, SWT.PUSH);
+		gridData = new GridData();
+		widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
+		filtersButton.setText(NewKeysPreferenceMessages.FiltersButton_Text);
+		gridData.widthHint = Math.max(widthHint, filtersButton.computeSize(
+				SWT.DEFAULT, SWT.DEFAULT, true).x) + 5;
+		filtersButton.setLayoutData(gridData);
+		filtersButton.addSelectionListener(new SelectionAdapter()
+        {
+		    public void widgetSelected(SelectionEvent e) {
+		        KeysPreferenceFiltersDialog dialog = new KeysPreferenceFiltersDialog(getShell());
+	            dialog.setFilterActionSet(fFilterActionSetContexts);
+	            dialog.setFilterInternal(fFilterInternalContexts);
+	            dialog.setFilterUncategorized(fFilteredTree.isFilteringCategories());
+	            if (dialog.open() == Window.OK) {
+	                fFilterActionSetContexts = dialog.getFilterActionSet();
+	                fFilterInternalContexts = dialog.getFilterInternal();
+	                fFilteredTree.filterCategories(dialog.getFilterUncategorized());
+
+	                // Apply context filters
+	                keyController.filterContexts(fFilterActionSetContexts, fFilterInternalContexts);
+
+	                ISelection currentContextSelection = fWhenCombo.getSelection();
+	                fWhenCombo.setInput(keyController.getContextModel());
+	                fWhenCombo.setSelection(currentContextSelection);
+	            }
+		    }
+        });
+
+		// Export bindings to CSV
+		final Button exportButton = new Button(buttonBar, SWT.PUSH);
+		// gridData = new GridData();
+		widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
+		exportButton.setText(NewKeysPreferenceMessages.ExportButton_Text);
+		gridData.widthHint = Math.max(widthHint, exportButton.computeSize(
+				SWT.DEFAULT, SWT.DEFAULT, true).x) + 5;
+		exportButton.setLayoutData(gridData);
+		exportButton.addSelectionListener(new SelectionAdapter()
+        {
+		    public void widgetSelected(SelectionEvent e) {
+//		        keyController.exportCSV(((Button) e.getSource()).getShell());
+		    }
+        });
+
+		return buttonBar;
+	}
+
+	private final void createDataControls(final Composite parent) {
+		GridLayout layout;
+		GridData gridData;
+
+		// Creates the data area.
+		final Composite dataArea = new Composite(parent, SWT.NONE);
+		layout = new GridLayout(2, true);
+		layout.marginWidth = 0;
+		dataArea.setLayout(layout);
+		gridData = new GridData();
+		gridData.grabExcessHorizontalSpace = true;
+		gridData.horizontalAlignment = SWT.FILL;
+		dataArea.setLayoutData(gridData);
+
+		// LEFT DATA AREA
+		// Creates the left data area.
+		final Composite leftDataArea = new Composite(dataArea, SWT.NONE);
+		layout = new GridLayout(3, false);
+		leftDataArea.setLayout(layout);
+		gridData = new GridData();
+		gridData.grabExcessHorizontalSpace = true;
+		gridData.verticalAlignment = SWT.TOP;
+		gridData.horizontalAlignment = SWT.FILL;
+		leftDataArea.setLayoutData(gridData);
+
+		// The command name label.
+		final Label commandNameLabel = new Label(leftDataArea, SWT.NONE);
+		commandNameLabel
+				.setText(NewKeysPreferenceMessages.CommandNameLabel_Text);
+
+		// The current command name.
+		commandNameValueLabel = new Label(leftDataArea, SWT.NONE);
+		gridData = new GridData();
+		gridData.grabExcessHorizontalSpace = true;
+		gridData.horizontalSpan = 2;
+		gridData.horizontalAlignment = SWT.FILL;
+		commandNameValueLabel.setLayoutData(gridData);
+
+		final Label commandDescriptionlabel = new Label(leftDataArea, SWT.LEAD);
+		commandDescriptionlabel.setText(NewKeysPreferenceMessages.CommandDescriptionLabel_Text);
+		gridData = new GridData();
+		gridData.verticalAlignment = SWT.BEGINNING;
+		commandDescriptionlabel.setLayoutData(gridData);
+
+		fDescriptionText = new Text(leftDataArea, SWT.MULTI | SWT.WRAP
+				| SWT.BORDER | SWT.READ_ONLY);
+
+		// The binding label.
+		final Label bindingLabel = new Label(leftDataArea, SWT.NONE);
+		bindingLabel.setText(NewKeysPreferenceMessages.BindingLabel_Text);
+
+		// The key sequence entry widget.
+		fBindingText = new Text(leftDataArea, SWT.BORDER);
+		gridData = new GridData();
+		gridData.grabExcessHorizontalSpace = true;
+		gridData.horizontalAlignment = SWT.FILL;
+		gridData.widthHint = 200;
+		fBindingText.setLayoutData(gridData);
+
+		fBindingText.addFocusListener(new FocusListener() {
+			@Override
+			public void focusGained(FocusEvent e) {
+				fBindingService.setKeyFilterEnabled(false);
+			}
+
+			@Override
+			public void focusLost(FocusEvent e) {
+				fBindingService.setKeyFilterEnabled(true);
+			}
+		});
+		fBindingText.addDisposeListener(e -> {
+			if (!fBindingService.isKeyFilterEnabled()) {
+				fBindingService.setKeyFilterEnabled(true);
+			}
+		});
+
+		fKeySequenceText = new KeySequenceText(fBindingText);
+		fKeySequenceText.setKeyStrokeLimit(4);
+		fKeySequenceText
+				.addPropertyChangeListener(event -> {
+if (!event.getOldValue().equals(event.getNewValue())) {
+				final KeySequence keySequence = fKeySequenceText.getKeySequence();
+				if (!keySequence.isComplete()) {
+					return;
+				}
+
+				BindingElement activeBinding = (BindingElement) keyController.getBindingModel()
+						.getSelectedElement();
+				if (activeBinding != null) {
+					activeBinding.setTrigger(keySequence);
+				}
+				fBindingText.setSelection(fBindingText.getTextLimit());
+}
+});
+
+		// Button for adding trapped key strokes
+		final Button addKeyButton = new Button(leftDataArea, SWT.LEFT | SWT.ARROW);
+		addKeyButton
+				.setToolTipText(NewKeysPreferenceMessages.AddKeyButton_ToolTipText);
+		gridData = new GridData();
+		gridData.heightHint = fSchemeCombo.getCombo().getTextHeight();
+		addKeyButton.setLayoutData(gridData);
+
+		// Arrow buttons aren't normally added to the tab list. Let's fix that.
+		final Control[] tabStops = dataArea.getTabList();
+		final ArrayList<Control> newTabStops = new ArrayList<>();
+		for (Control tabStop : tabStops) {
+			newTabStops.add(tabStop);
+			if (fBindingText.equals(tabStop)) {
+				newTabStops.add(addKeyButton);
+			}
+		}
+		final Control[] newTabStopArray = newTabStops
+				.toArray(new Control[newTabStops.size()]);
+		dataArea.setTabList(newTabStopArray);
+
+		// Construct the menu to attach to the above button.
+		final Menu addKeyMenu = new Menu(addKeyButton);
+		final Iterator trappedKeyItr = KeySequenceText.TRAPPED_KEYS.iterator();
+		while (trappedKeyItr.hasNext()) {
+			final KeyStroke trappedKey = (KeyStroke) trappedKeyItr.next();
+			final MenuItem menuItem = new MenuItem(addKeyMenu, SWT.PUSH);
+			menuItem.setText(trappedKey.format());
+			menuItem.addSelectionListener(new SelectionAdapter()
+            {
+			    /** {@inheritDoc} */
+			    @Override
+			    public void widgetSelected(SelectionEvent e)
+			    {
+			        fKeySequenceText.insert(trappedKey);
+	                fBindingText.setFocus();
+	                fBindingText.setSelection(fBindingText.getTextLimit());
+			    }
+            });
+		}
+		addKeyButton.addSelectionListener(new SelectionAdapter()
+        {
+		    public void widgetSelected(SelectionEvent e) {
+		        Point buttonLocation = addKeyButton.getLocation();
+	            buttonLocation = dataArea.toDisplay(buttonLocation.x, buttonLocation.y);
+	            Point buttonSize = addKeyButton.getSize();
+	            addKeyMenu.setLocation(buttonLocation.x, buttonLocation.y + buttonSize.y);
+	            addKeyMenu.setVisible(true);
+		    }
+        });
+
+		// The when label.
+		final Label whenLabel = new Label(leftDataArea, SWT.NONE);
+		whenLabel.setText(NewKeysPreferenceMessages.WhenLabel_Text);
+
+		// The when combo.
+		fWhenCombo = new ComboViewer(leftDataArea);
+		gridData = new GridData();
+		gridData.grabExcessHorizontalSpace = true;
+		gridData.horizontalAlignment = SWT.FILL;
+		gridData.horizontalSpan = 2;
+		gridData.widthHint = 200;
+		ViewerComparator comparator = new ViewerComparator();
+		fWhenCombo.setComparator(comparator);
+		fWhenCombo.getCombo().setLayoutData(gridData);
+		fWhenCombo.setContentProvider(new ModelContentProvider());
+		fWhenCombo.setLabelProvider(new ListLabelProvider());
+		fWhenCombo.addSelectionChangedListener(event -> {
+			ContextElement context = (ContextElement) ((IStructuredSelection) event
+					.getSelection()).getFirstElement();
+			if (context != null) {
+				keyController.getContextModel().setSelectedElement(context);
+			}
+		});
+		IPropertyChangeListener whenListener = event -> {
+			if (event.getSource() == keyController.getContextModel()
+					&& CommonModel.PROP_SELECTED_ELEMENT.equals(event
+							.getProperty())) {
+				Object newVal = event.getNewValue();
+				StructuredSelection structuredSelection = newVal == null ? null
+						: new StructuredSelection(newVal);
+				fWhenCombo.setSelection(structuredSelection, true);
+			}
+		};
+		keyController.addPropertyChangeListener(whenListener);
+
+		// RIGHT DATA AREA
+		// Creates the right data area.
+		final Composite rightDataArea = new Composite(dataArea, SWT.NONE);
+		layout = new GridLayout(1, false);
+		rightDataArea.setLayout(layout);
+		gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
+		rightDataArea.setLayoutData(gridData);
+
+		new Label(rightDataArea, SWT.NONE); // filler
+
+		// The description label.
+		final Label descriptionLabel = new Label(rightDataArea, SWT.NONE);
+		descriptionLabel.setText(NewKeysPreferenceMessages.ConflictsLabel_Text);
+		gridData = new GridData();
+		gridData.grabExcessHorizontalSpace = true;
+		gridData.horizontalAlignment = SWT.FILL;
+		descriptionLabel.setLayoutData(gridData);
+
+		conflictViewer = new TableViewer(rightDataArea, SWT.SINGLE | SWT.V_SCROLL
+				| SWT.BORDER | SWT.FULL_SELECTION);
+		Table table = conflictViewer.getTable();
+		table.setHeaderVisible(true);
+		TableColumn bindingNameColumn = new TableColumn(table, SWT.LEAD);
+		bindingNameColumn.setText(NewKeysPreferenceMessages.CommandNameColumn_Text);
+		bindingNameColumn.setWidth(150);
+		TableColumn bindingContextNameColumn = new TableColumn(table, SWT.LEAD);
+		bindingContextNameColumn.setText(NewKeysPreferenceMessages.WhenColumn_Text);
+		bindingContextNameColumn.setWidth(150);
+		gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
+		//gridData.horizontalIndent = 10;
+		table.setLayoutData(gridData);
+		TableLayout tableLayout = new TableLayout();
+		tableLayout.addColumnData(new ColumnWeightData(60));
+		tableLayout.addColumnData(new ColumnWeightData(40));
+		table.setLayout(tableLayout);
+		conflictViewer.setContentProvider(new IStructuredContentProvider()
+        {
+            
+		    @Override
+            public Object[] getElements(Object inputElement) {
+                if (inputElement instanceof Collection) {
+                    return ((Collection) inputElement).toArray();
+                }
+                return new Object[0];
+            }
+            
+            @Override
+            public void dispose() {
+            }
+            
+            @Override
+            public void inputChanged(Viewer viewer, Object oldInput,
+                    Object newInput) {
+            }
+        });
+		conflictViewer.setLabelProvider(new BindingElementLabelProvider() {
+			@Override
+			public String getColumnText(Object o, int index) {
+				BindingElement element = (BindingElement) o;
+				if (index == 0) {
+					return element.getName();
+				}
+				return element.getContext().getName();
+			}
+		});
+		conflictViewer
+				.addSelectionChangedListener(event -> {
+					ModelElement binding = (ModelElement) ((IStructuredSelection) event.getSelection())
+							.getFirstElement();
+					BindingModel bindingModel = keyController
+							.getBindingModel();
+					if (binding != null
+							&& binding != bindingModel.getSelectedElement()) {
+						StructuredSelection selection = new StructuredSelection(
+								binding);
+
+						bindingModel.setSelectedElement(binding);
+						conflictViewer.setSelection(selection);
+
+						boolean selectionVisible = false;
+						TreeItem[] items = fFilteredTree.getViewer()
+								.getTree().getItems();
+						for (TreeItem item : items) {
+							if (item.getData().equals(binding)) {
+								selectionVisible = true;
+								break;
+							}
+						}
+
+						if (!selectionVisible) {
+							fFilteredTree.getFilterControl().setText(""); //$NON-NLS-1$
+							fFilteredTree.getViewer().refresh();
+							bindingModel.setSelectedElement(binding);
+							conflictViewer.setSelection(selection);
+						}
+					}
+				});
+
+		IPropertyChangeListener conflictsListener = event -> {
+			if (event.getSource() == keyController.getConflictModel()
+					&& CommonModel.PROP_SELECTED_ELEMENT.equals(event
+							.getProperty())) {
+				if (keyController.getConflictModel().getConflicts() != null) {
+					Object newVal = event.getNewValue();
+					StructuredSelection structuredSelection = newVal == null ? null
+							: new StructuredSelection(newVal);
+					conflictViewer.setSelection(structuredSelection, true);
+				}
+			} else if (ConflictModel.PROP_CONFLICTS.equals(event
+					.getProperty())) {
+				conflictViewer.setInput(event.getNewValue());
+			} else if (ConflictModel.PROP_CONFLICTS_ADD.equals(event
+					.getProperty())) {
+				conflictViewer.add(event.getNewValue());
+			} else if (ConflictModel.PROP_CONFLICTS_REMOVE.equals(event
+					.getProperty())) {
+				conflictViewer.remove(event.getNewValue());
+			}
+		};
+		keyController.addPropertyChangeListener(conflictsListener);
+
+		IPropertyChangeListener dataUpdateListener = event -> {
+			BindingElement bindingElement = null;
+			boolean weCare = false;
+			if (event.getSource() == keyController.getBindingModel()
+					&& CommonModel.PROP_SELECTED_ELEMENT.equals(event
+							.getProperty())) {
+				bindingElement = (BindingElement) event.getNewValue();
+				weCare = true;
+			} else if (event.getSource() == keyController.getBindingModel()
+					.getSelectedElement()
+					&& ModelElement.PROP_MODEL_OBJECT.equals(event
+							.getProperty())) {
+				bindingElement = (BindingElement) event.getSource();
+				weCare = true;
+			}
+			if (bindingElement == null && weCare) {
+				commandNameValueLabel.setText(""); //$NON-NLS-1$
+				fDescriptionText.setText(""); //$NON-NLS-1$
+				fBindingText.setText(""); //$NON-NLS-1$
+			} else if (bindingElement != null) {
+				commandNameValueLabel.setText(bindingElement.getName());
+				String desc = bindingElement.getDescription();
+				fDescriptionText.setText(desc==null?"":desc); //$NON-NLS-1$
+				KeySequence trigger = (KeySequence) bindingElement
+						.getTrigger();
+				fKeySequenceText.setKeySequence(trigger);
+			}
+		};
+		keyController.addPropertyChangeListener(dataUpdateListener);
+
+	}
+
+	private void createTree(Composite parent) {
+		fPatternFilter = new CategoryPatternFilter(true, fDefaultCategory);
+		fPatternFilter.filterCategories(true);
+
+		GridData gridData;
+
+		fFilteredTree = new CategoryFilterTree(parent, SWT.SINGLE | SWT.FULL_SELECTION | SWT.BORDER, fPatternFilter);
+		final GridLayout layout = new GridLayout(1, false);
+		layout.marginWidth = 0;
+		fFilteredTree.setLayout(layout);
+		gridData = new GridData();
+		gridData.grabExcessHorizontalSpace = true;
+		gridData.grabExcessVerticalSpace = true;
+		gridData.horizontalAlignment = SWT.FILL;
+		gridData.verticalAlignment = SWT.FILL;
+		fFilteredTree.setLayoutData(gridData);
+
+		final TreeViewer viewer = fFilteredTree.getViewer();
+		// Make sure the filtered tree has a height of ITEMS_TO_SHOW
+		final Tree tree = viewer.getTree();
+		tree.setHeaderVisible(true);
+		final Object layoutData = tree.getLayoutData();
+		if (layoutData instanceof GridData) {
+			gridData = (GridData) layoutData;
+			final int itemHeight = tree.getItemHeight();
+			if (itemHeight > 1) {
+				gridData.heightHint = ITEMS_TO_SHOW * itemHeight;
+			}
+		}
+
+		BindingModelComparator comparator = new BindingModelComparator();
+		viewer.setComparator(comparator);
+
+		final TreeColumn commandNameColumn = new TreeColumn(tree, SWT.LEFT, COMMAND_NAME_COLUMN);
+		commandNameColumn.setText(NewKeysPreferenceMessages.CommandNameColumn_Text);
+		tree.setSortColumn(commandNameColumn);
+		tree.setSortDirection(comparator.isAscending() ? SWT.UP : SWT.DOWN);
+		commandNameColumn
+				.addSelectionListener(new ResortColumn(comparator, commandNameColumn, viewer, COMMAND_NAME_COLUMN));
+
+		final TreeColumn triggerSequenceColumn = new TreeColumn(tree, SWT.LEFT, KEY_SEQUENCE_COLUMN);
+		triggerSequenceColumn
+				.setText(NewKeysPreferenceMessages.TriggerSequenceColumn_Text);
+		triggerSequenceColumn
+				.addSelectionListener(new ResortColumn(comparator, triggerSequenceColumn, viewer, KEY_SEQUENCE_COLUMN));
+
+		final TreeColumn whenColumn = new TreeColumn(tree, SWT.LEFT,
+				CONTEXT_COLUMN);
+		whenColumn.setText(NewKeysPreferenceMessages.WhenColumn_Text);
+		whenColumn.addSelectionListener(new ResortColumn(comparator,
+				whenColumn, viewer, CONTEXT_COLUMN));
+
+		final TreeColumn categoryColumn = new TreeColumn(tree, SWT.LEFT,
+				CATEGORY_COLUMN);
+		categoryColumn.setText(NewKeysPreferenceMessages.CategoryColumn_Text);
+		categoryColumn.addSelectionListener(new ResortColumn(comparator,
+				categoryColumn, viewer, CATEGORY_COLUMN));
+
+		final TreeColumn userMarker = new TreeColumn(tree, SWT.LEFT, USER_DELTA_COLUMN);
+		userMarker.setText(NewKeysPreferenceMessages.UserColumn_Text);
+		userMarker.addSelectionListener(new ResortColumn(comparator, userMarker, viewer, USER_DELTA_COLUMN));
+
+		viewer.setContentProvider(new ModelContentProvider());
+		viewer.setLabelProvider(new BindingElementLabelProvider());
+
+		fFilteredTree.getPatternFilter().setIncludeLeadingWildcard(true);
+		final TreeColumn[] columns = viewer.getTree().getColumns();
+
+		columns[COMMAND_NAME_COLUMN].setWidth(240);
+		columns[KEY_SEQUENCE_COLUMN].setWidth(130);
+		columns[CONTEXT_COLUMN].setWidth(130);
+		columns[CATEGORY_COLUMN].setWidth(130);
+		columns[USER_DELTA_COLUMN].setWidth(50);
+
+		viewer.addSelectionChangedListener(event -> {
+			ModelElement binding = (ModelElement) ((IStructuredSelection) event
+					.getSelection()).getFirstElement();
+			keyController.getBindingModel().setSelectedElement(binding);
+		});
+
+		IPropertyChangeListener treeUpdateListener = event -> {
+			if (event.getSource() == keyController.getBindingModel()
+					&& CommonModel.PROP_SELECTED_ELEMENT.equals(event.getProperty())) {
+				Object newVal = event.getNewValue();
+				StructuredSelection structuredSelection = newVal == null ? null : new StructuredSelection(newVal);
+				viewer.setSelection(structuredSelection, true);
+			} else if (event.getSource() instanceof BindingElement
+					&& ModelElement.PROP_MODEL_OBJECT.equals(event.getProperty())) {
+				viewer.update(event.getSource(), null);
+			} else if (BindingElement.PROP_CONFLICT.equals(event
+					.getProperty())) {
+				viewer.update(event.getSource(), null);
+			} else if (BindingModel.PROP_BINDINGS.equals(event
+					.getProperty())) {
+				viewer.refresh();
+			} else if (BindingModel.PROP_BINDING_ADD.equals(event
+					.getProperty())) {
+				viewer.add(keyController.getBindingModel(), event
+						.getNewValue());
+			} else if (BindingModel.PROP_BINDING_REMOVE.equals(event
+					.getProperty())) {
+				viewer.remove(event.getNewValue());
+			} else if (BindingModel.PROP_BINDING_FILTER.equals(event
+					.getProperty())) {
+				viewer.refresh();
+			}
+		};
+		keyController.addPropertyChangeListener(treeUpdateListener);
+		// as far as I got
+	}
+
+	private final Control createTreeControls(final Composite parent) {
+		GridLayout layout;
+		GridData gridData;
+		int widthHint;
+
+		// Creates controls related to the tree.
+		final Composite treeControls = new Composite(parent, SWT.NONE);
+		layout = new GridLayout(4, false);
+		layout.marginWidth = 0;
+		treeControls.setLayout(layout);
+		gridData = new GridData();
+		gridData.grabExcessHorizontalSpace = true;
+		gridData.horizontalAlignment = SWT.FILL;
+		treeControls.setLayoutData(gridData);
+
+		final Button addBindingButton = new Button(treeControls, SWT.PUSH);
+		gridData = new GridData();
+		widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
+		addBindingButton
+				.setText(NewKeysPreferenceMessages.AddBindingButton_Text);
+		gridData.widthHint = Math.max(widthHint, addBindingButton.computeSize(
+				SWT.DEFAULT, SWT.DEFAULT, true).x) + 5;
+		addBindingButton.setLayoutData(gridData);
+		addBindingButton.addSelectionListener(new SelectionAdapter()
+        {
+		    public void widgetSelected(SelectionEvent e) {
+		        keyController.getBindingModel().copy();
+		    }
+        });
+
+		final Button removeBindingButton = new Button(treeControls, SWT.PUSH);
+		gridData = new GridData();
+		widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
+		removeBindingButton
+				.setText(NewKeysPreferenceMessages.RemoveBindingButton_Text);
+		gridData.widthHint = Math.max(widthHint, removeBindingButton
+				.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x) + 5;
+		removeBindingButton.setLayoutData(gridData);
+		removeBindingButton.addSelectionListener(new SelectionAdapter()
+        {
+            public void widgetSelected(SelectionEvent e) {
+                keyController.getBindingModel().remove();
+            }
+        });
+		final Button restore = new Button(treeControls, SWT.PUSH);
+		gridData = new GridData();
+		widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
+		restore.setText(NewKeysPreferenceMessages.RestoreBindingButton_Text);
+		gridData.widthHint = Math.max(widthHint, restore.computeSize(
+				SWT.DEFAULT, SWT.DEFAULT, true).x) + 5;
+		restore.setLayoutData(gridData);
+		restore.addSelectionListener(new SelectionAdapter()
+        {
+            public void widgetSelected(SelectionEvent e) {
+			try {
+				fFilteredTree.setRedraw(false);
+				BindingModel bindingModel = keyController.getBindingModel();
+				bindingModel.restoreBinding(keyController.getContextModel());
+			} finally {
+				fFilteredTree.setRedraw(true);
+			}
+            }
+		});
+
+		createButtonBar(treeControls);
+		return treeControls;
+	}
+
+	/**
+	 *
+	 */
+	private void fill() {
+		fSchemeCombo.setInput(keyController.getSchemeModel());
+		fSchemeCombo.setSelection(new StructuredSelection(keyController.getSchemeModel().getSelectedElement()));
+
+		// Apply context filters
+		keyController.filterContexts(fFilterActionSetContexts, fFilterInternalContexts);
+		fWhenCombo.setInput(keyController.getContextModel());
+
+		fFilteredTree.filterCategories(fPatternFilter.isFilteringCategories());
+		fFilteredTree.getViewer().setInput(keyController.getBindingModel());
+	}
+
+	private void createSchemeControls(Composite parent) {
+		final Composite schemeControls = new Composite(parent, SWT.NONE);
+		GridLayout layout = new GridLayout(3, false);
+		layout.marginWidth = 0;
+		schemeControls.setLayout(layout);
+
+		final Label schemeLabel = new Label(schemeControls, SWT.NONE);
+		schemeLabel.setText(NewKeysPreferenceMessages.SchemeLabel_Text);
+
+		fSchemeCombo = new ComboViewer(schemeControls);
+		fSchemeCombo.setLabelProvider(new ListLabelProvider());
+		fSchemeCombo.setContentProvider(new ModelContentProvider());
+		GridData gridData = new GridData();
+		gridData.widthHint = 150;
+		gridData.horizontalAlignment = SWT.FILL;
+		fSchemeCombo.getCombo().setLayoutData(gridData);
+		fSchemeCombo.addSelectionChangedListener(event -> BusyIndicator.showWhile(fFilteredTree.getViewer().getTree().getDisplay(), () -> {
+			SchemeElement scheme = (SchemeElement) ((IStructuredSelection) event.getSelection())
+					.getFirstElement();
+			keyController.getSchemeModel().setSelectedElement(scheme);
+		}));
+		IPropertyChangeListener listener = event -> {
+			if (event.getSource() == keyController.getSchemeModel()
+					&& CommonModel.PROP_SELECTED_ELEMENT.equals(event
+							.getProperty())) {
+				Object newVal = event.getNewValue();
+				StructuredSelection structuredSelection = newVal == null ? null
+						: new StructuredSelection(newVal);
+				fSchemeCombo.setSelection(structuredSelection, true);
+			}
+		};
+
+		keyController.addPropertyChangeListener(listener);
+	}
+
+	@Override
+	public void init(IWorkbench workbench) {
+		keyController = new KeyController();
+		keyController.init(workbench);
+
+		commandService = workbench.getService(ICommandService.class);
+		fDefaultCategory = commandService.getCategory(null);
+		fBindingService = workbench.getService(IBindingService.class);
+
+		commandImageService = workbench.getService(ICommandImageService.class);
+	}
+
+	@Override
+	public void applyData(Object data) {
+		if (data instanceof ModelElement) {
+			keyController.getBindingModel().setSelectedElement((ModelElement) data);
+		}
+		if (data instanceof Binding && fFilteredTree != null) {
+			BindingElement be = (BindingElement) keyController
+					.getBindingModel().getBindingToElement().get(data);
+			fFilteredTree.getViewer().setSelection(new StructuredSelection(be), true);
+		}
+		if (data instanceof ParameterizedCommand) {
+			Map commandToElement = keyController.getBindingModel().getCommandToElement();
+
+			BindingElement be = (BindingElement)commandToElement.get(data);
+			if(be != null) {
+				fFilteredTree.getViewer().setSelection(new StructuredSelection(be),
+					true);
+			}
+		}
+	}
+
+	@Override
+	public boolean performOk() {
+		keyController.saveBindings(fBindingService);
+		saveState(getDialogSettings());
+		return super.performOk();
+	}
+
+	/**
+	 * Save the state of the receiver.
+	 *
+	 * @param dialogSettings
+	 */
+	public void saveState(IDialogSettings dialogSettings) {
+		if (dialogSettings == null) {
+			return;
+		}
+		dialogSettings.put(TAG_FILTER_ACTION_SETS, fFilterActionSetContexts);
+		dialogSettings.put(TAG_FILTER_INTERNAL, fFilterInternalContexts);
+		dialogSettings.put(TAG_FILTER_UNCAT, fFilteredTree.isFilteringCategories());
+	}
+
+	protected IDialogSettings getDialogSettings() {
+		IDialogSettings workbenchSettings = WorkbenchPlugin.getDefault()
+				.getDialogSettings();
+
+		IDialogSettings settings = workbenchSettings
+				.getSection(TAG_DIALOG_SECTION);
+
+		if (settings == null) {
+			settings = workbenchSettings.addNewSection(TAG_DIALOG_SECTION);
+		}
+		return settings;
+	}
+
+	@Override
+	protected final void performDefaults() {
+
+		// Ask the user to confirm
+		final String title = NewKeysPreferenceMessages.RestoreDefaultsMessageBoxText;
+		final String message = NewKeysPreferenceMessages.RestoreDefaultsMessageBoxMessage;
+		final boolean confirmed = MessageDialog.open(MessageDialog.CONFIRM,
+				getShell(), title, message, SWT.SHEET);
+
+		if (confirmed) {
+			long startTime = 0L;
+			if (DEBUG) {
+				startTime = System.currentTimeMillis();
+			}
+
+			fFilteredTree.setRedraw(false);
+			BusyIndicator.showWhile(fFilteredTree.getViewer().getTree().getDisplay(), () -> keyController.setDefaultBindings(fBindingService));
+			fFilteredTree.setRedraw(true);
+			if (DEBUG) {
+				final long elapsedTime = System.currentTimeMillis() - startTime;
+				Tracing.printTrace(TRACING_COMPONENT,
+						"performDefaults:model in " + elapsedTime + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
+
+			}
+		}
+
+		super.performDefaults();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/NewKeysPreferencePage.properties b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/NewKeysPreferencePage.properties
new file mode 100644
index 0000000..4117a34
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/NewKeysPreferencePage.properties
@@ -0,0 +1,53 @@
+###############################################################################
+# Copyright (c) 2005, 2013 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
+#     Remy Chi Jian Suen <remy.suen@gmail.com> - Bug 186522 - [KeyBindings] New Keys preference page does not resort by binding with conflicts
+###############################################################################
+AddBindingButton_Text = &Copy Command
+AddKeyButton_ToolTipText = Copy the command from a binding
+FiltersButton_Text = F&ilters...
+ExportButton_Text = E&xport CSV...
+BindingLabel_Text = &Binding:
+CommandNameColumn_Text = Command
+CommandNameLabel_Text = &Name:
+CommandDescriptionLabel_Text = D&escription:
+CategoryColumn_Text= Category
+UserColumn_Text= User
+DeleteSchemeButton_Text = D&elete
+ConflictsLabel_Text = Con&flicts:
+RemoveBindingButton_Text = &Unbind Command
+RestoreBindingButton_Text = Res&tore Command
+SchemeLabel_Text = &Scheme:
+TriggerSequenceColumn_Text = Binding
+WhenLabel_Text = &When:
+WhenColumn_Text = When
+Asterisk_Text = * in the binding column denotes a key conflict
+
+GroupingCombo_Label = Group By: 
+GroupingCombo_Category_Text = Category
+GroupingCombo_None_Text = None
+GroupingCombo_When_Text = When
+
+RestoreDefaultsMessageBoxMessage=This will restore all keys to the default settings and remove user changes.\r\nAre you sure you want to do this?
+RestoreDefaultsMessageBoxText=Restore Keyboard Defaults
+
+PreferenceStoreError_Title=Error
+PreferenceStoreError_Message=Could not access the preference store
+
+Undefined_Command=Undefined Command
+		
+Unavailable_Category=Unavailable Category
+		
+Undefined_Context=Undefined Context
+
+ActionSetFilterCheckBox_Text= Filter &action set contexts
+InternalFilterCheckBox_Text = Filter &internal contexts
+UncategorizedFilterCheckBox_Text = Filter &uncategorized commands
+KeysPreferenceFilterDialog_Title= When Context Filters
+
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/NoKeysPreferencePage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/NoKeysPreferencePage.java
new file mode 100644
index 0000000..a2e59d8
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/NoKeysPreferencePage.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 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.ui.internal.keys;
+
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+
+public class NoKeysPreferencePage extends PreferencePage implements IWorkbenchPreferencePage {
+
+	@Override
+	public void init(IWorkbench workbench) {
+		// do nothing, we don't have content
+	}
+
+	@Override
+	protected Control createContents(Composite parent) {
+		Label info = new Label(parent, SWT.NONE);
+		info.setText("Custom key preferences are not available at this time.\nPlease create key bindings through the model."); //$NON-NLS-1$
+		return info;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/SchemeLegacyWrapper.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/SchemeLegacyWrapper.java
new file mode 100644
index 0000000..d537d44
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/SchemeLegacyWrapper.java
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.keys;
+
+import org.eclipse.jface.bindings.BindingManager;
+import org.eclipse.jface.bindings.Scheme;
+import org.eclipse.ui.commands.IKeyConfiguration;
+import org.eclipse.ui.commands.IKeyConfigurationListener;
+import org.eclipse.ui.commands.NotDefinedException;
+
+/**
+ * A wrapper around the new {@link Scheme} class, providing supported for the
+ * old {@link IKeyConfiguration} interface.
+ *
+ * @since 3.1
+ */
+public final class SchemeLegacyWrapper implements IKeyConfiguration {
+
+	/**
+	 * The binding manager managing this scheme. This value is never
+	 * <code>null</code>.
+	 */
+	private final BindingManager bindingManager;
+
+	/**
+	 * The wrapped scheme; never <code>null</code>
+	 */
+	private final Scheme scheme;
+
+	/**
+	 * Constructs a new instance of <code>SchemeWrapper</code>.
+	 *
+	 * @param scheme
+	 *            The scheme to be wrapped; must not be <code>null</code>.
+	 * @param bindingManager
+	 *            The binding manager for this scheme; must not be
+	 *            <code>null</code>.
+	 */
+	public SchemeLegacyWrapper(final Scheme scheme,
+			final BindingManager bindingManager) {
+		if (scheme == null) {
+			throw new NullPointerException("Cannot wrap a null scheme"); //$NON-NLS-1$
+		}
+
+		if (bindingManager == null) {
+			throw new NullPointerException(
+					"Cannot wrap a scheme without a binding manager"); //$NON-NLS-1$
+		}
+
+		this.scheme = scheme;
+		this.bindingManager = bindingManager;
+	}
+
+	@Override
+	public void addKeyConfigurationListener(
+			IKeyConfigurationListener keyConfigurationListener) {
+		scheme.addSchemeListener(new LegacySchemeListenerWrapper(
+				keyConfigurationListener, bindingManager));
+	}
+
+	@Override
+	public int compareTo(Object o) {
+		return scheme.compareTo(o);
+	}
+
+	@Override
+	public String getDescription() throws NotDefinedException {
+		try {
+			return scheme.getDescription();
+		} catch (final org.eclipse.core.commands.common.NotDefinedException e) {
+			throw new NotDefinedException(e);
+		}
+	}
+
+	@Override
+	public String getId() {
+		return scheme.getId();
+	}
+
+	@Override
+	public String getName() throws NotDefinedException {
+		try {
+			return scheme.getName();
+		} catch (final org.eclipse.core.commands.common.NotDefinedException e) {
+			throw new NotDefinedException(e);
+		}
+	}
+
+	@Override
+	public String getParentId() throws NotDefinedException {
+		try {
+			return scheme.getParentId();
+		} catch (final org.eclipse.core.commands.common.NotDefinedException e) {
+			throw new NotDefinedException(e);
+		}
+	}
+
+	@Override
+	public boolean isActive() {
+		return scheme.getId().equals(bindingManager.getActiveScheme().getId());
+	}
+
+	@Override
+	public boolean isDefined() {
+		return scheme.isDefined();
+	}
+
+	@Override
+	public void removeKeyConfigurationListener(
+			IKeyConfigurationListener keyConfigurationListener) {
+		scheme.removeSchemeListener(new LegacySchemeListenerWrapper(
+				keyConfigurationListener, bindingManager));
+
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/WindowsKeyFormatter.properties b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/WindowsKeyFormatter.properties
new file mode 100644
index 0000000..bad9f70
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/WindowsKeyFormatter.properties
@@ -0,0 +1,12 @@
+###############################################################################
+# Copyright (c) 2000, 2006 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
+###############################################################################
+
+KEY_STROKE_DELIMITER=, 
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/WorkbenchKeyboard.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/WorkbenchKeyboard.java
new file mode 100644
index 0000000..b9b86d2
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/WorkbenchKeyboard.java
@@ -0,0 +1,120 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2014 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.ui.internal.keys;
+
+import java.util.List;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.ui.bindings.keys.KeyBindingDispatcher;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+
+/**
+ * @since 3.5
+ *
+ */
+public class WorkbenchKeyboard {
+	private KeyBindingDispatcher delegate;
+
+	static class KeyDownFilter implements Listener {
+		private KeyBindingDispatcher.KeyDownFilter delegate;
+
+		/**
+		 * @param event
+		 * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event)
+		 */
+		@Override
+		public void handleEvent(Event event) {
+			delegate.handleEvent(event);
+		}
+
+		/**
+		 * @return
+		 * @see java.lang.Object#toString()
+		 */
+		@Override
+		public String toString() {
+			return delegate.toString();
+		}
+
+		public KeyDownFilter(KeyBindingDispatcher.KeyDownFilter filter) {
+			this.delegate = filter;
+		}
+
+	}
+
+	/**
+	 * @param o
+	 * @return
+	 * @see java.lang.Object#equals(java.lang.Object)
+	 */
+	@Override
+	public boolean equals(Object o) {
+		return delegate.equals(o);
+	}
+
+	/**
+	 * @return
+	 * @see java.lang.Object#hashCode()
+	 */
+	@Override
+	public int hashCode() {
+		return delegate.hashCode();
+	}
+
+	/**
+	 * @return
+	 * @see java.lang.Object#toString()
+	 */
+	@Override
+	public String toString() {
+		return delegate.toString();
+	}
+
+	/**
+	 * @return
+	 * @see org.eclipse.e4.ui.bindings.keys.KeyBindingDispatcher#getKeyDownFilter()
+	 */
+	public KeyDownFilter getKeyDownFilter() {
+		return new KeyDownFilter(delegate.getKeyDownFilter());
+	}
+
+	/**
+	 * @param potentialKeyStrokes
+	 * @param event
+	 * @return
+	 * @see org.eclipse.e4.ui.bindings.keys.KeyBindingDispatcher#press(java.util.List,
+	 *      org.eclipse.swt.widgets.Event)
+	 */
+	public boolean press(List potentialKeyStrokes, Event event) {
+		return delegate.press(potentialKeyStrokes, event);
+	}
+
+	/**
+	 * @param context
+	 * @see org.eclipse.e4.ui.bindings.keys.KeyBindingDispatcher#setContext(org.eclipse.e4.core.contexts.IEclipseContext)
+	 */
+	public void setContext(IEclipseContext context) {
+		delegate.setContext(context);
+	}
+
+	public WorkbenchKeyboard(KeyBindingDispatcher kbd) {
+		delegate = kbd;
+	}
+
+	/**
+	 * @param ctrlShiftT
+	 * @return
+	 */
+	public static List generatePossibleKeyStrokes(Event event) {
+		return KeyBindingDispatcher.generatePossibleKeyStrokes(event);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/WorkbenchKeyboard.properties b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/WorkbenchKeyboard.properties
new file mode 100644
index 0000000..a24ea83
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/WorkbenchKeyboard.properties
@@ -0,0 +1,14 @@
+###############################################################################
+# Copyright (c) 2000, 2007 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
+###############################################################################
+
+ExecutionError.Title=Error Executing Command
+ExecutionError.Message=The command for the key you pressed failed.  Please see the log for more information.
+ExecutionError.MessageCommandName="{0}" did not complete normally.  Please see the log for more information.
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/model/BindingElement.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/model/BindingElement.java
new file mode 100644
index 0000000..7960cff
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/model/BindingElement.java
@@ -0,0 +1,224 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal.keys.model;
+
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.jface.bindings.Binding;
+import org.eclipse.jface.bindings.TriggerSequence;
+import org.eclipse.jface.bindings.keys.KeyBinding;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.internal.keys.NewKeysPreferenceMessages;
+import org.eclipse.ui.internal.util.Util;
+
+/**
+ * @since 3.4
+ *
+ */
+public class BindingElement extends ModelElement {
+
+	public static final String PROP_TRIGGER = "trigger"; //$NON-NLS-1$
+	public static final String PROP_CONTEXT = "bindingContext"; //$NON-NLS-1$
+	public static final String PROP_CATEGORY = "category"; //$NON-NLS-1$
+	public static final String PROP_USER_DELTA = "userDelta"; //$NON-NLS-1$
+	private static final String PROP_IMAGE = "image"; //$NON-NLS-1$
+	public static final String PROP_CONFLICT = "bindingConflict"; //$NON-NLS-1$
+	private TriggerSequence trigger;
+	private ContextElement context;
+	private String category;
+	private Integer userDelta;
+	private Image image;
+	private Boolean conflict;
+
+	/**
+	 * @param kc
+	 */
+	public BindingElement(KeyController kc) {
+		super(kc);
+	}
+
+	/**
+	 * @param b
+	 * @param model
+	 */
+	public void init(Binding b, ContextModel model) {
+		setCommandInfo(b.getParameterizedCommand());
+		setTrigger(b.getTriggerSequence());
+		setContext((ContextElement) model.getContextIdToElement().get(
+				b.getContextId()));
+		setUserDelta(Integer.valueOf(b.getType()));
+		setModelObject(b);
+	}
+
+	/**
+	 * @param bindingCommand
+	 */
+	private void setCommandInfo(ParameterizedCommand bindingCommand) {
+		setId(bindingCommand.getId());
+		try {
+			setName(bindingCommand.getName());
+		} catch (NotDefinedException e) {
+			setName(NewKeysPreferenceMessages.Undefined_Command);
+		}
+		try {
+			setDescription(bindingCommand.getCommand().getDescription());
+		} catch (NotDefinedException e) {
+			setDescription(Util.ZERO_LENGTH_STRING);
+		}
+		try {
+			setCategory(bindingCommand.getCommand().getCategory().getName());
+		} catch (NotDefinedException e) {
+			setCategory(NewKeysPreferenceMessages.Unavailable_Category);
+		}
+		setConflict(Boolean.FALSE);
+	}
+
+	/**
+	 * @param cmd
+	 * @param type
+	 *            The binding type. Check {@link Binding} constants.
+	 */
+	public void init(ParameterizedCommand cmd) {
+		setCommandInfo(cmd);
+		setTrigger(null);
+		setContext(null);
+		setUserDelta(Integer.valueOf(Binding.SYSTEM));
+
+		setModelObject(cmd);
+	}
+
+	/**
+	 * @return Returns the trigger.
+	 */
+	public TriggerSequence getTrigger() {
+		return trigger;
+	}
+
+	/**
+	 * @param trigger
+	 *            The trigger to set.
+	 */
+	public void setTrigger(TriggerSequence trigger) {
+		Object old = this.trigger;
+		this.trigger = trigger;
+		controller.firePropertyChange(this, PROP_TRIGGER, old, trigger);
+	}
+
+	/**
+	 * @return Returns the context.
+	 */
+	public ContextElement getContext() {
+		return context;
+	}
+
+	/**
+	 * @param context
+	 *            The context to set.
+	 */
+	public void setContext(ContextElement context) {
+		Object old = this.context;
+		this.context = context;
+		controller.firePropertyChange(this, PROP_CONTEXT, old, context);
+	}
+
+	/**
+	 * @return Returns the category.
+	 */
+	public String getCategory() {
+		return category;
+	}
+
+	/**
+	 * @param category
+	 *            The category to set.
+	 */
+	public void setCategory(String category) {
+		Object old = this.category;
+		this.category = category;
+		controller.firePropertyChange(this, PROP_CATEGORY, old, category);
+	}
+
+	/**
+	 * @return Returns the userDelta.
+	 */
+	public Integer getUserDelta() {
+		return userDelta;
+	}
+
+	/**
+	 * @param userDelta
+	 *            The userDelta to set.
+	 */
+	public void setUserDelta(Integer userDelta) {
+		Object old = this.userDelta;
+		this.userDelta = userDelta;
+		controller.firePropertyChange(this, PROP_USER_DELTA, old, userDelta);
+	}
+
+	/**
+	 * @return Returns the image.
+	 */
+	public Image getImage() {
+		return image;
+	}
+
+	/**
+	 * @param image
+	 *            The image to set.
+	 */
+	public void setImage(Image image) {
+		Object old = this.image;
+		this.image = image;
+		controller.firePropertyChange(this, PROP_IMAGE, old, image);
+	}
+
+	/**
+	 * @return Returns the conflict.
+	 */
+	public Boolean getConflict() {
+		return conflict;
+	}
+
+	/**
+	 * @param conflict
+	 *            The conflict to set.
+	 */
+	public void setConflict(Boolean conflict) {
+		Object old = this.conflict;
+		this.conflict = conflict;
+		controller.firePropertyChange(this, PROP_CONFLICT, old, conflict);
+	}
+
+	/**
+	 * @param binding
+	 * @param contextModel
+	 */
+	public void fill(KeyBinding binding, ContextModel contextModel) {
+		setCommandInfo(binding.getParameterizedCommand());
+		setTrigger(binding.getTriggerSequence());
+		setContext((ContextElement) contextModel.getContextIdToElement().get(
+				binding.getContextId()));
+		setUserDelta(Integer.valueOf(binding.getType()));
+		setModelObject(binding);
+	}
+
+	/**
+	 * @param parameterizedCommand
+	 */
+	public void fill(ParameterizedCommand parameterizedCommand) {
+		setCommandInfo(parameterizedCommand);
+		setTrigger(null);
+		setContext(null);
+		setUserDelta(Integer.valueOf(Binding.SYSTEM));
+		setModelObject(parameterizedCommand);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/model/BindingModel.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/model/BindingModel.java
new file mode 100644
index 0000000..10d1b21
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/model/BindingModel.java
@@ -0,0 +1,459 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.keys.model;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.jface.bindings.Binding;
+import org.eclipse.jface.bindings.BindingManager;
+import org.eclipse.jface.bindings.TriggerSequence;
+import org.eclipse.jface.bindings.keys.KeyBinding;
+import org.eclipse.jface.bindings.keys.KeySequence;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.internal.util.Util;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * @since 3.4
+ *
+ */
+public class BindingModel extends CommonModel {
+	public static final String PROP_BINDING_ADD = "bindingAdd"; //$NON-NLS-1$
+	public static final String PROP_BINDING_ELEMENT_MAP = "bindingElementMap"; //$NON-NLS-1$
+	public static final String PROP_BINDING_FILTER = "bindingFilter"; //$NON-NLS-1$
+	public static final String PROP_BINDING_REMOVE = "bindingRemove"; //$NON-NLS-1$
+	public static final String PROP_BINDINGS = "bindings"; //$NON-NLS-1$
+	public static final String PROP_CONFLICT_ELEMENT_MAP = "bindingConfictMap"; //$NON-NLS-1$
+
+	final static boolean deletes(final Binding del, final Binding binding) {
+		boolean deletes = true;
+		deletes &= Util.equals(del.getContextId(), binding.getContextId());
+		deletes &= Util.equals(del.getTriggerSequence(), binding
+				.getTriggerSequence());
+		if (del.getLocale() != null) {
+			deletes &= Util.equals(del.getLocale(), binding.getLocale());
+		}
+		if (del.getPlatform() != null) {
+			deletes &= Util.equals(del.getPlatform(), binding.getPlatform());
+		}
+		deletes &= (binding.getType() == Binding.SYSTEM);
+		deletes &= Util.equals(del.getParameterizedCommand(), null);
+
+		return deletes;
+	}
+
+	private Collection allParameterizedCommands;
+	private BindingManager bindingManager;
+
+	/**
+	 * Holds all the {@link BindingElement} objects.
+	 */
+	private HashSet bindingElements;
+
+	/**
+	 * A map of {@link Binding} objects to {@link BindingElement} objects.
+	 */
+	private Map bindingToElement;
+
+	/**
+	 * A map of {@link ParameterizedCommand} objects to {@link BindingElement}
+	 * objects.
+	 */
+	private Map commandToElement;
+
+	/**
+	 * @param kc
+	 */
+	public BindingModel(KeyController kc) {
+		super(kc);
+	}
+
+	/**
+	 * Makes a copy of the selected element.
+	 *
+	 */
+	public void copy() {
+		BindingElement element = (BindingElement) getSelectedElement();
+		copy(element);
+	}
+
+	/**
+	 * Makes a copy of the
+	 *
+	 * @param element
+	 */
+	public void copy(BindingElement element) {
+		if (element == null || !(element.getModelObject() instanceof Binding)) {
+			return;
+		}
+		BindingElement be = new BindingElement(controller);
+		ParameterizedCommand parameterizedCommand = ((Binding) element
+				.getModelObject()).getParameterizedCommand();
+		be.init(parameterizedCommand);
+		be.setParent(this);
+		bindingElements.add(be);
+		commandToElement.put(parameterizedCommand, be);
+		controller.firePropertyChange(this, PROP_BINDING_ADD, null, be);
+		setSelectedElement(be);
+	}
+
+	/**
+	 * @return Returns the bindings.
+	 */
+	public HashSet getBindings() {
+		return bindingElements;
+	}
+
+	/**
+	 * @return Returns the bindingToElement.
+	 */
+	public Map getBindingToElement() {
+		return bindingToElement;
+	}
+
+	/**
+	 * @return Returns the commandToElement.
+	 */
+	public Map getCommandToElement() {
+		return commandToElement;
+	}
+
+	/**
+	 * The initialization only.
+	 *
+	 * @param locator
+	 * @param manager
+	 * @param model
+	 */
+	public void init(IServiceLocator locator, BindingManager manager,
+			ContextModel model) {
+		Set cmdsForBindings = new HashSet();
+		bindingToElement = new HashMap();
+		commandToElement = new HashMap();
+
+		bindingElements = new HashSet();
+		bindingManager = manager;
+
+		Iterator i = manager.getActiveBindingsDisregardingContextFlat()
+				.iterator();
+		while (i.hasNext()) {
+			Binding b = (Binding) i.next();
+			BindingElement be = new BindingElement(controller);
+			be.init(b, model);
+			be.setParent(this);
+			bindingElements.add(be);
+			bindingToElement.put(b, be);
+			cmdsForBindings.add(b.getParameterizedCommand());
+		}
+
+		ICommandService commandService = locator
+				.getService(ICommandService.class);
+		final Collection commandIds = commandService.getDefinedCommandIds();
+		allParameterizedCommands = new HashSet();
+		final Iterator commandIdItr = commandIds.iterator();
+		while (commandIdItr.hasNext()) {
+			final String currentCommandId = (String) commandIdItr.next();
+			final Command currentCommand = commandService
+					.getCommand(currentCommandId);
+			try {
+				allParameterizedCommands.addAll(ParameterizedCommand
+						.generateCombinations(currentCommand));
+			} catch (final NotDefinedException e) {
+				// It is safe to just ignore undefined commands.
+			}
+		}
+
+		i = allParameterizedCommands.iterator();
+		while (i.hasNext()) {
+			ParameterizedCommand cmd = (ParameterizedCommand) i.next();
+			if (!cmdsForBindings.contains(cmd)) {
+				BindingElement be = new BindingElement(controller);
+				be.init(cmd);
+				be.setParent(this);
+				bindingElements.add(be);
+				commandToElement.put(cmd, be);
+			}
+		}
+	}
+
+	/**
+	 * Refreshes the binding model to be in sync with the {@link BindingManager}.
+	 *
+	 * @param contextModel
+	 */
+	public void refresh(ContextModel contextModel) {
+		Set cmdsForBindings = new HashSet();
+		Collection activeManagerBindings = bindingManager
+				.getActiveBindingsDisregardingContextFlat();
+
+		// add any bindings that we don't already have.
+		Iterator i = activeManagerBindings.iterator();
+		while (i.hasNext()) {
+			KeyBinding b = (KeyBinding) i.next();
+			ParameterizedCommand parameterizedCommand = b
+					.getParameterizedCommand();
+			cmdsForBindings.add(parameterizedCommand);
+			if (!bindingToElement.containsKey(b)) {
+				BindingElement be = new BindingElement(controller);
+				be.init(b, contextModel);
+				be.setParent(this);
+				bindingElements.add(be);
+				bindingToElement.put(b, be);
+				controller.firePropertyChange(this, PROP_BINDING_ADD, null, be);
+
+				if (commandToElement.containsKey(parameterizedCommand)
+						&& be.getUserDelta().intValue() == Binding.SYSTEM) {
+					Object remove = commandToElement.remove(parameterizedCommand);
+					bindingElements.remove(remove);
+					controller.firePropertyChange(this, PROP_BINDING_REMOVE,
+							null, remove);
+				}
+			}
+		}
+
+		// remove bindings that shouldn't be there
+		i = bindingElements.iterator();
+		while (i.hasNext()) {
+			BindingElement be = (BindingElement) i.next();
+			Object obj = be.getModelObject();
+			if (obj instanceof Binding) {
+				Binding b = (Binding) obj;
+				if (!activeManagerBindings.contains(b)) {
+					ParameterizedCommand cmd = b.getParameterizedCommand();
+					if (cmd != null) {
+						commandToElement.remove(cmd);
+					}
+					bindingToElement.remove(b);
+					i.remove();
+					controller.firePropertyChange(this, PROP_BINDING_REMOVE,
+							null, be);
+				}
+			} else {
+				cmdsForBindings.add(obj);
+			}
+		}
+
+		// If we removed the last binding for a parameterized command,
+		// put back the CMD
+		i = allParameterizedCommands.iterator();
+		while (i.hasNext()) {
+			ParameterizedCommand cmd = (ParameterizedCommand) i.next();
+			if (!cmdsForBindings.contains(cmd)) {
+				BindingElement be = new BindingElement(controller);
+				be.init(cmd);
+				be.setParent(this);
+				bindingElements.add(be);
+				commandToElement.put(cmd, be);
+				controller.firePropertyChange(this, PROP_BINDING_ADD, null, be);
+			}
+		}
+	}
+
+	/**
+	 * Removes the selected element's binding
+	 *
+	 */
+	public void remove() {
+		BindingElement element = (BindingElement) getSelectedElement();
+		remove(element);
+	}
+
+	/**
+	 * Removes the <code>bindingElement</code> binding.
+	 *
+	 * @param bindingElement
+	 */
+	public void remove(BindingElement bindingElement) {
+		if (bindingElement == null
+				|| !(bindingElement.getModelObject() instanceof Binding)) {
+			return;
+		}
+		KeyBinding keyBinding = (KeyBinding) bindingElement.getModelObject();
+		if (keyBinding.getType() == Binding.USER) {
+			bindingManager.removeBinding(keyBinding);
+		} else {
+			KeySequence keySequence = keyBinding.getKeySequence();
+
+			// Add the delete binding
+			bindingManager.addBinding(new KeyBinding(keySequence, null,
+					keyBinding.getSchemeId(), keyBinding.getContextId(), null,
+					null, null, Binding.USER));
+
+			// Unbind any conflicts affected by the delete binding
+			ConflictModel conflictModel = controller.getConflictModel();
+			conflictModel.updateConflictsFor(bindingElement);
+			Collection conflictsList = conflictModel.getConflicts();
+			if (conflictsList != null) {
+				Object[] conflicts = conflictsList.toArray();
+				for (Object conflict : conflicts) {
+					BindingElement be = (BindingElement) conflict;
+					if (be == bindingElement) {
+						continue;
+					}
+					Object modelObject = be.getModelObject();
+					if (modelObject instanceof Binding) {
+						Binding binding = (Binding) modelObject;
+						if (binding.getType() != Binding.SYSTEM) {
+							continue;
+						}
+						ParameterizedCommand pCommand = binding
+								.getParameterizedCommand();
+						be.fill(pCommand);
+						commandToElement.put(pCommand, be);
+					}
+				}
+			}
+		}
+		ParameterizedCommand parameterizedCommand = keyBinding
+				.getParameterizedCommand();
+		bindingElement.fill(parameterizedCommand);
+		commandToElement.put(parameterizedCommand, bindingElement);
+		controller.firePropertyChange(this, PROP_CONFLICT_ELEMENT_MAP, null,
+				bindingElement);
+	}
+
+	/**
+	 * Restores the specified BindingElement. A refresh should be performed
+	 * afterwards. The refresh may be done after several elements have been
+	 * restored.
+	 *
+	 * @param element
+	 */
+	public void restoreBinding(BindingElement element) {
+		if (element == null) {
+			return;
+		}
+
+		Object modelObject = element.getModelObject();
+
+		ParameterizedCommand cmd = null;
+		if (modelObject instanceof ParameterizedCommand) {
+			cmd = (ParameterizedCommand) modelObject;
+			TriggerSequence trigger = bindingManager
+					.getBestActiveBindingFor(cmd.getId());
+			Binding binding = bindingManager.getPerfectMatch(trigger);
+			if (binding != null && binding.getType() == Binding.SYSTEM) {
+				return;
+			}
+		} else if (modelObject instanceof KeyBinding) {
+			cmd = ((KeyBinding) modelObject).getParameterizedCommand();
+		}
+
+		// Remove any USER bindings
+		Binding[] managerBindings = bindingManager.getBindings();
+		ArrayList systemBindings = new ArrayList();
+		ArrayList removalBindings = new ArrayList();
+		for (Binding managerBinding : managerBindings) {
+			if (managerBinding.getParameterizedCommand() == null) {
+				removalBindings.add(managerBinding);
+			} else if (managerBinding.getParameterizedCommand().equals(cmd)) {
+				if (managerBinding.getType() == Binding.USER) {
+					bindingManager.removeBinding(managerBinding);
+				} else if (managerBinding.getType() == Binding.SYSTEM) {
+					systemBindings.add(managerBinding);
+				}
+			}
+		}
+
+		// Clear the USER bindings for parameterized commands
+		Iterator i = systemBindings.iterator();
+		while (i.hasNext()) {
+			Binding sys = (Binding) i.next();
+			Iterator j = removalBindings.iterator();
+			while (j.hasNext()) {
+				Binding del = (Binding) j.next();
+				if (deletes(del, sys) && del.getType() == Binding.USER) {
+					bindingManager.removeBinding(del);
+				}
+			}
+		}
+
+		setSelectedElement(null);
+
+		bindingElements.remove(element);
+		bindingToElement.remove(modelObject);
+		commandToElement.remove(modelObject);
+		controller.firePropertyChange(this, PROP_BINDING_REMOVE, null, element);
+	}
+
+	/**
+	 * Restores the currently selected binding.
+	 *
+	 * @param contextModel
+	 */
+	public void restoreBinding(ContextModel contextModel) {
+		BindingElement element = (BindingElement) getSelectedElement();
+
+		if (element == null) {
+			return;
+		}
+
+		restoreBinding(element);
+		refresh(contextModel);
+
+		Object obj = element.getModelObject();
+		ParameterizedCommand cmd = null;
+		if (obj instanceof ParameterizedCommand) {
+			cmd = (ParameterizedCommand) obj;
+		} else if (obj instanceof KeyBinding) {
+			cmd = ((KeyBinding) obj).getParameterizedCommand();
+		}
+
+		boolean done = false;
+		Iterator i = bindingElements.iterator();
+		// Reselects the command
+		while (i.hasNext() && !done) {
+			BindingElement be = (BindingElement) i.next();
+			obj = be.getModelObject();
+			ParameterizedCommand pcmd = null;
+			if (obj instanceof ParameterizedCommand) {
+				pcmd = (ParameterizedCommand) obj;
+			} else if (obj instanceof KeyBinding) {
+				pcmd = ((KeyBinding) obj).getParameterizedCommand();
+			}
+			if (cmd.equals(pcmd)) {
+				done = true;
+				setSelectedElement(be);
+			}
+		}
+	}
+
+	/**
+	 * @param bindings
+	 *            The bindings to set.
+	 */
+	public void setBindings(HashSet bindings) {
+		HashSet old = this.bindingElements;
+		this.bindingElements = bindings;
+		controller.firePropertyChange(this, PROP_BINDINGS, old, bindings);
+	}
+
+	/**
+	 * @param bindingToElement
+	 *            The bindingToElement to set.
+	 */
+	public void setBindingToElement(Map bindingToElement) {
+		Map old = this.bindingToElement;
+		this.bindingToElement = bindingToElement;
+		controller.firePropertyChange(this, PROP_BINDING_ELEMENT_MAP, old,
+				bindingToElement);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/model/CommonModel.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/model/CommonModel.java
new file mode 100644
index 0000000..c9a7497
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/model/CommonModel.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 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.ui.internal.keys.model;
+
+/**
+ * @since 3.4
+ *
+ */
+public class CommonModel extends ModelElement {
+
+	public static final String PROP_SELECTED_ELEMENT = "selectedElement"; //$NON-NLS-1$
+	private ModelElement selectedElement;
+
+	/**
+	 * @param kc
+	 */
+	public CommonModel(KeyController kc) {
+		super(kc);
+	}
+
+	/**
+	 * @return Returns the selectedContext.
+	 */
+	public ModelElement getSelectedElement() {
+		return selectedElement;
+	}
+
+	/**
+	 * @param selectedContext
+	 *            The selectedContext to set.
+	 */
+	public void setSelectedElement(ModelElement selectedContext) {
+		ModelElement old = this.selectedElement;
+		this.selectedElement = selectedContext;
+		controller.firePropertyChange(this, PROP_SELECTED_ELEMENT, old,
+				selectedContext);
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/model/ConflictModel.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/model/ConflictModel.java
new file mode 100644
index 0000000..4a7e870
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/model/ConflictModel.java
@@ -0,0 +1,250 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal.keys.model;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.eclipse.jface.bindings.Binding;
+import org.eclipse.jface.bindings.BindingManager;
+import org.eclipse.jface.bindings.TriggerSequence;
+
+/**
+ * @since 3.4
+ *
+ */
+public class ConflictModel extends CommonModel {
+
+	public static final String PROP_CONFLICTS = "conflicts"; //$NON-NLS-1$
+	public static final String PROP_CONFLICTS_ADD = "conflictsAdd"; //$NON-NLS-1$
+	public static final String PROP_CONFLICTS_REMOVE = "conflictsRemove"; //$NON-NLS-1$
+
+	/**
+	 * The set of conflicts for the currently selected element.
+	 */
+	private Collection conflicts;
+
+	private BindingManager bindingManager;
+
+	private BindingModel bindingModel;
+
+	/**
+	 * A mapping of binding element to known conflicts.
+	 */
+	private Map conflictsMap;
+
+	/**
+	 * @param kc
+	 */
+	public ConflictModel(KeyController kc) {
+		super(kc);
+	}
+
+	/**
+	 * @return Returns the conflicts.
+	 */
+	public Collection getConflicts() {
+		return conflicts;
+	}
+
+	/**
+	 * Sets the conflicts to the given collection. Any conflicts in the
+	 * collection that do not exist in the <code>bindingModel</code> are
+	 * removed.
+	 *
+	 * @param conflicts
+	 *            The conflicts to set.
+	 */
+	public void setConflicts(Collection conflicts) {
+		Object old = this.conflicts;
+		this.conflicts = conflicts;
+
+		if (this.conflicts != null) {
+			Iterator i = this.conflicts.iterator();
+			Map bindingToElement = bindingModel.getBindingToElement();
+			while (i.hasNext()) {
+				Object next = i.next();
+				if (!bindingToElement.containsValue(next)
+						&& !next.equals(getSelectedElement())) {
+					i.remove();
+				}
+			}
+		}
+
+		controller.firePropertyChange(this, PROP_CONFLICTS, old, conflicts);
+	}
+
+	public void updateConflictsFor(BindingElement source) {
+		updateConflictsFor(source, false);
+	}
+
+	public void updateConflictsFor(BindingElement oldValue,
+			BindingElement newValue) {
+		updateConflictsFor(oldValue, newValue, false);
+	}
+
+	public void updateConflictsFor(BindingElement source, boolean removal) {
+		updateConflictsFor(null, source, removal);
+	}
+
+	private void updateConflictsFor(BindingElement oldValue,
+			BindingElement newValue, boolean removal) {
+		updateConflictsFor(newValue, oldValue == null ? null : oldValue
+				.getTrigger(), newValue == null ? null : newValue.getTrigger(),
+				removal);
+	}
+
+	public void updateConflictsFor(BindingElement newValue,
+			TriggerSequence oldTrigger, TriggerSequence newTrigger,
+			boolean removal) {
+		Collection matches = (Collection) conflictsMap.get(newValue);
+		if (matches != null) {
+			if (newTrigger == null || removal) {
+				// we need to clear this match
+				matches.remove(newValue);
+				conflictsMap.remove(newValue);
+				if (matches == conflicts) {
+					controller.firePropertyChange(this, PROP_CONFLICTS_REMOVE,
+							null, newValue);
+				}
+				if (matches.size() == 1) {
+					BindingElement tbe = (BindingElement) matches.iterator()
+							.next();
+					conflictsMap.remove(tbe);
+					tbe.setConflict(Boolean.FALSE);
+					if (matches == conflicts) {
+						setConflicts(null);
+					}
+				}
+				return;
+			} else if (oldTrigger != null && !newTrigger.equals(oldTrigger)) {
+				// we need to clear this match
+				matches.remove(newValue);
+				conflictsMap.remove(newValue);
+
+				if (matches == conflicts) {
+					controller.firePropertyChange(this, PROP_CONFLICTS_REMOVE,
+							null, newValue);
+				}
+				if (matches.size() == 1) {
+					BindingElement tbe = (BindingElement) matches.iterator()
+							.next();
+					conflictsMap.remove(tbe);
+					tbe.setConflict(Boolean.FALSE);
+					if (matches == conflicts) {
+						setConflicts(null);
+					}
+				}
+			} else {
+				return;
+			}
+		}
+
+		if (newValue.getTrigger() == null
+				|| !(newValue.getModelObject() instanceof Binding)) {
+			return;
+		}
+		Binding binding = (Binding) newValue.getModelObject();
+		TriggerSequence trigger = binding.getTriggerSequence();
+
+		matches = (Collection) bindingManager
+				.getActiveBindingsDisregardingContext().get(trigger);
+		ArrayList localConflicts = new ArrayList();
+		if (matches != null) {
+			localConflicts.add(newValue);
+			Iterator i = matches.iterator();
+			while (i.hasNext()) {
+				Binding b = (Binding) i.next();
+				if (binding != b
+						&& b.getContextId().equals(binding.getContextId())
+						&& b.getSchemeId().equals(binding.getSchemeId())) {
+					Object element = bindingModel.getBindingToElement().get(b);
+					if (element != null) {
+						localConflicts.add(element);
+					}
+				}
+			}
+		}
+
+		if (localConflicts.size() > 1) {
+			// first find if it is already a conflict collection
+			Collection knownConflicts = null;
+			Iterator i = localConflicts.iterator();
+			while (i.hasNext() && knownConflicts == null) {
+				BindingElement tbe = (BindingElement) i.next();
+				knownConflicts = (Collection) conflictsMap.get(tbe);
+			}
+			if (knownConflicts != null) {
+				knownConflicts.add(newValue);
+				conflictsMap.put(newValue, knownConflicts);
+				newValue.setConflict(Boolean.TRUE);
+				if (knownConflicts == conflicts) {
+					controller.firePropertyChange(this, PROP_CONFLICTS_ADD,
+							null, newValue);
+				} else if (newValue == getSelectedElement()) {
+					setConflicts(knownConflicts);
+				}
+				return;
+			}
+			boolean isSelected = false;
+			i = localConflicts.iterator();
+			while (i.hasNext()) {
+				BindingElement tbe = (BindingElement) i.next();
+				if (tbe != null) {
+					conflictsMap.put(tbe, localConflicts);
+					tbe.setConflict(Boolean.TRUE);
+				}
+				if (tbe == getSelectedElement()) {
+					isSelected = true;
+				}
+			}
+			if (isSelected) {
+				setConflicts(localConflicts);
+			}
+		}
+	}
+
+	public void init(BindingManager manager, BindingModel model) {
+		bindingManager = manager;
+		bindingModel = model;
+		conflictsMap = new HashMap();
+		Iterator i = bindingModel.getBindings().iterator();
+		while (i.hasNext()) {
+			BindingElement be = (BindingElement) i.next();
+			if (be.getModelObject() instanceof Binding) {
+				updateConflictsFor(be);
+			}
+		}
+		controller.addPropertyChangeListener(event -> {
+			if (event.getSource() == ConflictModel.this
+					&& CommonModel.PROP_SELECTED_ELEMENT.equals(event
+							.getProperty())) {
+				if (event.getNewValue() != null) {
+					updateConflictsFor(
+							(BindingElement) event.getOldValue(),
+							(BindingElement) event.getNewValue());
+					setConflicts((Collection) conflictsMap.get(event
+							.getNewValue()));
+				} else {
+					setConflicts(null);
+				}
+			} else if (BindingModel.PROP_BINDING_REMOVE.equals(event
+					.getProperty())) {
+				updateConflictsFor((BindingElement) event.getOldValue(),
+						(BindingElement) event.getNewValue(), true);
+			}
+		});
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/model/ContextElement.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/model/ContextElement.java
new file mode 100644
index 0000000..1e90f24
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/model/ContextElement.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal.keys.model;
+
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.core.commands.contexts.Context;
+
+/**
+ * @since 3.4
+ *
+ */
+public class ContextElement extends ModelElement {
+
+	/**
+	 * @param kc
+	 */
+	public ContextElement(KeyController kc) {
+		super(kc);
+	}
+
+	public void init(Context context) {
+		setId(context.getId());
+		setModelObject(context);
+		try {
+			setName(context.getName());
+			setDescription(context.getDescription());
+		} catch (NotDefinedException e) {
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/model/ContextModel.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/model/ContextModel.java
new file mode 100644
index 0000000..94f17e8
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/model/ContextModel.java
@@ -0,0 +1,183 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.keys.model;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.core.commands.contexts.Context;
+import org.eclipse.ui.contexts.IContextService;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * @since 3.4
+ *
+ */
+public class ContextModel extends CommonModel {
+	private static final String CONTEXT_ID_ACTION_SETS = "org.eclipse.ui.contexts.actionSet"; //$NON-NLS-1$
+	private static final String CONTEXT_ID_INTERNAL = ".internal."; //$NON-NLS-1$
+
+	public static final String PROP_CONTEXTS = "contexts"; //$NON-NLS-1$
+	public static final String PROP_CONTEXT_MAP = "contextIdElementMap"; //$NON-NLS-1$
+	private List contexts;
+	private Map contextIdToFilteredContexts;
+	private Map contextIdToElement;
+	private IContextService contextService;
+
+	public ContextModel(KeyController kc) {
+		super(kc);
+	}
+
+	/**
+	 * @param locator
+	 */
+	public void init(IServiceLocator locator) {
+		contextService = locator
+				.getService(IContextService.class);
+		contexts = new ArrayList();
+		contextIdToFilteredContexts = new HashMap();
+		contextIdToElement = new HashMap();
+
+		Context[] definedContexts = contextService.getDefinedContexts();
+		for (Context definedContext : definedContexts) {
+			ContextElement ce = new ContextElement(controller);
+			ce.init(definedContext);
+			ce.setParent(this);
+			contexts.add(ce);
+			contextIdToElement.put(definedContext.getId(), ce);
+		}
+	}
+
+	/**
+	 * @return Returns the contexts.
+	 */
+	public List getContexts() {
+		return contexts;
+	}
+
+	/**
+	 * @param contexts
+	 *            The contexts to set.
+	 */
+	public void setContexts(List contexts) {
+		List old = this.contexts;
+		this.contexts = contexts;
+		controller.firePropertyChange(this, PROP_CONTEXTS, old, contexts);
+	}
+
+	/**
+	 * @return Returns the contextToElement.
+	 */
+	public Map getContextIdToElement() {
+		return contextIdToElement;
+	}
+
+	/**
+	 * @param contextToElement
+	 *            The contextToElement to set.
+	 */
+	public void setContextIdToElement(Map contextToElement) {
+		Map old = this.contextIdToElement;
+		this.contextIdToElement = contextToElement;
+		controller.firePropertyChange(this, PROP_CONTEXT_MAP, old,
+				contextToElement);
+	}
+
+	/**
+	 * Removes any contexts according to the parameters. The contexts are stored
+	 * in a {@link List} to they can be easily restored.
+	 *
+	 * @param actionSets
+	 *            <code>true</code> to filter action set contexts.
+	 * @param internal
+	 *            <code>true</code> to filter internal contexts
+	 */
+	public void filterContexts(boolean actionSets, boolean internal) {
+		// Remove undesired contexts
+		for (int i = 0; i < contexts.size(); i++) {
+			boolean removeContext = false;
+			ContextElement contextElement = (ContextElement) contexts.get(i);
+
+			if (actionSets == true
+					&& contextElement.getId().equalsIgnoreCase(
+							CONTEXT_ID_ACTION_SETS)) {
+				removeContext = true;
+			} else {
+				String parentId;
+				try {
+					parentId = ((Context) contextElement.getModelObject())
+							.getParentId();
+					while (parentId != null) {
+						if (parentId.equalsIgnoreCase(CONTEXT_ID_ACTION_SETS)) {
+							removeContext = true;
+						}
+						parentId = contextService.getContext(parentId)
+								.getParentId();
+					}
+				} catch (NotDefinedException e) {
+					// No parentId to check
+				}
+			}
+
+			if (internal == true
+					&& contextElement.getId().indexOf(CONTEXT_ID_INTERNAL) != -1) {
+				removeContext = true;
+			}
+
+			if (removeContext) {
+				contextIdToFilteredContexts.put(contextElement.getId(),
+						contextElement);
+				contextIdToElement.remove(contextElement);
+			}
+		}
+
+		contexts.removeAll(contextIdToFilteredContexts.values());
+
+		Iterator iterator = contextIdToFilteredContexts.keySet().iterator();
+		// Restore desired contexts
+		while (iterator.hasNext()) {
+			boolean restoreContext = false;
+			ContextElement contextElement = (ContextElement) contextIdToFilteredContexts
+					.get(iterator.next());
+
+			try {
+				if (actionSets == false) {
+					if (contextElement.getId().equalsIgnoreCase(CONTEXT_ID_ACTION_SETS)) {
+						restoreContext = true;
+					} else {
+						String parentId = ((Context) contextElement.getModelObject()).getParentId();
+						if (parentId != null && parentId.equalsIgnoreCase(CONTEXT_ID_ACTION_SETS)) {
+							restoreContext = true;
+						}
+					}
+				}
+			} catch (NotDefinedException e) {
+				// No parentId to check
+			}
+			if (internal == false
+					&& contextElement.getId().indexOf(CONTEXT_ID_INTERNAL) != -1) {
+				restoreContext = true;
+			}
+
+			if (restoreContext) {
+				contexts.add(contextElement);
+				contextIdToElement.put(contextElement.getId(), contextElement);
+				iterator.remove();
+			}
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/model/KeyController.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/model/KeyController.java
new file mode 100644
index 0000000..eb82f5a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/model/KeyController.java
@@ -0,0 +1,548 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2016 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 440810, 472654
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.keys.model;
+
+import java.io.BufferedWriter;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.nio.charset.StandardCharsets;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.ResourceBundle;
+import java.util.Set;
+import org.eclipse.core.commands.CommandManager;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.core.commands.contexts.ContextManager;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.e4.ui.bindings.EBindingService;
+import org.eclipse.jface.bindings.Binding;
+import org.eclipse.jface.bindings.BindingManager;
+import org.eclipse.jface.bindings.Scheme;
+import org.eclipse.jface.bindings.keys.KeyBinding;
+import org.eclipse.jface.bindings.keys.KeySequence;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.jface.util.SafeRunnable;
+import org.eclipse.swt.SWT;
+//import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.contexts.IContextService;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.keys.KeysPreferencePage;
+import org.eclipse.ui.internal.keys.NewKeysPreferenceMessages;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.internal.util.Util;
+import org.eclipse.ui.keys.IBindingService;
+import org.eclipse.ui.services.IServiceLocator;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+/**
+ * @since 3.4
+ *
+ */
+public class KeyController {
+	private static final String DELIMITER = ","; //$NON-NLS-1$
+	private static final String ESCAPED_QUOTE = "\""; //$NON-NLS-1$
+	private static final String REPLACEMENT = "\"\""; //$NON-NLS-1$
+	/**
+	 * The resource bundle from which translations can be retrieved.
+	 */
+	private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle
+			.getBundle(KeysPreferencePage.class.getName());
+	private ListenerList<IPropertyChangeListener> eventManager = null;
+	private BindingManager fBindingManager;
+	private ContextModel contextModel;
+	private SchemeModel fSchemeModel;
+	private BindingModel bindingModel;
+	private boolean notifying = true;
+	private ConflictModel conflictModel;
+	private IServiceLocator serviceLocator;
+
+	private ListenerList<IPropertyChangeListener> getEventManager() {
+		if (eventManager == null) {
+			eventManager = new ListenerList<>(ListenerList.IDENTITY);
+		}
+		return eventManager;
+	}
+
+	public void setNotifying(boolean b) {
+		notifying = b;
+	}
+
+	public boolean isNotifying() {
+		return notifying;
+	}
+
+	public void firePropertyChange(Object source, String propId, Object oldVal,
+			Object newVal) {
+		if (!isNotifying()) {
+			return;
+		}
+		if (Util.equals(oldVal, newVal)) {
+			return;
+		}
+
+		PropertyChangeEvent event = new PropertyChangeEvent(source, propId,
+				oldVal, newVal);
+		for (IPropertyChangeListener listener : getEventManager()) {
+			listener.propertyChange(event);
+		}
+	}
+
+	public void addPropertyChangeListener(IPropertyChangeListener listener) {
+		getEventManager().add(listener);
+	}
+
+	public void removePropertyChangeListener(IPropertyChangeListener listener) {
+		getEventManager().remove(listener);
+	}
+
+	public void init(IServiceLocator locator) {
+		getEventManager().clear();
+		this.serviceLocator = locator;
+		fBindingManager = loadModelBackend(serviceLocator);
+		contextModel = new ContextModel(this);
+		contextModel.init(serviceLocator);
+		fSchemeModel = new SchemeModel(this);
+		fSchemeModel.init(fBindingManager);
+		bindingModel = new BindingModel(this);
+		bindingModel.init(serviceLocator, fBindingManager, contextModel);
+		conflictModel = new ConflictModel(this);
+		conflictModel.init(fBindingManager, bindingModel);
+		addSetContextListener();
+		addSetBindingListener();
+		addSetConflictListener();
+		addSetKeySequenceListener();
+		addSetSchemeListener();
+		addSetModelObjectListener();
+	}
+
+	private static BindingManager loadModelBackend(IServiceLocator locator) {
+		IBindingService bindingService = locator
+				.getService(IBindingService.class);
+		BindingManager bindingManager = new BindingManager(
+				new ContextManager(), new CommandManager());
+		final Scheme[] definedSchemes = bindingService.getDefinedSchemes();
+		try {
+			Scheme modelActiveScheme = null;
+			for (final Scheme scheme : definedSchemes) {
+				final Scheme copy = bindingManager.getScheme(scheme.getId());
+				copy.define(scheme.getName(), scheme.getDescription(), scheme.getParentId());
+				if (scheme.getId().equals(bindingService.getActiveScheme().getId())) {
+					modelActiveScheme = copy;
+				}
+			}
+			bindingManager.setActiveScheme(modelActiveScheme);
+		} catch (final NotDefinedException e) {
+			StatusManager.getManager().handle(
+					new Status(IStatus.WARNING, WorkbenchPlugin.PI_WORKBENCH,
+							"Keys page found an undefined scheme", e)); //$NON-NLS-1$
+		}
+
+		bindingManager.setLocale(bindingService.getLocale());
+		bindingManager.setPlatform(bindingService.getPlatform());
+
+		Set<Binding> bindings = new HashSet<>();
+		EBindingService eBindingService = locator
+				.getService(EBindingService.class);
+		bindings.addAll(eBindingService.getActiveBindings());
+		for (Binding binding : bindingService.getBindings()) {
+			bindings.add(binding);
+		}
+
+		bindingManager.setBindings(bindings.toArray(new Binding[0]));
+
+		return bindingManager;
+	}
+
+	public ContextModel getContextModel() {
+		return contextModel;
+	}
+
+	public SchemeModel getSchemeModel() {
+		return fSchemeModel;
+	}
+
+	public BindingModel getBindingModel() {
+		return bindingModel;
+	}
+
+	public ConflictModel getConflictModel() {
+		return conflictModel;
+	}
+
+	private void addSetContextListener() {
+		addPropertyChangeListener(event -> {
+			if (event.getSource() == contextModel
+					&& CommonModel.PROP_SELECTED_ELEMENT.equals(event
+							.getProperty())) {
+				updateBindingContext((ContextElement) event.getNewValue());
+			}
+		});
+	}
+
+	private void addSetBindingListener() {
+		addPropertyChangeListener(event -> {
+			if (event.getSource() == bindingModel
+					&& CommonModel.PROP_SELECTED_ELEMENT.equals(event
+							.getProperty())) {
+				BindingElement binding = (BindingElement) event
+						.getNewValue();
+				if (binding == null) {
+					conflictModel.setSelectedElement(null);
+					return;
+				}
+				conflictModel.setSelectedElement(binding);
+				ContextElement context = binding.getContext();
+				if (context != null) {
+					contextModel.setSelectedElement(context);
+				}
+			}
+		});
+	}
+
+	private void addSetConflictListener() {
+		addPropertyChangeListener(event -> {
+			if (event.getSource() == conflictModel
+					&& CommonModel.PROP_SELECTED_ELEMENT.equals(event
+							.getProperty())) {
+				if (event.getNewValue() != null) {
+					bindingModel.setSelectedElement((ModelElement) event
+							.getNewValue());
+				}
+			}
+		});
+	}
+
+	private void addSetKeySequenceListener() {
+		addPropertyChangeListener(event -> {
+			if (BindingElement.PROP_TRIGGER.equals(event.getProperty())) {
+				updateTrigger((BindingElement) event.getSource(),
+						(KeySequence) event.getOldValue(),
+						(KeySequence) event.getNewValue());
+			}
+		});
+	}
+
+	private void addSetModelObjectListener() {
+		addPropertyChangeListener(event -> {
+			if (event.getSource() instanceof BindingElement
+					&& ModelElement.PROP_MODEL_OBJECT.equals(event
+							.getProperty())) {
+				if (event.getNewValue() != null) {
+					BindingElement element = (BindingElement) event
+							.getSource();
+					Object oldValue = event.getOldValue();
+					Object newValue = event.getNewValue();
+					if (oldValue instanceof Binding
+							&& newValue instanceof Binding) {
+						conflictModel.updateConflictsFor(element,
+								((Binding) oldValue).getTriggerSequence(),
+								((Binding) newValue).getTriggerSequence(),
+								false);
+					} else {
+						conflictModel.updateConflictsFor(element, false);
+					}
+
+					ContextElement context = element.getContext();
+					if (context != null) {
+						contextModel.setSelectedElement(context);
+					}
+				}
+			}
+		});
+	}
+
+	private void addSetSchemeListener() {
+		addPropertyChangeListener(event -> {
+			if (event.getSource() == fSchemeModel
+					&& CommonModel.PROP_SELECTED_ELEMENT.equals(event
+							.getProperty())) {
+				changeScheme((SchemeElement) event.getOldValue(),
+						(SchemeElement) event.getNewValue());
+			}
+		});
+	}
+
+	/**
+	 * @param oldScheme
+	 * @param newScheme
+	 */
+	protected void changeScheme(SchemeElement oldScheme, SchemeElement newScheme) {
+		if (newScheme == null
+				|| newScheme.getModelObject() == fBindingManager
+						.getActiveScheme()) {
+			return;
+		}
+		try {
+			fBindingManager
+					.setActiveScheme((Scheme) newScheme.getModelObject());
+			bindingModel.refresh(contextModel);
+			bindingModel.setSelectedElement(null);
+		} catch (NotDefinedException e) {
+			WorkbenchPlugin.log(e);
+		}
+
+	}
+
+	private void updateBindingContext(ContextElement context) {
+		if (context == null) {
+			return;
+		}
+		BindingElement activeBinding = (BindingElement) bindingModel
+				.getSelectedElement();
+		if (activeBinding == null) {
+			return;
+		}
+		String activeSchemeId = fSchemeModel.getSelectedElement().getId();
+		Object obj = activeBinding.getModelObject();
+		if (obj instanceof KeyBinding) {
+			KeyBinding keyBinding = (KeyBinding) obj;
+			if (!keyBinding.getContextId().equals(context.getId())) {
+				final KeyBinding binding = new KeyBinding(keyBinding
+						.getKeySequence(),
+						keyBinding.getParameterizedCommand(), activeSchemeId,
+						context.getId(), null, null, null, Binding.USER);
+				if (keyBinding.getType() == Binding.USER) {
+					fBindingManager.removeBinding(keyBinding);
+				} else {
+					fBindingManager.addBinding(new KeyBinding(keyBinding
+							.getKeySequence(), null, keyBinding.getSchemeId(),
+							keyBinding.getContextId(), null, null, null,
+							Binding.USER));
+				}
+				bindingModel.getBindingToElement().remove(
+						activeBinding.getModelObject());
+
+				fBindingManager.addBinding(binding);
+				activeBinding.fill(binding, contextModel);
+				bindingModel.getBindingToElement().put(binding, activeBinding);
+			}
+		}
+	}
+
+	/**
+	 * @param activeBinding
+	 * @param oldSequence
+	 * @param keySequence
+	 */
+	public void updateTrigger(BindingElement activeBinding,
+			KeySequence oldSequence, KeySequence keySequence) {
+		if (activeBinding == null) {
+			return;
+		}
+		Object obj = activeBinding.getModelObject();
+		if (obj instanceof KeyBinding) {
+			KeyBinding keyBinding = (KeyBinding) obj;
+			if (!keyBinding.getKeySequence().equals(keySequence)) {
+				if (keySequence != null && !keySequence.isEmpty()) {
+					String activeSchemeId = fSchemeModel.getSelectedElement()
+							.getId();
+					ModelElement selectedElement = contextModel
+							.getSelectedElement();
+					String activeContextId = selectedElement == null ? IContextService.CONTEXT_ID_WINDOW
+							: selectedElement.getId();
+					final KeyBinding binding = new KeyBinding(keySequence,
+							keyBinding.getParameterizedCommand(),
+							activeSchemeId, activeContextId, null, null, null,
+							Binding.USER);
+					Map bindingToElement = bindingModel.getBindingToElement();
+					bindingToElement.remove(keyBinding);
+					if (keyBinding.getType() == Binding.USER) {
+						fBindingManager.removeBinding(keyBinding);
+					} else {
+						fBindingManager.addBinding(new KeyBinding(keyBinding
+								.getKeySequence(), null, keyBinding
+								.getSchemeId(), keyBinding.getContextId(),
+								null, null, null, Binding.USER));
+					}
+
+					fBindingManager.addBinding(binding);
+					activeBinding.fill(binding, contextModel);
+					bindingModel.getBindingToElement().put(binding,
+							activeBinding);
+
+					// Remove binding for any system conflicts
+
+					bindingModel.setSelectedElement(activeBinding);
+				} else {
+					bindingModel.getBindingToElement().remove(keyBinding);
+					if (keyBinding.getType() == Binding.USER) {
+						fBindingManager.removeBinding(keyBinding);
+					} else {
+						fBindingManager.addBinding(new KeyBinding(keyBinding
+								.getKeySequence(), null, keyBinding
+								.getSchemeId(), keyBinding.getContextId(),
+								null, null, null, Binding.USER));
+					}
+					activeBinding.fill(keyBinding.getParameterizedCommand());
+				}
+			}
+		} else if (obj instanceof ParameterizedCommand) {
+			ParameterizedCommand cmd = (ParameterizedCommand) obj;
+			if (keySequence != null && !keySequence.isEmpty()) {
+				String activeSchemeId = fSchemeModel.getSelectedElement()
+						.getId();
+				ModelElement selectedElement = contextModel
+						.getSelectedElement();
+				String activeContextId = selectedElement == null ? IContextService.CONTEXT_ID_WINDOW
+						: selectedElement.getId();
+				final KeyBinding binding = new KeyBinding(keySequence, cmd,
+						activeSchemeId, activeContextId, null, null, null,
+						Binding.USER);
+				fBindingManager.addBinding(binding);
+				activeBinding.fill(binding, contextModel);
+				bindingModel.getBindingToElement().put(binding, activeBinding);
+			}
+		}
+	}
+
+	/**
+	 * Replaces all the current bindings with the bindings in the local copy of
+	 * the binding manager.
+	 *
+	 * @param bindingService
+	 *            The binding service that saves the changes made to the local
+	 *            copy of the binding manager
+	 */
+	public void saveBindings(IBindingService bindingService) {
+		try {
+			bindingService.savePreferences(fBindingManager.getActiveScheme(),
+					fBindingManager.getBindings());
+		} catch (IOException e) {
+			logPreferenceStoreException(e);
+		}
+	}
+
+	/**
+	 * Logs the given exception, and opens an error dialog saying that something
+	 * went wrong. The exception is assumed to have something to do with the
+	 * preference store.
+	 *
+	 * @param exception
+	 *            The exception to be logged; must not be <code>null</code>.
+	 */
+	private final void logPreferenceStoreException(final Throwable exception) {
+		final String message = NewKeysPreferenceMessages.PreferenceStoreError_Message;
+		String exceptionMessage = exception.getMessage();
+		if (exceptionMessage == null) {
+			exceptionMessage = message;
+		}
+		final IStatus status = new Status(IStatus.ERROR,
+				WorkbenchPlugin.PI_WORKBENCH, 0, exceptionMessage, exception);
+		WorkbenchPlugin.log(message, status);
+		StatusUtil.handleStatus(message, exception, StatusManager.SHOW);
+	}
+
+	/**
+	 * Filters contexts for the When Combo.
+	 *
+	 * @param actionSets
+	 *            <code>true</code> to filter action set contexts
+	 * @param internal
+	 *            <code>false</code> to filter internal contexts
+	 *
+	 */
+	public void filterContexts(boolean actionSets, boolean internal) {
+		contextModel.filterContexts(actionSets, internal);
+	}
+
+	/**
+	 * Sets the bindings to default.
+	 *
+	 * @param bindingService
+	 */
+	public void setDefaultBindings(IBindingService bindingService) {
+		// Fix the scheme in the local changes.
+		final String defaultSchemeId = bindingService.getDefaultSchemeId();
+		final Scheme defaultScheme = fBindingManager.getScheme(defaultSchemeId);
+		try {
+			fBindingManager.setActiveScheme(defaultScheme);
+		} catch (final NotDefinedException e) {
+			// At least we tried....
+		}
+
+		// Restore any User defined bindings
+		for (Binding binding : fBindingManager.getBindings()) {
+			if (binding.getType() == Binding.USER) {
+				fBindingManager.removeBinding(binding);
+			}
+		}
+
+		bindingModel.refresh(contextModel);
+		saveBindings(bindingService);
+	}
+
+	// RAP
+//	public void exportCSV(Shell shell) {
+//		final FileDialog fileDialog = new FileDialog(shell, SWT.SAVE
+//				| SWT.SHEET);
+//		fileDialog.setFilterExtensions(new String[] { "*.csv" }); //$NON-NLS-1$
+//		fileDialog.setFilterNames(new String[] { Util.translateString(
+//				RESOURCE_BUNDLE, "csvFilterName") }); //$NON-NLS-1$
+//		fileDialog.setOverwrite(true);
+//		final String filePath = fileDialog.open();
+//		if (filePath == null) {
+//			return;
+//		}
+//
+//		final SafeRunnable runnable = new SafeRunnable() {
+//			@Override
+//			public final void run() throws IOException {
+//				Writer fileWriter = null;
+//				try {
+//					fileWriter = new BufferedWriter(new OutputStreamWriter(
+//							new FileOutputStream(filePath), StandardCharsets.UTF_8));
+//					final Object[] bindingElements = bindingModel.getBindings().toArray();
+//					for (Object bindingElement : bindingElements) {
+//						final BindingElement be = (BindingElement) bindingElement;
+//						if (be.getTrigger() == null
+//								|| be.getTrigger().isEmpty()) {
+//							continue;
+//						}
+//						StringBuffer buffer = new StringBuffer();
+//						buffer.append(ESCAPED_QUOTE
+//								+ Util.replaceAll(be.getCategory(),
+//										ESCAPED_QUOTE, REPLACEMENT)
+//								+ ESCAPED_QUOTE + DELIMITER);
+//						buffer.append(ESCAPED_QUOTE + be.getName()
+//								+ ESCAPED_QUOTE + DELIMITER);
+//						buffer.append(ESCAPED_QUOTE + be.getTrigger().format()
+//								+ ESCAPED_QUOTE + DELIMITER);
+//						buffer.append(ESCAPED_QUOTE + be.getContext().getName()
+//								+ ESCAPED_QUOTE);
+//						buffer.append(System.getProperty("line.separator")); //$NON-NLS-1$
+//						fileWriter.write(buffer.toString());
+//					}
+//
+//				} finally {
+//					if (fileWriter != null) {
+//						try {
+//							fileWriter.close();
+//						} catch (final IOException e) {
+//							// At least I tried.
+//						}
+//					}
+//
+//				}
+//			}
+//		};
+//		SafeRunner.run(runnable);
+//	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/model/ModelElement.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/model/ModelElement.java
new file mode 100644
index 0000000..e1a41d8
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/model/ModelElement.java
@@ -0,0 +1,115 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 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.ui.internal.keys.model;
+
+/**
+ * @since 3.4
+ *
+ */
+public class ModelElement {
+
+	public static final String PROP_PARENT = "parent"; //$NON-NLS-1$
+	public static final String PROP_ID = "id"; //$NON-NLS-1$
+	public static final String PROP_NAME = "name"; //$NON-NLS-1$
+	public static final String PROP_DESCRIPTION = "description"; //$NON-NLS-1$
+	public static final String PROP_MODEL_OBJECT = "modelObject"; //$NON-NLS-1$
+	protected KeyController controller;
+	private ModelElement parent;
+	private String id;
+	private String name;
+	private String description;
+	private Object modelObject;
+
+	public ModelElement(KeyController kc) {
+		controller = kc;
+	}
+
+	/**
+	 * @return Returns the parent.
+	 */
+	public ModelElement getParent() {
+		return parent;
+	}
+
+	/**
+	 * @param parent The parent to set.
+	 */
+	public void setParent(ModelElement parent) {
+		ModelElement old = this.parent;
+		this.parent = parent;
+		controller.firePropertyChange(this, PROP_PARENT, old, parent);
+	}
+
+	/**
+	 * @return Returns the id.
+	 */
+	public String getId() {
+		return id;
+	}
+
+	/**
+	 * @param id The id to set.
+	 */
+	public void setId(String id) {
+		String old = this.id;
+		this.id = id;
+		controller.firePropertyChange(this, PROP_ID, old, id);
+	}
+
+	/**
+	 * @return Returns the name.
+	 */
+	public String getName() {
+		return name;
+	}
+
+	/**
+	 * @param name The name to set.
+	 */
+	public void setName(String name) {
+		String old = this.name;
+		this.name = name;
+		controller.firePropertyChange(this, PROP_NAME, old, name);
+	}
+
+	/**
+	 * @return Returns the description.
+	 */
+	public String getDescription() {
+		return description;
+	}
+
+	/**
+	 * @param description The description to set.
+	 */
+	public void setDescription(String description) {
+		String old = this.description;
+		this.description = description;
+		controller.firePropertyChange(this, PROP_DESCRIPTION, old, description);
+	}
+
+	/**
+	 * @return Returns the context.
+	 */
+	public Object getModelObject() {
+		return modelObject;
+	}
+
+	/**
+	 * @param context The context to set.
+	 */
+	public void setModelObject(Object o) {
+		Object old = this.modelObject;
+		modelObject = o;
+		controller.firePropertyChange(this, PROP_MODEL_OBJECT, old, o);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/model/SchemeElement.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/model/SchemeElement.java
new file mode 100644
index 0000000..8adf8ff
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/model/SchemeElement.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal.keys.model;
+
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.jface.bindings.Scheme;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+
+/**
+ * @since 3.4
+ *
+ */
+public class SchemeElement extends ModelElement {
+
+	/**
+	 * @param kc
+	 */
+	public SchemeElement(KeyController kc) {
+		super(kc);
+	}
+
+	/**
+	 * @param scheme
+	 */
+	public void init(Scheme scheme) {
+		setId(scheme.getId());
+		setModelObject(scheme);
+		try {
+			setName(scheme.getName());
+			setDescription(scheme.getDescription());
+		} catch (NotDefinedException e) {
+			WorkbenchPlugin.log(e);
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/model/SchemeModel.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/model/SchemeModel.java
new file mode 100644
index 0000000..5bb91f1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/keys/model/SchemeModel.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal.keys.model;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.eclipse.jface.bindings.BindingManager;
+import org.eclipse.jface.bindings.Scheme;
+
+/**
+ * @since 3.4
+ *
+ */
+public class SchemeModel extends CommonModel {
+
+	public static final String PROP_SCHEMES = "schemes"; //$NON-NLS-1$
+	private List schemes;
+
+	/**
+	 * @param kc
+	 */
+	public SchemeModel(KeyController kc) {
+		super(kc);
+	}
+
+	/**
+	 * @param bindingManager
+	 */
+	public void init(BindingManager bindingManager) {
+		schemes = new ArrayList();
+		for (Scheme definedScheme : bindingManager.getDefinedSchemes()) {
+			SchemeElement se = new SchemeElement(controller);
+			se.init(definedScheme);
+			se.setParent(this);
+			schemes.add(se);
+			if (definedScheme == bindingManager.getActiveScheme()) {
+				setSelectedElement(se);
+			}
+		}
+	}
+
+	/**
+	 * @return Returns the schemes.
+	 */
+	public List getSchemes() {
+		return schemes;
+	}
+
+	/**
+	 * @param schemes
+	 *            The schemes to set.
+	 */
+	public void setSchemes(List schemes) {
+		List old = this.schemes;
+		this.schemes = schemes;
+		controller.firePropertyChange(this, PROP_SCHEMES, old, schemes);
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/layout/CacheWrapper.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/layout/CacheWrapper.java
new file mode 100644
index 0000000..91e96f0
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/layout/CacheWrapper.java
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.layout;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Layout;
+
+/**
+ * This class wraps a control with a complex computeSize method. It uses caching
+ * to reduce the number of times the control's computeSize method is called. This
+ * allows controls (such as Coolbars and wrapping text) with slow computeSize
+ * operations to be used inside layouts and composites that use inefficient caching.
+ * <p>
+ * For example, you want to use Coolbar A inside composite B. Rather than making A
+ * a direct child of B, place it inside a CacheWrapper and insert the CacheWrapper
+ * into B. Any layout data that would normally be attached to the control itself
+ * should be attached to the wrapper instead:
+ * </p>
+ * <code>
+ *
+ *   // Unoptimized code
+ *   Toolbar myToolbar = new Toolbar(someParent, SWT.WRAP);
+ *   myToolbar.setLayoutData(someLayoutData);
+ * </code>
+ * <code>
+ *
+ *   // Optimized code
+ *   CacheWrapper myWrapper = new CacheWrapper(someParent);
+ *   Toolbar myToolbar = new Toolbar(myWrapper.getControl(), SWT.WRAP);
+ *   myWrapper.getControl().setLayoutData(someLayoutData);
+ * </code>
+ * <p>
+ * CacheWrapper creates a Composite which should have exactly one child: the control
+ * whose size should be cached. Note that CacheWrapper does NOT respect the flushCache
+ * argument to layout() and computeSize(). This is intentional, since the whole point of
+ * this class is to workaround layouts with poor caching, and such layouts will typically
+ * be too eager about flushing the caches of their children. However, this means that you
+ * MUST manually call flushCache() whenver the child's preferred size changes (and before
+ * the parent is layed out).
+ * </p>
+ *
+ * @since 3.0
+ */
+public class CacheWrapper {
+    private Composite proxy;
+
+    private SizeCache cache = new SizeCache();
+
+    private Rectangle lastBounds = new Rectangle(0, 0, 0, 0);
+
+    private class WrapperLayout extends Layout implements ICachingLayout {
+        @Override
+		protected Point computeSize(Composite composite, int wHint, int hHint,
+                boolean flushCache) {
+            Control[] children = composite.getChildren();
+            if (children.length != 1) {
+                return new Point(0, 0);
+            }
+
+            cache.setControl(children[0]);
+
+            return cache.computeSize(wHint, hHint);
+        }
+
+        @Override
+		protected void layout(Composite composite, boolean flushCache) {
+            Control[] children = composite.getChildren();
+            if (children.length != 1) {
+                return;
+            }
+
+            Control child = children[0];
+            Rectangle newBounds = composite.getClientArea();
+            if (!newBounds.equals(lastBounds)) {
+                child.setBounds(newBounds);
+                lastBounds = newBounds;
+            }
+
+        }
+
+        @Override
+		public void flush(Control dirtyControl) {
+            CacheWrapper.this.flushCache();
+        }
+    }
+
+    /**
+     * Creates a <code>CacheWrapper</code> with the given parent
+     *
+     * @param parent
+     */
+    public CacheWrapper(Composite parent) {
+        proxy = new Composite(parent, SWT.NONE);
+
+        proxy.setLayout(new WrapperLayout());
+    }
+
+    /**
+     * Flush the cache. Call this when the child has changed in order to force
+     * the size to be recomputed in the next resize event.
+     */
+    public void flushCache() {
+        cache.flush();
+    }
+
+    /**
+     * Use this as the parent of the real control.
+     *
+     * @return the proxy contol. It should be given exactly one child.
+     */
+    public Composite getControl() {
+        return proxy;
+    }
+
+    /**
+     * Dispose of any widgets created by this wrapper.
+     */
+    public void dispose() {
+        if (proxy != null) {
+            proxy.dispose();
+            proxy = null;
+        }
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/layout/CellData.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/layout/CellData.java
new file mode 100644
index 0000000..6f0702e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/layout/CellData.java
@@ -0,0 +1,550 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.layout;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+
+/**
+ * <code>CellData</code> is the layout data object associated with
+ * <code>CellLayout</code>. You can attach a CellData object to a
+ * control by using the <code>setLayoutData</code> method. CellData
+ * objects are optional. If you do not attach any layout data to a control,
+ * it will behave just like attaching a CellData created using its default
+ * constructor.
+ *
+ * @since 3.0
+ **/
+public final class CellData {
+
+    /**
+     * hintType flag (value = 0) indicating that the control's computeSize method should be used
+     * to determine the control size. If modifierType is set to NONE, then the widthHint
+     * and heightHint fields will be ignored.
+     */
+    public final static int NONE = 0;
+
+    /**
+     * hintType flag (value = 1) indicating that the widthHint and heightHint should be used
+     * as the control's size instead of the result of computeSize
+     * <p>
+     * This flag is useful for list boxes, text boxes, tree controls, and other controls
+     * whose contents can change dynamically. For example, create a tree control and set
+     * its width and height hints to the default size for that control. This will cause
+     * the hints to be used instead of the preferred size of the tree control.</p>
+     */
+    public final static int OVERRIDE = 1;
+
+    /**
+     * hintType(value = 2) indicating that the width of the control should be no less than
+     * widthHint (if provided) and the height of the control should be no less
+     * than heightHint (if provided).
+     * <p>
+     * This flag is useful for buttons. For example, set the width and height hints to
+     * the default button size. This will use the default button size unless the button
+     * label is too large to fit on the button.
+     * </p>
+     */
+    public final static int MINIMUM = 2;
+
+    /**
+     * hintType flag (value = 3) indicating that the width of the control should be no more than
+     * widthHint (if provided) and the height of the control should be no more
+     * than heightHint (if provided).
+     * <p>
+     * This flag is useful for wrapping text. For example, set heightHint to SWT.DEFAULT
+     * and set widthHint to the desired number of pixels after which text should wrap. This
+     * will cause the text to wrap after the given number of pixels, but will not allocate
+     * extra space in the column if the text widget does not fill an entire line.
+     * </p>
+     */
+    public final static int MAXIMUM = 3;
+
+    /**
+     * This flag controls how the width and height hints are to be treated. See the constants
+     * above.
+     */
+    public int hintType = OVERRIDE;
+
+    /**
+     * Width hint. This modifies the width of the control, in pixels. If set to SWT.DEFAULT,
+     * this dimension will not be constrained. Depending on the value of modifierType,
+     * this may be a minimum size, a maximum size, or simply replace the preferred control
+     * size.
+     */
+    public int widthHint = SWT.DEFAULT;
+
+    /**
+     * Height hint. This modifies the height of the control, in pixels. If set to SWT.DEFAULT,
+     * this dimension will not be constrained. Depending on the value of modifierType,
+     * this will be a minimum size, a maximum size, or a replacement for the control's preferred
+     * size.
+     */
+    public int heightHint = SWT.DEFAULT;
+
+    /**
+     * Number of rows spanned by this cell (default = 1)
+     */
+    public int verticalSpan = 1;
+
+    /**
+     * Number of columns spanned by this cell (default = 1)
+     */
+    public int horizontalSpan = 1;
+
+    /**
+     * Horizontal alignment of the control within the cell. May be one
+     * of SWT.LEFT, SWT.RIGHT, SWT.CENTER, or SWT.NORMAL. SWT.NORMAL indicates
+     * that the control should be made as wide as the cell.
+     */
+    public int horizontalAlignment = SWT.FILL;
+
+    /**
+     * Vertical alignment of the control within the cell. May be one of
+     * SWT.TOP, SWT.BOTTOM, SWT.CENTER, or SWT.NORMAL. SWT.NORMAL indicates
+     * that the control should be made as wide as the cell.
+     */
+    public int verticalAlignment = SWT.FILL;
+
+    /**
+     * Horizontal indentation (pixels). Positive values move the control
+     * to the right, negative to the left.
+     */
+    public int horizontalIndent = 0;
+
+    /**
+     * Vertical indentation (pixels). Positive values move the control
+     * down, negative values move the control up.
+     */
+    public int verticalIndent = 0;
+
+    /**
+     * Constructs a CellData with default properties
+     */
+    public CellData() {
+        // Use the default values for all fields.
+    }
+
+    /**
+     * Creates a new CellData that with properties that are as close as possible to
+     * the given GridData. This is used for converting GridLayouts into CellLayouts.
+     *
+     * @param data
+     */
+    public CellData(GridData data) {
+        verticalSpan = data.verticalSpan;
+        horizontalSpan = data.horizontalSpan;
+
+        switch (data.horizontalAlignment) {
+        case GridData.BEGINNING:
+            horizontalAlignment = SWT.LEFT;
+            break;
+        case GridData.CENTER:
+            horizontalAlignment = SWT.CENTER;
+            break;
+        case GridData.END:
+            horizontalAlignment = SWT.RIGHT;
+            break;
+        case GridData.FILL:
+            horizontalAlignment = SWT.FILL;
+            break;
+        }
+
+        switch (data.verticalAlignment) {
+        case GridData.BEGINNING:
+            verticalAlignment = SWT.LEFT;
+            break;
+        case GridData.CENTER:
+            verticalAlignment = SWT.CENTER;
+            break;
+        case GridData.END:
+            verticalAlignment = SWT.RIGHT;
+            break;
+        case GridData.FILL:
+            verticalAlignment = SWT.FILL;
+            break;
+        }
+
+        widthHint = data.widthHint;
+        heightHint = data.heightHint;
+        horizontalIndent = data.horizontalIndent;
+        hintType = OVERRIDE;
+    }
+
+    /**
+     * Copies the given CellData
+     *
+     * @param newData
+     */
+    public CellData(CellData newData) {
+        hintType = newData.hintType;
+        widthHint = newData.widthHint;
+        heightHint = newData.heightHint;
+        horizontalAlignment = newData.horizontalAlignment;
+        verticalAlignment = newData.verticalAlignment;
+        horizontalSpan = newData.horizontalSpan;
+        verticalSpan = newData.verticalSpan;
+    }
+
+    /**
+     * Sets the size hint for this control. This is used to modify the control's
+     * preferred size. If one dimension should remain unmodified, that hint can be
+     * set to SWT.DEFAULT. Using a size hint of CellData.MINIMUM ensures that the preferred
+     * control size is larger than the hint. Using a size hint of CellData.MAXIMUM ensures
+     * that the preferred size is smaller than the hint. Using a size hint of CellData.OVERRIDE
+     * ensures that the preferred size is always equal to the hint.
+     *
+     * @param hintType one of CellData.MINIMUM, CellData.MAXIMUM, or CellData.OVERRIDE
+     * @param hint size hint (in pixels). If either dimension is set to SWT.DEFAULT, the
+     * hint will not affect that dimension
+     * @return this
+     */
+    public CellData setHint(int hintType, Point hint) {
+        return setHint(hintType, hint.x, hint.y);
+    }
+
+    /**
+     * Sets the size hint for this control. This is used to modify the control's
+     * preferred size. If one dimension should remain unmodified, that hint can be
+     * set to SWT.DEFAULT. Using a size hint of CellData.MINIMUM ensures that the preferred
+     * control size is larger than the hint. Using a size hint of CellData.MAXIMUM ensures
+     * that the preferred size is smaller than the hint. Using a size hint of CellData.OVERRIDE
+     * ensures that the preferred size is always equal to the hint. If both hints are equal
+     * to SWT.DEFAULT, then the control's preferred size is unmodified.
+     *
+     * @param hintType one of CellData.MINIMUM, CellData.MAXIMUM, or CellData.OVERRIDE
+     * @param horizontal horizontal hint (pixels). A value of SWT.DEFAULT will leave the result
+     * of the control's computeSize method unmodified.
+     * @param vertical vertical hint (pixels). A value of SWT.DEFAULT will leave the result of
+     * the control's computeSize method unmodified.
+     * @return this
+     */
+    public CellData setHint(int hintType, int horizontal, int vertical) {
+        this.hintType = hintType;
+        this.heightHint = vertical;
+        this.widthHint = horizontal;
+
+        return this;
+    }
+
+    /**
+     * Sets the alignment for this control
+     *
+     * @param horizontalAlignment one of SWT.LEFT, SWT.RIGHT, SWT.FILL, or SWT.CENTER
+     * @param verticalAlignment one of SWT.TOP, SWT.BOTTOM, SWT.FILL, or SWT.CENTER
+     * @return this
+     */
+    public CellData align(int horizontalAlignment, int verticalAlignment) {
+        this.horizontalAlignment = horizontalAlignment;
+        this.verticalAlignment = verticalAlignment;
+
+        return this;
+    }
+
+    /**
+     * Sets the number of rows and columns spanned by this control.
+     *
+     * @param horizontalSpan number of columns spanned by the control (> 0)
+     * @param verticalSpan number of rows spanned by the control (> 0)
+     * @return this
+     */
+    public CellData span(int horizontalSpan, int verticalSpan) {
+        this.horizontalSpan = horizontalSpan;
+        this.verticalSpan = verticalSpan;
+
+        return this;
+    }
+
+    /**
+     * Sets the indentation for this control. The indentation is added to
+     * the control's position within the cell. For example, indentation of
+     * (10,4) will move the control right by 10 pixels and down by 4 pixels.
+     *
+     * @param indent indentation (pixels)
+     * @return this
+     */
+    public CellData indent(Point indent) {
+        return this.indent(indent.x, indent.y);
+    }
+
+    /**
+     * Sets the indentation for this cell
+     *
+     * @param horizontalIndent distance (pixels) to move the control to the right
+     * @param verticalIndent distance (pixels) to move the control down
+     * @return this
+     */
+    public CellData indent(int horizontalIndent, int verticalIndent) {
+        this.horizontalIndent = horizontalIndent;
+        this.verticalIndent = verticalIndent;
+
+        return this;
+    }
+
+    /**
+     * Returns the preferred size of the given control, given the known dimensions of
+     * its cell.
+     *
+     * @param toCompute the control whose size is to be computed
+     * @param cellWidth width of the cell, in pixels (or SWT.DEFAULT if unknown)
+     * @param cellHeight height of the cell, in pixels (or SWT.DEFAULT if unknown)
+     * @return the preferred size of the given control, in pixels
+     */
+    public Point computeSize(SizeCache toCompute, int cellWidth, int cellHeight) {
+
+        int absHorizontalIndent = Math.abs(horizontalIndent);
+        int absVerticalIndent = Math.abs(verticalIndent);
+
+        // If we're going to indent, subtract off the space that will be required for indentation from
+        // the available space
+        if (cellWidth != SWT.DEFAULT) {
+            cellWidth -= absHorizontalIndent;
+        }
+
+        if (cellHeight != SWT.DEFAULT) {
+            cellHeight -= absVerticalIndent;
+        }
+
+        int controlWidth = horizontalAlignment == SWT.FILL ? cellWidth
+                : SWT.DEFAULT;
+        int controlHeight = verticalAlignment == SWT.FILL ? cellHeight
+                : SWT.DEFAULT;
+
+        // Note: this could be optimized further. If we're using a MAXIMUM hint and
+        // non-FILL alignment, we could simply call computeMaximumBoundedSize using the
+        // minimum of the cell size and the hint as the boundary -- basically, rather
+        // than applying two limits for the hint and the cell boundary, we can do it in
+        // one step and reduce the size computations by half (for this specific case).
+        Point controlSize = computeControlSize(toCompute, controlWidth,
+                controlHeight);
+
+        if (cellWidth != SWT.DEFAULT && controlSize.x > cellWidth) {
+            controlSize = computeControlSize(toCompute, cellWidth,
+                    controlHeight);
+            if (cellHeight != SWT.DEFAULT && controlSize.y > cellHeight) {
+                controlSize.y = cellHeight;
+            }
+        } else if (cellHeight != SWT.DEFAULT && controlSize.y > cellHeight) {
+            controlSize = computeControlSize(toCompute, controlWidth,
+                    cellHeight);
+            if (cellWidth != SWT.DEFAULT && controlSize.x > cellWidth) {
+                controlSize.x = cellWidth;
+            }
+        }
+
+        // If we're going to indent, add the indentation to the required space
+        controlSize.x += absHorizontalIndent;
+        controlSize.y += absVerticalIndent;
+
+        return controlSize;
+    }
+
+    /**
+     * Arranges the given control within the given rectangle using the
+     * criteria described by this CellData.
+     *
+     * @param control
+     * @param cellBounds
+     * @since 3.0
+     */
+    public void positionControl(SizeCache cache, Rectangle cellBounds) {
+
+        int startx = cellBounds.x;
+        int starty = cellBounds.y;
+        int availableWidth = cellBounds.width - horizontalIndent;
+        int availableHeight = cellBounds.height - verticalIndent;
+
+        Point size = computeSize(cache, availableWidth, availableHeight);
+
+        // Horizontal justification
+        switch (horizontalAlignment) {
+        case SWT.RIGHT:
+            startx = cellBounds.x + availableWidth - size.x;
+            break;
+        case SWT.CENTER:
+            startx = cellBounds.x + (availableWidth - size.x) / 2;
+            break;
+        }
+
+        // Vertical justification
+        switch (verticalAlignment) {
+        case SWT.BOTTOM:
+            starty = cellBounds.y + availableHeight - size.y;
+            break;
+        case SWT.CENTER:
+            starty = cellBounds.y + (availableHeight - size.y) / 2;
+            break;
+        }
+
+        // Position the control
+        cache.getControl().setBounds(startx + horizontalIndent,
+                starty + verticalIndent, size.x, size.y);
+    }
+
+    /**
+     * Returns the preferred size of the given control in this cell, given one or both
+     * known dimensions of the control. This differs from computeSize, which takes known
+     * dimensions of the <b>cell</b> as arguments.
+     *
+     * @param toCompute
+     * @param controlWidth
+     * @param controlHeight
+     * @return
+     * @since 3.0
+     */
+    private Point computeControlSize(SizeCache toCompute, int controlWidth,
+            int controlHeight) {
+        switch (hintType) {
+        case OVERRIDE:
+            return computeOverrideSize(toCompute, controlWidth, controlHeight,
+                    widthHint, heightHint);
+        case MINIMUM:
+            return computeMinimumBoundedSize(toCompute, controlWidth,
+                    controlHeight, widthHint, heightHint);
+        case MAXIMUM:
+            return computeMaximumBoundedSize(toCompute, controlWidth,
+                    controlHeight, widthHint, heightHint);
+        }
+
+        return computeRawSize(toCompute, controlWidth, controlHeight);
+    }
+
+    /**
+     * Computes the size of the control, given its outer dimensions. This should be used in
+     * place of calling Control.computeSize, since Control.computeSize takes control-specific
+     * inner dimensions as hints.
+     *
+     * @param toCompute Control whose size will be computed
+     * @param controlWidth width of the control (pixels or SWT.DEFAULT if unknown)
+     * @param controlHeight height of the control (pixels or SWT.DEFAULT if unknown)
+     * @return preferred dimensions of the control
+     */
+    private static Point computeRawSize(SizeCache toCompute, int controlWidth,
+            int controlHeight) {
+        if (controlWidth != SWT.DEFAULT && controlHeight != SWT.DEFAULT) {
+            return new Point(controlWidth, controlHeight);
+        }
+
+        // Known bug: we pass the OUTER dimension of the control into computeSize, even though
+        // SWT expects a control-specific inner dimension as width and height hints. Currently,
+        // SWT does not provide any means to convert outer dimensions into inner dimensions.
+        // Fortunately, the outer and inner dimensions tend to be quite close so we
+        // pass in the outer dimension and adjust the result if it differs from one of the
+        // hints. This may cause incorrect text wrapping in rare cases, and should be fixed
+        // once SWT provides a way to convert the outer dimension of a control into a valid
+        // width or height hint for Control.computeSize. Note that the distinction between outer
+        // and inner dimensions is undocumented in SWT, and most examples also contain this
+        // bug.
+        Point result = toCompute.computeSize(controlWidth, controlHeight);
+
+        // Hack: If the result of computeSize differs from the width or height-hints, adjust it.
+        // See above. Don't remove this hack until SWT provides some way to pass correct width
+        // and height hints into computeSize. Once this happens, these conditions should always
+        // return false and the hack will have no effect.
+        if (controlWidth != SWT.DEFAULT) {
+            result.x = controlWidth;
+        } else if (controlHeight != SWT.DEFAULT) {
+            result.y = controlHeight;
+        }
+
+        return result;
+    }
+
+    /**
+     * Computes the preferred size of the control. Optionally, one or both dimensions
+     * may be fixed to a given size.
+     *
+     * @param control object that can compute the size of the control of interest
+     * @param wHint known width (or SWT.DEFAULT if the width needs to be computed)
+     * @param hHint known height (or SWT.DEFAULT if the height needs to be computed)
+     * @param overrideW width that should always be returned by the control,
+     * or SWT.DEFAULT if the width is not being constrained
+     * @param overrideH height that should always be returned by the control,
+     * or SWT.DEFAULT if the height is not being constrained
+     * @return
+     */
+    private static Point computeOverrideSize(SizeCache control, int wHint,
+            int hHint, int overrideW, int overrideH) {
+        int resultWidth = overrideW;
+        int resultHeight = overrideH;
+
+        if (wHint != SWT.DEFAULT) {
+            resultWidth = wHint;
+        }
+
+        if (hHint != SWT.DEFAULT) {
+            resultHeight = hHint;
+        }
+
+        if (resultWidth == SWT.DEFAULT || resultHeight == SWT.DEFAULT) {
+            Point result = computeRawSize(control, resultWidth, resultHeight);
+
+            return result;
+        }
+
+        return new Point(resultWidth, resultHeight);
+    }
+
+    /**
+     * Computes the size for the control, optionally bounding the size in the x and
+     * y directions. The various hints are used to determine which dimensions are
+     * already known and which dimensions need to be computed.
+     *
+     * @param control The control whose size should be computed
+     * @param wHint known width (or SWT.DEFAULT if the width needs to be computed)
+     * @param hHint known height (or SWT.DEFAULT if the height needs to be computed)
+     * @param boundedWidth maximum width for the control (or SWT.DEFAULT if the width is unbounded)
+     * @param boundedHeight maximum height for the control (or SWT.DEFAULT if the height is unbounded)
+     * @return the preferred size of the control, given that it cannot exceed the given bounds
+     */
+    private static Point computeMaximumBoundedSize(SizeCache control,
+            int wHint, int hHint, int boundedWidth, int boundedHeight) {
+        Point controlSize = computeRawSize(control, wHint, hHint);
+
+        if (wHint == SWT.DEFAULT && boundedWidth != SWT.DEFAULT
+                && controlSize.x > boundedWidth) {
+            return computeMaximumBoundedSize(control, boundedWidth, hHint,
+                    boundedWidth, boundedHeight);
+        }
+
+        if (hHint == SWT.DEFAULT && boundedHeight != SWT.DEFAULT
+                && controlSize.y > boundedHeight) {
+            return computeMaximumBoundedSize(control, wHint, boundedHeight,
+                    boundedWidth, boundedHeight);
+        }
+
+        return controlSize;
+    }
+
+    private static Point computeMinimumBoundedSize(SizeCache control,
+            int wHint, int hHint, int minimumWidth, int minimumHeight) {
+
+        Point controlSize = computeRawSize(control, wHint, hHint);
+
+        if (minimumWidth != SWT.DEFAULT && wHint == SWT.DEFAULT
+                && controlSize.x < minimumWidth) {
+            return computeMinimumBoundedSize(control, minimumWidth, hHint,
+                    minimumWidth, minimumHeight);
+        }
+
+        if (minimumHeight != SWT.DEFAULT && hHint == SWT.DEFAULT
+                && controlSize.y < minimumHeight) {
+            return computeMinimumBoundedSize(control, wHint, minimumHeight,
+                    minimumWidth, minimumHeight);
+        }
+
+        return controlSize;
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/layout/CellLayout.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/layout/CellLayout.java
new file mode 100644
index 0000000..2179511
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/layout/CellLayout.java
@@ -0,0 +1,882 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.layout;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Layout;
+
+/**
+ * <p>Instance of this class lay out the control children of a <code>Composite</code>
+ * in a grid, using a simple set of rules and a simple API. This class is
+ * intended to be more predictable than <code>GridLayout</code> and easier to use than
+ * <code>FormLayout</code>, while retaining most of the power of both.</p>
+ *
+ * <p>The power of a <code>CellLayout</code> lies in the ability to control
+ * the size and resizing properties of each row and column. Unlike other layout
+ * classes, complex layouts can be created without attaching any layout data to
+ * individual controls in the layout. </p>
+ *
+ * <p>The various subclasses of <code>IColumnInfo</code>
+ * can be used to create columns with fixed width, columns whose width is computed
+ * from child controls, or width that grows in proportion to the size of other
+ * columns. Layouts can be given a default <code>IColumnInfo</code> that will
+ * be used to set the size of any column whose properties have not been explicitly
+ * set. This is useful for creating layouts where most or all columns have the
+ * same properties. Similarly, the subclasses of <code>IRowInfo</code> can be used to
+ * control the height of individual rows.</p>
+ *
+ * <p>For a finer grain of control, <code>CellData</code> objects can be attached
+ * to individual controls in the layout. These objects serve a similar function as
+ * <code>GridData</code> objects serve for <code>GridLayout</code>. They allow
+ * controls to span multiple rows or columns, set the justification of the control
+ * within its cell, and allow the user to override the preferred size of the control.
+ * </p>
+ *
+ * <p>In many cases, it is not necessary to attach any layout data to controls in
+ * the layout, since the controls can be arranged based on the properties of rows
+ * and columns. However, layout data may be attached to individual controls to
+ * allow them to span multiple columns or to control their justification within
+ * their cell.
+ * </p>
+ *
+ * <p>All the <code>set</code> methods in this class return <code>this</code>, allowing
+ * a layout to be created and initialized in a single line of code. For example: </p>
+ *
+ * <code>
+ * Composite myControl = new Composite(parent, SWT.NONE);
+ * myControl.setLayout(new CellLayout(2).setMargins(10,10).setSpacing(5,5));
+ * </code>
+ *
+ * @since 3.0
+ */
+public class CellLayout extends Layout {
+
+    /**
+     * Object used to compute the height of rows whose properties have not been
+     * explicitly set.
+     */
+    private Row defaultRowSettings = new Row(false);
+
+    /**
+     * Object used to compute the width of columns whose properties have not been
+     * explicitly set.
+     */
+    private Row defaultColSettings = new Row(true);
+
+    /**
+     * horizontalSpacing specifies the number of pixels between the right
+     * edge of one cell and the left edge of its neighbouring cell to
+     * the right.
+     *
+     * The default value is 5.
+     */
+    int horizontalSpacing = 5;
+
+    /**
+     * verticalSpacing specifies the number of pixels between the bottom
+     * edge of one cell and the top edge of its neighbouring cell underneath.
+     *
+     * The default value is 5.
+     */
+    int verticalSpacing = 5;
+
+    /**
+     * marginWidth specifies the number of pixels of horizontal margin
+     * that will be placed along the left and right edges of the layout.
+     *
+     * The default value is 0.
+     */
+    public int marginWidth = 5;
+
+    /**
+     * marginHeight specifies the number of pixels of vertical margin
+     * that will be placed along the top and bottom edges of the layout.
+     *
+     * The default value is 0.
+     */
+    public int marginHeight = 5;
+
+    /**
+     * Number of columns in this layout, or 0 indicating that the whole layout
+     * should be on a single row.
+     */
+    private int numCols;
+
+    /**
+     * List of IColumnInfo. The nth object is used to compute the width of the
+     * nth column, or null indicating that the default column should be used.
+     */
+    private List cols;
+
+    /**
+     * List of RowInfo. The nth object is used to compute the height of the
+     * nth row, or null indicating that the default row should be used.
+     */
+    private List rows = new ArrayList(16);
+
+    // Cached information
+    private GridInfo gridInfo = new GridInfo();
+
+    private int[] cachedRowMin = null;
+
+    private int[] cachedColMin = null;
+
+    public static int cacheMisses;
+
+    public static int cacheHits;
+
+    private LayoutCache cache = new LayoutCache();
+
+    // End of cached control sizes
+
+    /**
+     * Creates the layout
+     *
+     * @param numCols the number of columns in this layout,
+     * or 0 indicating that the whole layout should be on one row.
+     */
+    public CellLayout(int numCols) {
+        super();
+        this.numCols = numCols;
+        cols = new ArrayList(numCols == 0 ? 3 : numCols);
+    }
+
+    /**
+     * Sets the amount empty space between cells
+     *
+     * @param newSpacing a point (x,y) corresponding to the number of pixels of
+     * empty space between adjacent columns and rows respectively
+     */
+    public CellLayout setSpacing(int horizontalSpacing, int verticalSpacing) {
+        this.horizontalSpacing = horizontalSpacing;
+        this.verticalSpacing = verticalSpacing;
+
+        return this;
+    }
+
+    /**
+     * Sets the amount empty space between cells
+     *
+     * @param newSpacing a point (x,y) corresponding to the number of pixels of
+     * empty space between adjacent columns and rows respectively
+     */
+    public CellLayout setSpacing(Point newSpacing) {
+        horizontalSpacing = newSpacing.x;
+        verticalSpacing = newSpacing.y;
+        return this;
+    }
+
+    /**
+     * Returns the amount of empty space between adjacent cells
+     *
+     * @return a point (x,y) corresponding to the number of pixels of empty
+     * space between adjacent columns and rows respectively
+     */
+    public Point getSpacing() {
+        return new Point(horizontalSpacing, verticalSpacing);
+    }
+
+    /**
+     * Sets the size of the margin around the outside of the layout.
+     *
+     * @param marginWidth the size of the margin around the top and
+     * bottom of the layout
+     * @param marginHeight the size of the margin on the left and right
+     * of the layout.
+     */
+    public CellLayout setMargins(int marginWidth, int marginHeight) {
+        this.marginWidth = marginWidth;
+        this.marginHeight = marginHeight;
+        return this;
+    }
+
+    /**
+     * Sets the size of the margin around the outside of the layout.
+     *
+     * @param newMargins point indicating the size of the horizontal and vertical
+     * margins, in pixels.
+     */
+    public CellLayout setMargins(Point newMargins) {
+        marginWidth = newMargins.x;
+        marginHeight = newMargins.y;
+        return this;
+    }
+
+    /**
+     * Returns the size of the margins around the outside of the layout.
+     *
+     * @return the size of the outer margins, in pixels.
+     */
+    public Point getMargins() {
+        return new Point(marginWidth, marginHeight);
+    }
+
+    /**
+     * Sets the default column settings. All columns will use these settings unless
+     * they have been explicitly assigned custom settings by setColumn.
+     *
+     * @param info the properties of all default columns
+     * @see setColumn
+     */
+    public CellLayout setDefaultColumn(Row info) {
+        defaultColSettings = info;
+        return this;
+    }
+
+    /**
+     * Sets the column info for the given column number (the leftmost column is column 0).
+     * This replaces any existing info for the column. Note that more than one column
+     * are allowed to share the same IColumnInfo instance if they have identical properties.
+     *
+     * @param colNum the column number to modify
+     * @param info the properties of the column, or null if this column should use the
+     * default properties
+     */
+    public CellLayout setColumn(int colNum, Row info) {
+        while (cols.size() <= colNum) {
+            cols.add(null);
+        }
+
+        cols.set(colNum, info);
+
+        return this;
+    }
+
+    /**
+     * Sets the default row settings for this layout. Unless this is overridden
+     * for an individual row, all rows will use the default settings.
+     *
+     * @param info the row info object that should be used to set the size
+     * of rows, by default.
+     */
+    public CellLayout setDefaultRow(Row info) {
+        defaultRowSettings = info;
+
+        return this;
+    }
+
+    /**
+     * Sets the row info for the given rows. The topmost row is row 0. Multiple
+     * rows are allowed to share the same RowInfo instance.
+     *
+     * @param rowNum the row number to set
+     * @param info the row info that will control the sizing of the given row,
+     * or null if the row should use the default settings for this layout.
+     */
+    public CellLayout setRow(int rowNum, Row info) {
+        while (rows.size() <= rowNum) {
+            rows.add(null);
+        }
+
+        rows.set(rowNum, info);
+
+        return this;
+    }
+
+    /**
+     * Returns the row info that controls the size of the given row. Will return
+     * the default row settings for this layout if no custom row info has been
+     * assigned to the row.
+     *
+     * @param rowNum
+     * @return
+     */
+    private Row getRow(int rowNum, boolean isHorizontal) {
+        if (isHorizontal) {
+            if (rowNum >= rows.size()) {
+                return defaultRowSettings;
+            }
+
+            Row result = (Row) rows.get(rowNum);
+
+            if (result == null) {
+                result = defaultRowSettings;
+            }
+
+            return result;
+        } else {
+            if (rowNum >= cols.size()) {
+                return defaultColSettings;
+            }
+
+            Row result = (Row) cols.get(rowNum);
+
+            if (result == null) {
+                result = defaultColSettings;
+            }
+
+            return result;
+        }
+    }
+
+    /**
+     * Initializes the gridInfo object.
+     *
+     * @param children controls that are being layed out
+     */
+    private void initGrid(Control[] children) {
+        cache.setControls(children);
+        gridInfo.initGrid(children, this);
+        cachedRowMin = null;
+        cachedColMin = null;
+    }
+
+    @Override
+	protected Point computeSize(Composite composite, int wHint, int hHint,
+            boolean flushCache) {
+        Control[] children = composite.getChildren();
+        initGrid(children);
+
+        if (flushCache) {
+            cache.flush();
+        }
+
+        // Determine the amount of whitespace (area that cannot be used by controls)
+        Point emptySpace = totalEmptySpace();
+
+        int[] heightConstraints = computeConstraints(true);
+
+        int width;
+        if (wHint == SWT.DEFAULT) {
+            width = preferredSize(heightConstraints, false);
+        } else {
+            width = wHint - emptySpace.x;
+        }
+
+        int height = hHint;
+        if (hHint == SWT.DEFAULT) {
+            height = preferredSize(
+                    computeSizes(heightConstraints, width, false), true);
+        } else {
+            height = hHint - emptySpace.y;
+        }
+
+        Point preferredSize = new Point(width + emptySpace.x, height
+                + emptySpace.y);
+
+        // At this point we know the layout's preferred size. Now adjust it
+        // if we're smaller than the minimum possible size for the composite.
+
+        // If exactly one dimension of our preferred size is smaller than
+        // the minimum size of our composite, then set that dimension to
+        // the minimum size and recompute the other dimension (for example,
+        // increasing the width to match a shell's minimum width may reduce
+        // the height allocated for a wrapping text widget). There is no
+        // point in doing this if both dimensions are smaller than the
+        // composite's minimum size, since we're already smaller than
+        // we need to be.
+        Point minimumSize = CellLayoutUtil.computeMinimumSize(composite);
+
+        boolean wider = (preferredSize.x >= minimumSize.x);
+        boolean taller = (preferredSize.y >= minimumSize.y);
+
+        if (wider) {
+            if (taller) {
+                // If we're larger in both dimensions, don't adjust the minimum
+                // size.
+                return preferredSize;
+            } else {
+                // If our preferred height is smaller than the minimum height,
+                // recompute the preferred width using the minimum height
+                return computeSize(composite, wHint, minimumSize.y, false);
+            }
+        } else {
+            if (taller) {
+                // If our preferred width is smaller than the minimum width,
+                // recompute the preferred height using the minimum width
+                return computeSize(composite, minimumSize.x, hHint, false);
+            } else {
+                // If both dimensions are smaller than the minimum size,
+                // use the minimum size as our preferred size.
+                return minimumSize;
+            }
+        }
+    }
+
+    int[] computeSizes(int[] constraints, int availableSpace,
+            boolean computingRows) {
+        int[] result = computeMinSizes(constraints, computingRows);
+
+        int totalFixed = sumOfSizes(result);
+        int denominator = getResizeDenominator(computingRows);
+        int numRows = gridInfo.getNumRows(computingRows);
+
+        if (totalFixed < availableSpace) {
+            int remaining = availableSpace - totalFixed;
+
+            for (int idx = 0; idx < numRows && denominator > 0; idx++) {
+                Row row = getRow(idx, computingRows);
+
+                if (row.grows) {
+                    int greed = row.size;
+                    int amount = remaining * greed / denominator;
+
+                    result[idx] += amount;
+                    remaining -= amount;
+                    denominator -= greed;
+                }
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Computes one dimension of the preferred size of the layout.
+     *
+     * @param hint contains the result if already known, or SWT.DEFAULT if it needs to be computed
+     * @param constraints contains constraints along the other dimension, or SWT.DEFAULT if none. For
+     * example, if we are computing the preferred row sizes, this would be an array of known column sizes.
+     * @param computingRows if true, this method returns the height (pixels). Otherwise, it returns the
+     * width (pixels).
+     */
+    int preferredSize(int[] constraints, boolean computingRows) {
+        int[] fixedSizes = computeMinSizes(constraints, computingRows);
+
+        return sumOfSizes(fixedSizes)
+                + getDynamicSize(constraints, fixedSizes, computingRows);
+    }
+
+    /**
+     * Computes the sum of all integers in the given array. If any of the entries are SWT.DEFAULT,
+     * the result is SWT.DEFAULT.
+     */
+    static int sumOfSizes(int[] input) {
+        return sumOfSizes(input, 0, input.length);
+    }
+
+    static int sumOfSizes(int[] input, int start, int length) {
+        int sum = 0;
+        for (int idx = start; idx < start + length; idx++) {
+            int next = input[idx];
+
+            if (next == SWT.DEFAULT) {
+                return SWT.DEFAULT;
+            }
+
+            sum += next;
+        }
+
+        return sum;
+    }
+
+    /**
+     * Returns the preferred dynamic width of the layout
+     *
+     * @param constraints
+     * @param fixedSizes
+     * @param computingRows
+     * @return
+     */
+    int getDynamicSize(int[] constraints, int[] fixedSizes,
+            boolean computingRows) {
+        int result = 0;
+        int numerator = getResizeDenominator(computingRows);
+
+        // If no resizable columns, return
+        if (numerator == 0) {
+            return 0;
+        }
+
+        int rowSpacing = computingRows ? verticalSpacing : horizontalSpacing;
+        int colSpacing = computingRows ? horizontalSpacing : verticalSpacing;
+
+        int numControls = gridInfo.controls.length;
+        for (int idx = 0; idx < numControls; idx++) {
+            int controlRowStart = gridInfo.getStartPos(idx, computingRows);
+            int controlRowSpan = getSpan(idx, computingRows);
+            int controlColStart = gridInfo.getStartPos(idx, !computingRows);
+            int controlColSpan = getSpan(idx, !computingRows);
+
+            int denominator = getGrowthRatio(controlRowStart, controlRowSpan,
+                    computingRows);
+
+            if (denominator > 0) {
+
+                int widthHint = sumOfSizes(constraints, controlColStart,
+                        controlColSpan);
+                if (widthHint != SWT.DEFAULT) {
+                    widthHint += colSpacing * (controlColSpan - 1);
+                }
+
+                // Compute the total control size
+                int controlSize = computeControlSize(idx, widthHint,
+                        computingRows);
+
+                // Subtract the amount that overlaps fixed-size columns
+                controlSize -= sumOfSizes(fixedSizes, controlRowStart,
+                        controlRowSpan);
+
+                // Subtract the amount that overlaps spacing between cells
+                controlSize -= (rowSpacing * (controlRowSpan - 1));
+
+                result = Math
+                        .max(result, controlSize * numerator / denominator);
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Computes one dimension of a control's size
+     *
+     * @param control the index of the control being computed
+     * @param constraint the other dimension of the control's size, or SWT.DEFAULT if unknown
+     * @param computingHeight if true, this method returns a height. Else it returns a width
+     * @return the preferred height or width of the control, in pixels
+     */
+    int computeControlSize(int control, int constraint, boolean computingHeight) {
+        CellData data = gridInfo.getCellData(control);
+
+        // If we're looking for the preferred size of the control (without hints)
+        if (constraint == SWT.DEFAULT) {
+            Point result = data.computeSize(cache.getCache(control),
+                    SWT.DEFAULT, SWT.DEFAULT);
+
+            // Return result
+            if (computingHeight) {
+                return result.y;
+            }
+            return result.x;
+        }
+
+        // Compute a height
+        if (computingHeight) {
+            return data.computeSize(cache.getCache(control), constraint,
+                    SWT.DEFAULT).y;
+        }
+
+        return data.computeSize(cache.getCache(control), SWT.DEFAULT,
+                constraint).x;
+    }
+
+    /**
+     * Returns the relative amount that a control starting on the given row and spanning
+     * the given length will contribute
+     *
+     * @param start
+     * @param length
+     * @param computingRows
+     * @return
+     */
+    int getGrowthRatio(int start, int length, boolean computingRows) {
+        boolean willGrow = false;
+        int sum = 0;
+
+        int end = start + length;
+        for (int idx = start; idx < end; idx++) {
+            Row row = getRow(idx, computingRows);
+
+            if (row.largerThanChildren && row.grows) {
+                willGrow = true;
+            }
+
+            sum += row.size;
+        }
+
+        if (!willGrow) {
+            return 0;
+        }
+
+        return sum;
+    }
+
+    int[] computeMinSizes(int[] constraints, boolean computingRows) {
+        // We cache the result of this function since it might be called more than once
+        // for a single size computation
+        int[] result = computingRows ? cachedRowMin : cachedColMin;
+
+        if (result == null) {
+            int columnSpacing;
+            int rowSpacing;
+
+            if (computingRows) {
+                columnSpacing = horizontalSpacing;
+                rowSpacing = verticalSpacing;
+            } else {
+                columnSpacing = verticalSpacing;
+                rowSpacing = horizontalSpacing;
+            }
+
+            int rowCount = gridInfo.getNumRows(computingRows);
+            result = new int[rowCount];
+            int colCount = gridInfo.getNumRows(!computingRows);
+            int[] rowControls = new int[colCount];
+
+            int lastGrowingRow = -1;
+
+            for (int idx = 0; idx < rowCount; idx++) {
+                Row row = getRow(idx, computingRows);
+
+                if (row.grows) {
+                    // There is no minimum size for growing rows
+                    lastGrowingRow = idx;
+                    result[idx] = 0;
+                } else {
+                    result[idx] = row.size;
+
+                    if (row.largerThanChildren) {
+                        // Determine which controls are in this row
+                        gridInfo.getRow(rowControls, idx, computingRows);
+
+                        for (int control : rowControls) {
+                            // The getRow method will insert -1 into empty cells... skip these.
+                            if (control != -1) {
+                                int controlStart = gridInfo.getStartPos(
+                                        control, computingRows);
+                                int controlSpan = getSpan(control,
+                                        computingRows);
+
+                                // If the control ends on this row and does not span any growing rows
+                                if (controlStart + controlSpan - 1 == idx
+                                        && controlStart > lastGrowingRow) {
+                                    int controlColStart = gridInfo.getStartPos(
+                                            control, !computingRows);
+                                    int controlColSpan = getSpan(control,
+                                            !computingRows);
+                                    int controlRowSpan = getSpan(control,
+                                            computingRows);
+
+                                    // Compute the width constraint for this control
+                                    int spannedWidth = sumOfSizes(constraints,
+                                            controlColStart, controlColSpan);
+                                    if (spannedWidth != SWT.DEFAULT) {
+                                        spannedWidth += (columnSpacing * (controlSpan - 1));
+                                    }
+
+                                    int controlHeight = computeControlSize(
+                                            control, spannedWidth,
+                                            computingRows);
+
+                                    // Determine how much of the control spans already allocated columns
+                                    int allocatedHeight = sumOfSizes(result,
+                                            controlColStart, controlRowSpan - 1)
+                                            + (rowSpacing * (controlRowSpan - 1));
+
+                                    result[idx] = Math.max(result[idx],
+                                            controlHeight - allocatedHeight);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        // Cache this result
+        if (computingRows) {
+            cachedRowMin = result;
+        } else {
+            cachedColMin = result;
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns the height constraints that should be used when computing column widths. Requires initGrid
+     * to have been called first.
+     *
+     * @param result Will contain the height constraint for row i in the ith position of the array,
+     * or SWT.DEFAULT if there is no constraint on that row.
+     */
+    private int[] computeConstraints(boolean horizontal) {
+        // Initialize the height constraints for each row (basically, these will always be SWT.DEFAULT,
+        // except for rows of type FixedRow, which have a constant height).
+        int numRows = gridInfo.getNumRows(horizontal);
+        int[] result = new int[numRows];
+
+        for (int idx = 0; idx < numRows; idx++) {
+            Row row = getRow(idx, horizontal);
+
+            if (!(row.grows || row.largerThanChildren)) {
+                result[idx] = row.size;
+            } else {
+                result[idx] = SWT.DEFAULT;
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Computes the total greediness of all rows
+     *
+     * @return the total greediness of all rows
+     */
+    private int getResizeDenominator(boolean horizontal) {
+        int result = 0;
+        int numRows = gridInfo.getNumRows(horizontal);
+
+        for (int idx = 0; idx < numRows; idx++) {
+            Row row = getRow(idx, horizontal);
+
+            if (row.grows) {
+                result += row.size;
+            }
+        }
+
+        return result;
+    }
+
+    //	/**
+    //	 * Computes the total fixed height of all rows
+    //	 *
+    //	 * @param widthConstraints array where the nth entry indicates the known width of the
+    //	 * nth column, or SWT.DEFAULT if the width is still unknown
+    //	 *
+    //	 * @return the total fixed height for all rows
+    //	 */
+    //	private int getMinimumSize(int[] constraints, boolean horizontal) {
+    //		Control[] controls = new Control[gridInfo.getRows()];
+    //		int result = 0;
+    //		int numRows = gridInfo.getRows();
+    //
+    //		for (int idx = 0; idx < numRows; idx++) {
+    //			result += getRow(idx).getFixedHeight(gridInfo, widthConstraints, idx);
+    //		}
+    //
+    //		return result;
+    //	}
+
+    protected int getSpan(int controlId, boolean isRow) {
+        CellData data = gridInfo.getCellData(controlId);
+
+        if (isRow) {
+            return data.verticalSpan;
+        }
+        return data.horizontalSpan;
+    }
+
+    /**
+     * Returns the total space that will be required for margins and spacing between and
+     * around cells. initGrid(...) must have been called first.
+     *
+     * @return
+     */
+    private Point totalEmptySpace() {
+        int numRows = gridInfo.getRows();
+
+        return new Point((2 * marginWidth)
+                + ((gridInfo.getCols() - 1) * horizontalSpacing),
+                (2 * marginHeight) + ((numRows - 1) * verticalSpacing));
+    }
+
+    /**
+     * Returns the absolute positions of each row, given the start position, row sizes,
+     * and row spacing
+     *
+     * @param startPos position of the initial row
+     * @param sizes array of row sizes (pixels)
+     * @param spacing space between each row (pixels)
+     * @return array of row positions. The result size is sizes.length + 1. The last entry is
+     * the position of the end of the layout.
+     */
+    private static int[] computeRowPositions(int startPos, int[] sizes,
+            int spacing) {
+        int[] result = new int[sizes.length + 1];
+
+        result[0] = startPos;
+        for (int idx = 0; idx < sizes.length; idx++) {
+            result[idx + 1] = result[idx] + sizes[idx] + spacing;
+        }
+
+        return result;
+    }
+
+    @Override
+	protected void layout(Composite composite, boolean flushCache) {
+        Control[] children = composite.getChildren();
+
+        // If there are no children then this is a NO-OP
+        if (children.length == 0)
+        	return;
+
+        initGrid(children);
+
+        if (flushCache) {
+            cache.flush();
+        }
+
+        Point emptySpace = totalEmptySpace();
+
+        // Compute the area actually available for controls (once the margins and spacing is removed)
+        int availableWidth = composite.getClientArea().width - emptySpace.x;
+        int availableHeight = composite.getClientArea().height - emptySpace.y;
+
+        int[] heights = computeConstraints(true);
+        int[] widths = new int[gridInfo.getCols()];
+
+        // Compute the actual column widths
+        widths = computeSizes(heights, availableWidth, false);
+
+        // Compute the actual row heights (based on the actual column widths)
+        heights = computeSizes(widths, availableHeight, true);
+
+        Rectangle currentCell = new Rectangle(0, 0, 0, 0);
+
+        int[] starty = computeRowPositions(composite.getClientArea().y
+                + marginHeight, heights, verticalSpacing);
+        int[] startx = computeRowPositions(composite.getClientArea().x
+                + marginWidth, widths, horizontalSpacing);
+
+        int numChildren = gridInfo.controls.length;
+        for (int controlId = 0; controlId < numChildren; controlId++) {
+            CellData data = gridInfo.getCellData(controlId);
+
+            int row = gridInfo.controlRow[controlId];
+            int col = gridInfo.controlCol[controlId];
+
+            currentCell.x = startx[col];
+            currentCell.width = startx[col + data.horizontalSpan]
+                    - currentCell.x - horizontalSpacing;
+
+            currentCell.y = starty[row];
+            currentCell.height = starty[row + data.verticalSpan]
+                    - currentCell.y - verticalSpacing;
+
+            data.positionControl(cache.getCache(controlId), currentCell);
+        }
+    }
+
+    /**
+     * @return
+     */
+    public int getColumns() {
+        return numCols;
+    }
+
+    public boolean canGrow(Composite composite, boolean horizontally) {
+        initGrid(composite.getChildren());
+
+        int numRows = gridInfo.getNumRows(horizontally);
+
+        for (int idx = 0; idx < numRows; idx++) {
+            Row row = getRow(idx, horizontally);
+
+            if (row.grows) {
+                return true;
+            }
+        }
+
+        return false;
+
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/layout/CellLayoutUtil.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/layout/CellLayoutUtil.java
new file mode 100644
index 0000000..c997611
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/layout/CellLayoutUtil.java
@@ -0,0 +1,112 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.layout;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * Contains helper methods for CellLayout. Many of these methods are workarounds for
+ * known SWT bugs. They should be updated once the original bugs are fixed in SWT.
+ *
+ * @since 3.0
+ */
+class CellLayoutUtil {
+
+    private static Point zero = new Point(0, 0);
+
+    private static Point minimumShellSize;
+
+    private static CellData defaultData = new CellData();
+
+    /**
+     * Returns the minimum size for the given composite. That is,
+     * this returns the smallest values that will have any effect
+     * when passed into the composite's setSize method. Passing any
+     * smaller value is equivalent to passing the minimum size.
+     * <p>
+     * This method is intended for use by layouts. The layout can
+     * use this information when determining its preferred size.
+     * Returning a preferred size smaller than the composite's
+     * minimum size is pointless since the composite could never
+     * be set to that size. The layout may choose a different preferred
+     * size in this situation.
+     * </p><p>
+     * Note that this method is only concerned with restrictions imposed
+     * by the composite; not it's layout. If the only restriction on the
+     * composite's size is imposed by the layout, then this method returns (0,0).
+     * </p><p>
+     * Currently SWT does not expose this information through
+     * API, so this method is developed using trial-and-error. Whenever
+     * a composite is discovered that will not accept sizes below
+     * a certain threshold on some platform, this method should be
+     * updated to reflect that fact.
+     * </p><p>
+     * At this time, the only known composite that has a minimum size
+     * are Shells.
+     * </p>
+     *
+     * @param toCompute the composite whose minimum size is being computed
+     * @return a size, in pixels, which is the smallest value that can be
+     * passed into the composite's setSize(...) method.
+     */
+    static Point computeMinimumSize(Composite toCompute) {
+        if (toCompute instanceof Shell) {
+            if (minimumShellSize == null) {
+                Shell testShell = new Shell((Shell) toCompute, SWT.DIALOG_TRIM
+                        | SWT.RESIZE);
+                testShell.setSize(0, 0);
+                minimumShellSize = testShell.getSize();
+                testShell.dispose();
+            }
+
+            return minimumShellSize;
+        }
+
+        // If any other composites are discovered to have minimum sizes,
+        // add heuristics for them here.
+
+        // Otherwise, the composite can be reduced to size (0,0)
+
+        return zero;
+    }
+
+    /**
+     * Returns the CellData associated with the given control. If the control
+     * does not have any layout data associated with it, a default object is returned.
+     * If the control has a GridData object associated with it, an equivalent
+     * CellData object will be returned.
+     *
+     * @param control
+     * @return
+     */
+    static CellData getData(Control control) {
+        Object layoutData = control.getLayoutData();
+        CellData data = null;
+
+        if (layoutData instanceof CellData) {
+            data = (CellData) layoutData;
+        } else if (layoutData instanceof GridData) {
+            data = new CellData((GridData) layoutData);
+        }
+
+        if (data == null) {
+            data = defaultData;
+        }
+
+        return data;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/layout/GridInfo.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/layout/GridInfo.java
new file mode 100644
index 0000000..8b6ede6
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/layout/GridInfo.java
@@ -0,0 +1,171 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.layout;
+
+import org.eclipse.swt.widgets.Control;
+
+/**
+ * Computes and the positions of controls in a CellLayout, based on their span.
+ */
+class GridInfo {
+    private int cols = 0;
+
+    private int rows = 0;
+
+    private int[] gridInfo;
+
+    int[] controlRow;
+
+    int[] controlCol;
+
+    private CellData[] cellData;
+
+    Control[] controls;
+
+    /**
+     * Initialize the grid
+     *
+     * @param newControls
+     * @param cols
+     */
+    public void initGrid(Control[] newControls, CellLayout layout) {
+        cols = layout.getColumns();
+        controls = newControls;
+
+        int area = 0;
+        int totalWidth = 0;
+
+        controlRow = new int[controls.length];
+        controlCol = new int[controls.length];
+
+        // Get the CellData objects for each control, and compute
+        // the total number of cells spanned by controls in this layout.
+        cellData = new CellData[controls.length];
+        for (int idx = 0; idx < controls.length; idx++) {
+            if (controls[idx] == null) {
+                continue;
+            }
+
+            CellData next = CellLayoutUtil.getData(controls[idx]);
+            cellData[idx] = next;
+            area += next.horizontalSpan * next.verticalSpan;
+            totalWidth += next.horizontalSpan;
+        }
+
+        // Compute the number of columns
+        if (cols == 0) {
+            cols = totalWidth;
+        }
+
+        // Compute the number of rows
+        rows = area / cols;
+        if (area % cols > 0) {
+            // Ensure we count any partial rows
+            rows++;
+        }
+
+        area = rows * cols;
+
+        // Allocate the gridInfo array
+        gridInfo = new int[area];
+        for (int idx = 0; idx < area; idx++) {
+            gridInfo[idx] = -1;
+        }
+
+        int infoIdx = 0;
+        // Compute the positions of each control
+        for (int idx = 0; idx < controls.length; idx++) {
+            CellData data = cellData[idx];
+
+            // Find an empty position to insert the control
+            while (gridInfo[infoIdx] >= 0) {
+                infoIdx++;
+            }
+
+            controlRow[idx] = infoIdx / cols;
+            controlCol[idx] = infoIdx % cols;
+
+            // Insert the new control here
+            for (int rowIdx = 0; rowIdx < data.verticalSpan; rowIdx++) {
+                for (int colIdx = 0; colIdx < data.horizontalSpan; colIdx++) {
+                    gridInfo[infoIdx + rowIdx * cols + colIdx] = idx;
+                }
+            }
+
+            infoIdx += data.horizontalSpan;
+        }
+    }
+
+    public int getRows() {
+        return rows;
+    }
+
+    public int getStartPos(int control, boolean row) {
+        if (row) {
+            return controlRow[control];
+        } else {
+            return controlCol[control];
+        }
+    }
+
+    /**
+     * Returns the number of rows or columns
+     *
+     * @param isRow if true, returns the number of rows. If false, returns the number of columns
+     * @return
+     */
+    public int getNumRows(boolean isRow) {
+        if (isRow) {
+            return rows;
+        } else {
+			return cols;
+		}
+    }
+
+    public void getRow(int[] result, int rowId, boolean horizontal) {
+        if (horizontal) {
+            int prev = -1;
+            for (int colIdx = 0; colIdx < cols; colIdx++) {
+                int next = gridInfo[cols * rowId + colIdx];
+
+                if (prev == next) {
+                    result[colIdx] = -1;
+                } else {
+					result[colIdx] = next;
+				}
+
+                prev = next;
+            }
+        } else {
+            int prev = -1;
+            for (int rowIdx = 0; rowIdx < rows; rowIdx++) {
+                int next = gridInfo[cols * rowIdx + rowId];
+
+                if (prev == next) {
+                    result[rowIdx] = -1;
+                } else {
+					result[rowIdx] = next;
+				}
+
+                prev = next;
+            }
+        }
+    }
+
+    public CellData getCellData(int controlId) {
+        return cellData[controlId];
+    }
+
+    public int getCols() {
+        return cols;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/layout/ICachingLayout.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/layout/ICachingLayout.java
new file mode 100644
index 0000000..41c7d3e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/layout/ICachingLayout.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.layout;
+
+import org.eclipse.swt.widgets.Control;
+
+/**
+ * Layouts that implement this interface are capable of caching the
+ * sizes of child controls in a manner that allows the information
+ * for a single control to be flushed without affecting the remaining
+ * controls. These layouts will ignore the "changed" arguments to layout(...)
+ * and computeSize(...), however they will flush their cache for individual
+ * controls when the flush(...) method is called.
+ * <p>
+ * This allows for much more efficient layouts, since most of the cache
+ * can be reused when a child control changes.
+ * </p>
+ *
+ * @since 3.0
+ */
+public interface ICachingLayout {
+    /**
+     * Flushes cached data for the given control
+     */
+    public void flush(Control dirtyControl);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/layout/LayoutCache.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/layout/LayoutCache.java
new file mode 100644
index 0000000..3d164e6
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/layout/LayoutCache.java
@@ -0,0 +1,120 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.layout;
+
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Control;
+
+/**
+ * Caches the preferred sizes of an array of controls
+ *
+ * @since 3.0
+ */
+public class LayoutCache {
+    private SizeCache[] caches = new SizeCache[0];
+
+    /**
+     * Creates an empty layout cache
+     */
+    public LayoutCache() {
+    }
+
+    /**
+     * Creates a cache for the given array of controls
+     *
+     * @param controls
+     */
+    public LayoutCache(Control[] controls) {
+        rebuildCache(controls);
+    }
+
+    /**
+     * Returns the size cache for the given control
+     *
+     * @param idx
+     * @return
+     */
+    public SizeCache getCache(int idx) {
+        return caches[idx];
+    }
+
+    /**
+     * Sets the controls that are being cached here. If these are the same
+     * controls that were used last time, this method does nothing. Otherwise,
+     * the cache is flushed and a new cache is created for the new controls.
+     *
+     * @param controls
+     */
+    public void setControls(Control[] controls) {
+        // If the number of controls has changed, discard the entire cache
+        if (controls.length != caches.length) {
+            rebuildCache(controls);
+            return;
+        }
+
+        for (int idx = 0; idx < controls.length; idx++) {
+            caches[idx].setControl(controls[idx]);
+        }
+    }
+
+    /**
+     * Creates a new size cache for the given set of controls, discarding any
+     * existing cache.
+     *
+     * @param controls the controls whose size is being cached
+     */
+    private void rebuildCache(Control[] controls) {
+        SizeCache[] newCache = new SizeCache[controls.length];
+
+        for (int idx = 0; idx < controls.length; idx++) {
+            // Try to reuse existing caches if possible
+            if (idx < caches.length) {
+                newCache[idx] = caches[idx];
+                newCache[idx].setControl(controls[idx]);
+            } else {
+                newCache[idx] = new SizeCache(controls[idx]);
+            }
+        }
+
+        caches = newCache;
+    }
+
+    /**
+     * Computes the preferred size of the nth control
+     *
+     * @param controlIndex index of the control whose size will be computed
+     * @param widthHint width of the control (or SWT.DEFAULT if unknown)
+     * @param heightHint height of the control (or SWT.DEFAULT if unknown)
+     * @return the preferred size of the control
+     */
+    public Point computeSize(int controlIndex, int widthHint, int heightHint) {
+        return caches[controlIndex].computeSize(widthHint, heightHint);
+    }
+
+    /**
+     * Flushes the cache for the given control. This should be called if exactly
+     * one of the controls has changed but the remaining controls remain unmodified
+     *
+     * @param controlIndex
+     */
+    public void flush(int controlIndex) {
+        caches[controlIndex].flush();
+    }
+
+    /**
+     * Flushes the cache.
+     */
+    public void flush() {
+        for (SizeCache cache : caches) {
+            cache.flush();
+        }
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/layout/LayoutUtil.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/layout/LayoutUtil.java
new file mode 100644
index 0000000..91b516d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/layout/LayoutUtil.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.layout;
+
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Layout;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * Contains various methods for manipulating layouts
+ *
+ * @since 3.0
+ */
+public class LayoutUtil {
+
+    /**
+     * Should be called whenever a control's contents have changed. Will
+     * trigger a layout parent controls if necessary.
+     *
+     * @param changedControl
+     */
+    public static void resize(Control changedControl) {
+        Composite parent = changedControl.getParent();
+
+        Layout parentLayout = parent.getLayout();
+
+        if (parentLayout instanceof ICachingLayout) {
+            ((ICachingLayout) parentLayout).flush(changedControl);
+        }
+
+        if (parent instanceof Shell) {
+            parent.layout(true);
+        } else {
+            Rectangle currentBounds = parent.getBounds();
+
+            resize(parent);
+
+            // If the parent was resized, then it has already triggered a
+            // layout. Otherwise, we need to manually force it to layout again.
+            if (currentBounds.equals(parent.getBounds())) {
+                parent.layout(true);
+            }
+        }
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/layout/Row.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/layout/Row.java
new file mode 100644
index 0000000..ca09f19
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/layout/Row.java
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.layout;
+
+/**
+ * Describes a single row (or column) in a CellLayout
+ *
+ * @since 3.0
+ */
+public class Row {
+    /**
+     * True iff this row will expand to fill available space
+     */
+    boolean grows = false;
+
+    /**
+     * Size of this row. For growing rows, this is the relative size
+     * of the row with respect to other rows (ie: a row of size 100 is twice
+     * as wide as a row of size 50). For fixed rows, this is the absolute size
+     * of the row, in pixels.
+     */
+    int size = 0;
+
+    /**
+     * True iff this row should query its child controls for its size.
+     */
+    boolean largerThanChildren = true;
+
+    /**
+     * Creates a fixed-size row with the given width (pixels).
+     * The preferred sizes of child controls are ignored.
+     *
+     * @param size
+     */
+    public Row(int size) {
+        largerThanChildren = false;
+        this.size = size;
+        grows = false;
+    }
+
+    /**
+     * Creates a row that automatically computes its size based on the preferred
+     * sizes of its children.
+     *
+     * @param growing
+     */
+    public Row(boolean growing) {
+        this.grows = growing;
+
+        if (growing) {
+            size = 100;
+        }
+    }
+
+    /**
+     * Creates a growing row.
+     *
+     * @param sizeRatio determines the size of this row with respect to other growing rows
+     * (for example, a row with size = 3 will be 3x as large as a row with size = 1)
+     * @param largerThanChildren true iff the preferred size of this row should take into
+     * account the preferred sizes of its children.
+     */
+    public Row(int size, boolean largerThanChildren) {
+        this.grows = true;
+        this.size = size;
+        this.largerThanChildren = largerThanChildren;
+    }
+
+    /**
+     * Construct and return a typical growing row.
+     *
+     * @return a growing row
+     */
+    public static Row growing() {
+        return new Row(100, true);
+    }
+
+    /**
+     * Construct and return a growing row with custom properties
+     *
+     * @param size relative size of this row with respect to other growing rows
+     * @param largerThanChildren true iff the preferred size of this row should
+     * be based on the preferred sizes of its children
+     * @return a new Row
+     */
+    public static Row growing(int size, boolean largerThanChildren) {
+        return new Row(size, largerThanChildren);
+    }
+
+    /**
+     * Construct and return a fixed-size row. The row will not grow when the layout
+     * is resized, and its size will be computed from the default sizes of its children.
+     *
+     * @return a new Row
+     */
+    public static Row fixed() {
+        return new Row(false);
+    }
+
+    /**
+     * Construct and return a fixed-size row. The row will always have the given
+     * width, regardless of the size of the layout or the preferred sizes of its children.
+     *
+     * @param pixels size of the row
+     * @return a fixed-size row with the given width (in pixels)
+     */
+    public static Row fixed(int pixels) {
+        return new Row(pixels);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/layout/SizeCache.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/layout/SizeCache.java
new file mode 100644
index 0000000..d596208
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/layout/SizeCache.java
@@ -0,0 +1,364 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.layout;
+
+import java.util.List;
+
+import org.eclipse.jface.util.Geometry;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.ProgressBar;
+import org.eclipse.swt.widgets.Sash;
+import org.eclipse.swt.widgets.Scale;
+import org.eclipse.swt.widgets.Slider;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.Tree;
+
+/**
+ * Caches the preferred size of an SWT control
+ *
+ * @since 3.0
+ */
+public class SizeCache {
+    private Control control;
+
+    private Point preferredSize;
+
+    private Point cachedWidth;
+
+    private Point cachedHeight;
+
+    /**
+     * True iff we should recursively flush all children on the next layout
+     */
+    private boolean flushChildren;
+
+    /**
+     * True iff changing the height hint does not affect the preferred width and changing
+     * the width hint does not change the preferred height
+     */
+    private boolean independentDimensions = false;
+
+    /**
+     * True iff the preferred height for any hint larger than the preferred width will not
+     * change the preferred height.
+     */
+    private boolean preferredWidthOrLargerIsMinimumHeight = false;
+
+    // HACK: these values estimate how much to subtract from the width and height
+    // hints that get passed into computeSize, in order to produce a result
+    // that is exactly the desired size. To be removed once bug 46112 is fixed (note:
+    // bug 46112 is currently flagged as a duplicate, but there is still no workaround).
+    private int widthAdjustment = 0;
+
+    private int heightAdjustment = 0;
+
+    // END OF HACK
+
+    public SizeCache() {
+        this(null);
+    }
+
+    /**
+     * Creates a cache for size computations on the given control
+     *
+     * @param control the control for which sizes will be calculated,
+     * or null to always return (0,0)
+     */
+    public SizeCache(Control control) {
+        setControl(control);
+    }
+
+    /**
+     * Sets the control whose size is being cached. Does nothing (will not
+     * even flush the cache) if this is the same control as last time.
+     *
+     * @param newControl the control whose size is being cached, or null to always return (0,0)
+     */
+    public void setControl(Control newControl) {
+        if (newControl != control) {
+            control = newControl;
+            if (control == null) {
+                independentDimensions = true;
+                preferredWidthOrLargerIsMinimumHeight = false;
+                widthAdjustment = 0;
+                heightAdjustment = 0;
+            } else {
+                independentDimensions = independentLengthAndWidth(control);
+                preferredWidthOrLargerIsMinimumHeight = isPreferredWidthMaximum(control);
+                computeHintOffset(control);
+                flush();
+            }
+        }
+    }
+
+    /**
+     * Returns the control whose size is being cached
+     *
+     * @return the control whose size is being cached, or null if this cache always returns (0,0)
+     */
+    public Control getControl() {
+        return control;
+    }
+
+    /**
+     * Flush the cache (should be called if the control's contents may have changed since the
+     * last query)
+     */
+    public void flush() {
+        flush(true);
+    }
+
+    public void flush(boolean recursive) {
+        preferredSize = null;
+        cachedWidth = null;
+        cachedHeight = null;
+        this.flushChildren = recursive;
+    }
+
+    private Point getPreferredSize() {
+        if (preferredSize == null) {
+            preferredSize = computeSize(control, SWT.DEFAULT, SWT.DEFAULT);
+        }
+
+        return preferredSize;
+    }
+
+    /**
+     * Computes the preferred size of the control.
+     *
+     * @param widthHint the known width of the control (pixels) or SWT.DEFAULT if unknown
+     * @param heightHint the known height of the control (pixels) or SWT.DEFAULT if unknown
+     * @return the preferred size of the control
+     */
+    public Point computeSize(int widthHint, int heightHint) {
+        if (control == null) {
+            return new Point(0, 0);
+        }
+
+        // If both dimensions were supplied in the input, return them verbatim
+        if (widthHint != SWT.DEFAULT && heightHint != SWT.DEFAULT) {
+            return new Point(widthHint, heightHint);
+        }
+
+        // No hints given -- find the preferred size
+        if (widthHint == SWT.DEFAULT && heightHint == SWT.DEFAULT) {
+            return Geometry.copy(getPreferredSize());
+        }
+
+        // If the length and width are independent, compute the preferred size
+        // and adjust whatever dimension was supplied in the input
+        if (independentDimensions) {
+            Point result = Geometry.copy(getPreferredSize());
+
+            if (widthHint != SWT.DEFAULT) {
+                result.x = widthHint;
+            }
+
+            if (heightHint != SWT.DEFAULT) {
+                result.y = heightHint;
+            }
+
+            return result;
+        }
+
+        // Computing a height
+        if (heightHint == SWT.DEFAULT) {
+            // If we know the control's preferred size
+            if (preferredSize != null) {
+                // If the given width is the preferred width, then return the preferred size
+                if (widthHint == preferredSize.x) {
+                    return Geometry.copy(preferredSize);
+                }
+            }
+
+            // If we have a cached height measurement
+            if (cachedHeight != null) {
+                // If this was measured with the same width hint
+                if (cachedHeight.x == widthHint) {
+                    return Geometry.copy(cachedHeight);
+                }
+            }
+
+            // If this is a control where any hint larger than the
+            // preferred width results in the minimum height, determine if
+            // we can compute the result based on the preferred height
+            if (preferredWidthOrLargerIsMinimumHeight) {
+                // Computed the preferred size (if we don't already know it)
+                getPreferredSize();
+
+                // If the width hint is larger than the preferred width, then
+                // we can compute the result from the preferred width
+                if (widthHint >= preferredSize.x) {
+                    Point result = Geometry.copy(preferredSize);
+                    result.x = widthHint;
+                    return result;
+                }
+            }
+
+            // Else we can't find an existing size in the cache, so recompute
+            // it from scratch.
+            cachedHeight = computeSize(control, widthHint, heightHint);
+
+            return Geometry.copy(cachedHeight);
+        }
+
+        // Computing a width
+        if (widthHint == SWT.DEFAULT) {
+            // If we know the control's preferred size
+            if (preferredSize != null) {
+                // If the given height is the preferred height, then return the preferred size
+                if (heightHint == preferredSize.y) {
+                    return Geometry.copy(preferredSize);
+                }
+            }
+
+            // If we have a cached width measurement
+            if (cachedWidth != null) {
+                // If this was measured with the same height hint
+                if (cachedWidth.y == heightHint) {
+                    return Geometry.copy(cachedWidth);
+                }
+            }
+
+            cachedWidth = computeSize(control, widthHint, heightHint);
+
+            return Geometry.copy(cachedWidth);
+        }
+
+        return computeSize(control, widthHint, heightHint);
+    }
+
+    /**
+     * Compute the control's size, and ensure that non-default hints are returned verbatim
+     * (this tries to compensate for SWT's hints, which aren't really the outer width of the
+     * control).
+     *
+     * @param control
+     * @param widthHint
+     * @param heightHint
+     * @return
+     */
+    private Point computeSize(Control control, int widthHint, int heightHint) {
+        int adjustedWidthHint = widthHint == SWT.DEFAULT ? SWT.DEFAULT : Math
+                .max(0, widthHint - widthAdjustment);
+        int adjustedHeightHint = heightHint == SWT.DEFAULT ? SWT.DEFAULT : Math
+                .max(0, heightHint - heightAdjustment);
+
+        Point result = control.computeSize(adjustedWidthHint,
+                adjustedHeightHint, flushChildren);
+        flushChildren = false;
+
+        // If the amounts we subtracted off the widthHint and heightHint didn't do the trick, then
+        // manually adjust the result to ensure that a non-default hint will return that result verbatim.
+
+        if (widthHint != SWT.DEFAULT) {
+            result.x = widthHint;
+        }
+
+        if (heightHint != SWT.DEFAULT) {
+            result.y = heightHint;
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns true if the preferred length of the given control is
+     * independent of the width and visa-versa. If this returns true,
+     * then changing the widthHint argument to control.computeSize will
+     * never change the resulting height and changing the heightHint
+     * will never change the resulting width. Returns false if unknown.
+     * <p>
+     * This information can be used to improve caching. Incorrectly returning
+     * a value of false may decrease performance, but incorrectly returning
+     * a value of true will generate incorrect layouts... so always return
+     * false if unsure.
+     * </p>
+     *
+     * @param control
+     * @return
+     */
+    static boolean independentLengthAndWidth(Control control) {
+        if (control == null) {
+            return true;
+        }
+
+        if (control instanceof Button || control instanceof ProgressBar
+                || control instanceof Sash || control instanceof Scale
+                || control instanceof Slider || control instanceof List
+                || control instanceof Combo || control instanceof Tree) {
+            return true;
+        }
+
+        if (control instanceof Label || control instanceof Text) {
+            return (control.getStyle() & SWT.WRAP) == 0;
+        }
+
+        // Unless we're certain that the control has this property, we should
+        // return false.
+
+        return false;
+    }
+
+    /**
+     * Try to figure out how much we need to subtract from the hints that we
+     * pass into the given control's computeSize(...) method. This tries to
+     * compensate for bug 46112. To be removed once SWT provides an "official"
+     * way to compute one dimension of a control's size given the other known
+     * dimension.
+     *
+     * @param control
+     */
+    private void computeHintOffset(Control control) {
+        if (control instanceof Composite) {
+            // For composites, subtract off the trim size
+            Composite composite = (Composite) control;
+            Rectangle trim = composite.computeTrim(0, 0, 0, 0);
+
+            widthAdjustment = trim.width;
+            heightAdjustment = trim.height;
+        } else {
+            // For non-composites, subtract off 2 * the border size
+            widthAdjustment = control.getBorderWidth() * 2;
+            heightAdjustment = widthAdjustment;
+        }
+    }
+
+    /**
+     * Returns true only if the control will return a constant height for any
+     * width hint larger than the preferred width. Returns false if there is
+     * any situation in which the control does not have this property.
+     *
+     * <p>
+     * Note: this method is only important for wrapping controls, and it can
+     * safely return false for anything else. AFAIK, all SWT controls have this
+     * property, but to be safe they will only be added to the list once the
+     * property has been confirmed.
+     * </p>
+     *
+     * @param control
+     * @return
+     */
+    private static boolean isPreferredWidthMaximum(Control control) {
+        return (control instanceof ToolBar
+        //|| control instanceof CoolBar
+        || control instanceof Label);
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/ActionSet.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/ActionSet.java
new file mode 100644
index 0000000..d4c8cd0
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/ActionSet.java
@@ -0,0 +1,460 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ ******************************************************************************/
+
+package org.eclipse.ui.internal.menus;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.core.commands.contexts.Context;
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.ExpressionInfo;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.ui.internal.workbench.ContributionsAnalyzer;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.ui.MCoreExpression;
+import org.eclipse.e4.ui.model.application.ui.MElementContainer;
+import org.eclipse.e4.ui.model.application.ui.impl.UiFactoryImpl;
+import org.eclipse.e4.ui.model.application.ui.menu.MMenu;
+import org.eclipse.e4.ui.model.application.ui.menu.MMenuContribution;
+import org.eclipse.e4.ui.model.application.ui.menu.MMenuElement;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolBar;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolBarContribution;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolBarElement;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolBarSeparator;
+import org.eclipse.e4.ui.model.application.ui.menu.MTrimContribution;
+import org.eclipse.e4.ui.model.application.ui.menu.impl.MenuFactoryImpl;
+import org.eclipse.e4.ui.services.EContextService;
+import org.eclipse.e4.ui.workbench.renderers.swt.MenuManagerRenderer;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.IWorkbenchActionConstants;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.e4.compatibility.E4Util;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+
+/**
+ * @since e4
+ *
+ */
+public class ActionSet {
+
+	public static final String MAIN_TOOLBAR = "org.eclipse.ui.main.toolbar"; //$NON-NLS-1$
+	public static final String MAIN_MENU = "org.eclipse.ui.main.menu"; //$NON-NLS-1$
+
+	protected IConfigurationElement configElement;
+
+	protected MApplication application;
+
+	protected Expression visibleWhen;
+
+	private HashSet<String> menuContributionGroupIds = new HashSet<>();
+	private HashSet<String> toolbarContributionGroupIds = new HashSet<>();
+	private String id;
+
+	public String getId() {
+		return id;
+	}
+
+	public ActionSet(MApplication application, IEclipseContext appContext,
+			IConfigurationElement element) {
+		this.application = application;
+		this.configElement = element;
+		this.id = MenuHelper.getId(configElement);
+	}
+
+	public void addToModel(ArrayList<MMenuContribution> menuContributions,
+			ArrayList<MToolBarContribution> toolBarContributions,
+			ArrayList<MTrimContribution> trimContributions) {
+
+		String idContrib = MenuHelper.getId(configElement);
+		visibleWhen = createExpression(configElement);
+
+		EContextService contextService = application.getContext().get(EContextService.class);
+		Context actionSetContext = contextService.getContext(idContrib);
+		if (!actionSetContext.isDefined()) {
+			actionSetContext.define(MenuHelper.getLabel(configElement),
+					MenuHelper.getDescription(configElement), "org.eclipse.ui.contexts.actionSet"); //$NON-NLS-1$
+		}
+
+		IConfigurationElement[] menus = configElement
+				.getChildren(IWorkbenchRegistryConstants.TAG_MENU);
+		if (menus.length > 0) {
+			for (int i = menus.length; i > 0; i--) {
+				IConfigurationElement element = menus[i - 1];
+				addContribution(idContrib, menuContributions, element, true, MAIN_MENU);
+			}
+
+		}
+
+		IConfigurationElement[] actions = configElement
+				.getChildren(IWorkbenchRegistryConstants.TAG_ACTION);
+		if (actions.length > 0) {
+			for (int i = 0; i < actions.length; i++) {
+				IConfigurationElement up = actions[i];
+				IConfigurationElement down = actions[actions.length - 1 - i];
+				addContribution(idContrib, menuContributions, down, false, MAIN_MENU);
+				addToolBarContribution(idContrib, toolBarContributions, trimContributions, up,
+						MAIN_TOOLBAR);
+			}
+		}
+	}
+
+	protected Expression createExpression(IConfigurationElement configElement) {
+		String actionSetId = MenuHelper.getId(configElement);
+		Set<String> associatedPartIds = actionSetPartAssociations(actionSetId);
+		return new ActionSetAndPartExpression(actionSetId, associatedPartIds);
+	}
+
+	private Set<String> actionSetPartAssociations(String actionSetId) {
+		HashSet<String> result = new HashSet<>();
+		final IExtensionRegistry registry = Platform.getExtensionRegistry();
+		final IConfigurationElement[] associations = registry
+				.getConfigurationElementsFor(PlatformUI.PLUGIN_ID + '.'
+						+ IWorkbenchRegistryConstants.PL_ACTION_SET_PART_ASSOCIATIONS);
+		for (IConfigurationElement element : associations) {
+			String targetId = element.getAttribute(IWorkbenchRegistryConstants.ATT_TARGET_ID);
+			if (!actionSetId.equals(targetId)) {
+				continue;
+			}
+			IConfigurationElement[] children = element
+					.getChildren(IWorkbenchRegistryConstants.TAG_PART);
+			for (IConfigurationElement part : children) {
+				String id = MenuHelper.getId(part);
+				if (id != null && id.length() > 0) {
+				    MenuHelper.trace(IWorkbenchRegistryConstants.PL_ACTION_SET_PART_ASSOCIATIONS + ':' + actionSetId
+							+ ':' + id, null);
+					result.add(id);
+				}
+			}
+		}
+		return result;
+	}
+
+	static class ActionSetAndPartExpression extends Expression {
+		private String id;
+		private Set<String> partIds;
+
+		public ActionSetAndPartExpression(String id, Set<String> associatedPartIds) {
+			this.id = id;
+			this.partIds = associatedPartIds;
+		}
+
+		@Override
+		public void collectExpressionInfo(ExpressionInfo info) {
+			info.addVariableNameAccess(ISources.ACTIVE_CONTEXT_NAME);
+			info.addVariableNameAccess(ISources.ACTIVE_PART_ID_NAME);
+		}
+
+		@Override
+		public EvaluationResult evaluate(IEvaluationContext context) throws CoreException {
+			Object obj = context.getVariable(ISources.ACTIVE_CONTEXT_NAME);
+			if (obj instanceof Collection<?>) {
+				boolean rc = ((Collection) obj).contains(id);
+				if (rc) {
+					return EvaluationResult.TRUE;
+				}
+			}
+			if (!partIds.isEmpty()) {
+				return EvaluationResult.valueOf(partIds.contains(context
+						.getVariable(ISources.ACTIVE_PART_ID_NAME)));
+			}
+			return EvaluationResult.FALSE;
+		}
+
+		@Override
+		public boolean equals(Object obj) {
+			if (!(obj instanceof ActionSetAndPartExpression)) {
+				return false;
+			}
+			ActionSetAndPartExpression exp = (ActionSetAndPartExpression) obj;
+			return id.equals(exp.id) && partIds.equals(exp.partIds);
+		}
+
+		@Override
+		public int hashCode() {
+			return id.hashCode() + partIds.hashCode();
+		}
+	}
+
+	private MCoreExpression createVisibleWhen() {
+		if (visibleWhen == null) {
+			return null;
+		}
+		MCoreExpression exp = UiFactoryImpl.eINSTANCE.createCoreExpression();
+		exp.setCoreExpressionId("programmatic." + MenuHelper.getId(configElement)); //$NON-NLS-1$
+		exp.setCoreExpression(visibleWhen);
+		return exp;
+	}
+
+	protected void addContribution(String idContrib, ArrayList<MMenuContribution> contributions,
+			IConfigurationElement element, boolean isMenu, String parentId) {
+		MMenuContribution menuContribution = MenuFactoryImpl.eINSTANCE.createMenuContribution();
+		menuContribution.setVisibleWhen(createVisibleWhen());
+		menuContribution.getTags().add(ContributionsAnalyzer.MC_MENU);
+		menuContribution.getTags().add("scheme:menu"); //$NON-NLS-1$
+		final String elementId = MenuHelper.getId(element);
+		if (idContrib != null && idContrib.length() > 0) {
+			menuContribution.setElementId(idContrib + "/" + elementId); //$NON-NLS-1$
+		} else {
+			menuContribution.setElementId(elementId);
+		}
+
+		String path = isMenu ? MenuHelper.getPath(element) : MenuHelper.getMenuBarPath(element);
+		if (path == null || path.length() == 0) {
+			if (!isMenu) {
+				return;
+			}
+			path = IWorkbenchActionConstants.MB_ADDITIONS;
+		}
+		if (path.endsWith("/")) { //$NON-NLS-1$
+			path += IWorkbenchActionConstants.MB_ADDITIONS;
+		}
+		Path menuPath = new Path(path);
+		String positionInParent = "after=" + menuPath.segment(0); //$NON-NLS-1$
+		int segmentCount = menuPath.segmentCount();
+		if (segmentCount > 1) {
+			parentId = menuPath.segment(segmentCount - 2);
+			positionInParent = "after=" + menuPath.segment(segmentCount - 1); //$NON-NLS-1$
+		}
+		menuContribution.setParentId(parentId);
+		menuContribution.setPositionInParent(positionInParent);
+		if (isMenu) {
+			MMenu menu = MenuHelper.createMenuAddition(element);
+			if (menu != null) {
+				contributeMenuGroup(contributions, parentId, positionInParent);
+				menuContribution.getChildren().add(menu);
+				menu.getTransientData().put("ActionSet", id); //$NON-NLS-1$
+			}
+		} else {
+			if (parentId.equals(MAIN_MENU)) {
+				E4Util.unsupported("****MC: bad pie: " + menuPath); //$NON-NLS-1$
+				parentId = IWorkbenchActionConstants.M_WINDOW;
+				menuContribution.setParentId(parentId);
+			}
+			MMenuElement action = MenuHelper.createLegacyMenuActionAdditions(application, element);
+			if (action != null) {
+				contributeMenuGroup(contributions, parentId, positionInParent);
+				menuContribution.getChildren().add(action);
+				action.getTransientData().put("ActionSet", id); //$NON-NLS-1$
+			}
+		}
+		if (menuContribution.getChildren().size() > 0) {
+			contributions.add(menuContribution);
+		}
+		if (isMenu) {
+			processGroups(idContrib, contributions, element);
+		}
+	}
+
+	private void contributeMenuGroup(ArrayList<MMenuContribution> contributions, String parentId,
+			String positionInParent) {
+		String group = positionInParent.substring(6);
+		if (menuContributionGroupIds.contains(parentId + group)) {
+			return;
+		}
+		menuContributionGroupIds.add(parentId + group);
+		MMenuContribution menuContribution = MenuFactoryImpl.eINSTANCE.createMenuContribution();
+		menuContribution.setVisibleWhen(createVisibleWhen());
+		menuContribution.getTags().add(ContributionsAnalyzer.MC_MENU);
+		menuContribution.getTags().add("scheme:menu"); //$NON-NLS-1$
+		menuContribution.setParentId(parentId);
+		menuContribution.setPositionInParent("after=additions"); //$NON-NLS-1$
+		MMenuElement sep = MenuFactoryImpl.eINSTANCE.createMenuSeparator();
+		sep.getTags().add(MenuManagerRenderer.GROUP_MARKER);
+		sep.setVisible(false);
+		sep.setElementId(group);
+		menuContribution.getChildren().add(sep);
+		contributions.add(menuContribution);
+	}
+
+	private void contributeToolBarGroup(ArrayList<MToolBarContribution> contributions,
+			String parentId, String group) {
+		if (toolbarContributionGroupIds.contains(parentId + group)) {
+			return;
+		}
+		toolbarContributionGroupIds.add(parentId + group);
+		MToolBarContribution toolBarContribution = MenuFactoryImpl.eINSTANCE
+				.createToolBarContribution();
+		toolBarContribution.getTags().add(ContributionsAnalyzer.MC_MENU);
+		toolBarContribution.getTags().add("scheme:toolbar"); //$NON-NLS-1$
+		toolBarContribution.setParentId(parentId);
+		toolBarContribution.setPositionInParent("after=additions"); //$NON-NLS-1$
+		MToolBarSeparator sep = MenuFactoryImpl.eINSTANCE.createToolBarSeparator();
+		sep.setElementId(group);
+		sep.setVisible(false);
+		toolBarContribution.getChildren().add(sep);
+		contributions.add(toolBarContribution);
+	}
+
+	protected void addToolBarContribution(String idContrib,
+			ArrayList<MToolBarContribution> contributions,
+			ArrayList<MTrimContribution> trimContributions, IConfigurationElement element,
+			String parentId) {
+		String tpath = MenuHelper.getToolBarPath(element);
+		if (tpath == null || isEditorAction(element)) {
+			return;
+		}
+
+		if (tpath.endsWith("/")) { //$NON-NLS-1$
+			tpath += IWorkbenchActionConstants.MB_ADDITIONS;
+		}
+
+		MToolBarElement action = MenuHelper
+				.createLegacyToolBarActionAdditions(application, element);
+		if (action == null) {
+			return;
+		}
+
+		action.getTransientData().put("Name", MenuHelper.getLabel(element)); //$NON-NLS-1$
+		action.getTransientData().put("ActionSet", id); //$NON-NLS-1$
+
+		MToolBarContribution toolBarContribution = MenuFactoryImpl.eINSTANCE
+				.createToolBarContribution();
+		toolBarContribution.getTags().add(ContributionsAnalyzer.MC_MENU);
+		toolBarContribution.getTags().add("scheme:toolbar"); //$NON-NLS-1$
+		final String elementId = MenuHelper.getId(element);
+		if (idContrib != null && idContrib.length() > 0) {
+			toolBarContribution.setElementId(idContrib + "/" + elementId); //$NON-NLS-1$
+			toolBarContribution.getTags().add("ActionSet::" + idContrib); //$NON-NLS-1$
+		} else {
+			toolBarContribution.setElementId(elementId);
+		}
+
+		String tgroup = null;
+		if (tpath != null) {
+			int loc = tpath.lastIndexOf('/');
+			if (loc != -1) {
+				tgroup = tpath.substring(loc + 1);
+				tpath = tpath.substring(0, loc);
+			} else {
+				tgroup = tpath;
+				tpath = null;
+			}
+		}
+		if (tpath == null || tpath.equals("Normal")) { //$NON-NLS-1$
+			IConfigurationElement parent = (IConfigurationElement) element.getParent();
+			tpath = parent.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+		}
+		Path menuPath = new Path(tpath);
+		tpath = menuPath.segment(0);
+
+		if (MAIN_TOOLBAR.equals(parentId)) {
+			addTrimContribution(idContrib, contributions, trimContributions, element, parentId,
+					tpath, tgroup);
+		} else {
+			tpath = parentId;
+		}
+
+		// String positionInParent =
+		// MenuHelper.isSeparatorVisible(configElement) ? null
+		//					: "after=" + tpath; //$NON-NLS-1$
+		String positionInParent = "after=" + tgroup;//$NON-NLS-1$
+		contributeToolBarGroup(contributions, tpath, tgroup);
+		toolBarContribution.setParentId(tpath);
+
+		toolBarContribution.setPositionInParent(positionInParent);
+		toolBarContribution.setVisibleWhen(createVisibleWhen());
+		toolBarContribution.getChildren().add(action);
+
+		contributions.add(toolBarContribution);
+	}
+
+	private boolean isEditorAction(IConfigurationElement element) {
+		return IWorkbenchRegistryConstants.EXTENSION_EDITOR_ACTIONS.equals(element
+				.getDeclaringExtension().getExtensionPointUniqueIdentifier());
+	}
+
+	private void addTrimContribution(String idContrib,
+			ArrayList<MToolBarContribution> contributions,
+			ArrayList<MTrimContribution> trimContributions, IConfigurationElement element,
+			String parentId, String tpath, String tgroup) {
+
+		final String elementId = MenuHelper.getId(element);
+		MTrimContribution trimContribution = MenuFactoryImpl.eINSTANCE.createTrimContribution();
+		trimContribution.getTags().add(ContributionsAnalyzer.MC_TOOLBAR);
+		trimContribution.getTags().add("scheme:toolbar"); //$NON-NLS-1$
+		if (idContrib != null && idContrib.length() > 0) {
+			trimContribution.setElementId(idContrib + "/" + elementId); //$NON-NLS-1$
+		} else {
+			trimContribution.setElementId(elementId);
+		}
+		trimContribution.setParentId(parentId);
+		trimContribution.setPositionInParent("after=additions"); //$NON-NLS-1$		trimContribution.setVisibleWhen(createVisibleWhen());
+		MToolBar tb = MenuFactoryImpl.eINSTANCE.createToolBar();
+		tb.setElementId(tpath);
+		tb.getTransientData().put("Name", MenuHelper.getLabel(this.configElement)); //$NON-NLS-1$
+		tb.getTransientData().put("ActionSet", id); //$NON-NLS-1$
+		trimContribution.getChildren().add(tb);
+		trimContributions.add(trimContribution);
+	}
+
+	private void processGroups(String idContrib, ArrayList<MMenuContribution> contributions,
+			IConfigurationElement element) {
+		MMenuContribution menuContribution = MenuFactoryImpl.eINSTANCE.createMenuContribution();
+		menuContribution.setVisibleWhen(createVisibleWhen());
+		menuContribution.getTags().add(ContributionsAnalyzer.MC_MENU);
+		menuContribution.getTags().add("scheme:menu"); //$NON-NLS-1$
+		final String elementId = MenuHelper.getId(element);
+		if (idContrib != null && idContrib.length() > 0) {
+			menuContribution.setElementId(idContrib + "/" + elementId + ".groups"); //$NON-NLS-1$ //$NON-NLS-2$
+		} else {
+			menuContribution.setElementId(elementId + ".groups"); //$NON-NLS-1$
+		}
+		menuContribution.setParentId(elementId);
+		menuContribution.setPositionInParent("after=additions"); //$NON-NLS-1$
+		IConfigurationElement[] children = element.getChildren();
+		for (IConfigurationElement sepAddition : children) {
+			String name = sepAddition.getAttribute(IWorkbenchRegistryConstants.ATT_NAME);
+			String tag = sepAddition.getName();
+			MMenuElement sep = MenuFactoryImpl.eINSTANCE.createMenuSeparator();
+			sep.setElementId(name);
+			if ("groupMarker".equals(tag)) { //$NON-NLS-1$
+				sep.setVisible(false);
+				sep.getTags().add(MenuManagerRenderer.GROUP_MARKER);
+			}
+			menuContribution.getChildren().add(sep);
+		}
+		if (menuContribution.getChildren().size() > 0) {
+			contributions.add(menuContribution);
+		}
+	}
+
+	MElementContainer<MMenuElement> findMenuFromPath(MElementContainer<MMenuElement> menu,
+			Path menuPath, int segment) {
+		int idx = ContributionsAnalyzer.indexForId(menu, menuPath.segment(segment));
+		if (idx == -1) {
+			if (segment + 1 < menuPath.segmentCount() || !menuPath.hasTrailingSeparator()) {
+				return null;
+			}
+			return menu;
+		}
+		MElementContainer<MMenuElement> item = (MElementContainer<MMenuElement>) menu.getChildren()
+				.get(idx);
+		if (item.getChildren().size() == 0) {
+			if (segment + 1 == menuPath.segmentCount()) {
+				return menu;
+			} else {
+				return null;
+			}
+		}
+		return findMenuFromPath(item, menuPath, segment + 1);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/CommandMessages.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/CommandMessages.java
new file mode 100644
index 0000000..4608772
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/CommandMessages.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2015 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.ui.internal.menus;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ *
+ * @since 3.5
+ *
+ */
+public class CommandMessages extends NLS {
+
+	private static final String BUNDLE_NAME = "org.eclipse.ui.internal.menus.messages";//$NON-NLS-1$
+
+	static {
+		// load message values from bundle file
+		NLS.initializeMessages(BUNDLE_NAME, CommandMessages.class);
+	}
+
+	public static String Tooltip_Accelerator;
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/CompatibilityWorkbenchWindowControlContribution.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/CompatibilityWorkbenchWindowControlContribution.java
new file mode 100644
index 0000000..649a8f2
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/CompatibilityWorkbenchWindowControlContribution.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2015 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.ui.internal.menus;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.e4.ui.model.application.ui.MUIElement;
+import org.eclipse.e4.ui.model.application.ui.basic.MTrimBar;
+import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolControl;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.util.Util;
+import org.eclipse.ui.menus.IWorkbenchContribution;
+import org.eclipse.ui.menus.WorkbenchWindowControlContribution;
+
+/**
+ * This is a proxy object for instantiating the real as provided by a plug-in
+ * WorkbenchWindowControlContribution subclass.
+ */
+public class CompatibilityWorkbenchWindowControlContribution {
+
+	public static final String CONTROL_CONTRIBUTION_URI = "bundleclass://org.eclipse.ui.workbench/org.eclipse.ui.internal.menus.CompatibilityWorkbenchWindowControlContribution"; //$NON-NLS-1$
+
+	private WorkbenchWindowControlContribution contribution;
+
+	/**
+	 * Constructs the control contribution that this proxy represents.
+	 *
+	 * @param window
+	 *            the window that this control contribution is under
+	 * @param toolControl
+	 *            the tool control representing this contribution
+	 * @param composite
+	 *            the composite to create or parent the control under
+	 */
+	@PostConstruct
+	void construct(MWindow window, MToolControl toolControl, Composite composite) {
+		IConfigurationElement configurationElement = ControlContributionRegistry.get(toolControl
+				.getElementId());
+		if (configurationElement != null) {
+			contribution = (WorkbenchWindowControlContribution) Util.safeLoadExecutableExtension(
+					configurationElement, IWorkbenchRegistryConstants.ATT_CLASS,
+					WorkbenchWindowControlContribution.class);
+			if (contribution != null) {
+				IWorkbenchWindow workbenchWindow = window.getContext().get(IWorkbenchWindow.class);
+				contribution.setWorkbenchWindow(workbenchWindow);
+
+				if (contribution instanceof IWorkbenchContribution) {
+					((IWorkbenchContribution) contribution).initialize(workbenchWindow);
+				}
+
+				MUIElement parent = toolControl.getParent();
+				while (!(parent instanceof MTrimBar) && parent != null) {
+					parent = parent.getParent();
+				}
+
+				if (parent instanceof MTrimBar) {
+					switch (((MTrimBar) parent).getSide()) {
+					case BOTTOM:
+						contribution.setCurSide(SWT.BOTTOM);
+						break;
+					case LEFT:
+						contribution.setCurSide(SWT.LEFT);
+						break;
+					case RIGHT:
+						contribution.setCurSide(SWT.RIGHT);
+						break;
+					case TOP:
+						contribution.setCurSide(SWT.TOP);
+						break;
+					}
+				} else {
+					// default position
+					contribution.setCurSide(SWT.TOP);
+				}
+
+				contribution.delegateCreateControl(composite);
+			}
+		}
+	}
+
+	@PreDestroy
+	void dispose() {
+		if (contribution != null) {
+			contribution.dispose();
+			contribution = null;
+		}
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/ContributionFactoryGenerator.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/ContributionFactoryGenerator.java
new file mode 100644
index 0000000..8fc6e15
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/ContributionFactoryGenerator.java
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * Copyright (c) 2012, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ ******************************************************************************/
+
+package org.eclipse.ui.internal.menus;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.e4.core.contexts.ContextFunction;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.ui.internal.workbench.OpaqueElementUtil;
+import org.eclipse.e4.ui.model.application.ui.MCoreExpression;
+import org.eclipse.e4.ui.model.application.ui.MUIElement;
+import org.eclipse.e4.ui.model.application.ui.impl.UiFactoryImpl;
+import org.eclipse.e4.ui.model.application.ui.menu.MMenuItem;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolItem;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.services.ServiceLocator;
+import org.eclipse.ui.menus.AbstractContributionFactory;
+import org.eclipse.ui.menus.IMenuService;
+
+public class ContributionFactoryGenerator extends ContextFunction {
+	private AbstractContributionFactory factoryImpl;
+	private IConfigurationElement configElement;
+	private int type;
+
+	public ContributionFactoryGenerator(AbstractContributionFactory factory, int type) {
+		this.factoryImpl = factory;
+		this.type = type;
+	}
+
+	public ContributionFactoryGenerator(IConfigurationElement element, int type) {
+		configElement = element;
+		this.type = type;
+	}
+
+	private AbstractContributionFactory getFactory() {
+		if (factoryImpl == null && configElement != null) {
+			try {
+				factoryImpl = (AbstractContributionFactory) configElement
+						.createExecutableExtension("class"); //$NON-NLS-1$
+			} catch (CoreException e) {
+				WorkbenchPlugin.log(e);
+				return null;
+			}
+		}
+		return factoryImpl;
+	}
+
+	@Override
+	public Object compute(IEclipseContext context, String contextKey) {
+		AbstractContributionFactory factory = getFactory();
+		final IMenuService menuService = context.get(IMenuService.class);
+		final ContributionRoot root = new ContributionRoot(menuService, new HashSet<>(),
+				null, factory);
+		ServiceLocator sl = new ServiceLocator();
+		sl.setContext(context);
+		factory.createContributionItems(sl, root);
+		final List contributionItems = root.getItems();
+		final Map<IContributionItem, Expression> itemsToExpression = root.getVisibleWhen();
+		List<MUIElement> menuElements = new ArrayList<>();
+		for (Object obj : contributionItems) {
+			if (obj instanceof IContributionItem) {
+				IContributionItem ici = (IContributionItem) obj;
+				MUIElement opaqueItem = createUIElement(ici);
+				if (opaqueItem != null) {
+					if (itemsToExpression.containsKey(ici)) {
+						final Expression ex = itemsToExpression.get(ici);
+						MCoreExpression exp = UiFactoryImpl.eINSTANCE.createCoreExpression();
+						exp.setCoreExpressionId("programmatic." + ici.getId()); //$NON-NLS-1$
+						exp.setCoreExpression(ex);
+						opaqueItem.setVisibleWhen(exp);
+					}
+					menuElements.add(opaqueItem);
+				}
+			}
+		}
+		context.set(List.class, menuElements);
+
+		// return something disposable
+		return (Runnable) () -> root.release();
+	}
+
+	private MUIElement createUIElement(IContributionItem ici) {
+		switch (type) {
+		case 0:
+			return createMenuItem(ici);
+		case 1:
+			return createToolItem(ici);
+		}
+		return null;
+	}
+
+	private MUIElement createMenuItem(IContributionItem ici) {
+		MMenuItem opaqueItem = OpaqueElementUtil.createOpaqueMenuItem();
+		opaqueItem.setElementId(ici.getId());
+		OpaqueElementUtil.setOpaqueItem(opaqueItem, ici);
+		return opaqueItem;
+	}
+
+	private MUIElement createToolItem(IContributionItem ici) {
+		MToolItem opaqueItem = OpaqueElementUtil.createOpaqueToolItem();
+		opaqueItem.setElementId(ici.getId());
+		OpaqueElementUtil.setOpaqueItem(opaqueItem, ici);
+		return opaqueItem;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/ContributionRoot.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/ContributionRoot.java
new file mode 100644
index 0000000..6b25e4c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/ContributionRoot.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.menus;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.jface.action.ContributionManager;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.ui.internal.expressions.AlwaysEnabledExpression;
+import org.eclipse.ui.menus.AbstractContributionFactory;
+import org.eclipse.ui.menus.IContributionRoot;
+import org.eclipse.ui.menus.IMenuService;
+
+/**
+ * Default implementation.
+ *
+ * @since 3.3
+ */
+final class ContributionRoot implements
+		IContributionRoot {
+
+	private List topLevelItems = new ArrayList();
+	private Map<IContributionItem, Expression> itemsToExpressions = new HashMap<>();
+	Set restriction;
+	private ContributionManager mgr;
+	private AbstractContributionFactory factory;
+
+	public ContributionRoot(IMenuService menuService, Set restriction,
+			ContributionManager mgr, AbstractContributionFactory factory) {
+		this.restriction = restriction;
+		this.mgr = mgr;
+		this.factory = factory;
+	}
+
+	@Override
+	public void addContributionItem(IContributionItem item,
+			Expression visibleWhen) {
+		if (item == null)
+			throw new IllegalArgumentException();
+		topLevelItems.add(item);
+		if (visibleWhen == null)
+			visibleWhen = AlwaysEnabledExpression.INSTANCE;
+
+		// menuService.registerVisibleWhen(item, visibleWhen, restriction,
+		// createIdentifierId(item));
+		itemsToExpressions.put(item, visibleWhen);
+	}
+
+	/**
+     * Create the activity identifier for this contribution item.
+     *
+	 * @param item the item
+	 * @return the identifier
+	 */
+	String createIdentifierId(IContributionItem item) {
+		String namespace = factory.getNamespace();
+		String identifierID = namespace != null ? namespace + '/'
+				+ item.getId() : null; // create the activity identifier ID. If
+										// this factory doesn't have a namespace
+										// it will be null.
+		return identifierID;
+	}
+
+	public List getItems() {
+		return topLevelItems;
+	}
+
+	public Map<IContributionItem, Expression> getVisibleWhen() {
+		return itemsToExpressions;
+	}
+
+	/**
+	 * Unregister all visible when expressions from the menu service.
+	 */
+	public void release() {
+		for (IContributionItem item : itemsToExpressions.keySet()) {
+			// menuService.unregisterVisibleWhen(item, restriction);
+			item.dispose();
+		}
+		itemsToExpressions.clear();
+		topLevelItems.clear();
+	}
+
+	@Override
+	public void registerVisibilityForChild(IContributionItem item,
+			Expression visibleWhen) {
+		if (item == null)
+			throw new IllegalArgumentException();
+		if (visibleWhen == null)
+			visibleWhen = AlwaysEnabledExpression.INSTANCE;
+		// menuService.registerVisibleWhen(item, visibleWhen, restriction,
+		// createIdentifierId(item));
+		itemsToExpressions.put(item, visibleWhen);
+	}
+
+	/**
+	 * @return Returns the mgr.
+	 */
+	public ContributionManager getManager() {
+		return mgr;
+	}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/ControlContributionRegistry.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/ControlContributionRegistry.java
new file mode 100644
index 0000000..f79e906
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/ControlContributionRegistry.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ ******************************************************************************/
+
+package org.eclipse.ui.internal.menus;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.eclipse.core.runtime.IConfigurationElement;
+
+/**
+ * A registry between a given string id and a configuration element that
+ * corresponds to a control contribution.
+ */
+public class ControlContributionRegistry {
+
+	private static Map<String, IConfigurationElement> registry = new HashMap<>();
+
+	public static void clear() {
+		registry.clear();
+	}
+
+	public static void add(String id, IConfigurationElement element) {
+		registry.put(id, element);
+	}
+
+	public static IConfigurationElement get(String id) {
+		return registry.get(id);
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/DynamicMenuContributionItem.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/DynamicMenuContributionItem.java
new file mode 100644
index 0000000..ff72f95
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/DynamicMenuContributionItem.java
@@ -0,0 +1,214 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2015 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.ui.internal.menus;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.jface.action.ContributionItem;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.IContributionManager;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.CoolBar;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.util.Util;
+import org.eclipse.ui.menus.IWorkbenchContribution;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * A contribution item which proxies a dynamic menu or tool contribution.
+ * <p>
+ * It currently supports placement in menus.
+ * </p>
+ * <p>
+ *
+ * @author Prakash G.R.
+ *
+ * @since 3.5
+ *
+ */
+public class DynamicMenuContributionItem extends ContributionItem {
+
+	private final IConfigurationElement dynamicAddition;
+	private final IServiceLocator locator;
+	private boolean alreadyFailed;
+	private ContributionItem loadedDynamicContribution;
+
+	/**
+	 * Creates a DynamicMenuContributionItem
+	 *
+	 * @param id
+	 *            - Id of the menu item
+	 * @param locator
+	 *            - The Service Locator
+	 * @param dynamicAddition
+	 *            - The Configuration Element defined in the plugin.xml
+	 *
+	 */
+	public DynamicMenuContributionItem(String id, IServiceLocator locator,
+			IConfigurationElement dynamicAddition) {
+		super(id);
+
+		this.locator = locator;
+		this.dynamicAddition = dynamicAddition;
+	}
+
+	@Override
+	public boolean isDynamic() {
+		if (loadedDynamicContribution != null) {
+			return loadedDynamicContribution.isDynamic();
+		}
+		return true;
+	}
+
+	@Override
+	public boolean isDirty() {
+		if (loadedDynamicContribution != null) {
+			return loadedDynamicContribution.isDirty();
+		}
+		return super.isDirty();
+	}
+
+	@Override
+	public boolean isEnabled() {
+		if (loadedDynamicContribution != null) {
+			return loadedDynamicContribution.isEnabled();
+		}
+		return super.isEnabled();
+	}
+
+	@Override
+	public boolean isGroupMarker() {
+		if (loadedDynamicContribution != null) {
+			return loadedDynamicContribution.isGroupMarker();
+		}
+		return super.isGroupMarker();
+	}
+
+	@Override
+	public boolean isSeparator() {
+		if (loadedDynamicContribution != null) {
+			return loadedDynamicContribution.isSeparator();
+		}
+		return super.isSeparator();
+	}
+
+	@Override
+	public boolean isVisible() {
+		if (loadedDynamicContribution != null) {
+			return loadedDynamicContribution.isVisible();
+		}
+		return super.isVisible();
+	}
+
+	@Override
+	public void saveWidgetState() {
+		if (loadedDynamicContribution != null) {
+			loadedDynamicContribution.saveWidgetState();
+		}
+		super.saveWidgetState();
+	}
+
+	@Override
+	public void setVisible(boolean visible) {
+		if (loadedDynamicContribution != null) {
+			loadedDynamicContribution.setVisible(visible);
+		}
+		super.setVisible(visible);
+	}
+
+	@Override
+	public void fill(Composite parent) {
+		IContributionItem contributionItem = getContributionItem();
+		if (contributionItem != null)
+			contributionItem.fill(parent);
+	}
+
+	@Override
+	public void fill(CoolBar parent, int index) {
+		IContributionItem contributionItem = getContributionItem();
+		if (contributionItem != null)
+			contributionItem.fill(parent, index);
+	}
+
+	@Override
+	public void fill(Menu menu, int index) {
+		IContributionItem contributionItem = getContributionItem();
+		if (contributionItem != null)
+			contributionItem.fill(menu, index);
+	}
+
+	@Override
+	public void fill(ToolBar parent, int index) {
+		IContributionItem contributionItem = getContributionItem();
+		if (contributionItem != null)
+			contributionItem.fill(parent, index);
+	}
+
+	private IContributionItem getContributionItem() {
+		if (loadedDynamicContribution == null && !alreadyFailed)
+			createContributionItem();
+		return loadedDynamicContribution;
+	}
+
+	private void createContributionItem() {
+
+		loadedDynamicContribution = (ContributionItem) Util
+				.safeLoadExecutableExtension(dynamicAddition,
+						IWorkbenchRegistryConstants.ATT_CLASS,
+						ContributionItem.class);
+
+		if (loadedDynamicContribution == null) {
+			alreadyFailed = true;
+			return;
+		}
+
+		loadedDynamicContribution.setId(getId());
+		loadedDynamicContribution.setParent(getParent());
+		if (loadedDynamicContribution instanceof IWorkbenchContribution) {
+			((IWorkbenchContribution) loadedDynamicContribution)
+					.initialize(locator);
+		}
+	}
+
+	@Override
+	public void dispose() {
+		if (loadedDynamicContribution != null) {
+			loadedDynamicContribution.dispose();
+			loadedDynamicContribution = null;
+		}
+		super.dispose();
+	}
+
+	@Override
+	public void update() {
+		if (loadedDynamicContribution != null) {
+			loadedDynamicContribution.update();
+		}
+	}
+
+	@Override
+	public void update(String id) {
+		if (loadedDynamicContribution != null) {
+			loadedDynamicContribution.update(id);
+		}
+	}
+
+	@Override
+	public void setParent(IContributionManager parent) {
+		super.setParent(parent);
+		if (loadedDynamicContribution != null) {
+			loadedDynamicContribution.setParent(parent);
+		}
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/DynamicToolBarContributionItem.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/DynamicToolBarContributionItem.java
new file mode 100644
index 0000000..6666be1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/DynamicToolBarContributionItem.java
@@ -0,0 +1,219 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2015 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.ui.internal.menus;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.IContributionManager;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.CoolBar;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.util.Util;
+import org.eclipse.ui.menus.IWorkbenchContribution;
+import org.eclipse.ui.menus.WorkbenchWindowControlContribution;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * A contribution item which proxies a dynamic tool contribution.
+ * <p>
+ * It currently supports placement in menus.
+ * </p>
+ * <p>
+ *
+ * @author Prakash G.R.
+ *
+ * @since 3.6
+ *
+ */
+public class DynamicToolBarContributionItem extends WorkbenchWindowControlContribution {
+
+	private final IConfigurationElement dynamicAddition;
+	private final IServiceLocator locator;
+	private boolean alreadyFailed;
+	private WorkbenchWindowControlContribution loadedDynamicContribution;
+
+	/**
+	 * Creates a DynamicToolBarContributionItem
+	 *
+	 * @param id
+	 *            - Id of the menu item
+	 * @param locator
+	 *            - The Service Locator
+	 * @param dynamicAddition
+	 *            - The Configuration Element defined in the plugin.xml
+	 *
+	 */
+	public DynamicToolBarContributionItem(String id, IServiceLocator locator,
+			IConfigurationElement dynamicAddition) {
+		super(id);
+
+		this.locator = locator;
+		this.dynamicAddition = dynamicAddition;
+	}
+
+	@Override
+	public boolean isDynamic() {
+		if (loadedDynamicContribution != null) {
+			return loadedDynamicContribution.isDynamic();
+		}
+		return true;
+	}
+
+	@Override
+	public boolean isDirty() {
+		if (loadedDynamicContribution != null) {
+			return loadedDynamicContribution.isDirty();
+		}
+		return super.isDirty();
+	}
+
+	@Override
+	public boolean isEnabled() {
+		if (loadedDynamicContribution != null) {
+			return loadedDynamicContribution.isEnabled();
+		}
+		return super.isEnabled();
+	}
+
+	@Override
+	public boolean isGroupMarker() {
+		if (loadedDynamicContribution != null) {
+			return loadedDynamicContribution.isGroupMarker();
+		}
+		return super.isGroupMarker();
+	}
+
+	@Override
+	public boolean isSeparator() {
+		if (loadedDynamicContribution != null) {
+			return loadedDynamicContribution.isSeparator();
+		}
+		return super.isSeparator();
+	}
+
+	@Override
+	public void saveWidgetState() {
+		if (loadedDynamicContribution != null) {
+			loadedDynamicContribution.saveWidgetState();
+		}
+		super.saveWidgetState();
+	}
+
+	@Override
+	public void setVisible(boolean visible) {
+		if (loadedDynamicContribution != null) {
+			loadedDynamicContribution.setVisible(visible);
+		}
+		super.setVisible(visible);
+	}
+
+	@Override
+	public boolean isVisible() {
+		if (loadedDynamicContribution != null) {
+			return loadedDynamicContribution.isVisible();
+		}
+		return super.isVisible();
+	}
+
+	@Override
+	public void fill(CoolBar parent, int index) {
+		IContributionItem contributionItem = getContributionItem();
+		if (contributionItem != null)
+			contributionItem.fill(parent, index);
+	}
+
+	private WorkbenchWindowControlContribution getContributionItem() {
+		if (loadedDynamicContribution == null && !alreadyFailed)
+			createContributionItem();
+		return loadedDynamicContribution;
+	}
+
+	private void createContributionItem() {
+
+		loadedDynamicContribution = (WorkbenchWindowControlContribution) Util
+				.safeLoadExecutableExtension(dynamicAddition,
+						IWorkbenchRegistryConstants.ATT_CLASS,
+						WorkbenchWindowControlContribution.class);
+
+		if (loadedDynamicContribution == null) {
+			alreadyFailed = true;
+			return;
+		}
+
+		loadedDynamicContribution.setId(getId());
+		loadedDynamicContribution.setParent(getParent());
+		loadedDynamicContribution.setWorkbenchWindow(getWorkbenchWindow());
+		loadedDynamicContribution.setCurSide(getCurSide());
+		if (loadedDynamicContribution instanceof IWorkbenchContribution) {
+			((IWorkbenchContribution) loadedDynamicContribution)
+					.initialize(locator);
+		}
+	}
+
+	@Override
+	public void dispose() {
+		if (loadedDynamicContribution != null) {
+			loadedDynamicContribution.dispose();
+			loadedDynamicContribution = null;
+		}
+		super.dispose();
+	}
+
+	@Override
+	public void update() {
+		if (loadedDynamicContribution != null) {
+			loadedDynamicContribution.update();
+		}
+	}
+
+	@Override
+	public void update(String id) {
+		if (loadedDynamicContribution != null) {
+			loadedDynamicContribution.update(id);
+		}
+	}
+
+	@Override
+	public void setParent(IContributionManager parent) {
+		super.setParent(parent);
+		if (loadedDynamicContribution != null) {
+			loadedDynamicContribution.setParent(parent);
+		}
+	}
+
+	@Override
+	public void setWorkbenchWindow(IWorkbenchWindow wbw) {
+		super.setWorkbenchWindow(wbw);
+		if (loadedDynamicContribution != null) {
+			loadedDynamicContribution.setWorkbenchWindow(wbw);
+		}
+	}
+
+	@Override
+	public void setCurSide(int curSide) {
+		super.setCurSide(curSide);
+		if (loadedDynamicContribution != null) {
+			loadedDynamicContribution.setCurSide(curSide);
+		}
+	}
+	@Override
+	public Control createControl(Composite parent) {
+
+		WorkbenchWindowControlContribution contributionItem = getContributionItem();
+		if (contributionItem != null)
+			return contributionItem.delegateCreateControl(parent);
+		return null;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/ExtensionContribution.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/ExtensionContribution.java
new file mode 100644
index 0000000..3f0c2be
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/ExtensionContribution.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 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.ui.internal.menus;
+
+import org.eclipse.e4.ui.internal.workbench.IDelegateInitializer;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.MApplicationElement;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.e4.compatibility.CompatibilityPart;
+import org.eclipse.ui.menus.IWorkbenchContribution;
+import org.eclipse.ui.services.IServiceLocator;
+
+public class ExtensionContribution implements IDelegateInitializer {
+
+	@Override
+	public void initialize(MApplicationElement model, Object delegate) {
+		if (delegate instanceof IWorkbenchContribution) {
+			IServiceLocator locator = getServiceLocator((EObject) model);
+			if (locator != null) {
+				((IWorkbenchContribution) delegate).initialize(locator);
+			}
+		}
+	}
+
+	private IServiceLocator getServiceLocator(EObject object) {
+		if (object instanceof MPart) {
+			CompatibilityPart part = (CompatibilityPart) ((MPart) object).getObject();
+			return part.getReference().getSite();
+		} else if (object instanceof MWindow) {
+			IWorkbenchWindow workbenchWindow = ((MWindow) object).getContext().get(
+					IWorkbenchWindow.class);
+			if (workbenchWindow != null) {
+				return workbenchWindow;
+			}
+		} else if (object instanceof MApplication || object == null) {
+			return PlatformUI.getWorkbench();
+		}
+		return getServiceLocator(object.eContainer());
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/FocusControlSourceProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/FocusControlSourceProvider.java
new file mode 100644
index 0000000..ece4b61
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/FocusControlSourceProvider.java
@@ -0,0 +1,164 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal.menus;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Widget;
+import org.eclipse.ui.AbstractSourceProvider;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.swt.IFocusService;
+
+/**
+ * @since 3.3
+ *
+ */
+public class FocusControlSourceProvider extends AbstractSourceProvider
+		implements IFocusService {
+
+	/**
+	 * The names of the sources supported by this source provider.
+	 */
+	private static final String[] PROVIDED_SOURCE_NAMES = new String[] {
+			ISources.ACTIVE_FOCUS_CONTROL_ID_NAME,
+			ISources.ACTIVE_FOCUS_CONTROL_NAME };
+
+	Map controlToId = new HashMap();
+	private FocusListener focusListener;
+
+	private String currentId;
+
+	private Control currentControl;
+
+	private DisposeListener disposeListener;
+
+	@Override
+	public void addFocusTracker(Control control, String id) {
+		if (control.isDisposed()) {
+			return;
+		}
+		controlToId.put(control, id);
+		control.addFocusListener(getFocusListener());
+		control.addDisposeListener(getDisposeListener());
+	}
+
+	private DisposeListener getDisposeListener() {
+		if (disposeListener == null) {
+			disposeListener = e -> {
+				controlToId.remove(e.widget);
+				if (currentControl == e.widget) {
+					focusIn(null);
+
+				}
+			};
+		}
+		return disposeListener;
+	}
+
+	private FocusListener getFocusListener() {
+		if (focusListener == null) {
+			focusListener = new FocusListener() {
+				@Override
+				public void focusGained(FocusEvent e) {
+					focusIn(e.widget);
+				}
+
+				@Override
+				public void focusLost(FocusEvent e) {
+					focusIn(null);
+				}
+			};
+		}
+		return focusListener;
+	}
+
+	/**
+	 * @param widget
+	 */
+	private void focusIn(Widget widget) {
+		String id = (String) controlToId.get(widget);
+		if (currentId != id) {
+			Map m = new HashMap();
+			if (id == null) {
+				currentId = null;
+				currentControl = null;
+				m.put(ISources.ACTIVE_FOCUS_CONTROL_ID_NAME,
+						IEvaluationContext.UNDEFINED_VARIABLE);
+				m.put(ISources.ACTIVE_FOCUS_CONTROL_NAME,
+						IEvaluationContext.UNDEFINED_VARIABLE);
+			} else {
+				currentId = id;
+				currentControl = (Control) widget;
+				m.put(ISources.ACTIVE_FOCUS_CONTROL_ID_NAME, currentId);
+				m.put(ISources.ACTIVE_FOCUS_CONTROL_NAME, currentControl);
+			}
+			fireSourceChanged(ISources.ACTIVE_MENU, m);
+		}
+	}
+
+	@Override
+	public void removeFocusTracker(Control control) {
+		if (controlToId == null) {
+			// bug 396909: avoid NPEs if the service has already been disposed
+			return;
+		}
+		controlToId.remove(control);
+		if (control.isDisposed()) {
+			return;
+		}
+		control.removeFocusListener(getFocusListener());
+		control.removeDisposeListener(getDisposeListener());
+	}
+
+	@Override
+	public void dispose() {
+		Iterator i = controlToId.keySet().iterator();
+		while (i.hasNext()) {
+			Control c = (Control) i.next();
+			if (!c.isDisposed()) {
+				c.removeFocusListener(getFocusListener());
+				c.removeDisposeListener(getDisposeListener());
+			}
+		}
+		controlToId.clear();
+		controlToId = null;
+		focusListener = null;
+		disposeListener = null;
+	}
+
+	@Override
+	public Map getCurrentState() {
+		Map m = new HashMap();
+		if (currentId == null) {
+			m.put(ISources.ACTIVE_FOCUS_CONTROL_ID_NAME,
+					IEvaluationContext.UNDEFINED_VARIABLE);
+			m.put(ISources.ACTIVE_FOCUS_CONTROL_NAME,
+					IEvaluationContext.UNDEFINED_VARIABLE);
+
+		} else {
+			m.put(ISources.ACTIVE_FOCUS_CONTROL_ID_NAME, currentId);
+			m.put(ISources.ACTIVE_FOCUS_CONTROL_NAME, currentControl);
+		}
+		return m;
+	}
+
+	@Override
+	public String[] getProvidedSourceNames() {
+		return PROVIDED_SOURCE_NAMES;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/IActionSetsListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/IActionSetsListener.java
new file mode 100644
index 0000000..e43346c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/IActionSetsListener.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.menus;
+
+import org.eclipse.ui.internal.ActionSetsEvent;
+
+
+/**
+ * <p>
+ * A listener to changes in the list of active action sets.
+ * </p>
+ * <p>
+ * This class is only intended for internal use within
+ * <code>org.eclipse.ui.workbench</code>.
+ * </p>
+ * <p>
+ * This class will eventually exist in <code>org.eclipse.jface.menus</code>.
+ * </p>
+ *
+ * @since 3.2
+ */
+public interface IActionSetsListener {
+
+	/**
+	 * Indicates that the list of active action sets has changed.
+	 *
+	 * @param event
+	 *            The event carrying information about the new state of the
+	 *            action sets; never <code>null</code>.
+	 */
+	public void actionSetsChanged(ActionSetsEvent event);
+
+}
+
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/InternalControlContribution.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/InternalControlContribution.java
new file mode 100644
index 0000000..4209ce3
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/InternalControlContribution.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal.menus;
+
+import org.eclipse.jface.action.ControlContribution;
+import org.eclipse.swt.SWT;
+import org.eclipse.ui.IWorkbenchWindow;
+
+/**
+ * Add workbench specific information to a standard control contribution.
+ * Allows the client derivatives to access the IWorkbenchWindow hosting
+ * the control as well as the side of the workbench that the control is
+ * currently being displayed on.
+ *
+ * @since 3.3
+ *
+ */
+public abstract class InternalControlContribution extends ControlContribution {
+	private IWorkbenchWindow wbw;
+	private int curSide;
+
+	/**
+	 * @param id
+	 */
+	protected InternalControlContribution(String id) {
+		super(id);
+	}
+
+	public InternalControlContribution() {
+		this("unknown ID"); //$NON-NLS-1$
+	}
+
+	/**
+	 * @return Returns the wbw.
+	 */
+	public IWorkbenchWindow getWorkbenchWindow() {
+		return wbw;
+	}
+
+	/**
+	 * @param wbw The wbw to set.
+	 */
+	public void setWorkbenchWindow(IWorkbenchWindow wbw) {
+		this.wbw = wbw;
+	}
+
+	/**
+	 * @return Returns the curSide.
+	 */
+	public int getCurSide() {
+		return curSide;
+	}
+
+	/**
+	 * @param curSide The curSide to set.
+	 */
+	public void setCurSide(int curSide) {
+		this.curSide = curSide;
+	}
+
+	public int getOrientation() {
+		if (getCurSide() == SWT.LEFT || getCurSide() == SWT.RIGHT)
+			return SWT.VERTICAL;
+
+		return SWT.HORIZONTAL;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/LegacyActionPersistence.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/LegacyActionPersistence.java
new file mode 100644
index 0000000..49c34c0
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/LegacyActionPersistence.java
@@ -0,0 +1,723 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.menus;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import org.eclipse.core.commands.Category;
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.commands.State;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.IRegistryChangeEvent;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.LegacyActionTools;
+import org.eclipse.jface.commands.RadioState;
+import org.eclipse.jface.commands.ToggleState;
+import org.eclipse.jface.menus.IMenuStateIds;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.SelectionEnabler;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.handlers.IHandlerActivation;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.expressions.LegacyActionSetExpression;
+import org.eclipse.ui.internal.expressions.LegacyEditorContributionExpression;
+import org.eclipse.ui.internal.expressions.LegacySelectionEnablerWrapper;
+import org.eclipse.ui.internal.expressions.LegacyViewContributionExpression;
+import org.eclipse.ui.internal.handlers.ActionDelegateHandlerProxy;
+import org.eclipse.ui.internal.handlers.IActionCommandMappingService;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.services.RegistryPersistence;
+
+/**
+ * <p>
+ * A static class for reading actions from the registry. Actions were the
+ * mechanism in 3.1 and earlier for contributing to menus and tool bars in the
+ * Eclipse workbench. They have since been replaced with commands.
+ * </p>
+ * <p>
+ * This class is not intended for use outside of the
+ * <code>org.eclipse.ui.workbench</code> plug-in.
+ * </p>
+ *
+ * @since 3.2
+ */
+public final class LegacyActionPersistence extends RegistryPersistence {
+
+	/**
+	 * The index of the action set elements in the indexed array.
+	 *
+	 * @see LegacyActionPersistence#read()
+	 */
+	private static final int INDEX_ACTION_SETS = 0;
+
+	/**
+	 * The index of the editor contribution elements in the indexed array.
+	 *
+	 * @see LegacyActionPersistence#read()
+	 */
+	private static final int INDEX_EDITOR_CONTRIBUTIONS = INDEX_ACTION_SETS + 1;
+
+	/**
+	 * The index of the view contribution elements in the indexed array.
+	 *
+	 * @see LegacyActionPersistence#read()
+	 */
+	private static final int INDEX_VIEW_CONTRIBUTIONS = INDEX_EDITOR_CONTRIBUTIONS + 1;
+
+
+
+	/**
+	 * The command service which is providing the commands for the workbench;
+	 * must not be <code>null</code>.
+	 */
+	private final ICommandService commandService;
+
+	/**
+	 * The handler activations that have come from the registry. This is used to
+	 * flush the activations when the registry is re-read. This value is never
+	 * <code>null</code>
+	 */
+	private final Collection handlerActivations = new ArrayList();
+
+	/**
+	 * The menu contributions that have come from the registry. This is used to
+	 * flush the contributions when the registry is re-read. This value is never
+	 * <code>null</code>
+	 */
+	private final Collection menuContributions = new ArrayList();
+
+	/**
+	 * The service locator from which services can be retrieved in the future;
+	 * must not be <code>null</code>.
+	 */
+	private final IWorkbenchWindow window;
+
+	/**
+	 * Constructs a new instance of {@link LegacyActionPersistence}.
+	 *
+	 * @param window
+	 *            The window from which the services should be retrieved; must
+	 *            not be <code>null</code>.
+	 */
+	public LegacyActionPersistence(final IWorkbenchWindow window) {
+		// TODO Blind casts are bad.
+		this.commandService = window
+				.getService(ICommandService.class);
+		this.window = window;
+	}
+
+	/**
+	 * Deactivates all of the activations made by this class, and then clears
+	 * the collection. This should be called before every read.
+	 */
+	private final void clearActivations() {
+		final IHandlerService service = window
+				.getService(IHandlerService.class);
+		if (service == null) {
+			handlerActivations.clear();
+			return;
+		}
+		service.deactivateHandlers(handlerActivations);
+		final Iterator activationItr = handlerActivations.iterator();
+		while (activationItr.hasNext()) {
+			final IHandlerActivation activation = (IHandlerActivation) activationItr
+					.next();
+			final IHandler handler = activation.getHandler();
+			if (handler != null) {
+				handler.dispose();
+			}
+		}
+		handlerActivations.clear();
+	}
+
+	/**
+	 * Removes all of the image bindings made by this class, and then clears the
+	 * collection. This should be called before every read.
+	 *
+	 */
+	private final void clearImages() {
+		// TODO Implement
+	}
+
+	/**
+	 * Removes all of the contributions made by this class, and then clears the
+	 * collection. This should be called before every read.
+	 */
+	private final void clearMenus() {
+		menuContributions.clear();
+	}
+
+	/**
+	 * Determine which command to use. This is slightly complicated as actions
+	 * do not have to have commands, but the new architecture requires it. As
+	 * such, we will auto-generate a command for the action if the definitionId
+	 * is missing or points to a command that does not yet exist. All such
+	 * command identifiers are prefixed with AUTOGENERATED_COMMAND_ID_PREFIX.
+	 *
+	 * @param element
+	 *            The action element from which a command must be generated;
+	 *            must not be <code>null</code>.
+	 * @param primaryId
+	 *            The primary identifier to use when auto-generating a command;
+	 *            must not be <code>null</code>.
+	 * @param secondaryId
+	 *            The secondary identifier to use when auto-generating a
+	 *            command; must not be <code>null</code>.
+	 * @param warningsToLog
+	 *            The collection of warnings logged while reading the extension
+	 *            point; must not be <code>null</code>.
+	 * @return the fully-parameterized command; <code>null</code> if an error
+	 *         occurred.
+	 */
+	private final ParameterizedCommand convertActionToCommand(
+			final IConfigurationElement element, final String primaryId,
+			final String secondaryId, final List warningsToLog) {
+		String commandId = readOptional(element, ATT_DEFINITION_ID);
+		Command command = null;
+		if (commandId != null) {
+			command = commandService.getCommand(commandId);
+		}
+
+		final IActionCommandMappingService mappingService = window
+				.getService(IActionCommandMappingService.class);
+
+		String label = null;
+		if ((commandId == null) || (!command.isDefined())) {
+			// Add a mapping from this action id to the command id.
+			if (commandId == null && mappingService != null) {
+				commandId = mappingService.getGeneratedCommandId(primaryId,
+						secondaryId);
+			}
+			if (commandId == null) {
+				WorkbenchPlugin.log("MappingService unavailable"); //$NON-NLS-1$
+				return null;
+			}
+
+			// Read the label attribute.
+			label = readRequired(element, ATT_LABEL, warningsToLog,
+					"Actions require a non-empty label or definitionId", //$NON-NLS-1$
+					commandId);
+			if (label == null) {
+				label = WorkbenchMessages.get().LegacyActionPersistence_AutogeneratedCommandName;
+			}
+
+			/*
+			 * Read the tooltip attribute. The tooltip is really the description
+			 * of the command.
+			 */
+			final String tooltip = readOptional(element, ATT_TOOLTIP);
+
+			// Define the command.
+			command = commandService.getCommand(commandId);
+			final Category category = commandService.getCategory(null);
+			final String name = LegacyActionTools.removeAcceleratorText(Action
+					.removeMnemonics(label));
+			command.define(name, tooltip, category, null);
+
+			// TODO Decide the command state.
+			final String style = readOptional(element, ATT_STYLE);
+			if (STYLE_RADIO.equals(style)) {
+				final State state = new RadioState();
+				// TODO How to set the id?
+				final boolean checked = readBoolean(element, ATT_STATE, false);
+				state.setValue((checked) ? Boolean.TRUE : Boolean.FALSE);
+				command.addState(IMenuStateIds.STYLE, state);
+
+			} else if (STYLE_TOGGLE.equals(style)) {
+				final State state = new ToggleState();
+				final boolean checked = readBoolean(element, ATT_STATE, false);
+				state.setValue((checked) ? Boolean.TRUE : Boolean.FALSE);
+				command.addState(IMenuStateIds.STYLE, state);
+			}
+		}
+		// this allows us to look up a "commandId" give the contributionId
+		// and the actionId
+		if (mappingService != null && commandId != null) {
+			mappingService.map(mappingService.getGeneratedCommandId(primaryId,
+					secondaryId), commandId);
+		}
+
+		return new ParameterizedCommand(command, null);
+	}
+
+	/**
+	 * <p>
+	 * Extracts the handler information from the given action element. These are
+	 * registered with the handler service. They are always active.
+	 * </p>
+	 *
+	 * @param element
+	 *            The action element from which the handler should be read; must
+	 *            not be <code>null</code>.
+	 * @param actionId
+	 *            The identifier of the action for which a handler is being
+	 *            created; must not be <code>null</code>.
+	 * @param command
+	 *            The command for which this handler applies; must not be
+	 *            <code>null</code>.
+	 * @param activeWhenExpression
+	 *            The expression controlling when the handler is active; may be
+	 *            <code>null</code>.
+	 * @param viewId
+	 *            The view to which this handler is associated. This value is
+	 *            required if this is a view action; otherwise it can be
+	 *            <code>null</code>.
+	 * @param warningsToLog
+	 *            The collection of warnings while parsing this extension point;
+	 *            must not be <code>null</code>.
+	 */
+	private final void convertActionToHandler(
+			final IConfigurationElement element, final String actionId,
+			final ParameterizedCommand command,
+			final Expression activeWhenExpression, final String viewId,
+			final List warningsToLog) {
+		// Check to see if this is a retargettable action.
+		final boolean retarget = readBoolean(element, ATT_RETARGET, false);
+
+		final boolean classAvailable = (element.getAttribute(ATT_CLASS) != null)
+				|| (element.getChildren(TAG_CLASS).length != 0);
+		// Read the class attribute.
+		String classString = readOptional(element, ATT_CLASS);
+		if (classAvailable && classString == null) {
+			classString = readOptional(element.getChildren(TAG_CLASS)[0],
+					ATT_CLASS);
+		}
+
+		if (retarget) {
+			if (classAvailable && !isPulldown(element)) {
+				addWarning(warningsToLog,
+						"The class was not null but retarget was set to true", //$NON-NLS-1$
+						element, actionId, ATT_CLASS, classString);
+			}
+
+			// Add a mapping from this action id to the command id.
+			final IActionCommandMappingService mappingService = window
+					.getService(IActionCommandMappingService.class);
+			if (mappingService != null) {
+				mappingService.map(actionId, command.getId());
+			} else {
+				// this is probably the shutdown case where the service has
+				// already disposed.
+				addWarning(
+						warningsToLog,
+						"Retarget service unavailable", //$NON-NLS-1$
+						element, actionId);
+			}
+			return; // This is nothing more to be done.
+
+		} else if (!classAvailable) {
+			addWarning(
+					warningsToLog,
+					"There was no class provided, and the action is not retargettable", //$NON-NLS-1$
+					element, actionId);
+			return; // There is nothing to be done.
+		}
+
+		// Read the enablesFor attribute, and enablement and selection elements.
+		SelectionEnabler enabler = null;
+		if (element.getAttribute(ATT_ENABLES_FOR) != null) {
+			enabler = new SelectionEnabler(element);
+		} else {
+			IConfigurationElement[] kids = element.getChildren(TAG_ENABLEMENT);
+			if (kids.length > 0) {
+				enabler = new SelectionEnabler(element);
+			}
+		}
+		final Expression enabledWhenExpression;
+		if (enabler == null) {
+			enabledWhenExpression = null;
+		} else {
+			enabledWhenExpression = new LegacySelectionEnablerWrapper(enabler,
+					window);
+		}
+
+		/*
+		 * Create the handler. TODO The image style is read at the workbench
+		 * level, but it is hard to communicate this information to this point.
+		 * For now, I'll pass null, but this ultimately won't work.
+		 */
+		final ActionDelegateHandlerProxy handler = new ActionDelegateHandlerProxy(
+				element, ATT_CLASS, actionId, command, window, null,
+				enabledWhenExpression, viewId);
+
+		// Read the help context id.
+		final String helpContextId = readOptional(element, ATT_HELP_CONTEXT_ID);
+		if (helpContextId != null) {
+			commandService.setHelpContextId(handler, helpContextId);
+		}
+
+		// Activate the handler.
+		final String commandId = command.getId();
+		final IHandlerService service = window
+				.getService(IHandlerService.class);
+		final IHandlerActivation handlerActivation;
+		if (activeWhenExpression == null) {
+			handlerActivation = service.activateHandler(commandId, handler);
+		} else {
+			handlerActivation = service.activateHandler(commandId, handler,
+					activeWhenExpression);
+		}
+		handlerActivations.add(handlerActivation);
+	}
+
+
+
+	@Override
+	public final void dispose() {
+		super.dispose();
+		clear();
+	}
+
+	private void clear() {
+		clearActivations();
+		clearImages();
+		clearMenus();
+	}
+
+	protected final boolean isChangeImportant(final IRegistryChangeEvent event) {
+        // RAP [bm]: 
+//      return !((event.getExtensionDeltas(PlatformUI.PLUGIN_ID,
+//              IWorkbenchRegistryConstants.PL_ACTION_SETS).length == 0)
+//              && (event.getExtensionDeltas(PlatformUI.PLUGIN_ID,
+//                      IWorkbenchRegistryConstants.PL_EDITOR_ACTIONS).length == 0)
+//              && (event.getExtensionDeltas(PlatformUI.PLUGIN_ID,
+//                      IWorkbenchRegistryConstants.PL_POPUP_MENU).length == 0) && (event
+//              .getExtensionDeltas(PlatformUI.PLUGIN_ID,
+//                      IWorkbenchRegistryConstants.PL_VIEW_ACTIONS).length == 0));
+        return !((event.getExtensionDeltas(PlatformUI.PLUGIN_EXTENSION_NAME_SPACE,
+                IWorkbenchRegistryConstants.PL_ACTION_SETS).length == 0)
+                && (event.getExtensionDeltas(PlatformUI.PLUGIN_EXTENSION_NAME_SPACE,
+                        IWorkbenchRegistryConstants.PL_EDITOR_ACTIONS).length == 0)
+                && (event.getExtensionDeltas(PlatformUI.PLUGIN_EXTENSION_NAME_SPACE,
+                        IWorkbenchRegistryConstants.PL_POPUP_MENU).length == 0) && (event
+                .getExtensionDeltas(PlatformUI.PLUGIN_EXTENSION_NAME_SPACE,
+                        IWorkbenchRegistryConstants.PL_VIEW_ACTIONS).length == 0));
+        // RAPEND: [bm] 
+    }
+
+	/**
+	 * <p>
+	 * Reads all of the actions from the deprecated extension points. Actions
+	 * have been replaced with commands, command images, handlers, menu elements
+	 * and action sets.
+	 * </p>
+	 * <p>
+	 * TODO Before this method is called, all of the extension points must be
+	 * cleared.
+	 * </p>
+	 */
+	@Override
+	public final void read() {
+		clear();
+		LegacyActionPersistence.super.read();
+
+		// Create the extension registry mementos.
+		final IExtensionRegistry registry = Platform.getExtensionRegistry();
+		int actionSetCount = 0;
+		int editorContributionCount = 0;
+		int viewContributionCount = 0;
+		final IConfigurationElement[][] indexedConfigurationElements = new IConfigurationElement[5][];
+
+		// Sort the actionSets extension point.
+		for (final IConfigurationElement configElement : registry.getConfigurationElementsFor(EXTENSION_ACTION_SETS)) {
+			final String name = configElement.getName();
+			if (TAG_ACTION_SET.equals(name)) {
+				addElementToIndexedArray(configElement, indexedConfigurationElements,
+						INDEX_ACTION_SETS, actionSetCount++);
+			}
+		}
+
+		// Sort the editorActions extension point.
+		for (final IConfigurationElement configElement : registry
+				.getConfigurationElementsFor(EXTENSION_EDITOR_ACTIONS)) {
+			final String name = configElement.getName();
+			if (TAG_EDITOR_CONTRIBUTION.equals(name)) {
+				addElementToIndexedArray(configElement, indexedConfigurationElements,
+						INDEX_EDITOR_CONTRIBUTIONS, editorContributionCount++);
+			}
+		}
+
+		// Sort the viewActions extension point.
+		for (final IConfigurationElement configElement : registry.getConfigurationElementsFor(EXTENSION_VIEW_ACTIONS)) {
+			final String name = configElement.getName();
+			if (TAG_VIEW_CONTRIBUTION.equals(name)) {
+				addElementToIndexedArray(configElement, indexedConfigurationElements,
+						INDEX_VIEW_CONTRIBUTIONS, viewContributionCount++);
+			}
+		}
+
+		readActionSets(indexedConfigurationElements[INDEX_ACTION_SETS],
+				actionSetCount);
+		readEditorContributions(
+				indexedConfigurationElements[INDEX_EDITOR_CONTRIBUTIONS],
+				editorContributionCount);
+		readViewContributions(
+				indexedConfigurationElements[INDEX_VIEW_CONTRIBUTIONS],
+				viewContributionCount);
+
+	}
+
+	/**
+	 * Reads the actions, and defines all the necessary subcomponents in terms
+	 * of the command architecture. For each action, there could be a command, a
+	 * command image binding, a handler and a menu item.
+	 *
+	 * @param primaryId
+	 *            The identifier of the primary object to which this action
+	 *            belongs. This is used to auto-generate command identifiers
+	 *            when required. The <code>primaryId</code> must not be
+	 *            <code>null</code>.
+	 * @param elements
+	 *            The action elements to be read; must not be <code>null</code>.
+	 * @param warningsToLog
+	 *            The collection of warnings while parsing this extension point;
+	 *            must not be <code>null</code>.
+	 * @param visibleWhenExpression
+	 *            The expression controlling visibility of the corresponding
+	 *            menu elements; may be <code>null</code>.
+	 * @param viewId
+	 *            The view to which this handler is associated. This value is
+	 *            required if this is a view action; otherwise it can be
+	 *            <code>null</code>.
+	 * @return References to the created menu elements; may be <code>null</code>,
+	 *         and may be empty.
+	 */
+	private final void readActions(final String primaryId,
+			final IConfigurationElement[] elements, final List warningsToLog,
+			final Expression visibleWhenExpression, final String viewId) {
+		for (final IConfigurationElement configElement : elements) {
+			/*
+			 * We might need the identifier to generate the command, so we'll
+			 * read it out now.
+			 */
+			final String id = readRequired(configElement, ATT_ID, warningsToLog, "Actions require an id"); //$NON-NLS-1$
+			if (id == null) {
+				continue;
+			}
+
+			// Try to break out the command part of the action.
+			final ParameterizedCommand command = convertActionToCommand(configElement, primaryId, id, warningsToLog);
+			if (command == null) {
+				continue;
+			}
+
+			convertActionToHandler(configElement, id, command, visibleWhenExpression, viewId, warningsToLog);
+			// TODO Read the overrideActionId attribute
+		}
+	}
+
+	/**
+	 * Reads all of the action and menu child elements from the given element.
+	 *
+	 * @param element
+	 *            The configuration element from which the actions and menus
+	 *            should be read; must not be <code>null</code>, but may be
+	 *            empty.
+	 * @param id
+	 *            The identifier of the contribution being made. This could be
+	 *            an action set, an editor contribution, a view contribution, a
+	 *            viewer contribution or an object contribution. This value must
+	 *            not be <code>null</code>.
+	 * @param warningsToLog
+	 *            The list of warnings already logged for this extension point;
+	 *            must not be <code>null</code>.
+	 * @param visibleWhenExpression
+	 *            The expression controlling visibility of the corresponding
+	 *            menu elements; may be <code>null</code>.
+	 * @param viewId
+	 *            The view to which this handler is associated. This value is
+	 *            required if this is a view action; otherwise it can be
+	 *            <code>null</code>.
+	 * @return An array of references to the created menu elements. This value
+	 *         may be <code>null</code> if there was a problem parsing the
+	 *         configuration element.
+	 */
+	private final void readActionsAndMenus(
+			final IConfigurationElement element, final String id,
+			final List warningsToLog,
+			final Expression visibleWhenExpression, final String viewId) {
+
+		// Read its child elements.
+		final IConfigurationElement[] actionElements = element
+				.getChildren(TAG_ACTION);
+		readActions(id, actionElements,
+				warningsToLog, visibleWhenExpression, viewId);
+
+	}
+
+	/**
+	 * Reads the deprecated actions from an array of elements from the action
+	 * sets extension point.
+	 *
+	 * @param configurationElements
+	 *            The configuration elements in the extension point; must not be
+	 *            <code>null</code>, but may be empty.
+	 * @param configurationElementCount
+	 *            The number of configuration elements that are really in the
+	 *            array.
+	 */
+	private final void readActionSets(
+			final IConfigurationElement[] configurationElements,
+			final int configurationElementCount) {
+		//
+		// this was an even dumber fix than modifying the path
+		//
+		// stupid navigate group
+		// SGroup nav = menuService.getGroup(STUPID_NAVIGATE);
+		// if (!nav.isDefined()) {
+		// nav.define(new SLocation(new SBar(SBar.TYPE_MENU, null)));
+		// }
+		// stupid navigate group
+
+		final List warningsToLog = new ArrayList(1);
+
+		for (int i = 0; i < configurationElementCount; i++) {
+			final IConfigurationElement element = configurationElements[i];
+
+			// Read the action set identifier.
+			final String id = readRequired(element, ATT_ID, warningsToLog,
+					"Action sets need an id"); //$NON-NLS-1$
+			if (id == null) {
+				continue;
+			}
+
+			// Read the label.
+			final String label = readRequired(element, ATT_LABEL,
+					warningsToLog, "Actions set need a label", //$NON-NLS-1$
+					id);
+			if (label == null) {
+				continue;
+			}
+
+			// Restrict the handler to when the action set is active.
+			final LegacyActionSetExpression expression = new LegacyActionSetExpression(
+					id, window);
+
+
+			// Read all of the child elements.
+			readActionsAndMenus(element, id,
+					warningsToLog, expression, null);
+			// Define the action set.
+		}
+
+		logWarnings(
+				warningsToLog,
+				"Warnings while parsing the action sets from the 'org.eclipse.ui.actionSets' extension point"); //$NON-NLS-1$
+	}
+
+	/**
+	 * Reads the deprecated editor contributions from an array of elements from
+	 * the editor actions extension point.
+	 *
+	 * @param configurationElements
+	 *            The configuration elements in the extension point; must not be
+	 *            <code>null</code>, but may be empty.
+	 * @param configurationElementCount
+	 *            The number of configuration elements that are really in the
+	 *            array.
+	 */
+	private final void readEditorContributions(
+			final IConfigurationElement[] configurationElements,
+			final int configurationElementCount) {
+		final List warningsToLog = new ArrayList(1);
+
+		for (int i = 0; i < configurationElementCount; i++) {
+			final IConfigurationElement element = configurationElements[i];
+
+			// Read the editor contribution identifier.
+			final String id = readRequired(element, ATT_ID, warningsToLog,
+					"Editor contributions need an id"); //$NON-NLS-1$
+			if (id == null) {
+				continue;
+			}
+
+			/*
+			 * Read the target id. This is the identifier of the editor with
+			 * which these contributions are associated.
+			 */
+			final String targetId = readRequired(element, ATT_TARGET_ID,
+					warningsToLog, "Editor contributions need a target id", id); //$NON-NLS-1$
+			if (targetId == null) {
+				continue;
+			}
+			final Expression visibleWhenExpression = new LegacyEditorContributionExpression(
+					targetId, window);
+
+			// Read all of the child elements from the registry.
+			readActionsAndMenus(element, id, warningsToLog,
+					visibleWhenExpression, null);
+		}
+
+		logWarnings(
+				warningsToLog,
+				"Warnings while parsing the editor contributions from the 'org.eclipse.ui.editorActions' extension point"); //$NON-NLS-1$
+	}
+
+	/**
+	 * Reads the deprecated view contributions from an array of elements from
+	 * the view actions extension point.
+	 *
+	 * @param configurationElements
+	 *            The configuration elements in the extension point; must not be
+	 *            <code>null</code>, but may be empty.
+	 * @param configurationElementCount
+	 *            The number of configuration elements that are really in the
+	 *            array.
+	 */
+	private final void readViewContributions(
+			final IConfigurationElement[] configurationElements,
+			final int configurationElementCount) {
+		final List warningsToLog = new ArrayList(1);
+
+		for (int i = 0; i < configurationElementCount; i++) {
+			final IConfigurationElement element = configurationElements[i];
+
+			// Read the view contribution identifier.
+			final String id = readRequired(element, ATT_ID, warningsToLog,
+					"View contributions need an id"); //$NON-NLS-1$
+			if (id == null) {
+				continue;
+			}
+
+			/*
+			 * Read the target id. This is the identifier of the view with which
+			 * these contributions are associated.
+			 */
+			final String targetId = readRequired(element, ATT_TARGET_ID,
+					warningsToLog, "View contributions need a target id", id); //$NON-NLS-1$
+			if (targetId == null) {
+				continue;
+			}
+			final Expression visibleWhenExpression = new LegacyViewContributionExpression(
+					targetId, window);
+
+			// Read all of the child elements from the registry.
+			readActionsAndMenus(element, id, warningsToLog,
+					visibleWhenExpression, targetId);
+		}
+
+		logWarnings(
+				warningsToLog,
+				"Warnings while parsing the view contributions from the 'org.eclipse.ui.viewActions' extension point"); //$NON-NLS-1$
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/MenuAdditionCacheEntry.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/MenuAdditionCacheEntry.java
new file mode 100644
index 0000000..f764db5
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/MenuAdditionCacheEntry.java
@@ -0,0 +1,582 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2016 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
+ *     Remy Chi Jian Suen <remy.suen@gmail.com> - Bug 221662 [Contributions] Extension point org.eclipse.ui.menus: sub menu contribution does not have icon even if specified
+ *     Christian Walther (Indel AG) - Bug 398631: Use correct menu item icon from commandImages
+ *     Christian Walther (Indel AG) - Bug 384056: Use disabled icon from extension definition
+ *     Axel Richard <axel.richard@obeo.fr> - Bug 392457
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.menus;
+
+import java.util.ArrayList;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.e4.core.contexts.ContextFunction;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.ui.internal.workbench.ContributionsAnalyzer;
+import org.eclipse.e4.ui.internal.workbench.RenderedElementUtil;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.MApplicationElement;
+import org.eclipse.e4.ui.model.application.commands.MCommand;
+import org.eclipse.e4.ui.model.application.commands.MParameter;
+import org.eclipse.e4.ui.model.application.commands.impl.CommandsFactoryImpl;
+import org.eclipse.e4.ui.model.application.ui.MElementContainer;
+import org.eclipse.e4.ui.model.application.ui.menu.MHandledMenuItem;
+import org.eclipse.e4.ui.model.application.ui.menu.MHandledToolItem;
+import org.eclipse.e4.ui.model.application.ui.menu.MMenu;
+import org.eclipse.e4.ui.model.application.ui.menu.MMenuContribution;
+import org.eclipse.e4.ui.model.application.ui.menu.MMenuElement;
+import org.eclipse.e4.ui.model.application.ui.menu.MMenuFactory;
+import org.eclipse.e4.ui.model.application.ui.menu.MMenuItem;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolBar;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolBarContribution;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolBarElement;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolControl;
+import org.eclipse.e4.ui.model.application.ui.menu.MTrimContribution;
+import org.eclipse.e4.ui.model.application.ui.menu.impl.MenuFactoryImpl;
+import org.eclipse.e4.ui.services.help.EHelpService;
+import org.eclipse.e4.ui.workbench.renderers.swt.MenuManagerRenderer;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.activities.IActivityManager;
+import org.eclipse.ui.activities.IIdentifier;
+import org.eclipse.ui.activities.IIdentifierListener;
+import org.eclipse.ui.activities.IdentifierEvent;
+import org.eclipse.ui.commands.ICommandImageService;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.services.ServiceLocator;
+import org.eclipse.ui.menus.CommandContributionItem;
+
+public class MenuAdditionCacheEntry {
+	private static final String AFTER_ADDITIONS = "after=additions"; //$NON-NLS-1$
+
+	final static String MAIN_TOOLBAR = ActionSet.MAIN_TOOLBAR;
+
+	final static String TRIM_COMMAND1 = "org.eclipse.ui.trim.command1"; //$NON-NLS-1$
+
+	final static String TRIM_COMMAND2 = "org.eclipse.ui.trim.command2"; //$NON-NLS-1$
+
+	final static String TRIM_VERTICAL1 = "org.eclipse.ui.trim.vertical1"; //$NON-NLS-1$
+
+	final static String TRIM_VERTICAL2 = "org.eclipse.ui.trim.vertical2"; //$NON-NLS-1$
+
+	final static String TRIM_STATUS = "org.eclipse.ui.trim.status"; //$NON-NLS-1$
+
+	/**
+	 * Test whether the location URI is in one of the pre-defined workbench trim
+	 * areas.
+	 *
+	 * @param location
+	 * @return true if the URI is in workbench trim area.
+	 */
+	static boolean isInWorkbenchTrim(MenuLocationURI location) {
+		final String path = location.getPath();
+		return MAIN_TOOLBAR.equals(path) || TRIM_COMMAND1.equals(path)
+				|| TRIM_COMMAND2.equals(path) || TRIM_VERTICAL1.equals(path)
+				|| TRIM_VERTICAL2.equals(path) || TRIM_STATUS.equals(path);
+	}
+
+	private MApplication application;
+	// private IEclipseContext appContext;
+	private IConfigurationElement configElement;
+	private MenuLocationURI location;
+
+	private String namespaceIdentifier;
+
+	private IActivityManager activityManager;
+
+	public MenuAdditionCacheEntry(MApplication application, IEclipseContext appContext,
+			IConfigurationElement configElement, String attribute, String namespaceIdentifier) {
+		this.application = application;
+		// this.appContext = appContext;
+		assert appContext.equals(this.application.getContext());
+		this.configElement = configElement;
+		this.location = new MenuLocationURI(attribute);
+		this.namespaceIdentifier = namespaceIdentifier;
+
+		IWorkbench workbench = application.getContext().get(IWorkbench.class);
+		activityManager = workbench.getActivitySupport().getActivityManager();
+	}
+
+	private boolean inToolbar() {
+		return location.getScheme().startsWith("toolbar"); //$NON-NLS-1$
+	}
+
+	/**
+	 * @return <code>true</code> if this is a toolbar contribution
+	 */
+	public void mergeIntoModel(ArrayList<MMenuContribution> menuContributions,
+			ArrayList<MToolBarContribution> toolBarContributions,
+			ArrayList<MTrimContribution> trimContributions) {
+		boolean hasAdditions = false;
+		if ("menu:help?after=additions".equals(location.toString())) { //$NON-NLS-1$
+			IConfigurationElement[] menus = configElement
+					.getChildren(IWorkbenchRegistryConstants.TAG_MENU);
+			if (menus.length == 1
+					&& "org.eclipse.update.ui.updateMenu".equals(MenuHelper.getId(menus[0]))) { //$NON-NLS-1$
+				return;
+			}
+		}
+		if (location.getPath() == null || location.getPath().length() == 0) {
+			WorkbenchPlugin
+					.log("MenuAdditionCacheEntry.mergeIntoModel: Invalid menu URI: " + location); //$NON-NLS-1$
+			return;
+		}
+		if (inToolbar()) {
+			if (isInWorkbenchTrim(location)) {
+				processTrimChildren(trimContributions, toolBarContributions, configElement);
+			} else {
+				String query = location.getQuery();
+				hasAdditions = AFTER_ADDITIONS.equals(query);
+				if (query == null || query.length() == 0) {
+					query = AFTER_ADDITIONS;
+				}
+				processToolbarChildren(toolBarContributions, configElement, location.getPath(),
+						query, hasAdditions);
+			}
+			return;
+		}
+		MMenuContribution menuContribution = MenuFactoryImpl.eINSTANCE.createMenuContribution();
+		String idContrib = MenuHelper.getId(configElement);
+		if (idContrib != null && idContrib.length() > 0) {
+			menuContribution.setElementId(idContrib);
+		}
+		String query = location.getQuery();
+		if ("org.eclipse.ui.popup.any".equals(location.getPath())) { //$NON-NLS-1$
+			menuContribution.setParentId("popup"); //$NON-NLS-1$
+		} else {
+			menuContribution.setParentId(location.getPath());
+			hasAdditions = AFTER_ADDITIONS.equals(query);
+		}
+		if (query == null || query.length() == 0) {
+			query = AFTER_ADDITIONS;
+		}
+		menuContribution.setPositionInParent(query);
+		menuContribution.getTags().add("scheme:" + location.getScheme()); //$NON-NLS-1$
+		String filter = ContributionsAnalyzer.MC_MENU;
+		if ("popup".equals(location.getScheme())) { //$NON-NLS-1$
+			filter = ContributionsAnalyzer.MC_POPUP;
+		}
+		menuContribution.getTags().add(filter);
+		menuContribution.setVisibleWhen(MenuHelper.getVisibleWhen(configElement));
+		addMenuChildren(menuContribution, configElement, filter);
+		if (hasAdditions) {
+			menuContributions.add(0, menuContribution);
+		} else {
+			menuContributions.add(menuContribution);
+		}
+		processMenuChildren(menuContributions, configElement, filter);
+	}
+
+	/**
+	 * @param menuContributions
+	 * @param filter
+	 */
+	private void processMenuChildren(ArrayList<MMenuContribution> menuContributions,
+			IConfigurationElement element, String filter) {
+		IConfigurationElement[] menus = element.getChildren(IWorkbenchRegistryConstants.TAG_MENU);
+		if (menus.length == 0) {
+			return;
+		}
+		for (IConfigurationElement menu : menus) {
+			MMenuContribution menuContribution = MenuFactoryImpl.eINSTANCE.createMenuContribution();
+			String idContrib = MenuHelper.getId(menu);
+			if (idContrib != null && idContrib.length() > 0) {
+				menuContribution.setElementId(idContrib);
+			}
+			menuContribution.setParentId(idContrib);
+			menuContribution.setPositionInParent(AFTER_ADDITIONS);
+			menuContribution.getTags().add("scheme:" + location.getScheme()); //$NON-NLS-1$
+			menuContribution.getTags().add(filter);
+			menuContribution.setVisibleWhen(MenuHelper.getVisibleWhen(menu));
+			addMenuChildren(menuContribution, menu, filter);
+			menuContributions.add(menuContribution);
+			processMenuChildren(menuContributions, menu, filter);
+		}
+	}
+
+	private void addMenuChildren(final MElementContainer<MMenuElement> container,
+			IConfigurationElement parent, String filter) {
+		for (final IConfigurationElement child : parent.getChildren()) {
+			String itemType = child.getName();
+			String id = MenuHelper.getId(child);
+
+			if (IWorkbenchRegistryConstants.TAG_COMMAND.equals(itemType)) {
+				MMenuElement element = createMenuCommandAddition(child);
+				container.getChildren().add(element);
+			} else if (IWorkbenchRegistryConstants.TAG_SEPARATOR.equals(itemType)) {
+				MMenuElement element = createMenuSeparatorAddition(child);
+				container.getChildren().add(element);
+			} else if (IWorkbenchRegistryConstants.TAG_MENU.equals(itemType)) {
+				MMenu element = createMenuAddition(child, filter);
+				container.getChildren().add(element);
+			} else if (IWorkbenchRegistryConstants.TAG_TOOLBAR.equals(itemType)) {
+				System.out.println("Toolbar: " + id + " in " + location); //$NON-NLS-1$//$NON-NLS-2$
+			} else if (IWorkbenchRegistryConstants.TAG_DYNAMIC.equals(itemType)) {
+				ContextFunction generator = new ContextFunction() {
+					@Override
+					public Object compute(IEclipseContext context, String contextKey) {
+						ServiceLocator sl = new ServiceLocator();
+						sl.setContext(context);
+						DynamicMenuContributionItem item = new DynamicMenuContributionItem(
+								MenuHelper.getId(child), sl, child);
+						return item;
+					}
+				};
+
+				MMenuItem menuItem = RenderedElementUtil.createRenderedMenuItem();
+				menuItem.setElementId(id);
+				RenderedElementUtil.setContributionManager(menuItem, generator);
+				menuItem.setVisibleWhen(MenuHelper.getVisibleWhen(child));
+				container.getChildren().add(menuItem);
+			}
+		}
+	}
+
+	/**
+	 * @param iConfigurationElement
+	 * @return
+	 */
+	private MMenuElement createMenuCommandAddition(IConfigurationElement commandAddition) {
+		MHandledMenuItem item = MenuFactoryImpl.eINSTANCE.createHandledMenuItem();
+		item.setElementId(MenuHelper.getId(commandAddition));
+		String commandId = MenuHelper.getCommandId(commandAddition);
+		MCommand commandById = ContributionsAnalyzer.getCommandById(application, commandId);
+		if (commandById == null) {
+			commandById = CommandsFactoryImpl.eINSTANCE.createCommand();
+			commandById.setElementId(commandId);
+			commandById.setCommandName(commandId);
+			application.getCommands().add(commandById);
+		}
+		item.setCommand(commandById);
+		Map parms = MenuHelper.getParameters(commandAddition);
+		for (Object obj : parms.entrySet()) {
+			Map.Entry e = (Map.Entry) obj;
+			MParameter parm = CommandsFactoryImpl.eINSTANCE.createParameter();
+			parm.setName(e.getKey().toString());
+			parm.setValue(e.getValue().toString());
+			item.getParameters().add(parm);
+		}
+		String iconUrl = MenuHelper.getIconURI(commandAddition,
+				IWorkbenchRegistryConstants.ATT_ICON);
+
+		if (iconUrl == null) {
+			ICommandImageService commandImageService = application.getContext().get(
+					ICommandImageService.class);
+			ImageDescriptor descriptor = commandImageService == null ? null : commandImageService
+					.getImageDescriptor(commandId);
+			if (descriptor == null) {
+				descriptor = commandImageService == null ? null : commandImageService
+						.getImageDescriptor(item.getElementId());
+			}
+			if (descriptor != null) {
+				item.setIconURI(MenuHelper.getImageUrl(descriptor));
+			}
+		} else {
+			item.setIconURI(iconUrl);
+		}
+		item.setLabel(MenuHelper.getLabel(commandAddition));
+		item.setMnemonics(MenuHelper.getMnemonic(commandAddition));
+		item.setTooltip(MenuHelper.getTooltip(commandAddition));
+		item.setType(MenuHelper.getStyle(commandAddition));
+		item.setVisibleWhen(MenuHelper.getVisibleWhen(commandAddition));
+		String helpContextId = MenuHelper.getHelpContextId(commandAddition);
+		if (helpContextId != null) {
+			item.getPersistedState().put(EHelpService.HELP_CONTEXT_ID, helpContextId);
+		}
+		createIdentifierTracker(item);
+		return item;
+	}
+
+	private class IdListener implements IIdentifierListener {
+		@Override
+		public void identifierChanged(IdentifierEvent identifierEvent) {
+			application.getContext().set(identifierEvent.getIdentifier().getId(),
+					identifierEvent.getIdentifier().isEnabled());
+		}
+	}
+
+	private IdListener idUpdater = new IdListener();
+
+	private void createIdentifierTracker(MApplicationElement item) {
+		if (item.getElementId() != null && item.getElementId().length() > 0) {
+			String id = namespaceIdentifier + "/" + item.getElementId(); //$NON-NLS-1$
+			item.getPersistedState().put(MenuManagerRenderer.VISIBILITY_IDENTIFIER, id);
+			final IIdentifier identifier = activityManager.getIdentifier(id);
+			if (identifier != null) {
+				application.getContext().set(identifier.getId(), identifier.isEnabled());
+				identifier.addIdentifierListener(idUpdater);
+			}
+		}
+	}
+
+	private MMenuElement createMenuSeparatorAddition(final IConfigurationElement sepAddition) {
+		String name = MenuHelper.getName(sepAddition);
+		MMenuElement element = MenuFactoryImpl.eINSTANCE.createMenuSeparator();
+		element.setElementId(name);
+		if (!MenuHelper.isSeparatorVisible(sepAddition)) {
+			element.setVisible(false);
+			element.getTags().add(MenuManagerRenderer.GROUP_MARKER);
+		}
+		return element;
+	}
+
+	private MMenu createMenuAddition(final IConfigurationElement menuAddition, String filter) {
+		// Is this for a menu or a ToolBar ? We can't create
+		// a menu directly under a Toolbar; we have to add an
+		// item of style 'pulldown'
+		if (inToolbar()) {
+			return null;
+		}
+
+		MMenu menu = MenuHelper.createMenuAddition(menuAddition);
+		menu.getTags().add(filter);
+		// addMenuChildren(menu, menuAddition, filter);
+		return menu;
+	}
+
+	private boolean isUndefined(String query) {
+		if (query == null || query.length() == 0) {
+			return true;
+		}
+
+		int index = query.indexOf('=');
+		return index == -1 || query.substring(index + 1).equals("additions"); //$NON-NLS-1$
+	}
+
+	private void processTrimLocation(MTrimContribution contribution) {
+		String query = location.getQuery();
+		if (TRIM_COMMAND2.equals(location.getPath())) {
+			contribution.setParentId(MAIN_TOOLBAR);
+			if (isUndefined(query)) {
+				query = "endof"; //$NON-NLS-1$
+			}
+			contribution.setPositionInParent(query);
+		} else {
+			contribution.setParentId(location.getPath());
+			if (query == null || query.length() == 0) {
+				query = AFTER_ADDITIONS;
+			}
+			contribution.setPositionInParent(query);
+		}
+	}
+
+	private void processTrimChildren(ArrayList<MTrimContribution> trimContributions,
+			ArrayList<MToolBarContribution> toolBarContributions, IConfigurationElement element) {
+		IConfigurationElement[] toolbars = element
+				.getChildren(IWorkbenchRegistryConstants.TAG_TOOLBAR);
+		if (toolbars.length == 0) {
+			return;
+		}
+		MTrimContribution trimContribution = MenuFactoryImpl.eINSTANCE.createTrimContribution();
+		String idContrib = MenuHelper.getId(configElement);
+		if (idContrib != null && idContrib.length() > 0) {
+			trimContribution.setElementId(idContrib);
+		}
+		String query = location.getQuery();
+		boolean hasAdditions = AFTER_ADDITIONS.equals(query);
+		processTrimLocation(trimContribution);
+		trimContribution.getTags().add("scheme:" + location.getScheme()); //$NON-NLS-1$
+		for (IConfigurationElement toolbar : toolbars) {
+			MToolBar item = MenuFactoryImpl.eINSTANCE.createToolBar();
+			item.setElementId(MenuHelper.getId(toolbar));
+			item.getTransientData().put("Name", MenuHelper.getLabel(toolbar)); //$NON-NLS-1$
+			processToolbarChildren(toolBarContributions, toolbar, item.getElementId(),
+					AFTER_ADDITIONS, false);
+			trimContribution.getChildren().add(item);
+		}
+		if (hasAdditions) {
+			trimContributions.add(0, trimContribution);
+		} else {
+			trimContributions.add(trimContribution);
+		}
+	}
+
+	private void processToolbarChildren(ArrayList<MToolBarContribution> contributions,
+			IConfigurationElement toolbar, String parentId, String position, boolean hasAdditions) {
+		MToolBarContribution toolBarContribution = MenuFactoryImpl.eINSTANCE
+				.createToolBarContribution();
+		String idContrib = MenuHelper.getId(toolbar);
+		if (idContrib != null && idContrib.length() > 0) {
+			toolBarContribution.setElementId(idContrib);
+		}
+		toolBarContribution.setParentId(parentId);
+		toolBarContribution.setPositionInParent(position);
+		toolBarContribution.getTags().add("scheme:" + location.getScheme()); //$NON-NLS-1$
+
+		for (final IConfigurationElement child : toolbar.getChildren()) {
+			String itemType = child.getName();
+
+			if (IWorkbenchRegistryConstants.TAG_COMMAND.equals(itemType)) {
+				MToolBarElement element = createToolBarCommandAddition(child);
+				toolBarContribution.getChildren().add(element);
+			} else if (IWorkbenchRegistryConstants.TAG_SEPARATOR.equals(itemType)) {
+				MToolBarElement element = createToolBarSeparatorAddition(child);
+				toolBarContribution.getChildren().add(element);
+			} else if (IWorkbenchRegistryConstants.TAG_CONTROL.equals(itemType)) {
+				MToolBarElement element = createToolControlAddition(child);
+				toolBarContribution.getChildren().add(element);
+			} else if (IWorkbenchRegistryConstants.TAG_DYNAMIC.equals(itemType)) {
+				ContextFunction generator = new ContextFunction() {
+					@Override
+					public Object compute(IEclipseContext context, String contextKey) {
+						ServiceLocator sl = new ServiceLocator();
+						sl.setContext(context);
+						DynamicToolBarContributionItem dynamicItem = new DynamicToolBarContributionItem(
+								MenuHelper.getId(child), sl, child);
+						return dynamicItem;
+					}
+				};
+
+				MToolBarElement element = createToolDynamicAddition(child);
+				RenderedElementUtil.setContributionManager(element, generator);
+				toolBarContribution.getChildren().add(element);
+			}
+		}
+
+		if (hasAdditions) {
+			contributions.add(0, toolBarContribution);
+		} else {
+			contributions.add(toolBarContribution);
+		}
+	}
+
+	private MToolBarElement createToolDynamicAddition(IConfigurationElement element) {
+		String id = MenuHelper.getId(element);
+		final MToolControl object = 
+		MMenuFactory.INSTANCE.createToolControl();
+        object.getTags().add("Rendered");
+		MToolControl control = object;
+		control.setElementId(id);
+		control.setContributionURI(CompatibilityWorkbenchWindowControlContribution.CONTROL_CONTRIBUTION_URI);
+		ControlContributionRegistry.add(id, element);
+		control.setVisibleWhen(MenuHelper.getVisibleWhen(element));
+		createIdentifierTracker(control);
+		return control;
+	}
+
+	private MToolBarElement createToolControlAddition(IConfigurationElement element) {
+		String id = MenuHelper.getId(element);
+		MToolControl control = MenuFactoryImpl.eINSTANCE.createToolControl();
+		control.setElementId(id);
+		control.setContributionURI(CompatibilityWorkbenchWindowControlContribution.CONTROL_CONTRIBUTION_URI);
+		ControlContributionRegistry.add(id, element);
+		control.setVisibleWhen(MenuHelper.getVisibleWhen(element));
+		createIdentifierTracker(control);
+		return control;
+	}
+
+	private MToolBarElement createToolBarSeparatorAddition(final IConfigurationElement sepAddition) {
+		String name = MenuHelper.getName(sepAddition);
+		MToolBarElement element = MenuFactoryImpl.eINSTANCE.createToolBarSeparator();
+		element.setElementId(name);
+		if (!MenuHelper.isSeparatorVisible(sepAddition)) {
+			element.setToBeRendered(false);
+			element.setVisible(false);
+			element.getTags().add(MenuManagerRenderer.GROUP_MARKER);
+		}
+		return element;
+	}
+
+	private MToolBarElement createToolBarCommandAddition(final IConfigurationElement commandAddition) {
+		MHandledToolItem item = MenuFactoryImpl.eINSTANCE.createHandledToolItem();
+		item.setElementId(MenuHelper.getId(commandAddition));
+		String commandId = MenuHelper.getCommandId(commandAddition);
+		MCommand commandById = ContributionsAnalyzer.getCommandById(application, commandId);
+		if (commandById == null) {
+			commandById = CommandsFactoryImpl.eINSTANCE.createCommand();
+			commandById.setElementId(commandId);
+			commandById.setCommandName(commandId);
+			application.getCommands().add(commandById);
+		}
+		item.setCommand(commandById);
+		Map parms = MenuHelper.getParameters(commandAddition);
+		for (Object obj : parms.entrySet()) {
+			Map.Entry e = (Map.Entry) obj;
+			MParameter parm = CommandsFactoryImpl.eINSTANCE.createParameter();
+			parm.setName(e.getKey().toString());
+			parm.setValue(e.getValue().toString());
+			item.getParameters().add(parm);
+		}
+		String iconUrl = MenuHelper.getIconURI(commandAddition,
+				IWorkbenchRegistryConstants.ATT_ICON);
+
+		if (iconUrl == null) {
+			ICommandImageService commandImageService = application.getContext().get(
+					ICommandImageService.class);
+			ImageDescriptor descriptor = commandImageService == null ? null : commandImageService
+					.getImageDescriptor(commandId, ICommandImageService.IMAGE_STYLE_TOOLBAR);
+			if (descriptor == null) {
+				descriptor = commandImageService == null ? null : commandImageService
+						.getImageDescriptor(item.getElementId(),
+								ICommandImageService.IMAGE_STYLE_TOOLBAR);
+				if (descriptor == null) {
+					item.setLabel(MenuHelper.getLabel(commandAddition));
+				} else {
+					item.setIconURI(MenuHelper.getImageUrl(descriptor));
+				}
+			} else {
+				item.setIconURI(MenuHelper.getImageUrl(descriptor));
+			}
+		} else {
+			item.setIconURI(iconUrl);
+		}
+
+		iconUrl = MenuHelper.getIconURI(commandAddition,
+				IWorkbenchRegistryConstants.ATT_DISABLEDICON);
+		if (iconUrl == null) {
+			ICommandImageService commandImageService = application.getContext().get(
+					ICommandImageService.class);
+			if (commandImageService != null) {
+				ImageDescriptor descriptor = commandImageService.getImageDescriptor(commandId,
+						ICommandImageService.TYPE_DISABLED,
+						ICommandImageService.IMAGE_STYLE_TOOLBAR);
+				if (descriptor == null) {
+					descriptor = commandImageService.getImageDescriptor(item.getElementId(),
+							ICommandImageService.TYPE_DISABLED,
+							ICommandImageService.IMAGE_STYLE_TOOLBAR);
+				}
+				if (descriptor != null) {
+					iconUrl = MenuHelper.getImageUrl(descriptor);
+				}
+			}
+		}
+		if (iconUrl != null) {
+			MenuHelper.setDisabledIconURI(item, iconUrl);
+		}
+
+		item.setTooltip(MenuHelper.getTooltip(commandAddition));
+		item.setType(MenuHelper.getStyle(commandAddition));
+		if (MenuHelper.hasPulldownStyle(commandAddition)) {
+			MMenu element = MenuFactoryImpl.eINSTANCE.createMenu();
+			String id = MenuHelper.getId(commandAddition);
+			element.setElementId(id);
+			item.setMenu(element);
+		}
+		item.setVisibleWhen(MenuHelper.getVisibleWhen(commandAddition));
+
+		if (MenuHelper.getMode(commandAddition) == CommandContributionItem.MODE_FORCE_TEXT) {
+			item.getTags().add("FORCE_TEXT"); //$NON-NLS-1$
+			item.setLabel(MenuHelper.getLabel(commandAddition));
+		}
+
+		createIdentifierTracker(item);
+		return item;
+	}
+
+	@Override
+	public String toString() {
+		return "MenuAdditionCacheEntry [id=" + MenuHelper.getId(configElement) //$NON-NLS-1$
+				+ ", namespaceId=" + namespaceIdentifier + ", location=" + location + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/MenuFactoryGenerator.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/MenuFactoryGenerator.java
new file mode 100644
index 0000000..ae88bfc
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/MenuFactoryGenerator.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * Copyright (c) 2012, 2015 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.ui.internal.menus;
+
+import java.util.ArrayList;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.e4.core.contexts.ContextFunction;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.ui.internal.workbench.ContributionsAnalyzer;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.ui.menu.MMenuContribution;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolBarContribution;
+import org.eclipse.e4.ui.model.application.ui.menu.MTrimContribution;
+import org.eclipse.e4.ui.model.application.ui.menu.impl.MenuFactoryImpl;
+import org.eclipse.e4.ui.workbench.renderers.swt.ContributionRecord;
+import org.eclipse.e4.ui.workbench.renderers.swt.ToolBarContributionRecord;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+
+/**
+ * @since 3.102.0
+ *
+ */
+public class MenuFactoryGenerator {
+	private MApplication application;
+	private IConfigurationElement configElement;
+	private MenuLocationURI location;
+
+	public MenuFactoryGenerator(MApplication application, IEclipseContext appContext,
+			IConfigurationElement configElement, String attribute) {
+		this.application = application;
+		// this.appContext = appContext;
+		assert appContext.equals(this.application.getContext());
+		this.configElement = configElement;
+		this.location = new MenuLocationURI(attribute);
+	}
+
+	private boolean inToolbar() {
+		return location.getScheme().startsWith("toolbar"); //$NON-NLS-1$
+	}
+
+	public void mergeIntoModel(ArrayList<MMenuContribution> menuContributions,
+			ArrayList<MToolBarContribution> toolBarContributions,
+			ArrayList<MTrimContribution> trimContributions) {
+		if (location.getPath() == null || location.getPath().length() == 0) {
+			WorkbenchPlugin
+					.log("MenuFactoryGenerator.mergeIntoModel: Invalid menu URI: " + location); //$NON-NLS-1$
+			return;
+		}
+		if (inToolbar()) {
+			if (MenuAdditionCacheEntry.isInWorkbenchTrim(location)) {
+				// processTrimChildren(trimContributions, toolBarContributions,
+				// configElement);
+			} else {
+				String query = location.getQuery();
+				if (query == null || query.length() == 0) {
+					query = "after=additions"; //$NON-NLS-1$
+				}
+				processToolbarChildren(toolBarContributions, configElement, location.getPath(),
+						query);
+			}
+			return;
+		}
+		MMenuContribution menuContribution = MenuFactoryImpl.eINSTANCE.createMenuContribution();
+		String idContrib = MenuHelper.getId(configElement);
+		if (idContrib != null && idContrib.length() > 0) {
+			menuContribution.setElementId(idContrib);
+		}
+		if ("org.eclipse.ui.popup.any".equals(location.getPath())) { //$NON-NLS-1$
+			menuContribution.setParentId("popup"); //$NON-NLS-1$
+		} else {
+			menuContribution.setParentId(location.getPath());
+		}
+		String query = location.getQuery();
+		if (query == null || query.length() == 0) {
+			query = "after=additions"; //$NON-NLS-1$
+		}
+		menuContribution.setPositionInParent(query);
+		menuContribution.getTags().add("scheme:" + location.getScheme()); //$NON-NLS-1$
+		String filter = ContributionsAnalyzer.MC_MENU;
+		if ("popup".equals(location.getScheme())) { //$NON-NLS-1$
+			filter = ContributionsAnalyzer.MC_POPUP;
+		}
+		menuContribution.getTags().add(filter);
+		menuContribution.setVisibleWhen(MenuHelper.getVisibleWhen(configElement));
+		ContextFunction generator = new ContributionFactoryGenerator(configElement, 0);
+		menuContribution.getTransientData().put(ContributionRecord.FACTORY, generator);
+		menuContributions.add(menuContribution);
+	}
+
+	private void processToolbarChildren(ArrayList<MToolBarContribution> contributions,
+			IConfigurationElement toolbar, String parentId, String position) {
+		MToolBarContribution toolBarContribution = MenuFactoryImpl.eINSTANCE
+				.createToolBarContribution();
+		String idContrib = MenuHelper.getId(toolbar);
+		if (idContrib != null && idContrib.length() > 0) {
+			toolBarContribution.setElementId(idContrib);
+		}
+		toolBarContribution.setParentId(parentId);
+		toolBarContribution.setPositionInParent(position);
+		toolBarContribution.getTags().add("scheme:" + location.getScheme()); //$NON-NLS-1$
+
+		ContextFunction generator = new ContributionFactoryGenerator(configElement, 1);
+		toolBarContribution.getTransientData().put(ToolBarContributionRecord.FACTORY, generator);
+
+		contributions.add(toolBarContribution);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/MenuHelper.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/MenuHelper.java
new file mode 100644
index 0000000..a034f92
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/MenuHelper.java
@@ -0,0 +1,1213 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 180308, 472654
+ *******************************************************************************/
+package org.eclipse.ui.internal.menus;
+
+import java.lang.reflect.Field;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.ExpressionConverter;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IAdapterManager;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.InvalidRegistryObjectException;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.e4.core.commands.ECommandService;
+import org.eclipse.e4.core.commands.EHandlerService;
+import org.eclipse.e4.core.contexts.ContextFunction;
+import org.eclipse.e4.core.contexts.IContextFunction;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.di.annotations.CanExecute;
+import org.eclipse.e4.core.di.annotations.Execute;
+import org.eclipse.e4.ui.internal.workbench.ContributionsAnalyzer;
+import org.eclipse.e4.ui.internal.workbench.RenderedElementUtil;
+import org.eclipse.e4.ui.internal.workbench.swt.Policy;
+import org.eclipse.e4.ui.internal.workbench.swt.WorkbenchSWTActivator;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.commands.MCommand;
+import org.eclipse.e4.ui.model.application.commands.impl.CommandsFactoryImpl;
+import org.eclipse.e4.ui.model.application.ui.MCoreExpression;
+import org.eclipse.e4.ui.model.application.ui.MExpression;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.model.application.ui.impl.UiFactoryImpl;
+import org.eclipse.e4.ui.model.application.ui.menu.ItemType;
+import org.eclipse.e4.ui.model.application.ui.menu.MDirectMenuItem;
+import org.eclipse.e4.ui.model.application.ui.menu.MDirectToolItem;
+import org.eclipse.e4.ui.model.application.ui.menu.MHandledItem;
+import org.eclipse.e4.ui.model.application.ui.menu.MHandledMenuItem;
+import org.eclipse.e4.ui.model.application.ui.menu.MHandledToolItem;
+import org.eclipse.e4.ui.model.application.ui.menu.MMenu;
+import org.eclipse.e4.ui.model.application.ui.menu.MMenuElement;
+import org.eclipse.e4.ui.model.application.ui.menu.MMenuItem;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolBarElement;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolItem;
+import org.eclipse.e4.ui.model.application.ui.menu.impl.MenuFactoryImpl;
+import org.eclipse.e4.ui.workbench.IPresentationEngine;
+import org.eclipse.e4.ui.workbench.renderers.swt.DirectContributionItem;
+import org.eclipse.jface.action.ActionContributionItem;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IMenuCreator;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.ui.IActionDelegate;
+import org.eclipse.ui.ISelectionService;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.IWorkbenchWindowPulldownDelegate;
+import org.eclipse.ui.IWorkbenchWindowPulldownDelegate2;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.commands.ICommandImageService;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.internal.ActionDescriptor;
+import org.eclipse.ui.internal.OpenPreferencesAction;
+import org.eclipse.ui.internal.PluginAction;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.WorkbenchWindow;
+import org.eclipse.ui.internal.e4.compatibility.CompatibilityPart;
+import org.eclipse.ui.internal.handlers.ActionDelegateHandlerProxy;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.util.Util;
+import org.eclipse.ui.menus.CommandContributionItem;
+import org.eclipse.ui.menus.CommandContributionItemParameter;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+
+public class MenuHelper {
+
+	public static void trace(String msg, Throwable error) {
+		WorkbenchSWTActivator.trace(Policy.MENUS, msg, error);
+	}
+
+	private static final Pattern SCHEME_PATTERN = Pattern.compile("\\p{Alpha}[\\p{Alnum}+.-]*:.*"); //$NON-NLS-1$
+	public static final String MAIN_MENU_ID = ActionSet.MAIN_MENU;
+	private static Field urlField;
+
+	/**
+	 * The private 'location' field that is defined in the FileImageDescriptor.
+	 *
+	 * @see #getLocation(ImageDescriptor)
+	 */
+	private static Field locationField;
+
+	/**
+	 * The private 'name' field that is defined in the FileImageDescriptor.
+	 *
+	 * @see #getName(ImageDescriptor)
+	 */
+	private static Field nameField;
+
+	public static String getActionSetCommandId(IConfigurationElement element) {
+		String id = MenuHelper.getDefinitionId(element);
+		if (id != null) {
+			return id;
+		}
+		id = MenuHelper.getId(element);
+		String actionSetId = null;
+		Object obj = element.getParent();
+		while (obj instanceof IConfigurationElement && actionSetId == null) {
+			IConfigurationElement parent = (IConfigurationElement) obj;
+			String parentName = parent.getName();
+			if (parentName.equals(IWorkbenchRegistryConstants.TAG_ACTION_SET)
+					|| parentName.equals(IWorkbenchRegistryConstants.TAG_VIEW_CONTRIBUTION)
+					|| parentName.equals(IWorkbenchRegistryConstants.TAG_EDITOR_CONTRIBUTION)) {
+				actionSetId = MenuHelper.getId(parent);
+			}
+			obj = parent.getParent();
+		}
+		return IWorkbenchRegistryConstants.AUTOGENERATED_PREFIX + actionSetId + '/' + id;
+	}
+
+	public static String getImageUrl(ImageDescriptor imageDescriptor) {
+		return getIconURI(imageDescriptor, null);
+	}
+
+	private static String getUrl(Class<? extends ImageDescriptor> idc, ImageDescriptor imageDescriptor) {
+		try {
+			if (urlField == null) {
+				urlField = idc.getDeclaredField("url"); //$NON-NLS-1$
+				urlField.setAccessible(true);
+			}
+			Object value = urlField.get(imageDescriptor);
+			if (value != null) {
+				return value.toString();
+			}
+		} catch (SecurityException | NoSuchFieldException | IllegalArgumentException | IllegalAccessException e) {
+			WorkbenchPlugin.log(e);
+		}
+		return null;
+	}
+
+	private static Class<?> getLocation(ImageDescriptor imageDescriptor) {
+		try {
+			if (locationField == null) {
+				locationField = imageDescriptor.getClass().getDeclaredField("location"); //$NON-NLS-1$
+				locationField.setAccessible(true);
+			}
+			return (Class<?>) locationField.get(imageDescriptor);
+		} catch (SecurityException | NoSuchFieldException | IllegalAccessException e) {
+			WorkbenchPlugin.log(e);
+		}
+		return null;
+	}
+
+	private static String getName(ImageDescriptor imageDescriptor) {
+		try {
+			if (nameField == null) {
+				nameField = imageDescriptor.getClass().getDeclaredField("name"); //$NON-NLS-1$
+				nameField.setAccessible(true);
+			}
+			return (String) nameField.get(imageDescriptor);
+		} catch (SecurityException | NoSuchFieldException | IllegalAccessException e) {
+			WorkbenchPlugin.log(e);
+		}
+		return null;
+	}
+
+	/**
+	 * @param element
+	 *            the configuration element
+	 * @return <code>true</code> if the checkEnabled is <code>true</code>.
+	 */
+	static boolean getVisibleEnabled(IConfigurationElement element) {
+		IConfigurationElement[] children = element
+				.getChildren(IWorkbenchRegistryConstants.TAG_VISIBLE_WHEN);
+		String checkEnabled = null;
+
+		if (children.length > 0) {
+			checkEnabled = children[0].getAttribute(IWorkbenchRegistryConstants.ATT_CHECK_ENABLED);
+		}
+
+		return checkEnabled != null && checkEnabled.equalsIgnoreCase("true"); //$NON-NLS-1$
+	}
+
+	static MExpression getVisibleWhen(final IConfigurationElement commandAddition) {
+		try {
+			IConfigurationElement[] visibleConfig = commandAddition
+					.getChildren(IWorkbenchRegistryConstants.TAG_VISIBLE_WHEN);
+			if (visibleConfig.length > 0 && visibleConfig.length < 2) {
+				IConfigurationElement[] visibleChild = visibleConfig[0].getChildren();
+				if (visibleChild.length == 0) {
+					String checkEnabled = visibleConfig[0]
+							.getAttribute(IWorkbenchRegistryConstants.ATT_CHECK_ENABLED);
+					if (Boolean.parseBoolean(checkEnabled)) {
+						final String commandId = getCommandId(commandAddition);
+						if (commandId == null) {
+							return null;
+						}
+
+						Expression visWhen = new Expression() {
+							@Override
+							public EvaluationResult evaluate(IEvaluationContext context) {
+								EHandlerService service = getFromContext(context,
+										EHandlerService.class);
+								ICommandService commandService = getFromContext(context,
+										ICommandService.class);
+								if (service == null || commandService == null) {
+									WorkbenchPlugin
+											.log("Could not retrieve EHandlerService or ICommandService from context evaluation context for" //$NON-NLS-1$
+													+ commandId);
+									return EvaluationResult.FALSE;
+								}
+								Command c = commandService.getCommand(commandId);
+								ParameterizedCommand generateCommand = ParameterizedCommand
+										.generateCommand(c, Collections.EMPTY_MAP);
+								return EvaluationResult
+										.valueOf(service.canExecute(generateCommand));
+							}
+						};
+						MCoreExpression exp = UiFactoryImpl.eINSTANCE.createCoreExpression();
+						exp.setCoreExpressionId("programmatic.value"); //$NON-NLS-1$
+						exp.setCoreExpression(visWhen);
+						return exp;
+					}
+				} else if (visibleChild.length > 0) {
+					Expression visWhen = ExpressionConverter.getDefault().perform(visibleChild[0]);
+					MCoreExpression exp = UiFactoryImpl.eINSTANCE.createCoreExpression();
+					exp.setCoreExpressionId("programmatic.value"); //$NON-NLS-1$
+					exp.setCoreExpression(visWhen);
+					return exp;
+					// visWhenMap.put(configElement, visWhen);
+				}
+			}
+		} catch (InvalidRegistryObjectException | CoreException e) {
+			// visWhenMap.put(configElement, null);
+			WorkbenchPlugin.log(e);
+		}
+		return null;
+	}
+
+	/**
+	 * Do a type-safe extraction of an object from the evalation context
+	 *
+	 * @param context
+	 *            the evaluation context
+	 * @param expectedType
+	 *            the expected type
+	 * @return an object of the expected type or <code>null</code>
+	 * @throws NullPointerException
+	 *             if either argument is <code>null</code>
+	 */
+	protected static <T> T getFromContext(IEvaluationContext context, Class<T> expectedType) {
+		if (context == null || expectedType == null) {
+			throw new NullPointerException();
+		}
+		final Object rawValue = context.getVariable(expectedType.getName());
+		return (expectedType.isInstance(rawValue)) ? expectedType.cast(rawValue) : null;
+	}
+
+	/**
+	 * Returns id attribute of the element or unique string computed from the
+	 * element registry handle
+	 *
+	 * @param element
+	 *            non null
+	 * @return non null id
+	 */
+	public static String getId(IConfigurationElement element) {
+		String id = element.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+
+		// For sub-menu management -all- items must be id'd so enforce this
+		// here (we could optimize by checking the 'name' of the config
+		// element == "menu"
+		if (id == null || id.length() == 0) {
+			id = getCommandId(element);
+		}
+		if (id == null || id.length() == 0) {
+			id = getConfigurationHandleId(element);
+		}
+		return id;
+	}
+
+	/**
+	 * @return unique string computed from the element registry handle
+	 */
+	private static String getConfigurationHandleId(IConfigurationElement element) {
+		// Note: the line below depends on internal details of
+		// ConfigurationElementHandle implementation, see bug 515405 and 515587.
+
+		// ConfigurationElementHandle.hashCode() is implemented in the way that
+		// it returns same number for different element instances with the same
+		// registry handle id (see org.eclipse.core.internal.registry.Handle).
+
+		// Once the bug 515587 provides new API, we should use that
+		return element.toString();
+	}
+
+	static String getName(IConfigurationElement element) {
+		return element.getAttribute(IWorkbenchRegistryConstants.ATT_NAME);
+	}
+
+	static int getMode(IConfigurationElement element) {
+		if ("FORCE_TEXT".equals(element.getAttribute(IWorkbenchRegistryConstants.ATT_MODE))) { //$NON-NLS-1$
+			return CommandContributionItem.MODE_FORCE_TEXT;
+		}
+		return 0;
+	}
+
+	static String getLabel(IConfigurationElement element) {
+		return element.getAttribute(IWorkbenchRegistryConstants.ATT_LABEL);
+	}
+
+	static String getPath(IConfigurationElement element) {
+		return element.getAttribute(IWorkbenchRegistryConstants.ATT_PATH);
+	}
+
+	static String getMenuBarPath(IConfigurationElement element) {
+		return element.getAttribute(IWorkbenchRegistryConstants.ATT_MENUBAR_PATH);
+	}
+
+	static String getToolBarPath(IConfigurationElement element) {
+		return element.getAttribute(IWorkbenchRegistryConstants.ATT_TOOLBAR_PATH);
+	}
+
+	static String getMnemonic(IConfigurationElement element) {
+		return element.getAttribute(IWorkbenchRegistryConstants.ATT_MNEMONIC);
+	}
+
+	static String getTooltip(IConfigurationElement element) {
+		return element.getAttribute(IWorkbenchRegistryConstants.ATT_TOOLTIP);
+	}
+
+	public static String getIconURI(IConfigurationElement element, String attr) {
+		String iconPath = element.getAttribute(attr);
+		if (iconPath == null) {
+			return null;
+		}
+
+		// If iconPath doesn't specify a scheme, then try to transform to a URL
+		// RFC 3986: scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+		// This allows using data:, http:, or other custom URL schemes
+		if (!SCHEME_PATTERN.matcher(iconPath).matches()) {
+			// First attempt to resolve in ISharedImages (e.g. "IMG_OBJ_FOLDER")
+			// as per bug 391232 & AbstractUIPlugin.imageDescriptorFromPlugin().
+			ImageDescriptor d = WorkbenchPlugin.getDefault().getSharedImages()
+					.getImageDescriptor(iconPath);
+			if (d != null) {
+				return getImageUrl(d);
+			}
+			String extendingPluginId = element.getDeclaringExtension().getContributor().getName();
+			iconPath = "platform:/plugin/" + extendingPluginId + "/" + iconPath; //$NON-NLS-1$//$NON-NLS-2$
+		}
+		URL url = null;
+		try {
+			url = FileLocator.find(new URL(iconPath));
+		} catch (MalformedURLException e) {
+			/* IGNORE */
+		}
+		return url == null ? iconPath : rewriteDurableURL(url.toString());
+	}
+
+	static String getHelpContextId(IConfigurationElement element) {
+		return element.getAttribute(IWorkbenchRegistryConstants.ATT_HELP_CONTEXT_ID);
+	}
+
+	public static boolean isSeparatorVisible(IConfigurationElement element) {
+		String val = element.getAttribute(IWorkbenchRegistryConstants.ATT_VISIBLE);
+		return Boolean.valueOf(val).booleanValue();
+	}
+
+	public static String getClassSpec(IConfigurationElement element) {
+		return element.getAttribute(IWorkbenchRegistryConstants.ATT_CLASS);
+	}
+
+	public static String getCommandId(IConfigurationElement element) {
+		return element.getAttribute(IWorkbenchRegistryConstants.ATT_COMMAND_ID);
+	}
+
+	public static ItemType getStyle(IConfigurationElement element) {
+		String style = element.getAttribute(IWorkbenchRegistryConstants.ATT_STYLE);
+		if (style == null || style.length() == 0) {
+			return ItemType.PUSH;
+		}
+		if (IWorkbenchRegistryConstants.STYLE_TOGGLE.equals(style)) {
+			return ItemType.CHECK;
+		}
+		if (IWorkbenchRegistryConstants.STYLE_RADIO.equals(style)) {
+			return ItemType.RADIO;
+		}
+		if (IWorkbenchRegistryConstants.STYLE_PULLDOWN.equals(style)) {
+		    trace("Failed to get style for " + IWorkbenchRegistryConstants.STYLE_PULLDOWN, null); //$NON-NLS-1$
+		    // return CommandContributionItem.STYLE_PULLDOWN;
+		}
+		return ItemType.PUSH;
+	}
+
+	public static boolean hasPulldownStyle(IConfigurationElement element) {
+		String style = element.getAttribute(IWorkbenchRegistryConstants.ATT_STYLE);
+		return IWorkbenchRegistryConstants.STYLE_PULLDOWN.equals(style);
+	}
+
+	public static boolean getRetarget(IConfigurationElement element) {
+		String r = element.getAttribute(IWorkbenchRegistryConstants.ATT_RETARGET);
+		return Boolean.valueOf(r);
+	}
+
+	public static String getDefinitionId(IConfigurationElement element) {
+		return element.getAttribute(IWorkbenchRegistryConstants.ATT_DEFINITION_ID);
+	}
+
+	public static Map<String, String> getParameters(IConfigurationElement element) {
+		HashMap<String, String> map = new HashMap<>();
+		IConfigurationElement[] parameters = element
+				.getChildren(IWorkbenchRegistryConstants.TAG_PARAMETER);
+		for (IConfigurationElement parameter : parameters) {
+			String name = parameter.getAttribute(IWorkbenchRegistryConstants.ATT_NAME);
+			String value = parameter.getAttribute(IWorkbenchRegistryConstants.ATT_VALUE);
+			if (name != null && value != null) {
+				map.put(name, value);
+			}
+		}
+		return map;
+	}
+
+	public static MMenu createMenuAddition(IConfigurationElement menuAddition) {
+		MMenu element = MenuFactoryImpl.eINSTANCE.createMenu();
+		String id = MenuHelper.getId(menuAddition);
+		element.setElementId(id);
+		String text = MenuHelper.getLabel(menuAddition);
+		String mnemonic = MenuHelper.getMnemonic(menuAddition);
+		if (text != null && mnemonic != null) {
+			int idx = text.indexOf(mnemonic);
+			if (idx != -1) {
+				text = text.substring(0, idx) + '&' + text.substring(idx);
+			}
+		}
+		element.setVisibleWhen(getVisibleWhen(menuAddition));
+		element.setIconURI(MenuHelper
+				.getIconURI(menuAddition, IWorkbenchRegistryConstants.ATT_ICON));
+		element.setLabel(Util.safeString(text));
+
+		return element;
+	}
+
+	public static MMenuElement createLegacyMenuActionAdditions(MApplication app,
+			final IConfigurationElement element) {
+		final String id = MenuHelper.getId(element);
+		String text = MenuHelper.getLabel(element);
+		String mnemonic = MenuHelper.getMnemonic(element);
+		if (text != null && mnemonic != null) {
+			int idx = text.indexOf(mnemonic);
+			if (idx != -1) {
+				text = text.substring(0, idx) + '&' + text.substring(idx);
+			}
+		}
+		String iconUri = MenuHelper.getIconURI(element, IWorkbenchRegistryConstants.ATT_ICON);
+		final String cmdId = MenuHelper.getActionSetCommandId(element);
+
+		MCommand cmd = ContributionsAnalyzer.getCommandById(app, cmdId);
+		if (cmd == null) {
+			ECommandService commandService = app.getContext().get(ECommandService.class);
+			Command command = commandService.getCommand(cmdId);
+			if (command == null) {
+				ICommandService ics = app.getContext().get(ICommandService.class);
+				command = commandService.defineCommand(cmdId, text, null, ics.getCategory(null),
+						null);
+			}
+			cmd = CommandsFactoryImpl.eINSTANCE.createCommand();
+			cmd.setCommandName(text);
+			cmd.setElementId(cmdId);
+			app.getCommands().add(cmd);
+		}
+
+		String style = element.getAttribute(IWorkbenchRegistryConstants.ATT_STYLE);
+		String pulldown = element.getAttribute("pulldown"); //$NON-NLS-1$
+		if (IWorkbenchRegistryConstants.STYLE_PULLDOWN.equals(style)
+				|| (pulldown != null && pulldown.equals("true"))) { //$NON-NLS-1$
+			MMenuItem item = RenderedElementUtil.createRenderedMenuItem();
+			item.setLabel(text);
+			if (iconUri != null) {
+				item.setIconURI(iconUri);
+			}
+			IContextFunction generator = new ContextFunction() {
+				@Override
+				public Object compute(IEclipseContext context, String contextKey) {
+					IWorkbenchWindow window = context.get(IWorkbenchWindow.class);
+					if (window == null) {
+						return null;
+					}
+					ActionDescriptor desc = new ActionDescriptor(element,
+							ActionDescriptor.T_WORKBENCH_PULLDOWN, window);
+					final PluginAction action = desc.getAction();
+					return new ActionContributionItem(action) {
+						@Override
+						public void dispose() {
+							super.dispose();
+							action.disposeDelegate();
+						}
+					};
+				}
+			};
+			RenderedElementUtil.setContributionManager(item, generator);
+			return item;
+		}
+
+		ItemType type = ItemType.PUSH;
+		if (IWorkbenchRegistryConstants.STYLE_TOGGLE.equals(style)) {
+			type = ItemType.CHECK;
+		} else if (IWorkbenchRegistryConstants.STYLE_RADIO.equals(style)) {
+			type = ItemType.RADIO;
+		}
+		MHandledMenuItem item = MenuFactoryImpl.eINSTANCE.createHandledMenuItem();
+		item.setElementId(id);
+		item.setLabel(text);
+		item.setType(type);
+		item.setCommand(cmd);
+		if (iconUri != null) {
+			item.setIconURI(iconUri);
+		}
+		return item;
+	}
+
+	public static String getDescription(IConfigurationElement configElement) {
+		return configElement.getAttribute(IWorkbenchRegistryConstants.TAG_DESCRIPTION);
+	}
+
+	public static MToolBarElement createLegacyToolBarActionAdditions(MApplication app,
+			final IConfigurationElement element) {
+		String cmdId = MenuHelper.getActionSetCommandId(element);
+		final String id = MenuHelper.getId(element);
+		String text = MenuHelper.getLabel(element);
+		String mnemonic = MenuHelper.getMnemonic(element);
+		if (text != null && mnemonic != null) {
+			int idx = text.indexOf(mnemonic);
+			if (idx != -1) {
+				text = text.substring(0, idx) + '&' + text.substring(idx);
+			}
+		}
+		String iconUri = MenuHelper.getIconURI(element, IWorkbenchRegistryConstants.ATT_ICON);
+		String disabledIconUri = MenuHelper.getIconURI(element,
+				IWorkbenchRegistryConstants.ATT_DISABLEDICON);
+		MCommand cmd = ContributionsAnalyzer.getCommandById(app, cmdId);
+		if (cmd == null) {
+			ECommandService commandService = app.getContext().get(ECommandService.class);
+			Command command = commandService.getCommand(cmdId);
+			if (command == null) {
+				ICommandService ics = app.getContext().get(
+						ICommandService.class);
+				command = commandService.defineCommand(cmdId, text, null, ics.getCategory(null),
+						null);
+			}
+			cmd = CommandsFactoryImpl.eINSTANCE.createCommand();
+			cmd.setCommandName(text);
+			cmd.setElementId(cmdId);
+			app.getCommands().add(cmd);
+		}
+		final MHandledToolItem item = MenuFactoryImpl.eINSTANCE.createHandledToolItem();
+
+		String style = element.getAttribute(IWorkbenchRegistryConstants.ATT_STYLE);
+		String pulldown = element.getAttribute("pulldown"); //$NON-NLS-1$
+		if (IWorkbenchRegistryConstants.STYLE_TOGGLE.equals(style)) {
+			item.setType(ItemType.CHECK);
+			IContextFunction generator = createToggleFunction(element);
+			if (generator != null) {
+				item.getTransientData().put(ItemType.CHECK.toString(), generator);
+			}
+		} else if (IWorkbenchRegistryConstants.STYLE_RADIO.equals(style)) {
+			item.setType(ItemType.RADIO);
+		} else {
+			item.setType(ItemType.PUSH);
+		}
+
+		if (IWorkbenchRegistryConstants.STYLE_PULLDOWN.equals(style)
+				|| (pulldown != null && pulldown.equals("true"))) { //$NON-NLS-1$
+			MMenu menu = RenderedElementUtil.createRenderedMenu();
+			ECommandService cs = app.getContext().get(ECommandService.class);
+			final ParameterizedCommand parmCmd = cs.createCommand(cmdId, null);
+			IContextFunction generator = new ContextFunction() {
+				@Override
+				public Object compute(IEclipseContext context, String contextKey) {
+					return new IMenuCreator() {
+						private ActionDelegateHandlerProxy handlerProxy;
+
+						private ActionDelegateHandlerProxy getProxy() {
+							if (handlerProxy == null) {
+								handlerProxy = new ActionDelegateHandlerProxy(element,
+										IWorkbenchRegistryConstants.ATT_CLASS, id, parmCmd,
+										PlatformUI
+										.getWorkbench().getActiveWorkbenchWindow(), null, null,
+ null);
+							}
+							return handlerProxy;
+						}
+
+						private IWorkbenchWindowPulldownDelegate getDelegate() {
+							getProxy();
+							if (handlerProxy == null) {
+								return null;
+							}
+							if (handlerProxy.getDelegate() == null) {
+								handlerProxy.loadDelegate();
+
+								ISelectionService service = PlatformUI.getWorkbench()
+										.getActiveWorkbenchWindow().getSelectionService();
+								IActionDelegate delegate = handlerProxy.getDelegate();
+								delegate.selectionChanged(handlerProxy.getAction(),
+										service.getSelection());
+							}
+							return (IWorkbenchWindowPulldownDelegate) handlerProxy.getDelegate();
+						}
+
+						@Override
+						public Menu getMenu(Menu parent) {
+							IWorkbenchWindowPulldownDelegate2 delegate = (IWorkbenchWindowPulldownDelegate2) getDelegate();
+							if (delegate == null) {
+								return null;
+							}
+							return delegate.getMenu(parent);
+						}
+
+						@Override
+						public Menu getMenu(Control parent) {
+							return getDelegate() == null ? null : getDelegate().getMenu(parent);
+						}
+
+						@Override
+						public void dispose() {
+							if (handlerProxy != null) {
+								handlerProxy.dispose();
+								handlerProxy = null;
+							}
+						}
+					};
+				}
+			};
+			RenderedElementUtil.setContributionManager(menu, generator);
+			item.setMenu(menu);
+		}
+
+		item.setElementId(id);
+		item.setCommand(cmd);
+		if (iconUri == null) {
+			item.setLabel(text);
+		} else {
+			item.setIconURI(iconUri);
+		}
+		if (disabledIconUri != null) {
+			setDisabledIconURI(item, disabledIconUri);
+		}
+		String tooltip = getTooltip(element);
+		// if no tooltip defined, use the textual label as the tooltip
+		item.setTooltip(tooltip == null ? text : tooltip);
+		return item;
+	}
+
+	private static int getType(String name) {
+		if (name.equals(IWorkbenchRegistryConstants.TAG_ACTION_SET)) {
+			return ActionDescriptor.T_WORKBENCH;
+		} else if (name.equals(IWorkbenchRegistryConstants.TAG_VIEW_CONTRIBUTION)) {
+			return ActionDescriptor.T_VIEW;
+		} else if (name.equals(IWorkbenchRegistryConstants.TAG_EDITOR_CONTRIBUTION)) {
+			return ActionDescriptor.T_EDITOR;
+		}
+		return -1;
+	}
+
+	private static IContextFunction createToggleFunction(final IConfigurationElement element) {
+		Object ice = element.getParent();
+		if (!(ice instanceof IConfigurationElement)) {
+			return null;
+		}
+
+		// identify the type of contribution that this is
+		IConfigurationElement parent = (IConfigurationElement) ice;
+		final int type = getType(parent.getName());
+		if (type == -1) {
+			// unknown, don't create a toggling function
+			return null;
+		}
+
+		IContextFunction generator = new ContextFunction() {
+			private ActionDescriptor getDescriptor(IEclipseContext context) {
+				switch (type) {
+				case ActionDescriptor.T_WORKBENCH:
+					IWorkbenchWindow window = context.get(IWorkbenchWindow.class);
+					return window == null ? null : new ActionDescriptor(element, type, window);
+				case ActionDescriptor.T_EDITOR:
+					return new ActionDescriptor(element, type, null);
+				case ActionDescriptor.T_VIEW:
+					MPart part = context.get(MPart.class);
+					if (part != null) {
+						Object object = part.getObject();
+						if (object instanceof CompatibilityPart) {
+							return new ActionDescriptor(element, type,
+									((CompatibilityPart) object).getPart());
+						}
+					}
+					return null;
+				default:
+					return null;
+				}
+			}
+
+			@Override
+			public Object compute(IEclipseContext context, String contextKey) {
+				final MHandledItem model = context.get(MHandledItem.class);
+				if (model == null) {
+					return null;
+				}
+				ActionDescriptor desc = getDescriptor(context);
+				final IAction action = desc.getAction();
+				final IPropertyChangeListener propListener = event -> {
+					if (IAction.CHECKED.equals(event.getProperty())) {
+						boolean checked = false;
+						if (event.getNewValue() instanceof Boolean) {
+							checked = ((Boolean) event.getNewValue()).booleanValue();
+						}
+						model.setSelected(checked);
+					}
+				};
+				action.addPropertyChangeListener(propListener);
+				Runnable obj = new Runnable() {
+					@Override
+					@Execute
+					public void run() {
+						action.removePropertyChangeListener(propListener);
+					}
+				};
+				model.setSelected(action.isChecked());
+				return obj;
+			}
+		};
+		return generator;
+	}
+
+	public static MMenu createMenu(MenuManager manager) {
+		MMenu subMenu = MenuFactoryImpl.eINSTANCE.createMenu();
+		subMenu.setLabel(manager.getMenuText());
+		subMenu.setElementId(manager.getId());
+		return subMenu;
+	}
+
+	public static MMenuItem createItem(MApplication application, CommandContributionItem cci) {
+		MCommand command = getMCommand(application, cci);
+		if (command != null) {
+			CommandContributionItemParameter data = cci.getData();
+			MHandledMenuItem menuItem = MenuFactoryImpl.eINSTANCE.createHandledMenuItem();
+			menuItem.setCommand(command);
+			menuItem.setContributorURI(command.getContributorURI());
+			if (data.label != null) {
+				menuItem.setLabel(data.label);
+			} else {
+				menuItem.setLabel(command.getCommandName());
+			}
+			if (data.mnemonic != null) {
+				menuItem.setMnemonics(data.mnemonic);
+			}
+			if (data.icon != null) {
+				menuItem.setIconURI(getIconURI(data.icon, application.getContext()));
+			} else {
+				menuItem.setIconURI(getIconURI(command.getElementId(), application.getContext(),
+						ICommandImageService.TYPE_DEFAULT));
+			}
+			String itemId = cci.getId();
+			menuItem.setElementId(itemId == null ? command.getElementId() : itemId);
+			return menuItem;
+		}
+		return null;
+	}
+
+	public static MHandledToolItem createToolItem(MApplication application, CommandContributionItem cci) {
+		MCommand command = getMCommand(application, cci);
+		if (command != null) {
+			CommandContributionItemParameter data = cci.getData();
+			MHandledToolItem toolItem = MenuFactoryImpl.eINSTANCE.createHandledToolItem();
+			toolItem.setCommand(command);
+			toolItem.setContributorURI(command.getContributorURI());
+			toolItem.setVisible(cci.isVisible());
+
+			String iconURI = null;
+			String disabledIconURI = null;
+
+			toolItem.setType(ItemType.PUSH);
+			if (data.style == CommandContributionItem.STYLE_CHECK)
+				toolItem.setType(ItemType.CHECK);
+			else if (data.style == CommandContributionItem.STYLE_RADIO)
+				toolItem.setType(ItemType.RADIO);
+
+			if (data.icon != null) {
+				iconURI = getIconURI(data.icon, application.getContext());
+			}
+			if (iconURI == null) {
+				iconURI = getIconURI(command.getElementId(), application.getContext(),
+						ICommandImageService.TYPE_DEFAULT);
+			}
+			if (iconURI == null) {
+				toolItem.setLabel(command.getCommandName());
+			} else {
+				toolItem.setIconURI(iconURI);
+			}
+
+			if (data.disabledIcon != null) {
+				disabledIconURI = getIconURI(data.disabledIcon, application.getContext());
+			}
+
+			if (disabledIconURI == null) {
+				disabledIconURI = getIconURI(command.getElementId(), application.getContext(),
+						ICommandImageService.TYPE_DISABLED);
+			}
+
+			if (disabledIconURI != null) {
+				setDisabledIconURI(toolItem, disabledIconURI);
+			}
+
+			if (data.tooltip != null) {
+				toolItem.setTooltip(data.tooltip);
+			} else if (data.label != null) {
+				toolItem.setTooltip(data.label);
+			} else {
+				toolItem.setTooltip(command.getDescription());
+			}
+
+			String itemId = cci.getId();
+			toolItem.setElementId(itemId == null ? command.getElementId() : itemId);
+			return toolItem;
+		}
+		return null;
+	}
+
+	public static MCommand getMCommand(MApplication application, CommandContributionItem contribution) {
+		ParameterizedCommand command = contribution.getCommand();
+		if (command != null) {
+			for (MCommand mcommand : application.getCommands()) {
+				if (mcommand.getElementId().equals(command.getId())) {
+					return mcommand;
+				}
+			}
+		}
+		return null;
+	}
+
+	public static MToolItem createToolItem(MApplication application, ActionContributionItem item) {
+		final IAction action = item.getAction();
+		String id = action.getActionDefinitionId();
+		if (id != null) {
+			for (MCommand command : application.getCommands()) {
+				if (id.equals(command.getElementId())) {
+					MHandledToolItem toolItem = MenuFactoryImpl.eINSTANCE.createHandledToolItem();
+					toolItem.setCommand(command);
+					toolItem.setContributorURI(command.getContributorURI());
+					toolItem.setVisible(item.isVisible());
+
+					String iconURI = getIconURI(action.getImageDescriptor(),
+							application.getContext());
+					if (iconURI == null) {
+						iconURI = getIconURI(id, application.getContext(),
+								ICommandImageService.TYPE_DEFAULT);
+						if (iconURI == null) {
+							toolItem.setLabel(command.getCommandName());
+						} else {
+							toolItem.setIconURI(iconURI);
+						}
+					} else {
+						toolItem.setIconURI(iconURI);
+					}
+					if (action.getToolTipText() != null) {
+						toolItem.setTooltip(action.getToolTipText());
+					}
+
+					String disabledIconURI = getIconURI(action.getDisabledImageDescriptor(),
+							application.getContext());
+					if (disabledIconURI == null)
+						disabledIconURI = getIconURI(id, application.getContext(),
+								ICommandImageService.TYPE_DEFAULT);
+					if (disabledIconURI != null)
+						setDisabledIconURI(toolItem, disabledIconURI);
+
+					switch (action.getStyle()) {
+					case IAction.AS_CHECK_BOX:
+						toolItem.setType(ItemType.CHECK);
+						toolItem.setSelected(action.isChecked());
+						break;
+					case IAction.AS_RADIO_BUTTON:
+						toolItem.setType(ItemType.RADIO);
+						toolItem.setSelected(action.isChecked());
+						break;
+					default:
+						toolItem.setType(ItemType.PUSH);
+						break;
+					}
+					String itemId = item.getId();
+					toolItem.setElementId(itemId == null ? id : itemId);
+					return toolItem;
+				}
+			}
+		} else {
+			final MDirectToolItem toolItem = MenuFactoryImpl.eINSTANCE.createDirectToolItem();
+			String itemId = item.getId();
+			toolItem.setElementId(itemId);
+			toolItem.setVisible(item.isVisible());
+			String iconURI = getIconURI(action.getImageDescriptor(), application.getContext());
+			if (iconURI == null) {
+				if (itemId == null) {
+					if (action.getText() != null) {
+						toolItem.setLabel(action.getText());
+					}
+				} else {
+					iconURI = getIconURI(itemId, application.getContext(),
+							ICommandImageService.TYPE_DEFAULT);
+					if (iconURI == null) {
+						if (action.getText() != null) {
+							toolItem.setLabel(action.getText());
+						}
+					} else {
+						toolItem.setIconURI(iconURI);
+					}
+				}
+			} else {
+				toolItem.setIconURI(iconURI);
+			}
+			if (action.getToolTipText() != null) {
+				toolItem.setTooltip(action.getToolTipText());
+			}
+
+			switch (action.getStyle()) {
+			case IAction.AS_CHECK_BOX:
+				toolItem.setType(ItemType.CHECK);
+				toolItem.setSelected(action.isChecked());
+				break;
+			case IAction.AS_RADIO_BUTTON:
+				toolItem.setType(ItemType.RADIO);
+				toolItem.setSelected(action.isChecked());
+				break;
+			default:
+				toolItem.setType(ItemType.PUSH);
+				break;
+			}
+			toolItem.setContributionURI("bundleclass://org.eclipse.ui.workbench/programmic.contribution"); //$NON-NLS-1$
+			toolItem.setObject(new DirectProxy(action));
+			toolItem.setEnabled(action.isEnabled());
+
+			final IPropertyChangeListener propertyListener = event -> {
+				String property = event.getProperty();
+				if (property.equals(IAction.ENABLED)) {
+					toolItem.setEnabled(action.isEnabled());
+				} else if (property.equals(IAction.CHECKED)) {
+					toolItem.setSelected(action.isChecked());
+				} else if (property.equals(IAction.TEXT)) {
+					toolItem.setLabel(action.getText());
+				} else if (property.equals(IAction.TOOL_TIP_TEXT)) {
+					toolItem.setLabel(action.getToolTipText());
+				}
+			};
+			// property listener is removed in
+			// DirectContributionItem#handleWidgetDispose()
+			action.addPropertyChangeListener(propertyListener);
+			toolItem.getTransientData().put(DirectContributionItem.DISPOSABLE, (Runnable) () -> action.removePropertyChangeListener(propertyListener));
+			return toolItem;
+		}
+		return null;
+	}
+
+	public static MMenuItem createItem(MApplication application, ActionContributionItem item) {
+		IAction action = item.getAction();
+		String id = action.getActionDefinitionId();
+		if (action instanceof OpenPreferencesAction) {
+			for (MCommand command : application.getCommands()) {
+				if (IWorkbenchCommandConstants.WINDOW_PREFERENCES.equals(command.getElementId())) {
+					MHandledMenuItem menuItem = MenuFactoryImpl.eINSTANCE.createHandledMenuItem();
+					menuItem.setCommand(command);
+					menuItem.setLabel(command.getCommandName());
+					menuItem.setIconURI(getIconURI(action.getImageDescriptor(),
+							application.getContext()));
+
+					// extract the mnemonic definition
+					String text = action.getText();
+					int index = text.indexOf('&');
+					if (index != -1 && index != text.length() - 1) {
+						menuItem.setMnemonics(text.substring(index + 1, index + 2));
+					}
+
+					switch (action.getStyle()) {
+					case IAction.AS_CHECK_BOX:
+						menuItem.setType(ItemType.CHECK);
+						menuItem.setSelected(action.isChecked());
+						break;
+					case IAction.AS_RADIO_BUTTON:
+						menuItem.setType(ItemType.RADIO);
+						menuItem.setSelected(action.isChecked());
+						break;
+					default:
+						menuItem.setType(ItemType.PUSH);
+						break;
+					}
+
+					String itemId = item.getId();
+					menuItem.setElementId(itemId == null ? id : itemId);
+					return menuItem;
+				}
+			}
+		} else if (id != null) {
+
+			for (MCommand command : application.getCommands()) {
+				if (id.equals(command.getElementId())) {
+					MHandledMenuItem menuItem = MenuFactoryImpl.eINSTANCE.createHandledMenuItem();
+					menuItem.setCommand(command);
+					if (action.getText() != null) {
+						menuItem.setLabel(action.getText());
+					} else {
+						menuItem.setLabel(command.getCommandName());
+					}
+					menuItem.setIconURI(getIconURI(action.getImageDescriptor(),
+							application.getContext()));
+
+					switch (action.getStyle()) {
+					case IAction.AS_CHECK_BOX:
+						menuItem.setType(ItemType.CHECK);
+						menuItem.setSelected(action.isChecked());
+						break;
+					case IAction.AS_RADIO_BUTTON:
+						menuItem.setType(ItemType.RADIO);
+						menuItem.setSelected(action.isChecked());
+						break;
+					default:
+						menuItem.setType(ItemType.PUSH);
+						break;
+					}
+
+					String itemId = item.getId();
+					menuItem.setElementId(itemId == null ? id : itemId);
+					return menuItem;
+				}
+			}
+		} else {
+			MDirectMenuItem menuItem = MenuFactoryImpl.eINSTANCE.createDirectMenuItem();
+			if (action.getText() != null) {
+				menuItem.setLabel(action.getText());
+			}
+			String itemId = item.getId();
+			menuItem.setElementId(itemId == null ? id : itemId);
+			menuItem.setIconURI(getIconURI(action.getImageDescriptor(), application.getContext()));
+			switch (action.getStyle()) {
+			case IAction.AS_CHECK_BOX:
+				menuItem.setType(ItemType.CHECK);
+				menuItem.setSelected(action.isChecked());
+				break;
+			case IAction.AS_RADIO_BUTTON:
+				menuItem.setType(ItemType.RADIO);
+				menuItem.setSelected(action.isChecked());
+				break;
+			default:
+				menuItem.setType(ItemType.PUSH);
+				break;
+			}
+			menuItem.setContributionURI("bundleclass://org.eclipse.ui.workbench/programmic.contribution"); //$NON-NLS-1$
+			menuItem.setObject(new DirectProxy(action));
+			return menuItem;
+		}
+		return null;
+	}
+
+	static class DirectProxy {
+		private IAction action;
+
+		public DirectProxy(IAction action) {
+			this.action = action;
+		}
+
+		@CanExecute
+		public boolean canExecute() {
+			return action.isEnabled();
+		}
+
+		@Execute
+		public void execute() {
+			action.run();
+		}
+	}
+
+	public static String getIconURI(ImageDescriptor descriptor, IEclipseContext context) {
+		if (descriptor == null) {
+			return null;
+		}
+
+		// Attempt to retrieve URIs from the descriptor and convert into a more
+		// durable form in case it's to be persisted
+		if (descriptor.getClass().toString().endsWith("URLImageDescriptor")) { //$NON-NLS-1$
+			String url = getUrl(descriptor.getClass(), descriptor);
+			return rewriteDurableURL(url);
+		} else if (descriptor.getClass().toString().endsWith("FileImageDescriptor")) { //$NON-NLS-1$
+			Class<?> sourceClass = getLocation(descriptor);
+			if (sourceClass == null) {
+				return null;
+			}
+
+			String path = getName(descriptor);
+			if (path == null) {
+				return null;
+			}
+
+			Bundle bundle = FrameworkUtil.getBundle(sourceClass);
+			// get the fully qualified class name
+			String parentPath = sourceClass.getName();
+			// remove the class's name
+			parentPath = parentPath.substring(0, parentPath.lastIndexOf('.'));
+			// swap '.' with '/' so that it becomes a path
+			parentPath = parentPath.replace('.', '/');
+
+			// construct the URL
+			URL url = FileLocator.find(bundle, new Path(parentPath).append(path), null);
+			return url == null ? null : rewriteDurableURL(url.toString());
+		} else {
+			if (descriptor instanceof IAdaptable) {
+				Object o = ((IAdaptable) descriptor).getAdapter(URL.class);
+				if (o != null) {
+					return rewriteDurableURL(o.toString());
+				}
+				o = ((IAdaptable) descriptor).getAdapter(URI.class);
+				if (o != null) {
+					return rewriteDurableURL(o.toString());
+				}
+			} else if (context != null) {
+				IAdapterManager adapter = context.get(IAdapterManager.class);
+				if (adapter != null) {
+					Object o = adapter.getAdapter(descriptor, URL.class);
+					if (o != null) {
+						return rewriteDurableURL(o.toString());
+					}
+					o = adapter.getAdapter(descriptor, URI.class);
+					if (o != null) {
+						return rewriteDurableURL(o.toString());
+					}
+				}
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Rewrite certain types of URLs to more durable forms, as these URLs may
+	 * may be persisted in the model.
+	 *
+	 * @param url
+	 *            the url
+	 * @return the rewritten URL
+	 */
+	private static String rewriteDurableURL(String url) {
+		// Rewrite bundleentry and bundleresource entries as they are
+		// invalidated on -clean or a bundle remove, . These Platform URIs are
+		// of the form:
+		// bundleentry://<bundle-id>.XXX/path/to/file
+		// bundleresource://<bundle-id>.XXX/path/to/file
+		if (!url.startsWith("bundleentry:") && !url.startsWith("bundleresource:")) { //$NON-NLS-1$ //$NON-NLS-2$
+			return url;
+		}
+
+		BundleContext ctxt = FrameworkUtil.getBundle(WorkbenchWindow.class).getBundleContext();
+		try {
+			URI uri = new URI(url);
+			String host = uri.getHost();
+			String bundleId = host.substring(0, host.indexOf('.'));
+			Bundle bundle = ctxt.getBundle(Long.parseLong(bundleId));
+			StringBuilder builder = new StringBuilder("platform:/plugin/"); //$NON-NLS-1$
+			builder.append(bundle.getSymbolicName());
+			builder.append(uri.getPath());
+			return builder.toString();
+		} catch (URISyntaxException e) {
+			return url;
+		}
+	}
+
+	private static String getIconURI(String commandId, IEclipseContext workbench, int type) {
+		if (commandId == null) {
+			return null;
+		}
+
+		ICommandImageService imageService = workbench.get(ICommandImageService.class);
+		ImageDescriptor descriptor = imageService.getImageDescriptor(commandId, type);
+		return getIconURI(descriptor, workbench);
+	}
+
+	/**
+	 * @param item
+	 * @param disabledIconURI
+	 */
+	public static void setDisabledIconURI(MToolItem item, String disabledIconURI) {
+		item.getTransientData().put(IPresentationEngine.DISABLED_ICON_IMAGE_KEY, disabledIconURI);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/MenuLocationURI.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/MenuLocationURI.java
new file mode 100644
index 0000000..ba215b8
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/MenuLocationURI.java
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.menus;
+
+import org.eclipse.ui.internal.util.Util;
+
+/**
+ * Basic implementation of the java.net.URI api. This is
+ * needed because the java 'foundation' doesn't contain
+ * the actual <code>java.net.URI</code> class.
+ * <p>
+ * The expected format for URI Strings managed by this class is:
+ * </p><p>
+ * "[scheme]:[path]?[query]"
+ * </p><p>
+ *  with the 'query' format being "[id1]=[val1]&[id2]=[val2]..."
+ * </p>
+ * @since 3.3
+ *
+ */
+public class MenuLocationURI {
+
+	private String rawString;
+
+	/**
+	 * @param uriDef
+	 */
+	public MenuLocationURI(String uriDef) {
+		rawString = uriDef;
+	}
+
+	/**
+	 * @return The query part of the uri (i.e. the
+	 * part after the '?').
+	 */
+	public String getQuery() {
+		// Trim off the scheme
+		String[] vals = Util.split(rawString, '?');
+		return vals.length>1?vals[1]:Util.ZERO_LENGTH_STRING;
+	}
+
+	/**
+	 * @return The scheme part of the uri (i.e. the
+	 * part before the ':').
+	 */
+	public String getScheme() {
+		String[] vals = Util.split(rawString, ':');
+		return vals[0];
+	}
+
+	/**
+	 * @return The path part of the uri (i.e. the
+	 * part between the ':' and the '?').
+	 */
+	public String getPath() {
+		// Trim off the scheme
+		String[] vals = Util.split(rawString, ':');
+		if (vals.length<2)
+			return null;
+
+		// Now, trim off any query
+		vals = Util.split(vals[1], '?');
+		return vals.length==0?Util.ZERO_LENGTH_STRING:vals[0];
+	}
+
+	@Override
+	public String toString() {
+		return rawString;
+	}
+
+	/**
+	 * @return the full URI definition string
+	 */
+	public String getRawString() {
+		return rawString;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/MenuPersistence.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/MenuPersistence.java
new file mode 100644
index 0000000..4c78321
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/MenuPersistence.java
@@ -0,0 +1,153 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2016 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ *     Friederike Schertel <friederike@schertel.org> - Bug 478336
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.menus;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.regex.Pattern;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.IRegistryChangeEvent;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.ui.internal.workbench.ContributionsAnalyzer;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.ui.menu.MMenuContribution;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolBarContribution;
+import org.eclipse.e4.ui.model.application.ui.menu.MTrimContribution;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.services.RegistryPersistence;
+
+/**
+ * <p>
+ * A static class for accessing the registry.
+ * </p>
+ * <p>
+ * This class is not intended for use outside of the
+ * <code>org.eclipse.ui.workbench</code> plug-in.
+ * </p>
+ *
+ * @since 3.2
+ */
+final public class MenuPersistence extends RegistryPersistence {
+
+	private MApplication application;
+	private IEclipseContext appContext;
+	private ArrayList<MenuAdditionCacheEntry> cacheEntries = new ArrayList<>();
+
+	private ArrayList<MMenuContribution> menuContributions = new ArrayList<>();
+	private ArrayList<MToolBarContribution> toolBarContributions = new ArrayList<>();
+	private ArrayList<MTrimContribution> trimContributions = new ArrayList<>();
+
+	private final Comparator<IConfigurationElement> comparer = (c1, c2) -> c1.getContributor().getName().compareToIgnoreCase(c2.getContributor().getName());
+	private Pattern contributorFilter;
+
+	/**
+	 * @param application
+	 * @param appContext
+	 */
+	public MenuPersistence(MApplication application, IEclipseContext appContext) {
+		this.application = application;
+		this.appContext = appContext;
+	}
+
+	public MenuPersistence(MApplication application, IEclipseContext appContext, String filterRegex) {
+		this(application, appContext);
+		contributorFilter = Pattern.compile(filterRegex);
+	}
+
+	@Override
+	public void dispose() {
+		ControlContributionRegistry.clear();
+		application.getMenuContributions().removeAll(menuContributions);
+		application.getToolBarContributions().removeAll(toolBarContributions);
+		application.getTrimContributions().removeAll(trimContributions);
+		menuContributions.clear();
+		cacheEntries.clear();
+		super.dispose();
+	}
+	@Override
+	protected boolean isChangeImportant(IRegistryChangeEvent event) {
+		return false;
+	}
+
+	public void reRead() {
+		read();
+	}
+
+	@Override
+	protected final void read() {
+		super.read();
+
+		readAdditions();
+
+		ArrayList<MMenuContribution> tmp = new ArrayList<>(menuContributions);
+		menuContributions.clear();
+		ContributionsAnalyzer.mergeContributions(tmp, menuContributions);
+		application.getMenuContributions().addAll(menuContributions);
+
+		ArrayList<MToolBarContribution> tmpToolbar = new ArrayList<>(
+				toolBarContributions);
+		toolBarContributions.clear();
+		ContributionsAnalyzer.mergeToolBarContributions(tmpToolbar, toolBarContributions);
+		application.getToolBarContributions().addAll(toolBarContributions);
+
+		ArrayList<MTrimContribution> tmpTrim = new ArrayList<>(trimContributions);
+		trimContributions.clear();
+		ContributionsAnalyzer.mergeTrimContributions(tmpTrim, trimContributions);
+		application.getTrimContributions().addAll(trimContributions);
+	}
+
+	private void readAdditions() {
+		final IExtensionRegistry registry = Platform.getExtensionRegistry();
+		ArrayList<IConfigurationElement> configElements = new ArrayList<>();
+		// Create a cache entry for every menu addition;
+		for (IConfigurationElement configElement : registry.getConfigurationElementsFor(EXTENSION_MENUS)) {
+			if (PL_MENU_CONTRIBUTION.equals(configElement.getName())) {
+				if (contributorFilter == null
+						|| contributorFilter.matcher(
+								configElement.getContributor().getName()).matches()) {
+					configElements.add(configElement);
+				}
+			}
+		}
+		Collections.sort(configElements, comparer);
+		Iterator<IConfigurationElement> i = configElements.iterator();
+		while (i.hasNext()) {
+			final IConfigurationElement configElement = i.next();
+
+			if (isProgramaticContribution(configElement)) {
+				MenuFactoryGenerator gen = new MenuFactoryGenerator(application, appContext,
+						configElement,
+						configElement.getAttribute(IWorkbenchRegistryConstants.TAG_LOCATION_URI));
+				gen.mergeIntoModel(menuContributions, toolBarContributions, trimContributions);
+			} else {
+				MenuAdditionCacheEntry menuContribution = new MenuAdditionCacheEntry(application,
+						appContext, configElement,
+						configElement.getAttribute(IWorkbenchRegistryConstants.TAG_LOCATION_URI),
+						configElement.getNamespaceIdentifier());
+				cacheEntries.add(menuContribution);
+				menuContribution.mergeIntoModel(menuContributions, toolBarContributions,
+						trimContributions);
+			}
+		}
+	}
+
+
+	private boolean isProgramaticContribution(IConfigurationElement menuAddition) {
+		return menuAddition.getAttribute(IWorkbenchRegistryConstants.ATT_CLASS) != null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/PulldownDelegateWidgetProxy.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/PulldownDelegateWidgetProxy.java
new file mode 100644
index 0000000..f152152
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/PulldownDelegateWidgetProxy.java
@@ -0,0 +1,437 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.menus;
+
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.commands.common.CommandException;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.menus.IWidget;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.CoolBar;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+import org.eclipse.swt.widgets.Widget;
+import org.eclipse.ui.IWorkbenchWindowPulldownDelegate;
+import org.eclipse.ui.IWorkbenchWindowPulldownDelegate2;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * <p>
+ * A proxy for a {@link IWorkbenchWindowPulldownDelegate} on a pulldown action
+ * set action. This delays the class loading until the delegate is really asked
+ * for information. Asking a proxy for anything (except disposing) will cause
+ * the proxy to instantiate the proxied delegate.
+ * </p>
+ * <p>
+ * This class is not intended for use outside of the
+ * <code>org.eclipse.ui.workbench</code> plug-in.
+ * </p>
+ *
+ * @since 3.2
+ */
+final class PulldownDelegateWidgetProxy implements IWidget {
+
+	/**
+	 * A wrapper for loading the menu that defends against possible exceptions
+	 * triggered outside of the workbench.
+	 */
+	private static final class MenuLoader implements ISafeRunnable {
+
+		/**
+		 * The parent for the menu to be created. This value is
+		 * <code>null</code> if the parent is a menu.
+		 */
+		private final Control control;
+
+		/**
+		 * The delegate from which to load the menu.
+		 */
+		private final IWorkbenchWindowPulldownDelegate delegate;
+
+		/**
+		 * The loaded menu. This value is <code>null</code> if the load
+		 * failed, or if it hasn't been loaded yet.
+		 */
+		private Menu menu = null;
+
+		/**
+		 * The parent for the menu to be created. This value is
+		 * <code>null</code> if the parent is a control.
+		 */
+		private final Menu parent;
+
+		/**
+		 * Constructs a new instance of <code>MenuLoader</code>
+		 *
+		 * @param delegate
+		 *            The delegate from which the menu will be loaded; this
+		 *            value must not be <code>null</code>.
+		 * @param parent
+		 *            The parent of the menu to be loaded; this value must not
+		 *            be <code>null</code>.
+		 */
+		private MenuLoader(final IWorkbenchWindowPulldownDelegate delegate,
+				final Control parent) {
+			this.delegate = delegate;
+			this.parent = null;
+			this.control = parent;
+		}
+
+		/**
+		 * Constructs a new instance of <code>MenuLoader</code>
+		 *
+		 * @param delegate
+		 *            The delegate from which the menu will be loaded; this
+		 *            value must not be <code>null</code>.
+		 * @param parent
+		 *            The parent of the menu to be loaded; this value must not
+		 *            be <code>null</code>.
+		 */
+		private MenuLoader(final IWorkbenchWindowPulldownDelegate2 delegate,
+				final Menu parent) {
+			this.delegate = delegate;
+			this.parent = parent;
+			this.control = null;
+		}
+
+		/**
+		 * Returns the menu loaded, if any.
+		 *
+		 * @return the loaded menu, or <code>null</code> if none.
+		 */
+		private Menu getMenu() {
+			return menu;
+		}
+
+		/**
+		 * @see ISafeRunnable#handleException(java.lang.Throwable)
+		 */
+		@Override
+		public void handleException(Throwable exception) {
+			// Do nothing
+		}
+
+		/**
+		 * @see ISafeRunnable#run()
+		 */
+		@Override
+		public void run() throws Exception {
+			if (parent == null) {
+				menu = delegate.getMenu(control);
+			} else {
+				menu = ((IWorkbenchWindowPulldownDelegate2) delegate)
+						.getMenu(parent);
+			}
+		}
+	}
+
+	/**
+	 * The command to execute when the pulldown delegate appears in a tool bar,
+	 * and the arrow is <em>not</em> clicked. This also carries a help context
+	 * identifier. This value must be <code>null</code>.
+	 */
+	private final ParameterizedCommand command;
+
+	/**
+	 * The configuration element from which the delegate can be created. This
+	 * value will exist until the element is converted into a real class -- at
+	 * which point this value will be set to <code>null</code>.
+	 */
+	private IConfigurationElement configurationElement;
+
+	/**
+	 * The real delegate. This value is <code>null</code> until the proxy is
+	 * forced to load the real delegate. At this point, the configuration
+	 * element is converted, nulled out, and this delegate gains a reference.
+	 */
+	private IWorkbenchWindowPulldownDelegate delegate = null;
+
+	/**
+	 * The name of the configuration element attribute which contains the
+	 * information necessary to instantiate the real delegate.
+	 */
+	private final String delegateAttributeName;
+
+	private final DisposeListener disposeListener = new DisposeListener() {
+		@Override
+		public void widgetDisposed(DisposeEvent e) {
+			if (e.widget == widget) {
+				dispose();
+				widget = null;
+
+				// TODO Is this necessary?
+				// disposeOldImages();
+			}
+		}
+	};
+
+	/**
+	 * The service locator from which a handler service can be retrieved. This
+	 * is needed if the pulldown appears in the tool bar, and the drop-down
+	 * arrow is <em>not</em> clicked. This value must not be <code>null</code>.
+	 */
+	private final IServiceLocator locator;
+
+	private final Listener selectionListener = new Listener() {
+		@Override
+		public final void handleEvent(final Event event) {
+			final Widget item = event.widget;
+			if (item == null) {
+				return;
+			}
+
+			final int style = item.getStyle();
+			if (((style & SWT.DROP_DOWN) != 0) && (event.detail == SWT.ARROW)
+					&& (item instanceof ToolItem)) {
+				// Create the submenu.
+				final ToolItem toolItem = (ToolItem) item;
+				final ToolBar toolBar = toolItem.getParent();
+				if (loadDelegate()
+						&& (delegate instanceof IWorkbenchWindowPulldownDelegate2)) {
+					final IWorkbenchWindowPulldownDelegate2 delegate2 = (IWorkbenchWindowPulldownDelegate2) delegate;
+					final MenuLoader loader = new MenuLoader(delegate2, toolBar);
+					SafeRunner.run(loader);
+					final Menu subMenu = loader.getMenu();
+					if (subMenu != null) {
+						// position the menu below the drop down item
+						final Rectangle bounds = toolItem.getBounds();
+						final Point location = toolBar.toDisplay(new Point(
+								bounds.x, bounds.y + bounds.height));
+						subMenu.setLocation(location);
+						subMenu.setVisible(true);
+						return; // we don't fire the command
+					}
+				}
+			}
+
+			final IHandlerService service = locator
+					.getService(IHandlerService.class);
+			try {
+				service.executeCommand(command, event);
+			} catch (final CommandException e) {
+				/*
+				 * TODO There should be an API on IHandlerService that handles
+				 * the exceptions.
+				 */
+			}
+		}
+
+	};
+
+	/**
+	 * The widget created for this pulldown delegate. If this proxy has not been
+	 * asked to fill or it has been disposed, then this value is
+	 * <code>null</code>.
+	 */
+	private Widget widget = null;
+
+	/**
+	 * Constructs a new instance of <code>PulldownDelegateWidgetProxy</code>
+	 * with all the information it needs to try to avoid loading until it is
+	 * needed.
+	 *
+	 * @param configurationElement
+	 *            The configuration element from which the real class can be
+	 *            loaded at run-time; must not be <code>null</code>.
+	 * @param delegateAttributeName
+	 *            The name of the attibute or element containing the delegate;
+	 *            must not be <code>null</code>.
+	 * @param command
+	 *            The command to execute if this the pulldown is not shown; must
+	 *            not be <code>null</code>.
+	 * @param locator
+	 *            A service locator from which a handler service can be
+	 *            retrieved; must not be <code>null</code>.
+	 */
+	public PulldownDelegateWidgetProxy(
+			final IConfigurationElement configurationElement,
+			final String delegateAttributeName,
+			final ParameterizedCommand command, final IServiceLocator locator) {
+		if (configurationElement == null) {
+			throw new NullPointerException(
+					"The configuration element backing a handler proxy cannot be null"); //$NON-NLS-1$
+		}
+
+		if (delegateAttributeName == null) {
+			throw new NullPointerException(
+					"The attribute containing the handler class must be known"); //$NON-NLS-1$
+		}
+
+		if (command == null) {
+			throw new NullPointerException("The command cannot be null"); //$NON-NLS-1$
+		}
+
+		this.configurationElement = configurationElement;
+		this.delegateAttributeName = delegateAttributeName;
+		this.command = command;
+		this.locator = locator;
+	}
+
+	/**
+	 * Passes the dipose on to the proxied handler, if it has been loaded.
+	 */
+	@Override
+	public final void dispose() {
+		if (delegate != null) {
+			delegate.dispose();
+		}
+	}
+
+	@Override
+	public final void fill(final Composite parent) {
+		// This does not need to be supported.
+	}
+
+	@Override
+	public final void fill(CoolBar parent, final int index) {
+		// This does not need to be supported.
+	}
+
+	@Override
+	public final void fill(final Menu parent, final int index) {
+		if ((widget != null) || (parent == null)) {
+			return;
+		}
+
+		// Create the menu item.
+		final MenuItem menuItem;
+		if (index >= 0) {
+			menuItem = new MenuItem(parent, SWT.CASCADE, index);
+		} else {
+			menuItem = new MenuItem(parent, SWT.CASCADE);
+		}
+		menuItem.setData(this);
+		widget = menuItem;
+
+		// Create the submenu.
+		if (loadDelegate()
+				&& (delegate instanceof IWorkbenchWindowPulldownDelegate2)) {
+			final IWorkbenchWindowPulldownDelegate2 delegate2 = (IWorkbenchWindowPulldownDelegate2) delegate;
+			final MenuLoader loader = new MenuLoader(delegate2, parent);
+			SafeRunner.run(loader);
+			final Menu subMenu = loader.getMenu();
+			if (subMenu != null) {
+				menuItem.setMenu(subMenu);
+			}
+		}
+
+		menuItem.addDisposeListener(disposeListener);
+		menuItem.addListener(SWT.Selection, selectionListener);
+
+		// TODO Needs a way to be linked to a command.
+		// if (action.getHelpListener() != null)
+		// menuItem.addHelpListener(action.getHelpListener());
+
+		// TODO Needs a way of updating itself
+		// update(null);
+	}
+
+	@Override
+	public final void fill(final ToolBar parent, final int index) {
+		if ((widget != null) && (parent == null)) {
+			return;
+		}
+
+		final ToolItem toolItem;
+		if (index >= 0) {
+			toolItem = new ToolItem(parent, SWT.DROP_DOWN, index);
+		} else {
+			toolItem = new ToolItem(parent, SWT.DROP_DOWN);
+		}
+		toolItem.setData(this);
+		widget = toolItem;
+
+		// Attach some listeners.
+		toolItem.addDisposeListener(disposeListener);
+		toolItem.addListener(SWT.Selection, selectionListener);
+
+		// TODO Needs a way to be linked to a command.
+		// toolItem.addListener(SWT.Selection, getToolItemListener());
+		// action.addPropertyChangeListener(propertyListener);
+		// if (action != null) {
+		// String commandId = action.getActionDefinitionId();
+		// ExternalActionManager.ICallback callback = ExternalActionManager
+		// .getInstance().getCallback();
+		//
+		// if ((callback != null) && (commandId != null)) {
+		// callback.addPropertyChangeListener(commandId,
+		// actionTextListener);
+		// }
+		// }
+
+		// TODO Needs a way of updating itself
+		// update(null);
+	}
+
+	/**
+	 * Loads the delegate, if possible. If the delegate is loaded, then the
+	 * member variables are updated accordingly.
+	 *
+	 * @return <code>true</code> if the delegate is now non-null;
+	 *         <code>false</code> otherwise.
+	 */
+	private final boolean loadDelegate() {
+		if (delegate == null) {
+			// Load the handler.
+			try {
+				delegate = (IWorkbenchWindowPulldownDelegate) configurationElement
+						.createExecutableExtension(delegateAttributeName);
+				configurationElement = null;
+				return true;
+
+			} catch (final ClassCastException e) {
+				final String message = "The proxied delegate was the wrong class"; //$NON-NLS-1$
+				final IStatus status = new Status(IStatus.ERROR,
+						WorkbenchPlugin.PI_WORKBENCH, 0, message, e);
+				WorkbenchPlugin.log(message, status);
+				return false;
+
+			} catch (final CoreException e) {
+				final String message = "The proxied delegate for '" + configurationElement.getAttribute(delegateAttributeName) //$NON-NLS-1$
+						+ "' could not be loaded"; //$NON-NLS-1$
+				IStatus status = new Status(IStatus.ERROR,
+						WorkbenchPlugin.PI_WORKBENCH, 0, message, e);
+				WorkbenchPlugin.log(message, status);
+				return false;
+			}
+		}
+
+		return true;
+	}
+
+	@Override
+	public final String toString() {
+		if (delegate == null) {
+			return configurationElement.getAttribute(delegateAttributeName);
+		}
+
+		return delegate.toString();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/SlaveMenuService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/SlaveMenuService.java
new file mode 100644
index 0000000..8debb38
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/SlaveMenuService.java
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * Copyright (c) 2013, 2015 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.ui.internal.menus;
+
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.e4.ui.model.application.MApplicationElement;
+import org.eclipse.jface.action.ContributionManager;
+import org.eclipse.ui.ISourceProvider;
+import org.eclipse.ui.menus.AbstractContributionFactory;
+import org.eclipse.ui.menus.IMenuService;
+
+/**
+ * @since 3.105
+ *
+ */
+public class SlaveMenuService implements IMenuService {
+	private IMenuService parentService;
+
+	/**
+	 * @param provider
+	 * @see org.eclipse.ui.services.IServiceWithSources#addSourceProvider(org.eclipse.ui.ISourceProvider)
+	 */
+	@Override
+	public void addSourceProvider(ISourceProvider provider) {
+		parentService.addSourceProvider(provider);
+	}
+
+	/**
+	 * @param provider
+	 * @see org.eclipse.ui.services.IServiceWithSources#removeSourceProvider(org.eclipse.ui.ISourceProvider)
+	 */
+	@Override
+	public void removeSourceProvider(ISourceProvider provider) {
+		parentService.removeSourceProvider(provider);
+	}
+
+	/**
+	 * @param factory
+	 * @see org.eclipse.ui.menus.IMenuService#addContributionFactory(org.eclipse.ui.menus.AbstractContributionFactory)
+	 */
+	@Override
+	public void addContributionFactory(AbstractContributionFactory factory) {
+		parentService.addContributionFactory(factory);
+	}
+
+	/**
+	 *
+	 * @see org.eclipse.ui.services.IDisposable#dispose()
+	 */
+	@Override
+	public void dispose() {
+		// nothing to do here yet.
+	}
+
+	/**
+	 * @param factory
+	 * @see org.eclipse.ui.menus.IMenuService#removeContributionFactory(org.eclipse.ui.menus.AbstractContributionFactory)
+	 */
+	@Override
+	public void removeContributionFactory(AbstractContributionFactory factory) {
+		parentService.removeContributionFactory(factory);
+	}
+
+	/**
+	 * @param mgr
+	 * @param location
+	 * @see org.eclipse.ui.menus.IMenuService#populateContributionManager(org.eclipse.jface.action.ContributionManager,
+	 *      java.lang.String)
+	 */
+	@Override
+	public void populateContributionManager(ContributionManager mgr, String location) {
+		populateContributionManager(model, mgr, location);
+	}
+
+	public void populateContributionManager(MApplicationElement model, ContributionManager mgr,
+			String location) {
+		if (parentService instanceof SlaveMenuService) {
+			((SlaveMenuService) parentService).populateContributionManager(model, mgr, location);
+		} else if (parentService instanceof WorkbenchMenuService) {
+			((WorkbenchMenuService) parentService)
+					.populateContributionManager(model, mgr, location);
+		}
+	}
+	/**
+	 * @param mgr
+	 * @see org.eclipse.ui.menus.IMenuService#releaseContributions(org.eclipse.jface.action.ContributionManager)
+	 */
+	@Override
+	public void releaseContributions(ContributionManager mgr) {
+		parentService.releaseContributions(mgr);
+	}
+
+	/**
+	 * @return
+	 * @see org.eclipse.ui.menus.IMenuService#getCurrentState()
+	 */
+	@Override
+	public IEvaluationContext getCurrentState() {
+		return parentService.getCurrentState();
+	}
+
+	public SlaveMenuService(IMenuService parent, MApplicationElement model) {
+		parentService = parent;
+		this.model = model;
+	}
+
+	private MApplicationElement model;
+
+	public MApplicationElement getModel() {
+		return model;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/ViewAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/ViewAction.java
new file mode 100644
index 0000000..33300d1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/ViewAction.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 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.ui.internal.menus;
+
+import java.util.ArrayList;
+import org.eclipse.core.commands.contexts.Context;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.ui.menu.MMenuContribution;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolBarContribution;
+import org.eclipse.e4.ui.model.application.ui.menu.MTrimContribution;
+import org.eclipse.e4.ui.services.EContextService;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+
+public class ViewAction extends ActionSet {
+
+	private IConfigurationElement parent;
+	private boolean isMenu;
+
+	public ViewAction(MApplication application, IEclipseContext appContext,
+			IConfigurationElement parent, IConfigurationElement element, boolean isMenu) {
+		super(application, appContext, element);
+		this.parent = parent;
+		this.isMenu = isMenu;
+	}
+
+	@Override
+	public void addToModel(ArrayList<MMenuContribution> menuContributions,
+			ArrayList<MToolBarContribution> toolBarContributions,
+			ArrayList<MTrimContribution> trimContributions) {
+		String idContrib = MenuHelper.getId(configElement);
+		visibleWhen = createExpression(configElement);
+
+		EContextService contextService = application.getContext().get(EContextService.class);
+		Context actionSetContext = contextService.getContext(idContrib);
+		if (!actionSetContext.isDefined()) {
+			actionSetContext.define(MenuHelper.getLabel(configElement),
+					MenuHelper.getDescription(configElement), "org.eclipse.ui.contexts.actionSet"); //$NON-NLS-1$
+		}
+
+		String parentId = parent.getAttribute(IWorkbenchRegistryConstants.ATT_TARGET_ID);
+		addContribution(idContrib, menuContributions, configElement, isMenu, parentId);
+		if (!isMenu) {
+			addToolBarContribution(idContrib, toolBarContributions, trimContributions,
+					configElement, parentId);
+		}
+	}
+
+	@Override
+	protected Expression createExpression(IConfigurationElement configElement) {
+		return null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/WidgetProxy.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/WidgetProxy.java
new file mode 100644
index 0000000..5729020
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/WidgetProxy.java
@@ -0,0 +1,212 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.menus;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.CoolBar;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.menus.AbstractWorkbenchTrimWidget;
+import org.eclipse.ui.menus.IWorkbenchWidget;
+
+/**
+ * <p>
+ * A proxy for a widget that has been defined in XML. This delays the class
+ * loading until the widget is really asked to fill a menu collection. Asking
+ * the widget for anything will instantiate the class.
+ * </p>
+ *
+ * @since 3.2
+ */
+final class WidgetProxy implements IWorkbenchWidget {
+
+	/**
+	 * Used to determine whether the load has been tried to
+	 * prevent multiple retries at a failed load.
+	 */
+	private boolean firstLoad = true;
+
+	/**
+	 * The configuration element from which the widget can be created. This
+	 * value will exist until the element is converted into a real class -- at
+	 * which point this value will be set to <code>null</code>.
+	 */
+	private IConfigurationElement configurationElement;
+
+	/**
+	 * The real widget. This value is <code>null</code> until the proxy is
+	 * forced to load the real widget. At this point, the configuration element
+	 * is converted, nulled out, and this widget gains a reference.
+	 */
+	private IWorkbenchWidget widget = null;
+
+	/**
+	 * The name of the configuration element attribute which contains the
+	 * information necessary to instantiate the real widget.
+	 */
+	private final String widgetAttributeName;
+
+	/**
+	 * Constructs a new instance of <code>WidgetProxy</code> with all the
+	 * information it needs to try to load the class at a later point in time.
+	 *
+	 * @param configurationElement
+	 *            The configuration element from which the real class can be
+	 *            loaded at run-time; must not be <code>null</code>.
+	 * @param widgetAttributeName
+	 *            The name of the attibute or element containing the widget
+	 *            executable extension; must not be <code>null</code>.
+	 */
+	public WidgetProxy(final IConfigurationElement configurationElement,
+			final String widgetAttributeName) {
+		if (configurationElement == null) {
+			throw new NullPointerException(
+					"The configuration element backing a widget proxy cannot be null"); //$NON-NLS-1$
+		}
+
+		if (widgetAttributeName == null) {
+			throw new NullPointerException(
+					"The attribute containing the widget class must be known"); //$NON-NLS-1$
+		}
+
+		this.configurationElement = configurationElement;
+		this.widgetAttributeName = widgetAttributeName;
+	}
+
+	@Override
+	public final void dispose() {
+		if (loadWidget()) {
+			widget.dispose();
+		}
+	}
+
+	@Override
+	public final void fill(final Composite parent) {
+		if (loadWidget()) {
+			widget.fill(parent);
+		}
+	}
+
+	@Override
+	public final void fill(final CoolBar parent, final int index) {
+		if (loadWidget()) {
+			widget.fill(parent, index);
+		}
+	}
+
+	@Override
+	public final void fill(final Menu parent, final int index) {
+		if (loadWidget()) {
+			widget.fill(parent, index);
+		}
+	}
+
+	@Override
+	public final void fill(final ToolBar parent, final int index) {
+		if (loadWidget()) {
+			widget.fill(parent, index);
+		}
+	}
+
+	@Override
+	public void init(IWorkbenchWindow workbenchWindow) {
+		if (loadWidget()) {
+			widget.init(workbenchWindow);
+		}
+	}
+
+	/**
+	 * Convenience method that allows the trim layout manager to
+	 * inform widgets if they have changed locations. If the IWidget
+	 * implementation does not support the method then we default
+	 * to using the simpler <code>fill(final Composite parent)</code>.
+	 *
+	 * @param parent The composite to create the controls in
+	 * @param oldSide The side the trim was previously displayed on
+	 * @param newSide The new side that the trim will be displayed on
+	 */
+	public final void fill(Composite parent, int oldSide, int newSide) {
+		if (loadWidget()) {
+			if (isMoveableTrimWidget()) {
+				((AbstractWorkbenchTrimWidget) widget).fill(parent, oldSide, newSide);
+			} else {
+				widget.fill(parent);
+			}
+		}
+	}
+
+	/**
+	 * Loads the widget, if possible. If the widget is loaded, then the member
+	 * variables are updated accordingly.
+	 *
+	 * @return <code>true</code> if the widget is now non-null;
+	 *         <code>false</code> otherwise.
+	 */
+	private final boolean loadWidget() {
+		if (firstLoad) {
+			// Load the handler.
+			try {
+				widget = (IWorkbenchWidget) configurationElement
+						.createExecutableExtension(widgetAttributeName);
+				configurationElement = null;
+			} catch (final ClassCastException e) {
+				final String message = "The proxied widget was the wrong class"; //$NON-NLS-1$
+				final IStatus status = new Status(IStatus.ERROR,
+						WorkbenchPlugin.PI_WORKBENCH, 0, message, e);
+				WorkbenchPlugin.log(message, status);
+
+			} catch (final CoreException e) {
+				final String message = "The proxied widget for '" + configurationElement.getAttribute(widgetAttributeName) //$NON-NLS-1$
+						+ "' could not be loaded"; //$NON-NLS-1$
+				IStatus status = new Status(IStatus.ERROR,
+						WorkbenchPlugin.PI_WORKBENCH, 0, message, e);
+				WorkbenchPlugin.log(message, status);
+			}
+		}
+
+		// We're througth the first load
+		firstLoad = false;
+
+		// the load only succeeded if there's a widget..
+		return widget != null;
+	}
+
+	/**
+	 * Determine if the widget knows how to respond to changes in the
+	 * workbench 'side' that it is being displayed on.
+	 *
+	 * @return <code>true</code> iff the <code>IWidget</code> implementation
+	 * is actually based on <code>AbstractTrimWidget</code>
+	 */
+	private final boolean isMoveableTrimWidget() {
+		if (loadWidget()) {
+			return widget instanceof AbstractWorkbenchTrimWidget;
+		}
+
+		return false;
+	}
+
+	@Override
+	public final String toString() {
+		if (widget == null) {
+			return configurationElement.getAttribute(widgetAttributeName);
+		}
+
+		return widget.toString();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/WorkbenchMenuService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/WorkbenchMenuService.java
new file mode 100644
index 0000000..2550181
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/WorkbenchMenuService.java
@@ -0,0 +1,490 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2016 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ ******************************************************************************/
+
+package org.eclipse.ui.internal.menus;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.e4.core.commands.ExpressionContext;
+import org.eclipse.e4.core.contexts.ContextFunction;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.ui.internal.workbench.ContributionsAnalyzer;
+import org.eclipse.e4.ui.internal.workbench.UIEventPublisher;
+import org.eclipse.e4.ui.internal.workbench.swt.AbstractPartRenderer;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.MApplicationElement;
+import org.eclipse.e4.ui.model.application.ui.MContext;
+import org.eclipse.e4.ui.model.application.ui.MElementContainer;
+import org.eclipse.e4.ui.model.application.ui.MUIElement;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.model.application.ui.menu.MMenu;
+import org.eclipse.e4.ui.model.application.ui.menu.MMenuContribution;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolBar;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolBarContribution;
+import org.eclipse.e4.ui.model.application.ui.menu.impl.MenuFactoryImpl;
+import org.eclipse.e4.ui.model.internal.ModelUtils;
+import org.eclipse.e4.ui.services.IServiceConstants;
+import org.eclipse.e4.ui.workbench.IPresentationEngine;
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+import org.eclipse.e4.ui.workbench.renderers.swt.ContributionRecord;
+import org.eclipse.e4.ui.workbench.renderers.swt.MenuManagerRenderer;
+import org.eclipse.e4.ui.workbench.renderers.swt.MenuManagerRendererFilter;
+import org.eclipse.e4.ui.workbench.renderers.swt.ToolBarContributionRecord;
+import org.eclipse.e4.ui.workbench.renderers.swt.ToolBarManagerRenderer;
+import org.eclipse.e4.ui.workbench.swt.factories.IRendererFactory;
+import org.eclipse.emf.common.notify.Notifier;
+import org.eclipse.jface.action.ContributionManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.ToolBarManager;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.ui.ISourceProvider;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.WorkbenchWindow;
+import org.eclipse.ui.internal.services.IWorkbenchLocationService;
+import org.eclipse.ui.internal.services.ServiceLocator;
+import org.eclipse.ui.menus.AbstractContributionFactory;
+import org.eclipse.ui.menus.IMenuService;
+
+/**
+ * @since 3.5
+ *
+ */
+public class WorkbenchMenuService implements IMenuService {
+
+	private static final String POPULATED_TOOL_BARS = "populatedToolBars"; //$NON-NLS-1$
+	private static final String POPULATED_MENUS = "populatedMenus"; //$NON-NLS-1$
+	private IEclipseContext e4Context;
+	private ServiceLocator serviceLocator;
+	private ExpressionContext legacyContext;
+	private MenuPersistence persistence;
+	private Map<AbstractContributionFactory, Object> factoriesToContributions = new HashMap<>();
+	private EModelService modelService;
+
+	/**
+	 * @param serviceLocator
+	 * @param e4Context
+	 */
+	public WorkbenchMenuService(ServiceLocator serviceLocator, IEclipseContext e4Context) {
+		this.serviceLocator = serviceLocator;
+		this.e4Context = e4Context;
+		modelService = e4Context.get(EModelService.class);
+
+		persistence = new MenuPersistence(e4Context.get(MApplication.class), e4Context);
+	}
+
+	@Override
+	public void addSourceProvider(ISourceProvider provider) {
+		// TODO Auto-generated method
+
+	}
+
+	@Override
+	public void removeSourceProvider(ISourceProvider provider) {
+	}
+
+	@Override
+	public void dispose() {
+		persistence.dispose();
+	}
+
+	private boolean inToolbar(MenuLocationURI location) {
+		return location.getScheme().startsWith("toolbar"); //$NON-NLS-1$
+	}
+
+	@Override
+	public void addContributionFactory(final AbstractContributionFactory factory) {
+		MenuLocationURI location = new MenuLocationURI(factory.getLocation());
+		if (location.getPath() == null || location.getPath().length() == 0) {
+			WorkbenchPlugin
+					.log("WorkbenchMenuService.addContributionFactory: Invalid menu URI: " + location); //$NON-NLS-1$
+			return;
+		}
+
+		if (inToolbar(location)) {
+			if (MenuAdditionCacheEntry.isInWorkbenchTrim(location)) {
+				// processTrimChildren(trimContributions, toolBarContributions,
+				// configElement);
+			} else {
+				String query = location.getQuery();
+				if (query == null || query.length() == 0) {
+					query = "after=additions"; //$NON-NLS-1$
+				}
+				processToolbarChildren(factory, location, location.getPath(), query);
+			}
+			return;
+		}
+		MMenuContribution menuContribution = MenuFactoryImpl.eINSTANCE.createMenuContribution();
+		menuContribution.setElementId(factory.getNamespace() + ":" + factory.hashCode()); //$NON-NLS-1$
+
+		if ("org.eclipse.ui.popup.any".equals(location.getPath())) { //$NON-NLS-1$
+			menuContribution.setParentId("popup"); //$NON-NLS-1$
+		} else {
+			menuContribution.setParentId(location.getPath());
+		}
+		String query = location.getQuery();
+		if (query == null || query.length() == 0) {
+			query = "after=additions"; //$NON-NLS-1$
+		}
+		menuContribution.setPositionInParent(query);
+		menuContribution.getTags().add("scheme:" + location.getScheme()); //$NON-NLS-1$
+		String filter = ContributionsAnalyzer.MC_MENU;
+		if ("popup".equals(location.getScheme())) { //$NON-NLS-1$
+			filter = ContributionsAnalyzer.MC_POPUP;
+		}
+		menuContribution.getTags().add(filter);
+		ContextFunction generator = new ContributionFactoryGenerator(factory, 0);
+		menuContribution.getTransientData().put(ContributionRecord.FACTORY, generator);
+		factoriesToContributions.put(factory, menuContribution);
+		MApplication app = e4Context.get(MApplication.class);
+		app.getMenuContributions().add(menuContribution);
+
+	}
+
+	private void processToolbarChildren(AbstractContributionFactory factory,
+			MenuLocationURI location, String parentId, String position) {
+		MToolBarContribution toolBarContribution = MenuFactoryImpl.eINSTANCE
+				.createToolBarContribution();
+		toolBarContribution.setElementId(factory.getNamespace() + ":" + factory.hashCode()); //$NON-NLS-1$
+		toolBarContribution.setParentId(parentId);
+		toolBarContribution.setPositionInParent(position);
+		toolBarContribution.getTags().add("scheme:" + location.getScheme()); //$NON-NLS-1$
+
+		ContextFunction generator = new ContributionFactoryGenerator(factory, 1);
+		toolBarContribution.getTransientData().put(ToolBarContributionRecord.FACTORY, generator);
+		factoriesToContributions.put(factory, toolBarContribution);
+		MApplication app = e4Context.get(MApplication.class);
+		app.getToolBarContributions().add(toolBarContribution);
+	}
+
+	@Override
+	public void removeContributionFactory(AbstractContributionFactory factory) {
+		Object contribution;
+		if ((contribution = factoriesToContributions.remove(factory)) != null) {
+			MApplication app = e4Context.get(MApplication.class);
+			if (app == null)
+				return;
+			if (contribution instanceof MMenuContribution) {
+				app.getMenuContributions().remove(contribution);
+			} else if (contribution instanceof MToolBarContribution) {
+				app.getToolBarContributions().remove(contribution);
+			}
+		}
+
+	}
+
+	protected IWorkbenchWindow getWindow() {
+		if (serviceLocator == null)
+			return null;
+
+		IWorkbenchLocationService wls = serviceLocator.getService(IWorkbenchLocationService.class);
+
+		IWorkbenchWindow window = null;
+		if (window == null) {
+			window = wls.getWorkbenchWindow();
+		}
+		if (window == null) {
+			IWorkbench wb = wls.getWorkbench();
+			if (wb != null) {
+				window = wb.getActiveWorkbenchWindow();
+			}
+		}
+		if (window == null) {
+			window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+		}
+		return window;
+	}
+
+	@Override
+	public void populateContributionManager(ContributionManager mgr, String location) {
+		MApplicationElement model = getPartToExtend();
+		if (model == null) {
+			final IWorkbenchWindow window = getWindow();
+			if (window instanceof WorkbenchWindow) {
+				model = ((WorkbenchWindow) window).getModel();
+			}
+		}
+		populateContributionManager(model, mgr, location);
+	}
+
+	public void populateContributionManager(MApplicationElement model, ContributionManager mgr,
+			String location) {
+		MenuLocationURI uri = new MenuLocationURI(location);
+
+		// Now handle registering dynamic additions by querying E4 model
+		if (mgr instanceof MenuManager) {
+			MenuManager menu = (MenuManager) mgr;
+			MMenu mMenu = getMenuModel(model, menu, uri);
+			if (mMenu == null) {
+				return;
+			}
+
+			IRendererFactory factory = e4Context.get(IRendererFactory.class);
+			AbstractPartRenderer obj = factory.getRenderer(mMenu, null);
+			if (obj instanceof MenuManagerRenderer) {
+				MenuManagerRenderer renderer = (MenuManagerRenderer) obj;
+				mMenu.setRenderer(renderer);
+				renderer.reconcileManagerToModel(menu, mMenu);
+				renderer.processContributions(mMenu, uri.getPath(), false,
+						"popup".equals(uri.getScheme())); //$NON-NLS-1$
+				// double cast because we're bad people
+				renderer.processContents((MElementContainer<MUIElement>) ((Object) mMenu));
+				final IEclipseContext evalContext;
+				if (mMenu instanceof MContext) {
+					evalContext = ((MContext) mMenu).getContext();
+				} else {
+					evalContext = modelService.getContainingContext(mMenu);
+				}
+				MenuManagerRendererFilter.updateElementVisibility(mMenu, renderer, menu,
+						evalContext, 2, true);
+			}
+		} else if (mgr instanceof ToolBarManager) {
+			ToolBarManager toolbar = (ToolBarManager) mgr;
+			MToolBar mToolBar = getToolbarModel(model, toolbar, uri);
+			if (mToolBar == null) {
+				return;
+			}
+
+			IRendererFactory factory = e4Context.get(IRendererFactory.class);
+			AbstractPartRenderer obj = factory.getRenderer(mToolBar, null);
+			if (obj instanceof ToolBarManagerRenderer) {
+				ToolBarManagerRenderer renderer = (ToolBarManagerRenderer) obj;
+				mToolBar.setRenderer(renderer);
+				renderer.reconcileManagerToModel(toolbar, mToolBar);
+				renderer.processContribution(mToolBar, uri.getPath());
+				// double cast because we're bad people
+				renderer.processContents((MElementContainer<MUIElement>) ((Object) mToolBar));
+			}
+		} else {
+			WorkbenchPlugin.log("populateContributionManager: Unhandled manager: " + mgr); //$NON-NLS-1$
+		}
+	}
+
+	protected MToolBar getToolbarModel(MApplicationElement model, ToolBarManager toolbarManager,
+			MenuLocationURI location) {
+		final IRendererFactory factory = e4Context.get(IRendererFactory.class);
+		final AbstractPartRenderer obj = factory.getRenderer(
+				MenuFactoryImpl.eINSTANCE.createToolBar(), null);
+		if (!(obj instanceof ToolBarManagerRenderer)) {
+			return null;
+		}
+		ToolBarManagerRenderer renderer = (ToolBarManagerRenderer) obj;
+		MToolBar mToolBar = renderer.getToolBarModel(toolbarManager);
+		if (mToolBar != null) {
+			String tag = "toolbar:" + location.getPath(); //$NON-NLS-1$
+			if (!mToolBar.getTags().contains(tag)) {
+				mToolBar.getTags().add(tag);
+			}
+			return mToolBar;
+		}
+
+		if (mToolBar == null) {
+			mToolBar = MenuFactoryImpl.eINSTANCE.createToolBar();
+			mToolBar.setElementId(location.getPath());
+			mToolBar.getTags().add(ContributionsAnalyzer.MC_TOOLBAR);
+			String tag = "toolbar:" + location.getPath(); //$NON-NLS-1$
+			mToolBar.getTags().add(tag);
+			addToolbar(model, mToolBar, ((MContext) model).getContext());
+		}
+
+		renderer.linkModelToManager(mToolBar, toolbarManager);
+
+		return mToolBar;
+	}
+
+	private void addToolbar(MApplicationElement model, MToolBar tb, IEclipseContext ctx) {
+		ArrayList<MToolBar> toolbars = (ArrayList<MToolBar>) model.getTransientData().get(
+				POPULATED_TOOL_BARS);
+		if (toolbars == null) {
+			toolbars = new ArrayList<>();
+			model.getTransientData().put(POPULATED_TOOL_BARS, toolbars);
+		}
+		if (toolbars.contains(tb)) {
+			return;
+		}
+		toolbars.add(tb);
+		tb.getTransientData().put(ModelUtils.CONTAINING_PARENT, model);
+		((Notifier) tb).eAdapters().add(ctx.get(UIEventPublisher.class));
+	}
+
+	private void addMenu(MApplicationElement model, MMenu menu, IEclipseContext ctx) {
+		ArrayList<MMenu> menus = (ArrayList<MMenu>) model.getTransientData().get(POPULATED_MENUS);
+		if (menus == null) {
+			menus = new ArrayList<>();
+			model.getTransientData().put(POPULATED_MENUS, menus);
+		}
+		if (menus.contains(menu)) {
+			return;
+		}
+		menus.add(menu);
+		menu.getTransientData().put(ModelUtils.CONTAINING_PARENT, model);
+		((Notifier) menu).eAdapters().add(ctx.get(UIEventPublisher.class));
+	}
+
+	protected MMenu getMenuModel(MApplicationElement model, MenuManager menuManager,
+			MenuLocationURI location) {
+
+		final IRendererFactory factory = e4Context.get(IRendererFactory.class);
+		final AbstractPartRenderer obj = factory.getRenderer(((WorkbenchWindow) getWindow())
+				.getModel().getMainMenu(), null);
+		if (!(obj instanceof MenuManagerRenderer)) {
+			return null;
+		}
+		MenuManagerRenderer renderer = (MenuManagerRenderer) obj;
+		MMenu mMenu = renderer.getMenuModel(menuManager);
+		if (mMenu != null) {
+			final String tag;
+			if ("popup".equals(location.getScheme())) { //$NON-NLS-1$
+				tag = "popup:" + location.getPath(); //$NON-NLS-1$
+			} else {
+				tag = "menu:" + location.getPath(); //$NON-NLS-1$
+			}
+			if (!mMenu.getTags().contains(tag)) {
+				mMenu.getTags().add(tag);
+			}
+			return mMenu;
+		}
+
+		if (mMenu == null) {
+			mMenu = MenuFactoryImpl.eINSTANCE.createMenu();
+			mMenu.setElementId(menuManager.getId());
+			if (mMenu.getElementId() == null) {
+				mMenu.setElementId(location.getPath());
+			}
+			final String tag;
+			if ("popup".equals(location.getScheme())) { //$NON-NLS-1$
+				mMenu.getTags().add(ContributionsAnalyzer.MC_POPUP);
+				tag = "popup:" + location.getPath(); //$NON-NLS-1$
+			} else {
+				mMenu.getTags().add(ContributionsAnalyzer.MC_MENU);
+				tag = "menu:" + location.getPath(); //$NON-NLS-1$
+			}
+			mMenu.getTags().add(tag);
+			mMenu.setLabel(menuManager.getMenuText());
+			addMenu(model, mMenu, ((MContext) model).getContext());
+		}
+
+		renderer.linkModelToManager(mMenu, menuManager);
+
+		return mMenu;
+	}
+
+
+	private MPart getPartToExtend() {
+		return (MPart) e4Context.getActiveLeaf().get(IServiceConstants.ACTIVE_PART);
+	}
+
+	@Override
+	public void releaseContributions(ContributionManager mgr) {
+		if (mgr instanceof MenuManager) {
+			MenuManager menu = (MenuManager) mgr;
+			releaseContributionManager(menu);
+		} else if (mgr instanceof ToolBarManager) {
+			ToolBarManager toolbar = (ToolBarManager) mgr;
+			releaseContributionManager(toolbar);
+		} else {
+			WorkbenchPlugin.log("releaseContributions: Unhandled manager: " + mgr); //$NON-NLS-1$
+		}
+	}
+
+	/**
+	 * @param toolbar
+	 */
+	private void releaseContributionManager(ToolBarManager toolbarManager) {
+		final IRendererFactory factory = e4Context.get(IRendererFactory.class);
+		final AbstractPartRenderer obj = factory.getRenderer(
+				MenuFactoryImpl.eINSTANCE.createToolBar(), null);
+		if (!(obj instanceof ToolBarManagerRenderer)) {
+			return;
+		}
+		ToolBarManagerRenderer renderer = (ToolBarManagerRenderer) obj;
+		MToolBar mToolBar = renderer.getToolBarModel(toolbarManager);
+		if (mToolBar == null) {
+			return;
+		}
+		MApplicationElement model = (MApplicationElement) mToolBar.getTransientData().get(
+				ModelUtils.CONTAINING_PARENT);
+		if (model != null) {
+			((Notifier) mToolBar).eAdapters().clear();
+			ArrayList<MToolBar> toolbars = (ArrayList<MToolBar>) model.getTransientData().get(
+					POPULATED_TOOL_BARS);
+			if (toolbars != null) {
+				toolbars.remove(mToolBar);
+			}
+		}
+		final ToolBar widget = toolbarManager.getControl();
+		if (widget != null && !widget.isDisposed()
+				&& widget.getData(AbstractPartRenderer.OWNING_ME) == null) {
+			widget.setData(AbstractPartRenderer.OWNING_ME, mToolBar);
+		}
+		final IPresentationEngine engine = e4Context.get(IPresentationEngine.class);
+		engine.removeGui(mToolBar);
+		mToolBar.getTransientData().remove(ModelUtils.CONTAINING_PARENT);
+	}
+
+	/**
+	 * @param menu
+	 */
+	private void releaseContributionManager(MenuManager menuManager) {
+		final IRendererFactory factory = e4Context.get(IRendererFactory.class);
+		final AbstractPartRenderer obj = factory.getRenderer(((WorkbenchWindow) getWindow())
+				.getModel().getMainMenu(), null);
+		if (!(obj instanceof MenuManagerRenderer)) {
+			return;
+		}
+		MenuManagerRenderer renderer = (MenuManagerRenderer) obj;
+		MMenu mMenu = renderer.getMenuModel(menuManager);
+		if (mMenu == null) {
+			return;
+		}
+		MApplicationElement model = (MApplicationElement) mMenu.getTransientData().get(
+				ModelUtils.CONTAINING_PARENT);
+		if (model != null) {
+			((Notifier) mMenu).eAdapters().clear();
+			ArrayList<MMenu> menus = (ArrayList<MMenu>) model.getTransientData().get(
+					POPULATED_MENUS);
+			if (menus != null) {
+				menus.remove(mMenu);
+			}
+		}
+		final Menu widget = menuManager.getMenu();
+		if (widget != null && !widget.isDisposed()
+				&& widget.getData(AbstractPartRenderer.OWNING_ME) == null) {
+			widget.setData(AbstractPartRenderer.OWNING_ME, mMenu);
+		}
+		final IPresentationEngine engine = e4Context.get(IPresentationEngine.class);
+		engine.removeGui(mMenu);
+		mMenu.getTransientData().remove(ModelUtils.CONTAINING_PARENT);
+	}
+
+	@Override
+	public IEvaluationContext getCurrentState() {
+		if (legacyContext == null) {
+			legacyContext = new ExpressionContext(e4Context);
+		}
+		return legacyContext;
+	}
+
+	/**
+	 * read in the menu contributions and turn them into model menu
+	 * contributions
+	 */
+	public void readRegistry() {
+		persistence.read();
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/messages.properties b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/messages.properties
new file mode 100644
index 0000000..3b31d17
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/menus/messages.properties
@@ -0,0 +1,14 @@
+###############################################################################
+# Copyright (c) 2008, 2011 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.ui.internal.menus
+
+Tooltip_Accelerator = {0} ({1})
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/messages.properties b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/messages.properties
new file mode 100644
index 0000000..2f50535
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/messages.properties
@@ -0,0 +1,999 @@
+###############################################################################
+# Copyright (c) 2000, 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
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#     IBM Corporation - initial API and implementation
+#     Sebastian Davids (sdavids@gmx.de)
+#        - Fix for Bug 57087
+#        - Fix for Bug 138034 [Preferences] Label decorations page - extra space
+#        - Fix for Bug 128529
+#     Semion Chichelnitsky (semion@il.ibm.com) - bug 278064
+#     Tristan Hume - <trishume@gmail.com> -
+#     		Fix for Bug 2369 [Workbench] Would like to be able to save workspace without exiting
+#     		Implemented workbench auto-save to correctly restore state in case of crash.
+#     Andrey Loskutov <loskutov@gmx.de> - Bug 445538
+#     Alain Bernard <alain.bernard1224@gmail.com> - Bug 281490
+#     Lars Vogel <Lars.Vogel@vogella.com> - Bug 407432
+#     Patrik Suzzi <psuzzi@gmail.com> - Bug 491572, 491785, 501811, 511198
+###############################################################################
+
+# package: org.eclipse.ui
+
+PlatformUI_NoWorkbench = Workbench has not been created yet.
+
+Workbench_CreatingWorkbenchTwice = Workbench already exists and cannot be created again.
+
+# ==============================================================================
+# Workbench Actions
+# ==============================================================================
+
+# --- File Menu ---
+NewWizardAction_text = &Other...
+NewWizardAction_toolTip = New
+CloseAllAction_text = C&lose All
+CloseAllAction_toolTip = Close All
+CloseOthersAction_text = Close O&thers
+CloseOthersAction_toolTip = Close Others
+CloseAllSavedAction_text = Cl&ose All Saved
+CloseAllSavedAction_toolTip = Close All Saved
+CloseEditorAction_text = &Close
+CloseEditorAction_toolTip = Close
+NewEditorAction_text=New &Editor
+NewEditorAction_tooltip=New Editor
+SaveAction_text = &Save
+SaveAction_toolTip = Save
+SaveAs_text = Save &As...
+SaveAs_toolTip = Save As
+SaveAll_text = Sav&e All
+SaveAll_toolTip = Save All
+Workbench_revert = Rever&t
+Workbench_revertToolTip = Revert
+Workbench_missingPropertyMessage=Unable to relaunch the platform with the current workspace because the ''{0}'' property has not been set.
+Workbench_move = Mo&ve...
+Workbench_moveToolTip = Move
+Workbench_rename = Rena&me...
+Workbench_renameToolTip = Rename
+Workbench_refresh = Re&fresh
+Workbench_refreshToolTip = Refresh
+Workbench_properties = P&roperties
+Workbench_propertiesToolTip = Properties
+Workbench_print = &Print...
+Workbench_printToolTip = Print
+ExportResourcesAction_text = E&xport...
+ExportResourcesAction_fileMenuText = Exp&ort...
+ExportResourcesAction_toolTip = Export
+ImportResourcesAction_text = &Import...
+ImportResourcesAction_toolTip = Import
+OpenRecent_errorTitle = Problems opening editor
+OpenRecent_unableToOpen = Unable to open ''{0}''.
+Exit_text = E&xit
+Exit_toolTip = Exit Workbench
+
+
+# --- Edit Menu ---
+Workbench_undo = &Undo
+Workbench_undoToolTip = Undo
+Workbench_redo = &Redo
+Workbench_redoToolTip = Redo
+Workbench_cut = Cu&t
+Workbench_cutToolTip = Cut
+Workbench_copy = &Copy
+Workbench_copyToolTip = Copy
+Workbench_paste = &Paste
+Workbench_pasteToolTip = Paste
+Workbench_delete = &Delete
+Workbench_deleteToolTip = Delete
+Workbench_selectAll = Select &All
+Workbench_selectAllToolTip = Select All
+Workbench_findReplace = &Find/Replace...
+Workbench_findReplaceToolTip = Find/Replace
+
+# --- Navigate Menu ---
+Workbench_goInto = Go &Into
+Workbench_goIntoToolTip = Go Into
+Workbench_back = &Back
+Workbench_backToolTip = Back
+Workbench_forward = &Forward
+Workbench_forwardToolTip = Forward
+Workbench_up = &Up One Level
+Workbench_upToolTip = Up
+Workbench_next = Ne&xt
+Workbench_nextToolTip = Next
+Workbench_previous = Pre&vious
+Workbench_previousToolTip = Previous
+
+NavigationHistoryAction_forward_text=&Forward
+NavigationHistoryAction_forward_toolTip=Forward
+NavigationHistoryAction_backward_text=&Back
+NavigationHistoryAction_backward_toolTip=Back
+NavigationHistoryAction_forward_toolTipName=Forward to {0}
+NavigationHistoryAction_backward_toolTipName=Back to {0}
+NavigationHistoryAction_locations = {0} ({1} locations)
+
+Workbench_showInNoTargets = <No Applicable Views>
+Workbench_showInNoPerspectives = <No Applicable Perspectives>
+Workbench_noApplicableItems = <No Applicable Items>
+
+OpenPreferences_text = &Preferences
+OpenPreferences_toolTip = Preferences
+
+# --- Window Menu ---
+PerspectiveMenu_otherItem = &Other...
+SelectPerspective_shellTitle = Open Perspective
+SelectPerspective_selectPerspectiveHelp = Use F2 to display the description for a selected perspective.
+SelectPerspective_noDesc = No description available.
+SelectPerspective_open_button_label=&Open
+Workbench_showPerspectiveError = Problems opening perspective ''{0}''
+ChangeToPerspectiveMenu_errorTitle = Problems Changing Perspective
+
+ShowView_title = &Other...
+ShowView_shellTitle = Show View
+ShowView_selectViewHelp = Use F2 to display the description for a selected view.
+ShowView_noDesc = No description available.
+ShowView_open_button_label=&Open
+
+ToggleEditor_hideEditors = Hide &Editors
+ToggleEditor_showEditors = Show &Editors
+ToggleEditor_toolTip = Hide/Show Editors
+
+LockToolBarAction_toolTip = Toggle Lock Toolbars
+
+# --- Customize Perspective Dialog ---
+EditActionSetsAction_text = Customi&ze Perspective...
+EditActionSetsAction_toolTip = Customize Perspective
+ActionSetSelection_customize = Customize Perspective - {0}
+ActionSetDialogInput_viewCategory = Show View
+ActionSetDialogInput_perspectiveCategory = Open Perspective
+ActionSetDialogInput_wizardCategory = New
+
+Shortcuts_shortcutTab = Shortcuts
+Shortcuts_selectShortcutsLabel = Select the shortcuts that you want to see added as cascade items to the following submenus.  The selections made will only affect the current perspective ({0}).
+Shortcuts_availableMenus = &Submenus:
+Shortcuts_availableCategories = Shortcut &Categories:
+Shortcuts_allShortcuts = S&hortcuts:
+
+ActionSetSelection_actionSetsTab = Action Set Availability
+ActionSetSelection_selectActionSetsLabel = Select the action sets that you want to see added to the current perspective ({0}).  The details field identifies which menu items and/or toolbar items are added to the perspective by the selected action set.
+ActionSetSelection_availableActionSets = Available &action sets:
+ActionSetSelection_menubarActions = &Menubar details:
+ActionSetSelection_toolbarActions = &Toolbar details:
+ActionSetSelection_descriptionColumnHeader = Description
+ActionSetSelection_menuColumnHeader = Shortcut
+
+HideItems_itemInActionSet = Contributed by the <a>''{0}'' action set</a>.
+HideItems_itemInUnavailableActionSet = This item cannot be made visible because the <a>action set ''{0}''</a> which contributes it is unavailable.
+HideItems_itemInUnavailableCommand = This command cannot be made visible in this dialog.
+HideItems_unavailableChildCommandGroup = This item cannot be made visible because all of its children are in the unavailable <a href="{0}">action set ''{1}''</a>.
+HideItems_unavailableChildCommandGroups = This item cannot be made visible because all of its children are in unavailable action sets: {0}
+HideItems_keyBindings = Key bindings: <a>{0}</a>.
+HideItems_keyBindingsActionSetUnavailable = Key bindings (cannot be used because action set is unavailable): <a>{0}</a>
+HideItems_noKeyBindings = No <a>key bindings</a>
+HideItems_noKeyBindingsActionSetUnavailable = No key bindings (to edit, make action set available).
+HideItems_commandGroupTitle = &Action Sets:
+HideItems_turnOnActionSets = &Filter by action set
+
+
+HideItems_dynamicItemName = [Dynamic]
+HideItems_dynamicItemDescription = The labels and number of menu items contributed by this dynamic entry are variable.
+HideItems_dynamicItemList = The items which are currently being displayed are:
+HideItems_dynamicItemEmptyList = There are no items which are currently being displayed.
+
+HideItemsCannotMakeVisible_dialogTitle = Make Item Visible
+HideItemsCannotMakeVisible_unavailableCommandGroupText = ''{0}'' cannot be made visible because it is in the unavailable ''{1}'' action set.
+HideItemsCannotMakeVisible_unavailableCommandItemText = ''{0}'' command cannot be made visible in this dialog.
+HideItemsCannotMakeVisible_switchToCommandGroupTab = Would you like to switch to the Action Set Availability tab?
+HideItemsCannotMakeVisible_unavailableChildrenText = ''{0}'' cannot be made visible because all of its children are in unavailable action sets.
+
+HideMenuItems_menuItemsTab = Menu Visibility
+HideMenuItems_chooseMenuItemsLabel = Choose which menu items to display.
+HideMenuItems_menuStructure = &Menu Structure:
+
+HideToolBarItems_toolBarItemsTab = Tool Bar Visibility
+HideToolBarItems_chooseToolBarItemsLabel = Choose which tool bar items to display.
+HideToolBarItems_toolBarStructure = &Tool Bar Structure:
+
+SavePerspective_text = Save Perspective &As...
+SavePerspective_toolTip = Save Perspective As
+SavePerspective_shellTitle = Save Perspective As...
+SavePerspective_saveButtonLabel = &Save
+SavePerspectiveDialog_description = Enter or select a name to save the current\nperspective as.
+SavePerspective_name = &Name:
+SavePerspective_existing = &Existing Perspectives:
+SavePerspective_overwriteTitle = Overwrite Perspective
+SavePerspective_overwriteQuestion = A perspective with the name ''{0}'' already exists. Do you want to overwrite?
+SavePerspective_singletonQuestion = The current perspective can only be opened once and cannot be saved using a new name. Do you want to overwrite?
+SavePerspective_errorTitle = Cannot Save Perspective
+SavePerspective_errorMessage = Invalid Perspective Descriptor
+
+ResetPerspective_text = &Reset Perspective...
+ResetPerspective_toolTip = Reset Perspective
+ResetPerspective_message = Do you want to reset the current {0} perspective to its defaults?
+ResetPerspective_title = Reset Perspective
+RevertPerspective_note='Revert' removes the customization from the selected perspective.\nThis only applies to newly opened perspectives.
+
+RevertPerspective_title = Reset Perspective
+RevertPerspective_message = Do you want to reset the current {0} perspective to its saved state?
+RevertPerspective_option = &Also discard perspective's customization
+
+ClosePerspectiveAction_text = &Close Perspective
+ClosePerspectiveAction_toolTip = Close Perspective
+CloseAllPerspectivesAction_text = Close A&ll Perspectives
+CloseAllPerspectivesAction_toolTip = Close All Perspectives
+
+OpenInNewWindowAction_text = Open in &New Window
+OpenInNewWindowAction_toolTip = Open in New Window
+OpenInNewWindowAction_errorTitle = Problems Opening New Window
+CycleEditorAction_next_text = Next &Editor
+CycleEditorAction_next_toolTip = Next Editor
+CycleEditorAction_prev_text = P&revious Editor
+CycleEditorAction_prev_toolTip = Previous Editor
+CycleEditorAction_header=Editors
+CyclePartAction_next_text = Next &View
+CyclePartAction_next_toolTip = Next View
+CyclePartAction_prev_text = Previ&ous View
+CyclePartAction_prev_toolTip = Previous View
+CyclePartAction_header = Views
+CyclePartAction_editor = Editor
+CyclePerspectiveAction_next_text = Next &Perspective
+CyclePerspectiveAction_next_toolTip = Next Perspective
+CyclePerspectiveAction_prev_text = Previo&us Perspective
+CyclePerspectiveAction_prev_toolTip = Previous Perspective
+CyclePerspectiveAction_header=Perspectives
+ActivateEditorAction_text = &Activate Editor
+ActivateEditorAction_toolTip = Activate Editor
+MaximizePartAction_toolTip = Toggles Maximize/Restore State of Active View or Editor
+MinimizePartAction_toolTip = Minimizes the Active View or Editor
+# --- Filtered Table Base ---
+FilteredTableBase_Filter=Filter
+
+
+# --- Help Menu ---
+AboutAction_text = &About {0}
+AboutAction_toolTip = About {0}
+HelpContentsAction_text = &Help Contents
+HelpContentsAction_toolTip= Help Contents
+HelpSearchAction_text = S&earch
+HelpSearchAction_toolTip= Search Help
+DynamicHelpAction_text = &Show Contextual Help
+DynamicHelpAction_toolTip = Show Contextual Help
+AboutDialog_shellTitle = About {0}
+AboutDialog_defaultProductName =
+AboutDialog_DetailsButton=&Installation Details
+ProductInfoDialog_errorTitle = Problems Opening Link
+ProductInfoDialog_unableToOpenWebBrowser = Unable to open web browser on {0}
+PreferencesExportDialog_ErrorDialogTitle=Error
+AboutPluginsDialog_shellTitle = About {0} Plug-ins
+AboutPluginsDialog_pluginName = Plug-in Name
+AboutPluginsDialog_pluginId = Plug-in Id
+AboutPluginsDialog_version = Version
+AboutPluginsDialog_provider = Provider
+AboutPluginsDialog_signed = Signed
+AboutPluginsDialog_state_installed = Installed
+AboutPluginsDialog_state_resolved = Resolved
+AboutPluginsDialog_state_starting = Starting
+AboutPluginsDialog_state_stopping = Stopping
+AboutPluginsDialog_state_uninstalled = Uninstalled
+AboutPluginsDialog_state_active = Active
+AboutPluginsDialog_state_unknown = Unknown State
+AboutPluginsDialog_moreInfo = &Legal Info
+AboutPluginsDialog_signingInfo_show = &Show Signing Info
+AboutPluginsDialog_signingInfo_hide = &Hide Signing Info
+AboutPluginsDialog_columns = C&olumns...
+AboutPluginsDialog_errorTitle = Problems Opening File
+AboutPluginsDialog_unableToOpenFile = Unable to find file {0} in plug-in {1}.
+AboutPluginsDialog_filterTextMessage=type filter text
+AboutPluginsPage_Load_Bundle_Data=Loading Bundle Data...
+AboutFeaturesDialog_shellTitle = About {0} Features
+AboutFeaturesDialog_featureName = Feature Name
+AboutFeaturesDialog_featureId = Feature Id
+AboutFeaturesDialog_version = Version
+AboutFeaturesDialog_provider = Provider
+AboutFeaturesDialog_moreInfo = &License
+AboutFeaturesDialog_pluginsInfo = &Plug-in Details
+AboutFeaturesDialog_columns = C&olumns...
+AboutFeaturesDialog_noInformation = No further information is available for this feature.
+AboutFeaturesDialog_pluginInfoTitle = Feature Plug-ins
+AboutFeaturesDialog_pluginInfoMessage = Plug-ins contributed by feature: {0}
+AboutFeaturesDialog_noInfoTitle = No Further Information
+AboutFeaturesDialog_SimpleTitle=Features
+AboutSystemDialog_browseErrorLogName = &View Error Log
+AboutSystemDialog_copyToClipboardName = Copy &to Clipboard
+AboutSystemDialog_noLogTitle = Error Log Not Found
+AboutSystemDialog_noLogMessage = The error log was not found at {0}.  No errors have been reported in this workspace.
+AboutSystemPage_FetchJobTitle=Configuration Fetch Job
+AboutSystemPage_RetrievingSystemInfo=Retrieving system information...
+
+# --- Shortcutbar ---
+PerspectiveBarContributionItem_toolTip = {0} perspective
+PerspectiveBarNewContributionItem_toolTip = Open Perspective
+
+#--- Coolbar ---
+WorkbenchWindow_HelpToolbar = Help
+WorkbenchWindow_FileToolbar = File
+WorkbenchWindow_NavigateToolbar = Navigate
+WorkbenchWindow_searchCombo_toolTip = Enter help search expression and press Enter
+WorkbenchWindow_searchCombo_text = Search help
+
+
+WorkbenchWindow_close = &Close
+WorkbenchPage_ErrorCreatingPerspective = Unable to create perspective ''{0}''.  There is no corresponding perspective extension.
+
+SelectWorkingSetAction_text= Select &Working Set...
+SelectWorkingSetAction_toolTip= Select a working set
+EditWorkingSetAction_text= &Edit Active Working Set...
+EditWorkingSetAction_toolTip= Edit the active working set
+EditWorkingSetAction_error_nowizard_title= Edit Working Set
+EditWorkingSetAction_error_nowizard_message= Can not edit the active working set.
+ClearWorkingSetAction_text= Deselect Wor&king Set
+ClearWorkingSetAction_toolTip= Deselect the active working set
+WindowWorkingSets= &Window Working Sets
+NoWorkingSet = N&o Working Sets
+SelectedWorkingSets = Se&lected Working Sets
+NoApplicableWorkingSets = No applicable working sets
+
+# ==============================================================================
+# Drill Actions
+# ==============================================================================
+GoHome_text = Go &Home
+GoHome_toolTip = Home
+GoBack_text = Go &Back
+GoBack_toolTip = Back
+GoInto_text = Go &Into
+GoInto_toolTip = Go Into
+
+
+ICategory_other = Other
+ICategory_general = General
+
+# ==============================================================================
+# Wizards
+# ==============================================================================
+NewWizard_title = New
+NewWorkingSet=New Working Set
+NewWizardNewPage_description = The following resource creation wizards are available.
+NewWizardNewPage_wizardsLabel = &Wizards:
+NewWizardNewPage_showAll = &Show All Wizards.
+WizardList_description = The following wizards are available.
+Select = Select
+NewWizardSelectionPage_description = Select a wizard
+NewWizardShortcutAction_errorTitle = Problem Opening Wizard
+NewWizardShortcutAction_errorMessage = The selected wizard could not be started.
+
+NewWizardsRegistryReader_otherCategory = Other
+NewWizardDropDown_text = &New Wizards
+
+WizardHandler_menuLabel = {0}...
+WorkbenchWizard_errorMessage = The selected wizard could not be started.
+WorkbenchWizard_errorTitle = Problem Opening Wizard
+WizardTransferPage_selectAll = &Select All
+WizardTransferPage_deselectAll = &Deselect All
+TypesFiltering_title = Select Types
+TypesFiltering_message = Reduce selection to only files of &type(s):
+TypesFiltering_otherExtensions = &Other extensions:
+TypesFiltering_typeDelimiter = ,
+
+# --- Import/Export ---
+ImportExportPage_chooseImportWizard=Choose import wizard.
+ImportExportPage_chooseExportWizard=Choose export wizard.
+
+# --- Import ---
+ImportWizard_title = Import
+ImportWizard_selectWizard=&Select an import wizard:
+
+# --- Export ---
+ExportWizard_title = Export
+ExportWizard_selectWizard=&Select an export wizard:
+# --- New Project ---
+NewProject_title = New Project
+
+# ==============================================================================
+# Preference Pages
+# ==============================================================================
+PreferenceNode_errorMessage = Unable to create the selected preference page.
+PreferenceNode_NotFound = {0} not found
+Preference_note = Note:
+
+# --- Workbench ---
+WorkbenchPreference_showMultipleEditorTabsButton = Show &multiple editor tabs
+WorkbenchPreference_allowInplaceEditingButton = Allow in-place &system editors
+WorkbenchPreference_useIPersistableEditorButton = Restore &editor state on startup
+WorkbenchPreference_promptWhenStillOpenButton = Pr&ompt to save on close even if still open elsewhere
+WorkbenchPreference_stickyCycleButton = Keep &next/previous editor, view and perspectives dialog open
+WorkbenchPreference_RunInBackgroundButton=Always r&un in background
+WorkbenchPreference_RunInBackgroundToolTip=Run long operations in the background where possible
+WorkbenchPreference_HeapStatusButton = Sho&w heap status
+WorkbenchPreference_HeapStatusButtonToolTip = Show the heap status area on the bottom of the window
+
+
+# --- Appearance ---
+ViewsPreferencePage_Theme=&Theme:
+ViewsPreference_currentTheme = &Color and Font theme:
+ViewsPreference_currentThemeDescription = Descr&iption:
+ViewsPreference_currentThemeFormat = {0} (current)
+ViewsPreference_enableAnimations = &Enable animations
+ViewsPreference_useColoredLabels = &Use mixed fonts and colors for labels
+ViewsPreference_visibleTabs_description = Visible tabs on overflow:
+ViewsPreference_enableMRU = Show &most recently used tabs
+ToggleFullScreenMode_ActivationPopup_Description=You have gone full screen. Use the Toggle Full Screen command ({0}) to deactivate.
+ToggleFullScreenMode_ActivationPopup_Description_NoKeybinding=You have gone full screen. Use the Toggle Full Screen command to deactivate.
+ToggleFullScreenMode_ActivationPopup_DoNotShowAgain=Do not show again
+# --- File Editors ---
+FileEditorPreference_fileTypes = File &types:
+FileEditorPreference_add = &Add...
+FileEditorPreference_remove = &Remove
+FileEditorPreference_associatedEditors = Associated &editors:
+FileEditorPreference_addEditor = A&dd...
+FileEditorPreference_removeEditor = Re&move
+FileEditorPreference_default = De&fault
+FileEditorPreference_existsTitle = File Type Exists
+FileEditorPreference_existsMessage = An entry already exists for that file type
+FileEditorPreference_defaultLabel = (default)
+FileEditorPreference_contentTypesRelatedLink = See <a>''{0}''</a> for content-type based file associations.
+FileEditorPreference_isLocked = {0} (locked by ''{1}'' content type)
+
+FileExtension_extensionEmptyMessage = The file extension cannot be empty
+FileExtension_fileNameInvalidMessage = The file name cannot include the wild card character (*) in the current location
+FilteredPreferenceDialog_Key_Scrolling=Key &Scrolling
+FilteredPreferenceDialog_PreferenceSaveFailed=Preferences save failed.
+FilteredPreferenceDialog_Resize = &Resize tree
+FilteredPreferenceDialog_FilterToolTip = Additional Dialog Actions
+
+FileExtension_fileTypeMessage =  Enter file type to add: (*.doc or report.doc for example)
+FileExtension_fileTypeLabel = File &type:
+FileExtension_shellTitle = Add File Type
+FileExtension_dialogTitle = Define a New File Type
+
+Choose_the_editor_for_file = Choose the editor for files of type ({0})
+EditorSelection_chooseAnEditor = Choose an editor:
+EditorSelection_internal = &Internal editors
+EditorSelection_external = &External programs
+EditorSelection_rememberEditor = &Use this editor for all ''{0}'' files
+EditorSelection_rememberType = Use it for &all ''*.{0}'' files
+EditorSelection_browse = &Browse...
+EditorSelection_title = Editor Selection
+
+# --- Perspectives ---
+OpenPerspectiveMode_optionsTitle = Open a new perspective
+OpenPerspectiveMode_sameWindow = In the &same window
+OpenPerspectiveMode_newWindow = In a &new window
+
+PerspectivesPreference_MakeDefault = Ma&ke Default
+PerspectivesPreference_MakeDefaultTip = Make the Current Selection the Default Perspective
+PerspectivesPreference_Reset = &Revert
+PerspectivesPreference_ResetTip = Reverts the Current Selection to its Original Value
+PerspectivesPreference_Delete = D&elete
+PerspectivesPreference_DeleteTip = Delete a User Defined Perspective
+PerspectivesPreference_available = Available &perspectives:
+PerspectivesPreference_defaultLabel = {0} (default)
+PerspectivesPreference_perspectiveopen_title=Delete Perspective
+PerspectivesPreference_perspectiveopen_message=Are you sure you want to delete the ''{0}'' perspective? It has open instances.
+
+PerspectiveLabelProvider_unknown = Unknown Element Type
+
+OpenPerspectiveDialogAction_text=&Open Perspective...
+OpenPerspectiveDialogAction_tooltip=Open Perspective
+
+#---- General Preferences----
+PreferencePage_noDescription = (No description available)
+PreferencePageParameterValues_pageLabelSeparator = \ >\ 
+ThemeChangeWarningText = A restart may be required for the theme change to take full effect.
+ThemingEnabled = E&nable theming (requires restart)
+# --- Workbench -----
+WorkbenchPreference_openMode=Open mode
+WorkbenchPreference_doubleClick=D&ouble click
+WorkbenchPreference_singleClick=&Single click
+WorkbenchPreference_singleClick_SelectOnHover=Select on &hover
+WorkbenchPreference_singleClick_OpenAfterDelay=Open when using arrow &keys
+WorkbenchPreference_noEffectOnAllViews=This preference may not take effect on all views
+
+# --- Globalization -----
+GlobalizationPreference_nlExtensions=&Unicode locale extensions:
+GlobalizationPreference_layoutDirection=&Graphical layout direction:
+GlobalizationPreference_bidiSupport=&Enable bidirectional support
+GlobalizationPreference_textDirection=&Text direction:
+GlobalizationPreference_defaultDirection=OS Default
+GlobalizationPreference_ltrDirection=Left to right
+GlobalizationPreference_autoDirection=Contextual
+GlobalizationPreference_rtlDirection=Right to left
+GlobalizationPreference_restartWidget=A restart is required for these preferences to take full effect.
+
+# --- Fonts ---
+FontsPreference_useSystemFont=&Use System Font
+
+# --- Decorators ---
+DecoratorsPreferencePage_description = Descriptio&n:
+DecoratorsPreferencePage_decoratorsLabel = Available &label decorations:
+DecoratorsPreferencePage_explanation = Label decorations show extra information about an item on its label or icon.\nSelect which additional decorations should be displayed.
+DecoratorError = Exception in Decorator.
+DecoratorWillBeDisabled = Exception in Decorator. The ''{0}'' decorator will be disabled.
+
+# --- Startup preferences ---
+StartupPreferencePage_label=&Plug-ins activated on startup:
+
+# ==============================================================================
+# Property Pages
+# ==============================================================================
+PropertyDialog_text = P&roperties
+PropertyDialog_toolTip = Open Properties Dialog
+PropertyDialog_messageTitle = Property Pages
+PropertyDialog_noPropertyMessage = No property pages for {0}.
+PropertyDialog_propertyMessage = Properties for {0}
+PropertyPageNode_errorMessage = Unable to create the selected property page.
+
+SystemInPlaceDescription_name = &In-Place Editor
+SystemEditorDescription_name = &System Editor
+
+# ==============================================================================
+# Dialogs
+# ==============================================================================
+Error = Error
+Information = Information
+InstallationDialog_ShellTitle={0} Installation Details
+
+Workbench_NeedsClose_Title = Restart Needed
+Workbench_NeedsClose_Message = A required plug-in is no longer available and the Workbench needs to be restarted. You will be prompted to save if there is any unsaved work.
+
+ErrorPreferencePage_errorMessage = An error has occurred when creating this preference page.
+
+ListSelection_title = Selection Needed
+ListSelection_message = Select the items:
+
+SelectionDialog_selectLabel = &Select All
+SelectionDialog_deselectLabel = &Deselect All
+
+ElementTreeSelectionDialog_nothing_available=No entries available.
+
+CheckedTreeSelectionDialog_nothing_available=No entries available.
+CheckedTreeSelectionDialog_select_all=Select &All
+CheckedTreeSelectionDialog_deselect_all=&Deselect All
+
+# ==============================================================================
+# Editor Framework
+# ==============================================================================
+EditorManager_saveResourcesMessage = Select the &resources to save:
+EditorManager_saveResourcesOptionallyMessage = The following resources have been modified, but are still open elsewhere with identical changes. Closing will not lose those changes. Select the &resources to save now anyway:
+EditorManager_saveResourcesTitle = Save Resources
+
+# The parameter {0} stands for the status message
+
+EditorManager_systemEditorError = System editor can only open file base resources.
+EditorManager_siteIncorrect = Editor initialization failed: {0}.  Site is incorrect.
+EditorManager_unknownEditorIDMessage = Unable to open editor, unknown editor ID: ''{0}''
+EditorManager_errorOpeningExternalEditor = Unable to open external editor {0} ({1}).
+EditorManager_operationFailed = {0} Failed
+EditorManager_saveChangesQuestion = ''{0}'' has been modified. Save changes?
+EditorManager_saveChangesOptionallyQuestion = ''{0}'' has been modified, but is still open elsewhere with identical changes. Closing this will not lose those changes. Would you like to save now anyway?
+EditorManager_closeWithoutPromptingOption = Do not prompt to save on close when still open elsewhere
+EditorManager_no_in_place_support=Unable to restore in-place editor. In-place support is missing.
+EditorManager_no_input_factory_ID=No input factory ID found for editor id={0} name={1}
+EditorManager_bad_element_factory=Cannot instantiate input element factory {0} for editor id={1} name={2}
+EditorManager_openNewEditorLabel=&Open New Editor
+EditorManager_no_persisted_state=No saved state can be found for editor id={0} name={1}
+EditorManager_reuseEditorDialogTitle=Close Editor Automatically
+EditorManager_wrong_createElement_result=Factory {0} returned a result from createElement that is not an IEditorInput for editor id={1} name={2}
+EditorManager_create_element_returned_null=Factory {0} returned null from createElement for editor id={1} name={2}
+EditorManager_missing_editor_descriptor=No editor descriptor for id {0}
+EditorManager_backgroundSaveJobName=Saving {0}
+EditorManager_largeDocumentWarning= The document you are trying to open is large. This may affect the stability of the application. Opening with an external program is recommended.
+
+ExternalEditor_errorMessage = Error opening external editor ({0}).
+Save = Save
+Save_Resource = Save Resource
+Saving_Modifications = Saving modifications
+Save_All = Save All
+Dont_Save = Don't Save
+
+SaveableHelper_Save = &Save
+SaveableHelper_Cancel = Cancel
+SaveableHelper_Dont_Save = Do&n't Save
+
+# ==============================================================================
+# Perspective Framework
+# ==============================================================================
+OpenNewPageMenu_dialogTitle = Problems Opening Page
+OpenNewPageMenu_unknownPageInput = Unknown Page Input
+
+OpenNewWindowMenu_dialogTitle = Problems Opening Window
+OpenNewWindowMenu_unknownInput = Unknown Window Input
+
+OpenPerspectiveMenu_pageProblemsTitle = Problems Opening Perspective
+OpenPerspectiveMenu_errorUnknownInput = Unknown Perspective Input
+
+Perspective_localCopyLabel = <{0}>
+WorkbenchPage_problemRestoringTitle = Restoring Problems
+
+# ==============================================================================
+# Views Framework
+# ==============================================================================
+ViewLabel_unknown = Unknown
+
+# The parameter {0} stands for the status message
+ViewFactory_initException = Could not create the view: {0}
+ViewFactory_siteException = View initialization failed: {0}.  Site is incorrect.
+
+# The parameter {0} stands for the view ID
+ViewFactory_couldNotCreate = Could not create view: {0}
+
+# ==============================================================================
+# Workbench
+# ==============================================================================
+WorkbenchPage_UnknownLabel = <Unknown Label>
+
+# These four keys are marked as unused by the NLS search, but they are indirectly used
+# and should be removed.
+
+PartPane_sizeLeft=&Left
+PartPane_sizeRight=&Right
+PartPane_sizeTop=&Top
+PartPane_sizeBottom=&Bottom
+
+PluginAction_operationNotAvailableMessage = The chosen operation is not currently available.
+PluginAction_disabledMessage = The chosen operation is not enabled.
+ActionDescriptor_invalidLabel = Unknown Label
+
+XMLMemento_parserConfigError = Internal XML parser configuration error.
+XMLMemento_ioError = Could not read content of XML file.
+XMLMemento_formatError = Could not parse content of XML file.
+XMLMemento_noElement = Could not find root element node of XML file.
+
+StatusUtil_errorOccurred = An unexpected exception was thrown.
+
+# --- Workbench Errors/Problems ---
+WorkbenchWindow_exceptionMessage = Abnormal Workbench Condition
+WorkbenchPage_AbnormalWorkbenchCondition = Abnormal Workbench Condition
+WorkbenchPage_IllegalSecondaryId = Illegal secondary id (cannot be empty or contain a colon)
+WorkbenchPage_IllegalViewMode = Illegal view mode
+WorkbenchPart_AutoTitleFormat={0} ({1})
+AbstractWorkingSetManager_updatersActivating=Activating working set updaters for bundle {0}
+
+DecoratorManager_ErrorActivatingDecorator = An error has occurred activating decorator {0}.
+
+EditorRegistry_errorTitle = Load Problem
+EditorRegistry_errorMessage = Unable to load editor associations.
+
+ErrorClosing = An error has occurred when closing the workbench. See error log for more details.
+ErrorClosingNoArg = An error has occurred. See error log for more details. Do you want to exit?
+ErrorClosingOneArg = An error has occurred: {0}. See error log for more details. Do you want to exit?
+ErrorLogUtil_ShowErrorLogHyperlink=<a>Show Error Log</a>
+ErrorLogUtil_ShowErrorLogTooltip=Show the Error Log View
+SavingProblem = Saving Problems
+
+Problems_Opening_Page = Problems Opening Page
+
+Startup_Loading=Loading {0}
+Startup_Loading_Workbench=Loading Workbench
+Startup_Done=Done
+
+Workbench_problemsSavingMsg=Could not save workbench layout.
+Workbench_problemsRestoring=Problems occurred restoring workbench.
+Workbench_problemsSaving=Problems occurred saving workbench.
+
+PageLayout_missingRefPart=Referenced part does not exist yet: {0}.
+
+
+# ==============================================================================
+# Keys used in the reuse editor which is released as experimental.
+# ==============================================================================
+PinEditorAction_toolTip=Pin Editor
+WorkbenchPreference_reuseEditors=&Close editors automatically
+WorkbenchPreference_reuseEditorsThreshold=Number of opened editors before closi&ng:
+WorkbenchPreference_reuseEditorsThresholdError=The number of opened editors should be more than 0.
+WorkbenchPreference_recentFiles=Size of &recently opened files list:
+WorkbenchPreference_recentFilesError=The size of the recently opened files list should be between 0 and {0}.
+WorkbenchPreference_workbenchSaveInterval=Workbench save &interval (in minutes):
+WorkbenchPreference_workbenchSaveIntervalError=The workbench save interval should be an integer between 0 and {0}.
+WorkbenchEditorsAction_label=S&witch to Editor...
+WorkbookEditorsAction_label=&Quick Switch Editor
+
+WorkbenchEditorsDialog_title=Switch to Editor
+WorkbenchEditorsDialog_label=Select an &editor to switch to:
+WorkbenchEditorsDialog_closeSelected=&Close Selected Editors
+WorkbenchEditorsDialog_saveSelected=&Save Selected Editors
+WorkbenchEditorsDialog_selectClean=Se&lect Clean Editors
+WorkbenchEditorsDialog_invertSelection=&Invert Selection
+WorkbenchEditorsDialog_allSelection=Select &All
+WorkbenchEditorsDialog_showAllPersp=Show editors from all &windows
+WorkbenchEditorsDialog_name=Name
+WorkbenchEditorsDialog_path=Path
+WorkbenchEditorsDialog_activate=Ac&tivate Selected Editor
+WorkbenchEditorsDialog_close=Close
+
+ShowPartPaneMenuAction_text=Show &System Menu
+ShowPartPaneMenuAction_toolTip=Show System Menu
+ShowViewMenuAction_text=Show View &Menu
+ShowViewMenuAction_toolTip=Show View Menu
+QuickAccessAction_text=&Quick Access
+QuickAccessAction_toolTip=Quick Access
+
+ToggleCoolbarVisibilityAction_show_text = Show &Toolbar
+ToggleCoolbarVisibilityAction_hide_text = Hide &Toolbar
+ToggleStatusBarVisibilityAction_show_text = Show &Status Bar
+ToggleStatusBarVisibilityAction_hide_text = Hide &Status Bar
+ToggleCoolbarVisibilityAction_toolTip = Toggle the visibility of the window toolbar and perspective switcher
+# ==============================================================================
+# Working Set Framework.
+# ==============================================================================
+ProblemSavingWorkingSetState_message = Unable to store working set state.
+ProblemSavingWorkingSetState_title = Saving Problems
+ProblemRestoringWorkingSetState_message = Unable to restore working set state.
+ProblemRestoringWorkingSetState_title = Restoring Problems
+ProblemCyclicDependency = Removed cyclic dependency in the working set ''{0}''.
+
+WorkingSetEditWizard_title=Edit Working Set
+WorkingSetNewWizard_title=New Working Set
+
+WorkingSetTypePage_description=Select a working set type
+WorkingSetTypePage_typesLabel=&Working set type:
+
+WorkingSetSelectionDialog_title= Select Working Set
+WorkingSetSelectionDialog_title_multiSelect= Select Working Sets
+WorkingSetSelectionDialog_message= Selec&t a working set:
+WorkingSetSelectionDialog_message_multiSelect= &Select working sets:
+WorkingSetSelectionDialog_detailsButton_label= &Edit...
+WorkingSetSelectionDialog_newButton_label= &New...
+WorkingSetSelectionDialog_removeButton_label= &Remove
+
+WorkbenchPage_workingSet_default_label=Window Working Set
+WorkbenchPage_workingSet_multi_label=Multiple Working Sets
+
+# =================================================================
+# System Summary
+# =================================================================
+SystemSummary_timeStamp= *** Date: {0}
+SystemSummary_systemProperties= *** System properties:
+SystemSummary_features= *** Features:
+SystemSummary_pluginRegistry= *** Plug-in Registry:
+SystemSummary_userPreferences= *** User Preferences:
+SystemSummary_sectionTitle = *** {0}:
+SystemSummary_sectionError = Could not write section, see error log.
+
+# parameter 0 is the feature name, parameter 1 is the version and parameter 2 is the Id
+SystemSummary_featureVersion= {0} ({1}) "{2}"
+
+# parameter 0 is the description name, parameter 1 is the version and parameter 2 is the Id
+SystemSummary_descriptorIdVersionState= {0} ({1}) "{2}" [{3}]
+
+# =================================================================
+# Editor List
+# =================================================================
+DecorationScheduler_UpdateJobName=Update for Decoration Completion
+DecorationScheduler_CalculationJobName=Decoration Calculation
+DecorationScheduler_UpdatingTask=Updating
+DecorationScheduler_CalculatingTask=Calculating Decorations
+DecorationScheduler_ClearResultsJob=Clear Results
+DecorationScheduler_DecoratingSubtask=Decorating {0}
+
+PerspectiveBar_showText=Show &Text
+PerspectiveBar_customize=Customi&ze...
+PerspectiveBar_saveAs= Save &As...
+PerspectiveBar_reset= &Reset
+
+WorkbenchPlugin_extension=Cannot create extension
+
+EventLoopProgressMonitor_OpenDialogJobName=Open Blocked Dialog
+DecorationReference_EmptyReference=Decorating
+RectangleAnimation_Animating_Rectangle=Animating rectangle
+FilteredList_UpdateJobName=Table Update
+FilteredTree_ClearToolTip=Clear
+FilteredTree_FilterMessage=type filter text
+FilteredTree_FilteredDialogTitle={0} (Filtered)
+FilteredTree_AccessibleListenerClearButton=Clear filter field
+FilteredTree_AccessibleListenerFiltered={0} {1} matches.
+Workbench_startingPlugins = Starting plug-ins
+ScopedPreferenceStore_DefaultAddedError=Do not add the default to the search contexts
+
+WorkbenchEncoding_invalidCharset = {0} is not a valid charset.
+
+#==============================================================
+# Undo/Redo Support
+
+################################################################################
+#Operations_undoCommand and Operations_redoCommand are
+#used to concatenate the Undo or Redo command with a specific
+#operation name such as Delete Resources, Typing, Add Bookmark, etc.
+#to result in a string such as "Undo Typing".
+#The commmand should include the mnemonic character somewhere in the
+#string.  {0} represents the operation to be undone or redone
+################################################################################
+Operations_undoCommand=&Undo {0}
+Operations_redoCommand=&Redo {0}
+
+################################################################################
+#Operations_undoTooltipCommand and Operations_redoTooltipCommand are
+#used to concatenate the Undo or Redo command with a specific
+#operation name such as Delete Resources, Typing, Add Bookmark, etc.
+#to result in a string such as "Undo Typing".
+#The commmand should NOT include the mnemonic character.
+################################################################################
+Operations_undoTooltipCommand=Undo {0}
+Operations_redoTooltipCommand=Redo {0}
+
+################################################################################
+#Operations_undoRedoCommandDisabled is used when no undo or redo
+#operation is available.  {0} represents "Undo" or "Redo"
+################################################################################
+Operations_undoRedoCommandDisabled=Can''t {0}
+
+Operations_undoProblem=Undo Problem
+Operations_redoProblem=Redo Problem
+Operations_executeProblem=Problem Executing Operation
+Operations_undoInfo=Undo Information
+Operations_redoInfo=Redo Information
+Operations_executeInfo=Operation Information
+Operations_undoWarning=Undo Warning
+Operations_redoWarning=Redo Warning
+Operations_executeWarning=Operation Warning
+Operations_linearUndoViolation=There have been local changes in ''{0}'' since ''{1}'' was performed.  These changes must be undone before proceeding.  Proceed anyway?
+Operations_linearRedoViolation=Local changes in ''{0}'' have been undone since ''{1}'' was undone.  They must be redone before proceeding.  Continue with redoing ''{1}''?
+Operations_nonLocalUndoWarning=Undoing ''{0}'' affects elements outside of ''{1}''.  Continue with undoing ''{0}''?
+Operations_nonLocalRedoWarning=Redoing ''{0}'' affects elements outside of ''{1}''.  Continue with redoing ''{0}''?
+Operations_discardUndo=&Discard Undo
+Operations_discardRedo=&Discard Redo
+Operations_proceedWithNonOKUndoStatus={0}\nProceed with undoing ''{1}'' anyway?
+Operations_proceedWithNonOKRedoStatus={0}\nProceed with redoing ''{1}'' anyway?
+Operations_proceedWithNonOKExecuteStatus={0}\nProceed with executing ''{1}'' anyway?
+Operations_stoppedOnUndoErrorStatus=''{1}'' cannot be undone.  \nReason: {0}
+Operations_stoppedOnRedoErrorStatus=''{1}'' cannot be redone.  \nReason: {0}
+Operations_stoppedOnExecuteErrorStatus=''{1}'' cannot be performed.  \nReason: {0}
+#==============================================================
+# Heap Status
+
+
+HeapStatus_status={0} of {1}
+HeapStatus_widthStr=MMMMMMMMMMMM
+HeapStatus_memoryToolTip= Heap size: {0} of total: {1} max: {2} mark: {3}
+HeapStatus_meg= {0}M
+HeapStatus_maxUnknown= <unknown>
+HeapStatus_noMark= <none>
+HeapStatus_buttonToolTip= Run Garbage Collector
+SetMarkAction_text=&Set Mark
+ClearMarkAction_text=&Clear Mark
+ShowMaxAction_text=Show &Max Heap
+SplitValues_Horizontal=Horizontal
+SplitValues_Vertical=Vertical
+#ShowKyrsoftViewAction_text=Show &Kyrsoft Memory Monitor View
+#ShowKyrsoftViewAction_KyrsoftNotInstalled=The Kyrsoft Memory Monitor plug-in is not installed.\n\
+#  For more info, visit:\n\
+#  http://www.kyrsoft.com/opentools/memmon.html\n\
+#  http://eclipse-plugins.2y.net/eclipse/plugin_details.jsp?id=205
+#ShowKyrsoftViewAction_OpenPerspectiveFirst=Please open a perspective first.
+#ShowKyrsoftViewAction_ErrorShowingKyrsoftView=Error showing Kyrsoft Memory Monitor view.
+
+#==============================================================
+# Content Types
+ContentTypes_lockedFormat = {0} (locked)
+ContentTypes_characterSetLabel = Default &encoding:
+ContentTypes_characterSetUpdateLabel = &Update
+ContentTypes_unsupportedEncoding = The selected encoding is not supported.
+ContentTypes_fileAssociationsLabel = &File associations:
+ContentTypes_fileAssociationsAddLabel = &Add...
+ContentTypes_fileAssociationsEditLabel = E&dit...
+ContentTypes_fileAssociationsRemoveLabel = &Remove
+ContentTypes_contentTypesLabel = &Content types:
+ContentTypes_errorDialogMessage = There was an error removing content type file association(s).
+ContentTypes_FileEditorsRelatedLink=See <a>''{0}''</a> for associating editors with file types.
+ContentTypes_addDialog_title=Add Content Type Association
+ContentTypes_addDialog_messageHeader=Define New Content Type Association
+ContentTypes_addDialog_message=Enter content type association to add: (*.doc or report.doc for example)
+ContentTypes_addDialog_label=&Content type:
+
+ContentTypes_editDialog_title=Edit Content Type Association
+ContentTypes_editDialog_messageHeader=Edit Content Type Association
+ContentTypes_editDialog_message=Edit content type association: (*.doc or report.doc for example)
+ContentTypes_editDialog_label=Co&ntent type:
+ContentTypes_addRootContentTypeButton=Add Roo&t...
+ContentTypes_addChildContentTypeButton=Add C&hild...
+ContentTypes_removeContentTypeButton=Re&move
+ContentTypes_newContentTypeDialog_title=Create a new content-type
+ContentTypes_newContentTypeDialog_descritption=Set initial attributes of a new content-type
+ContentTypes_newContentTypeDialog_nameLabel=&Name:
+ContentTypes_newContentTypeDialog_defaultNameNoParent=Custom Content-Type
+ContentTypes_newContentTypeDialog_defaultNameWithParent=Custom Sub-type of {0}
+ContentTypes_newContentTypeDialog_invalidContentTypeName=Invalid name for a content-type
+ContentTypes_failedAtEditingContentTypes=Couldn't edit content-type registry
+
+# =========================================================================
+# Deprecated actions support
+# =========================================================================
+CommandService_AutogeneratedCategoryName = Uncategorized
+CommandService_AutogeneratedCategoryDescription = Commands that were either auto-generated or have no category
+LegacyActionPersistence_AutogeneratedCommandName = Legacy Action With No Label
+
+Edit=&Edit...
+
+#==============================================================
+# Trim Common UI
+
+# Menu strings
+TrimCommon_DockOn=&Dock On
+TrimCommon_Left=&Left
+TrimCommon_Right=&Right
+TrimCommon_Bottom=&Bottom
+TrimCommon_Top=&Top
+TrimCommon_Close=&Close
+
+# Trim Display Names
+TrimCommon_Progress_TrimName=&Progress
+
+# FilteredItemsSelectionDialog
+FilteredItemsSelectionDialog_menu = Menu
+FilteredItemsSelectionDialog_refreshJob = Dialog refresh
+FilteredItemsSelectionDialog_progressRefreshJob = Progress message refresh
+FilteredItemsSelectionDialog_cacheRefreshJob = Cache refresh
+FilteredItemsSelectionDialog_cacheRefreshJob_checkDuplicates = Checking for duplicates
+FilteredItemsSelectionDialog_cacheRefreshJob_getFilteredElements = Get filtered elements
+FilteredItemsSelectionDialog_cacheSearchJob_taskName = Searching in cache
+FilteredItemsSelectionDialog_patternLabel = &Select an item to open (? = any character, * = any string):
+FilteredItemsSelectionDialog_listLabel = &Matching items:
+FilteredItemsSelectionDialog_searchJob_taskName = Searching
+FilteredItemsSelectionDialog_toggleStatusAction = &Show Status Line
+FilteredItemsSelectionDialog_removeItemsFromHistoryAction = &Remove from History
+FilteredItemsSelectionDialog_separatorLabel = Workspace matches
+FilteredItemsSelectionDialog_nItemsSelected = {0} items selected
+
+FilteredItemsSelectionDialog_jobLabel=Items filtering
+FilteredItemsSelectionDialog_jobError=Items filtering failed
+
+FilteredItemsSelectionDialog_storeError=Storing the dialog failed
+FilteredItemsSelectionDialog_restoreError=Restoring the dialog failed
+
+FilteredItemsSelectionDialog_taskProgressMessage={0} ({1}%)
+FilteredItemsSelectionDialog_subtaskProgressMessage={0}: {1}
+
+#==============================================================
+# Content Assist
+
+# Content Assist cue strings
+ContentAssist_Cue_Description_Key=Content Assist Available ({0})
+
+#===============================================================
+WorkbenchLayoutSettings_Name=Workbench Layout;
+WorkbenchSettings_CouldNotCreateDirectories = Could not create workspace directories
+WorkbenchSettings_CouldNotFindLocation=Could not find workbench settings location
+WorkingSets_Name=Working Sets
+WorkingSets_CannotSave=Cannot save working sets
+WorkbenchPreferences_Name=Preferences
+BundleSigningTray_Signing_Date=Signing Date:
+BundleSigningTray_Working=Working...
+BundleSigningTray_Signing_Certificate=Signing Certificate:
+BundleSigningTray_Cant_Find_Service=Could not find certificate service.
+BundleSigningTray_Determine_Signer_For=Determine Signer for {0}
+BundleSigningTray_Unsigned=Unsigned
+BundleSigningTray_Unknown=Unknown
+BundleSigningTray_Unget_Signing_Service=Return Signing Service
+
+# StatusDialog
+WorkbenchStatusDialog_SupportTooltip=Get Support
+WorkbenchStatusDialog_SupportHyperlink=<a>Get Support</a>
+WorkbenchStatusDialog_StatusWithChildren=This status has children statuses. See 'Details' for more information.
+WorkbenchStatusDialog_SeeDetails=See 'Details' for more information.
+WorkbenchStatusDialog_MultipleProblemsHaveOccured=Multiple problems have occurred
+WorkbenchStatusDialog_ProblemOccurred=A problem has occurred.
+WorkbenchStatusDialog_ProblemOccurredInJob=''{0}'' has encountered a problem.
+StackTraceSupportArea_CausedBy=Caused by:
+StackTraceSupportArea_NoStackTrace=No stack trace found
+StackTraceSupportArea_Title=Stacktrace:
+
+# WorkingSetConfigurationBlock
+WorkingSetConfigurationBlock_WorkingSetText_name=W&orking sets:
+WorkingSetConfigurationBlock_SelectWorkingSet_button=S&elect...
+WorkingSetConfigurationBlock_NewWorkingSet_button=Ne&w...
+
+WorkingSetPropertyPage_ReadOnlyWorkingSet_description=This is a read-only working set. Its content can not be changed.
+WorkingSetPropertyPage_ReadOnlyWorkingSet_title=Read-only Working Set
+
+WorkingSetGroup_EnableWorkingSet_button=Add projec&t to working sets
+WorkingSetGroup_WorkingSetSelection_message=The new project will be added to the selected working sets:
+WorkingSetGroup_WorkingSets_group=Working sets
+
+FilteredTableBaseHandler_Close=&Close
+
+# ==============================================================================
+# Util
+# ==============================================================================
+Util_List={0}, {1}
+Util_listNull=null
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/misc/Policy.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/misc/Policy.java
new file mode 100644
index 0000000..113c632
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/misc/Policy.java
@@ -0,0 +1,203 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.misc;
+
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.swt.graphics.Device;
+import org.eclipse.ui.ISourceProvider;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * A common facility for parsing the <code>org.eclipse.ui/.options</code>
+ * file.
+ *
+ * @since 2.1
+ */
+public class Policy {
+    public static boolean DEFAULT = false;
+
+    public static boolean DEBUG_SWT_GRAPHICS = DEFAULT;
+
+    public static boolean DEBUG_SWT_DEBUG = DEFAULT;
+
+    public static boolean DEBUG_SWT_DEBUG_GLOBAL = DEFAULT;
+
+    public static boolean DEBUG_DRAG_DROP = DEFAULT;
+
+    /**
+     * Flag to log stale jobs
+     */
+    public static boolean DEBUG_STALE_JOBS = DEFAULT;
+
+    /**
+	 * Whether to report all events entering through the common event framework
+	 * used by the commands architecture.
+	 *
+	 * @see ISourceProvider
+	 * @since 3.2
+	 */
+    public static boolean DEBUG_SOURCES = DEFAULT;
+
+    /**
+     * Whether to print information about key bindings that are successfully
+     * recognized within the system (as the keys are pressed).
+     */
+    public static boolean DEBUG_KEY_BINDINGS = DEFAULT;
+
+    /**
+     * Whether to print information about every key seen by the system.
+     */
+    public static boolean DEBUG_KEY_BINDINGS_VERBOSE = DEFAULT;
+
+    /**
+     * Whether to print extra information about error conditions dealing with
+     * cool bars in the workbench, and their disposal.
+     */
+    public static boolean DEBUG_TOOLBAR_DISPOSAL = DEFAULT;
+
+    /**
+     * Whether to print debugging information about the execution of commands
+     */
+    public static boolean DEBUG_COMMANDS = DEFAULT;
+
+    /**
+     * Whether to print debugging information about the internal state of the
+     * context support within the workbench.
+     */
+    public static boolean DEBUG_CONTEXTS = DEFAULT;
+
+    /**
+     * Whether to print debugging information about the performance of context
+     * computations.
+     */
+    public static boolean DEBUG_CONTEXTS_PERFORMANCE = DEFAULT;
+
+    /**
+     * Whether to print even more debugging information about the internal state
+     * of the context support within the workbench.
+     */
+    public static boolean DEBUG_CONTEXTS_VERBOSE = DEFAULT;
+
+    /**
+     * Whether to print debugging information about the internal state of the
+     * command support (in relation to handlers) within the workbench.
+     */
+    public static boolean DEBUG_HANDLERS = DEFAULT;
+
+    /**
+     * Whether to print debugging information about the performance of handler
+     * computations.
+     */
+    public static boolean DEBUG_HANDLERS_PERFORMANCE = DEFAULT;
+
+    /**
+     * Whether to print out verbose information about changing handlers in the
+     * workbench.
+     */
+    public static boolean DEBUG_HANDLERS_VERBOSE = DEFAULT;
+
+    /**
+     * Whether to print debugging information about unexpected occurrences and
+     * important state changes in the operation history.
+     */
+    public static boolean DEBUG_OPERATIONS = DEFAULT;
+
+    /**
+     * Whether to print out verbose information about the operation histories,
+     * including all notifications sent.
+     */
+    public static boolean DEBUG_OPERATIONS_VERBOSE = DEFAULT;
+
+
+    /**
+     * Whether or not to show system jobs at all times.
+     */
+    public static boolean DEBUG_SHOW_ALL_JOBS = DEFAULT;
+
+    /**
+     * Whether or not to resolve images as they are declared.
+     *
+     * @since 3.1
+     */
+    public static boolean DEBUG_DECLARED_IMAGES = DEFAULT;
+
+    /**
+     * Whether or not to print contribution-related issues.
+     *
+     * @since 3.1
+     */
+    public static boolean DEBUG_CONTRIBUTIONS = DEFAULT;
+
+    /**
+     * Which command identifier to print handler information for.  This
+     * restricts the debugging output, so a developer can focus on one command
+     * at a time.
+     */
+    public static String DEBUG_HANDLERS_VERBOSE_COMMAND_ID = null;
+
+    /**
+     * Whether experimental features in the rendering of commands into menus
+     * and toolbars should be enabled.  This is not guaranteed to provide a
+     * working workbench.
+     */
+    public static boolean EXPERIMENTAL_MENU = DEFAULT;
+
+    public static boolean DEBUG_MPE = DEFAULT;
+
+    /**
+     * Whether or not additional working set logging will occur.
+     *
+     * @since 3.4
+     */
+    public static boolean DEBUG_WORKING_SETS = DEFAULT;
+
+    static {
+        if (getDebugOption("/debug")) { //$NON-NLS-1$
+            DEBUG_SWT_GRAPHICS = getDebugOption("/trace/graphics"); //$NON-NLS-1$
+            DEBUG_SWT_DEBUG = getDebugOption("/debug/swtdebug"); //$NON-NLS-1$
+            DEBUG_SWT_DEBUG_GLOBAL = getDebugOption("/debug/swtdebugglobal"); //$NON-NLS-1$
+            DEBUG_DRAG_DROP = getDebugOption("/trace/dragDrop"); //$NON-NLS-1$
+            DEBUG_SOURCES = getDebugOption("/trace/sources"); //$NON-NLS-1$
+            DEBUG_KEY_BINDINGS = getDebugOption("/trace/keyBindings"); //$NON-NLS-1$
+            DEBUG_KEY_BINDINGS_VERBOSE = getDebugOption("/trace/keyBindings.verbose"); //$NON-NLS-1$
+            DEBUG_TOOLBAR_DISPOSAL = "true".equalsIgnoreCase(Platform.getDebugOption("org.eclipse.jface/trace/toolbarDisposal")); //$NON-NLS-1$ //$NON-NLS-2$
+            DEBUG_COMMANDS = getDebugOption("/trace/commands"); //$NON-NLS-1$
+            DEBUG_CONTEXTS = getDebugOption("/trace/contexts"); //$NON-NLS-1$
+            DEBUG_CONTEXTS_PERFORMANCE = getDebugOption("/trace/contexts.performance"); //$NON-NLS-1$
+            DEBUG_CONTEXTS_VERBOSE = getDebugOption("/trace/contexts.verbose"); //$NON-NLS-1$
+            DEBUG_HANDLERS = getDebugOption("/trace/handlers"); //$NON-NLS-1$
+            DEBUG_HANDLERS_PERFORMANCE = getDebugOption("/trace/handlers.performance"); //$NON-NLS-1$
+            DEBUG_HANDLERS_VERBOSE = getDebugOption("/trace/handlers.verbose"); //$NON-NLS-1$
+            DEBUG_OPERATIONS = getDebugOption("/trace/operations"); //$NON-NLS-1$
+            DEBUG_OPERATIONS_VERBOSE = getDebugOption("/trace/operations.verbose"); //$NON-NLS-1$
+            DEBUG_SHOW_ALL_JOBS = getDebugOption("/debug/showAllJobs"); //$NON-NLS-1$
+            DEBUG_STALE_JOBS = getDebugOption("/debug/job.stale"); //$NON-NLS-1$
+            DEBUG_HANDLERS_VERBOSE_COMMAND_ID = Platform
+                    .getDebugOption(PlatformUI.PLUGIN_ID
+                            + "/trace/handlers.verbose.commandId"); //$NON-NLS-1$
+            if ("".equals(DEBUG_HANDLERS_VERBOSE_COMMAND_ID)) { //$NON-NLS-1$
+            	DEBUG_HANDLERS_VERBOSE_COMMAND_ID = null;
+            }
+            DEBUG_DECLARED_IMAGES = getDebugOption("/debug/declaredImages"); //$NON-NLS-1$
+            DEBUG_CONTRIBUTIONS = getDebugOption("/debug/contributions"); //$NON-NLS-1$
+            EXPERIMENTAL_MENU = getDebugOption("/experimental/menus"); //$NON-NLS-1$
+            DEBUG_MPE = getDebugOption("/trace/multipageeditor"); //$NON-NLS-1$
+            DEBUG_WORKING_SETS = getDebugOption("/debug/workingSets"); //$NON-NLS-1$
+
+//            if(DEBUG_SWT_DEBUG_GLOBAL)
+//            	Device.DEBUG = true;
+        }
+    }
+
+    private static boolean getDebugOption(String option) {
+        return "true".equalsIgnoreCase(Platform.getDebugOption(PlatformUI.PLUGIN_ID + option)); //$NON-NLS-1$
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/misc/ProgramImageDescriptor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/misc/ProgramImageDescriptor.java
new file mode 100644
index 0000000..bdd9cc8
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/misc/ProgramImageDescriptor.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.misc;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.internal.WorkbenchImages;
+
+/**
+ * An image descriptor that loads its data from a program file.
+ */
+public class ProgramImageDescriptor extends ImageDescriptor {
+    private String filename;
+
+    private int offset;
+
+    /**
+     * Creates a new ImageDescriptor. The image is loaded
+     * from a file with the given name <code>name</code>.
+     */
+    public ProgramImageDescriptor(String fullPath, int offsetInFile) {
+        filename = fullPath;
+        offset = offsetInFile;
+    }
+
+    /**
+     * @see Object#equals
+     */
+    @Override
+	public boolean equals(Object o) {
+        if (!(o instanceof ProgramImageDescriptor)) {
+            return false;
+        }
+        ProgramImageDescriptor other = (ProgramImageDescriptor) o;
+        return filename.equals(other.filename) && offset == other.offset;
+    }
+
+    /**
+     * Returns an SWT Image that is described by the information
+     * in this descriptor.  Each call returns a new Image.
+     */
+    public Image getImage() {
+        return createImage();
+    }
+
+    // RAP [DM]
+//    /**
+//     * Returns an SWT Image that is described by the information
+//     * in this descriptor.
+//     */
+//    @Override
+//	public ImageData getImageData(int zoom) {
+//        /*This is a user defined offset into the file which always
+//         *returns us the defualt - return the default regardless*/
+//
+//        return WorkbenchImages.getImageDescriptor(ISharedImages.IMG_OBJ_FILE)
+//				.getImageData(zoom);
+//    }    
+    /**
+     * Returns an SWT Image that is described by the information
+     * in this descriptor.
+     */
+    @Override
+    public ImageData getImageData() {
+        /*This is a user defined offset into the file which always
+         *returns us the defualt - return the default regardless*/
+
+        return WorkbenchImages.getImageDescriptor(ISharedImages.IMG_OBJ_FILE)
+                .getImageData();
+    }
+
+    /**
+     * @see Object#hashCode
+     */
+    @Override
+	public int hashCode() {
+        return filename.hashCode() + offset;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/misc/StatusUtil.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/misc/StatusUtil.java
new file mode 100644
index 0000000..bc01165
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/misc/StatusUtil.java
@@ -0,0 +1,279 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.misc;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+/**
+ * Utility class to create status objects.
+ *
+ * @private - This class is an internal implementation class and should
+ * not be referenced or subclassed outside of the workbench
+ */
+public class StatusUtil {
+    /**
+     *	Answer a flat collection of the passed status and its recursive children
+     */
+    protected static List flatten(IStatus aStatus) {
+        List result = new ArrayList();
+
+        if (aStatus.isMultiStatus()) {
+			for (IStatus status : aStatus.getChildren()) {
+				if (status.isMultiStatus()) {
+					Iterator childStatiiEnum = flatten(status).iterator();
+                    while (childStatiiEnum.hasNext()) {
+						result.add(childStatiiEnum.next());
+					}
+                } else {
+					result.add(status);
+				}
+            }
+        } else {
+			result.add(aStatus);
+		}
+
+        return result;
+    }
+
+    /**
+     * This method must not be called outside the workbench.
+     *
+     * Utility method for creating status.
+     */
+    protected static IStatus newStatus(IStatus[] stati, String message,
+            Throwable exception) {
+
+        Assert.isTrue(message != null);
+        Assert.isTrue(message.trim().length() != 0);
+
+        return new MultiStatus(WorkbenchPlugin.PI_WORKBENCH, IStatus.ERROR,
+                stati, message, exception);
+    }
+
+    public static IStatus newStatus(String pluginId, Throwable exception) {
+        return newStatus(pluginId, getLocalizedMessage(exception), exception);
+    }
+
+    /**
+     * Returns a localized message describing the given exception. If the given exception does not
+     * have a localized message, this returns the string "An error occurred".
+     *
+     * @param exception
+     * @return
+     */
+    public static String getLocalizedMessage(Throwable exception) {
+        String message = exception.getLocalizedMessage();
+
+        if (message != null) {
+            return message;
+        }
+
+        // Workaround for the fact that CoreException does not implement a getLocalizedMessage() method.
+        // Remove this branch when and if CoreException implements getLocalizedMessage()
+        if (exception instanceof CoreException) {
+            CoreException ce = (CoreException)exception;
+            return ce.getStatus().getMessage();
+        }
+
+        return WorkbenchMessages.get().StatusUtil_errorOccurred;
+    }
+
+    /**
+     * Creates a new Status based on the original status, but with a different message
+     *
+     * @param originalStatus
+     * @param newMessage
+     * @return
+     */
+    public static IStatus newStatus(IStatus originalStatus, String newMessage) {
+        return new Status(originalStatus.getSeverity(),
+                originalStatus.getPlugin(), originalStatus.getCode(), newMessage, originalStatus.getException());
+    }
+
+    public static IStatus newStatus(String pluginId, String message, Throwable exception) {
+        return new Status(IStatus.ERROR, pluginId, IStatus.OK,
+                message, getCause(exception));
+    }
+
+    public static Throwable getCause(Throwable exception) {
+        // Figure out which exception should actually be logged -- if the given exception is
+        // a wrapper, unwrap it
+        Throwable cause = null;
+        if (exception != null) {
+            if (exception instanceof CoreException) {
+                // Workaround: CoreException contains a cause, but does not actually implement getCause().
+                // If we get a CoreException, we need to manually unpack the cause. Otherwise, use
+                // the general-purpose mechanism. Remove this branch if CoreException ever implements
+                // a correct getCause() method.
+                CoreException ce = (CoreException)exception;
+                cause = ce.getStatus().getException();
+            } else {
+            	// use reflect instead of a direct call to getCause(), to allow compilation against JCL Foundation (bug 80053)
+            	try {
+            		Method causeMethod = exception.getClass().getMethod("getCause", new Class[0]); //$NON-NLS-1$
+            		Object o = causeMethod.invoke(exception, new Object[0]);
+            		if (o instanceof Throwable) {
+            			cause = (Throwable) o;
+            		}
+            	}
+            	catch (NoSuchMethodException e) {
+            		// ignore
+            	} catch (IllegalArgumentException e) {
+            		// ignore
+				} catch (IllegalAccessException e) {
+            		// ignore
+				} catch (InvocationTargetException e) {
+            		// ignore
+				}
+            }
+
+            if (cause == null) {
+                cause = exception;
+            }
+        }
+
+        return cause;
+    }
+
+    /**
+     * This method must not be called outside the workbench.
+     *
+     * Utility method for creating status.
+     */
+    public static IStatus newStatus(int severity, String message,
+            Throwable exception) {
+
+        String statusMessage = message;
+        if (message == null || message.trim().length() == 0) {
+            if (exception.getMessage() == null) {
+				statusMessage = exception.toString();
+			} else {
+				statusMessage = exception.getMessage();
+			}
+        }
+
+        return new Status(severity, WorkbenchPlugin.PI_WORKBENCH, severity,
+                statusMessage, getCause(exception));
+    }
+
+    /**
+     * This method must not be called outside the workbench.
+     *
+     * Utility method for creating status.
+     */
+    public static IStatus newStatus(List children, String message,
+            Throwable exception) {
+
+        List flatStatusCollection = new ArrayList();
+        Iterator iter = children.iterator();
+        while (iter.hasNext()) {
+            IStatus currentStatus = (IStatus) iter.next();
+            Iterator childrenIter = flatten(currentStatus).iterator();
+            while (childrenIter.hasNext()) {
+				flatStatusCollection.add(childrenIter.next());
+			}
+        }
+
+        IStatus[] stati = new IStatus[flatStatusCollection.size()];
+        flatStatusCollection.toArray(stati);
+        return newStatus(stati, message, exception);
+    }
+
+    /**
+     * This method must not be called outside the workbench.
+     *
+     * Utility method for handling status.
+     */
+    public static void handleStatus(IStatus status, int hint, Shell shell) {
+    	StatusManager.getManager().handle(status, hint);
+	}
+
+    /**
+     * This method must not be called outside the workbench.
+     *
+     * Utility method for handling status.
+     */
+    public static void handleStatus(Throwable e, int hint) {
+		StatusManager.getManager().handle(
+				newStatus(WorkbenchPlugin.PI_WORKBENCH, e), hint);
+	}
+
+    /**
+     * This method must not be called outside the workbench.
+     *
+     * Utility method for handling status.
+     */
+	public static void handleStatus(String message, Throwable e, int hint) {
+		StatusManager.getManager().handle(
+				newStatus(WorkbenchPlugin.PI_WORKBENCH, message, e), hint);
+	}
+
+	/**
+     * This method must not be called outside the workbench.
+     *
+     * Utility method for handling status.
+     */
+	public static void handleStatus(String message, Throwable e, int hint,
+			Shell shell) {
+		StatusManager.getManager().handle(
+				newStatus(WorkbenchPlugin.PI_WORKBENCH, message, e), hint);
+	}
+
+	/**
+     * This method must not be called outside the workbench.
+     *
+     * Utility method for handling status.
+     */
+	public static void handleStatus(IStatus status, String message, int hint) {
+		StatusManager.getManager().handle(newStatus(status, message), hint);
+	}
+
+	/**
+     * This method must not be called outside the workbench.
+     *
+     * Utility method for handling status.
+     */
+	public static void handleStatus(IStatus status, String message, int hint,
+			Shell shell) {
+		StatusManager.getManager().handle(newStatus(status, message), hint);
+	}
+
+	/**
+     * This method must not be called outside the workbench.
+     *
+     * Utility method for handling status.
+     */
+	public static void handleStatus(String message, int hint) {
+		handleStatus(message, null, hint);
+	}
+
+	/**
+     * This method must not be called outside the workbench.
+     *
+     * Utility method for handling status.
+     */
+	public static void handleStatus(String message, int hint, Shell shell) {
+		handleStatus(message, null, hint);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/misc/StringMatcher.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/misc/StringMatcher.java
new file mode 100644
index 0000000..0e0d356
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/misc/StringMatcher.java
@@ -0,0 +1,451 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.misc;
+
+import java.util.Vector;
+
+/**
+ * A string pattern matcher, suppporting "*" and "?" wildcards.
+ */
+public class StringMatcher {
+    protected String fPattern;
+
+    protected int fLength; // pattern length
+
+    protected boolean fIgnoreWildCards;
+
+    protected boolean fIgnoreCase;
+
+    protected boolean fHasLeadingStar;
+
+    protected boolean fHasTrailingStar;
+
+    protected String fSegments[]; //the given pattern is split into * separated segments
+
+    /* boundary value beyond which we don't need to search in the text */
+    protected int fBound = 0;
+
+    protected static final char fSingleWildCard = '\u0000';
+
+    public static class Position {
+        int start; //inclusive
+
+        int end; //exclusive
+
+        public Position(int start, int end) {
+            this.start = start;
+            this.end = end;
+        }
+
+        public int getStart() {
+            return start;
+        }
+
+        public int getEnd() {
+            return end;
+        }
+    }
+
+    /**
+     * StringMatcher constructor takes in a String object that is a simple
+     * pattern which may contain '*' for 0 and many characters and
+     * '?' for exactly one character.
+     *
+     * Literal '*' and '?' characters must be escaped in the pattern
+     * e.g., "\*" means literal "*", etc.
+     *
+     * Escaping any other character (including the escape character itself),
+     * just results in that character in the pattern.
+     * e.g., "\a" means "a" and "\\" means "\"
+     *
+     * If invoking the StringMatcher with string literals in Java, don't forget
+     * escape characters are represented by "\\".
+     *
+     * @param pattern the pattern to match text against
+     * @param ignoreCase if true, case is ignored
+     * @param ignoreWildCards if true, wild cards and their escape sequences are ignored
+     * 		  (everything is taken literally).
+     */
+    public StringMatcher(String pattern, boolean ignoreCase,
+            boolean ignoreWildCards) {
+        if (pattern == null) {
+			throw new IllegalArgumentException();
+		}
+        fIgnoreCase = ignoreCase;
+        fIgnoreWildCards = ignoreWildCards;
+        fPattern = pattern;
+        fLength = pattern.length();
+
+        if (fIgnoreWildCards) {
+            parseNoWildCards();
+        } else {
+            parseWildCards();
+        }
+    }
+
+    /**
+     * Find the first occurrence of the pattern between <code>start</code)(inclusive)
+     * and <code>end</code>(exclusive).
+     * @param text the String object to search in
+     * @param start the starting index of the search range, inclusive
+     * @param end the ending index of the search range, exclusive
+     * @return an <code>StringMatcher.Position</code> object that keeps the starting
+     * (inclusive) and ending positions (exclusive) of the first occurrence of the
+     * pattern in the specified range of the text; return null if not found or subtext
+     * is empty (start==end). A pair of zeros is returned if pattern is empty string
+     * Note that for pattern like "*abc*" with leading and trailing stars, position of "abc"
+     * is returned. For a pattern like"*??*" in text "abcdf", (1,3) is returned
+     */
+    public StringMatcher.Position find(String text, int start, int end) {
+        if (text == null) {
+			throw new IllegalArgumentException();
+		}
+
+        int tlen = text.length();
+        if (start < 0) {
+			start = 0;
+		}
+        if (end > tlen) {
+			end = tlen;
+		}
+        if (end < 0 || start >= end) {
+			return null;
+		}
+        if (fLength == 0) {
+			return new Position(start, start);
+		}
+        if (fIgnoreWildCards) {
+            int x = posIn(text, start, end);
+            if (x < 0) {
+				return null;
+			}
+            return new Position(x, x + fLength);
+        }
+
+        int segCount = fSegments.length;
+        if (segCount == 0) {
+			return new Position(start, end);
+		}
+
+        int curPos = start;
+        int matchStart = -1;
+        int i;
+        for (i = 0; i < segCount && curPos < end; ++i) {
+            String current = fSegments[i];
+            int nextMatch = regExpPosIn(text, curPos, end, current);
+            if (nextMatch < 0) {
+				return null;
+			}
+            if (i == 0) {
+				matchStart = nextMatch;
+			}
+            curPos = nextMatch + current.length();
+        }
+        if (i < segCount) {
+			return null;
+		}
+        return new Position(matchStart, curPos);
+    }
+
+    /**
+     * match the given <code>text</code> with the pattern
+     * @return true if matched otherwise false
+     * @param text a String object
+     */
+    public boolean match(String text) {
+    	if(text == null) {
+			return false;
+		}
+        return match(text, 0, text.length());
+    }
+
+    /**
+     * Given the starting (inclusive) and the ending (exclusive) positions in the
+     * <code>text</code>, determine if the given substring matches with aPattern
+     * @return true if the specified portion of the text matches the pattern
+     * @param text a String object that contains the substring to match
+     * @param start marks the starting position (inclusive) of the substring
+     * @param end marks the ending index (exclusive) of the substring
+     */
+    public boolean match(String text, int start, int end) {
+        if (null == text) {
+			throw new IllegalArgumentException();
+		}
+
+        if (start > end) {
+			return false;
+		}
+
+        if (fIgnoreWildCards) {
+			return (end - start == fLength)
+                    && fPattern.regionMatches(fIgnoreCase, 0, text, start,
+                            fLength);
+		}
+        int segCount = fSegments.length;
+        if (segCount == 0 && (fHasLeadingStar || fHasTrailingStar)) {
+			return true;
+		}
+        if (start == end) {
+			return fLength == 0;
+		}
+        if (fLength == 0) {
+			return start == end;
+		}
+
+        int tlen = text.length();
+        if (start < 0) {
+			start = 0;
+		}
+        if (end > tlen) {
+			end = tlen;
+		}
+
+        int tCurPos = start;
+        int bound = end - fBound;
+        if (bound < 0) {
+			return false;
+		}
+        int i = 0;
+        String current = fSegments[i];
+        int segLength = current.length();
+
+        /* process first segment */
+        if (!fHasLeadingStar) {
+            if (!regExpRegionMatches(text, start, current, 0, segLength)) {
+                return false;
+            } else {
+                ++i;
+                tCurPos = tCurPos + segLength;
+            }
+        }
+        if ((fSegments.length == 1) && (!fHasLeadingStar)
+                && (!fHasTrailingStar)) {
+            // only one segment to match, no wildcards specified
+            return tCurPos == end;
+        }
+        /* process middle segments */
+        while (i < segCount) {
+            current = fSegments[i];
+            int currentMatch;
+            int k = current.indexOf(fSingleWildCard);
+            if (k < 0) {
+                currentMatch = textPosIn(text, tCurPos, end, current);
+                if (currentMatch < 0) {
+					return false;
+				}
+            } else {
+                currentMatch = regExpPosIn(text, tCurPos, end, current);
+                if (currentMatch < 0) {
+					return false;
+				}
+            }
+            tCurPos = currentMatch + current.length();
+            i++;
+        }
+
+        /* process final segment */
+        if (!fHasTrailingStar && tCurPos != end) {
+            int clen = current.length();
+            return regExpRegionMatches(text, end - clen, current, 0, clen);
+        }
+        return i == segCount;
+    }
+
+    /**
+     * This method parses the given pattern into segments seperated by wildcard '*' characters.
+     * Since wildcards are not being used in this case, the pattern consists of a single segment.
+     */
+    private void parseNoWildCards() {
+        fSegments = new String[1];
+        fSegments[0] = fPattern;
+        fBound = fLength;
+    }
+
+    /**
+     * Parses the given pattern into segments seperated by wildcard '*' characters.
+     * @param p, a String object that is a simple regular expression with '*' and/or '?'
+     */
+    private void parseWildCards() {
+        if (fPattern.startsWith("*")) { //$NON-NLS-1$
+			fHasLeadingStar = true;
+		}
+        if (fPattern.endsWith("*")) {//$NON-NLS-1$
+            /* make sure it's not an escaped wildcard */
+            if (fLength > 1 && fPattern.charAt(fLength - 2) != '\\') {
+                fHasTrailingStar = true;
+            }
+        }
+
+        Vector temp = new Vector();
+
+        int pos = 0;
+        StringBuffer buf = new StringBuffer();
+        while (pos < fLength) {
+            char c = fPattern.charAt(pos++);
+            switch (c) {
+            case '\\':
+                if (pos >= fLength) {
+                    buf.append(c);
+                } else {
+                    char next = fPattern.charAt(pos++);
+                    /* if it's an escape sequence */
+                    if (next == '*' || next == '?' || next == '\\') {
+                        buf.append(next);
+                    } else {
+                        /* not an escape sequence, just insert literally */
+                        buf.append(c);
+                        buf.append(next);
+                    }
+                }
+                break;
+            case '*':
+                if (buf.length() > 0) {
+                    /* new segment */
+                    temp.addElement(buf.toString());
+                    fBound += buf.length();
+                    buf.setLength(0);
+                }
+                break;
+            case '?':
+                /* append special character representing single match wildcard */
+                buf.append(fSingleWildCard);
+                break;
+            default:
+                buf.append(c);
+            }
+        }
+
+        /* add last buffer to segment list */
+        if (buf.length() > 0) {
+            temp.addElement(buf.toString());
+            fBound += buf.length();
+        }
+
+        fSegments = new String[temp.size()];
+        temp.copyInto(fSegments);
+    }
+
+    /**
+     * @param text a string which contains no wildcard
+     * @param start the starting index in the text for search, inclusive
+     * @param end the stopping point of search, exclusive
+     * @return the starting index in the text of the pattern , or -1 if not found
+     */
+    protected int posIn(String text, int start, int end) {//no wild card in pattern
+        int max = end - fLength;
+
+        if (!fIgnoreCase) {
+            int i = text.indexOf(fPattern, start);
+            if (i == -1 || i > max) {
+				return -1;
+			}
+            return i;
+        }
+
+        for (int i = start; i <= max; ++i) {
+            if (text.regionMatches(true, i, fPattern, 0, fLength)) {
+				return i;
+			}
+        }
+
+        return -1;
+    }
+
+    /**
+     * @param text a simple regular expression that may only contain '?'(s)
+     * @param start the starting index in the text for search, inclusive
+     * @param end the stopping point of search, exclusive
+     * @param p a simple regular expression that may contains '?'
+     * @return the starting index in the text of the pattern , or -1 if not found
+     */
+    protected int regExpPosIn(String text, int start, int end, String p) {
+        int plen = p.length();
+
+        int max = end - plen;
+        for (int i = start; i <= max; ++i) {
+            if (regExpRegionMatches(text, i, p, 0, plen)) {
+				return i;
+			}
+        }
+        return -1;
+    }
+
+    /**
+     *
+     * @return boolean
+     * @param text a String to match
+     * @param start int that indicates the starting index of match, inclusive
+     * @param end</code> int that indicates the ending index of match, exclusive
+     * @param p String,  String, a simple regular expression that may contain '?'
+     * @param ignoreCase boolean indicating wether code>p</code> is case sensitive
+     */
+    protected boolean regExpRegionMatches(String text, int tStart, String p,
+            int pStart, int plen) {
+        while (plen-- > 0) {
+            char tchar = text.charAt(tStart++);
+            char pchar = p.charAt(pStart++);
+
+            /* process wild cards */
+            if (!fIgnoreWildCards) {
+                /* skip single wild cards */
+                if (pchar == fSingleWildCard) {
+                    continue;
+                }
+            }
+            if (pchar == tchar) {
+				continue;
+			}
+            if (fIgnoreCase) {
+                if (Character.toUpperCase(tchar) == Character
+                        .toUpperCase(pchar)) {
+					continue;
+				}
+                // comparing after converting to upper case doesn't handle all cases;
+                // also compare after converting to lower case
+                if (Character.toLowerCase(tchar) == Character
+                        .toLowerCase(pchar)) {
+					continue;
+				}
+            }
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * @param text the string to match
+     * @param start the starting index in the text for search, inclusive
+     * @param end the stopping point of search, exclusive
+     * @param p a pattern string that has no wildcard
+     * @return the starting index in the text of the pattern , or -1 if not found
+     */
+    protected int textPosIn(String text, int start, int end, String p) {
+
+        int plen = p.length();
+        int max = end - plen;
+
+        if (!fIgnoreCase) {
+            int i = text.indexOf(p, start);
+            if (i == -1 || i > max) {
+				return -1;
+			}
+            return i;
+        }
+
+        for (int i = start; i <= max; ++i) {
+            if (text.regionMatches(true, i, p, 0, plen)) {
+				return i;
+			}
+        }
+
+        return -1;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/misc/TestPartListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/misc/TestPartListener.java
new file mode 100644
index 0000000..2a64e4c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/misc/TestPartListener.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.misc;
+
+import org.eclipse.ui.IPartListener;
+import org.eclipse.ui.IWorkbenchPart;
+
+/**
+ * Prints out part listener events
+ */
+public class TestPartListener implements IPartListener {
+    /**
+     * TestPartListener constructor comment.
+     * @issue seems like garbage - no one using it
+     */
+    public TestPartListener() {
+        super();
+    }
+
+    /**
+     * Notifies this listener that the given part has been activated.
+     *
+     * @param part the part that was activated
+     * @see IPerspective#activate
+     */
+    @Override
+	public void partActivated(IWorkbenchPart part) {
+        System.out.println("partActivated(" + part + ")");//$NON-NLS-2$//$NON-NLS-1$
+    }
+
+    /**
+     * Notifies this listener that the given part has been brought to the top.
+     * <p>
+     * These events occur when an editor is brought to the top in the editor area,
+     * or when a view is brought to the top in a page book with multiple views.
+     * They are normally only sent when a part is brought to the top
+     * programmatically (via <code>IPerspective.bringToTop</code>). When a part is
+     * activated by the user clicking on it, only <code>partActivated</code> is sent.
+     * </p>
+     *
+     * @param part the part that was surfaced
+     * @see IPerspective#bringToTop
+     */
+    @Override
+	public void partBroughtToTop(IWorkbenchPart part) {
+        System.out.println("partBroughtToTop(" + part + ")");//$NON-NLS-2$//$NON-NLS-1$
+    }
+
+    /**
+     * Notifies this listener that the given part has been closed.
+     *
+     * @param part the part that was closed
+     * @see IPerspective#close
+     */
+    @Override
+	public void partClosed(IWorkbenchPart part) {
+        System.out.println("partClosed(" + part + ")");//$NON-NLS-2$//$NON-NLS-1$
+    }
+
+    /**
+     * Notifies this listener that the given part has been deactivated.
+     *
+     * @param part the part that was deactivated
+     * @see IPerspective#activate
+     */
+    @Override
+	public void partDeactivated(IWorkbenchPart part) {
+        System.out.println("partDeactivated(" + part + ")");//$NON-NLS-2$//$NON-NLS-1$
+    }
+
+    /**
+     * Notifies this listener that the given part has been opened.
+     *
+     * @param part the part that was opened
+     */
+    @Override
+	public void partOpened(IWorkbenchPart part) {
+        System.out.println("partOpened(" + part + ")");//$NON-NLS-2$//$NON-NLS-1$
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/misc/UIListenerLogging.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/misc/UIListenerLogging.java
new file mode 100644
index 0000000..37f1304
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/misc/UIListenerLogging.java
@@ -0,0 +1,244 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.misc;
+
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartConstants;
+import org.eclipse.ui.IWorkbenchPartReference;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.util.Util;
+
+
+/**
+ * To whom it may concern: Please stop deleting the logging code. This is important for debugging
+ * event ordering issues.
+ */
+public class UIListenerLogging {
+
+    // Types of listeners that can be logged (the names of the options that enable/disable their logging)
+    private final static String LISTENER_EVENTS = PlatformUI.PLUGIN_ID + "/debug"; //$NON-NLS-1$
+    public  final static String PAGE_PARTLISTENER_EVENTS = PlatformUI.PLUGIN_ID + "/listeners/IWorkbenchPage.IPartListener"; //$NON-NLS-1$
+    public  final static String PAGE_PARTLISTENER2_EVENTS = PlatformUI.PLUGIN_ID + "/listeners/IWorkbenchPage.IPartListener2"; //$NON-NLS-1$
+    private final static String PAGE_PROPERTY_EVENTS = PlatformUI.PLUGIN_ID + "/listeners/IWorkbenchPage.IPropertyChangeListener"; //$NON-NLS-1$
+    private final static String WINDOW_PAGE_EVENTS = PlatformUI.PLUGIN_ID + "/listeners/IWorkbenchWindow.IPageListener"; //$NON-NLS-1$
+    private final static String WINDOW_PERSPECTIVE_EVENTS = PlatformUI.PLUGIN_ID + "/listeners/IWorkbenchWindow.IPerspectiveListener"; //$NON-NLS-1$
+    public  final static String WINDOW_PARTLISTENER_EVENTS = PlatformUI.PLUGIN_ID + "/listeners/IWorkbenchWindow.IPartListener"; //$NON-NLS-1$
+    public  final static String WINDOW_PARTLISTENER2_EVENTS = PlatformUI.PLUGIN_ID + "/listeners/IWorkbenchWindow.IPartListener2"; //$NON-NLS-1$
+    private final static String PARTREFERENCE_PROPERTY_EVENTS = PlatformUI.PLUGIN_ID + "/listeners/IWorkbenchPartReference"; //$NON-NLS-1$
+
+    public final static boolean enabled = internal_isEnabled(LISTENER_EVENTS);
+
+    // IPartListener events
+    public final static String PE_ACTIVATED = "partActivated"; //$NON-NLS-1$
+    public final static String PE_PART_BROUGHT_TO_TOP = "partBroughtToTop"; //$NON-NLS-1$
+    public final static String PE_PART_CLOSED = "partClosed"; //$NON-NLS-1$
+    public final static String PE_PART_DEACTIVATED = "partDeactivated"; //$NON-NLS-1$
+    public final static String PE_PART_OPENED = "partOpened"; //$NON-NLS-1$
+
+    // IPartListener2 events
+    public final static String PE2_ACTIVATED = "partActivated"; //$NON-NLS-1$
+    public final static String PE2_PART_VISIBLE = "partVisible"; //$NON-NLS-1$
+    public final static String PE2_PART_HIDDEN = "partHidden"; //$NON-NLS-1$
+    public final static String PE2_PART_BROUGHT_TO_TOP = "partBroughtToTop"; //$NON-NLS-1$
+    public final static String PE2_PART_CLOSED = "partClosed"; //$NON-NLS-1$
+    public final static String PE2_PART_DEACTIVATED = "partDectivated"; //$NON-NLS-1$
+    public final static String PE2_PART_OPENED = "partOpened"; //$NON-NLS-1$
+    public static final String PE2_PART_INPUT_CHANGED = "partInputChanged"; //$NON-NLS-1$
+
+    // IPageListener events
+    public final static String WPE_PAGE_ACTIVATED = "pageActivated"; //$NON-NLS-1$
+    public final static String WPE_PAGE_OPENED = "pageOpened"; //$NON-NLS-1$
+    public final static String WPE_PAGE_CLOSED = "pageClosed"; //$NON-NLS-1$
+
+    // IPerspectiveListener events
+    public static final String PLE_PERSP_PRE_DEACTIVATE = "perspectivePreDeactivate"; //$NON-NLS-1$
+    public static final String PLE_PERSP_DEACTIVATED = "perspectiveDeactivated"; //$NON-NLS-1$
+    public static final String PLE_PERSP_ACTIVATED = "perspectiveActivated"; //$NON-NLS-1$
+    public static final String PLE_PERSP_OPENED = "perspectiveOpened"; //$NON-NLS-1$
+    public static final String PLE_PERSP_CLOSED = "perspectiveClosed"; //$NON-NLS-1$
+    public static final String PLE_PERSP_SAVED_AS = "perspectiveSavedAs"; //$NON-NLS-1$
+
+    private static String getSourceId(Object source) {
+        return Util.safeString(Integer.toString(source.hashCode() % 1000));
+    }
+
+    private static String getWindowId(IWorkbenchWindow source) {
+        return "window " + Util.safeString(Integer.toString(source.hashCode() % 1000)); //$NON-NLS-1$
+    }
+
+    private static String getPageId(IWorkbenchPage page) {
+        return "page " + Util.safeString(Integer.toString(page.hashCode() % 1000)); //$NON-NLS-1$
+    }
+
+    private static String getPerspectiveId(IPerspectiveDescriptor descriptor) {
+        return Util.safeString(descriptor.getId());
+    }
+
+    public static final void logPageEvent(IWorkbenchWindow window, IWorkbenchPage page, String eventId) {
+        if (isEnabled(WINDOW_PAGE_EVENTS)) {
+            System.out.println(WINDOW_PAGE_EVENTS
+                    + " " + getWindowId(window) //$NON-NLS-1$
+                    + " " + eventId + " (" + getPageId(page) + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+        }
+    }
+
+    public static final void logPerspectiveEvent(IWorkbenchWindow window, IWorkbenchPage page,
+            IPerspectiveDescriptor descriptor, String eventId) {
+
+        if (isEnabled(WINDOW_PERSPECTIVE_EVENTS)) {
+            System.out.println(WINDOW_PERSPECTIVE_EVENTS
+                    + " " + getWindowId(window) //$NON-NLS-1$
+                    + " " + eventId + " (" + getPageId(page) + ", " + getPerspectiveId(descriptor) + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+        }
+    }
+
+    public static final void logPerspectiveChangedEvent(IWorkbenchWindow window, IWorkbenchPage page,
+            IPerspectiveDescriptor descriptor, IWorkbenchPartReference ref, String changeId) {
+
+        if (isEnabled(WINDOW_PERSPECTIVE_EVENTS)) {
+            System.out.println(WINDOW_PERSPECTIVE_EVENTS
+                    + " "+ getWindowId(window) //$NON-NLS-1$
+                    + " perspectiveChanged (" + getPageId(page) + ", " + getPerspectiveId(descriptor)  //$NON-NLS-1$ //$NON-NLS-2$
+                    + ", " + getPartId(ref) + ", " + changeId + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+        }
+    }
+
+    public static final void logPerspectiveSavedAs(IWorkbenchWindow window, IWorkbenchPage page,
+    		IPerspectiveDescriptor oldDescriptor, IPerspectiveDescriptor newDescriptor) {
+
+        if (isEnabled(WINDOW_PERSPECTIVE_EVENTS)) {
+            System.out.println(WINDOW_PERSPECTIVE_EVENTS
+                    + " " + getWindowId(window) //$NON-NLS-1$
+                    + " " + PLE_PERSP_SAVED_AS + " (" + getPageId(page) + ", " + getPerspectiveId(oldDescriptor)  + ", " + getPerspectiveId(newDescriptor) + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+        }
+    }
+
+
+    private static String getPartId(IWorkbenchPart part) {
+        if (part == null) {
+            return "null part"; //$NON-NLS-1$
+        }
+
+        return Util.safeString(part.getTitle()) + " - "  //$NON-NLS-1$
+            + Util.safeString(part.getSite().getId());
+    }
+
+    private static String getPartId(IWorkbenchPartReference ref) {
+        if (ref == null) {
+            return "null part"; //$NON-NLS-1$
+        }
+
+        return Util.safeString(ref.getPartName()) + " - "  //$NON-NLS-1$
+            + Util.safeString(ref.getId());
+    }
+
+    /**
+     * Log a partListener event fired from the workbench window
+     *
+     * @param page
+     * @param eventId
+     */
+    public static final void logPartListenerEvent(String sourceType, Object source, IWorkbenchPart part, String eventId) {
+        if (isEnabled(sourceType)) {
+            System.out.println(sourceType + " " + getSourceId(source) //$NON-NLS-1$
+                    + ", " + eventId + "(" + getPartId(part) + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+        }
+    }
+
+    /**
+     * Log a partListener2 event fired from the workbench window
+     *
+     * @param page
+     * @param eventId
+     */
+    public static final void logPartListener2Event(String sourceType, Object source, IWorkbenchPartReference part, String eventId) {
+        if (isEnabled(sourceType)) {
+            System.out.println(sourceType + " " + getSourceId(source) //$NON-NLS-1$
+                    + ", " + eventId + "(" + getPartId(part) + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+        }
+    }
+
+    /**
+     * Log an event fired from the workbench page
+     *
+     * @param page
+     * @param eventId
+     */
+    public static final void logPartListenerEvent(IWorkbenchPage page, IWorkbenchPart part, String eventId) {
+        if (isEnabled(PAGE_PARTLISTENER_EVENTS)) {
+            System.out.println(PAGE_PARTLISTENER_EVENTS + " page "  //$NON-NLS-1$
+                    + Util.safeString(page.getLabel())
+                    + ", " + eventId + "(" + getPartId(part) + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+        }
+    }
+
+    /**
+     * Log an event fired from the workbench page
+     *
+     * @param page
+     * @param eventId
+     */
+    public static final void logPartListener2Event(IWorkbenchPage page, IWorkbenchPartReference part, String eventId) {
+        if (isEnabled(PAGE_PARTLISTENER2_EVENTS)) {
+            System.out.println(PAGE_PARTLISTENER2_EVENTS + " page "  //$NON-NLS-1$
+                    + Util.safeString(page.getLabel())
+                    + ", " + eventId + "(" + getPartId(part) + ")");          //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+        }
+    }
+
+    /**
+     * Log an event fired from the workbench page
+     *
+     * @param page
+     * @param eventId
+     */
+    public static final void logPagePropertyChanged(IWorkbenchPage page, String changeId, Object oldValue, Object newValue) {
+        if (isEnabled(PAGE_PROPERTY_EVENTS)) {
+            System.out.println(PAGE_PROPERTY_EVENTS + " page "  //$NON-NLS-1$
+                    + Util.safeString(page.getLabel())
+                    + ", " + changeId + " = " + Util.safeString(newValue.toString()) + "( old value = " + newValue.toString() + " )"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+        }
+    }
+
+    public static final void logPartReferencePropertyChange(IWorkbenchPartReference ref, int changeId) {
+        if (isEnabled(PARTREFERENCE_PROPERTY_EVENTS)) {
+            String eventDescription;
+
+            switch(changeId) {
+                case IWorkbenchPartConstants.PROP_TITLE: eventDescription = "title"; break; //$NON-NLS-1$
+                case IWorkbenchPartConstants.PROP_DIRTY: eventDescription = "dirty"; break; //$NON-NLS-1$
+                case IWorkbenchPartConstants.PROP_INPUT: eventDescription = "input"; break; //$NON-NLS-1$
+                case IWorkbenchPartConstants.PROP_PART_NAME: eventDescription = "part_name"; break; //$NON-NLS-1$
+                case IWorkbenchPartConstants.PROP_CONTENT_DESCRIPTION: eventDescription = "content_description"; break; //$NON-NLS-1$
+                default:
+                    eventDescription = "unknown event id = " + changeId; //$NON-NLS-1$
+            }
+
+            System.out.println(PARTREFERENCE_PROPERTY_EVENTS + " "  //$NON-NLS-1$
+                    + getPartId(ref)
+                    + ", property " + eventDescription);         //$NON-NLS-1$
+        }
+    }
+
+    private static boolean isEnabled(String eventName) {
+        return enabled && internal_isEnabled(eventName);
+    }
+
+    private static boolean internal_isEnabled(String eventName) {
+        String option = Platform.getDebugOption(eventName);
+        return option != null && !option.equalsIgnoreCase("false") && !option.equalsIgnoreCase("-1"); //$NON-NLS-1$ //$NON-NLS-2$
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/misc/UIStats.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/misc/UIStats.java
new file mode 100644
index 0000000..2fea0b2
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/misc/UIStats.java
@@ -0,0 +1,163 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.misc;
+
+import java.util.HashMap;
+import org.eclipse.core.runtime.PerformanceStats;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * This class is used for monitoring performance events.  Each performance
+ * event has an associated option in the org.eclipse.ui plugin's .options file
+ * that specifies an maximum acceptable duration for that event.
+ *
+ * @see org.eclipse.core.runtime.PerformanceStats
+ */
+public class UIStats {
+
+	 private static HashMap operations = new HashMap();
+
+    public static final int CREATE_PART = 0;
+
+    public static final int CREATE_PART_CONTROL = 1;
+
+    public static final int INIT_PART = 2;
+
+    public static final int CREATE_PERSPECTIVE = 3;
+
+    public static final int RESTORE_WORKBENCH = 4;
+
+    public static final int START_WORKBENCH = 5;
+
+    public static final int CREATE_PART_INPUT = 6;
+
+    public static final int ACTIVATE_PART = 7;
+
+    public static final int BRING_PART_TO_TOP = 8;
+
+    public static final int NOTIFY_PART_LISTENERS = 9;
+
+    public static final int SWITCH_PERSPECTIVE = 10;
+
+    public static final int NOTIFY_PAGE_LISTENERS = 11;
+
+    public static final int NOTIFY_PERSPECTIVE_LISTENERS = 12;
+
+    public static final int UI_JOB = 13;
+
+	public static final int CONTENT_TYPE_LOOKUP = 14;
+
+	public static final int EARLY_STARTUP = 15;
+
+	/**
+	 * Change this value when you add a new event constant.
+	 */
+	public static final int LAST_VALUE = EARLY_STARTUP;
+
+    private static boolean debug[] = new boolean[LAST_VALUE+1];
+
+    private static String[] events = new String[LAST_VALUE+1];
+
+    static {
+        events[CREATE_PART] = PlatformUI.PLUGIN_ID + "/perf/part.create"; //$NON-NLS-1$
+        events[CREATE_PART_INPUT] = PlatformUI.PLUGIN_ID + "/perf/part.input"; //$NON-NLS-1$
+        events[CREATE_PART_CONTROL] = PlatformUI.PLUGIN_ID + "/perf/part.control"; //$NON-NLS-1$
+        events[INIT_PART] = PlatformUI.PLUGIN_ID + "/perf/part.init"; //$NON-NLS-1$
+        events[CREATE_PERSPECTIVE] = PlatformUI.PLUGIN_ID + "/perf/perspective.create"; //$NON-NLS-1$
+        events[SWITCH_PERSPECTIVE] = PlatformUI.PLUGIN_ID + "/perf/perspective.switch"; //$NON-NLS-1$
+        events[RESTORE_WORKBENCH] = PlatformUI.PLUGIN_ID + "/perf/workbench.restore"; //$NON-NLS-1$
+        events[START_WORKBENCH] = PlatformUI.PLUGIN_ID + "/perf/workbench.start"; //$NON-NLS-1$
+        events[ACTIVATE_PART] = PlatformUI.PLUGIN_ID + "/perf/part.activate"; //$NON-NLS-1$
+        events[BRING_PART_TO_TOP] = PlatformUI.PLUGIN_ID + "/perf/part.activate"; //$NON-NLS-1$
+        events[NOTIFY_PART_LISTENERS] = PlatformUI.PLUGIN_ID + "/perf/part.listeners"; //$NON-NLS-1$
+        events[NOTIFY_PAGE_LISTENERS] = PlatformUI.PLUGIN_ID + "/perf/page.listeners"; //$NON-NLS-1$
+        events[NOTIFY_PERSPECTIVE_LISTENERS] = PlatformUI.PLUGIN_ID + "/perf/perspective.listeners"; //$NON-NLS-1$
+        events[UI_JOB] = PlatformUI.PLUGIN_ID + "/perf/uijob"; //$NON-NLS-1$
+		events[CONTENT_TYPE_LOOKUP] = PlatformUI.PLUGIN_ID + "/perf/contentTypes"; //$NON-NLS-1$
+		events[EARLY_STARTUP] = PlatformUI.PLUGIN_ID + "/perf/earlyStartup"; //$NON-NLS-1$
+
+        for (int i = 0; i <= LAST_VALUE; i++) {
+        	//don't log any performance events if the general performance stats is disabled
+        	if (events[i] != null && PerformanceStats.ENABLED) {
+				debug[i] = PerformanceStats.isEnabled(events[i]);
+			}
+        }
+    }
+
+    /**
+     * Returns whether tracing of the given debug event is turned on.
+     *
+     * @param event The event id
+     * @return <code>true</code> if tracing of this event is turned on,
+     * and <code>false</code> otherwise.
+     */
+    public static boolean isDebugging(int event) {
+        return debug[event];
+    }
+
+    /**
+     * Indicates the start of a performance event
+     *
+     * @param event The event id
+     * @param label The event label
+     */
+    public static void start(int event, String label) {
+        if (debug[event]) {
+			operations.put(event + label, new Long(System.currentTimeMillis()));
+		}
+    }
+
+    /**
+     * Indicates the end of a performance operation
+     *
+     * @param event The event id
+     * @param blame An object that is responsible for the event that occurred,
+     * or that uniquely describes the event that occurred
+     * @param label The event label
+     */
+   	public static void end(int event, Object blame, String label) {
+        if (debug[event]) {
+            Long startTime = (Long) operations.remove(event + label);
+            if (startTime == null) {
+				return;
+			}
+            final long elapsed = System.currentTimeMillis() - startTime.longValue();
+//			System.out.println("Time - " + //$NON-NLS-1$
+//                    elapsed + events[event] + label);
+            PerformanceStats.getStats(events[event], blame).addRun(elapsed, label);
+        }
+    }
+
+   	/**
+   	 * Special hook to signal that application startup is complete and the event
+   	 * loop has started running.
+   	 */
+   	public static void startupComplete() {
+   		// We use a runtime debug option here for backwards compatibility (bug 96672)
+		// Note that this value is only relevant if the workspace chooser is not used.
+   		String option = Platform.getDebugOption(Platform.PI_RUNTIME + "/debug"); //$NON-NLS-1$
+		if (option == null || !"true".equalsIgnoreCase(option)) { //$NON-NLS-1$
+			return;
+		}
+		String startString = System.getProperty("eclipse.startTime"); //$NON-NLS-1$
+		if (startString == null) {
+			return;
+		}
+		try {
+			long start = Long.parseLong(startString);
+			long end = System.currentTimeMillis();
+			System.out.println("Startup complete: " + (end - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
+		} catch (NumberFormatException e) {
+			//this is just debugging code -- ok to swallow exception
+		}
+   	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/model/ContributionService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/model/ContributionService.java
new file mode 100644
index 0000000..e2b9daa
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/model/ContributionService.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2015 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.ui.internal.model;
+
+import org.eclipse.ui.application.WorkbenchAdvisor;
+import org.eclipse.ui.model.ContributionComparator;
+import org.eclipse.ui.model.IContributionService;
+
+public class ContributionService implements IContributionService {
+
+	private WorkbenchAdvisor advisor;
+
+	/**
+	 * @param advisor
+	 */
+	public ContributionService(WorkbenchAdvisor advisor) {
+		this.advisor = advisor;
+	}
+
+	@Override
+	public ContributionComparator getComparatorFor(String contributionType) {
+		return advisor.getComparatorFor(contributionType);
+	}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/operations/AdvancedValidationUserApprover.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/operations/AdvancedValidationUserApprover.java
new file mode 100644
index 0000000..88a36fc
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/operations/AdvancedValidationUserApprover.java
@@ -0,0 +1,390 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2016 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
+ *     Patrik Suzzi <psuzzi@gmail.com> - Bug 490700
+ *******************************************************************************/
+package org.eclipse.ui.internal.operations;
+
+import java.lang.reflect.InvocationTargetException;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.operations.IAdvancedUndoableOperation;
+import org.eclipse.core.commands.operations.IAdvancedUndoableOperation2;
+import org.eclipse.core.commands.operations.IOperationApprover;
+import org.eclipse.core.commands.operations.IOperationApprover2;
+import org.eclipse.core.commands.operations.IOperationHistory;
+import org.eclipse.core.commands.operations.IUndoContext;
+import org.eclipse.core.commands.operations.IUndoableOperation;
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.core.runtime.IAdaptable;
+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.jface.dialogs.ErrorDialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.window.Window;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.misc.StatusUtil;
+
+/**
+ * <p>
+ * An operation approver that rechecks the validity of a proposed undo or redo
+ * operation using
+ * {@link IAdvancedUndoableOperation#computeUndoableStatus(IProgressMonitor)} or
+ * {@link IAdvancedUndoableOperation#computeRedoableStatus(IProgressMonitor)}.
+ * Some complex operations do not compute their validity in canUndo() or
+ * canRedo() because it is too time-consuming. To save time on complex
+ * validations, the true validity is not determined until it is time to perform
+ * the operation.
+ * </p>
+ * <p>
+ * Since 3.3, this operation approver also checks the validity of a proposed
+ * execute by determining whether the redo is viable.
+ *
+ * @since 3.1
+ */
+public class AdvancedValidationUserApprover implements IOperationApprover,
+		IOperationApprover2 {
+
+    /**
+     * Static to prevent opening of error dialogs for automated testing.
+     *
+     * @since 3.3
+     */
+    public static boolean AUTOMATED_MODE = false;
+
+	private IUndoContext context;
+
+	private static final int EXECUTING = 1;
+
+	private static final int UNDOING = 2;
+
+	private static final int REDOING = 3;
+
+	private class StatusReportingRunnable implements IRunnableWithProgress {
+		IStatus status;
+
+		int doing;
+
+		IUndoableOperation operation;
+
+		IAdaptable uiInfo;
+
+		StatusReportingRunnable(IUndoableOperation operation,
+				IOperationHistory history, IAdaptable uiInfo, int doing) {
+			super();
+			this.operation = operation;
+			this.doing = doing;
+			this.uiInfo = uiInfo;
+		}
+
+		// The casts to IAdvancedUndoableOperation and
+		// IAdvancedUndoableOperation2 are safe because these types were checked
+		// in the call chain.
+		@Override
+		public void run(IProgressMonitor pm) {
+			try {
+				switch (doing) {
+				case UNDOING:
+					status = ((IAdvancedUndoableOperation) operation)
+							.computeUndoableStatus(pm);
+					break;
+				case REDOING:
+					status = ((IAdvancedUndoableOperation) operation)
+							.computeRedoableStatus(pm);
+					break;
+				case EXECUTING:
+					status = ((IAdvancedUndoableOperation2) operation)
+							.computeExecutionStatus(pm);
+					break;
+				}
+
+			} catch (ExecutionException e) {
+				reportException(e, uiInfo);
+				status = IOperationHistory.OPERATION_INVALID_STATUS;
+			}
+		}
+
+		IStatus getStatus() {
+			return status;
+		}
+	}
+
+	/**
+	 * Create an AdvancedValidationUserApprover that performs advanced
+	 * validations on proposed undo and redo operations for a given undo
+	 * context.
+	 *
+	 * @param context -
+	 *            the undo context of operations in question.
+	 */
+	public AdvancedValidationUserApprover(IUndoContext context) {
+		super();
+		this.context = context;
+	}
+
+	@Override
+	public IStatus proceedRedoing(IUndoableOperation operation,
+			IOperationHistory history, IAdaptable uiInfo) {
+		return proceedWithOperation(operation, history, uiInfo, REDOING);
+	}
+
+	@Override
+	public IStatus proceedUndoing(IUndoableOperation operation,
+			IOperationHistory history, IAdaptable uiInfo) {
+
+		return proceedWithOperation(operation, history, uiInfo, UNDOING);
+	}
+
+	@Override
+	public IStatus proceedExecuting(IUndoableOperation operation,
+			IOperationHistory history, IAdaptable uiInfo) {
+		return proceedWithOperation(operation, history, uiInfo, EXECUTING);
+	}
+
+	/*
+	 * Determine whether the operation in question is still valid.
+	 */
+	private IStatus proceedWithOperation(final IUndoableOperation operation,
+			final IOperationHistory history, final IAdaptable uiInfo,
+			final int doing) {
+
+		// return immediately if the operation is not relevant
+		if (!operation.hasContext(context)) {
+			return Status.OK_STATUS;
+		}
+
+		// if the operation does not support advanced validation,
+		// then we assume it is valid.
+		if (doing == EXECUTING) {
+			if (!(operation instanceof IAdvancedUndoableOperation2)) {
+				return Status.OK_STATUS;
+			}
+		} else {
+			if (!(operation instanceof IAdvancedUndoableOperation)) {
+				return Status.OK_STATUS;
+			}
+		}
+
+		// The next two methods make a number of UI calls, so we wrap the
+		// whole thing up in a syncExec.
+		final IStatus[] status = new IStatus[1];
+		PlatformUI.getWorkbench().getDisplay().syncExec(() -> {
+			// Compute the undoable or redoable status
+			status[0] = computeOperationStatus(operation, history, uiInfo,
+					doing);
+
+			// Report non-OK statuses to the user. In some cases, the user
+			// may choose to proceed, and the returned status will be
+			// different than what is reported.
+			if (!status[0].isOK()) {
+				status[0] = reportAndInterpretStatus(status[0], uiInfo,
+						operation, doing);
+			}
+
+		});
+
+		// If the operation is still not OK, inform the history that the
+		// operation has changed, since it was previously believed to be valid.
+		// We rely here on the ability of an IAdvancedUndoableOperation to
+		// correctly report canUndo() and canRedo() once the undoable and
+		// redoable status have been computed.
+		if (!status[0].isOK()) {
+			history.operationChanged(operation);
+		}
+		return status[0];
+	}
+
+	private IStatus computeOperationStatus(IUndoableOperation operation,
+			IOperationHistory history, IAdaptable uiInfo, int doing) {
+		try {
+			StatusReportingRunnable runnable = new StatusReportingRunnable(
+					operation, history, uiInfo, doing);
+			TimeTriggeredProgressMonitorDialog progressDialog = new TimeTriggeredProgressMonitorDialog(
+					getShell(uiInfo), PlatformUI.getWorkbench()
+							.getProgressService().getLongOperationTime());
+
+			progressDialog.run(false, true, runnable);
+			return runnable.getStatus();
+		} catch (OperationCanceledException e) {
+			return Status.CANCEL_STATUS;
+		} catch (InvocationTargetException e) {
+			reportException(e, uiInfo);
+			return IOperationHistory.OPERATION_INVALID_STATUS;
+		} catch (InterruptedException e) {
+			// Operation was cancelled and acknowledged by runnable with this
+			// exception. Do nothing.
+			return Status.CANCEL_STATUS;
+		}
+	}
+
+	/*
+	 * Report the specified execution exception to the log and to the user.
+	 */
+	private void reportException(Exception e, IAdaptable uiInfo) {
+		Throwable nestedException = StatusUtil.getCause(e);
+		Throwable exception = (nestedException == null) ? e : nestedException;
+		String title = WorkbenchMessages.get().Error;
+		String message = WorkbenchMessages.get().WorkbenchWindow_exceptionMessage;
+		String exceptionMessage = exception.getMessage();
+		if (exceptionMessage == null) {
+			exceptionMessage = message;
+		}
+		IStatus status = new Status(IStatus.ERROR,
+				WorkbenchPlugin.PI_WORKBENCH, 0, exceptionMessage, exception);
+		WorkbenchPlugin.log(message, status);
+
+		boolean createdShell = false;
+		Shell shell = getShell(uiInfo);
+		if (shell == null) {
+			createdShell = true;
+			shell = new Shell();
+		}
+		ErrorDialog.openError(shell, title, message, status);
+		if (createdShell) {
+			shell.dispose();
+		}
+	}
+
+	/*
+	 * Report a non-OK status to the user
+	 */
+	private IStatus reportAndInterpretStatus(IStatus status, IAdaptable uiInfo,
+			IUndoableOperation operation, int doing) {
+		// Nothing to report if we are running automated tests.  We will treat
+		// warnings as if they were authorized by the user.
+		if (AUTOMATED_MODE) {
+			if (status.getSeverity() == IStatus.WARNING) {
+				return Status.OK_STATUS;
+			}
+			return status;
+		}
+
+		// CANCEL status is assumed to be initiated by the user, so there
+		// is nothing to report.
+		if (status.getSeverity() == IStatus.CANCEL) {
+			return status;
+		}
+
+		// Other status severities are reported with a message dialog.
+		// First obtain a shell and set up the dialog title.
+		boolean createdShell = false;
+		IStatus reportedStatus = status;
+
+		Shell shell = getShell(uiInfo);
+		if (shell == null) {
+			createdShell = true;
+			shell = new Shell();
+		}
+
+		// Set up the dialog. For non-error statuses, we use a warning dialog
+		// that allows the user to proceed or to cancel out of the operation.
+
+		if (!(status.getSeverity() == IStatus.ERROR)) {
+			String warning, title;
+			switch (doing) {
+			case UNDOING:
+				warning = WorkbenchMessages.get().Operations_proceedWithNonOKUndoStatus;
+				if (status.getSeverity() == IStatus.INFO) {
+					title = WorkbenchMessages.get().Operations_undoInfo;
+				} else {
+					title = WorkbenchMessages.get().Operations_undoWarning;
+				}
+				break;
+			case REDOING:
+				warning = WorkbenchMessages.get().Operations_proceedWithNonOKRedoStatus;
+				if (status.getSeverity() == IStatus.INFO) {
+					title = WorkbenchMessages.get().Operations_redoInfo;
+				} else {
+					title = WorkbenchMessages.get().Operations_redoWarning;
+				}
+				break;
+			default: // EXECUTING
+				warning = WorkbenchMessages.get().Operations_proceedWithNonOKExecuteStatus;
+				if (status.getSeverity() == IStatus.INFO) {
+					title = WorkbenchMessages.get().Operations_executeInfo;
+				} else {
+					title = WorkbenchMessages.get().Operations_executeWarning;
+				}
+				break;
+			}
+
+			String message = NLS.bind(warning, new Object[] { status.getMessage(), operation.getLabel() });
+			String[] buttons = new String[] { IDialogConstants.get().YES_LABEL,
+					IDialogConstants.get().NO_LABEL };
+			MessageDialog dialog = new MessageDialog(shell, title, null,
+					message, MessageDialog.WARNING, buttons, 0);
+			int dialogAnswer = dialog.open();
+			// The user has been given the specific status and has chosen
+			// to proceed or to cancel. The user choice determines what
+			// the status should be at this point, OK or CANCEL.
+			if (dialogAnswer == Window.OK) {
+				reportedStatus = Status.OK_STATUS;
+			} else {
+				reportedStatus = Status.CANCEL_STATUS;
+			}
+		} else {
+			String title, stopped;
+			switch (doing) {
+			case UNDOING:
+				title = WorkbenchMessages.get().Operations_undoProblem;
+				stopped = WorkbenchMessages.get().Operations_stoppedOnUndoErrorStatus;
+				break;
+			case REDOING:
+				title = WorkbenchMessages.get().Operations_redoProblem;
+				stopped = WorkbenchMessages.get().Operations_stoppedOnRedoErrorStatus;
+				break;
+			default: // EXECUTING
+				title = WorkbenchMessages.get().Operations_executeProblem;
+				stopped = WorkbenchMessages.get().Operations_stoppedOnExecuteErrorStatus;
+
+				break;
+			}
+
+			// It is an error condition. The user has no choice to proceed, so
+			// we only report what has gone on. We use a warning icon instead of
+			// an error icon since there has not yet been a failure.
+
+			String message = NLS.bind(stopped, status.getMessage(), operation
+					.getLabel());
+
+			MessageDialog dialog = new MessageDialog(shell, title, null,
+					message, MessageDialog.WARNING,
+					new String[] { IDialogConstants.get().OK_LABEL }, 0); // ok
+			dialog.open();
+		}
+
+		if (createdShell) {
+			shell.dispose();
+		}
+
+		return reportedStatus;
+
+	}
+
+	/*
+	 * Return the shell described by the supplied uiInfo, or null if no shell is
+	 * described.
+	 */
+	Shell getShell(IAdaptable uiInfo) {
+		if (uiInfo != null) {
+			Shell shell = Adapters.adapt(uiInfo, Shell.class);
+			if (shell != null) {
+				return shell;
+			}
+		}
+		return null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/operations/TimeTriggeredProgressMonitorDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/operations/TimeTriggeredProgressMonitorDialog.java
new file mode 100644
index 0000000..2255f66
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/operations/TimeTriggeredProgressMonitorDialog.java
@@ -0,0 +1,181 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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 - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ui.internal.operations;
+
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.dialogs.ProgressMonitorDialog;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * The TimeTriggeredProgressMonitorDialog is a progress monitor dialog that only
+ * opens if the runnable provided exceeds the specified long operation time.
+ *
+ * @since 3.1
+ */
+public class TimeTriggeredProgressMonitorDialog extends ProgressMonitorDialog {
+
+	/**
+	 * The time considered to be the long operation time.
+	 */
+	private int longOperationTime;
+
+	/**
+	 * The time at which the dialog should be opened.
+	 */
+	private long triggerTime = -1;
+
+	/**
+	 * Whether or not we've already opened a dialog.
+	 */
+	private boolean dialogOpened = false;
+
+	/**
+	 * Wrappered monitor so we can check ticks and open the dialog when
+	 * appropriate
+	 */
+	private IProgressMonitor wrapperedMonitor;
+
+	/**
+	 * Create a new instance of the receiver.
+	 *
+	 * @param parent
+	 *            the parent of the dialog
+	 * @param longOperationTime
+	 *            the time (in milliseconds) considered to be a long enough
+	 *            execution time to warrant opening a dialog.
+	 */
+	public TimeTriggeredProgressMonitorDialog(Shell parent,
+			int longOperationTime) {
+		super(parent);
+		setOpenOnRun(false);
+		this.longOperationTime = longOperationTime;
+	}
+
+   /**
+	 * Create a monitor for the receiver that wrappers the superclasses monitor.
+	 *
+	 */
+    public void createWrapperedMonitor() {
+        wrapperedMonitor = new IProgressMonitor() {
+
+            IProgressMonitor superMonitor = TimeTriggeredProgressMonitorDialog.super
+                    .getProgressMonitor();
+
+            @Override
+			public void beginTask(String name, int totalWork) {
+                superMonitor.beginTask(name, totalWork);
+                checkTicking();
+            }
+
+            /**
+			 * Check if we have ticked in the last 800ms.
+			 */
+            private void checkTicking() {
+            	if (triggerTime < 0) {
+					triggerTime = System.currentTimeMillis() + longOperationTime;
+				}
+    			if (!dialogOpened && System.currentTimeMillis() > triggerTime) {
+    				open();
+    				dialogOpened = true;
+    			}
+            }
+
+
+
+            @Override
+			public void done() {
+                superMonitor.done();
+                checkTicking();
+            }
+
+            @Override
+			public void internalWorked(double work) {
+                superMonitor.internalWorked(work);
+                checkTicking();
+            }
+
+            @Override
+			public boolean isCanceled() {
+                return superMonitor.isCanceled();
+            }
+
+            @Override
+			public void setCanceled(boolean value) {
+                superMonitor.setCanceled(value);
+
+            }
+
+            @Override
+			public void setTaskName(String name) {
+                superMonitor.setTaskName(name);
+                checkTicking();
+
+            }
+
+            @Override
+			public void subTask(String name) {
+                superMonitor.subTask(name);
+                checkTicking();
+            }
+
+            @Override
+			public void worked(int work) {
+                superMonitor.worked(work);
+                checkTicking();
+
+            }
+        };
+    }
+
+    @Override
+	public IProgressMonitor getProgressMonitor() {
+        if (wrapperedMonitor == null) {
+			createWrapperedMonitor();
+		}
+        return wrapperedMonitor;
+    }
+
+    @Override
+	public void run(final boolean fork, final boolean cancelable,
+            final IRunnableWithProgress runnable) throws InvocationTargetException,
+            InterruptedException {
+    	final InvocationTargetException[] invokes = new InvocationTargetException[1];
+        final InterruptedException[] interrupt = new InterruptedException[1];
+        Runnable dialogWaitRunnable = () -> {
+			try {
+				TimeTriggeredProgressMonitorDialog.super.run(fork, cancelable, runnable);
+			} catch (InvocationTargetException e1) {
+				invokes[0] = e1;
+			} catch (InterruptedException e2) {
+				interrupt[0]= e2;
+			}
+		};
+        final Display display = PlatformUI.getWorkbench().getDisplay();
+        if (display == null) {
+			return;
+		}
+        //show a busy cursor until the dialog opens
+        BusyIndicator.showWhile(display, dialogWaitRunnable);
+        if (invokes[0] != null) {
+            throw invokes[0];
+        }
+        if (interrupt[0] != null) {
+            throw interrupt[0];
+        }
+     }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/operations/WorkbenchOperationSupport.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/operations/WorkbenchOperationSupport.java
new file mode 100644
index 0000000..3e16359
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/operations/WorkbenchOperationSupport.java
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.operations;
+
+import org.eclipse.core.commands.operations.DefaultOperationHistory;
+import org.eclipse.core.commands.operations.IOperationApprover;
+import org.eclipse.core.commands.operations.IOperationHistory;
+import org.eclipse.core.commands.operations.IUndoContext;
+import org.eclipse.core.commands.operations.ObjectUndoContext;
+import org.eclipse.core.commands.operations.OperationHistoryFactory;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.misc.Policy;
+import org.eclipse.ui.operations.IWorkbenchOperationSupport;
+
+/**
+ * <p>
+ * Provides undoable operation support for the workbench.  This includes  providing access to the default
+ * operation history and installing a workbench-specific operation approver that enforces a linear
+ * undo strategy.
+ * </p>
+ *
+ * @since 3.1
+ */
+public class WorkbenchOperationSupport implements IWorkbenchOperationSupport {
+
+	private ObjectUndoContext undoContext;
+	private IOperationApprover approver;
+
+	// initialize debug options
+	static {
+		DefaultOperationHistory.DEBUG_OPERATION_HISTORY_UNEXPECTED = Policy.DEBUG_OPERATIONS;
+		DefaultOperationHistory.DEBUG_OPERATION_HISTORY_OPENOPERATION = Policy.DEBUG_OPERATIONS;
+		DefaultOperationHistory.DEBUG_OPERATION_HISTORY_APPROVAL = Policy.DEBUG_OPERATIONS;
+		DefaultOperationHistory.DEBUG_OPERATION_HISTORY_NOTIFICATION = Policy.DEBUG_OPERATIONS && Policy.DEBUG_OPERATIONS_VERBOSE;
+		DefaultOperationHistory.DEBUG_OPERATION_HISTORY_DISPOSE = Policy.DEBUG_OPERATIONS && Policy.DEBUG_OPERATIONS_VERBOSE;
+	}
+
+	/**
+	 * Disposes of anything created by the operation support.
+	 */
+	public void dispose() {
+		/*
+		 * uninstall the operation approver that we added to the operation history
+		 */
+		getOperationHistory().removeOperationApprover(approver);
+		/*
+		 * dispose of all operations using our context
+		 */
+		getOperationHistory().dispose(getUndoContext(), true, true, true);
+	}
+
+	/**
+	 * Returns the undo context for workbench operations.
+	 * The workbench configures an undo context with the appropriate policies
+	 * for the workbench undo model.
+	 *
+	 * @return the workbench operation context.
+	 * @since 3.1
+	 */
+	@Override
+	public IUndoContext getUndoContext() {
+		if (undoContext == null) {
+			undoContext = new ObjectUndoContext(PlatformUI.getWorkbench(),
+					"Workbench Context"); //$NON-NLS-1$
+		}
+		return undoContext;
+	}
+
+	/**
+	 * Returns the workbench operation history.
+	 *
+	 * @return the operation history for workbench operations.
+	 * @since 3.1
+	 */
+	@Override
+	public IOperationHistory getOperationHistory() {
+		IOperationHistory history = OperationHistoryFactory.getOperationHistory();
+		/*
+		 * Set up the history if we have not done so before.
+		 */
+		if (approver == null) {
+			/*
+			 * install an operation approver that prevents linear undo violations
+			 * in any context
+			 */
+			approver = new AdvancedValidationUserApprover(getUndoContext());
+			history.addOperationApprover(approver);
+			/*
+			 * set a limit for the workbench undo context
+			 */
+			history.setLimit(getUndoContext(), 25);
+		}
+		return history;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/part/IMultiPageEditorSiteHolder.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/part/IMultiPageEditorSiteHolder.java
new file mode 100644
index 0000000..690ccd6
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/part/IMultiPageEditorSiteHolder.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2008 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.ui.internal.part;
+
+import org.eclipse.ui.part.MultiPageEditorSite;
+
+/**
+ * @since 3.4
+ *
+ */
+public interface IMultiPageEditorSiteHolder {
+	public MultiPageEditorSite getSite();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/part/IPageSiteHolder.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/part/IPageSiteHolder.java
new file mode 100644
index 0000000..611df0f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/part/IPageSiteHolder.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2008 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.ui.internal.part;
+
+import org.eclipse.ui.part.IPageSite;
+
+/**
+ * @since 3.4
+ *
+ */
+public interface IPageSiteHolder {
+	public IPageSite getSite();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/part/NullEditorInput.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/part/NullEditorInput.java
new file mode 100644
index 0000000..398e651
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/part/NullEditorInput.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2016 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.ui.internal.part;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IPersistableElement;
+import org.eclipse.ui.internal.EditorReference;
+
+/**
+ * @since 3.1
+ */
+public class NullEditorInput implements IEditorInput {
+
+	private EditorReference editorReference;
+
+	/**
+	 * Creates a <code>NullEditorInput</code>.
+	 */
+	public NullEditorInput() {
+	}
+
+	/**
+	 * Creates a <code>NullEditorInput</code> for the
+	 * given editor reference.
+	 *
+	 * @param editorReference the editor reference
+	 * @since 3.4
+	 */
+	public NullEditorInput(EditorReference editorReference) {
+		Assert.isLegal(editorReference != null);
+		this.editorReference= editorReference;
+
+	}
+
+    @Override
+	public boolean exists() {
+        return false;
+    }
+
+    @Override
+	public ImageDescriptor getImageDescriptor() {
+        return ImageDescriptor.getMissingImageDescriptor();
+    }
+
+    @Override
+	public String getName() {
+		String result = null;
+		if (editorReference != null) {
+			result = editorReference.getName();
+		}
+		if (result != null) {
+			return result;
+		}
+        return ""; //$NON-NLS-1$
+    }
+
+    @Override
+	public IPersistableElement getPersistable() {
+        return null;
+    }
+
+    @Override
+	public String getToolTipText() {
+		if (editorReference != null)
+			return editorReference.getTitleToolTip();
+        return ""; //$NON-NLS-1$
+    }
+
+    @Override
+	public <T> T getAdapter(Class<T> adapter) {
+        return null;
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/part/StatusPart.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/part/StatusPart.java
new file mode 100644
index 0000000..0553f5f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/part/StatusPart.java
@@ -0,0 +1,216 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.part;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.statushandlers.StatusManager;
+import org.eclipse.ui.views.IViewDescriptor;
+
+/**
+ * @since 3.1
+ */
+public class StatusPart {
+
+	private static final String LOG_VIEW_ID = "org.eclipse.pde.runtime.LogView"; //$NON-NLS-1$
+    boolean showingDetails = false;
+    private Button detailsButton;
+    private Composite detailsArea;
+    private Control details = null;
+	private IStatus reason;
+
+    public StatusPart(final Composite parent, IStatus reason_) {
+    	Color bgColor= parent.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND);
+		Color fgColor= parent.getDisplay().getSystemColor(SWT.COLOR_LIST_FOREGROUND);
+
+		parent.setBackground(bgColor);
+		parent.setForeground(fgColor);
+
+        this.reason = reason_;
+        GridLayout layout = new GridLayout();
+
+		layout.numColumns = 3;
+
+        int spacing = 8;
+        int margins = 8;
+        layout.marginBottom = margins;
+        layout.marginTop = margins;
+        layout.marginLeft = margins;
+        layout.marginRight = margins;
+        layout.horizontalSpacing = spacing;
+        layout.verticalSpacing = spacing;
+        parent.setLayout(layout);
+
+        Label imageLabel = new Label(parent, SWT.NONE);
+        imageLabel.setBackground(bgColor);
+        Image image = getImage();
+        if (image != null) {
+            image.setBackground(bgColor);
+            imageLabel.setImage(image);
+			GridData gridData = new GridData(GridData.HORIZONTAL_ALIGN_CENTER | GridData.VERTICAL_ALIGN_BEGINNING);
+			imageLabel.setLayoutData(gridData);
+        }
+
+        Text text = new Text(parent, SWT.MULTI | SWT.READ_ONLY | SWT.WRAP);
+        text.setBackground(bgColor);
+        text.setForeground(fgColor);
+
+		text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+        text.setText(reason.getMessage());
+
+        Composite buttonParent = new Composite(parent, SWT.NONE);
+        buttonParent.setBackground(parent.getBackground());
+        GridLayout buttonsLayout = new GridLayout();
+        buttonsLayout.numColumns = 2;
+        buttonsLayout.marginHeight = 0;
+        buttonsLayout.marginWidth  = 0;
+        buttonsLayout.horizontalSpacing = 0;
+		buttonParent.setLayout(buttonsLayout);
+
+
+        detailsButton = new Button(buttonParent, SWT.PUSH);
+        detailsButton.addSelectionListener(new SelectionAdapter()
+        {
+            /** {@inheritDoc} */
+            @Override
+            public void widgetSelected(SelectionEvent e)
+            {
+                showDetails(!showingDetails);
+            }
+        });
+
+        detailsButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.FILL, false, false));
+        detailsButton.setVisible(reason.getException() != null);
+
+        createShowLogButton(buttonParent);
+
+        updateDetailsText();
+
+        detailsArea = new Composite(parent, SWT.NONE);
+        detailsArea.setBackground(bgColor);
+        detailsArea.setForeground(fgColor);
+        GridData data = new GridData(GridData.FILL_BOTH);
+        data.horizontalSpan = 3;
+        data.verticalSpan = 1;
+        detailsArea.setLayoutData(data);
+        detailsArea.setLayout(new FillLayout());
+        parent.layout(true);
+    }
+
+    /**
+     * Return the image for the upper-left corner of this part
+     *
+     * @return the image
+     */
+    private Image getImage() {
+        Display d = Display.getCurrent();
+
+        switch(reason.getSeverity()) {
+        case IStatus.ERROR:
+            return d.getSystemImage(SWT.ICON_ERROR);
+        case IStatus.WARNING:
+            return d.getSystemImage(SWT.ICON_WARNING);
+        default:
+            return d.getSystemImage(SWT.ICON_INFORMATION);
+        }
+    }
+
+    private void showDetails(boolean shouldShow) {
+        if (shouldShow == showingDetails) {
+            return;
+        }
+        this.showingDetails = shouldShow;
+        updateDetailsText();
+    }
+
+    private void updateDetailsText() {
+        if (details != null) {
+            details.dispose();
+            details = null;
+        }
+
+        if (showingDetails) {
+            detailsButton.setText(IDialogConstants.get().HIDE_DETAILS_LABEL);
+            Text detailsText = new Text(detailsArea, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL
+                    | SWT.MULTI | SWT.READ_ONLY | SWT.LEFT_TO_RIGHT);
+            detailsText.setText(getDetails(reason));
+			detailsText.setBackground(detailsText.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
+            details = detailsText;
+            detailsArea.layout(true);
+        } else {
+            detailsButton.setText(IDialogConstants.get().SHOW_DETAILS_LABEL);
+        }
+    }
+
+
+    private String getDetails(IStatus status) {
+        if (status.getException() != null) {
+            return getStackTrace(status.getException());
+        }
+
+        return ""; //$NON-NLS-1$
+    }
+
+    private String getStackTrace(Throwable throwable) {
+        StringWriter swriter = new StringWriter();
+        PrintWriter pwriter = new PrintWriter(swriter);
+        throwable.printStackTrace(pwriter);
+        pwriter.flush();
+        pwriter.close();
+        return swriter.toString();
+    }
+
+    private void createShowLogButton(Composite parent){
+		IViewDescriptor descriptor = PlatformUI.getWorkbench().getViewRegistry().find(LOG_VIEW_ID);
+		if (descriptor == null) {
+			return;
+		}
+		Button button = new Button(parent, SWT.PUSH);
+		button.addSelectionListener(new SelectionAdapter()
+        {
+            /** {@inheritDoc} */
+            @Override
+            public void widgetSelected(SelectionEvent e)
+            {
+    			try {
+    				PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().showView(LOG_VIEW_ID);
+    			} catch (CoreException ce) {
+    				StatusManager.getManager().handle(ce, WorkbenchPlugin.PI_WORKBENCH);
+    			}
+            }
+		});
+		final Image image = descriptor.getImageDescriptor().createImage();
+		button.setImage(image);
+		button.setToolTipText(WorkbenchMessages.get().ErrorLogUtil_ShowErrorLogTooltip);
+		button.addDisposeListener(e -> image.dispose());
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/AbstractBooleanListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/AbstractBooleanListener.java
new file mode 100644
index 0000000..14a48e2
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/AbstractBooleanListener.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2006 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.ui.internal.preferences;
+
+/**
+ */
+public abstract class AbstractBooleanListener extends AbstractPropertyListener {
+
+    private IDynamicPropertyMap map;
+    private boolean defaultValue;
+    private String propertyId;
+    
+    public AbstractBooleanListener() {
+    }
+    
+    public void attach(IDynamicPropertyMap map, String propertyId, boolean defaultValue) {
+        this.defaultValue = defaultValue;
+        this.propertyId = propertyId;
+        if (this.map != null) {
+            this.map.removeListener(this);
+        }
+        
+        this.map = map;
+        
+        if (this.map != null) {
+            this.map.addListener(new String[]{propertyId}, this);
+        }
+    }
+
+    /* (non-Javadoc)
+     * @see org.eclipse.ui.internal.preferences.AbstractPropertyListener#update()
+     */
+    protected void update() {
+        handleValue(PropertyUtil.get(map, propertyId, defaultValue));
+    }
+
+    /**
+     * @param b
+     */
+    protected abstract void handleValue(boolean b);
+   
+    
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/AbstractIntegerListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/AbstractIntegerListener.java
new file mode 100644
index 0000000..f37f6ba
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/AbstractIntegerListener.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.preferences;
+
+/**
+ * @since 3.1
+ */
+public abstract class AbstractIntegerListener extends AbstractPropertyListener {
+
+    private IDynamicPropertyMap map;
+    private int defaultValue;
+    private String propertyId;
+
+    public AbstractIntegerListener() {
+    }
+
+    public void attach(IDynamicPropertyMap map, String propertyId, int defaultValue) {
+        this.defaultValue = defaultValue;
+        this.propertyId = propertyId;
+        if (this.map != null) {
+            this.map.removeListener(this);
+        }
+
+        this.map = map;
+
+        if (this.map != null) {
+            this.map.addListener(new String[]{propertyId}, this);
+        }
+    }
+
+    @Override
+	protected void update() {
+        handleValue(PropertyUtil.get(map, propertyId, defaultValue));
+    }
+
+    /**
+     * @param b
+     * @since 3.1
+     */
+    protected abstract void handleValue(int b);
+
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/AbstractPropertyListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/AbstractPropertyListener.java
new file mode 100644
index 0000000..dde9547
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/AbstractPropertyListener.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.preferences;
+
+/**
+ * @since 3.1
+ */
+public abstract class AbstractPropertyListener implements IPropertyMapListener {
+
+    @Override
+	public void propertyChanged(String[] propertyIds) {
+        update();
+    }
+
+    @Override
+	public void listenerAttached() {
+        update();
+    }
+
+    protected abstract void update();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/Base64.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/Base64.java
new file mode 100644
index 0000000..f02ef9e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/Base64.java
@@ -0,0 +1,214 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.preferences;
+
+/**
+ * Base64 is a helper class for converting byte arrays to and
+ * from base 64 encoded Strings.
+ *
+ */
+//RAP [bm]: made public to allow access from org.eclipse.rap.ui
+//class Base64 {
+public class Base64{
+
+	private static final byte equalSign = (byte) '=';
+
+	static char digits[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', //
+			'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', //
+			'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', //
+			'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
+
+	/**
+	 * This method decodes the byte array in base 64 encoding into a char array
+	 * Base 64 encoding has to be according to the specification given by the
+	 * RFC 1521 (5.2).
+	 *
+	 * @param data the encoded byte array
+	 * @return the decoded byte array
+	 */
+	public static byte[] decode(byte[] data) {
+		if (data.length == 0) {
+			return data;
+		}
+		int lastRealDataIndex = data.length - 1;
+		while (data[lastRealDataIndex] == equalSign) {
+			lastRealDataIndex--;
+		}
+		// original data digit is 8 bits long, but base64 digit is 6 bits long
+		int padBytes = data.length - 1 - lastRealDataIndex;
+		int byteLength = data.length * 6 / 8 - padBytes;
+		byte[] result = new byte[byteLength];
+		// Each 4 bytes of input (encoded) we end up with 3 bytes of output
+		int dataIndex = 0;
+		int resultIndex = 0;
+		int allBits = 0;
+		// how many result chunks we can process before getting to pad bytes
+		int resultChunks = (lastRealDataIndex + 1) / 4;
+		for (int i = 0; i < resultChunks; i++) {
+			allBits = 0;
+			// Loop 4 times gathering input bits (4 * 6 = 24)
+			for (int j = 0; j < 4; j++) {
+				allBits = (allBits << 6) | decodeDigit(data[dataIndex++]);
+			}
+			// Loop 3 times generating output bits (3 * 8 = 24)
+			for (int j = resultIndex + 2; j >= resultIndex; j--) {
+				result[j] = (byte) (allBits & 0xff); // Bottom 8 bits
+				allBits = allBits >>> 8;
+			}
+			resultIndex += 3; // processed 3 result bytes
+		}
+		// Now we do the extra bytes in case the original (non-encoded) data
+		// was not multiple of 3 bytes
+		switch (padBytes) {
+			case 1 :
+				// 1 pad byte means 3 (4-1) extra Base64 bytes of input, 18
+				// bits, of which only 16 are meaningful
+				// Or: 2 bytes of result data
+				allBits = 0;
+				// Loop 3 times gathering input bits
+				for (int j = 0; j < 3; j++) {
+					allBits = (allBits << 6) | decodeDigit(data[dataIndex++]);
+				}
+				// NOTE - The code below ends up being equivalent to allBits =
+				// allBits>>>2
+				// But we code it in a non-optimized way for clarity
+				// The 4th, missing 6 bits are all 0
+				allBits = allBits << 6;
+				// The 3rd, missing 8 bits are all 0
+				allBits = allBits >>> 8;
+				// Loop 2 times generating output bits
+				for (int j = resultIndex + 1; j >= resultIndex; j--) {
+					result[j] = (byte) (allBits & 0xff); // Bottom 8
+					// bits
+					allBits = allBits >>> 8;
+				}
+				break;
+			case 2 :
+				// 2 pad bytes mean 2 (4-2) extra Base64 bytes of input, 12 bits
+				// of data, of which only 8 are meaningful
+				// Or: 1 byte of result data
+				allBits = 0;
+				// Loop 2 times gathering input bits
+				for (int j = 0; j < 2; j++) {
+					allBits = (allBits << 6) | decodeDigit(data[dataIndex++]);
+				}
+				// NOTE - The code below ends up being equivalent to allBits =
+				// allBits>>>4
+				// But we code it in a non-optimized way for clarity
+				// The 3rd and 4th, missing 6 bits are all 0
+				allBits = allBits << 6;
+				allBits = allBits << 6;
+				// The 3rd and 4th, missing 8 bits are all 0
+				allBits = allBits >>> 8;
+				allBits = allBits >>> 8;
+				result[resultIndex] = (byte) (allBits & 0xff); // Bottom
+				// 8
+				// bits
+				break;
+		}
+		return result;
+	}
+
+	/**
+	 * This method converts a Base 64 digit to its numeric value.
+	 *
+	 * @param data digit (character) to convert
+	 * @return value for the digit
+	 */
+	static int decodeDigit(byte data) {
+		char charData = (char) data;
+		if (charData <= 'Z' && charData >= 'A') {
+			return charData - 'A';
+		}
+		if (charData <= 'z' && charData >= 'a') {
+			return charData - 'a' + 26;
+		}
+		if (charData <= '9' && charData >= '0') {
+			return charData - '0' + 52;
+		}
+		switch (charData) {
+			case '+' :
+				return 62;
+			case '/' :
+				return 63;
+			default :
+				throw new IllegalArgumentException("Invalid char to decode: " + data); //$NON-NLS-1$
+		}
+	}
+
+	/**
+	 * This method encodes the byte array into a char array in base 64 according
+	 * to the specification given by the RFC 1521 (5.2).
+	 *
+	 * @param data the encoded char array
+	 * @return the byte array that needs to be encoded
+	 */
+	public static byte[] encode(byte[] data) {
+		int sourceChunks = data.length / 3;
+		int len = ((data.length + 2) / 3) * 4;
+		byte[] result = new byte[len];
+		int extraBytes = data.length - (sourceChunks * 3);
+		// Each 4 bytes of input (encoded) we end up with 3 bytes of output
+		int dataIndex = 0;
+		int resultIndex = 0;
+		int allBits = 0;
+		for (int i = 0; i < sourceChunks; i++) {
+			allBits = 0;
+			// Loop 3 times gathering input bits (3 * 8 = 24)
+			for (int j = 0; j < 3; j++) {
+				allBits = (allBits << 8) | (data[dataIndex++] & 0xff);
+			}
+			// Loop 4 times generating output bits (4 * 6 = 24)
+			for (int j = resultIndex + 3; j >= resultIndex; j--) {
+				result[j] = (byte) digits[(allBits & 0x3f)]; // Bottom
+				// 6
+				// bits
+				allBits = allBits >>> 6;
+			}
+			resultIndex += 4; // processed 4 result bytes
+		}
+		// Now we do the extra bytes in case the original (non-encoded) data
+		// is not multiple of 4 bytes
+		switch (extraBytes) {
+			case 1 :
+				allBits = data[dataIndex++]; // actual byte
+				allBits = allBits << 8; // 8 bits of zeroes
+				allBits = allBits << 8; // 8 bits of zeroes
+				// Loop 4 times generating output bits (4 * 6 = 24)
+				for (int j = resultIndex + 3; j >= resultIndex; j--) {
+					result[j] = (byte) digits[(allBits & 0x3f)]; // Bottom
+					// 6
+					// bits
+					allBits = allBits >>> 6;
+				}
+				// 2 pad tags
+				result[result.length - 1] = (byte) '=';
+				result[result.length - 2] = (byte) '=';
+				break;
+			case 2 :
+				allBits = data[dataIndex++]; // actual byte
+				allBits = (allBits << 8) | (data[dataIndex++] & 0xff); // actual
+				// byte
+				allBits = allBits << 8; // 8 bits of zeroes
+				// Loop 4 times generating output bits (4 * 6 = 24)
+				for (int j = resultIndex + 3; j >= resultIndex; j--) {
+					result[j] = (byte) digits[(allBits & 0x3f)]; // Bottom
+					// 6
+					// bits
+					allBits = allBits >>> 6;
+				}
+				// 1 pad tag
+				result[result.length - 1] = (byte) '=';
+				break;
+		}
+		return result;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/IDynamicPropertyMap.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/IDynamicPropertyMap.java
new file mode 100644
index 0000000..fd80510
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/IDynamicPropertyMap.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.preferences;
+
+/**
+ * @since 3.1
+ */
+public interface IDynamicPropertyMap extends IPropertyMap {
+    /**
+     * Attaches a property map listener to this map. The listener will be notified
+     * whenever one of the properties in the map is changed, added, or removed.
+     *
+     * @param listener
+     * @since 3.1
+     */
+    public void addListener(IPropertyMapListener listener);
+
+    /**
+     * Attaches a listener that will receive notifications when any
+     * of the given properties change. If an identical listener is already registered,
+     * then this will add additional IDs to the set of properties being monitored
+     * by the given listener.
+     *
+     * @param listener
+     * @param propertyIds
+     * @since 3.1
+     */
+    public void addListener(String[] propertyIds, IPropertyMapListener listener);
+
+    /**
+     * Removes a property map listener from this map . The listener will no longer
+     * be notified whenever one of the properties in the map is changed, added, or removed.
+     *
+     * @param listener
+     * @since 3.1
+     */
+    public void removeListener(IPropertyMapListener listener);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/IPropertyMap.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/IPropertyMap.java
new file mode 100644
index 0000000..3125eb8
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/IPropertyMap.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.preferences;
+
+import java.util.Set;
+
+/**
+ * Eclipse provides many different classes and interfaces that map ids onto values and
+ * send property change notifications (some examples are themes, preference stores,
+ * xml nodes, property providers, and others). This interface is intended to provide
+ * interoperability between these various classes.
+ *
+ * @since 3.1
+ */
+public interface IPropertyMap {
+
+    /**
+     * Returns the set of keys that are recognized by this property map
+     * (optional operation).
+     *
+     * @return the set of valid keys for this map
+     * @throws UnsupportedOperationException if this type of property map
+     * cannot compute the set of valid keys
+     * @since 3.1
+     */
+    public Set keySet();
+
+    /**
+     * Returns the value of the given property. Returns null if the given
+     * property does not exist, cannot be converted into the expected type,
+     * or if the value of the property is null.
+     *
+     * @param propertyId property ID to query
+     * @param propertyType type of the expected return value
+     * @return an object of the given propertyType or null if the property
+     * does not exist or has the wrong type
+     * @since 3.1
+     */
+    public Object getValue(String propertyId, Class propertyType);
+
+    /**
+     * If this map represents the union of multiple property maps, this
+     * returns true iff the property existed in every map in the union.
+     * Always returns true if this map was not computed from the union
+     * of multiple maps.
+     *
+     * @param propertyId
+     * @return true iff the given property existed in every child map
+     * @since 3.1
+     */
+    public boolean isCommonProperty(String propertyId);
+
+    /**
+     * Returns true iff the given property exists.
+     *
+     * @param propertyId
+     * @return true iff the given property exists in this map
+     * @since 3.1
+     */
+    public boolean propertyExists(String propertyId);
+
+    /**
+     * Sets the value of the given property to the given value (optional
+     * operation).
+     *
+     * @param propertyId
+     * @param newValue
+     * @throws UnsupportedOperationException if this type of property map
+     * is read-only
+     * @since 3.1
+     */
+    public void setValue(String propertyId, Object newValue);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/IPropertyMapListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/IPropertyMapListener.java
new file mode 100644
index 0000000..ba24ad3
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/IPropertyMapListener.java
@@ -0,0 +1,19 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2006 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.ui.internal.preferences;
+
+/**
+ * @since 3.1
+ */
+public interface IPropertyMapListener {
+    public void propertyChanged(String[] propertyIds);
+    public void listenerAttached();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/PreferenceStoreAdapter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/PreferenceStoreAdapter.java
new file mode 100644
index 0000000..b587376
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/PreferenceStoreAdapter.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.preferences;
+
+import java.util.Set;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.util.IPropertyChangeListener;
+
+/**
+ * @since 3.1
+ */
+public final class PreferenceStoreAdapter extends PropertyMapAdapter {
+
+    private IPreferenceStore store;
+
+    private IPropertyChangeListener listener = event -> firePropertyChange(event.getProperty());
+
+    public PreferenceStoreAdapter(IPreferenceStore toConvert) {
+        this.store = toConvert;
+    }
+
+    @Override
+	protected void attachListener() {
+        store.addPropertyChangeListener(listener);
+    }
+
+    @Override
+	protected void detachListener() {
+        store.removePropertyChangeListener(listener);
+    }
+
+    @Override
+	public Set keySet() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+	public Object getValue(String propertyId, Class propertyType) {
+        if (propertyType.isAssignableFrom(String.class)) {
+            return store.getString(propertyId);
+        }
+
+        if (propertyType == Boolean.class) {
+            return store.getBoolean(propertyId) ? Boolean.TRUE : Boolean.FALSE;
+        }
+
+        if (propertyType == Double.class) {
+            return new Double(store.getDouble(propertyId));
+        }
+
+        if (propertyType == Float.class) {
+            return new Float(store.getFloat(propertyId));
+        }
+
+        if (propertyType == Integer.class) {
+			return Integer.valueOf(store.getInt(propertyId));
+        }
+
+        if (propertyType == Long.class) {
+            return new Long(store.getLong(propertyId));
+        }
+
+        return null;
+    }
+
+    @Override
+	public boolean propertyExists(String propertyId) {
+        return store.contains(propertyId);
+    }
+
+    @Override
+	public void setValue(String propertyId, Object newValue) {
+        if (newValue instanceof String) {
+            store.setValue(propertyId, (String)newValue);
+        } else if (newValue instanceof Integer) {
+            store.setValue(propertyId, ((Integer)newValue).intValue());
+        } else if (newValue instanceof Boolean) {
+            store.setValue(propertyId, ((Boolean)newValue).booleanValue());
+        } else if (newValue instanceof Double) {
+            store.setValue(propertyId, ((Double)newValue).doubleValue());
+        } else if (newValue instanceof Float) {
+            store.setValue(propertyId, ((Float)newValue).floatValue());
+        } else if (newValue instanceof Integer) {
+            store.setValue(propertyId, ((Integer)newValue).intValue());
+        } else if (newValue instanceof Long) {
+            store.setValue(propertyId, ((Long)newValue).longValue());
+        }
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/PreferenceTransferElement.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/PreferenceTransferElement.java
new file mode 100644
index 0000000..eafdee7
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/PreferenceTransferElement.java
@@ -0,0 +1,185 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.preferences;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.preferences.IPreferenceFilter;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.IPluginContribution;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.registry.PreferenceTransferRegistryReader;
+import org.eclipse.ui.internal.registry.RegistryReader;
+import org.eclipse.ui.model.WorkbenchAdapter;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+/**
+ * Instances represent registered preference transfers.
+ *
+ * @since 3.1
+ */
+public class PreferenceTransferElement extends WorkbenchAdapter implements
+		IPluginContribution {
+	private String id;
+
+	private ImageDescriptor imageDescriptor;
+
+	private IConfigurationElement configurationElement;
+
+	private IPreferenceFilter filter;
+
+	/**
+	 * Create a new instance of this class
+	 *
+	 * @param configurationElement
+	 *
+	 */
+	public PreferenceTransferElement(IConfigurationElement configurationElement) {
+		this.configurationElement = configurationElement;
+		id = configurationElement
+				.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+	}
+
+	/**
+	 * @return IConfigurationElement
+	 */
+	public IConfigurationElement getConfigurationElement() {
+		return configurationElement;
+	}
+
+	/**
+	 * Answer the preference filter of this element.
+	 *
+	 * @return a preference filter
+	 * @throws CoreException
+	 */
+	public IPreferenceFilter getFilter() throws CoreException {
+		if (filter == null) {
+			IConfigurationElement[] mappingConfigurations = PreferenceTransferRegistryReader
+					.getMappings(configurationElement);
+			int size = mappingConfigurations.length;
+			Set scopes = new HashSet(size);
+			Map mappingsMap = new HashMap(size);
+			for (int i = 0; i < size; i++) {
+				String scope = PreferenceTransferRegistryReader
+						.getScope(mappingConfigurations[i]);
+				scopes.add(scope);
+
+				Map mappings;
+				if (!mappingsMap.containsKey(scope)) {
+					mappings = new HashMap(size);
+					mappingsMap.put(scope, mappings);
+				} else {
+					mappings = (Map) mappingsMap.get(scope);
+					if (mappings == null) {
+						continue;
+					}
+				}
+
+				Map entries = PreferenceTransferRegistryReader
+						.getEntry(mappingConfigurations[i]);
+				if (entries == null) {
+					mappingsMap.put(scope, null);
+				} else {
+					mappings.putAll(entries);
+				}
+			}
+			filter = new PreferenceFilter((String[]) scopes
+					.toArray(new String[scopes.size()]), mappingsMap);
+		}
+		return filter;
+	}
+
+	/**
+	 * Answer the description parameter of this element
+	 *
+	 * @return java.lang.String
+	 */
+	public String getDescription() {
+		return RegistryReader.getDescription(configurationElement);
+	}
+
+	/**
+	 * Answer the id as specified in the extension.
+	 *
+	 * @return java.lang.String
+	 */
+	public String getID() {
+		return id;
+	}
+
+	/**
+	 * Returns the name of this preference transfer element.
+	 *
+	 * @return the name of the element
+	 */
+	public String getName() {
+		return configurationElement
+				.getAttribute(IWorkbenchRegistryConstants.ATT_NAME);
+	}
+
+	@Override
+	public String getLocalId() {
+		return getID();
+	}
+
+	@Override
+	public String getPluginId() {
+		return (configurationElement != null) ? configurationElement
+				.getContributor().getName() : null;
+	}
+
+	class PreferenceFilter implements IPreferenceFilter {
+
+		private String[] scopes;
+		private Map mappings;
+
+		public PreferenceFilter(String[] scopes, Map mappings) {
+			this.scopes = scopes;
+			this.mappings = mappings;
+		}
+
+		@Override
+		public String[] getScopes() {
+			return scopes;
+		}
+
+		@Override
+		public Map getMapping(String scope) {
+			return (Map) mappings.get(scope);
+		}
+
+	}
+
+	@Override
+	public String getLabel(Object object) {
+		return getName();
+	}
+
+	@Override
+	public ImageDescriptor getImageDescriptor(Object object) {
+		if (imageDescriptor == null) {
+			String iconName = configurationElement
+					.getAttribute(IWorkbenchRegistryConstants.ATT_ICON);
+			if (iconName == null) {
+				return null;
+			}
+			imageDescriptor = AbstractUIPlugin.imageDescriptorFromPlugin(
+					getPluginId(), iconName);
+		}
+		return imageDescriptor;
+
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/PreferenceTransferManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/PreferenceTransferManager.java
new file mode 100644
index 0000000..41ee166
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/PreferenceTransferManager.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2006 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.ui.internal.preferences;
+
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.registry.PreferenceTransferRegistryReader;
+
+/**
+ * Manages preference transfer support for the workbench
+ *
+ * @since 3.1
+ */
+public class PreferenceTransferManager {
+
+    /**
+     * Return an array of <code>IPreferenceTransfer</code> objects
+     * @return an array of <code>IPreferenceTransfer</code> objects
+     */
+    public static PreferenceTransferElement[] getPreferenceTransfers() {
+        return new PreferenceTransferRegistryReader(
+                    IWorkbenchRegistryConstants.PL_PREFERENCE_TRANSFER)
+                    .getPreferenceTransfers();
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/PreferencesAdapter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/PreferencesAdapter.java
new file mode 100644
index 0000000..e8af82e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/PreferencesAdapter.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.preferences;
+
+import java.util.HashSet;
+import java.util.Set;
+import org.eclipse.core.runtime.Preferences;
+
+/**
+ * @since 3.1
+ */
+public final class PreferencesAdapter extends PropertyMapAdapter {
+    private Preferences store;
+
+    private Preferences.IPropertyChangeListener listener = event -> firePropertyChange(event.getProperty());
+
+    public PreferencesAdapter(Preferences toConvert) {
+        this.store = toConvert;
+    }
+
+    @Override
+	protected void attachListener() {
+        store.addPropertyChangeListener(listener);
+    }
+
+    @Override
+	protected void detachListener() {
+        store.removePropertyChangeListener(listener);
+    }
+
+    @Override
+	public Set keySet() {
+        Set result = new HashSet();
+
+		for (String name : store.propertyNames()) {
+			result.add(name);
+        }
+
+        return result;
+    }
+
+    @Override
+	public Object getValue(String propertyId, Class propertyType) {
+        if (propertyType.isAssignableFrom(String.class)) {
+            return store.getString(propertyId);
+        }
+
+        if (propertyType == Boolean.class) {
+            return store.getBoolean(propertyId) ? Boolean.TRUE : Boolean.FALSE;
+        }
+
+        if (propertyType == Double.class) {
+            return new Double(store.getDouble(propertyId));
+        }
+
+        if (propertyType == Float.class) {
+            return new Float(store.getFloat(propertyId));
+        }
+
+        if (propertyType == Integer.class) {
+			return Integer.valueOf(store.getInt(propertyId));
+        }
+
+        if (propertyType == Long.class) {
+            return new Long(store.getLong(propertyId));
+        }
+
+        return null;
+    }
+
+    @Override
+	public boolean propertyExists(String propertyId) {
+        return store.contains(propertyId);
+    }
+
+    @Override
+	public void setValue(String propertyId, Object newValue) {
+        if (newValue instanceof String) {
+            store.setValue(propertyId, (String)newValue);
+        } else if (newValue instanceof Integer) {
+            store.setValue(propertyId, ((Integer)newValue).intValue());
+        } else if (newValue instanceof Boolean) {
+            store.setValue(propertyId, ((Boolean)newValue).booleanValue());
+        } else if (newValue instanceof Double) {
+            store.setValue(propertyId, ((Double)newValue).doubleValue());
+        } else if (newValue instanceof Float) {
+            store.setValue(propertyId, ((Float)newValue).floatValue());
+        } else if (newValue instanceof Integer) {
+            store.setValue(propertyId, ((Integer)newValue).intValue());
+        } else if (newValue instanceof Long) {
+            store.setValue(propertyId, ((Long)newValue).longValue());
+        }
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/PreferencesSettingsTransfer.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/PreferencesSettingsTransfer.java
new file mode 100644
index 0000000..fe9df07
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/PreferencesSettingsTransfer.java
@@ -0,0 +1,76 @@
+package org.eclipse.ui.internal.preferences;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchMessages;
+
+/**
+ * The PreferenceSettingsTransfer is the settings transfer for the workbench
+ * preferences.
+ *
+ * @since 3.110
+ *
+ */
+public class PreferencesSettingsTransfer extends WorkbenchSettingsTransfer{
+
+	@Override
+	public IStatus transferSettings(IPath newWorkspaceRoot) {
+		File srcFolder = new File(getOldPath().toOSString());
+		File destFolder = new File(getNewPath(newWorkspaceRoot).toOSString());
+
+		if (!destFolder.exists()) {
+			destFolder.mkdirs();
+		}
+
+		if (srcFolder.isDirectory()) {
+			for (String file : srcFolder.list()) {
+				File srcFile = new File(srcFolder.getPath().toString(), file);
+				File destFile = new File(destFolder.getPath().toString(), file);
+
+				try {
+					copyFiles(srcFile, destFile);
+				} catch (IOException e) {
+					return new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, e.getMessage());
+				}
+			}
+		}
+		return Status.OK_STATUS;
+	}
+
+	private void copyFiles(File src, File dest) throws IOException {
+		FileInputStream fis = new FileInputStream(src);
+		FileOutputStream fos = new FileOutputStream(dest);
+
+		byte[] buffer = new byte[1024];
+
+		int length;
+		while ((length = fis.read(buffer)) > 0) {
+			fos.write(buffer, 0, length);
+		}
+
+		fis.close();
+		fos.close();
+	}
+
+	@Override
+	public String getName() {
+		return WorkbenchMessages.get().WorkbenchPreferences_Name;
+	}
+
+	private IPath getNewPath(IPath newWorkspaceRoot) {
+		return newWorkspaceRoot.append(new Path(".metadata/.plugins/org.eclipse.core.runtime/.settings")); //$NON-NLS-1$
+	}
+
+	private IPath getOldPath() {
+		return Platform.getLocation().append(new Path(".metadata/.plugins/org.eclipse.core.runtime/.settings")); //$NON-NLS-1$
+	}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/PropertyListenerList.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/PropertyListenerList.java
new file mode 100644
index 0000000..c4979c7
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/PropertyListenerList.java
@@ -0,0 +1,189 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.preferences;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @since 3.1
+ */
+public final class PropertyListenerList {
+    private Map listeners;
+    private List globalListeners;
+    private static String[] singlePropertyDelta;
+    private static Object mutex = new Object();
+
+    public PropertyListenerList() {
+    }
+
+    public void firePropertyChange(String prefId) {
+        String[] delta;
+
+        // Optimization: as long as we're not being called recursively,
+        // we can reuse the same delta object to avoid repeated memory
+        // allocation.
+        synchronized(mutex) {
+	        if (singlePropertyDelta != null) {
+	            delta = singlePropertyDelta;
+	            singlePropertyDelta = null;
+	        } else {
+	            delta = new String[] {prefId};
+	        }
+        }
+
+        delta[0] = prefId;
+
+        firePropertyChange(delta);
+
+        // Optimization: allow this same delta object to be reused at a later
+        // time
+        if (singlePropertyDelta == null) {
+	        synchronized(mutex) {
+	            singlePropertyDelta = delta;
+	        }
+        }
+    }
+
+    public void firePropertyChange(String[] propertyIds) {
+        if (globalListeners != null) {
+            for (Iterator iter = globalListeners.iterator(); iter.hasNext();) {
+                IPropertyMapListener next = (IPropertyMapListener) iter.next();
+
+                next.propertyChanged(propertyIds);
+            }
+        }
+
+        if (listeners != null) {
+
+            // To avoid temporary memory allocation, we try to simply move the
+            // result pointer around if possible. We only allocate a HashSet
+            // to compute which listeners we care about
+            Collection result = Collections.EMPTY_SET;
+            HashSet union = null;
+
+            for (String property : propertyIds) {
+                List existingListeners = (List)listeners.get(property);
+
+    	        if (existingListeners != null) {
+    	            if (result == Collections.EMPTY_SET) {
+    	                result = existingListeners;
+    	            } else {
+    	                if (union == null) {
+    	                    union = new HashSet();
+    	                    union.addAll(result);
+    	                    result = union;
+    	                }
+
+    	                union.addAll(existingListeners);
+    	            }
+    	        }
+            }
+
+            for (Iterator iter = result.iterator(); iter.hasNext();) {
+                IPropertyMapListener next = (IPropertyMapListener) iter.next();
+
+                next.propertyChanged(propertyIds);
+            }
+        }
+    }
+
+    public void add(IPropertyMapListener newListener) {
+        if (globalListeners == null) {
+            globalListeners = new ArrayList();
+        }
+
+        globalListeners.add(newListener);
+        newListener.listenerAttached();
+    }
+
+    /**
+     * Adds a listener which will be notified when the given property changes
+     *
+     * @param propertyId
+     * @param newListener
+     * @since 3.1
+     */
+    private void addInternal(String propertyId, IPropertyMapListener newListener) {
+        if (listeners == null) {
+            listeners = new HashMap();
+        }
+
+        List listenerList = (List)listeners.get(propertyId);
+
+        if (listenerList == null) {
+            listenerList = new ArrayList(1);
+            listeners.put(propertyId, listenerList);
+        }
+
+        if (!listenerList.contains(newListener)) {
+            listenerList.add(newListener);
+        }
+    }
+
+    public void add(String[] propertyIds, IPropertyMapListener newListener) {
+        for (String id : propertyIds) {
+            addInternal(id, newListener);
+        }
+        newListener.listenerAttached();
+    }
+
+    public void remove(String propertyId, IPropertyMapListener toRemove) {
+        if (listeners == null) {
+            return;
+        }
+        List listenerList = (List)listeners.get(propertyId);
+
+        if (listenerList != null) {
+            listenerList.remove(toRemove);
+
+            if (listenerList.isEmpty()) {
+                listeners.remove(propertyId);
+
+                if (listeners.isEmpty()) {
+                    listeners = null;
+                }
+            }
+        }
+    }
+
+    public void removeAll() {
+        globalListeners = null;
+        listeners = null;
+    }
+
+    public void remove(IPropertyMapListener toRemove) {
+        if (globalListeners != null) {
+            globalListeners.remove(toRemove);
+            if (globalListeners.isEmpty()) {
+                globalListeners = null;
+            }
+        }
+
+        if (listeners != null) {
+            for (Iterator iter = listeners.keySet().iterator(); iter.hasNext();) {
+                String key = (String) iter.next();
+
+                remove(key, toRemove);
+            }
+        }
+    }
+
+    public boolean isEmpty() {
+        return globalListeners == null && listeners == null;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/PropertyMapAdapter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/PropertyMapAdapter.java
new file mode 100644
index 0000000..c616eda
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/PropertyMapAdapter.java
@@ -0,0 +1,115 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.preferences;
+
+import java.util.ArrayList;
+
+/**
+ * @since 3.1
+ */
+public abstract class PropertyMapAdapter implements IDynamicPropertyMap {
+
+    private PropertyListenerList listeners;
+    private int ignoreCount = 0;
+    private ArrayList queuedEvents = new ArrayList();
+
+    @Override
+	public final void addListener(IPropertyMapListener listener) {
+        if (listeners == null) {
+            listeners = new PropertyListenerList();
+            attachListener();
+        }
+        listeners.add(listener);
+    }
+
+    @Override
+	public final void removeListener(IPropertyMapListener listener) {
+        if (listeners != null) {
+            listeners.remove(listener);
+            if (listeners.isEmpty()) {
+                detachListener();
+                listeners = null;
+            }
+        }
+    }
+
+    @Override
+	public final boolean isCommonProperty(String propertyId) {
+        return true;
+    }
+
+    /**
+     * Detaches all listeners which have been registered with other objects
+     *
+     * @since 3.1
+     */
+    public void dispose() {
+        if (listeners != null) {
+            detachListener();
+            listeners = null;
+        }
+    }
+
+    protected final void firePropertyChange(String prefId) {
+        if (ignoreCount > 0) {
+            queuedEvents.add(prefId);
+            return;
+        }
+
+        if (listeners != null) {
+            listeners.firePropertyChange(prefId);
+        }
+    }
+
+    @Override
+	public final void addListener(String[] eventsOfInterest, IPropertyMapListener listener) {
+        if (listeners == null) {
+            listeners = new PropertyListenerList();
+            attachListener();
+        }
+        listeners.add(eventsOfInterest, listener);
+    }
+
+    protected final void firePropertyChange(String[] prefIds) {
+        if (ignoreCount > 0) {
+            for (String prefId : prefIds) {
+                queuedEvents.add(prefId);
+            }
+            return;
+        }
+
+        if (listeners != null) {
+            listeners.firePropertyChange(prefIds);
+        }
+    }
+
+    public final void startTransaction() {
+        ignoreCount++;
+    }
+
+    public final void endTransaction() {
+        ignoreCount--;
+        if (ignoreCount == 0 && !queuedEvents.isEmpty()) {
+            if (listeners != null) {
+                listeners.firePropertyChange((String[]) queuedEvents.toArray(new String[queuedEvents.size()]));
+            }
+            queuedEvents.clear();
+        }
+    }
+
+    @Override
+	public boolean equals(Object toCompare) {
+        return toCompare instanceof IPropertyMap && PropertyUtil.isEqual(this, (IPropertyMap)toCompare);
+    }
+
+    protected abstract void attachListener();
+    protected abstract void detachListener();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/PropertyMapUnion.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/PropertyMapUnion.java
new file mode 100644
index 0000000..8e7a298
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/PropertyMapUnion.java
@@ -0,0 +1,130 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.preferences;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.ui.internal.util.Util;
+
+/**
+ * @since 3.1
+ */
+public class PropertyMapUnion implements IPropertyMap {
+
+    private Map values;
+
+    private final static class PropertyInfo {
+        Object value;
+        boolean commonAttribute;
+
+        PropertyInfo(Object value, boolean commonAttribute) {
+            this.value = value;
+            this.commonAttribute = commonAttribute;
+        }
+    }
+
+    @Override
+	public Set keySet() {
+        return values.keySet();
+    }
+
+    @Override
+	public Object getValue(String propertyId, Class propertyType) {
+        PropertyInfo info = (PropertyInfo)values.get(propertyId);
+
+        if (info == null) {
+            return null;
+        }
+
+        Object value = info.value;
+
+        if (propertyType.isInstance(value)) {
+            return value;
+        }
+
+        return null;
+    }
+
+    @Override
+	public boolean isCommonProperty(String propertyId) {
+        PropertyInfo info = (PropertyInfo)values.get(propertyId);
+
+        if (info == null) {
+            return false;
+        }
+
+        return info.commonAttribute;
+    }
+
+    @Override
+	public boolean propertyExists(String propertyId) {
+        return values.get(propertyId) != null;
+    }
+
+    @Override
+	public void setValue(String propertyId, Object newValue) {
+        PropertyInfo info = new PropertyInfo(newValue, true);
+
+        values.put(propertyId, info);
+    }
+
+    public void addMap(IPropertyMap toAdd) {
+        Set keySet = toAdd.keySet();
+
+        // Update any existing attributes
+        for (Iterator iter = keySet().iterator(); iter.hasNext();) {
+            String key = (String) iter.next();
+
+            PropertyInfo localInfo = (PropertyInfo)values.get(key);
+            // Shouldn't be null, but just in case...
+            if (localInfo != null) {
+                // If the attribute exists in the new map
+                if (toAdd.propertyExists(key)) {
+                    // Determine if the value is common
+	                Object value = toAdd.getValue(key, Object.class);
+
+	                if (!Util.equals(value, toAdd.getValue(key, Object.class))) {
+	                    // Set the value to null if not common
+	                    localInfo.value = null;
+	                }
+
+	                // The attribute must be common in both the receiver and the new map to be common
+	                // everywhere
+	                localInfo.commonAttribute = localInfo.commonAttribute && toAdd.isCommonProperty(key);
+                } else {
+                    // If the attribute doesn't exist in the new map, it cannot be common
+                    localInfo.commonAttribute = false;
+                }
+            }
+        }
+
+        // Add any new attributes that exist in the target
+        for (Iterator iter = keySet.iterator(); iter.hasNext();) {
+            String element = (String) iter.next();
+
+            PropertyInfo localInfo = (PropertyInfo)values.get(element);
+            if (localInfo == null) {
+                Object value = toAdd.getValue(element, Object.class);
+
+                boolean isCommon = toAdd.isCommonProperty(element);
+
+                localInfo = new PropertyInfo(value, isCommon);
+                values.put(element, localInfo);
+            }
+        }
+    }
+
+    public void removeValue(String propertyId) {
+        values.remove(propertyId);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/PropertyUtil.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/PropertyUtil.java
new file mode 100644
index 0000000..8b50557
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/PropertyUtil.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.preferences;
+
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * @since 3.1
+ */
+public class PropertyUtil {
+    private PropertyUtil() {
+    }
+
+    public static boolean isEqual(IPropertyMap map1, IPropertyMap map2) {
+        Set map1Keys = map1.keySet();
+        Set map2Keys = map2.keySet();
+
+        if (!map1Keys.equals(map2Keys)) {
+            return false;
+        }
+
+        for (Iterator iter = map1Keys.iterator(); iter.hasNext();) {
+            String next = (String) iter.next();
+
+            if (!map1.getValue(next, Object.class).equals(map2.getValue(next, Object.class))) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Copies all properties from the given source to the given destination
+     *
+     * @param destination
+     * @param source
+     * @since 3.1
+     */
+    public static void copy(IPropertyMap destination, IPropertyMap source) {
+       Set keys = source.keySet();
+
+       for (Iterator iter = keys.iterator(); iter.hasNext();) {
+           String key = (String) iter.next();
+
+           destination.setValue(key, source.getValue(key, Object.class));
+       }
+    }
+
+    /**
+     * Computes the union of a set property maps. The result will contain all properties from
+     * all of the contributing maps. If the same property had a different value in two or
+     * more maps, its value in the union will be null. If the same property
+     *
+     * Note that the result is a standalone
+     * object and will not be updated to reflect subsequent changes in the source maps.
+     *
+     * @param sources
+     * @return
+     * @since 3.1
+     */
+    public static IPropertyMap union(IPropertyMap[] sources) {
+        PropertyMapUnion result = new PropertyMapUnion();
+
+        for (IPropertyMap map : sources) {
+            result.addMap(map);
+        }
+
+        return result;
+    }
+
+    public static boolean get(IPropertyMap toRead, String propertyId, boolean defaultValue) {
+        Boolean result = ((Boolean)toRead.getValue(propertyId, Boolean.class));
+
+        if (result == null) {
+            return defaultValue;
+        }
+
+        return result.booleanValue();
+    }
+
+    public static int get(IPropertyMap toRead, String propertyId, int defaultValue) {
+        Integer result = ((Integer)toRead.getValue(propertyId, Integer.class));
+
+        if (result == null) {
+            return defaultValue;
+        }
+
+        return result.intValue();
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/SettingsTransferRegistryReader.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/SettingsTransferRegistryReader.java
new file mode 100644
index 0000000..171393d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/SettingsTransferRegistryReader.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.preferences;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.registry.RegistryReader;
+
+/**
+ * The SettingsTransferRegistryReader is the class that supplies all of the
+ * transfer settings used by the settingsTransfer in the preferencesTransfer
+ * extension point.
+ *
+ *
+ * @since 3.3
+ *
+ */
+public class SettingsTransferRegistryReader extends RegistryReader {
+
+	Collection settingsTransfers = new ArrayList();
+
+	/**
+	 * Create an instance of the receiver.
+	 */
+	public SettingsTransferRegistryReader() {
+
+	}
+
+	/**
+	 * Get all of the currently registered settings transfers.
+	 *
+	 * @return IConfigurationElement[]
+	 */
+	public IConfigurationElement[] getSettingTransfers() {
+
+		settingsTransfers = new ArrayList();
+		IExtensionRegistry registry = Platform.getExtensionRegistry();
+		// RAP [bm]: namespace
+		readRegistry(registry, PlatformUI.PLUGIN_EXTENSION_NAME_SPACE,
+				IWorkbenchRegistryConstants.PL_PREFERENCE_TRANSFER);
+
+		IConfigurationElement[] transfers = new IConfigurationElement[settingsTransfers
+				.size()];
+		settingsTransfers.toArray(transfers);
+		return transfers;
+
+	}
+
+	@Override
+	protected boolean readElement(IConfigurationElement element) {
+		if (element.getName().equals(
+				IWorkbenchRegistryConstants.TAG_SETTINGS_TRANSFER)) {
+
+			settingsTransfers.add(element);
+			return true;
+		}
+
+		//Ignore the preference transfers
+		return element.getName().equals(
+				IWorkbenchRegistryConstants.TAG_TRANSFER);
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/ThemeAdapter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/ThemeAdapter.java
new file mode 100644
index 0000000..15a641f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/ThemeAdapter.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.preferences;
+
+import java.util.HashSet;
+import java.util.Set;
+import org.eclipse.jface.resource.FontRegistry;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.ui.themes.ITheme;
+
+/**
+ * @since 3.1
+ */
+public class ThemeAdapter extends PropertyMapAdapter {
+
+    private ITheme targetTheme;
+
+    private IPropertyChangeListener listener = event -> firePropertyChange(event.getProperty());
+
+    public ThemeAdapter(ITheme targetTheme) {
+        this.targetTheme = targetTheme;
+    }
+
+    @Override
+	protected void attachListener() {
+        targetTheme.addPropertyChangeListener(listener);
+    }
+
+    @Override
+	protected void detachListener() {
+        targetTheme.removePropertyChangeListener(listener);
+    }
+
+    @Override
+	public Set keySet() {
+        return getKeySet(targetTheme);
+    }
+
+    @Override
+	public Object getValue(String propertyId, Class propertyType) {
+        return getValue(targetTheme, propertyId, propertyType);
+    }
+
+    public static Set getKeySet(ITheme targetTheme) {
+        Set result = new HashSet();
+
+        result.addAll(targetTheme.keySet());
+        result.addAll(targetTheme.getColorRegistry().getKeySet());
+        result.addAll(targetTheme.getFontRegistry().getKeySet());
+
+        return result;
+    }
+
+    public static Object getValue(ITheme targetTheme, String propertyId, Class propertyType) {
+
+        if (propertyType.isAssignableFrom(String.class)) {
+            return targetTheme.getString(propertyId);
+        }
+
+        if (propertyType.isAssignableFrom(Color.class)) {
+            Color result = targetTheme.getColorRegistry().get(propertyId);
+            if (result != null) {
+                return result;
+            }
+        }
+
+        if (propertyType.isAssignableFrom(Font.class)) {
+            FontRegistry fonts = targetTheme.getFontRegistry();
+
+            if (fonts.hasValueFor(propertyId)) {
+                return fonts.get(propertyId);
+            }
+        }
+
+        if (propertyType == Integer.class) {
+			return Integer.valueOf(targetTheme.getInt(propertyId));
+        }
+
+        if (propertyType == Boolean.class) {
+            return targetTheme.getBoolean(propertyId) ? Boolean.TRUE : Boolean.FALSE;
+        }
+
+        return null;
+    }
+
+    @Override
+	public boolean propertyExists(String propertyId) {
+        return keySet().contains(propertyId);
+    }
+
+    @Override
+	public void setValue(String propertyId, Object newValue) {
+        throw new UnsupportedOperationException();
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/ThemeManagerAdapter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/ThemeManagerAdapter.java
new file mode 100644
index 0000000..fe4f513
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/ThemeManagerAdapter.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.preferences;
+
+import java.util.Set;
+
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.ui.themes.IThemeManager;
+
+/**
+ * @since 3.1
+ */
+public class ThemeManagerAdapter extends PropertyMapAdapter {
+
+    private IThemeManager manager;
+
+    private IPropertyChangeListener listener = event -> firePropertyChange(event.getProperty());
+
+    public ThemeManagerAdapter(IThemeManager manager) {
+        this.manager = manager;
+    }
+
+    @Override
+	protected void attachListener() {
+        manager.addPropertyChangeListener(listener);
+    }
+
+    @Override
+	protected void detachListener() {
+        manager.removePropertyChangeListener(listener);
+    }
+
+    @Override
+	public Set keySet() {
+        Set result = ThemeAdapter.getKeySet(manager.getCurrentTheme());
+
+        return result;
+    }
+
+    @Override
+	public Object getValue(String propertyId, Class propertyType) {
+        return ThemeAdapter.getValue(manager.getCurrentTheme(), propertyId, propertyType);
+    }
+
+    @Override
+	public boolean propertyExists(String propertyId) {
+        return keySet().contains(propertyId);
+    }
+
+    @Override
+	public void setValue(String propertyId, Object newValue) {
+        throw new UnsupportedOperationException();
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/WorkbenchPreferenceExpressionNode.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/WorkbenchPreferenceExpressionNode.java
new file mode 100644
index 0000000..507093f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/WorkbenchPreferenceExpressionNode.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2015 Bredex GmbH 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:
+ *     Jan-Hendrik Diederich, Bredex GmbH - initial API and implementation, bug 201052
+ *     IBM Corporation - bug 201052
+ ******************************************************************************/
+
+package org.eclipse.ui.internal.preferences;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jface.preference.IPreferenceNode;
+import org.eclipse.jface.preference.PreferenceNode;
+import org.eclipse.ui.IPluginContribution;
+import org.eclipse.ui.activities.WorkbenchActivityHelper;
+
+/**
+ * @since 3.4
+ * @author Jan Diederich
+ */
+public class WorkbenchPreferenceExpressionNode extends PreferenceNode
+	implements IPluginContribution {
+
+
+	/**
+	 * @param id The id.
+	 * @see PreferenceNode#PreferenceNode(String)
+	 */
+	public WorkbenchPreferenceExpressionNode(String id) {
+		super(id);
+	}
+
+    @Override
+	public IPreferenceNode findSubNode(String id) {
+        return getNodeExpression(super.findSubNode(id));
+    }
+
+    @Override
+	public IPreferenceNode[] getSubNodes() {
+    	IPreferenceNode[] prefNodes = super.getSubNodes();
+        int size = prefNodes.length;
+        List list = new ArrayList(size);
+        for (int i = 0; i < size; i++) {
+        	IPreferenceNode prefNode = getNodeExpression(prefNodes[i]);
+            if (prefNode != null) {
+                list.add(prefNode);
+            }
+        }
+        return (IPreferenceNode[])list.toArray(new IPreferenceNode[list.size()]);
+    }
+
+    /**
+     * Returns the given <code>prefNode</code>, but only if it's no
+     * WorkbenchPreferenceExtensionNode which fails the Expression check.
+     *
+     * @param prefNode
+     *            The preference node which will be checked. Can be <code>null
+     *            </code>.
+     * @return The given <code>prefNode</code>, or <code>null</code> if it
+     *         fails the Expressions check.
+     */
+    public static IPreferenceNode getNodeExpression(
+    		IPreferenceNode prefNode) {
+    	if (prefNode == null)
+    		return null;
+        if (prefNode instanceof WorkbenchPreferenceExtensionNode) {
+        	WorkbenchPreferenceExpressionNode node =
+        		(WorkbenchPreferenceExtensionNode)prefNode;
+            if (WorkbenchActivityHelper.restrictUseOf(node)) {
+                return null;
+            }
+        }
+        return prefNode;
+    }
+
+	@Override
+	public String getLocalId() {
+		return getId();
+	}
+
+	@Override
+	public String getPluginId() {
+		return ""; //$NON-NLS-1$
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/WorkbenchPreferenceExtensionNode.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/WorkbenchPreferenceExtensionNode.java
new file mode 100644
index 0000000..6fad5d4
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/WorkbenchPreferenceExtensionNode.java
@@ -0,0 +1,218 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2016 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
+ *     Jan-Hendrik Diederich, Bredex GmbH - bug 201052
+ *     Oakland Software (Francis Upton) <francisu@ieee.org> - bug 219273
+ *
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.preferences;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.registry.KeywordRegistry;
+import org.eclipse.ui.model.IComparableContribution;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+/**
+ * The WorkbenchPreferenceExtensionNode is the abstract class for all property
+ * and page nodes in the workbench.
+ *
+ * @since 3.1
+ */
+public abstract class WorkbenchPreferenceExtensionNode extends WorkbenchPreferenceExpressionNode
+    implements IComparableContribution {
+
+	private Collection keywordReferences;
+
+	private IConfigurationElement configurationElement;
+
+	private ImageDescriptor imageDescriptor;
+
+	private Image image;
+
+	private Collection keywordLabelCache;
+
+	private int priority;
+
+	private String pluginId;
+
+	/**
+	 * Create a new instance of the reciever.
+	 *
+	 * @param id
+	 * @param configurationElement
+	 */
+	public WorkbenchPreferenceExtensionNode(String id, IConfigurationElement configurationElement) {
+		super(id);
+		this.configurationElement = configurationElement;
+		this.pluginId = configurationElement.getNamespaceIdentifier();
+	}
+
+	/**
+	 * Get the ids of the keywords the receiver is bound to.
+	 *
+	 * @return Collection of <code>String</code>.  Never <code>null</code>.
+	 */
+	public Collection getKeywordReferences() {
+		if (keywordReferences == null) {
+			IConfigurationElement[] references = getConfigurationElement()
+					.getChildren(IWorkbenchRegistryConstants.TAG_KEYWORD_REFERENCE);
+			HashSet list = new HashSet(references.length);
+			for (IConfigurationElement configElement : references) {
+				String id = configElement.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+				if (id != null) {
+					list.add(id);
+				}
+			}
+
+			if (!list.isEmpty()) {
+				keywordReferences = list;
+			} else {
+				keywordReferences = Collections.EMPTY_SET;
+			}
+
+		}
+		return keywordReferences;
+	}
+
+	/**
+	 * Get the labels of all of the keywords of the receiver.
+	 *
+	 * @return Collection of <code>String</code>.  Never <code>null</code>.
+	 */
+	public Collection getKeywordLabels() {
+		if (keywordLabelCache != null) {
+			return keywordLabelCache;
+		}
+
+		Collection refs = getKeywordReferences();
+
+		if(refs == Collections.EMPTY_SET) {
+			keywordLabelCache = Collections.EMPTY_SET;
+			return keywordLabelCache;
+		}
+
+		keywordLabelCache = new ArrayList(refs.size());
+		Iterator referenceIterator = refs.iterator();
+		while(referenceIterator.hasNext()){
+			Object label = KeywordRegistry.getInstance().getKeywordLabel(
+					(String) referenceIterator.next());
+			if(label != null) {
+				keywordLabelCache.add(label);
+			}
+		}
+
+		return keywordLabelCache;
+	}
+
+	/**
+	 * Clear the keyword cache, if any.
+	 */
+	public void clearKeywords() {
+		keywordLabelCache = null;
+	}
+
+	@Override
+	public void disposeResources() {
+        if (image != null) {
+            image.dispose();
+            image = null;
+        }
+        super.disposeResources();
+	}
+
+	@Override
+	public Image getLabelImage() {
+        if (image == null) {
+        	ImageDescriptor desc = getImageDescriptor();
+        	if (desc != null) {
+				image = imageDescriptor.createImage();
+			}
+        }
+        return image;
+    }
+
+
+	@Override
+	public String getLabelText() {
+		return getConfigurationElement().getAttribute(IWorkbenchRegistryConstants.ATT_NAME);
+	}
+
+    /**
+     * Returns the image descriptor for this node.
+     *
+     * @return the image descriptor
+     */
+    @Override
+	public ImageDescriptor getImageDescriptor() {
+    	if (imageDescriptor != null) {
+			return imageDescriptor;
+		}
+
+    	String imageName = getConfigurationElement().getAttribute(IWorkbenchRegistryConstants.ATT_ICON);
+		if (imageName != null) {
+			String contributingPluginId = pluginId;
+			imageDescriptor = AbstractUIPlugin.imageDescriptorFromPlugin(contributingPluginId, imageName);
+		}
+		return imageDescriptor;
+    }
+
+    /**
+     * Return the configuration element.
+     *
+     * @return the configuration element
+     */
+	public IConfigurationElement getConfigurationElement() {
+		return configurationElement;
+	}
+
+	@Override
+	public String getLocalId() {
+		return getId();
+	}
+
+	@Override
+	public String getPluginId() {
+		return pluginId;
+	}
+
+	@Override
+	public <T> T getAdapter(Class<T> adapter) {
+        if (adapter == IConfigurationElement.class)
+			return adapter.cast(getConfigurationElement());
+        return null;
+    }
+
+    @Override
+	public String getLabel()
+    {
+        return getLabelText();
+    }
+
+    @Override
+	public int getPriority()
+    {
+        return priority;
+    }
+
+    public void setPriority(int pri)
+    {
+        priority = pri;
+    }
+
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/WorkbenchSettingsTransfer.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/WorkbenchSettingsTransfer.java
new file mode 100644
index 0000000..7d1716b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/WorkbenchSettingsTransfer.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.preferences;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.preferences.SettingsTransfer;
+
+/**
+ * The WorkbenchSettingsTransfer is the abstract superclass of settings
+ * transfers in the workbench.
+ *
+ * @since 3.3
+ *
+ */
+public abstract class WorkbenchSettingsTransfer extends SettingsTransfer {
+
+	/**
+	 * Return a status message for missing workspace settings.
+	 * @return IStatus
+	 */
+	protected IStatus noWorkingSettingsStatus() {
+		return new Status(IStatus.ERROR, WorkbenchPlugin.PI_WORKBENCH,
+				WorkbenchMessages.get().WorkbenchSettings_CouldNotFindLocation);
+	}
+
+	/**
+	 * Return the workbench settings location for the new root
+	 * @param newWorkspaceRoot
+	 * @return IPath or <code>null</code> if it can't be determined.
+	 */
+	protected IPath getNewWorkbenchStateLocation(IPath newWorkspaceRoot) {
+		IPath currentWorkspaceRoot = Platform.getLocation();
+
+		IPath dataLocation = WorkbenchPlugin.getDefault().getDataLocation();
+
+		if (dataLocation == null)
+			return null;
+		int segmentsToRemove = dataLocation
+				.matchingFirstSegments(currentWorkspaceRoot);
+
+		// Strip it down to the extension
+		dataLocation = dataLocation.removeFirstSegments(segmentsToRemove);
+		// Now add in the
+		dataLocation = newWorkspaceRoot.append(dataLocation);
+		return dataLocation;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/WorkingCopyPreferences.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/WorkingCopyPreferences.java
new file mode 100644
index 0000000..dd224f9
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/WorkingCopyPreferences.java
@@ -0,0 +1,479 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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
+ *     Timo Kinnunen <timo.kinnunen@gmail.com> - Bug 431924
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.preferences;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import org.eclipse.core.commands.common.EventManager;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.IPreferenceNodeVisitor;
+import org.osgi.service.prefs.BackingStoreException;
+import org.osgi.service.prefs.Preferences;
+
+/**
+ * Represents a working copy of a preference node, backed by the real node.
+ * <p>
+ * Note: Working copy nodes do not fire node change events.
+ * </p>
+ * <p>
+ * Note: Preference change listeners registered on this node will only receive
+ * events from this node and not events based on the original backing node.
+ * </p>
+ * @since 3.1
+ */
+public class WorkingCopyPreferences extends EventManager implements
+		IEclipsePreferences {
+
+	private static final String TRUE = "true"; //$NON-NLS-1$
+
+	private final Map<String, Object> temporarySettings;
+	private final IEclipsePreferences original;
+	private boolean removed = false;
+	private org.eclipse.ui.preferences.WorkingCopyManager manager;
+
+	/**
+	 * @param original the underlying preference node
+	 * @param manager the working copy manager
+	 */
+	public WorkingCopyPreferences(IEclipsePreferences original, org.eclipse.ui.preferences.WorkingCopyManager manager) {
+		super();
+		this.original = original;
+		this.manager = manager;
+		this.temporarySettings = new HashMap<>();
+	}
+
+	/*
+	 * Convenience method for throwing an exception when methods
+	 * are called on a removed node.
+	 */
+	private void checkRemoved() {
+		if (removed) {
+			String message = "Preference node: " + absolutePath() + " has been removed."; //$NON-NLS-1$ //$NON-NLS-2$
+			throw new IllegalStateException(message);
+		}
+	}
+
+	@Override
+	public void addNodeChangeListener(INodeChangeListener listener) {
+		// no-op - working copy nodes don't fire node change events
+	}
+
+	@Override
+	public void removeNodeChangeListener(INodeChangeListener listener) {
+		// no-op - working copy nodes don't fire node change events
+	}
+
+	@Override
+	public void addPreferenceChangeListener(IPreferenceChangeListener listener) {
+		checkRemoved();
+		addListenerObject(listener);
+	}
+
+	@Override
+	public void removePreferenceChangeListener(IPreferenceChangeListener listener) {
+		checkRemoved();
+		removeListenerObject(listener);
+	}
+
+	@Override
+	public void removeNode() throws BackingStoreException {
+		checkRemoved();
+
+		// clear all values (long way so people get notified)
+		for (String key : keys()) {
+			remove(key);
+		}
+
+		// remove children
+		for (String childName : childrenNames()) {
+			node(childName).removeNode();
+		}
+
+		// mark as removed
+		removed = true;
+	}
+
+
+	@Override
+	public Preferences node(String path) {
+		checkRemoved();
+		return manager.getWorkingCopy((IEclipsePreferences) getOriginal().node(path));
+	}
+
+	@Override
+	public void accept(IPreferenceNodeVisitor visitor) throws BackingStoreException {
+		checkRemoved();
+		if (!visitor.visit(this)) {
+			return;
+		}
+		for (String childName : childrenNames()) {
+			((IEclipsePreferences) node(childName)).accept(visitor);
+		}
+	}
+
+	@Override
+	public void put(String key, String value) {
+		checkRemoved();
+		if (key == null || value == null) {
+			throw new NullPointerException();
+		}
+		String oldValue = null;
+		if (temporarySettings.containsKey(key)) {
+			oldValue = (String) temporarySettings.get(key);
+		} else {
+			oldValue = getOriginal().get(key, null);
+		}
+		temporarySettings.put(key, value);
+		if (!value.equals(oldValue)) {
+			firePropertyChangeEvent(key, oldValue, value);
+		}
+	}
+
+	private void firePropertyChangeEvent(String key, Object oldValue, Object newValue) {
+		Object[] listeners = getListeners();
+		if (listeners.length == 0) {
+			return;
+		}
+		PreferenceChangeEvent event = new PreferenceChangeEvent(this, key, oldValue, newValue);
+		for (Object listener : listeners) {
+			((IPreferenceChangeListener) listener).preferenceChange(event);
+		}
+	}
+
+	@Override
+	public String get(String key, String defaultValue) {
+		checkRemoved();
+		return internalGet(key, defaultValue);
+	}
+
+	private String internalGet(String key, String defaultValue) {
+		if (key == null) {
+			throw new NullPointerException();
+		}
+		if (temporarySettings.containsKey(key)) {
+			Object value = temporarySettings.get(key);
+			return value == null ? defaultValue : (String) value;
+		}
+		return getOriginal().get(key, defaultValue);
+	}
+
+	@Override
+	public void remove(String key) {
+		checkRemoved();
+		if (key == null) {
+			throw new NullPointerException();
+		}
+		Object oldValue = null;
+		if (temporarySettings.containsKey(key)) {
+			oldValue = temporarySettings.get(key);
+		} else {
+			oldValue = original.get(key, null);
+		}
+		if (oldValue == null) {
+			return;
+		}
+		temporarySettings.put(key, null);
+		firePropertyChangeEvent(key, oldValue, null);
+	}
+
+	@Override
+	public void clear() {
+		checkRemoved();
+		for (Entry<String, Object> entry : temporarySettings.entrySet()) {
+			String key = entry.getKey();
+			Object value = entry.getValue();
+			if (value != null) {
+				temporarySettings.put(key, null);
+				firePropertyChangeEvent(key, value, null);
+			}
+		}
+	}
+
+	@Override
+	public void putInt(String key, int value) {
+		checkRemoved();
+		if (key == null) {
+			throw new NullPointerException();
+		}
+		String oldValue = null;
+		if (temporarySettings.containsKey(key)) {
+			oldValue = (String) temporarySettings.get(key);
+		} else {
+			oldValue = getOriginal().get(key, null);
+		}
+		String newValue = Integer.toString(value);
+		temporarySettings.put(key, newValue);
+		if (!newValue.equals(oldValue)) {
+			firePropertyChangeEvent(key, oldValue, newValue);
+		}
+	}
+
+	@Override
+	public int getInt(String key, int defaultValue) {
+		checkRemoved();
+		String value = internalGet(key, null);
+		int result = defaultValue;
+		if (value != null) {
+			try {
+				result = Integer.parseInt(value);
+			} catch (NumberFormatException e) {
+				// use default
+			}
+		}
+		return result;
+	}
+
+	@Override
+	public void putLong(String key, long value) {
+		checkRemoved();
+		if (key == null) {
+			throw new NullPointerException();
+		}
+		String oldValue = null;
+		if (temporarySettings.containsKey(key)) {
+			oldValue = (String) temporarySettings.get(key);
+		} else {
+			oldValue = getOriginal().get(key, null);
+		}
+		String newValue = Long.toString(value);
+		temporarySettings.put(key, newValue);
+		if (!newValue.equals(oldValue)) {
+			firePropertyChangeEvent(key, oldValue, newValue);
+		}
+	}
+
+	@Override
+	public long getLong(String key, long defaultValue) {
+		checkRemoved();
+		String value = internalGet(key, null);
+		long result = defaultValue;
+		if (value != null) {
+			try {
+				result = Long.parseLong(value);
+			} catch (NumberFormatException e) {
+				// use default
+			}
+		}
+		return result;
+	}
+
+	@Override
+	public void putBoolean(String key, boolean value) {
+		checkRemoved();
+		if (key == null) {
+			throw new NullPointerException();
+		}
+		String oldValue = null;
+		if (temporarySettings.containsKey(key)) {
+			oldValue = (String) temporarySettings.get(key);
+		} else {
+			oldValue = getOriginal().get(key, null);
+		}
+		String newValue = String.valueOf(value);
+		temporarySettings.put(key, newValue);
+		if (!newValue.equalsIgnoreCase(oldValue)) {
+			firePropertyChangeEvent(key, oldValue, newValue);
+		}
+	}
+
+	@Override
+	public boolean getBoolean(String key, boolean defaultValue) {
+		checkRemoved();
+		String value = internalGet(key, null);
+		return value == null ? defaultValue : TRUE.equalsIgnoreCase(value);
+	}
+
+	@Override
+	public void putFloat(String key, float value) {
+		checkRemoved();
+		if (key == null) {
+			throw new NullPointerException();
+		}
+		String oldValue = null;
+		if (temporarySettings.containsKey(key)) {
+			oldValue = (String) temporarySettings.get(key);
+		} else {
+			oldValue = getOriginal().get(key, null);
+		}
+		String newValue = Float.toString(value);
+		temporarySettings.put(key, newValue);
+		if (!newValue.equals(oldValue)) {
+			firePropertyChangeEvent(key, oldValue, newValue);
+		}
+	}
+
+	@Override
+	public float getFloat(String key, float defaultValue) {
+		checkRemoved();
+		String value = internalGet(key, null);
+		float result = defaultValue;
+		if (value != null) {
+			try {
+				result = Float.parseFloat(value);
+			} catch (NumberFormatException e) {
+				// use default
+			}
+		}
+		return result;
+	}
+
+	@Override
+	public void putDouble(String key, double value) {
+		checkRemoved();
+		if (key == null) {
+			throw new NullPointerException();
+		}
+		String oldValue = null;
+		if (temporarySettings.containsKey(key)) {
+			oldValue = (String) temporarySettings.get(key);
+		} else {
+			oldValue = getOriginal().get(key, null);
+		}
+		String newValue = Double.toString(value);
+		temporarySettings.put(key, newValue);
+		if (!newValue.equals(oldValue)) {
+			firePropertyChangeEvent(key, oldValue, newValue);
+		}
+	}
+
+	@Override
+	public double getDouble(String key, double defaultValue) {
+		checkRemoved();
+		String value = internalGet(key, null);
+		double result = defaultValue;
+		if (value != null) {
+			try {
+				result = Double.parseDouble(value);
+			} catch (NumberFormatException e) {
+				// use default
+			}
+		}
+		return result;
+	}
+
+	@Override
+	public void putByteArray(String key, byte[] value) {
+		checkRemoved();
+		if (key == null || value == null) {
+			throw new NullPointerException();
+		}
+		String oldValue = null;
+		if (temporarySettings.containsKey(key)) {
+			oldValue = (String) temporarySettings.get(key);
+		} else {
+			oldValue = getOriginal().get(key, null);
+		}
+		String newValue = new String(Base64.encode(value));
+		temporarySettings.put(key, newValue);
+		if (!newValue.equals(oldValue)) {
+			firePropertyChangeEvent(key, oldValue, newValue);
+		}
+	}
+
+	@Override
+	public byte[] getByteArray(String key, byte[] defaultValue) {
+		checkRemoved();
+		String value = internalGet(key, null);
+		return value == null ? defaultValue : Base64.decode(value.getBytes());
+	}
+
+	@Override
+	public String[] keys() throws BackingStoreException {
+		checkRemoved();
+		HashSet<String> allKeys = new HashSet<>(Arrays.asList(getOriginal().keys()));
+		for (Entry<String, Object> entry : temporarySettings.entrySet()) {
+			String key = entry.getKey();
+			if (entry.getValue() != null) {
+				allKeys.add(key);
+			} else {
+				allKeys.remove(key);
+			}
+		}
+		return allKeys.toArray(new String[allKeys.size()]);
+	}
+
+	@Override
+	public String[] childrenNames() throws BackingStoreException {
+		checkRemoved();
+		return getOriginal().childrenNames();
+	}
+
+	@Override
+	public Preferences parent() {
+		checkRemoved();
+		return manager.getWorkingCopy((IEclipsePreferences) getOriginal().parent());
+	}
+
+	@Override
+	public boolean nodeExists(String pathName) throws BackingStoreException {
+		// short circuit for this node
+		if (pathName.length() == 0) {
+			return removed ? false : getOriginal().nodeExists(pathName);
+		}
+		return getOriginal().nodeExists(pathName);
+	}
+
+	@Override
+	public String name() {
+		return getOriginal().name();
+	}
+
+	@Override
+	public String absolutePath() {
+		return getOriginal().absolutePath();
+	}
+
+	@Override
+	public void flush() throws BackingStoreException {
+		if (removed) {
+			getOriginal().removeNode();
+			return;
+		}
+		checkRemoved();
+		// update underlying preferences
+		for (Entry<String, Object> entry : temporarySettings.entrySet()) {
+			String key = entry.getKey();
+			String value = (String) entry.getValue();
+			if (value == null) {
+				getOriginal().remove(key);
+			} else {
+				getOriginal().put(key, value);
+			}
+		}
+		// clear our settings
+		temporarySettings.clear();
+
+		// save the underlying preference store
+		getOriginal().flush();
+	}
+
+	@Override
+	public void sync() throws BackingStoreException {
+		checkRemoved();
+		// forget our settings
+		temporarySettings.clear();
+		// load the underlying preference store
+		getOriginal().sync();
+	}
+
+	/**
+	 * @return Returns the original preference node.
+	 */
+	private IEclipsePreferences getOriginal() {
+		return original;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/WorkingSetPropertyPage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/WorkingSetPropertyPage.java
new file mode 100644
index 0000000..aa23b19
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/WorkingSetPropertyPage.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal.preferences;
+
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.jface.wizard.IWizard;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IWorkingSet;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.preferences.WizardPropertyPage;
+
+/**
+ * Embeds a working set wizard for a given working set into a property page.
+ *
+ * @since 3.4
+ */
+public class WorkingSetPropertyPage extends WizardPropertyPage {
+
+	private static final class ReadOnlyWizard extends Wizard {
+
+		public ReadOnlyWizard() {
+		}
+
+		/**
+		 * {@inheritDoc}
+		 */
+		@Override
+		public boolean performFinish() {
+			return true;
+		}
+
+		/**
+		 * {@inheritDoc}
+		 */
+		@Override
+		public void addPages() {
+			addPage(new ReadOnlyPage());
+		}
+	}
+
+	private static final class ReadOnlyPage extends WizardPage {
+
+		protected ReadOnlyPage() {
+			super(WorkbenchMessages.get().WorkingSetPropertyPage_ReadOnlyWorkingSet_title);
+			setDescription(WorkbenchMessages.get().WorkingSetPropertyPage_ReadOnlyWorkingSet_description);
+		}
+
+		/**
+		 * {@inheritDoc}
+		 */
+		@Override
+		public void createControl(Composite parent) {
+			Composite composite= new Composite(parent, SWT.NONE);
+			composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+			composite.setLayout(new GridLayout(1, false));
+
+			setControl(composite);
+		}
+	}
+
+	private IWorkingSet fWorkingSet;
+
+	public WorkingSetPropertyPage() {
+		noDefaultAndApplyButton();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void setElement(IAdaptable element) {
+		super.setElement(element);
+		fWorkingSet = Adapters.adapt(element, IWorkingSet.class);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	protected void applyChanges() {
+		//Wizard does all the work
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	protected IWizard createWizard() {
+		if (fWorkingSet.isEditable()) {
+			return PlatformUI.getWorkbench().getWorkingSetManager().createWorkingSetEditWizard(fWorkingSet);
+		}
+
+		return new ReadOnlyWizard();
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/WorkingSetSettingsTransfer.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/WorkingSetSettingsTransfer.java
new file mode 100644
index 0000000..875f852
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/preferences/WorkingSetSettingsTransfer.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.preferences;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.ui.IWorkingSetManager;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.AbstractWorkingSetManager;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.WorkingSetManager;
+
+/**
+ * The WorkingSetSettingsTransfer is the settings transfer for the workbench
+ * working sets.
+ *
+ * @since 3.3
+ *
+ */
+public class WorkingSetSettingsTransfer extends WorkbenchSettingsTransfer {
+
+	@Override
+	public String getName() {
+		return WorkbenchMessages.get().WorkingSets_Name;
+	}
+
+	@Override
+	public IStatus transferSettings(IPath newWorkspaceRoot) {
+		IPath dataLocation = getNewWorkbenchStateLocation(newWorkspaceRoot);
+
+		if (dataLocation == null)
+			return noWorkingSettingsStatus();
+
+		dataLocation = dataLocation
+				.append(WorkingSetManager.WORKING_SET_STATE_FILENAME);
+
+		File stateFile = new File(dataLocation.toOSString());
+
+		try {
+			IWorkingSetManager manager = PlatformUI.getWorkbench()
+					.getWorkingSetManager();
+			if (manager instanceof AbstractWorkingSetManager)
+				((AbstractWorkingSetManager) manager).saveState(stateFile);
+			else
+				return new Status(IStatus.ERROR, WorkbenchPlugin.PI_WORKBENCH,
+						WorkbenchMessages.get().WorkingSets_CannotSave);
+		} catch (IOException e) {
+			new Status(IStatus.ERROR, WorkbenchPlugin.PI_WORKBENCH,
+					WorkbenchMessages.get().ProblemSavingWorkingSetState_message, e);
+		}
+		return Status.OK_STATUS;
+
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/AbstractProgressViewer.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/AbstractProgressViewer.java
new file mode 100644
index 0000000..73a2cd1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/AbstractProgressViewer.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.progress;
+
+import org.eclipse.jface.viewers.StructuredViewer;
+
+/**
+ * The AbstractProgressViewer is the abstract superclass of the viewers that
+ * show progress.
+ *
+ */
+public abstract class AbstractProgressViewer extends StructuredViewer {
+
+	/**
+	 * Add the elements to the receiver.
+	 * @param elements
+	 */
+	public abstract void add(Object[] elements);
+
+	/**
+	 * Remove the elements from the receiver.
+	 * @param elements
+	 */
+	public abstract void remove(Object[] elements);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/AnimationItem.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/AnimationItem.java
new file mode 100644
index 0000000..32184be
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/AnimationItem.java
@@ -0,0 +1,157 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.internal.progress;
+
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IWorkbenchWindow;
+
+/**
+ * The AnimationItem is the class that manages the animation for the progress.
+ */
+public abstract class AnimationItem {
+	IWorkbenchWindow window;
+
+    interface IAnimationContainer {
+        /**
+         * The animation has started.
+         */
+        public abstract void animationStart();
+
+        /**
+         * The animation has ended.
+         */
+        public abstract void animationDone();
+    }
+
+    //Create a containter that does nothing by default
+    IAnimationContainer animationContainer = new IAnimationContainer() {
+        @Override
+		public void animationDone() {
+            //Do nothing by default
+        }
+
+        @Override
+		public void animationStart() {
+            //Do nothing by default
+        }
+    };
+
+    /**
+     * Create a new instance of the receiver.
+     *
+     * @param workbenchWindow
+     *            the window being created
+     */
+	public AnimationItem(IWorkbenchWindow workbenchWindow) {
+        this.window = workbenchWindow;
+    }
+
+    /**
+     * Create the canvas that will display the image.
+     *
+     * @param parent
+     */
+    public void createControl(Composite parent) {
+
+        Control animationItem = createAnimationItem(parent);
+
+        animationItem.addMouseListener(new MouseListener() {
+            @Override
+			public void mouseDoubleClick(MouseEvent arg0) {
+                ProgressManagerUtil.openProgressView(AnimationItem.this.window);
+            }
+
+            @Override
+			public void mouseDown(MouseEvent arg0) {
+                //Do nothing
+            }
+
+            @Override
+			public void mouseUp(MouseEvent arg0) {
+                //Do nothing
+            }
+        });
+        animationItem.addDisposeListener(e -> AnimationManager.getInstance().removeItem(AnimationItem.this));
+        AnimationManager.getInstance().addItem(this);
+    }
+
+    /**
+     * Create the animation item control.
+     * @param parent the parent Composite
+     * @return Control
+     */
+    protected abstract Control createAnimationItem(Composite parent);
+
+    /**
+     * Paint the image in the canvas.
+     *
+     * @param event
+     *            The PaintEvent that generated this call.
+     * @param image
+     *            The image to display
+     * @param imageData
+     *            The array of ImageData. Required to show an animation.
+     */
+    void paintImage(PaintEvent event, Image image, ImageData imageData) {
+        event.gc.drawImage(image, 0, 0);
+    }
+
+    /**
+     * Get the SWT control for the receiver.
+     *
+     * @return Control
+     */
+    public abstract Control getControl();
+
+    /**
+     * The animation has begun.
+     */
+    void animationStart() {
+        animationContainer.animationStart();
+    }
+
+    /**
+     * The animation has ended.
+     */
+    void animationDone() {
+        animationContainer.animationDone();
+    }
+
+    /**
+     * Get the preferred width of the receiver.
+     *
+     * @return int
+     */
+    public int getPreferredWidth() {
+        return AnimationManager.getInstance().getPreferredWidth() + 5;
+    }
+
+    /**
+     * Set the container that will be updated when this runs.
+     * @param container The animationContainer to set.
+     */
+    void setAnimationContainer(IAnimationContainer container) {
+        this.animationContainer = container;
+    }
+
+	/**
+	 * @return Returns the window.
+	 */
+	public IWorkbenchWindow getWindow() {
+		return window;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/AnimationManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/AnimationManager.java
new file mode 100644
index 0000000..ffd1c48
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/AnimationManager.java
@@ -0,0 +1,327 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2012 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
+ *     EclipseSource - adaptation for RAP
+ *******************************************************************************/
+package org.eclipse.ui.internal.progress;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+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.rap.rwt.RWT;
+import org.eclipse.rap.rwt.SingletonUtil;
+import org.eclipse.rap.rwt.service.UISessionEvent;
+import org.eclipse.rap.rwt.service.UISessionListener;
+import org.eclipse.rap.ui.internal.progress.IJobMarker;
+import org.eclipse.rap.ui.internal.progress.JobCanceler;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.progress.WorkbenchJob;
+
+/**
+ * The AnimationManager is the class that keeps track of the animation items to
+ * update.
+ */
+//RAP [fappel]: AnimationManager needs to be session aware
+public class AnimationManager {
+//    private static AnimationManager singleton;
+
+    boolean animated = false;
+
+    private IJobProgressManagerListener listener;
+
+    IAnimationProcessor animationProcessor;
+
+    WorkbenchJob animationUpdateJob;
+
+    Display display;
+
+    public static AnimationManager getInstance() {
+// RAP [fappel]: AnimationManager needs to be session aware
+//      if (singleton == null) {
+//          singleton = new AnimationManager();
+//      }
+//      return singleton;
+      AnimationManager instance = SingletonUtil.getSessionInstance( AnimationManager.class );
+      if( instance.display == null ) {
+        instance.display = Display.getCurrent();
+      }
+      return instance;
+    }
+
+    /**
+     * Get the background color to be used.
+     * 
+     * @param control
+     *            The source of the display.
+     * @return Color
+     */
+    static Color getItemBackgroundColor(Control control) {
+        return control.getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND);
+    }
+
+    AnimationManager() {
+         // RAP [fappel]: This is a helping flag used to avoid a memory leak
+         //               due to thread management.
+         //               Note that this is still under investigation.
+         //               See comment in JobManagerAdapter
+         final AtomicBoolean done = new AtomicBoolean();
+
+
+        animationProcessor = new ProgressAnimationProcessor(this);
+
+        animationUpdateJob = new WorkbenchJob(ProgressMessages.get().AnimationManager_AnimationStart) {
+
+            /*
+             * (non-Javadoc)
+             * 
+             * @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor)
+             */
+            public IStatus runInUIThread(IProgressMonitor monitor) {
+
+                if (animated) {
+					animationProcessor.animationStarted();
+				} else {
+					animationProcessor.animationFinished();
+				}
+                return Status.OK_STATUS;
+            }
+            
+            // RAP [fappel]: This is a helping mechanism used to avoid a memory
+            //               leak due to thread management.
+            //               Note that this is still under investigation.
+            //               See comment in JobManagerAdapter
+            public Object getAdapter( final Class adapter ) {
+              Object result;
+              if( adapter == IJobMarker.class ) {
+                result = new IJobMarker() {
+                  public boolean canBeRemoved() {
+                    return done.get();
+                  }
+                };
+              } else {
+                result = super.getAdapter( adapter );
+              }
+              return result;
+            }
+
+        };
+        animationUpdateJob.setSystem(true);
+        
+        listener = getProgressListener();
+        ProgressManager.getInstance().addListener(listener);
+
+        // RAP [fappel]: This is a helping mechanism used to avoid a memory leak
+        //               due to thread management.
+        //               Note that this is still under investigation.
+        //               See comment in JobManagerAdapter
+        RWT.getUISession().addUISessionListener( new UISessionListener() {
+          public void beforeDestroy( UISessionEvent event ) {
+            if( animationUpdateJob != null ) {
+              animationUpdateJob.cancel();
+              animationUpdateJob.addJobChangeListener( new JobCanceler() );
+              done.set( true );
+            }
+          }
+        } );
+    }
+
+    /**
+     * Add an item to the list
+     * 
+     * @param item
+     */
+    void addItem(final AnimationItem item) {
+        animationProcessor.addItem(item);
+    }
+
+    /**
+     * Remove an item from the list
+     * 
+     * @param item
+     */
+    void removeItem(final AnimationItem item) {
+        animationProcessor.removeItem(item);
+    }
+
+    /**
+     * Return whether or not the current state is animated.
+     * 
+     * @return boolean
+     */
+    boolean isAnimated() {
+        return animated;
+    }
+
+    /**
+     * Set whether or not the receiver is animated.
+     * 
+     * @param bool
+     */
+// RAP [fappel]: map job to session
+//    void setAnimated(final boolean bool) {
+//      animated = bool;
+//      animationUpdateJob.schedule(100);
+//    }
+    void setAnimated(final boolean bool) {
+      animated = bool;
+      Runnable scheduler = new Runnable() {
+        public void run() {
+          animationUpdateJob.schedule(100);
+        }
+      };
+      RWT.getUISession( display ).exec( scheduler );
+    }
+
+    /**
+     * Dispose the images in the receiver.
+     */
+    void dispose() {
+        setAnimated(false);
+        ProgressManager.getInstance().removeListener(listener);
+    }
+
+    private IJobProgressManagerListener getProgressListener() {
+        return new IJobProgressManagerListener() {
+            Set jobs = Collections.synchronizedSet(new HashSet());
+
+            /*
+             * (non-Javadoc)
+             * 
+             * @see org.eclipse.ui.internal.progress.IJobProgressManagerListener#addJob(org.eclipse.ui.internal.progress.JobInfo)
+             */
+            public void addJob(JobInfo info) {
+                incrementJobCount(info);
+            }
+
+            /*
+             * (non-Javadoc)
+             * 
+             * @see org.eclipse.ui.internal.progress.IJobProgressManagerListener#refreshJobInfo(org.eclipse.ui.internal.progress.JobInfo)
+             */
+            public void refreshJobInfo(JobInfo info) {
+                int state = info.getJob().getState();
+                if (state == Job.RUNNING) {
+					addJob(info);
+				} else {
+					removeJob(info);
+				}
+            }
+
+            /*
+             * (non-Javadoc)
+             * 
+             * @see org.eclipse.ui.internal.progress.IJobProgressManagerListener#refreshAll()
+             */
+            public void refreshAll() {
+                ProgressManager manager = ProgressManager.getInstance();
+                jobs.clear();
+                setAnimated(false);
+                JobInfo[] currentInfos = manager.getJobInfos(showsDebug());
+                for (int i = 0; i < currentInfos.length; i++) {
+                    addJob(currentInfos[i]);
+                }
+            }
+
+            /*
+             * (non-Javadoc)
+             * 
+             * @see org.eclipse.ui.internal.progress.IJobProgressManagerListener#remove(org.eclipse.ui.internal.progress.JobInfo)
+             */
+            public void removeJob(JobInfo info) {
+                decrementJobCount(info.getJob());
+            }
+
+            /*
+             * (non-Javadoc)
+             * 
+             * @see org.eclipse.ui.internal.progress.IJobProgressManagerListener#showsDebug()
+             */
+            public boolean showsDebug() {
+                return false;
+            }
+
+            private void incrementJobCount(JobInfo info) {
+                //Don't count the animate job itself
+                if (isNotTracked(info)) {
+					return;
+				}
+                if (jobs.isEmpty()) {
+					setAnimated(true);
+				}
+                jobs.add(info.getJob());
+            }
+
+            /*
+             * Decrement the job count for the job
+             */
+            private void decrementJobCount(Job job) {
+                jobs.remove(job);
+                if (jobs.isEmpty()) {
+					setAnimated(false);
+				}
+            }
+
+            /**
+             * If this is one of our jobs or not running then don't bother.
+             */
+            private boolean isNotTracked(JobInfo info) {
+                //We always track errors
+                Job job = info.getJob();
+                return job.getState() != Job.RUNNING
+                        || animationProcessor.isProcessorJob(job);
+            }
+
+            /*
+             * (non-Javadoc)
+             * 
+             * @see org.eclipse.ui.internal.progress.IJobProgressManagerListener#addGroup(org.eclipse.ui.internal.progress.GroupInfo)
+             */
+            public void addGroup(GroupInfo info) {
+                //Don't care about groups
+            }
+
+            /*
+             * (non-Javadoc)
+             * 
+             * @see org.eclipse.ui.internal.progress.IJobProgressManagerListener#removeGroup(org.eclipse.ui.internal.progress.GroupInfo)
+             */
+            public void removeGroup(GroupInfo group) {
+                //Don't care about groups
+            }
+
+            /*
+             * (non-Javadoc)
+             * 
+             * @see org.eclipse.ui.internal.progress.IJobProgressManagerListener#refreshGroup(org.eclipse.ui.internal.progress.GroupInfo)
+             */
+            public void refreshGroup(GroupInfo info) {
+                //Don't care about groups
+            }
+        };
+    }
+
+    /**
+     * Get the preferred width for widgets displaying the animation.
+     * 
+     * @return int. Return 0 if there is no image data.
+     */
+    int getPreferredWidth() {
+        return animationProcessor.getPreferredWidth();
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/BlockedJobsDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/BlockedJobsDialog.java
new file mode 100644
index 0000000..83a8e8e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/BlockedJobsDialog.java
@@ -0,0 +1,419 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.progress;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.IconAndMessageDialog;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.rap.rwt.SingletonUtil;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Cursor;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.progress.WorkbenchJob;
+
+/**
+ * The BlockedJobsDialog class displays a dialog that provides information on
+ * the running jobs.
+ */
+public class BlockedJobsDialog extends IconAndMessageDialog {
+    
+    /**
+     * The singleton dialog instance. A singleton avoids the possibility of
+     * recursive dialogs being created. The singleton is created when a dialog
+     * is requested, and cleared when the dialog is disposed.
+     */
+// RAP [fappel]: BlockedJobsDialog needs to be session aware
+//  protected static BlockedJobsDialog singleton;
+  public static class BlockedJobsDialogProvider {
+    public BlockedJobsDialog blockedJobsDialog;
+
+    protected static BlockedJobsDialogProvider getInstance() {
+      return SingletonUtil.getSessionInstance( BlockedJobsDialogProvider.class );
+    }
+  }
+  private static BlockedJobsDialog getSingleton() {
+    return BlockedJobsDialogProvider.getInstance().blockedJobsDialog;
+  }
+  private static void setSingleton( final BlockedJobsDialog dialog ) {
+    BlockedJobsDialogProvider.getInstance().blockedJobsDialog = dialog;
+  }
+  
+	/**
+	 * The singleton dialog instance. A singleton avoids the possibility of
+	 * recursive dialogs being created. The singleton is created when a dialog
+	 * is requested, and cleared when the dialog is disposed.
+	 */
+	protected static BlockedJobsDialog singleton;
+
+	/**
+	 * The running jobs progress viewer.
+	 */
+	private DetailedProgressViewer viewer;
+
+	/**
+	 * The name of the task that is being blocked.
+	 */
+	private String blockedTaskName = ProgressMessages.get().SubTaskInfo_UndefinedTaskName;
+
+	/**
+	 * The Cancel button control.
+	 */
+	private Button cancelSelected;
+
+	/**
+	 * The cursor for the buttons.
+	 */
+	private Cursor arrowCursor;
+
+	/**
+	 * The cursor for the Shell.
+	 */
+	private Cursor waitCursor;
+
+	private IProgressMonitor blockingMonitor;
+
+	private JobTreeElement blockedElement = new BlockedUIElement();
+
+	/**
+	 * The BlockedUIElement is the JobTreeElement that represents the blocked
+	 * job in the dialog.
+	 */
+	private class BlockedUIElement extends JobTreeElement {
+		@Override
+		Object[] getChildren() {
+			return ProgressManagerUtil.EMPTY_OBJECT_ARRAY;
+		}
+
+		@Override
+		String getDisplayString() {
+			if (blockedTaskName == null || blockedTaskName.length() == 0) {
+				return ProgressMessages.get().BlockedJobsDialog_UserInterfaceTreeElement;
+			}
+			return blockedTaskName;
+		}
+
+		@Override
+		public Image getDisplayImage() {
+			return JFaceResources.getImage(ProgressManager.WAITING_JOB_KEY);
+		}
+
+		@Override
+		boolean hasChildren() {
+			return false;
+		}
+
+		@Override
+		boolean isActive() {
+			return true;
+		}
+
+		@Override
+		boolean isJobInfo() {
+			return false;
+		}
+
+		@Override
+		public void cancel() {
+			blockingMonitor.setCanceled(true);
+		}
+
+		@Override
+		public boolean isCancellable() {
+			return true;
+		}
+	}
+
+	/**
+	 * Creates a progress monitor dialog under the given shell. It also sets the
+	 * dialog's message. The dialog is opened automatically after a reasonable
+	 * delay. When no longer needed, the dialog must be closed by calling
+	 * <code>close(IProgressMonitor)</code>, where the supplied monitor is
+	 * the same monitor passed to this factory method.
+	 *
+	 * @param parentShell
+	 *            The parent shell, or <code>null</code> to create a top-level
+	 *            shell. If the parentShell is not null we will open immediately
+	 *            as parenting has been determined. If it is <code>null</code>
+	 *            then the dialog will not open until there is no modal shell
+	 *            blocking it.
+	 * @param blockedMonitor
+	 *            The monitor that is currently blocked
+	 * @param reason
+	 *            A status describing why the monitor is blocked
+	 * @param taskName
+	 *            A name to give the blocking task in the dialog
+	 * @return BlockedJobsDialog
+	 */
+	public static BlockedJobsDialog createBlockedDialog(Shell parentShell,
+			IProgressMonitor blockedMonitor, IStatus reason, String taskName) {
+	 // RAP [fappel]: use session aware getSingleton() call in this method
+
+        // use an existing dialog if available
+        if (getSingleton() != null) {
+            return getSingleton();
+        }
+        setSingleton( new BlockedJobsDialog(parentShell, blockedMonitor, reason) );
+
+        if (taskName == null || taskName.length() == 0)
+            getSingleton()
+                    .setBlockedTaskName(ProgressMessages.get().BlockedJobsDialog_UserInterfaceTreeElement);
+        else
+            getSingleton().setBlockedTaskName(taskName);
+
+		/**
+		 * If there is no parent shell we have not been asked for a parent so we
+		 * want to avoid blocking. If there is a parent then it is OK to open.
+		 */
+		if (parentShell == null) {
+			// Create the job that will open the dialog after a delay.
+			WorkbenchJob dialogJob = new WorkbenchJob(
+					WorkbenchMessages.get().EventLoopProgressMonitor_OpenDialogJobName) {
+				@Override
+				public IStatus runInUIThread(IProgressMonitor monitor) {
+					if (singleton == null) {
+						return Status.CANCEL_STATUS;
+					}
+					if (ProgressManagerUtil.rescheduleIfModalShellOpen(this)) {
+						return Status.CANCEL_STATUS;
+					}
+					singleton.open();
+					return Status.OK_STATUS;
+				}
+			};
+			// Wait for long operation time to prevent a proliferation of
+			// dialogs.
+			dialogJob.setSystem(true);
+			dialogJob.schedule(PlatformUI.getWorkbench().getProgressService()
+					.getLongOperationTime());
+		} else {
+			singleton.open();
+		}
+
+		return singleton;
+	}
+
+	/**
+	 * The monitor is done. Clear the receiver.
+	 *
+	 * @param monitor
+	 *            The monitor that is now cleared.
+	 */
+	public static void clear(IProgressMonitor monitor) {
+// RAP [fappel]: use session aware getSingleton() call in this method
+        if (getSingleton() == null) {
+            return;
+        }
+        getSingleton().close(monitor);
+	}
+
+	/**
+	 * Creates a progress monitor dialog under the given shell. It also sets the
+	 * dialog's\ message. <code>open</code> is non-blocking.
+	 *
+	 * @param parentShell
+	 *            The parent shell, or <code>null</code> to create a top-level
+	 *            shell.
+	 * @param blocking
+	 *            The monitor that is blocking the job
+	 * @param blockingStatus
+	 *            A status describing why the monitor is blocked
+	 */
+	private BlockedJobsDialog(Shell parentShell, IProgressMonitor blocking,
+			IStatus blockingStatus) {
+		super(parentShell == null ? ProgressManagerUtil.getDefaultParent()
+				: parentShell);
+		blockingMonitor = blocking;
+		setShellStyle(SWT.BORDER | SWT.TITLE | SWT.APPLICATION_MODAL
+				| SWT.RESIZE | SWT.MAX | getDefaultOrientation());
+		// no close button
+		setBlockOnOpen(false);
+		setMessage(blockingStatus.getMessage());
+	}
+
+	/**
+	 * Creates the dialog area under the parent composite.
+	 *
+	 * @param parent
+	 *            The parent Composite.
+	 *
+	 * @return parent The parent Composite.
+	 */
+	@Override
+	protected Control createDialogArea(Composite parent) {
+		setMessage(message);
+		createMessageArea(parent);
+		showJobDetails(parent);
+		return parent;
+	}
+
+	/**
+	 * Creates a dialog area in the parent composite and displays a progress
+	 * tree viewer of the running jobs.
+	 *
+	 * @param parent
+	 *            The parent Composite.
+	 */
+	void showJobDetails(Composite parent) {
+		viewer = new DetailedProgressViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
+		viewer.setComparator(new ViewerComparator() {
+			@Override
+			@SuppressWarnings("unchecked")
+			public int compare(Viewer testViewer, Object e1, Object e2) {
+				return ((Comparable<Object>) e1).compareTo(e2);
+			}
+		});
+		ProgressViewerContentProvider provider = getContentProvider();
+		viewer.setContentProvider(provider);
+		viewer.setInput(provider);
+		viewer.setLabelProvider(new ProgressLabelProvider());
+		GridData data = new GridData(GridData.GRAB_HORIZONTAL
+				| GridData.GRAB_VERTICAL | GridData.FILL_BOTH);
+		data.horizontalSpan = 2;
+		int heightHint = convertHeightInCharsToPixels(10);
+		data.heightHint = heightHint;
+		viewer.getControl().setLayoutData(data);
+	}
+
+	/**
+	 * Returns the content provider used for the receiver.
+	 *
+	 * @return ProgressTreeContentProvider
+	 */
+	private ProgressViewerContentProvider getContentProvider() {
+		return new ProgressViewerContentProvider(viewer, true, false) {
+			@Override
+			public Object[] getElements(Object inputElement) {
+				Object[] elements = super.getElements(inputElement);
+				Object[] result = new Object[elements.length + 1];
+				System.arraycopy(elements, 0, result, 1, elements.length);
+				result[0] = blockedElement;
+				return result;
+			}
+		};
+	}
+
+	/**
+	 * Clears the cursors in the dialog.
+	 */
+	private void clearCursors() {
+		clearCursor(cancelSelected);
+		clearCursor(getShell());
+		if (arrowCursor != null) {
+			arrowCursor.dispose();
+		}
+		if (waitCursor != null) {
+			waitCursor.dispose();
+		}
+		arrowCursor = null;
+		waitCursor = null;
+	}
+
+	/**
+	 * Clears the cursor on the supplied control.
+	 *
+	 * @param control
+	 */
+	private void clearCursor(Control control) {
+		if (control != null && !control.isDisposed()) {
+			control.setCursor(null);
+		}
+	}
+
+	@Override
+	protected void configureShell(Shell shell) {
+		super.configureShell(shell);
+		shell.setText(ProgressMessages.get().BlockedJobsDialog_BlockedTitle);
+		if (waitCursor == null) {
+			waitCursor = new Cursor(shell.getDisplay(), SWT.CURSOR_WAIT);
+		}
+		shell.setCursor(waitCursor);
+	}
+
+	/**
+	 * This method sets the message in the message label.
+	 *
+	 * @param messageString
+	 *            the String for the message area
+	 */
+	private void setMessage(String messageString) {
+		// must not set null text in a label
+		message = messageString == null ? "" : messageString; //$NON-NLS-1$
+		if (messageLabel == null || messageLabel.isDisposed()) {
+			return;
+		}
+		messageLabel.setText(message);
+	}
+
+	@Override
+	protected Image getImage() {
+		return getInfoImage();
+	}
+
+	/**
+	 * Returns the progress monitor being used for this dialog. This allows
+	 * recursive blockages to also respond to cancelation.
+	 *
+	 * @return IProgressMonitor
+	 */
+	public IProgressMonitor getProgressMonitor() {
+		return blockingMonitor;
+	}
+
+	/**
+	 * Requests that the blocked jobs dialog be closed. The supplied monitor
+	 * must be the same one that was passed to the createBlockedDialog method.
+	 *
+	 * @param monitor
+	 * @return IProgressMonitor
+	 */
+	public boolean close(IProgressMonitor monitor) {
+		// ignore requests to close the dialog from all but the first monitor
+		if (blockingMonitor != monitor) {
+			return false;
+		}
+		return close();
+	}
+
+	@Override
+	public boolean close() {
+        // Clear the singleton first
+// RAP [fappel]:
+//      singleton = null;
+        setSingleton( null );
+        clearCursors();
+        return super.close();
+	}
+
+	@Override
+	protected Control createButtonBar(Composite parent) {
+		// Do nothing here as we want no buttons
+		return parent;
+	}
+
+	/**
+	 * @param taskName
+	 *            The blockedTaskName to set.
+	 */
+	void setBlockedTaskName(String taskName) {
+		this.blockedTaskName = taskName;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/DetailedProgressViewer.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/DetailedProgressViewer.java
new file mode 100644
index 0000000..6f197b7
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/DetailedProgressViewer.java
@@ -0,0 +1,460 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.progress;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.ScrolledComposite;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.ControlListener;
+import org.eclipse.swt.events.FocusAdapter;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.Widget;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+
+/**
+ * The DetailedProgressViewer is a viewer that shows the details of all in
+ * progress job or jobs that are finished awaiting user input.
+ *
+ * @since 3.2
+ *
+ */
+public class DetailedProgressViewer extends AbstractProgressViewer {
+
+	//Maximum number of entries to display so that the view does not flood the UI with events
+	private static final int MAX_DISPLAYED = 20;
+
+	Composite control;
+
+	private ScrolledComposite scrolled;
+
+	private Composite noEntryArea;
+
+	/**
+	 * Create a new instance of the receiver with a control that is a child of
+	 * parent with style style.
+	 *
+	 * @param parent
+	 * @param style
+	 */
+	public DetailedProgressViewer(Composite parent, int style) {
+		scrolled = new ScrolledComposite(parent, SWT.V_SCROLL | style);
+		// RAP [fappel]: setIncrement not available
+//		int height = JFaceResources.getDefaultFont().getFontData()[0]
+//				.getHeight();
+//		scrolled.getVerticalBar().setIncrement(height * 2);
+		scrolled.setExpandHorizontal(true);
+		scrolled.setExpandVertical(true);
+
+		control = new Composite(scrolled, SWT.NONE);
+		GridLayout layout = new GridLayout();
+		layout.marginHeight = 0;
+		layout.marginWidth = 0;
+		control.setLayout(layout);
+		control.setBackground(parent.getDisplay().getSystemColor(
+				SWT.COLOR_LIST_BACKGROUND));
+
+		control.addFocusListener(new FocusAdapter() {
+
+			private boolean settingFocus = false;
+
+			@Override
+			public void focusGained(FocusEvent e) {
+				if (!settingFocus) {
+					// Prevent new focus events as a result this update
+					// occurring
+					settingFocus = true;
+					setFocus();
+					settingFocus = false;
+				}
+			}
+		});
+
+		control.addControlListener(new ControlListener() {
+			@Override
+			public void controlMoved(ControlEvent e) {
+				updateVisibleItems();
+
+			}
+
+			@Override
+			public void controlResized(ControlEvent e) {
+				updateVisibleItems();
+			}
+		});
+
+		PlatformUI.getWorkbench().getHelpSystem().setHelp(control,
+				IWorkbenchHelpContextIds.RESPONSIVE_UI);
+
+		scrolled.setContent(control);
+		hookControl(control);
+
+		noEntryArea = new Composite(scrolled, SWT.NONE);
+		noEntryArea.setLayout(new GridLayout());
+		noEntryArea.setBackground(noEntryArea.getDisplay()
+				.getSystemColor(SWT.COLOR_LIST_BACKGROUND));
+
+		Text noEntryLabel = new Text(noEntryArea, SWT.SINGLE);
+		noEntryLabel.setText(ProgressMessages.get().ProgressView_NoOperations);
+		noEntryLabel.setBackground(noEntryArea.getDisplay().getSystemColor(
+				SWT.COLOR_LIST_BACKGROUND));
+		GridData textData = new GridData(GridData.VERTICAL_ALIGN_BEGINNING);
+		noEntryLabel.setLayoutData(textData);
+		noEntryLabel.setEditable(false);
+
+		PlatformUI.getWorkbench().getHelpSystem().setHelp(noEntryLabel,
+				IWorkbenchHelpContextIds.RESPONSIVE_UI);
+
+	}
+
+	@Override
+	public void add(Object[] elements) {
+		ViewerComparator sorter = getComparator();
+
+		// Use a Set in case we are getting something added that exists
+		Set newItems = new HashSet(elements.length);
+
+		Control[] existingChildren = control.getChildren();
+		for (Control child : existingChildren) {
+			if (child.getData() != null)
+				newItems.add(child.getData());
+		}
+
+		for (Object element : elements) {
+			if (element != null)
+				newItems.add(element);
+		}
+
+		JobTreeElement[] infos = new JobTreeElement[newItems.size()];
+		newItems.toArray(infos);
+
+		if (sorter != null) {
+			sorter.sort(this, infos);
+		}
+
+		// Update with the new elements to prevent flash
+		for (Control child : existingChildren) {
+			((ProgressInfoItem) child).dispose();
+		}
+
+		int totalSize = Math.min(newItems.size(), MAX_DISPLAYED);
+
+		for (int i = 0; i < totalSize; i++) {
+			ProgressInfoItem item = createNewItem(infos[i]);
+			item.setColor(i);
+		}
+
+		control.layout(true);
+		updateForShowingProgress();
+	}
+
+	/**
+	 * Update for the progress being displayed.
+	 */
+	private void updateForShowingProgress() {
+		if (control.getChildren().length > 0) {
+			updateSize();
+			scrolled.setContent(control);
+		} else {
+			scrolled.setMinSize(null);
+			scrolled.setContent(noEntryArea);
+		}
+	}
+
+	/**
+	 * Create a new item for info.
+	 *
+	 * @param info
+	 * @return ProgressInfoItem
+	 */
+	private ProgressInfoItem createNewItem(JobTreeElement info) {
+		final ProgressInfoItem item = new ProgressInfoItem(control, SWT.NONE,
+				info);
+
+		item.setIndexListener(new ProgressInfoItem.IndexListener() {
+			@Override
+			public void selectNext() {
+				DetailedProgressViewer.this.selectNext(item);
+
+			}
+
+			@Override
+			public void selectPrevious() {
+				DetailedProgressViewer.this.selectPrevious(item);
+
+			}
+
+			@Override
+			public void select() {
+				for (Control element : control.getChildren()) {
+					ProgressInfoItem child = (ProgressInfoItem) element;
+					if (!item.equals(child)) {
+						child.selectWidgets(false);
+					}
+				}
+				item.selectWidgets(true);
+
+			}
+		});
+
+		// Refresh to populate with the current tasks
+		item.refresh();
+		return item;
+	}
+
+	/**
+	 * Select the previous item in the receiver.
+	 *
+	 * @param item
+	 */
+	protected void selectPrevious(ProgressInfoItem item) {
+		Control[] children = control.getChildren();
+		for (int i = 0; i < children.length; i++) {
+			ProgressInfoItem child = (ProgressInfoItem) children[i];
+			if (item.equals(child)) {
+				ProgressInfoItem previous;
+				if (i == 0) {
+					previous = (ProgressInfoItem) children[children.length - 1];
+				} else {
+					previous = (ProgressInfoItem) children[i - 1];
+				}
+
+				item.selectWidgets(false);
+				previous.selectWidgets(true);
+				return;
+			}
+		}
+	}
+
+	/**
+	 * Select the next item in the receiver.
+	 *
+	 * @param item
+	 */
+	protected void selectNext(ProgressInfoItem item) {
+		Control[] children = control.getChildren();
+		for (int i = 0; i < children.length; i++) {
+			ProgressInfoItem child = (ProgressInfoItem) children[i];
+			if (item.equals(child)) {
+				ProgressInfoItem next;
+				if (i == children.length - 1) {
+					next = (ProgressInfoItem) children[0];
+				} else {
+					next = (ProgressInfoItem) children[i + 1];
+				}
+				item.selectWidgets(false);
+				next.selectWidgets(true);
+
+				return;
+			}
+		}
+
+	}
+
+	@Override
+	protected Widget doFindInputItem(Object element) {
+		return null;
+	}
+
+	@Override
+	protected Widget doFindItem(Object element) {
+		for (Control control : control.getChildren()) {
+			if (control.isDisposed()
+					|| control.getData() == null) {
+				continue;
+			}
+			if (control.getData().equals(element)) {
+				return control;
+			}
+		}
+		return null;
+	}
+
+	@Override
+	protected void doUpdateItem(Widget item, Object element, boolean fullMap) {
+		if (usingElementMap()) {
+			unmapElement(item);
+		}
+		item.dispose();
+		add(new Object[] { element });
+	}
+
+	@Override
+	public Control getControl() {
+		return scrolled;
+	}
+
+	@Override
+	protected List getSelectionFromWidget() {
+		return new ArrayList(0);
+	}
+
+	@Override
+	protected void inputChanged(Object input, Object oldInput) {
+		super.inputChanged(input, oldInput);
+		refreshAll();
+	}
+
+	@Override
+	protected void internalRefresh(Object element) {
+		if (element == null) {
+			return;
+		}
+
+		if (element.equals(getRoot())) {
+			refreshAll();
+			return;
+		}
+		Widget widget = findItem(element);
+		if (widget == null) {
+			add(new Object[] { element });
+			return;
+		}
+		((ProgressInfoItem) widget).refresh();
+
+		updateSize();
+	}
+
+	@Override
+	public void remove(Object[] elements) {
+
+		for (Object element : elements) {
+			JobTreeElement treeElement = (JobTreeElement) element;
+			// Make sure we are not keeping this one
+			if (FinishedJobs.getInstance().isKept(treeElement)) {
+				Widget item = doFindItem(element);
+				if (item != null) {
+					((ProgressInfoItem) item).refresh();
+				}
+
+			} else {
+				Widget item = doFindItem(treeElement);
+				if (item == null) {
+					// Is the parent showing?
+					Object parent = treeElement.getParent();
+					if (parent != null)
+						item = doFindItem(parent);
+				}
+				if (item != null) {
+					unmapElement(element);
+					item.dispose();
+				}
+			}
+		}
+
+		Control[] existingChildren = control.getChildren();
+		for (int i = 0; i < existingChildren.length; i++) {
+			ProgressInfoItem item = (ProgressInfoItem) existingChildren[i];
+			item.setColor(i);
+		}
+		control.layout(true);
+		updateForShowingProgress();
+	}
+
+	@Override
+	public void reveal(Object element) {
+
+	}
+
+	@Override
+	protected void setSelectionToWidget(List l, boolean reveal) {
+
+	}
+
+	/**
+	 * Cancel the current selection
+	 *
+	 */
+	public void cancelSelection() {
+
+	}
+
+	/**
+	 * Set focus on the current selection.
+	 *
+	 */
+	public void setFocus() {
+		Control[] children = control.getChildren();
+		if (children.length > 0) {
+			((ProgressInfoItem)children[0]).setButtonFocus();
+		} else {
+			noEntryArea.setFocus();
+		}
+	}
+
+	/**
+	 * Refresh everything as the root is being refreshed.
+	 */
+	private void refreshAll() {
+
+		Object[] infos = getSortedChildren(getRoot());
+
+		for (Control control : control.getChildren()) {
+			control.dispose();
+
+		}
+
+		int maxLength = Math.min(infos.length,MAX_DISPLAYED);
+		// Create new ones if required
+		for (int i = 0; i < maxLength; i++) {
+			ProgressInfoItem item = createNewItem((JobTreeElement) infos[i]);
+			item.setColor(i);
+		}
+
+		control.layout(true);
+		updateForShowingProgress();
+	}
+
+	/**
+	 * Set the virtual items to be visible or not depending on the displayed
+	 * area.
+	 */
+	private void updateVisibleItems() {
+		int top = scrolled.getOrigin().y;
+		int bottom = top + scrolled.getParent().getBounds().height;
+		for (Control control : control.getChildren()) {
+			ProgressInfoItem item = (ProgressInfoItem) control;
+			item.setDisplayed(top, bottom);
+		}
+	}
+
+	/**
+	 * Update the minimum size for scrolled composite.
+	 */
+	private void updateSize() {
+		Point size = control.computeSize(SWT.DEFAULT, SWT.DEFAULT);
+		size.x += IDialogConstants.HORIZONTAL_SPACING;
+		size.y += IDialogConstants.VERTICAL_SPACING;
+
+		scrolled.setMinSize(size);
+	}
+
+	public ProgressInfoItem[] getProgressInfoItems() {
+		Control[] children = control.getChildren();
+		ProgressInfoItem[] progressInfoItems = new ProgressInfoItem[children.length];
+		System.arraycopy(children, 0, progressInfoItems, 0, children.length);
+		return progressInfoItems;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ErrorInfo.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ErrorInfo.java
new file mode 100644
index 0000000..3154abd
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ErrorInfo.java
@@ -0,0 +1,114 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.internal.progress;
+
+import com.ibm.icu.text.DateFormat;
+import java.util.Date;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * ErrorInfo is the info that displays errors.
+ */
+public class ErrorInfo extends JobTreeElement {
+	private final IStatus errorStatus;
+	private final Job job;
+	private final long timestamp;
+
+	/**
+	 * Creates a new instance of ErrorInfo.
+	 *
+	 * @param status
+	 * @param job
+	 *            the Job to create
+	 */
+	public ErrorInfo(IStatus status, Job job) {
+		errorStatus = status;
+		this.job = job;
+		timestamp = System.currentTimeMillis();
+	}
+
+	@Override
+	boolean hasChildren() {
+		return false;
+	}
+
+	@Override
+	Object[] getChildren() {
+		return ProgressManagerUtil.EMPTY_OBJECT_ARRAY;
+	}
+
+	@Override
+	String getDisplayString() {
+		return NLS.bind(ProgressMessages.get().JobInfo_Error, (new Object[] {
+				job.getName(),
+				DateFormat.getDateTimeInstance(DateFormat.LONG,DateFormat.LONG).format(new Date(timestamp)) }));
+	}
+
+	/**
+	 * Returns the image for the receiver.
+	 *
+	 * @return Image
+	 */
+	Image getImage() {
+		return JFaceResources.getImage(ProgressManager.ERROR_JOB_KEY);
+	}
+
+	@Override
+	boolean isJobInfo() {
+		return false;
+	}
+
+	/**
+	 * Returns the current status of the receiver.
+	 *
+	 * @return IStatus
+	 */
+	IStatus getErrorStatus() {
+		return errorStatus;
+	}
+
+	@Override
+	boolean isActive() {
+		return true;
+	}
+
+	/**
+	 * Returns the job that generated the error.
+	 *
+	 * @return the job that generated the error
+	 */
+	public Job getJob() {
+		return job;
+	}
+
+	/**
+	 * Returns the timestamp for the job.
+	 *
+	 * @return long
+	 */
+	public long getTimestamp() {
+		return timestamp;
+	}
+
+	@Override
+	public int compareTo(JobTreeElement other) {
+		if (other instanceof ErrorInfo) {
+			// Order ErrorInfo by time received.
+			return Long.compare(timestamp, ((ErrorInfo) other).timestamp);
+		}
+
+		return super.compareTo(other);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/FinishedJobs.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/FinishedJobs.java
new file mode 100644
index 0000000..a861252
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/FinishedJobs.java
@@ -0,0 +1,404 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.internal.progress;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
+import org.eclipse.core.commands.common.EventManager;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.ui.actions.ActionFactory;
+import org.eclipse.ui.progress.IProgressConstants;
+
+/**
+ * This singleton remembers all JobTreeElements that should be preserved (e.g.
+ * because their associated Jobs have the "keep" property set).
+ */
+public class FinishedJobs extends EventManager {
+
+	/*
+	 * Interface for notify listeners.
+	 */
+	static interface KeptJobsListener {
+
+		/**
+		 * A job to be kept has finished
+		 *
+		 * @param jte
+		 */
+		void finished(JobTreeElement jte);
+
+		/**
+		 * A kept job has been removed.
+		 *
+		 * @param jte
+		 */
+		void removed(JobTreeElement jte);
+	}
+
+	private static FinishedJobs theInstance;
+
+	private IJobProgressManagerListener listener;
+
+	private HashSet keptjobinfos = new HashSet();
+
+	private HashMap finishedTime = new HashMap();
+
+	private static JobTreeElement[] EMPTY_INFOS;
+
+	public static synchronized FinishedJobs getInstance() {
+		if (theInstance == null) {
+			theInstance = new FinishedJobs();
+			EMPTY_INFOS = new JobTreeElement[0];
+		}
+		return theInstance;
+	}
+
+	private FinishedJobs() {
+		listener = new IJobProgressManagerListener() {
+			@Override
+			public void addJob(JobInfo info) {
+				checkForDuplicates(info);
+			}
+
+			@Override
+			public void addGroup(GroupInfo info) {
+				checkForDuplicates(info);
+			}
+
+			@Override
+			public void refreshJobInfo(JobInfo info) {
+				checkTasks(info);
+			}
+
+			@Override
+			public void refreshGroup(GroupInfo info) {
+			}
+
+			@Override
+			public void refreshAll() {
+			}
+
+			@Override
+			public void removeJob(JobInfo info) {
+				if (keep(info)) {
+					checkForDuplicates(info);
+					add(info);
+				}
+			}
+
+			@Override
+			public void removeGroup(GroupInfo group) {
+			}
+
+			@Override
+			public boolean showsDebug() {
+				return false;
+			}
+		};
+		ProgressManager.getInstance().addListener(listener);
+	}
+
+	/**
+	 * Returns true if JobInfo indicates that it must be kept.
+	 */
+	static boolean keep(JobInfo info) {
+		Job job = info.getJob();
+		if (job != null) {
+			Object prop = job.getProperty(ProgressManagerUtil.KEEP_PROPERTY);
+			if (prop instanceof Boolean) {
+				if (((Boolean) prop).booleanValue()) {
+					return true;
+				}
+			}
+
+			prop = job.getProperty(ProgressManagerUtil.KEEPONE_PROPERTY);
+			if (prop instanceof Boolean) {
+				if (((Boolean) prop).booleanValue()) {
+					return true;
+				}
+			}
+
+			IStatus status = job.getResult();
+			if (status != null && status.getSeverity() == IStatus.ERROR) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Register for notification.
+	 */
+	void addListener(KeptJobsListener l) {
+		addListenerObject(l);
+	}
+
+	/**
+	 * Deregister for notification.
+	 */
+	void removeListener(KeptJobsListener l) {
+		removeListenerObject(l);
+	}
+
+	private void checkForDuplicates(GroupInfo info) {
+		for (Object child : info.getChildren()) {
+			if (child instanceof JobInfo) {
+				checkForDuplicates((JobInfo) child);
+			}
+		}
+	}
+
+	private void checkForDuplicates(JobTreeElement info) {
+		JobTreeElement[] toBeRemoved = findJobsToRemove(info);
+		if (toBeRemoved != null) {
+			for (JobTreeElement element : toBeRemoved) {
+				remove(element);
+			}
+		}
+	}
+
+	/**
+	 * Add given Job to list of kept jobs.
+	 */
+	private void add(JobInfo info) {
+		boolean fire = false;
+
+		if (!keptjobinfos.contains(info)) {
+			keptjobinfos.add(info);
+
+			long now = System.currentTimeMillis();
+			finishedTime.put(info, new Long(now));
+
+			Object parent = info.getParent();
+			if (!(parent == null || keptjobinfos.contains(parent))) {
+				keptjobinfos.add(parent);
+				finishedTime.put(parent, new Long(now));
+			}
+
+			fire = true;
+		}
+
+		if (fire) {
+			for (Object listener : getListeners()) {
+				KeptJobsListener jv = (KeptJobsListener) listener;
+				jv.finished(info);
+			}
+		}
+	}
+
+	static void disposeAction(JobTreeElement jte) {
+		if (jte.isJobInfo()) {
+			JobInfo ji = (JobInfo) jte;
+			Job job = ji.getJob();
+			if (job != null) {
+				Object prop = job
+						.getProperty(IProgressConstants.ACTION_PROPERTY);
+				if (prop instanceof ActionFactory.IWorkbenchAction) {
+					((ActionFactory.IWorkbenchAction) prop).dispose();
+				}
+			}
+		}
+	}
+
+	private JobTreeElement[] findJobsToRemove(JobTreeElement info) {
+
+		if (info.isJobInfo()) {
+			Job myJob = ((JobInfo) info).getJob();
+
+			if (myJob != null) {
+
+				Object prop = myJob.getProperty(ProgressManagerUtil.KEEPONE_PROPERTY);
+				if (prop instanceof Boolean && ((Boolean) prop).booleanValue()) {
+					ArrayList found = null;
+					JobTreeElement[] all;
+					all = (JobTreeElement[]) keptjobinfos.toArray(new JobTreeElement[keptjobinfos.size()]);
+					for (JobTreeElement jobTreeElement : all) {
+						if (jobTreeElement != info && jobTreeElement.isJobInfo()) {
+							Job job = ((JobInfo) jobTreeElement).getJob();
+							if (job != null && job != myJob
+									&& job.belongsTo(myJob)) {
+								if (found == null) {
+									found = new ArrayList();
+								}
+								found.add(jobTreeElement);
+							}
+						}
+					}
+					if (found != null) {
+						return (JobTreeElement[]) found
+								.toArray(new JobTreeElement[found.size()]);
+					}
+				}
+			}
+		}
+		return null;
+	}
+
+	private void checkTasks(JobInfo info) {
+		if (keep(info)) {
+			TaskInfo tinfo = info.getTaskInfo();
+			if (tinfo != null) {
+				JobTreeElement[] toBeRemoved = null;
+				boolean fire = false;
+				JobTreeElement element = (JobTreeElement) tinfo.getParent();
+				if (element == info && !keptjobinfos.contains(tinfo)) {
+					toBeRemoved = findJobsToRemove(element);
+					keptjobinfos.add(tinfo);
+					finishedTime.put(tinfo, new Long(System.currentTimeMillis()));
+				}
+
+				if (toBeRemoved != null) {
+					for (JobTreeElement jobTreeElement : toBeRemoved) {
+						remove(jobTreeElement);
+					}
+				}
+
+				if (fire) {
+					for (Object listener : getListeners()) {
+						KeptJobsListener jv = (KeptJobsListener) listener;
+						jv.finished(info);
+					}
+				}
+			}
+		}
+	}
+
+	public void removeErrorJobs() {
+		JobTreeElement[] infos = getKeptElements();
+		for (JobTreeElement info : infos) {
+			if (info.isJobInfo()) {
+				JobInfo info1 = (JobInfo) info;
+				Job job = info1.getJob();
+				if (job != null) {
+					IStatus status = job.getResult();
+					if (status != null && status.getSeverity() == IStatus.ERROR) {
+						JobTreeElement topElement = (JobTreeElement) info1
+								.getParent();
+						if (topElement == null) {
+							topElement = info1;
+						}
+						FinishedJobs.getInstance().remove(topElement);
+					}
+				}
+			}
+		}
+	}
+
+	boolean remove(JobTreeElement jte) {
+		boolean fire = false;
+		boolean removed = false;
+
+		if (keptjobinfos.remove(jte)) {
+			removed = true;
+			finishedTime.remove(jte);
+			disposeAction(jte);
+
+			// delete all elements that have jte as their direct or indirect
+			// parent
+			JobTreeElement jtes[] = (JobTreeElement[]) keptjobinfos.toArray(new JobTreeElement[keptjobinfos.size()]);
+			for (JobTreeElement jobTreeElement : jtes) {
+				JobTreeElement parent = (JobTreeElement) jobTreeElement.getParent();
+				if (parent != null) {
+					if (parent == jte || parent.getParent() == jte) {
+						if (keptjobinfos.remove(jobTreeElement)) {
+							disposeAction(jobTreeElement);
+						}
+						finishedTime.remove(jobTreeElement);
+					}
+				}
+			}
+			fire = true;
+		}
+
+		if (fire) {
+			// notify listeners
+			for (Object listener : getListeners()) {
+				KeptJobsListener jv = (KeptJobsListener) listener;
+				jv.removed(jte);
+			}
+		}
+		return removed;
+	}
+
+	/**
+	 * Returns all kept elements.
+	 */
+	JobTreeElement[] getKeptElements() {
+		JobTreeElement[] all;
+		if (keptjobinfos.isEmpty()) {
+			return EMPTY_INFOS;
+		}
+
+		synchronized (keptjobinfos) {
+			all = (JobTreeElement[]) keptjobinfos
+					.toArray(new JobTreeElement[keptjobinfos.size()]);
+		}
+
+		return all;
+	}
+
+	/**
+	 * Get the date that indicates the finish time.
+	 *
+	 * @param jte
+	 * @return Date
+	 */
+	public Date getFinishDate(JobTreeElement jte) {
+		Object o = finishedTime.get(jte);
+		if (o instanceof Long) {
+			return new Date(((Long) o).longValue());
+		}
+		return null;
+	}
+
+	/**
+	 * Return whether or not the kept infos have the element.
+	 *
+	 * @param element
+	 * @return boolean
+	 */
+	public boolean isKept(JobTreeElement element) {
+		return keptjobinfos.contains(element);
+	}
+
+	/**
+	 * Clear all kept jobs.
+	 */
+	public void clearAll() {
+		synchronized (keptjobinfos) {
+			JobTreeElement[] all = (JobTreeElement[]) keptjobinfos
+					.toArray(new JobTreeElement[keptjobinfos.size()]);
+			for (JobTreeElement jobTreeElement : all) {
+				disposeAction(jobTreeElement);
+			}
+			keptjobinfos.clear();
+			finishedTime.clear();
+		}
+
+		// notify listeners
+		for (Object listener : getListeners()) {
+			KeptJobsListener jv = (KeptJobsListener) listener;
+			jv.removed(null);
+		}
+	}
+
+	/**
+	 * Return the set of kept jobs.
+	 * @return Set
+	 */
+	Set getKeptAsSet() {
+		return keptjobinfos;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/GroupInfo.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/GroupInfo.java
new file mode 100644
index 0000000..067dcf1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/GroupInfo.java
@@ -0,0 +1,207 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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
+ *     Michael Fraenkel <fraenkel@us.ibm.com> - Fix for bug 60698 -
+ *     [Progress] ConcurrentModificationException in NewProgressViewer.
+ *******************************************************************************/
+package org.eclipse.ui.internal.progress;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * The GroupInfo is the object used to display group properties.
+ */
+
+class GroupInfo extends JobTreeElement implements IProgressMonitor {
+	private List<JobInfo> infos = new ArrayList<>();
+	private Object lock = new Object();
+	private String taskName = ProgressMessages.get().SubTaskInfo_UndefinedTaskName;
+	boolean isActive;
+	double total = -1;
+	double currentWork;
+
+	@Override
+	boolean hasChildren() {
+		synchronized (lock) {
+			return !infos.isEmpty();
+		}
+	}
+
+	@Override
+	Object[] getChildren() {
+		synchronized (lock) {
+			return infos.toArray();
+		}
+	}
+
+	@Override
+	String getDisplayString() {
+		if (total < 0) {
+			return taskName;
+		}
+		String[] messageValues = new String[2];
+		messageValues[0] = taskName;
+		messageValues[1] = String.valueOf(getPercentDone());
+		return NLS.bind(ProgressMessages.get().JobInfo_NoTaskNameDoneMessage, messageValues);
+	}
+
+	/**
+	 * Returns an integer representing the amount of work completed.
+	 *
+	 * @return int
+	 */
+	int getPercentDone() {
+		return (int) (currentWork * 100 / total);
+	}
+
+	@Override
+	boolean isJobInfo() {
+		return false;
+	}
+
+	@Override
+	public void beginTask(String name, int totalWork) {
+		if (name == null) {
+			name = ProgressMessages.get().SubTaskInfo_UndefinedTaskName;
+		} else {
+			taskName = name;
+		}
+		total = totalWork;
+		synchronized (lock) {
+			isActive = true;
+		}
+		ProgressManager.getInstance().refreshGroup(this);
+	}
+
+	@Override
+	public void done() {
+		synchronized (lock) {
+			isActive = false;
+		}
+		updateInProgressManager();
+	}
+
+	/**
+	 * Updates the receiver in the progress manager. If all of the jobs are
+	 * finished and the receiver is not being kept then remove it.
+	 */
+	private void updateInProgressManager() {
+		for (JobInfo info : infos) {
+			if (!(info.getJob().getState() == Job.NONE)) {
+				ProgressManager.getInstance().refreshGroup(this);
+				return;
+			}
+		}
+
+		if (FinishedJobs.getInstance().isKept(this)) {
+			ProgressManager.getInstance().refreshGroup(this);
+		} else {
+			ProgressManager.getInstance().removeGroup(this);
+		}
+	}
+
+	@Override
+	public void internalWorked(double work) {
+		synchronized (lock) {
+			currentWork += work;
+		}
+	}
+
+	@Override
+	public boolean isCanceled() {
+		// Just a group so no cancel state.
+		return false;
+	}
+
+	@Override
+	public void setCanceled(boolean value) {
+		cancel();
+	}
+
+	@Override
+	public void setTaskName(String name) {
+		synchronized (this) {
+			isActive = true;
+		}
+		if (name == null) {
+			taskName = ProgressMessages.get().SubTaskInfo_UndefinedTaskName;
+		} else {
+			taskName = name;
+		}
+	}
+
+	@Override
+	public void subTask(String name) {
+		// Not interesting for this monitor.
+	}
+
+	@Override
+	public void worked(int work) {
+		internalWorked(work);
+	}
+
+	/**
+	 * Removes the job from the list of jobs.
+	 *
+	 * @param job
+	 */
+	void removeJobInfo(final JobInfo job) {
+		synchronized (lock) {
+			infos.remove(job);
+			if (infos.isEmpty()) {
+				done();
+			}
+		}
+	}
+
+	/**
+	 * Removes the job from the list of jobs.
+	 *
+	 * @param job
+	 */
+	void addJobInfo(final JobInfo job) {
+		synchronized (lock) {
+			infos.add(job);
+		}
+	}
+
+	@Override
+	boolean isActive() {
+		return isActive;
+	}
+
+	@Override
+	public void cancel() {
+		for (Object jobInfo : getChildren()) {
+			((JobInfo) jobInfo).cancel();
+		}
+		// Call the refresh so that this is updated immediately
+		updateInProgressManager();
+	}
+
+	@Override
+	public boolean isCancellable() {
+		return true;
+	}
+
+	/**
+	 * Get the task name for the receiver.
+	 *
+	 * @return String
+	 */
+	String getTaskName() {
+		return taskName;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/IAnimationProcessor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/IAnimationProcessor.java
new file mode 100644
index 0000000..371fef8
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/IAnimationProcessor.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.progress;
+
+import org.eclipse.core.runtime.jobs.Job;
+
+/**
+ * The IAnimationProcessor is the class that handles the animation of
+ * the animation item.
+ */
+interface IAnimationProcessor {
+
+    /**
+     * Add an item to the list of the items we are updating.
+     * @param item
+     */
+    void addItem(AnimationItem item);
+
+    /**
+     * Remove an item from the list of the items we are updating.
+     * @param item
+     */
+    void removeItem(AnimationItem item);
+
+    /**
+     * Return whether or not the receiver has any items.
+     * @return
+     */
+    boolean hasItems();
+
+    /**
+     * Animation has begun. Inform any listeners. This is called
+     * from the UI Thread.
+     */
+    void animationStarted();
+
+    /**
+     * Animation has finished. Inform any listeners. This is called
+     * from the UI Thread.
+     */
+    void animationFinished();
+
+    /**
+     * Get the preferred width of the types of items this
+     * processor manages.
+     * @return
+     */
+    int getPreferredWidth();
+
+    /**
+     * Return whether or not this is a job used by the processor.
+     * @param job
+     * @return
+     */
+    boolean isProcessorJob(Job job);
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/IJobBusyListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/IJobBusyListener.java
new file mode 100644
index 0000000..d984b09
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/IJobBusyListener.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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 - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.progress;
+
+import org.eclipse.core.runtime.jobs.Job;
+
+/**
+ * The IJobBusyListener is used to listen for running and
+ * terminating of jobs of a particular family.
+ */
+interface IJobBusyListener {
+
+    /**
+     * Increment the busy count for job.
+     * @param job
+     */
+    public void incrementBusy(Job job);
+
+    /**
+     * Decrement the busy count for job.
+     * @param job
+     */
+    public void decrementBusy(Job job);
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/IJobProgressManagerListener.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/IJobProgressManagerListener.java
new file mode 100644
index 0000000..f88fe6b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/IJobProgressManagerListener.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2006 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.ui.internal.progress;
+
+/**
+ * The IJobProgressManagerListener is a class that listeners to the JobProgressManager.
+ */
+interface IJobProgressManagerListener {
+
+    /**
+     * Refresh the viewer as a result of an addition of info.
+     * @param info
+     */
+    void addJob(final JobInfo info);
+
+    /**
+     * Refresh the viewer as a result of an addition of group.
+     * @param info
+     */
+    void addGroup(final GroupInfo info);
+
+    /**
+     * Refresh the IJobProgressManagerListeners as a result of a change in info.
+     * @param info
+     */
+    public void refreshJobInfo(JobInfo info);
+
+    /**
+     * Refresh the IJobProgressManagerListeners as a result of a change in groups.
+     * @param info
+     */
+    public void refreshGroup(GroupInfo info);
+
+    /**
+     * Refresh the viewer for all jobs.
+     * @param info
+     */
+    void refreshAll();
+
+    /**
+     * Refresh the viewer as a result of a removal of info.
+     * @param info
+     */
+    void removeJob(final JobInfo info);
+
+    /**
+     * Refresh the viewer as a result of a removal of group.
+     * @param info
+     */
+    void removeGroup(final GroupInfo group);
+
+    /**
+     * Return whether or not this listener shows debug information.
+     * @return boolean
+     */
+    boolean showsDebug();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/IProgressUpdateCollector.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/IProgressUpdateCollector.java
new file mode 100644
index 0000000..a69fd30
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/IProgressUpdateCollector.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2006 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.ui.internal.progress;
+
+/**
+ * The IProgressUpdateCollector is the interface that content providers
+ * conform to in order that the ProgressViewUpdater can talk to various
+ * types of content provider.
+ */
+public interface IProgressUpdateCollector {
+
+    /**
+     * Refresh the viewer.
+     */
+    void refresh();
+
+    /**
+     * Refresh the elements.
+     * @param elements
+     */
+    void refresh(Object[] elements);
+
+    /**
+     * Add the elements.
+     * @param elements Array of JobTreeElement
+     */
+    void add(Object[] elements);
+
+    /**
+     * Remove the elements.
+     * @param elements Array of JobTreeElement
+     */
+    void remove(Object[] elements);
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/JobInfo.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/JobInfo.java
new file mode 100644
index 0000000..032d044
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/JobInfo.java
@@ -0,0 +1,419 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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
+ *     Brock Janiczak <brockj@tpg.com.au> - Fix for Bug 123169 [Progress] NPE from JobInfo
+ *     Martin W. Kirst <martin.kirst@s1998.tu-chemnitz.de> - jUnit test for Bug 361121 [Progress] DetailedProgressViewer's comparator violates its general contract
+ *******************************************************************************/
+package org.eclipse.ui.internal.progress;
+
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * JobInfo is the class that keeps track of the tree structure for objects that
+ * display job status in a tree.
+ */
+public class JobInfo extends JobTreeElement {
+    private IStatus blockedStatus;
+
+	private volatile boolean canceled;
+	private final Queue<JobTreeElement> children = new ConcurrentLinkedQueue<>();
+
+	private final Job job;
+
+    private GroupInfo parent;
+
+    private TaskInfo taskInfo;
+
+	// Default to no progress.
+    private int ticks = -1;
+
+    /**
+	 * Creates a top level JobInfo.
+	 *
+	 * @param enclosingJob
+	 */
+	protected JobInfo(Job enclosingJob) {
+        this.job = enclosingJob;
+    }
+
+    /**
+	 * Adds the subtask to the receiver.
+	 *
+	 * @param subTaskName
+	 */
+    void addSubTask(String subTaskName) {
+        children.add(new SubTaskInfo(this, subTaskName));
+    }
+
+    /**
+	 * Adds the amount of work to the job info.
+	 *
+	 * @param workIncrement
+	 */
+    void addWork(double workIncrement) {
+        if (taskInfo == null) {
+			return;
+		}
+        if (parent == null || ticks < 1) {
+			taskInfo.addWork(workIncrement);
+		} else {
+			taskInfo.addWork(workIncrement, parent, ticks);
+		}
+    }
+
+    /**
+	 * Begins the task called taskName with the supplied work.
+	 *
+	 * @param taskName
+	 * @param work
+	 */
+    void beginTask(String taskName, int work) {
+        taskInfo = new TaskInfo(this, taskName, work);
+    }
+
+    @Override
+	public void cancel() {
+        this.canceled = true;
+        this.job.cancel();
+		// Call the refresh so that this is updated immediately.
+        ProgressManager.getInstance().refreshJobInfo(this);
+    }
+
+    /**
+	 * Clears the collection of subtasks an the task info.
+	 */
+    void clearChildren() {
+        children.clear();
+    }
+
+    void clearTaskInfo() {
+		FinishedJobs.getInstance().remove(taskInfo);
+        taskInfo = null;
+    }
+
+    /**
+	 * Compares the job of the receiver to another job.
+	 *
+	 * @param jobInfo
+	 *            The info we are comparing to
+	 * @return Returns a negative integer, zero, or a positive integer as this
+	 *         object is less than, equal to, or greater than the specified
+	 *         object.
+	 */
+    private int compareJobs(JobInfo jobInfo) {
+        Job job2 = jobInfo.getJob();
+
+		// User jobs have top priority.
+        if (job.isUser()) {
+            if (!job2.isUser()) {
+				return -1;
+			}
+        } else {
+            if (job2.isUser()) {
+				return 1;
+			}
+        }
+
+		// Show the blocked ones last.
+        if (isBlocked()) {
+            if (!jobInfo.isBlocked()) {
+				return 1;
+			}
+        } else {
+            if (jobInfo.isBlocked()) {
+				return -1;
+			}
+        }
+
+        int thisPriority = job.getPriority();
+		int otherPriority = job2.getPriority();
+		// If equal priority, order by names.
+		if (thisPriority == otherPriority) {
+            return job.getName().compareTo(job2.getName());
+        }
+
+		// Order by priority.
+        if (thisPriority > otherPriority) {
+			return -1;
+		}
+        return 1;
+    }
+
+    @Override
+	public int compareTo(JobTreeElement other) {
+		if (!(other instanceof JobInfo)) {
+			return super.compareTo(other);
+		}
+		JobInfo element = (JobInfo) other;
+
+        boolean thisCanceled = isCanceled();
+		boolean anotherCanceled = element.isCanceled();
+		if (thisCanceled && !anotherCanceled) {
+			// If the receiver is cancelled then it is lowest priority.
+			return 1;
+		} else if (!thisCanceled && anotherCanceled) {
+			return -1;
+		}
+
+		int thisState = getJob().getState();
+		int anotherState = element.getJob().getState();
+
+		// If equal job state, compare other job attributes.
+		if (thisState == anotherState) {
+			return compareJobs(element);
+		}
+
+		// Ordering by job states, Job.RUNNING should be ordered first.
+		return Integer.compare(anotherState, thisState);
+    }
+
+    /**
+	 * Disposes of the receiver.
+	 */
+    void dispose() {
+        if (parent != null) {
+			parent.removeJobInfo(this);
+		}
+    }
+
+    /**
+	 * Returns the blocked status or <code>null</code> if there isn't one.
+	 *
+	 * @return the blockedStatus.
+	 */
+    public IStatus getBlockedStatus() {
+        return blockedStatus;
+    }
+
+    @Override
+	Object[] getChildren() {
+        return children.toArray();
+    }
+
+    @Override
+	String getCondensedDisplayString() {
+    	TaskInfo info = getTaskInfo();
+        if (info != null) {
+			return info.getDisplayStringWithoutTask(true);
+		}
+        return getJob().getName();
+    }
+
+    @Override
+	public Image getDisplayImage() {
+        int done = getPercentDone();
+        if (done > 0) {
+            return super.getDisplayImage();
+        }
+        if (isBlocked()) {
+			return JFaceResources.getImage(ProgressManager.BLOCKED_JOB_KEY);
+		}
+        int state = getJob().getState();
+        if (state == Job.SLEEPING) {
+			return JFaceResources.getImage(ProgressManager.SLEEPING_JOB_KEY);
+		}
+        if (state == Job.WAITING) {
+			return JFaceResources.getImage(ProgressManager.WAITING_JOB_KEY);
+		}
+		// By default return the first progress image.
+        return super.getDisplayImage();
+
+    }
+    @Override
+	String getDisplayString() {
+    	return getDisplayString(true);
+    }
+
+    @Override
+	String getDisplayString(boolean showProgress) {
+        String name = getDisplayStringWithStatus(showProgress);
+        if (job.isSystem()) {
+			return NLS.bind(ProgressMessages.get().JobInfo_System, (new Object[] { name }));
+		}
+        return name;
+    }
+
+    /**
+	 * Returns the display string based on the current status and the name of
+	 * the job.
+	 *
+	 * @param showProgress
+	 *            a boolean to indicate if we should show progress or not.
+	 *
+	 * @return String
+	 */
+    private String getDisplayStringWithStatus(boolean showProgress) {
+        if (isCanceled()) {
+			return NLS.bind(ProgressMessages.get().JobInfo_Cancelled, (new Object[] { getJob().getName() }));
+		}
+        if (isBlocked()) {
+			return NLS.bind(ProgressMessages.get().JobInfo_Blocked, (new Object[] { getJob().getName(),
+			blockedStatus.getMessage() }));
+		}
+        if (getJob().getState() == Job.RUNNING) {
+        	TaskInfo info = getTaskInfo();
+            if (info == null) {
+				return getJob().getName();
+			}
+            return info.getDisplayString(showProgress);
+        }
+        if (getJob().getState() == Job.SLEEPING) {
+			return NLS.bind(ProgressMessages.get().JobInfo_Sleeping, (new Object[] { getJob().getName() }));
+		}
+
+        return NLS.bind(ProgressMessages.get().JobInfo_Waiting, (new Object[] { getJob().getName() }));
+    }
+
+    /**
+	 * Returns the GroupInfo for the receiver if it' is active.
+	 *
+	 * @return GroupInfo or <code>null</code>.
+	 */
+    GroupInfo getGroupInfo() {
+        if (parent != null) {
+			return parent;
+		}
+        return null;
+    }
+
+    /**
+	 * Returns the job that the receiver is collecting data on.
+	 *
+	 * @return Job
+	 */
+	public Job getJob() {
+        return job;
+    }
+
+	@Override
+	public Object getParent() {
+        return parent;
+    }
+
+    /**
+	 * Returns the amount of progress we have had as a percentage. If there is
+	 * no progress or it is indeterminate return IProgressMonitor.UNKNOWN.
+	 *
+	 * @return int
+	 */
+    int getPercentDone() {
+    	TaskInfo info = getTaskInfo();
+        if (info != null){
+        	if(info.totalWork == IProgressMonitor.UNKNOWN) {
+				return IProgressMonitor.UNKNOWN;
+			}
+        	if(info.totalWork == 0) {
+				return 0;
+			}
+            return (int) info.preWork * 100 / info.totalWork;
+        }
+        return IProgressMonitor.UNKNOWN;
+    }
+
+    /**
+	 * Returns the taskInfo.
+	 */
+    TaskInfo getTaskInfo() {
+        return taskInfo;
+    }
+
+    @Override
+	boolean hasChildren() {
+		return !children.isEmpty();
+    }
+
+    /**
+	 * Returns whether or not there is a task.
+	 *
+	 * @return boolean
+	 */
+    boolean hasTaskInfo() {
+        return taskInfo != null;
+    }
+
+    @Override
+	boolean isActive() {
+        return getJob().getState() != Job.NONE;
+    }
+
+    /**
+	 * Returns whether or not the receiver is blocked.
+	 *
+	 * @return boolean <code>true</code> if this is a currently blocked job.
+	 */
+    public boolean isBlocked() {
+        return getBlockedStatus() != null;
+    }
+
+    /**
+	 * Returns whether or not the job was cancelled in the UI.
+	 *
+	 * @return boolean
+	 */
+    public boolean isCanceled() {
+        return canceled;
+    }
+
+    @Override
+	public boolean isCancellable() {
+        return super.isCancellable();
+    }
+
+    @Override
+	boolean isJobInfo() {
+        return true;
+    }
+
+    /**
+	 * Sets the description of the blocking status.
+	 *
+	 * @param blockedStatus
+	 *            The IStatus that describes the blockage or <code>null</code>
+	 */
+    public void setBlockedStatus(IStatus blockedStatus) {
+        this.blockedStatus = blockedStatus;
+    }
+
+    /**
+	 * Sets the GroupInfo to be the group.
+	 *
+	 * @param group
+	 */
+    void setGroupInfo(GroupInfo group) {
+        parent = group;
+    }
+
+    /**
+	 * Sets the name of the taskInfo.
+	 *
+	 * @param name
+	 */
+    void setTaskName(String name) {
+        taskInfo.setTaskName(name);
+    }
+
+    /**
+	 * Sets the number of ticks this job represents. Default is indeterminate
+	 * (-1).
+	 *
+	 * @param ticks
+	 *            The ticks to set.
+	 */
+    public void setTicks(int ticks) {
+        this.ticks = ticks;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/JobTreeElement.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/JobTreeElement.java
new file mode 100644
index 0000000..8ecae14
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/JobTreeElement.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.internal.progress;
+
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * The JobTreeElement is the abstract superclass of items displayed in the tree.
+ */
+public abstract class JobTreeElement implements Comparable<JobTreeElement> {
+	/**
+	 * Returns the parent of this object.
+	 *
+	 * @return Object
+	 */
+	public Object getParent() {
+		return null;
+	}
+
+	/**
+	 * Returns whether or not the receiver has children.
+	 *
+	 * @return boolean
+	 */
+	abstract boolean hasChildren();
+
+	/**
+	 * Returns the children of the receiver.
+	 *
+	 * @return Object[]
+	 */
+	abstract Object[] getChildren();
+
+	/**
+	 * Returns the displayString for the receiver.
+	 *
+	 * @return String
+	 */
+	abstract String getDisplayString();
+
+	/**
+	 * Returns the displayString for the receiver.
+	 *
+	 * @param showProgress
+	 *            Whether or not progress is being shown (if relevant).
+	 * @return String
+	 */
+	String getDisplayString(boolean showProgress) {
+		return getDisplayString();
+	}
+
+	/**
+	 * Returns the image for the receiver.
+	 *
+	 * @return Image or <code>null</code>.
+	 */
+	public Image getDisplayImage() {
+		return JFaceResources.getImage(ProgressInfoItem.DEFAULT_JOB_KEY);
+	}
+
+	/**
+	 * Returns the condensed version of the display string.
+	 *
+	 * @return String
+	 */
+	String getCondensedDisplayString() {
+		return getDisplayString();
+	}
+
+	/**
+	 * Returns whether or not the receiver is an info.
+	 *
+	 * @return boolean
+	 */
+	abstract boolean isJobInfo();
+
+	@Override
+	public int compareTo(JobTreeElement other) {
+		return getDisplayString().compareTo(other.getDisplayString());
+	}
+
+	/**
+	 * Returns whether or not this is currently active.
+	 *
+	 * @return boolean
+	 */
+	abstract boolean isActive();
+
+	/**
+	 * Returns whether or not the receiver can be cancelled.
+	 *
+	 * @return boolean
+	 */
+	public boolean isCancellable() {
+		return false;
+	}
+
+	/**
+	 * Cancels the receiver.
+	 */
+	public void cancel() {
+		// By default do nothing.
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/JobsViewPreferenceDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/JobsViewPreferenceDialog.java
new file mode 100644
index 0000000..4120923
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/JobsViewPreferenceDialog.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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
+ *     Sebastian Davids  <sdavids@gmx.de> - Fix for Bug 132156 [Dialogs] Progress Preferences dialog problems
+ *******************************************************************************/
+package org.eclipse.ui.internal.progress;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.preference.BooleanFieldEditor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkbenchPreferenceConstants;
+import org.eclipse.ui.internal.util.PrefUtil;
+import org.eclipse.ui.preferences.ViewSettingsDialog;
+
+/**
+ * The JobsViewPreferenceDialog is the dialog that
+ * allows the user to set the preferences.
+ */
+public class JobsViewPreferenceDialog extends ViewSettingsDialog {
+
+	private BooleanFieldEditor verboseEditor;
+
+	/**
+	 * Create a new instance of the receiver.
+	 * @param parentShell
+	 */
+	public JobsViewPreferenceDialog(Shell parentShell) {
+		super(parentShell);
+	}
+
+	@Override
+	protected void configureShell(Shell newShell) {
+		super.configureShell(newShell);
+		newShell.setText(ProgressMessages.get().JobsViewPreferenceDialog_Title);
+	}
+
+	@Override
+	protected Control createDialogArea(Composite parent) {
+		Composite top = (Composite) super.createDialogArea(parent);
+
+		Composite editArea = new Composite(top, SWT.NONE);
+		editArea.setLayout(new GridLayout());
+		editArea.setLayoutData(new GridData(GridData.FILL_BOTH | GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL));
+
+		verboseEditor = new BooleanFieldEditor("verbose", ProgressMessages.get().JobsViewPreferenceDialog_Note, editArea);//$NON-NLS-1$
+		verboseEditor.setPreferenceName(IWorkbenchPreferenceConstants.SHOW_SYSTEM_JOBS);
+		verboseEditor.setPreferenceStore(PrefUtil.getAPIPreferenceStore());
+		verboseEditor.load();
+
+		Dialog.applyDialogFont(top);
+
+		return top;
+	}
+
+	@Override
+	protected void okPressed() {
+		verboseEditor.store();
+		super.okPressed();
+	}
+
+	@Override
+	protected void performDefaults() {
+		verboseEditor.loadDefault();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressAnimationItem.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressAnimationItem.java
new file mode 100644
index 0000000..87eed27
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressAnimationItem.java
@@ -0,0 +1,407 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2016 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 422040, 440810
+ *******************************************************************************/
+package org.eclipse.ui.internal.progress;
+
+import java.time.Duration;
+
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.NotEnabledException;
+import org.eclipse.core.commands.NotHandledException;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.util.Util;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.accessibility.AccessibleAdapter;
+import org.eclipse.swt.accessibility.AccessibleEvent;
+import org.eclipse.swt.accessibility.AccessibleListener;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.ProgressBar;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.progress.IProgressConstants;
+import org.eclipse.ui.progress.IProgressConstants2;
+import org.eclipse.ui.statushandlers.StatusAdapter;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+/**
+ * The ProgressAnimationItem is the animation items that uses the progress bar.
+ */
+public class ProgressAnimationItem extends AnimationItem implements
+		FinishedJobs.KeptJobsListener {
+
+	ProgressBar bar;
+
+	MouseListener mouseListener;
+
+	Composite top;
+
+	ToolBar toolbar;
+
+	ToolItem toolButton;
+
+	ProgressRegion progressRegion;
+
+	Image noneImage, okImage, errorImage;
+
+	boolean animationRunning;
+
+	// ProgressBar flags
+	private int flags;
+
+	private AccessibleListener currentAccessibleListener;
+
+	private Throttler throttledRefresh = new Throttler(PlatformUI.getWorkbench().getDisplay(), Duration.ofMillis(100),
+			this::refresh);
+
+	/**
+	 * Create an instance of the receiver in the supplied region.
+	 *
+	 * @param region
+	 *            The ProgressRegion that contains the receiver.
+	 * @param flags
+	 *            flags to use for creation of the progress bar
+	 */
+	ProgressAnimationItem(ProgressRegion region, int flags) {
+		super(region.workbenchWindow);
+		this.flags = flags;
+		FinishedJobs.getInstance().addListener(this);
+
+		progressRegion = region;
+		mouseListener = new MouseAdapter() {
+			@Override
+			public void mouseDoubleClick(MouseEvent e) {
+				doAction();
+			}
+		};
+	}
+
+	void doAction() {
+
+		JobTreeElement[] jobTreeElements = FinishedJobs.getInstance()
+				.getKeptElements();
+		// search from end (youngest)
+		for (int i = jobTreeElements.length - 1; i >= 0; i--) {
+			if (jobTreeElements[i] instanceof JobInfo) {
+				JobInfo ji = (JobInfo) jobTreeElements[i];
+				Job job = ji.getJob();
+				if (job != null) {
+
+					IStatus status = job.getResult();
+					if (status != null && status.getSeverity() == IStatus.ERROR) {
+						StatusAdapter statusAdapter = StatusAdapterHelper
+								.getInstance().getStatusAdapter(ji);
+
+						if (statusAdapter == null)
+							statusAdapter = new StatusAdapter(status);
+
+						StatusManager.getManager().handle(statusAdapter,
+								StatusManager.SHOW);
+
+						removeTopElement(ji);
+					}
+
+					// To fix a bug (335543) introduced in 3.6.1.
+					// doAction() should return if progress region button was
+					// selected to open a job result action or command.
+					if (execute(ji, job)) {
+						return;
+					}
+				}
+			}
+		}
+
+		progressRegion.processDoubleClick();
+		refresh();
+	}
+
+	/**
+	 * @param ji
+	 * @param job
+	 * @return <code>true</code> if Action or Command is executed
+	 */
+	private boolean execute(JobInfo ji, Job job) {
+
+		Object prop = job.getProperty(IProgressConstants.ACTION_PROPERTY);
+		if (prop instanceof IAction && ((IAction) prop).isEnabled()) {
+			IAction action = (IAction) prop;
+			action.run();
+			removeTopElement(ji);
+			return true;
+		}
+
+		prop = job.getProperty(IProgressConstants2.COMMAND_PROPERTY);
+		if (prop instanceof ParameterizedCommand) {
+			ParameterizedCommand command = (ParameterizedCommand) prop;
+			IWorkbenchWindow window = getWindow();
+			IHandlerService service = window
+					.getService(IHandlerService.class);
+			Exception exception = null;
+			try {
+				service.executeCommand(command, null);
+				removeTopElement(ji);
+			} catch (ExecutionException e) {
+				exception = e;
+			} catch (NotDefinedException e) {
+				exception = e;
+			} catch (NotEnabledException e) {
+				exception = e;
+			} catch (NotHandledException e) {
+				exception = e;
+			}
+
+			if (exception != null) {
+				Status status = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID,
+						exception.getMessage(), exception);
+				StatusManager.getManager().handle(status,
+						StatusManager.LOG | StatusManager.SHOW);
+			}
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * @param ji
+	 */
+	private void removeTopElement(JobInfo ji) {
+		JobTreeElement topElement = (JobTreeElement) ji.getParent();
+		if (topElement == null) {
+			topElement = ji;
+		}
+		FinishedJobs.getInstance().remove(topElement);
+	}
+
+	private IAction getAction(Job job) {
+		Object property = job.getProperty(IProgressConstants.ACTION_PROPERTY);
+		if (property instanceof IAction) {
+			return (IAction) property;
+		}
+		return null;
+	}
+
+	private void refresh() {
+
+		// Abort the refresh if we are in the process of shutting down
+		if (!PlatformUI.isWorkbenchRunning()) {
+			return;
+		}
+
+		if (toolbar == null || toolbar.isDisposed()) {
+			return;
+		}
+
+		JobTreeElement[] jobTreeElements = FinishedJobs.getInstance()
+				.getKeptElements();
+		// search from end (youngest)
+		for (int i = jobTreeElements.length - 1; i >= 0; i--) {
+			if (jobTreeElements[i] instanceof JobInfo) {
+				JobInfo ji = (JobInfo) jobTreeElements[i];
+				Job job = ji.getJob();
+				if (job != null) {
+					IStatus status = job.getResult();
+					if (status != null && status.getSeverity() == IStatus.ERROR) {
+						// green arrow with error overlay
+						initButton(errorImage, NLS.bind(
+								ProgressMessages.get().ProgressAnimationItem_error,
+								job.getName()));
+						return;
+					}
+					IAction action = getAction(job);
+					if (action != null && action.isEnabled()) {
+						// green arrow with exclamation mark
+						String tt = action.getToolTipText();
+						if (tt == null || tt.trim().length() == 0) {
+							tt = NLS.bind(
+									ProgressMessages.get().ProgressAnimationItem_ok,
+									job.getName());
+						}
+						initButton(okImage, tt);
+						return;
+					}
+					// just the green arrow
+					initButton(noneImage,
+							ProgressMessages.get().ProgressAnimationItem_tasks);
+					return;
+				}
+			}
+		}
+
+		if (animationRunning) {
+			initButton(noneImage, ProgressMessages.get().ProgressAnimationItem_tasks);
+			return;
+		}
+
+		// if nothing found hide tool item
+		toolbar.setVisible(false);
+	}
+
+	private void initButton(Image im, final String tt) {
+		toolButton.setImage(im);
+		toolButton.setToolTipText(tt);
+    	toolbar.setVisible(true);
+		toolbar.getParent().layout(); // must layout
+
+		if (currentAccessibleListener != null)
+			toolbar.getAccessible().removeAccessibleListener(currentAccessibleListener);
+		currentAccessibleListener = new AccessibleAdapter() {
+			@Override
+			public void getName(AccessibleEvent e) {
+				e.result = tt;
+			}
+		};
+		toolbar.getAccessible().addAccessibleListener(currentAccessibleListener);
+	}
+
+	@Override
+	protected Control createAnimationItem(Composite parent) {
+
+		if (okImage == null) {
+			Display display = parent.getDisplay();
+			noneImage = WorkbenchImages.getWorkbenchImageDescriptor(
+					"progress/progress_none.gif").createImage(display); //$NON-NLS-1$
+			okImage = WorkbenchImages.getWorkbenchImageDescriptor(
+					"progress/progress_ok.gif").createImage(display); //$NON-NLS-1$
+			errorImage = WorkbenchImages.getWorkbenchImageDescriptor(
+					"progress/progress_error.gif").createImage(display); //$NON-NLS-1$
+		}
+
+		top = new Composite(parent, SWT.NULL);
+		top.addDisposeListener(e -> {
+			FinishedJobs.getInstance().removeListener(
+					ProgressAnimationItem.this);
+			noneImage.dispose();
+			okImage.dispose();
+			errorImage.dispose();
+		});
+
+		boolean isCarbon = Util.isMac();
+
+		GridLayout gl = new GridLayout();
+		if (isHorizontal())
+			gl.numColumns = isCarbon ? 3 : 2;
+		gl.marginHeight = 0;
+		gl.marginWidth = 0;
+		if (isHorizontal()) {
+			gl.horizontalSpacing = 2;
+		} else {
+			gl.verticalSpacing = 2;
+		}
+		top.setLayout(gl);
+
+		bar = new ProgressBar(top, flags | SWT.INDETERMINATE);
+		bar.setVisible(false);
+		bar.addMouseListener(mouseListener);
+
+		GridData gd;
+		int hh = 12;
+		if (isHorizontal()) {
+			gd = new GridData(SWT.BEGINNING, SWT.CENTER, true, false);
+			gd.heightHint = hh;
+		} else {
+			gd = new GridData(SWT.CENTER, SWT.BEGINNING, false, true);
+			gd.widthHint = hh;
+		}
+
+		bar.setLayoutData(gd);
+
+		toolbar = new ToolBar(top, SWT.FLAT);
+		toolbar.setVisible(false);
+
+		toolButton = new ToolItem(toolbar, SWT.NONE);
+		toolButton.addSelectionListener(new SelectionAdapter()
+        {
+		    public void widgetSelected(SelectionEvent e) {
+		        doAction();
+		    }
+        });
+
+		if (isCarbon) {
+			new Label(top, SWT.NONE).setLayoutData(new GridData(4, 4));
+		}
+
+		refresh();
+
+		return top;
+	}
+
+	/**
+	 * @return <code>true</code> if the control is horizontally oriented
+	 */
+	private boolean isHorizontal() {
+		return (flags & SWT.HORIZONTAL) != 0;
+	}
+
+	@Override
+	public Control getControl() {
+		return top;
+	}
+
+	@Override
+	void animationDone() {
+		super.animationDone();
+		animationRunning = false;
+		if (bar.isDisposed()) {
+			return;
+		}
+		bar.setVisible(false);
+		refresh();
+	}
+
+	/**
+	 * @return <code>true</code> when the animation is running
+	 */
+	public boolean animationRunning() {
+		return animationRunning;
+	}
+
+	@Override
+	void animationStart() {
+		super.animationStart();
+		animationRunning = true;
+		if (bar.isDisposed()) {
+			return;
+		}
+		bar.setVisible(true);
+		refresh();
+	}
+
+	@Override
+	public void removed(JobTreeElement info) {
+		throttledRefresh.throttledExec();
+	}
+
+	@Override
+	public void finished(final JobTreeElement jte) {
+		throttledRefresh.throttledExec();
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressAnimationProcessor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressAnimationProcessor.java
new file mode 100644
index 0000000..46cb734
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressAnimationProcessor.java
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.progress;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * The ProgressAnimationProcessor is the processor for the animation using the
+ * system progress.
+ */
+class ProgressAnimationProcessor implements IAnimationProcessor {
+
+    AnimationManager manager;
+
+    /**
+     * Create a new instance of the receiver and listen to the animation
+     * manager.
+     *
+     * @param animationManager
+     */
+    ProgressAnimationProcessor(AnimationManager animationManager) {
+        manager = animationManager;
+    }
+
+	List items = new ArrayList();
+
+    public void startAnimationLoop(IProgressMonitor monitor) {
+
+        // Create an off-screen image to draw on, and a GC to draw with.
+        // Both are disposed after the animation.
+        if (items.size() == 0) {
+			return;
+		}
+        if (!PlatformUI.isWorkbenchRunning()) {
+			return;
+		}
+
+        while (manager.isAnimated() && !monitor.isCanceled()) {
+            //Do nothing while animation is happening
+        }
+
+		for (ProgressAnimationItem animationItem : getAnimationItems()) {
+            animationItem.animationDone();
+        }
+
+    }
+
+    @Override
+	public void addItem(AnimationItem item) {
+        Assert.isTrue(item instanceof ProgressAnimationItem);
+        items.add(item);
+    }
+
+    @Override
+	public void removeItem(AnimationItem item) {
+        Assert.isTrue(item instanceof ProgressAnimationItem);
+        items.remove(item);
+    }
+
+    @Override
+	public boolean hasItems() {
+        return items.size() > 0;
+    }
+
+    public void itemsInactiveRedraw() {
+        //Nothing to do here as SWT handles redraw
+
+    }
+
+    @Override
+	public void animationStarted() {
+		for (AnimationItem animationItem : getAnimationItems()) {
+            animationItem.animationStart();
+        }
+
+    }
+
+    @Override
+	public int getPreferredWidth() {
+        return 30;
+    }
+
+    /**
+     * Get the animation items currently registered for the receiver.
+     *
+     * @return ProgressAnimationItem[]
+     */
+    private ProgressAnimationItem[] getAnimationItems() {
+		ProgressAnimationItem[] animationItems = new ProgressAnimationItem[items.size()];
+        items.toArray(animationItems);
+        return animationItems;
+    }
+
+    @Override
+	public void animationFinished() {
+		for (AnimationItem animationItem : getAnimationItems()) {
+            animationItem.animationDone();
+        }
+
+    }
+
+    @Override
+	public boolean isProcessorJob(Job job) {
+        // We have no jobs
+        return false;
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressCanvasViewer.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressCanvasViewer.java
new file mode 100644
index 0000000..4a31814
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressCanvasViewer.java
@@ -0,0 +1,258 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.progress;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.FontMetrics;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Widget;
+
+/**
+ * The ProgressCanvasViewer is the viewer used by progress windows. It displays text
+ * on the canvas.
+ */
+public class ProgressCanvasViewer extends AbstractProgressViewer {
+
+    // RAP [fappel]: RWT Canvas has no functionality yet - so we use a 
+    //                label for now... 
+//    Canvas canvas;
+    Label canvas;
+    // RAPEND: [bm]
+    
+    Object[] displayedItems = new Object[0];
+
+    private final static List EMPTY_LIST = new ArrayList();
+
+    /**
+     * Font metrics to use for determining pixel sizes.
+     */
+    // RAP [bm]: 
+//    private FontMetrics fontMetrics;
+
+    private int numShowItems = 1;
+
+    private int maxCharacterWidth;
+
+    // RAP [bm]: 
+//	private int orientation = SWT.HORIZONTAL;
+
+    /**
+     * Create a new instance of the receiver with the supplied
+     * parent and style bits.
+     * @param parent The composite the Canvas is created in
+     * @param style style bits for the canvas
+     * @param itemsToShow the number of items this will show
+     * @param numChars The number of characters for the width hint.
+     * @param side the side to display text, this helps determine horizontal vs vertical
+     */
+    ProgressCanvasViewer(Composite parent, int style, int itemsToShow, int numChars, int orientation) {
+        super();
+        // RAP [bm]: not used
+//        this.orientation = orientation;
+        // RAPEND: [bm] 
+
+        numShowItems = itemsToShow;
+        maxCharacterWidth = numChars;
+        // RAP [bm]: 
+//        canvas = new Canvas(parent, style);
+        canvas = new Label( parent, style | SWT.CENTER );
+        // RAPEND: [bm] 
+
+        hookControl(canvas);
+        // Compute and store a font metric
+        // RAP [bm]: 
+//        GC gc = new GC(canvas);
+//        gc.setFont(JFaceResources.getDefaultFont());
+//        fontMetrics = gc.getFontMetrics();
+//        gc.dispose();
+        // RAPEND: [bm] 
+        initializeListeners();
+    }
+
+    /**
+     * NE: Copied from ContentViewer.  We don't want the OpenStrategy hooked
+     * in StructuredViewer.hookControl otherwise the canvas will take focus
+     * since it has a key listener.  We don't want this included in the window's
+     * tab traversal order.  Defeating it here is more self-contained then
+     * setting the tab list on the shell or other parent composite.
+     */
+    @Override
+	protected void hookControl(Control control) {
+        control.addDisposeListener(event -> handleDispose(event));
+    }
+
+    @Override
+	protected Widget doFindInputItem(Object element) {
+        return null; // No widgets associated with items
+    }
+
+    @Override
+	protected Widget doFindItem(Object element) {
+        return null; // No widgets associated with items
+    }
+
+    @Override
+	protected void doUpdateItem(Widget item, Object element, boolean fullMap) {
+        // RAP [bm]: 
+        // RAP [bm]: 
+        updateLabel();
+        // RAPEND: [bm] 
+        canvas.redraw();
+    }
+
+    @Override
+	protected List getSelectionFromWidget() {
+        //No selection on a Canvas
+        return EMPTY_LIST;
+    }
+
+    @Override
+	protected void internalRefresh(Object element) {
+        displayedItems = getSortedChildren(getRoot());
+        // RAP [bm]: 
+        updateLabel();
+        // RAPEND: [bm] 
+        canvas.redraw();
+    }
+    
+    // RAP [bm]: 
+    private void updateLabel() {
+        ILabelProvider labelProvider = (ILabelProvider) getLabelProvider();
+        if (displayedItems.length > 0) {
+            canvas.setText(labelProvider.getText(displayedItems[0]));
+        } else {
+            canvas.setText("");
+        }
+    }
+    // RAPEND: [bm]
+
+
+    @Override
+	public void reveal(Object element) {
+        //Nothing to do here as we do not scroll
+    }
+
+    @Override
+	protected void setSelectionToWidget(List l, boolean reveal) {
+        //Do nothing as there is no selection
+    }
+
+    @Override
+	public Control getControl() {
+        return canvas;
+    }
+
+    private void initializeListeners() {
+     // RAP [bm]: 
+//        canvas.addPaintListener(event -> {
+//
+//		    GC gc = event.gc;
+//		    Transform transform = null;
+//		    if (orientation == SWT.VERTICAL) {
+//		        transform = new Transform(event.display);
+//		    	transform.translate(TrimUtil.TRIM_DEFAULT_HEIGHT, 0);
+//		    	transform.rotate(90);
+//		    }
+//		    ILabelProvider labelProvider = (ILabelProvider) getLabelProvider();
+//
+//		    int itemCount = Math.min(displayedItems.length, numShowItems);
+//
+//		    int yOffset = 0;
+//		    int xOffset = 0;
+//		    if (numShowItems == 1) {//If there is a single item try to center it
+//		        Rectangle clientArea = canvas.getParent().getClientArea();
+//		        if (orientation == SWT.HORIZONTAL) {
+//		        	int size1 = clientArea.height;
+//		            yOffset = size1 - (fontMetrics.getHeight());
+//		            yOffset = yOffset / 2;
+//		        } else {
+//		        	int size2 = clientArea.width;
+//		        	xOffset = size2 - (fontMetrics.getHeight());
+//		        	xOffset = xOffset / 2;
+//		        }
+//		    }
+//
+//		    for (int i = 0; i < itemCount; i++) {
+//		        String string = labelProvider.getText(displayedItems[i]);
+//		        if(string == null) {
+//					string = "";//$NON-NLS-1$
+//				}
+//		        if (orientation == SWT.HORIZONTAL) {
+//		        	gc.drawString(string, 2, yOffset + (i * fontMetrics.getHeight()), true);
+//		        } else {
+//		        	gc.setTransform(transform);
+//		        	gc.drawString(string, xOffset + (i * fontMetrics.getHeight()), 2, true);
+//		        }
+//		    }
+//		    if (transform != null)
+//		    	transform.dispose();
+//		});
+    }
+
+    @Override
+	public void setLabelProvider(IBaseLabelProvider labelProvider) {
+        Assert.isTrue(labelProvider instanceof ILabelProvider);
+        super.setLabelProvider(labelProvider);
+    }
+
+    /**
+     * Get the size hints for the receiver. These are used for
+     * layout data.
+     * @return Point - the preferred x and y coordinates
+     */
+    public Point getSizeHints() {
+
+        Display display = canvas.getDisplay();
+
+        GC gc = new GC(canvas);
+        FontMetrics fm = gc.getFontMetrics();
+        int charWidth = fm.getAverageCharWidth();
+        int charHeight = fm.getHeight();
+        gc.dispose();
+
+        int maxWidth = display.getBounds().width / 2;
+        int maxHeight = display.getBounds().height / 6;
+        int fontWidth = charWidth * maxCharacterWidth;
+        int fontHeight = charHeight * numShowItems;
+        if (maxWidth < fontWidth) {
+			fontWidth = maxWidth;
+		}
+        if (maxHeight < fontHeight) {
+			fontHeight = maxHeight;
+		}
+        return new Point(fontWidth, fontHeight);
+    }
+
+	@Override
+	public void add(Object[] elements) {
+		refresh(true);
+
+	}
+
+	@Override
+	public void remove(Object[] elements) {
+		refresh(true);
+
+	}
+
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressContentProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressContentProvider.java
new file mode 100644
index 0000000..7c76265
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressContentProvider.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.internal.progress;
+
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+
+/**
+ * The ProgressContentProvider is the content provider used for classes that
+ * listen to the progress changes.
+ */
+public abstract class ProgressContentProvider implements
+        IProgressUpdateCollector, IStructuredContentProvider {
+
+	/**
+	 * Return whether or not we check the preferences or overide.
+	 */
+    private boolean canShowDebug = false;
+
+    /**
+     * Create a new instance of the receiver with all of the
+     * default values.
+     */
+    public ProgressContentProvider() {
+    	ProgressViewUpdater.getSingleton().addCollector(this);
+    }
+
+    /**
+     * Create a new instance of the receiver with a flag to
+     * indicate if there will be debug info shown or not.
+     * @param debug If true debug information will be shown
+     * if the debug flag in the ProgressManager is true.
+     */
+    public ProgressContentProvider(boolean debug) {
+    	this();
+    	canShowDebug = debug;
+    }
+
+    @Override
+	public Object[] getElements(Object inputElement) {
+
+        return ProgressManager.getInstance().getRootElements(debug());
+    }
+
+    @Override
+	public void dispose() {
+        ProgressViewUpdater.getSingleton().removeCollector(this);
+    }
+
+    @Override
+	public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+        //No change when input changes
+    }
+
+    /**
+     * Return whether or not we are debugging. Check the
+     * system settings unless we are overiding them.
+     * @return boolean <code>true</code> if debug
+     * (system) jobs are being shown.
+     */
+    public boolean debug(){
+    	if(!canShowDebug) {
+			return false;
+		}
+    	return ProgressViewUpdater.getSingleton().debug;
+
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressInfoItem.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressInfoItem.java
new file mode 100644
index 0000000..ab2d6ff
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressInfoItem.java
@@ -0,0 +1,1126 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2010 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 422040, 440810
+ *     G.R.Prakash <me@grprakash.com> - Bug 394036
+ *     Manumitting Technologies - Bug 394036
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.progress;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.NotEnabledException;
+import org.eclipse.core.commands.NotHandledException;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.commands.common.NotDefinedException;
+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.e4.core.commands.EHandlerService;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.contexts.RunAndTrack;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.jface.resource.ResourceManager;
+import org.eclipse.jface.util.Util;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.layout.FormAttachment;
+import org.eclipse.swt.layout.FormData;
+import org.eclipse.swt.layout.FormLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Link;
+import org.eclipse.swt.widgets.ProgressBar;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.progress.IProgressConstants;
+import org.eclipse.ui.progress.IProgressConstants2;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+import com.ibm.icu.text.DateFormat;
+
+/**
+ * ProgressInfoItem is the item used to show jobs.
+ *
+ *
+ */
+public class ProgressInfoItem extends Composite {
+
+	static String STOP_IMAGE_KEY = "org.eclipse.ui.internal.progress.PROGRESS_STOP"; //$NON-NLS-1$
+
+	static String DISABLED_STOP_IMAGE_KEY = "org.eclipse.ui.internal.progress.DISABLED_PROGRESS_STOP"; //$NON-NLS-1$
+
+	static String CLEAR_FINISHED_JOB_KEY = "org.eclipse.ui.internal.progress.CLEAR_FINISHED_JOB"; //$NON-NLS-1$
+
+	static String DISABLED_CLEAR_FINISHED_JOB_KEY = "org.eclipse.ui.internal.progress.DISABLED_CLEAR_FINISHED_JOB"; //$NON-NLS-1$
+
+	static String DEFAULT_JOB_KEY = "org.eclipse.ui.internal.progress.PROGRESS_DEFAULT"; //$NON-NLS-1$
+
+	static String DARK_COLOR_KEY = "org.eclipse.ui.internal.progress.PROGRESS_DARK_COLOR"; //$NON-NLS-1$
+
+	static String DEFAULT_THEME = "org.eclipse.e4.ui.css.theme.e4_default"; //$NON-NLS-1$
+
+	JobTreeElement info;
+
+	Label progressLabel;
+
+	ToolBar actionBar;
+
+	ToolItem actionButton;
+
+	List taskEntries = new ArrayList(0);
+
+	private ProgressBar progressBar;
+
+	private Label jobImageLabel;
+
+	static final int MAX_PROGRESS_HEIGHT = 12;
+
+	static final int MIN_ICON_SIZE = 16;
+
+	private static final String TEXT_KEY = "Text"; //$NON-NLS-1$
+
+	private static final String TRIGGER_KEY = "Trigger";//$NON-NLS-1$
+
+	interface IndexListener {
+		/**
+		 * Select the item previous to the receiver.
+		 */
+		public void selectPrevious();
+
+		/**
+		 * Select the next previous to the receiver.
+		 */
+		public void selectNext();
+
+		/**
+		 * Select the receiver.
+		 */
+		public void select();
+	}
+
+	IndexListener indexListener;
+
+	private int currentIndex;
+
+	private boolean selected;
+
+	private MouseAdapter mouseListener;
+
+	private boolean isShowing = true;
+
+	private ResourceManager resourceManager;
+
+	private Link link;
+
+	private HandlerChangeTracker tracker;
+
+	private boolean isThemed;
+
+	// RAP [fappel]: static initializer would fail to access image registry
+//  static {
+	static void init() {
+		JFaceResources
+				.getImageRegistry()
+				.put(
+						STOP_IMAGE_KEY,
+						WorkbenchImages
+								.getWorkbenchImageDescriptor("elcl16/progress_stop.png"));//$NON-NLS-1$
+
+		JFaceResources
+				.getImageRegistry()
+				.put(
+						DISABLED_STOP_IMAGE_KEY,
+						WorkbenchImages
+								.getWorkbenchImageDescriptor("dlcl16/progress_stop.png"));//$NON-NLS-1$
+
+		JFaceResources
+				.getImageRegistry()
+				.put(
+						DEFAULT_JOB_KEY,
+						WorkbenchImages
+								.getWorkbenchImageDescriptor("progress/progress_task.png")); //$NON-NLS-1$
+
+		JFaceResources
+				.getImageRegistry()
+				.put(
+						CLEAR_FINISHED_JOB_KEY,
+						WorkbenchImages
+								.getWorkbenchImageDescriptor("elcl16/progress_rem.png")); //$NON-NLS-1$
+
+		JFaceResources
+				.getImageRegistry()
+				.put(
+						DISABLED_CLEAR_FINISHED_JOB_KEY,
+						WorkbenchImages
+								.getWorkbenchImageDescriptor("dlcl16/progress_rem.png")); //$NON-NLS-1$
+
+		// Mac has different Gamma value
+		int shift = Util.isMac() ? -25 : -10;
+
+// RAP [if] Fix for bug 341816      
+//      Color lightColor = PlatformUI.getWorkbench().getDisplay()
+        Color lightColor = Display.getCurrent()		
+				.getSystemColor(SWT.COLOR_LIST_BACKGROUND);
+
+		// Determine a dark color by shifting the list color
+		RGB darkRGB = new RGB(Math.max(0, lightColor.getRed() + shift), Math
+				.max(0, lightColor.getGreen() + shift), Math.max(0, lightColor
+				.getBlue()
+				+ shift));
+		JFaceResources.getColorRegistry().put(DARK_COLOR_KEY, darkRGB);
+	}
+
+	/**
+	 * Create a new instance of the receiver with the specified parent, style
+	 * and info object/
+	 * 
+	 * @param parent
+	 * @param style
+	 * @param progressInfo
+	 */
+	public ProgressInfoItem(Composite parent, int style,
+			JobTreeElement progressInfo) {
+		super(parent, style);
+		info = progressInfo;
+		createChildren();
+		isThemed = getCustomThemeFlag();
+		setData(info);
+		setLayoutData(new GridData(SWT.FILL, SWT.NONE, true, false));
+	}
+
+	/**
+	 * Create the child widgets of the receiver.
+	 */
+	protected void createChildren() {
+
+		FormLayout layout = new FormLayout();
+		setLayout(layout);
+
+		jobImageLabel = new Label(this, SWT.NONE);
+		Image infoImage = getInfoImage();
+		jobImageLabel.setImage(infoImage);
+		FormData imageData = new FormData();
+		if (infoImage != null) {
+			// position it in the center
+			imageData.top = new FormAttachment(50,
+					-infoImage.getBounds().height / 2);
+		} else {
+			imageData.top = new FormAttachment(0,
+					IDialogConstants.VERTICAL_SPACING);
+		}
+		imageData.left = new FormAttachment(0,
+				IDialogConstants.HORIZONTAL_SPACING / 2);
+		jobImageLabel.setLayoutData(imageData);
+
+		progressLabel = new Label(this, SWT.NONE);
+		setMainText();
+
+		actionBar = new ToolBar(this, SWT.FLAT);
+		actionBar.setCursor(getDisplay().getSystemCursor(SWT.CURSOR_ARROW));
+
+		// set cursor to overwrite any busy cursor we might have
+
+		actionButton = new ToolItem(actionBar, SWT.NONE);
+		actionButton
+				.setToolTipText(ProgressMessages.get().NewProgressView_CancelJobToolTip);
+		actionButton.addSelectionListener(new SelectionAdapter()
+        {
+		    /** {@inheritDoc} */
+		    @Override
+		    public void widgetSelected(SelectionEvent e)
+		    {
+		        actionButton.setEnabled(false);
+	            cancelOrRemove();
+		    }
+        });
+// RAP [fappel]: traverse listener not supported
+//		actionBar.addListener(SWT.Traverse, event -> {
+//			if (indexListener == null) {
+//				return;
+//			}
+//			int detail = event.detail;
+//			if (detail == SWT.TRAVERSE_ARROW_NEXT) {
+//				indexListener.selectNext();
+//			}
+//			if (detail == SWT.TRAVERSE_ARROW_PREVIOUS) {
+//				indexListener.selectPrevious();
+//			}
+//
+//		});
+		updateToolBarValues();
+
+		FormData progressData = new FormData();
+		progressData.top = new FormAttachment(0,
+				IDialogConstants.VERTICAL_SPACING);
+		progressData.left = new FormAttachment(jobImageLabel,
+				IDialogConstants.HORIZONTAL_SPACING / 2);
+		progressData.right = new FormAttachment(actionBar,
+				IDialogConstants.HORIZONTAL_SPACING * -1);
+		progressLabel.setLayoutData(progressData);
+
+		mouseListener = new MouseAdapter() {
+			/*
+			 * (non-Javadoc)
+			 * 
+			 * @see org.eclipse.swt.events.MouseListener#mouseDown(org.eclipse.swt.events.MouseEvent)
+			 */
+			public void mouseDown(MouseEvent e) {
+				if (indexListener != null) {
+					indexListener.select();
+				}
+			}
+		};
+		addMouseListener(mouseListener);
+		jobImageLabel.addMouseListener(mouseListener);
+		progressLabel.addMouseListener(mouseListener);
+
+		setLayoutsForNoProgress();
+
+		refresh();
+	}
+
+	/**
+	 * Set the main text of the receiver. Truncate to fit the available space.
+	 */
+	private void setMainText() {
+		progressLabel
+				.setText(Dialog.shortenText(getMainTitle(), progressLabel));
+	}
+
+	/**
+	 * Set the layout of the widgets for the no progress case.
+	 * 
+	 */
+	private void setLayoutsForNoProgress() {
+
+		FormData buttonData = new FormData();
+		buttonData.top = new FormAttachment(progressLabel, 0, SWT.TOP);
+		buttonData.right = new FormAttachment(100,
+				IDialogConstants.HORIZONTAL_SPACING * -1);
+
+		actionBar.setLayoutData(buttonData);
+		if (taskEntries.size() > 0) {
+			FormData linkData = new FormData();
+			linkData.top = new FormAttachment(progressLabel,
+					IDialogConstants.VERTICAL_SPACING);
+			linkData.left = new FormAttachment(progressLabel, 0, SWT.LEFT);
+			linkData.right = new FormAttachment(actionBar, 0, SWT.LEFT);
+			((Link) taskEntries.get(0)).setLayoutData(linkData);
+
+		}
+	}
+
+	/**
+	 * Cancel or remove the reciever.
+	 * 
+	 */
+	protected void cancelOrRemove() {
+
+		if (FinishedJobs.getInstance().isKept(info) && isCompleted()) {
+			FinishedJobs.getInstance().remove(info);
+		} else {
+			info.cancel();
+		}
+
+	}
+
+	/**
+	 * Get the image for the info.
+	 * 
+	 * @return Image
+	 */
+	private Image getInfoImage() {
+
+		if (!info.isJobInfo()) {
+			return JFaceResources.getImage(DEFAULT_JOB_KEY);
+		}
+
+		JobInfo jobInfo = (JobInfo) info;
+
+		ImageDescriptor descriptor = null;
+		Object property = jobInfo.getJob().getProperty(
+				IProgressConstants.ICON_PROPERTY);
+
+		if (property instanceof ImageDescriptor) {
+			descriptor = (ImageDescriptor) property;
+		} else if (property instanceof URL) {
+			descriptor = ImageDescriptor.createFromURL((URL) property);
+		}
+
+		Image image = null;
+		if (descriptor == null) {
+			image = ProgressManager.getInstance().getIconFor(jobInfo.getJob());
+		} else {
+			image = getResourceManager().createImageWithDefault(descriptor);
+		}
+
+		if (image == null)
+			image = jobInfo.getDisplayImage();
+
+		return image;
+	}
+
+	/**
+	 * Return a resource manager for the receiver.
+	 * 
+	 * @return {@link ResourceManager}
+	 */
+	private ResourceManager getResourceManager() {
+		if (resourceManager == null)
+			resourceManager = new LocalResourceManager(JFaceResources
+					.getResources());
+		return resourceManager;
+	}
+
+	/**
+	 * Get the main title for the receiver.
+	 * 
+	 * @return String
+	 */
+	private String getMainTitle() {
+		if (info.isJobInfo()) {
+			return getJobNameAndStatus((JobInfo) info);
+		}
+		if (info.hasChildren()) {
+			return ((GroupInfo) info).getTaskName();
+		}
+		return info.getDisplayString();
+
+	}
+
+	/**
+	 * Get the name and status for a jobInfo
+	 * 
+	 * @param jobInfo
+	 * 
+	 * @return String
+	 */
+	public String getJobNameAndStatus(JobInfo jobInfo) {
+
+		Job job = jobInfo.getJob();
+
+		String name = job.getName();
+
+		if (job.isSystem()) {
+			name = NLS.bind(ProgressMessages.get().JobInfo_System, name);
+		}
+
+		if (jobInfo.isCanceled()) {
+			if (job.getState() == Job.RUNNING)
+				return NLS
+						.bind(ProgressMessages.get().JobInfo_Cancel_Requested, name);
+			return NLS.bind(ProgressMessages.get().JobInfo_Cancelled, name);
+		}
+
+		if (jobInfo.isBlocked()) {
+			IStatus blockedStatus = jobInfo.getBlockedStatus();
+			return NLS.bind(ProgressMessages.get().JobInfo_Blocked, name,
+					blockedStatus.getMessage());
+		}
+
+		switch (job.getState()) {
+		case Job.RUNNING:
+			return name;
+		case Job.SLEEPING: {
+			return NLS.bind(ProgressMessages.get().JobInfo_Sleeping, name);
+
+		}
+		case Job.NONE: // Only happens for kept jobs
+			return getJobInfoFinishedString(job, true);
+		default:
+			return NLS.bind(ProgressMessages.get().JobInfo_Waiting, name);
+		}
+	}
+
+	/**
+	 * Return the finished String for a job.
+	 * 
+	 * @param job
+	 *            the completed Job
+	 * @param withTime
+	 * @return String
+	 */
+	String getJobInfoFinishedString(Job job, boolean withTime) {
+		String time = null;
+		if (withTime) {
+			time = getTimeString();
+		}
+		if (time != null) {
+			return NLS.bind(ProgressMessages.get().JobInfo_FinishedAt, job.getName(),
+					time);
+		}
+		return NLS.bind(ProgressMessages.get().JobInfo_Finished, job.getName());
+	}
+
+	/**
+	 * Get the time string the finished job
+	 * 
+	 * @return String or <code>null</code> if this is not one of the finished
+	 *         jobs.
+	 */
+	private String getTimeString() {
+		Date date = FinishedJobs.getInstance().getFinishDate(info);
+		if (date != null) {
+			return DateFormat.getTimeInstance(DateFormat.SHORT).format(date);
+		}
+		return null;
+	}
+
+	/**
+	 * Refresh the contents of the receiver.
+	 * 
+	 */
+	void refresh() {
+
+		// Don't refresh if not visible
+		if (isDisposed() || !isShowing)
+			return;
+
+		jobImageLabel.setImage(getInfoImage());
+		int percentDone = getPercentDone();
+
+		JobInfo[] infos = getJobInfos();
+		if (isRunning()) {
+			if (progressBar == null) {
+				if (percentDone == IProgressMonitor.UNKNOWN) {
+					// Only do it if there is an indeterminate task
+					// There may be no task so we don't want to create it
+					// until we know for sure
+					for (JobInfo jobInfo : infos) {
+						if (jobInfo.hasTaskInfo()
+								&& jobInfo.getTaskInfo().totalWork == IProgressMonitor.UNKNOWN) {
+							createProgressBar(SWT.INDETERMINATE);
+							break;
+						}
+					}
+				} else {
+					createProgressBar(SWT.NONE);
+					progressBar.setMinimum(0);
+					progressBar.setMaximum(100);
+				}
+			}
+
+			// Protect against bad counters
+			if (percentDone >= 0 && percentDone <= 100
+					&& percentDone != progressBar.getSelection()) {
+				progressBar.setSelection(percentDone);
+			}
+		}
+
+		else if (isCompleted()) {
+
+			if (progressBar != null) {
+				progressBar.dispose();
+				progressBar = null;
+			}
+			setLayoutsForNoProgress();
+
+		}
+
+		for (int i = 0; i < infos.length; i++) {
+			JobInfo jobInfo = infos[i];
+			TaskInfo taskInfo = jobInfo.getTaskInfo();
+
+			if (taskInfo != null) {
+
+				String taskString = taskInfo.getTaskName();
+				String subTaskString = null;
+				Object[] jobChildren = jobInfo.getChildren();
+				if (jobChildren.length > 0) {
+					subTaskString = ((JobTreeElement) jobChildren[0])
+							.getDisplayString();
+				}
+
+				if (subTaskString != null) {
+					if (taskString == null || taskString.length() == 0) {
+						taskString = subTaskString;
+					} else {
+						taskString = NLS.bind(
+								ProgressMessages.get().JobInfo_DoneNoProgressMessage,
+								taskString, subTaskString);
+					}
+				}
+				if (taskString != null) {
+					setLinkText(infos[i].getJob(), taskString, i);
+				}
+			} else {// Check for the finished job state
+				Job job = jobInfo.getJob();
+				IStatus result = job.getResult();
+
+				if (result == null || result.getMessage().length() == 0
+						&& !info.isJobInfo()) {
+					setLinkText(job, getJobNameAndStatus(jobInfo), i);
+				} else {
+					setLinkText(job, result.getMessage(), i);
+
+				}
+
+			}
+			setColor(currentIndex);
+		}
+
+		// Remove completed tasks
+		if (infos.length < taskEntries.size()) {
+			for (int i = infos.length; i < taskEntries.size(); i++) {
+				((Link) taskEntries.get(i)).dispose();
+
+			}
+			if (infos.length > 1)
+				taskEntries = taskEntries.subList(0, infos.length - 1);
+			else
+				taskEntries.clear();
+		}
+
+		updateToolBarValues();
+		setMainText();
+	}
+
+	/**
+	 * Return whether or not the receiver is a completed job.
+	 * 
+	 * @return boolean <code>true</code> if the state is Job#NONE.
+	 */
+	private boolean isCompleted() {
+
+		JobInfo[] infos = getJobInfos();
+		for (JobInfo jobInfo : infos) {
+			if (jobInfo.getJob().getState() != Job.NONE) {
+				return false;
+			}
+		}
+		// Only completed if there are any jobs
+		return infos.length > 0;
+	}
+
+	/**
+	 * Return the job infos in the receiver.
+	 * 
+	 * @return JobInfo[]
+	 */
+	public JobInfo[] getJobInfos() {
+		if (info.isJobInfo()) {
+			return new JobInfo[] { (JobInfo) info };
+		}
+		Object[] children = info.getChildren();
+		JobInfo[] infos = new JobInfo[children.length];
+		System.arraycopy(children, 0, infos, 0, children.length);
+		return infos;
+	}
+
+	/**
+	 * Return whether or not the receiver is being displayed as running.
+	 * 
+	 * @return boolean
+	 */
+	private boolean isRunning() {
+
+		for (JobInfo jobInfo : getJobInfos()) {
+			int state = jobInfo.getJob().getState();
+			if (state == Job.WAITING || state == Job.RUNNING)
+				return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Get the current percent done.
+	 * 
+	 * @return int
+	 */
+	private int getPercentDone() {
+		if (info.isJobInfo()) {
+			return ((JobInfo) info).getPercentDone();
+		}
+
+		if (info.hasChildren()) {
+			Object[] roots = ((GroupInfo) info).getChildren();
+			if (roots.length == 1 && roots[0] instanceof JobTreeElement) {
+				TaskInfo ti = ((JobInfo) roots[0]).getTaskInfo();
+				if (ti != null) {
+					return ti.getPercentDone();
+				}
+			}
+			return ((GroupInfo) info).getPercentDone();
+		}
+		return 0;
+	}
+
+	/**
+	 * Set the images in the toolbar based on whether the receiver is finished
+	 * or not. Also update tooltips if required.
+	 * 
+	 */
+	private void updateToolBarValues() {
+		if (isCompleted()) {
+			actionButton.setImage(JFaceResources
+					.getImage(CLEAR_FINISHED_JOB_KEY));
+			actionButton.setDisabledImage(JFaceResources
+					.getImage(DISABLED_CLEAR_FINISHED_JOB_KEY));
+			actionButton
+					.setToolTipText(ProgressMessages.get().NewProgressView_ClearJobToolTip);
+		} else {
+			actionButton.setImage(JFaceResources.getImage(STOP_IMAGE_KEY));
+			actionButton.setDisabledImage(JFaceResources
+					.getImage(DISABLED_STOP_IMAGE_KEY));
+
+		}
+
+		for (JobInfo jobInfo : getJobInfos()) {
+			// Only disable if there is an unresponsive operation
+			if (jobInfo.isCanceled() && !isCompleted()) {
+				actionButton.setEnabled(false);
+				return;
+			}
+		}
+		actionButton.setEnabled(true);
+	}
+
+	/**
+	 * Create the progress bar and apply any style bits from style.
+	 * 
+	 * @param style
+	 */
+	void createProgressBar(int style) {
+
+		FormData buttonData = new FormData();
+		buttonData.top = new FormAttachment(progressLabel, 0);
+		buttonData.right = new FormAttachment(100,
+				IDialogConstants.HORIZONTAL_SPACING * -1);
+
+		actionBar.setLayoutData(buttonData);
+
+		progressBar = new ProgressBar(this, SWT.HORIZONTAL | style);
+		FormData barData = new FormData();
+		barData.top = new FormAttachment(actionBar,
+				IDialogConstants.VERTICAL_SPACING, SWT.TOP);
+		barData.left = new FormAttachment(progressLabel, 0, SWT.LEFT);
+		barData.right = new FormAttachment(actionBar,
+				IDialogConstants.HORIZONTAL_SPACING * -1);
+		barData.height = MAX_PROGRESS_HEIGHT;
+		barData.width = 0;// default is too large
+		progressBar.setLayoutData(barData);
+
+		if (taskEntries.size() > 0) {
+			// Reattach the link label if there is one
+			FormData linkData = new FormData();
+			linkData.top = new FormAttachment(progressBar,
+					IDialogConstants.VERTICAL_SPACING);
+			linkData.left = new FormAttachment(0,
+					IDialogConstants.HORIZONTAL_SPACING);
+			linkData.right = new FormAttachment(progressBar, 0, SWT.RIGHT);
+			// Give an initial value so as to constrain the link shortening
+			linkData.width = IDialogConstants.INDENT;
+
+			((Link) taskEntries.get(0)).setLayoutData(linkData);
+		}
+	}
+
+	/**
+	 * Set the text of the link to the taskString.
+	 * 
+	 * @param taskString
+	 */
+	void setLinkText(Job linkJob, String taskString, int index) {
+
+		if (index >= taskEntries.size()) {// Is it new?
+			link = new Link(this, SWT.NONE);
+
+			FormData linkData = new FormData();
+			if (index == 0 || taskEntries.size() == 0) {
+				Control top = progressBar;
+				if (top == null) {
+					top = progressLabel;
+				}
+				linkData.top = new FormAttachment(top,
+						IDialogConstants.VERTICAL_SPACING);
+				linkData.left = new FormAttachment(top, 0, SWT.LEFT);
+				linkData.right = new FormAttachment(progressBar, 0, SWT.RIGHT);
+				// Give an initial value so as to constrain the link shortening
+				linkData.width = IDialogConstants.INDENT;
+			} else {
+				Link previous = (Link) taskEntries.get(index - 1);
+				linkData.top = new FormAttachment(previous,
+						IDialogConstants.VERTICAL_SPACING);
+				linkData.left = new FormAttachment(previous, 0, SWT.LEFT);
+				linkData.right = new FormAttachment(previous, 0, SWT.RIGHT);
+				// Give an initial value so as to constrain the link shortening
+				linkData.width = 20;
+			}
+
+			link.setLayoutData(linkData);
+
+			link.addSelectionListener(new SelectionAdapter()			
+            {
+			    /** {@inheritDoc} */
+			    @Override
+			    public void widgetSelected(SelectionEvent e)
+			    {
+			        executeTrigger();
+			    }
+            });
+
+			link.addListener(SWT.Resize, event -> {
+
+				Object text = link.getData(TEXT_KEY);
+				if (text == null)
+					return;
+
+				updateText((String) text, link);
+
+			});
+			taskEntries.add(link);
+		} else {
+			link = (Link) taskEntries.get(index);
+		}
+
+		link.setToolTipText(taskString);
+		link.setData(TEXT_KEY, taskString);
+
+		// check for action property
+		Object actionProperty = linkJob
+.getProperty(IProgressConstants.ACTION_PROPERTY);
+		Object commandProperty = linkJob
+.getProperty(IProgressConstants2.COMMAND_PROPERTY);
+
+		if (actionProperty != null && commandProperty != null) {
+			// if both are specified, then use neither
+			updateTrigger(null, link);
+		} else {
+			Object property = actionProperty != null ? actionProperty
+					: commandProperty;
+			updateTrigger(property, link);
+		}
+
+		updateText(taskString, link);
+
+	}
+
+	public void executeTrigger() {
+
+		Object data = link.getData(TRIGGER_KEY);
+		if (data instanceof IAction) {
+			IAction action = (IAction) data;
+			if (action.isEnabled())
+				action.run();
+			updateTrigger(action, link);
+		} else if (data instanceof ParameterizedCommand) {
+			IWorkbench workbench = PlatformUI
+					.getWorkbench();
+			IHandlerService handlerService = (IHandlerService) workbench
+					.getService(
+							IHandlerService.class);
+			IStatus status = Status.OK_STATUS;
+			try {
+				handlerService
+						.executeCommand((ParameterizedCommand) data, null);
+			} catch (ExecutionException e) {
+				status = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, e
+						.getMessage(), e);
+			} catch (NotDefinedException e) {
+				status = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, e
+						.getMessage(), e);
+			} catch (NotEnabledException e) {
+				status = new Status(IStatus.WARNING, PlatformUI.PLUGIN_ID, e
+						.getMessage(), e);
+			} catch (NotHandledException e) {
+				status = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, e
+						.getMessage(), e);
+			}
+
+			if (!status.isOK()) {
+				StatusManager.getManager().handle(status,
+						StatusManager.LOG | StatusManager.SHOW);
+			}
+		}
+
+		Object text = link.getData(TEXT_KEY);
+		if (text == null)
+			return;
+
+		// Refresh the text as enablement might have changed
+		updateText((String) text, link);
+	}
+
+	/**
+	 * Update the trigger key if either action is available and enabled or
+	 * command is available
+	 * 
+	 * @param trigger
+	 *            {@link Object} or <code>null</code>
+	 * @param link
+	 */
+	private void updateTrigger(Object trigger, Link link) {
+
+		if (trigger instanceof IAction && ((IAction) trigger).isEnabled()) {
+			link.setData(TRIGGER_KEY, trigger);
+		} else if (trigger instanceof ParameterizedCommand) {
+			link.setData(TRIGGER_KEY, trigger);
+		} else {
+			link.setData(TRIGGER_KEY, null);
+		}
+
+	}
+
+	/**
+	 * Update the text in the link
+	 * 
+	 * @param taskString
+	 * @param link
+	 */
+	private void updateText(String taskString, Link link) {
+		taskString = Dialog.shortenText(taskString, link);
+
+		// Put in a hyperlink if there is an action
+		link.setText(link.getData(TRIGGER_KEY) == null ? taskString : NLS.bind(
+				"<a>{0}</a>", taskString));//$NON-NLS-1$
+	}
+
+	/**
+	 * Set the color base on the index
+	 * 
+	 * @param i
+	 */
+	public void setColor(int i) {
+		currentIndex = i;
+
+		if (selected) {
+			setAllBackgrounds(getDisplay().getSystemColor(
+					SWT.COLOR_LIST_SELECTION));
+			setAllForegrounds(getDisplay().getSystemColor(
+					SWT.COLOR_LIST_SELECTION_TEXT));
+			return;
+		}
+
+		if (!isThemed) {
+			if (i % 2 == 0) {
+				setAllBackgrounds(JFaceResources.getColorRegistry().get(DARK_COLOR_KEY));
+			} else {
+				setAllBackgrounds(getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
+			}
+			setAllForegrounds(getDisplay().getSystemColor(SWT.COLOR_LIST_FOREGROUND));
+		}
+
+	}
+
+	/**
+	 * Set the foreground of all widgets to the supplied color.
+	 * 
+	 * @param color
+	 */
+	private void setAllForegrounds(Color color) {
+		setForeground(color);
+		progressLabel.setForeground(color);
+
+		Iterator taskEntryIterator = taskEntries.iterator();
+		while (taskEntryIterator.hasNext()) {
+			((Link) taskEntryIterator.next()).setForeground(color);
+		}
+
+	}
+
+	/**
+	 * Set the background of all widgets to the supplied color.
+	 * 
+	 * @param color
+	 */
+	private void setAllBackgrounds(Color color) {
+		setBackground(color);
+		progressLabel.setBackground(color);
+		actionBar.setBackground(color);
+		jobImageLabel.setBackground(color);
+
+		Iterator taskEntryIterator = taskEntries.iterator();
+		while (taskEntryIterator.hasNext()) {
+			((Link) taskEntryIterator.next()).setBackground(color);
+		}
+
+	}
+
+	/**
+	 * Set the focus to the button.
+	 * 
+	 */
+	void setButtonFocus() {
+		actionBar.setFocus();
+	}
+
+	/**
+	 * Set the selection colors.
+	 * 
+	 * @param select
+	 *            boolean that indicates whether or not to show selection.
+	 */
+	void selectWidgets(boolean select) {
+		if (select) {
+			setButtonFocus();
+		}
+		selected = select;
+		setColor(currentIndex);
+	}
+
+	/**
+	 * Set the listener for index changes.
+	 * 
+	 * @param indexListener
+	 */
+	void setIndexListener(IndexListener indexListener) {
+		this.indexListener = indexListener;
+	}
+
+	/**
+	 * Return whether or not the receiver is selected.
+	 * 
+	 * @return boolean
+	 */
+	boolean isSelected() {
+		return selected;
+	}
+
+	/**
+	 * Set whether or not the receiver is being displayed based on the top and
+	 * bottom of the currently visible area.
+	 * 
+	 * @param top
+	 * @param bottom
+	 */
+	void setDisplayed(int top, int bottom) {
+		int itemTop = getLocation().y;
+		int itemBottom = itemTop + getBounds().height;
+		setDisplayed(itemTop <= bottom && itemBottom > top);
+
+	}
+
+	/**
+	 * Set whether or not the receiver is being displayed
+	 * 
+	 * @param displayed
+	 */
+	private void setDisplayed(boolean displayed) {
+		// See if this element has been turned off
+		boolean refresh = !isShowing && displayed;
+		isShowing = displayed;
+		if (refresh)
+			refresh();
+	}
+	
+	/* (non-Javadoc)
+	 * @see org.eclipse.swt.widgets.Widget#dispose()
+	 */
+	public void dispose() {
+		super.dispose();
+		if(resourceManager != null)
+			resourceManager.dispose();
+	}
+
+	/**
+	 * @return Returns the info.
+	 */
+	public JobTreeElement getInfo() {
+		return info;
+	}
+
+	/**
+	 * For testing only
+	 *
+	 * @return true if the trigger is enabled
+	 * @noreference
+	 */
+	public boolean isTriggerEnabled() {
+		return link != null && !link.isDisposed() && link.isEnabled();
+	}
+
+	/** Called whenever trigger details change */
+	private void hookTriggerCommandEnablement() {
+		final Object data = link.getData(TRIGGER_KEY);
+		if (!(data instanceof ParameterizedCommand) || !PlatformUI.isWorkbenchRunning())
+			return;
+
+		// Would be nice to have the window's context, but we're too deep
+		IEclipseContext context = PlatformUI.getWorkbench().getService(IEclipseContext.class);
+		if (context == null) {
+			return;
+		}
+		if (tracker != null) {
+			// stop any existing RATs as the command details may have changed
+			tracker.stop();
+		}
+		tracker = new HandlerChangeTracker((ParameterizedCommand) data);
+		context.runAndTrack(tracker);
+	}
+
+	/**
+	 * A RAT to update the trigger link on handler changes for the given command
+	 */
+	private class HandlerChangeTracker extends RunAndTrack {
+		private ParameterizedCommand parmCommand;
+		private boolean stop = false;
+
+		public HandlerChangeTracker(ParameterizedCommand parmCommand) {
+			this.parmCommand = parmCommand;
+		}
+
+		public void stop() {
+			this.stop = true;
+		}
+
+		@Override
+		public boolean changed(IEclipseContext context) {
+			if (stop || isDisposed() || !isShowing) {
+				// stop listening for changes
+				return false;
+			}
+			EHandlerService service = context.get(EHandlerService.class);
+			link.setEnabled(service != null && service.canExecute(parmCommand));
+			return true;
+		}
+	}
+	/*
+	 * Check if workspace is using a theme. If it is, confirm it is not the
+	 * default theme.
+	 */
+
+	private boolean getCustomThemeFlag() {
+	    // RAP [DM]
+//		IThemeEngine engine = PlatformUI.getWorkbench().getService(IThemeEngine.class);
+//		if (engine != null) {
+//			ITheme activeTheme = engine.getActiveTheme();
+//			if (activeTheme != null) {
+//				return !DEFAULT_THEME.equals(activeTheme.getId());
+//			}
+//		}
+		return false;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressLabelProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressLabelProvider.java
new file mode 100644
index 0000000..cdd6811
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressLabelProvider.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.internal.progress;
+
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * The ProgressLabelProvider is a label provider used for viewers
+ * that need anILabelprovider to show JobInfos.
+ */
+public class ProgressLabelProvider extends LabelProvider {
+
+    Image image;
+
+    @Override
+	public Image getImage(Object element) {
+        return ((JobTreeElement) element).getDisplayImage();
+    }
+
+    @Override
+	public String getText(Object element) {
+        return ((JobTreeElement) element).getDisplayString();
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressManager.java
new file mode 100644
index 0000000..4a36345
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressManager.java
@@ -0,0 +1,1435 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2010 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
+ *     Teddy Walker <teddy.walker@googlemail.com>
+ *     		- Fix for Bug 151204 [Progress] Blocked status of jobs are not applied/reported
+ *******************************************************************************/
+package org.eclipse.ui.internal.progress;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IProgressMonitorWithBlocking;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.QualifiedName;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.IJobChangeEvent;
+import org.eclipse.core.runtime.jobs.IJobChangeListener;
+import org.eclipse.core.runtime.jobs.IJobManager;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.core.runtime.jobs.JobChangeAdapter;
+import org.eclipse.core.runtime.jobs.ProgressProvider;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.operation.IRunnableContext;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.rap.rwt.SingletonUtil;
+import org.eclipse.rap.ui.internal.progress.ProgressUtil;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.ImageLoader;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.IPreferenceConstants;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.dialogs.EventLoopProgressMonitor;
+import org.eclipse.ui.internal.dialogs.WorkbenchDialogBlockedHandler;
+import org.eclipse.ui.internal.misc.Policy;
+import org.eclipse.ui.progress.IProgressConstants;
+import org.eclipse.ui.progress.IProgressService;
+import org.eclipse.ui.progress.WorkbenchJob;
+import org.eclipse.ui.statushandlers.StatusAdapter;
+import org.eclipse.ui.statushandlers.StatusManager;
+import org.eclipse.ui.statushandlers.StatusManager.INotificationListener;
+import org.eclipse.ui.statushandlers.StatusManager.INotificationTypes;
+
+/**
+ * JobProgressManager provides the progress monitor to the job manager and
+ * informs any ProgressContentProviders of changes.
+ */
+public class ProgressManager extends ProgressProvider implements
+		IProgressService {
+	/**
+	 * A property to determine if the job was run in the dialog. Kept for
+	 * backwards compatability.
+	 * 
+	 * @deprecated
+	 * @see IProgressConstants#PROPERTY_IN_DIALOG
+	 */
+	public static final QualifiedName PROPERTY_IN_DIALOG = IProgressConstants.PROPERTY_IN_DIALOG;
+
+	private static final String ERROR_JOB = "errorstate.gif"; //$NON-NLS-1$
+
+	static final String ERROR_JOB_KEY = "ERROR_JOB"; //$NON-NLS-1$
+
+// RAP [fappel]: ProgressManager needs to be session aware	
+//	private static ProgressManager singleton;
+    Display display;
+    public static class ProgressManagerProvider {
+      public static ProgressManager getInstance() {
+    	ProgressManager instance = SingletonUtil.getSessionInstance( ProgressManager.class );
+    	if( instance.display == null ) {
+    	  Dialog.setBlockedHandler(new WorkbenchDialogBlockedHandler());
+    	  instance.display = Display.getCurrent();
+    	  // TODO [fappel]: find a better place for initialization...
+    	  ProgressInfoItem.init();
+    
+    	  URL iconsRoot = ProgressManagerUtil.getIconsRoot();
+    	  try {
+    	    instance.setUpImage(iconsRoot, SLEEPING_JOB, SLEEPING_JOB_KEY);
+    	    instance.setUpImage(iconsRoot, WAITING_JOB, WAITING_JOB_KEY);
+    	    instance.setUpImage(iconsRoot, BLOCKED_JOB, BLOCKED_JOB_KEY);
+    	    // Let the error manager set up its own icons
+			ImageDescriptor errorImage = ImageDescriptor
+							.createFromURL(new URL(iconsRoot, ERROR_JOB));
+			JFaceResources.getImageRegistry().put(ERROR_JOB_KEY,
+							errorImage);
+
+    	  } catch (MalformedURLException e) {
+    	    ProgressManagerUtil.logException(e);
+    	  }
+    	}
+    	return instance;
+      }
+    }
+
+	final private Map jobs = Collections.synchronizedMap(new HashMap());
+
+	final private Map familyListeners = Collections
+			.synchronizedMap(new HashMap());
+
+	//	list of IJobProgressManagerListener
+	private ListenerList listeners = new ListenerList();
+	
+	// RAP [bm]: made public to access in org.eclipse.rap.ui.*
+	public IJobChangeListener changeListener;
+
+	static final String PROGRESS_VIEW_NAME = "org.eclipse.ui.views.ProgressView"; //$NON-NLS-1$
+
+	static final String PROGRESS_FOLDER = "$nl$/icons/full/progress/"; //$NON-NLS-1$
+
+	private static final String SLEEPING_JOB = "sleeping.gif"; //$NON-NLS-1$
+
+	private static final String WAITING_JOB = "waiting.gif"; //$NON-NLS-1$
+
+	private static final String BLOCKED_JOB = "lockedstate.gif"; //$NON-NLS-1$
+
+	/**
+	 * The key for the sleeping job icon.
+	 */
+	public static final String SLEEPING_JOB_KEY = "SLEEPING_JOB"; //$NON-NLS-1$
+
+	/**
+	 * The key for the waiting job icon.
+	 */
+	public static final String WAITING_JOB_KEY = "WAITING_JOB"; //$NON-NLS-1$
+
+	/**
+	 * The key for the locked job icon.
+	 */
+	public static final String BLOCKED_JOB_KEY = "LOCKED_JOB"; //$NON-NLS-1$
+
+	final Map runnableMonitors = Collections.synchronizedMap(new HashMap());
+
+	// A table that maps families to keys in the Jface image
+	// table
+	private Hashtable imageKeyTable = new Hashtable();
+
+	/*
+	 * A listener that allows for removing error jobs & indicators when errors
+	 * are handled.
+	 */
+	private final INotificationListener notificationListener;
+
+	private static final String IMAGE_KEY = "org.eclipse.ui.progress.images"; //$NON-NLS-1$
+
+	/**
+	 * Get the progress manager currently in use.
+	 * 
+	 * @return JobProgressManager
+	 */
+	public static ProgressManager getInstance() {
+// RAP [fappel]: ProgressManager needs to be session aware
+//		if (singleton == null) {
+//			singleton = new ProgressManager();
+//		}
+//		return singleton;
+	  return ProgressManagerProvider.getInstance();
+	}
+
+	/**
+	 * Shutdown the singleton if there is one.
+	 */
+	public static void shutdownProgressManager() {
+// RAP [fappel]: ProgressManager needs to be session aware
+//		if (singleton == null) {
+//			return;
+//		}
+//		singleton.shutdown();
+       if (getInstance() == null) {
+           return;
+       }
+       getInstance().shutdown();
+
+	}
+
+	/**
+	 * The JobMonitor is the inner class that handles the IProgressMonitor
+	 * integration with the ProgressMonitor.
+	 */
+	class JobMonitor implements IProgressMonitorWithBlocking {
+		Job job;
+
+		String currentTaskName;
+
+		IProgressMonitorWithBlocking listener;
+
+		/**
+		 * Create a monitor on the supplied job.
+		 * 
+		 * @param newJob
+		 */
+		JobMonitor(Job newJob) {
+			job = newJob;
+		}
+
+		/**
+		 * Add monitor as another monitor that
+		 * 
+		 * @param monitor
+		 */
+		void addProgressListener(IProgressMonitorWithBlocking monitor) {
+			listener = monitor;
+			JobInfo info = getJobInfo(job);
+			TaskInfo currentTask = info.getTaskInfo();
+			if (currentTask != null) {
+				listener.beginTask(currentTaskName, currentTask.totalWork);
+				listener.internalWorked(currentTask.preWork);
+			}
+		}
+
+		/*
+		 * (non-Javadoc)
+		 * 
+		 * @see org.eclipse.core.runtime.IProgressMonitor#beginTask(java.lang.String,
+		 *      int)
+		 */
+		public void beginTask(String taskName, int totalWork) {
+			JobInfo info = getJobInfo(job);
+			info.beginTask(taskName, totalWork);
+			refreshJobInfo(info);
+			currentTaskName = taskName;
+			if (listener != null) {
+				listener.beginTask(taskName, totalWork);
+			}
+		}
+
+		/*
+		 * (non-Javadoc)
+		 * 
+		 * @see org.eclipse.core.runtime.IProgressMonitor#done()
+		 */
+		public void done() {
+			final JobInfo info = getJobInfo(job);
+			// RAP [if]: ensure mapping to context
+			RWT.getUISession( display ).exec( new Runnable() {
+              public void run() {
+                info.clearTaskInfo();
+              }
+            } );
+			info.clearChildren();
+			runnableMonitors.remove(job);
+			if (listener != null) {
+				listener.done();
+			}
+		}
+
+		/*
+		 * (non-Javadoc)
+		 * 
+		 * @see org.eclipse.core.runtime.IProgressMonitor#internalWorked(double)
+		 */
+		public void internalWorked(double work) {
+			JobInfo info = getJobInfo(job);
+			if (info.hasTaskInfo()) {
+				info.addWork(work);
+				refreshJobInfo(info);
+			}
+			if (listener != null) {
+				listener.internalWorked(work);
+			}
+		}
+
+		/*
+		 * (non-Javadoc)
+		 * 
+		 * @see org.eclipse.core.runtime.IProgressMonitor#isCanceled()
+		 */
+		public boolean isCanceled() {
+			// Use the internal get so we don't create a Job Info for
+			// a job that is not running (see bug 149857)
+			JobInfo info = internalGetJobInfo(job);
+			if (info == null)
+				return false;
+			return info.isCanceled();
+		}
+
+		/*
+		 * (non-Javadoc)
+		 * 
+		 * @see org.eclipse.core.runtime.IProgressMonitor#setCanceled(boolean)
+		 */
+		public void setCanceled(boolean value) {
+			JobInfo info = getJobInfo(job);
+			// Don't bother cancelling twice
+			if (value && !info.isCanceled()) {
+				info.cancel();
+				// Only inform the first time
+				if (listener != null) {
+					listener.setCanceled(value);
+				}
+			}
+		}
+
+		/*
+		 * (non-Javadoc)
+		 * 
+		 * @see org.eclipse.core.runtime.IProgressMonitor#setTaskName(java.lang.String)
+		 */
+		public void setTaskName(String taskName) {
+			JobInfo info = getJobInfo(job);
+			if (info.hasTaskInfo()) {
+				info.setTaskName(taskName);
+			} else {
+				beginTask(taskName, 100);
+				return;
+			}
+			info.clearChildren();
+			refreshJobInfo(info);
+			currentTaskName = taskName;
+			if (listener != null) {
+				listener.setTaskName(taskName);
+			}
+		}
+
+		/*
+		 * (non-Javadoc)
+		 * 
+		 * @see org.eclipse.core.runtime.IProgressMonitor#subTask(java.lang.String)
+		 */
+		public void subTask(String name) {
+			if (name == null) {
+				return;
+			}
+			JobInfo info = getJobInfo(job);
+			info.clearChildren();
+			info.addSubTask(name);
+			refreshJobInfo(info);
+			if (listener != null) {
+				listener.subTask(name);
+			}
+		}
+
+		/*
+		 * (non-Javadoc)
+		 * 
+		 * @see org.eclipse.core.runtime.IProgressMonitor#worked(int)
+		 */
+		public void worked(int work) {
+			internalWorked(work);
+		}
+
+		/*
+		 * (non-Javadoc)
+		 * 
+		 * @see org.eclipse.core.runtime.IProgressMonitorWithBlocking#clearBlocked()
+		 */
+		public void clearBlocked() {
+			JobInfo info = getJobInfo(job);
+			info.setBlockedStatus(null);
+			refreshJobInfo(info);
+			if (listener != null) {
+				listener.clearBlocked();
+			}
+		}
+
+		/*
+		 * (non-Javadoc)
+		 * 
+		 * @see org.eclipse.core.runtime.IProgressMonitorWithBlocking#setBlocked(org.eclipse.core.runtime.IStatus)
+		 */
+		public void setBlocked(IStatus reason) {
+			JobInfo info = getJobInfo(job);
+			info.setBlockedStatus(reason);
+			refreshJobInfo(info);
+			if (listener != null) {
+				listener.setBlocked(reason);
+			}
+		}
+	}
+
+	/**
+	 * Create a new instance of the receiver.
+	 */
+	// RAP [bm]: made public to access in org.eclipse.rap.ui.*
+	public ProgressManager() {
+// RAP [fappel]:	  
+//		Job.getJobManager().setProgressProvider(this);
+//		Dialog.setBlockedHandler(new WorkbenchDialogBlockedHandler());
+		createChangeListener();
+		notificationListener = createNotificationListener();
+// RAP [fappel]:	  
+//		Job.getJobManager().addJobChangeListener(this.changeListener);
+//		URL iconsRoot = ProgressManagerUtil.getIconsRoot();
+//		try {
+//			setUpImage(iconsRoot, SLEEPING_JOB, SLEEPING_JOB_KEY);
+//			setUpImage(iconsRoot, WAITING_JOB, WAITING_JOB_KEY);
+//			setUpImage(iconsRoot, BLOCKED_JOB, BLOCKED_JOB_KEY);
+//
+//			// Let the error manager set up its own icons
+//			setUpImages(iconsRoot);
+//		} catch (MalformedURLException e) {
+//			ProgressManagerUtil.logException(e);
+//		}
+	}
+
+	private INotificationListener createNotificationListener() {
+
+		return new StatusManager.INotificationListener(){
+
+			public void statusManagerNotified(int type, StatusAdapter[] adapters) {
+				if(type == INotificationTypes.HANDLED){
+					FinishedJobs.getInstance().removeErrorJobs();
+					StatusAdapterHelper.getInstance().clear();
+				}
+			}
+			
+		};
+	}
+
+	/**
+	 * Create and return the IJobChangeListener registered with the Job manager.
+	 * 
+	 * @return the created IJobChangeListener
+	 */
+	private void createChangeListener() {
+		changeListener = new JobChangeAdapter() {
+
+			/*
+			 * (non-Javadoc)
+			 * 
+			 * @see org.eclipse.core.runtime.jobs.JobChangeAdapter#aboutToRun(org.eclipse.core.runtime.jobs.IJobChangeEvent)
+			 */
+			public void aboutToRun(IJobChangeEvent event) {
+				JobInfo info = getJobInfo(event.getJob());
+				refreshJobInfo(info);
+				Iterator startListeners = busyListenersForJob(event.getJob())
+						.iterator();
+				while (startListeners.hasNext()) {
+					IJobBusyListener next = (IJobBusyListener) startListeners
+							.next();
+					next.incrementBusy(event.getJob());
+				}
+			}
+
+			/*
+			 * (non-Javadoc)
+			 * 
+			 * @see org.eclipse.core.runtime.jobs.JobChangeAdapter#done(org.eclipse.core.runtime.jobs.IJobChangeEvent)
+			 */
+			public void done(IJobChangeEvent event) {
+// RAP [rh] run regardless of a running workbench (see bug 283595)
+//				if (!PlatformUI.isWorkbenchRunning()) {
+//					return;
+//				}
+				Iterator startListeners = busyListenersForJob(event.getJob())
+						.iterator();
+				while (startListeners.hasNext()) {
+					IJobBusyListener next = (IJobBusyListener) startListeners
+							.next();
+					next.decrementBusy(event.getJob());
+				}
+
+				final JobInfo info = getJobInfo(event.getJob());
+				removeJobInfo(info);
+
+				if (event.getResult() != null
+						&& event.getResult().getSeverity() == IStatus.ERROR) {
+					StatusAdapter statusAdapter = new StatusAdapter(event
+							.getResult());
+					statusAdapter.addAdapter(Job.class, event.getJob());
+
+					if (event
+							.getJob()
+							.getProperty(
+									IProgressConstants.NO_IMMEDIATE_ERROR_PROMPT_PROPERTY) == Boolean.TRUE) {
+						statusAdapter
+								.setProperty(
+										IProgressConstants.NO_IMMEDIATE_ERROR_PROMPT_PROPERTY,
+										Boolean.TRUE);
+						StatusAdapterHelper.getInstance().putStatusAdapter(
+								info, statusAdapter);
+					}
+
+					StatusManager.getManager().handle(statusAdapter, StatusManager.SHOW);
+				}
+			}
+
+			/*
+			 * (non-Javadoc)
+			 * 
+			 * @see org.eclipse.core.runtime.jobs.JobChangeAdapter#scheduled(org.eclipse.core.runtime.jobs.IJobChangeEvent)
+			 */
+			public void scheduled(IJobChangeEvent event) {
+				updateFor(event);
+				if (event.getJob().isUser()) {
+					boolean noDialog = shouldRunInBackground();
+					if (!noDialog) {
+						final IJobChangeEvent finalEvent = event;
+						WorkbenchJob showJob = new WorkbenchJob(
+								ProgressMessages.get().ProgressManager_showInDialogName) {
+							/*
+							 * (non-Javadoc)
+							 * 
+							 * @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor)
+							 */
+							public IStatus runInUIThread(
+									IProgressMonitor monitor) {
+								showInDialog(null, finalEvent.getJob());
+								return Status.OK_STATUS;
+							}
+						};
+						showJob.setSystem(true);
+						showJob.schedule();
+						return;
+					}
+				}
+			}
+
+			/**
+			 * Update the listeners for the receiver for the event.
+			 * 
+			 * @param event
+			 */
+			private void updateFor(IJobChangeEvent event) {
+				if (isInfrastructureJob(event.getJob())) {
+					return;
+				}
+				if (jobs.containsKey(event.getJob())) {
+					refreshJobInfo(getJobInfo(event.getJob()));
+				} else {
+					addJobInfo(new JobInfo(event.getJob()));
+				}
+			}
+
+			/*
+			 * (non-Javadoc)
+			 * 
+			 * @see org.eclipse.core.runtime.jobs.JobChangeAdapter#awake(org.eclipse.core.runtime.jobs.IJobChangeEvent)
+			 */
+			public void awake(IJobChangeEvent event) {
+				updateFor(event);
+			}
+
+			/*
+			 * (non-Javadoc)
+			 * 
+			 * @see org.eclipse.core.runtime.jobs.JobChangeAdapter#sleeping(org.eclipse.core.runtime.jobs.IJobChangeEvent)
+			 */
+			public void sleeping(IJobChangeEvent event) {
+
+				if (jobs.containsKey(event.getJob()))// Are we showing this?
+					sleepJobInfo(getJobInfo(event.getJob()));
+			}
+		};
+	}
+
+	/**
+	 * The job in JobInfo is now sleeping. Refresh it if we are showing it,
+	 * remove it if not.
+	 * 
+	 * @param info
+	 */
+	protected void sleepJobInfo(JobInfo info) {
+		if (isInfrastructureJob(info.getJob()))
+			return;
+
+		GroupInfo group = info.getGroupInfo();
+		if (group != null) {
+			sleepGroup(group,info);
+		}
+
+		Object[] listenersArray = listeners.getListeners();
+		for (int i = 0; i < listenersArray.length; i++) {
+			IJobProgressManagerListener listener = (IJobProgressManagerListener) listenersArray[i];
+			// Is this one the user never sees?
+			if (isNeverDisplaying(info.getJob(), listener.showsDebug()))
+				continue;
+			if (listener.showsDebug())
+				listener.refreshJobInfo(info);
+			else
+				listener.removeJob(info);
+
+		}
+	}
+
+	/**
+	 * Refresh the group when info is sleeping.
+	 * @param group
+	 */
+	private void sleepGroup(GroupInfo group, JobInfo info) {
+		Object[] listenersArray = listeners.getListeners();
+		for (int i = 0; i < listenersArray.length; i++) {
+			
+			IJobProgressManagerListener listener = (IJobProgressManagerListener) listenersArray[i];
+			if (isNeverDisplaying(info.getJob(), listener.showsDebug()))
+				continue;
+	
+			if (listener.showsDebug() || group.isActive())
+				listener.refreshGroup(group);
+			else
+				listener.removeGroup(group);
+		}
+	}
+
+	/**
+	 * Set up the image in the image regsitry.
+	 * 
+	 * @param iconsRoot
+	 * @param fileName
+	 * @param key
+	 * @throws MalformedURLException
+	 */
+	private void setUpImage(URL iconsRoot, String fileName, String key)
+			throws MalformedURLException {
+		JFaceResources.getImageRegistry().put(key,
+				ImageDescriptor.createFromURL(new URL(iconsRoot, fileName)));
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.eclipse.core.runtime.jobs.ProgressProvider#createMonitor(org.eclipse.core.runtime.jobs.Job)
+	 */
+	public IProgressMonitor createMonitor(Job job) {
+		return progressFor(job);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.eclipse.core.runtime.jobs.ProgressProvider#getDefaultMonitor()
+	 */
+	public IProgressMonitor getDefaultMonitor() {
+		// only need a default monitor for operations the UI thread
+		// and only if there is a display
+// RAP [fappel]:
+//		Display display;
+//		if (PlatformUI.isWorkbenchRunning()
+		if (ProgressUtil.isWorkbenchRunning( display )
+				&& !(PlatformUI.getWorkbench()).isStarting()) {
+//			display = PlatformUI.getWorkbench().getDisplay();
+			if (!display.isDisposed()
+					&& (display.getThread() == Thread.currentThread())) {
+				return new EventLoopProgressMonitor(new NullProgressMonitor());
+			}
+		}
+		return super.getDefaultMonitor();
+	}
+
+	/**
+	 * Return a monitor for the job. Check if we cached a monitor for this job
+	 * previously for a long operation timeout check.
+	 * 
+	 * @param job
+	 * @return IProgressMonitor
+	 */
+	public JobMonitor progressFor(Job job) {
+
+		synchronized (runnableMonitors) {
+			JobMonitor monitor = (JobMonitor) runnableMonitors.get(job);
+			if (monitor == null) {
+				monitor = new JobMonitor(job);
+				runnableMonitors.put(job, monitor);
+			}
+			
+			return monitor;
+		}
+
+	}
+
+	/**
+	 * Add an IJobProgressManagerListener to listen to the changes.
+	 * 
+	 * @param listener
+	 */
+	void addListener(IJobProgressManagerListener listener) {
+		listeners.add(listener);
+	}
+
+	/**
+	 * Remove the supplied IJobProgressManagerListener from the list of
+	 * listeners.
+	 * 
+	 * @param listener
+	 */
+	void removeListener(IJobProgressManagerListener listener) {
+		listeners.remove(listener);
+	}
+
+	/**
+	 * Get the JobInfo for the job. If it does not exist create it.
+	 * 
+	 * @param job
+	 * @return JobInfo
+	 */
+	JobInfo getJobInfo(Job job) {
+		JobInfo info = internalGetJobInfo(job);
+		if (info == null) {
+			info = new JobInfo(job);
+			jobs.put(job, info);
+		}
+		return info;
+	}
+
+	/**
+	 * Return an existing job info for the given Job or <code>null</code> if
+	 * there isn't one.
+	 * 
+	 * @param job
+	 * @return JobInfo
+	 */
+	JobInfo internalGetJobInfo(Job job) {
+		return (JobInfo) jobs.get(job);
+	}
+
+	/**
+	 * Refresh the IJobProgressManagerListeners as a result of a change in info.
+	 * 
+	 * @param info
+	 */
+	public void refreshJobInfo(JobInfo info) {
+		GroupInfo group = info.getGroupInfo();
+		if (group != null) {
+			refreshGroup(group);
+		}
+
+		Object[] listenersArray = listeners.getListeners();
+		for (int i = 0; i < listenersArray.length; i++) {
+			IJobProgressManagerListener listener = (IJobProgressManagerListener) listenersArray[i];
+			if (!isCurrentDisplaying(info.getJob(), listener.showsDebug())) {
+				listener.refreshJobInfo(info);
+			}
+		}
+	}
+
+	/**
+	 * Refresh the IJobProgressManagerListeners as a result of a change in info.
+	 * 
+	 * @param info
+	 */
+	public void refreshGroup(GroupInfo info) {
+
+		Object[] listenersArray = listeners.getListeners();
+		for (int i = 0; i < listenersArray.length; i++) {
+			((IJobProgressManagerListener)listenersArray[i]).refreshGroup(info);
+		}
+	}
+
+	/**
+	 * Refresh all the IJobProgressManagerListener as a result of a change in
+	 * the whole model.
+	 */
+	public void refreshAll() {
+
+		pruneStaleJobs();
+		Object[] listenersArray = listeners.getListeners();
+		for (int i = 0; i < listenersArray.length; i++) {
+			((IJobProgressManagerListener)listenersArray[i]).refreshAll();
+		}
+
+	}
+
+	/**
+	 * Refresh the content providers as a result of a deletion of info.
+	 * 
+	 * @param info
+	 *            JobInfo
+	 */
+	public void removeJobInfo(JobInfo info) {
+
+		Job job = info.getJob();
+		jobs.remove(job);
+		runnableMonitors.remove(job);
+
+		Object[] listenersArray = listeners.getListeners();
+		for (int i = 0; i < listenersArray.length; i++) {
+			IJobProgressManagerListener listener = (IJobProgressManagerListener) listenersArray[i];
+			if (!isCurrentDisplaying(info.getJob(), listener.showsDebug())) {
+				listener.removeJob(info);
+			}
+		}
+	}
+
+	/**
+	 * Remove the group from the roots and inform the listeners.
+	 * 
+	 * @param group
+	 *            GroupInfo
+	 */
+	public void removeGroup(GroupInfo group) {
+
+		Object[] listenersArray = listeners.getListeners();
+		for (int i = 0; i < listenersArray.length; i++) {
+			((IJobProgressManagerListener)listenersArray[i]).removeGroup(group);
+		}
+	}
+
+	/**
+	 * Refresh the content providers as a result of an addition of info.
+	 * 
+	 * @param info
+	 */
+	public void addJobInfo(JobInfo info) {
+		GroupInfo group = info.getGroupInfo();
+		if (group != null) {
+			refreshGroup(group);
+		}
+
+		jobs.put(info.getJob(), info);
+		Object[] listenersArray = listeners.getListeners();
+		for (int i = 0; i < listenersArray.length; i++) {
+			IJobProgressManagerListener listener = (IJobProgressManagerListener) listenersArray[i];
+			if (!isCurrentDisplaying(info.getJob(), listener.showsDebug())) {
+				listener.addJob(info);
+			}
+		}
+	}
+
+	/**
+	 * Return whether or not this job is currently displayable.
+	 * 
+	 * @param job
+	 * @param debug
+	 *            If the listener is in debug mode.
+	 * @return boolean <code>true</code> if the job is not displayed.
+	 */
+	boolean isCurrentDisplaying(Job job, boolean debug) {
+		return isNeverDisplaying(job, debug) || job.getState() == Job.SLEEPING;
+	}
+
+	/**
+	 * Return whether or not we even display this job with debug mode set to
+	 * debug.
+	 * 
+	 * @param job
+	 * @param debug
+	 * @return boolean
+	 */
+	boolean isNeverDisplaying(Job job, boolean debug) {
+		if (isInfrastructureJob(job)) {
+			return true;
+		}
+		if (debug)
+			return false;
+
+		return job.isSystem();
+	}
+
+	/**
+	 * Return whether or not this job is an infrastructure job.
+	 * 
+	 * @param job
+	 * @return boolean <code>true</code> if it is never displayed.
+	 */
+	private boolean isInfrastructureJob(Job job) {
+		if (Policy.DEBUG_SHOW_ALL_JOBS)
+			return false;
+		return job.getProperty(ProgressManagerUtil.INFRASTRUCTURE_PROPERTY) != null;
+	}
+
+	/**
+	 * Return the current job infos filtered on debug mode.
+	 * 
+	 * @param debug
+	 * @return JobInfo[]
+	 */
+	public JobInfo[] getJobInfos(boolean debug) {
+		synchronized (jobs) {
+			Iterator iterator = jobs.keySet().iterator();
+			Collection result = new ArrayList();
+			while (iterator.hasNext()) {
+				Job next = (Job) iterator.next();
+				if (!isCurrentDisplaying(next, debug)) {
+					result.add(jobs.get(next));
+				}
+			}
+			JobInfo[] infos = new JobInfo[result.size()];
+			result.toArray(infos);
+			return infos;
+		}
+	}
+
+	/**
+	 * Return the current root elements filtered on the debug mode.
+	 * 
+	 * @param debug
+	 * @return JobTreeElement[]
+	 */
+	public JobTreeElement[] getRootElements(boolean debug) {
+		synchronized (jobs) {
+			Iterator iterator = jobs.keySet().iterator();
+			Collection result = new HashSet();
+			while (iterator.hasNext()) {
+				Job next = (Job) iterator.next();
+				if (!isCurrentDisplaying(next, debug)) {
+					JobInfo jobInfo = (JobInfo) jobs.get(next);
+					GroupInfo group = jobInfo.getGroupInfo();
+					if (group == null) {
+						result.add(jobInfo);
+					} else {
+						result.add(group);
+					}
+				}
+			}
+			JobTreeElement[] infos = new JobTreeElement[result.size()];
+			result.toArray(infos);
+			return infos;
+		}
+	}
+
+	/**
+	 * Return whether or not there are any jobs being displayed.
+	 * 
+	 * @return boolean
+	 */
+	public boolean hasJobInfos() {
+		synchronized (jobs) {
+			Iterator iterator = jobs.keySet().iterator();
+			while (iterator.hasNext()) {
+				return true;
+			}
+			return false;
+		}
+	}
+
+	/**
+	 * Returns the image descriptor with the given relative path.
+	 * 
+	 * @param source
+	 * @return Image
+	 */
+	Image getImage(ImageData source) {
+// RAP [rst]: constructing image with transparency mask not supported
+//		ImageData mask = source.getTransparencyMask();
+//		return new Image(null, source, mask);
+	  return new Image( null, source );
+	}
+
+	/**
+	 * Returns the image descriptor with the given relative path.
+	 * 
+	 * @param fileSystemPath
+	 *            The URL for the file system to the image.
+	 * @param loader -
+	 *            the loader used to get this data
+	 * @return ImageData[]
+	 */
+	ImageData[] getImageData(URL fileSystemPath, ImageLoader loader) {
+		try {
+			InputStream stream = fileSystemPath.openStream();
+			ImageData[] result = loader.load(stream);
+			stream.close();
+			return result;
+		} catch (FileNotFoundException exception) {
+			ProgressManagerUtil.logException(exception);
+			return null;
+		} catch (IOException exception) {
+			ProgressManagerUtil.logException(exception);
+			return null;
+		}
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.eclipse.ui.progress.IProgressService#busyCursorWhile(org.eclipse.jface.operation.IRunnableWithProgress)
+	 */
+	public void busyCursorWhile(final IRunnableWithProgress runnable)
+			throws InvocationTargetException, InterruptedException {
+		final ProgressMonitorJobsDialog dialog = new ProgressMonitorJobsDialog(
+				ProgressManagerUtil.getDefaultParent());
+		dialog.setOpenOnRun(false);
+		final InvocationTargetException[] invokes = new InvocationTargetException[1];
+		final InterruptedException[] interrupt = new InterruptedException[1];
+		// show a busy cursor until the dialog opens
+		Runnable dialogWaitRunnable = new Runnable() {
+			public void run() {
+				try {
+					dialog.setOpenOnRun(false);
+					setUserInterfaceActive(false);
+					dialog.run(true, true, runnable);
+				} catch (InvocationTargetException e) {
+					invokes[0] = e;
+				} catch (InterruptedException e) {
+					interrupt[0] = e;
+				} finally {
+					setUserInterfaceActive(true);
+				}
+			}
+		};
+		busyCursorWhile(dialogWaitRunnable, dialog);
+		if (invokes[0] != null) {
+			throw invokes[0];
+		}
+		if (interrupt[0] != null) {
+			throw interrupt[0];
+		}
+	}
+
+	/**
+	 * Show the busy cursor while the runnable is running. Schedule a job to
+	 * replace it with a progress dialog.
+	 * 
+	 * @param dialogWaitRunnable
+	 * @param dialog
+	 */
+	private void busyCursorWhile(Runnable dialogWaitRunnable,
+			ProgressMonitorJobsDialog dialog) {
+		// create the job that will open the dialog after a delay
+		scheduleProgressMonitorJob(dialog);
+		final Display display = PlatformUI.getWorkbench().getDisplay();
+		if (display == null) {
+			return;
+		}
+		// show a busy cursor until the dialog opens
+		BusyIndicator.showWhile(display, dialogWaitRunnable);
+	}
+
+	/**
+	 * Schedule the job that will open the progress monitor dialog
+	 * 
+	 * @param dialog
+	 *            the dialog to open
+	 */
+	private void scheduleProgressMonitorJob(
+			final ProgressMonitorJobsDialog dialog) {
+
+		final WorkbenchJob updateJob = new WorkbenchJob(
+				ProgressMessages.get().ProgressManager_openJobName) {
+			/*
+			 * (non-Javadoc)
+			 * 
+			 * @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor)
+			 */
+			public IStatus runInUIThread(IProgressMonitor monitor) {
+				setUserInterfaceActive(true);
+				if (ProgressManagerUtil.safeToOpen(dialog, null)) {
+					dialog.open();
+				}
+				return Status.OK_STATUS;
+			}
+		};
+		updateJob.setSystem(true);
+		updateJob.schedule(getLongOperationTime());
+
+	}
+
+	/**
+	 * Shutdown the receiver.
+	 */
+	private void shutdown() {
+// RAP [fappel]: progress manager must not be shutdown since its not directly
+//               added to jobmanager
+//		synchronized (listenersKey) {
+//			this.listeners = new IJobProgressManagerListener[0];
+//		}
+//		Job.getJobManager().setProgressProvider(null);
+//		Job.getJobManager().removeJobChangeListener(this.changeListener);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.eclipse.core.runtime.jobs.ProgressProvider#createProgressGroup()
+	 */
+	public IProgressMonitor createProgressGroup() {
+		return new GroupInfo();
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.eclipse.core.runtime.jobs.ProgressProvider#createMonitor(org.eclipse.core.runtime.jobs.Job,
+	 *      org.eclipse.core.runtime.IProgressMonitor, int)
+	 */
+	public IProgressMonitor createMonitor(Job job, IProgressMonitor group,
+			int ticks) {
+		JobMonitor monitor = progressFor(job);
+		if (group instanceof GroupInfo) {
+			GroupInfo groupInfo = (GroupInfo) group;
+			JobInfo jobInfo = getJobInfo(job);
+			jobInfo.setGroupInfo(groupInfo);
+			jobInfo.setTicks(ticks);
+			groupInfo.addJobInfo(jobInfo);
+		}
+		return monitor;
+	}
+
+	/**
+	 * Add the listener to the family.
+	 * 
+	 * @param family
+	 * @param listener
+	 */
+	void addListenerToFamily(Object family, IJobBusyListener listener) {
+		synchronized (familyListeners) {
+			Collection currentListeners = (Collection) familyListeners.get(family);
+			if (currentListeners == null) {
+				currentListeners = new HashSet();
+				familyListeners.put(family, currentListeners);
+			}
+			currentListeners.add(listener);
+		}
+	}
+
+	/**
+	 * Remove the listener from all families.
+	 * 
+	 * @param listener
+	 */
+	void removeListener(IJobBusyListener listener) {
+		synchronized (familyListeners) {
+			Iterator families = familyListeners.keySet().iterator();
+			while (families.hasNext()) {
+				Object next = families.next();
+				Collection currentListeners = (Collection) familyListeners
+						.get(next);
+				currentListeners.remove(listener);
+
+				// Remove any empty listeners
+				if (currentListeners.isEmpty()) {
+					families.remove();
+				}
+			}
+		}
+	}
+
+	/**
+	 * Return the listeners for the job.
+	 * 
+	 * @param job
+	 * @return Collection of IJobBusyListener
+	 */
+	private Collection busyListenersForJob(Job job) {
+		if (job.isSystem()) {
+			return Collections.EMPTY_LIST;
+		}
+		synchronized (familyListeners) {
+
+			if (familyListeners.isEmpty()) {
+				return Collections.EMPTY_LIST;
+			}
+
+			Iterator families = familyListeners.keySet().iterator();
+			Collection returnValue = new HashSet();
+			while (families.hasNext()) {
+				Object next = families.next();
+				if (job.belongsTo(next)) {
+					Collection currentListeners = (Collection) familyListeners
+							.get(next);
+					returnValue.addAll(currentListeners);
+				}
+			}
+			return returnValue;
+		}
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.eclipse.ui.progress.IProgressService#showInDialog(org.eclipse.swt.widgets.Shell,
+	 *      org.eclipse.core.runtime.jobs.Job)
+	 */
+	public void showInDialog(Shell shell, Job job) {
+		if (shouldRunInBackground()) {
+			return;
+		}
+
+		final ProgressMonitorFocusJobDialog dialog = new ProgressMonitorFocusJobDialog(
+				shell);
+		dialog.show(job, shell);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.eclipse.jface.operation.IRunnableContext#run(boolean, boolean,
+	 *      org.eclipse.jface.operation.IRunnableWithProgress)
+	 */
+	public void run(boolean fork, boolean cancelable,
+			IRunnableWithProgress runnable) throws InvocationTargetException,
+			InterruptedException {
+		if (fork == false || cancelable == false) {
+			// backward compatible code
+			final ProgressMonitorJobsDialog dialog = new ProgressMonitorJobsDialog(
+					null);
+			dialog.run(fork, cancelable, runnable);
+			return;
+		}
+
+		busyCursorWhile(runnable);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.eclipse.ui.progress.IProgressService#runInUI(org.eclipse.jface.operation.IRunnableWithProgress,
+	 *      org.eclipse.core.runtime.jobs.ISchedulingRule)
+	 */
+	public void runInUI(final IRunnableContext context,
+			final IRunnableWithProgress runnable, final ISchedulingRule rule)
+			throws InvocationTargetException, InterruptedException {
+		final RunnableWithStatus runnableWithStatus = new RunnableWithStatus(
+				context,
+				runnable, rule);
+		final Display display = Display.getDefault();
+		display.syncExec(new Runnable() {
+			public void run() {
+				BusyIndicator.showWhile(display, runnableWithStatus);
+			}
+
+		});
+
+		IStatus status = runnableWithStatus.getStatus();
+		if (!status.isOK()) {
+			Throwable exception = status.getException();
+			if (exception instanceof InvocationTargetException)
+				throw (InvocationTargetException) exception;
+			else if (exception instanceof InterruptedException)
+				throw (InterruptedException) exception;
+			else // should be OperationCanceledException
+				throw new InterruptedException(exception.getMessage());
+		}
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.eclipse.ui.progress.IProgressService#getLongOperationTime()
+	 */
+	public int getLongOperationTime() {
+		return 800;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.eclipse.ui.progress.IProgressService#registerIconForFamily(org.eclipse.jface.resource.ImageDescriptor,
+	 *      java.lang.Object)
+	 */
+	public void registerIconForFamily(ImageDescriptor icon, Object family) {
+		String key = IMAGE_KEY + String.valueOf(imageKeyTable.size());
+		imageKeyTable.put(family, key);
+		ImageRegistry registry = JFaceResources.getImageRegistry();
+
+		// Avoid registering twice
+		if (registry.getDescriptor(key) == null) {
+			registry.put(key, icon);
+		}
+
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.eclipse.ui.progress.IProgressService#getIconFor(org.eclipse.core.runtime.jobs.Job)
+	 */
+	public Image getIconFor(Job job) {
+		Enumeration families = imageKeyTable.keys();
+		while (families.hasMoreElements()) {
+			Object next = families.nextElement();
+			if (job.belongsTo(next)) {
+				return JFaceResources.getImageRegistry().get(
+						(String) imageKeyTable.get(next));
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Iterate through all of the windows and set them to be disabled or enabled
+	 * as appropriate.'
+	 * 
+	 * @param active
+	 *            The set the windows will be set to.
+	 */
+	private void setUserInterfaceActive(boolean active) {
+		IWorkbench workbench = PlatformUI.getWorkbench();
+		Shell[] shells = workbench.getDisplay().getShells();
+		if (active) {
+			for (int i = 0; i < shells.length; i++) {
+				if (!shells[i].isDisposed()) {
+					shells[i].setEnabled(active);
+				}
+			}
+		} else {
+			// Deactive shells in reverse order
+			for (int i = shells.length - 1; i >= 0; i--) {
+				if (!shells[i].isDisposed()) {
+					shells[i].setEnabled(active);
+				}
+			}
+		}
+	}
+
+	/**
+	 * Check to see if there are any stale jobs we have not cleared out.
+	 * 
+	 * @return <code>true</code> if anything was pruned
+	 */
+	private boolean pruneStaleJobs() {
+		Object[] jobsToCheck = jobs.keySet().toArray();
+		boolean pruned = false;
+		for (int i = 0; i < jobsToCheck.length; i++) {
+			Job job = (Job) jobsToCheck[i];
+			if (checkForStaleness(job)) {
+				if (Policy.DEBUG_STALE_JOBS) {
+					WorkbenchPlugin.log("Stale Job " + job.getName()); //$NON-NLS-1$
+				}
+				pruned = true;
+			}
+		}
+
+		return pruned;
+	}
+
+	/**
+	 * Check the if the job should be removed from the list as it may be stale.
+	 * 
+	 * @param job
+	 * @return boolean
+	 */
+	boolean checkForStaleness(Job job) {
+		if (job.getState() == Job.NONE) {
+			removeJobInfo(getJobInfo(job));
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Return whether or not dialogs should be run in the background
+	 * 
+	 * @return <code>true</code> if the dialog should not be shown.
+	 */
+	private boolean shouldRunInBackground() {
+		return WorkbenchPlugin.getDefault().getPreferenceStore().getBoolean(
+				IPreferenceConstants.RUN_IN_BACKGROUND);
+	}
+
+	/**
+	 * Set whether or not the ProgressViewUpdater should show system jobs.
+	 * 
+	 * @param showSystem
+	 */
+	public void setShowSystemJobs(boolean showSystem) {
+		ProgressViewUpdater updater = ProgressViewUpdater.getSingleton();
+		updater.debug = showSystem;
+		updater.refreshAll();
+
+	}
+
+	private class RunnableWithStatus implements Runnable {
+
+		IStatus status = Status.OK_STATUS;
+		private final IRunnableContext context;
+		private final IRunnableWithProgress runnable;
+		private final ISchedulingRule rule;
+
+		public RunnableWithStatus(IRunnableContext context,
+				IRunnableWithProgress runnable, ISchedulingRule rule) {
+			this.context = context;
+			this.runnable = runnable;
+			this.rule = rule;
+		}
+
+		public void run() {
+			IJobManager manager = Job.getJobManager();
+			try {
+				manager.beginRule(rule, getEventLoopMonitor());
+				context.run(false, false, runnable);
+			} catch (InvocationTargetException e) {
+				status = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, e
+						.getMessage(), e);
+			} catch (InterruptedException e) {
+				status = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, e
+						.getMessage(), e);
+			} catch (OperationCanceledException e) {
+				status = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, e
+						.getMessage(), e);
+			} finally {
+				manager.endRule(rule);
+			}
+		}
+
+		/**
+		 * Get a progress monitor that forwards to an event loop monitor.
+		 * Override #setBlocked() so that we always open the blocked dialog.
+		 * 
+		 * @return the monitor on the event loop
+		 */
+		private IProgressMonitor getEventLoopMonitor() {
+
+			if (PlatformUI.getWorkbench().isStarting())
+				return new NullProgressMonitor();
+
+			return new EventLoopProgressMonitor(new NullProgressMonitor()) {
+
+				public void setBlocked(IStatus reason) {
+
+					// Set a shell to open with as we want to create
+					// this
+					// even if there is a modal shell.
+					Dialog.getBlockedHandler().showBlocked(
+							ProgressManagerUtil.getDefaultParent(), this,
+							reason, getTaskName());
+				}
+			};
+		}
+		public IStatus getStatus() {
+			return status;
+		}
+
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressManagerUtil.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressManagerUtil.java
new file mode 100644
index 0000000..451e116
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressManagerUtil.java
@@ -0,0 +1,511 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 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.ui.internal.progress;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.QualifiedName;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.jface.window.IShellProvider;
+import org.eclipse.rap.rwt.internal.textsize.TextSizeUtil;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.WorkbenchWindow;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.internal.util.BundleUtility;
+import org.eclipse.ui.progress.IProgressConstants;
+import org.eclipse.ui.views.IViewDescriptor;
+
+/**
+ * The ProgressUtil is a class that contains static utility methods used for the
+ * progress API.
+ */
+
+public class ProgressManagerUtil {
+	/**
+	 * A constant used by the progress support to determine if an operation is
+	 * too short to show progress.
+	 */
+	public static long SHORT_OPERATION_TIME = 250;
+
+	static final QualifiedName KEEP_PROPERTY = IProgressConstants.KEEP_PROPERTY;
+
+	static final QualifiedName KEEPONE_PROPERTY = IProgressConstants.KEEPONE_PROPERTY;
+
+	static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
+
+	static final QualifiedName INFRASTRUCTURE_PROPERTY = new QualifiedName(
+			WorkbenchPlugin.PI_WORKBENCH, "INFRASTRUCTURE_PROPERTY");//$NON-NLS-1$
+
+// RAP [fappel]: session aware NLS
+//	private static String ellipsis = ProgressMessages.ProgressFloatingWindow_EllipsisValue;
+	// private static String ellipsis = ProgressMessages.get().ProgressFloatingWindow_EllipsisValue;
+    private static String getEllipsis() {
+      return ProgressMessages.get().ProgressFloatingWindow_EllipsisValue;
+    }
+
+	/**
+	 * Return a status for the exception.
+	 *
+	 * @param exception
+	 * @return IStatus
+	 */
+	static IStatus exceptionStatus(Throwable exception) {
+		return StatusUtil.newStatus(IStatus.ERROR,
+				exception.getMessage() == null ? "" : exception.getMessage(), //$NON-NLS-1$
+				exception);
+	}
+
+	/**
+	 * Log the exception for debugging.
+	 *
+	 * @param exception
+	 */
+	static void logException(Throwable exception) {
+		BundleUtility.log(PlatformUI.PLUGIN_ID, exception);
+	}
+
+	// /**
+	// * Sets the label provider for the viewer.
+	// *
+	// * @param viewer
+	// */
+	// static void initLabelProvider(ProgressTreeViewer viewer) {
+	// viewer.setLabelProvider(new ProgressLabelProvider());
+	// }
+	/**
+	 * Return a viewer comparator for looking at the jobs.
+	 *
+	 * @return ViewerComparator
+	 */
+	static ViewerComparator getProgressViewerComparator() {
+		return new ViewerComparator() {
+			/*
+			 * (non-Javadoc)
+			 *
+			 * @see org.eclipse.jface.viewers.ViewerComparator#compare(org.eclipse.jface.viewers.Viewer,
+			 *      java.lang.Object, java.lang.Object)
+			 */
+			@Override
+      public int compare(Viewer testViewer, Object e1, Object e2) {
+				return ((Comparable) e1).compareTo(e2);
+			}
+		};
+	}
+
+	/**
+	 * Open the progress view in the supplied window.
+	 *
+	 * @param window
+	 */
+	static void openProgressView(IWorkbenchWindow window) {
+		IWorkbenchPage page = window.getActivePage();
+		if (page == null) {
+			return;
+		}
+		try {
+			IViewDescriptor reference = WorkbenchPlugin.getDefault()
+					.getViewRegistry()
+					.find(IProgressConstants.PROGRESS_VIEW_ID);
+
+			if (reference == null) {
+				return;
+			}
+			page.showView(IProgressConstants.PROGRESS_VIEW_ID);
+		} catch (PartInitException exception) {
+			logException(exception);
+		}
+	}
+
+	/**
+	 * Shorten the given text <code>t</code> so that its length doesn't exceed
+	 * the given width. The default implementation replaces characters in the
+	 * center of the original string with an ellipsis ("..."). Override if you
+	 * need a different strategy.
+	 *
+	 * @param textValue
+	 * @param control
+	 * @return String
+	 */
+
+	static String shortenText(String textValue, Control control) {
+// RAP [fappel]: GC not supported
+//		if (textValue == null) {
+//			return null;
+//		}
+//		GC gc = new GC(control);
+//		int maxWidth = control.getBounds().width - 5;
+//		int maxExtent = gc.textExtent(textValue).x;
+//		if (maxExtent < maxWidth) {
+//			gc.dispose();
+//			return textValue;
+//		}
+//		int length = textValue.length();
+//		int charsToClip = Math.round(0.95f * length
+//				* (1 - ((float) maxWidth / maxExtent)));
+//		int secondWord = findSecondWhitespace(textValue, gc, maxWidth);
+//		int pivot = ((length - secondWord) / 2) + secondWord;
+//		int start = pivot - (charsToClip / 2);
+//		int end = pivot + (charsToClip / 2) + 1;
+//		while (start >= 0 && end < length) {
+//			String s1 = textValue.substring(0, start);
+//			String s2 = textValue.substring(end, length);
+//			String s = s1 + ellipsis + s2;
+//			int l = gc.textExtent(s).x;
+//			if (l < maxWidth) {
+//				gc.dispose();
+//				return s;
+//			}
+//			start--;
+//			end++;
+//		}
+//		gc.dispose();
+//		return textValue;
+	  if (textValue == null) {
+        return null;
+      }
+      int maxWidth = control.getBounds().width - 5;
+      Font font = control.getFont();
+      if (TextSizeUtil.textExtent(font, textValue, 0).x < maxWidth) {
+        return textValue;
+      }
+      int length = textValue.length();
+      int ellipsisWidth = TextSizeUtil.textExtent(font, getEllipsis(), 0).x;
+      // Find the second space seperator and start from there
+      int secondWord = findSecondWhitespace(textValue, font, maxWidth);
+      int pivot = ((length - secondWord) / 2) + secondWord;
+      int start = pivot;
+      int end = pivot + 1;
+      while (start >= secondWord && end < length) {
+        String s1 = textValue.substring(0, start);
+        String s2 = textValue.substring(end, length);
+        int l1 = TextSizeUtil.textExtent(font, s1, 0).x;
+        int l2 = TextSizeUtil.textExtent(font, s2, 0).x;
+        if (l1 + ellipsisWidth + l2 < maxWidth) {
+          return s1 + getEllipsis() + s2;
+        }
+        start--;
+        end++;
+      }
+      return textValue;
+	}
+
+// RAP [fappel]: GC not supported
+//	/**
+//	 * Find the second index of a whitespace. Return the first index if there
+//	 * isn't one or 0 if there is no space at all.
+//	 *
+//	 * @param textValue
+//	 * @param gc
+//	 *            The GC to test max length
+//	 * @param maxWidth
+//	 *            The maximim extent
+//	 * @return int
+//	 */
+//	private static int findSecondWhitespace(String textValue, GC gc,
+//	        int maxWidth) {
+    private static int findSecondWhitespace(String textValue, Font font,
+			int maxWidth) {
+		int firstCharacter = 0;
+		char[] chars = textValue.toCharArray();
+		// Find the first whitespace
+		for (int i = 0; i < chars.length; i++) {
+			if (Character.isWhitespace(chars[i])) {
+				firstCharacter = i;
+				break;
+			}
+		}
+		// If we didn't find it once don't continue
+		if (firstCharacter == 0) {
+			return 0;
+		}
+		// Initialize to firstCharacter in case there is no more whitespace
+		int secondCharacter = firstCharacter;
+		// Find the second whitespace
+		for (int i = firstCharacter; i < chars.length; i++) {
+			if (Character.isWhitespace(chars[i])) {
+				secondCharacter = i;
+				break;
+			}
+		}
+		// Check that we haven't gone over max width. Throw
+		// out an index that is too high
+// RAP [fappel]: GC not supported
+//		if (gc.textExtent(textValue.substring(0, secondCharacter)).x > maxWidth) {
+//			if (gc.textExtent(textValue.substring(0, firstCharacter)).x > maxWidth) {
+        if (TextSizeUtil.textExtent(font, textValue.substring(0, secondCharacter), 0).x > maxWidth) {
+          if (TextSizeUtil.textExtent(font, textValue.substring(0, firstCharacter), 0).x > maxWidth) {
+		      return 0;
+			}
+			return firstCharacter;
+		}
+		return secondCharacter;
+	}
+
+	/**
+	 * If there are any modal shells open reschedule openJob to wait until they
+	 * are closed. Return true if it rescheduled, false if there is nothing
+	 * blocking it.
+	 *
+	 * @param openJob
+	 * @return boolean. true if the job was rescheduled due to modal dialogs.
+	 */
+	public static boolean rescheduleIfModalShellOpen(Job openJob) {
+		Shell modal = getModalShellExcluding(null);
+		if (modal == null) {
+			return false;
+		}
+
+		// try again in a few seconds
+		openJob.schedule(PlatformUI.getWorkbench().getProgressService()
+				.getLongOperationTime());
+		return true;
+	}
+
+	/**
+	 * Return whether or not it is safe to open this dialog. If so then return
+	 * <code>true</code>. If not then set it to open itself when it has had
+	 * ProgressManager#longOperationTime worth of ticks.
+	 *
+	 * @param dialog
+	 *            ProgressMonitorJobsDialog that will be opening
+	 * @param excludedShell
+	 *            The shell
+	 * @return boolean. <code>true</code> if it can open. Otherwise return
+	 *         false and set the dialog to tick.
+	 */
+	public static boolean safeToOpen(ProgressMonitorJobsDialog dialog,
+			Shell excludedShell) {
+		Shell modal = getModalShellExcluding(excludedShell);
+		if (modal == null) {
+			return true;
+		}
+
+		dialog.watchTicks();
+		return false;
+	}
+
+	/**
+	 * Return the modal shell that is currently open. If there isn't one then
+	 * return null. If there are stacked modal shells, return the top one.
+	 *
+	 * @param shell
+	 *            A shell to exclude from the search. May be <code>null</code>.
+	 *
+	 * @return Shell or <code>null</code>.
+	 */
+
+	public static Shell getModalShellExcluding(Shell shell) {
+
+		// If shell is null or disposed, then look through all shells
+		if (shell == null || shell.isDisposed()) {
+			return getModalChildExcluding(PlatformUI.getWorkbench()
+					.getDisplay().getShells(), shell);
+		}
+
+		// Start with the shell to exclude and check it's shells
+		return getModalChildExcluding(shell.getShells(), shell);
+	}
+
+	/**
+	 * Return the modal shell that is currently open. If there isn't one then
+	 * return null.
+	 *
+	 * @param toSearch shells to search for modal children
+	 * @param toExclude shell to ignore
+	 * @return the most specific modal child, or null if none
+	 */
+	private static Shell getModalChildExcluding(Shell[] toSearch, Shell toExclude) {
+		int modal = SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL
+				| SWT.PRIMARY_MODAL;
+
+		// Make sure we don't pick a parent that has a modal child (this can
+		// lock the app)
+		// If we picked a parent with a modal child, use the modal child instead
+
+		for (int i = toSearch.length - 1; i >= 0; i--) {
+			Shell shell = toSearch[i];
+			if(shell.equals(toExclude)) {
+				continue;
+			}
+
+			// Check if this shell has a modal child
+			Shell[] children = shell.getShells();
+			Shell modalChild = getModalChildExcluding(children, toExclude);
+			if (modalChild != null) {
+				return modalChild;
+			}
+
+			// If not, check if this shell is modal itself
+			if (shell.isVisible() && (shell.getStyle() & modal) != 0) {
+				return shell;
+			}
+		}
+
+		return null;
+	}
+
+	/**
+	 * Utility method to get the best parenting possible for a dialog. If there
+	 * is a modal shell create it so as to avoid two modal dialogs. If not then
+	 * return the shell of the active workbench window. If neither can be found
+	 * return null.
+	 *
+	 * @return Shell or <code>null</code>
+	 */
+	public static Shell getDefaultParent() {
+		Shell modal = getModalShellExcluding(null);
+		if (modal != null) {
+			return modal;
+		}
+
+		return getNonModalShell();
+	}
+
+	/**
+	 * Get the active non modal shell. If there isn't one return null.
+	 *
+	 * @return Shell
+	 */
+	public static Shell getNonModalShell() {
+		IWorkbenchWindow window = PlatformUI.getWorkbench()
+				.getActiveWorkbenchWindow();
+		if (window == null) {
+			IWorkbenchWindow[] windows = PlatformUI.getWorkbench()
+					.getWorkbenchWindows();
+			if (windows.length > 0)
+				return windows[0].getShell();
+		} else
+			return window.getShell();
+
+		return null;
+	}
+
+	/**
+	 * Animate the closing of a window given the start position down to the
+	 * progress region.
+	 *
+	 * @param startPosition
+	 *            Rectangle. The position to start drawing from.
+	 */
+	public static void animateDown(Rectangle startPosition) {
+		IWorkbenchWindow currentWindow = PlatformUI.getWorkbench()
+				.getActiveWorkbenchWindow();
+		if (currentWindow == null) {
+			return;
+		}
+		WorkbenchWindow internalWindow = (WorkbenchWindow) currentWindow;
+
+		ProgressRegion progressRegion = internalWindow.getProgressRegion();
+		if (progressRegion == null) {
+			return;
+		}
+		Rectangle endPosition = progressRegion.getControl().getBounds();
+
+		Point windowLocation = internalWindow.getShell().getLocation();
+		endPosition.x += windowLocation.x;
+		endPosition.y += windowLocation.y;
+
+		// RAP [bm]: Animations
+//		AnimationEngine.createTweakedAnimation(internalWindow.getShell(), 400, startPosition, endPosition);
+		// RAPEND: [bm]
+
+	}
+
+	/**
+	 * Animate the opening of a window given the start position down to the
+	 * progress region.
+	 *
+	 * @param endPosition
+	 *            Rectangle. The position to end drawing at.
+	 */
+	public static void animateUp(Rectangle endPosition) {
+		IWorkbenchWindow currentWindow = PlatformUI.getWorkbench()
+				.getActiveWorkbenchWindow();
+		if (currentWindow == null) {
+			return;
+		}
+		WorkbenchWindow internalWindow = (WorkbenchWindow) currentWindow;
+		Point windowLocation = internalWindow.getShell().getLocation();
+
+		ProgressRegion progressRegion = internalWindow.getProgressRegion();
+		if (progressRegion == null) {
+			return;
+		}
+		Rectangle startPosition = progressRegion.getControl().getBounds();
+		startPosition.x += windowLocation.x;
+		startPosition.y += windowLocation.y;
+
+		// RAP [bm]:
+//		RectangleAnimation animation = new RectangleAnimation(internalWindow
+//				.getShell(), startPosition, endPosition);
+//		animation.schedule();
+		// RAPEND: [bm]
+
+	}
+
+	/**
+	 * Get the shell provider to use in the progress support dialogs. This
+	 * provider will try to always parent off of an existing modal shell. If
+	 * there isn't one it will use the current workbench window.
+	 *
+	 * @return IShellProvider
+	 */
+	static IShellProvider getShellProvider() {
+		return new IShellProvider() {
+
+			/*
+			 * (non-Javadoc)
+			 *
+			 * @see org.eclipse.jface.window.IShellProvider#getShell()
+			 */
+			public Shell getShell() {
+				return getDefaultParent();
+			}
+		};
+	}
+
+	/**
+	 * Get the icons root for the progress support.
+	 *
+	 * @return URL
+	 */
+	public static URL getIconsRoot() {
+		return BundleUtility.find(PlatformUI.PLUGIN_ID,
+				ProgressManager.PROGRESS_FOLDER);
+	}
+
+	/**
+	 * Return the location of the progress spinner.
+	 *
+	 * @return URL or <code>null</code> if it cannot be found
+	 */
+	public static URL getProgressSpinnerLocation() {
+		try {
+			return new URL(getIconsRoot(), "progress_spinner.gif");//$NON-NLS-1$
+		} catch (MalformedURLException e) {
+			return null;
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressMessages.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressMessages.java
new file mode 100644
index 0000000..cfd0233
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressMessages.java
@@ -0,0 +1,151 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2008 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 - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ui.internal.progress;
+
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.swt.widgets.Display;
+
+// RAP [fappel]: NLS needs to be session/request aware
+//public class ProgressMessages extends NLS{
+public class ProgressMessages {
+	private static final String BUNDLE_NAME = "org.eclipse.ui.internal.progress.messages";//$NON-NLS-1$
+
+//	public static String PendingUpdateAdapter_PendingLabel;
+//	public static String JobInfo_DoneMessage;
+//	public static String JobInfo_DoneNoProgressMessage;
+//	public static String JobInfo_NoTaskNameDoneMessage;
+//	public static String JobsViewPreferenceDialog_Note;
+//	public static String JobErrorDialog_CustomJobText;
+//	public static String JobInfo_UnknownProgress;
+//	public static String JobInfo_Waiting;
+//	public static String JobInfo_Sleeping;
+//	public static String JobInfo_System;
+//	public static String JobInfo_Cancelled;
+//	public static String JobInfo_Cancel_Requested;
+//	public static String JobInfo_Error;
+//	public static String JobInfo_Blocked;
+//	public static String JobInfo_Finished;
+//	public static String JobInfo_FinishedAt;
+//	public static String JobErrorDialog_CloseDialogMessage;
+//	public static String InternalError;
+//	public static String DeferredTreeContentManager_NotDeferred;
+//	public static String DeferredTreeContentManager_AddingChildren;
+//	public static String DeferredTreeContentManager_FetchingName;
+//	public static String ProgressView_CancelAction;
+//	public static String ProgressView_ClearAllAction;
+//	public static String ProgressView_NoOperations;
+//
+//	public static String NewProgressView_RemoveAllJobsToolTip;
+//	public static String NewProgressView_CancelJobToolTip;
+//	public static String NewProgressView_ClearJobToolTip;
+//	public static String NewProgressView_errorDialogTitle;
+//	public static String NewProgressView_errorDialogMessage;
+//	public static String ProgressAnimationItem_tasks;
+//	public static String ProgressAnimationItem_ok;
+//	public static String ProgressAnimationItem_error;
+//	public static String SubTaskInfo_UndefinedTaskName;
+//	public static String DeferredTreeContentManager_ClearJob;
+//	public static String ProgressContentProvider_UpdateProgressJob;
+//	public static String JobErrorDialog_MultipleErrorsTitle;
+//	public static String ProgressManager_openJobName;
+//	public static String ProgressManager_showInDialogName;
+//	public static String ProgressMonitorJobsDialog_DetailsTitle;
+//	public static String ProgressMonitorJobsDialog_HideTitle;
+//	public static String ErrorNotificationManager_OpenErrorDialogJob;
+//	public static String AnimationManager_AnimationStart;
+//	public static String ProgressFloatingWindow_EllipsisValue;
+//	public static String BlockedJobsDialog_UserInterfaceTreeElement;
+//	public static String BlockedJobsDialog_BlockedTitle;
+//	public static String WorkbenchSiteProgressService_CursorJob;
+//	public static String ProgressMonitorFocusJobDialog_UserDialogJob;
+//	public static String ProgressMonitorFocusJobDialog_CLoseDialogJob;
+//	public static String ProgressMonitorFocusJobDialog_RunInBackgroundButton;
+//
+//	public static String JobErrorDialog_MultipleErrorsMessage;
+//	public static String JobErrorDialog_CloseDialogTitle;
+//	public static String JobsViewPreferenceDialog_Title;
+//	public static String JobErrorDialog_DoNotShowAgainMessage;
+	public String PendingUpdateAdapter_PendingLabel;
+	public String JobInfo_DoneMessage;
+	public String JobInfo_DoneNoProgressMessage;
+	public String JobInfo_NoTaskNameDoneMessage;
+	public String JobsViewPreferenceDialog_Note;
+	public String JobErrorDialog_CustomJobText;
+	public String JobInfo_UnknownProgress;
+	public String JobInfo_Waiting;
+	public String JobInfo_Sleeping;
+	public String JobInfo_System;
+	public String JobInfo_Cancelled;
+	public String JobInfo_Cancel_Requested;
+	public String JobInfo_Error;
+	public String JobInfo_Blocked;
+	public String JobInfo_Finished;
+	public String JobInfo_FinishedAt;
+	public String JobErrorDialog_CloseDialogMessage;
+	public String InternalError;
+	public String DeferredTreeContentManager_NotDeferred;
+	public String DeferredTreeContentManager_AddingChildren;
+	public String DeferredTreeContentManager_FetchingName;
+	public String ProgressView_CancelAction;
+	public String ProgressView_ClearAllAction;
+	public String ProgressView_NoOperations;
+
+	public String NewProgressView_RemoveAllJobsToolTip;
+	public String NewProgressView_CancelJobToolTip;
+	public String NewProgressView_ClearJobToolTip;
+	public String NewProgressView_errorDialogTitle;
+	public String NewProgressView_errorDialogMessage;
+	public String ProgressAnimationItem_tasks;
+	public String ProgressAnimationItem_ok;
+	public String ProgressAnimationItem_error;
+	public String SubTaskInfo_UndefinedTaskName;
+	public String DeferredTreeContentManager_ClearJob;
+	public String ProgressContentProvider_UpdateProgressJob;
+	public String JobErrorDialog_MultipleErrorsTitle;
+	public String ProgressManager_openJobName;
+	public String ProgressManager_showInDialogName;
+	public String ProgressMonitorJobsDialog_DetailsTitle;
+	public String ProgressMonitorJobsDialog_HideTitle;
+	public String ErrorNotificationManager_OpenErrorDialogJob;
+	public String AnimationManager_AnimationStart;
+	public String ProgressFloatingWindow_EllipsisValue;
+	public String BlockedJobsDialog_UserInterfaceTreeElement;
+	public String BlockedJobsDialog_BlockedTitle;
+	public String WorkbenchSiteProgressService_CursorJob;
+	public String ProgressMonitorFocusJobDialog_UserDialogJob;
+	public String ProgressMonitorFocusJobDialog_CLoseDialogJob;
+	public String ProgressMonitorFocusJobDialog_RunInBackgroundButton;
+
+	public String JobErrorDialog_MultipleErrorsMessage;
+	public String JobErrorDialog_CloseDialogTitle;
+	public String JobsViewPreferenceDialog_Title;
+	public String JobErrorDialog_DoNotShowAgainMessage;
+
+//	static {
+//		// load message values from bundle file
+//		NLS.initializeMessages(BUNDLE_NAME, ProgressMessages.class);
+//	}
+
+    public static ProgressMessages get() {
+      return RWT.NLS.getISO8859_1Encoded( BUNDLE_NAME, ProgressMessages.class );
+    }
+
+    public static ProgressMessages get( Display display ) {
+      final ProgressMessages[] result = { null };
+      RWT.getUISession( display ).exec( new Runnable() {
+        public void run() {
+          result[ 0 ] = get();
+        }
+      } );
+      return result[ 0 ];
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressMonitorFocusJobDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressMonitorFocusJobDialog.java
new file mode 100644
index 0000000..259cbb5
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressMonitorFocusJobDialog.java
@@ -0,0 +1,372 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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 - Initial API and implementation
+ * Markus Schorn (Wind River Systems)
+ * Patrik Suzzi <psuzzi@gmail.com> - Bug 460683
+ *******************************************************************************/
+package org.eclipse.ui.internal.progress;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.IJobChangeEvent;
+import org.eclipse.core.runtime.jobs.IJobChangeListener;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.core.runtime.jobs.JobChangeAdapter;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.rap.rwt.internal.lifecycle.LifeCycleUtil;
+import org.eclipse.rap.rwt.internal.service.ContextProvider;
+import org.eclipse.rap.rwt.service.UISession;
+import org.eclipse.rap.rwt.service.UISessionEvent;
+import org.eclipse.rap.rwt.service.UISessionListener;
+import org.eclipse.rap.ui.internal.progress.JobCanceler;
+import org.eclipse.rap.ui.internal.progress.ProgressUtil;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+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.ui.PlatformUI;
+import org.eclipse.ui.internal.IPreferenceConstants;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.progress.IProgressConstants;
+import org.eclipse.ui.progress.WorkbenchJob;
+
+/**
+ * The ProgressMonitorFocusJobDialog is a dialog that shows progress for a
+ * particular job in a modal dialog so as to give a user accustomed to a modal
+ * UI a more familiar feel.
+ */
+public class ProgressMonitorFocusJobDialog extends ProgressMonitorJobsDialog {
+	Job job;
+	private boolean showDialog;
+
+	/**
+	 * Create a new instance of the receiver with progress reported on the job.
+	 *
+	 * @param parentShell
+	 *            The shell this is parented from.
+	 */
+	public ProgressMonitorFocusJobDialog(Shell parentShell) {
+		super(parentShell == null ? ProgressManagerUtil.getNonModalShell()
+				: parentShell);
+        // RAP [fappel]: fix this, switched to modal since we do not have
+        //               a client side window management system to keep
+        //               the dialog in front...
+//      setShellStyle(getDefaultOrientation() | SWT.BORDER | SWT.TITLE
+//              | SWT.RESIZE | SWT.MAX | SWT.MODELESS);
+		setCancelable(true);
+		enableDetailsButton = true;
+	}
+
+	@Override
+	protected void cancelPressed() {
+		job.cancel();
+		super.cancelPressed();
+	}
+
+	@Override
+	protected void configureShell(Shell shell) {
+		super.configureShell(shell);
+		shell.setText(job.getName());
+		shell.addTraverseListener(e -> {
+			if (e.detail == SWT.TRAVERSE_ESCAPE) {
+				cancelPressed();
+				e.detail = SWT.TRAVERSE_NONE;
+				e.doit = true;
+			}
+		});
+	}
+
+	@Override
+	protected void createButtonsForButtonBar(Composite parent) {
+		Button runInWorkspace = createButton(
+				parent,
+				IDialogConstants.CLOSE_ID,
+				ProgressMessages.get().ProgressMonitorFocusJobDialog_RunInBackgroundButton,
+				true);
+		runInWorkspace.addSelectionListener(new SelectionAdapter()
+        {
+		    /** {@inheritDoc} */
+		    @Override
+		    public void widgetSelected(SelectionEvent e)
+		    {
+		        Rectangle shellPosition = getShell().getBounds();
+		        job.setProperty(IProgressConstants.PROPERTY_IN_DIALOG, Boolean.FALSE);
+		        finishedRun();
+		        ProgressManagerUtil.animateDown(shellPosition);
+		    }
+		});
+		runInWorkspace.setCursor(arrowCursor);
+
+		cancel = createButton(parent, IDialogConstants.CANCEL_ID,
+				IDialogConstants.get().CANCEL_LABEL, false);
+		cancel.setCursor(arrowCursor);
+
+		createDetailsButton(parent);
+	}
+
+	/**
+	 * Returns a listener that will close the dialog when the job completes.
+	 *
+	 * @return IJobChangeListener
+	 */
+	private IJobChangeListener createCloseListener() {
+	    // RAP: Obtain localized message here as within the JobChangeAdapter#done
+	    //      method there is no session context available
+	    final String closeJobDialogMsg
+	      = ProgressMessages.get().ProgressMonitorFocusJobDialog_CLoseDialogJob;
+	      return new JobChangeAdapter() {
+	            /*
+	             * (non-Javadoc)
+	             *
+	             * @see org.eclipse.core.runtime.jobs.IJobChangeListener#done(org.eclipse.core.runtime.jobs.IJobChangeEvent)
+	             */
+	            public void done(IJobChangeEvent event) {
+	                // first of all, make sure this listener is removed
+	                event.getJob().removeJobChangeListener(this);
+	// RAP [fappel]: uses session aware approach
+//	              if (!PlatformUI.isWorkbenchRunning()) {
+//	                  return;
+//	              }
+	                Display display;
+	                if( getShell() == null ) {
+	                  if( !ContextProvider.hasContext() ) {
+	                    return;
+	                  }
+	                  display = LifeCycleUtil.getSessionDisplay();
+	                } else {
+	                  display = getShell().getDisplay();
+
+	                }
+	                if (!ProgressUtil.isWorkbenchRunning( display ) ) {
+	                    return;
+	                }
+
+	                // nothing to do if the dialog is already closed
+	                if (getShell() == null) {
+	                    return;
+	                }
+	                // RAP [fappel]: ensure mapping to context
+	                RWT.getUISession( display ).exec( new Runnable() {
+	                  public void run() {
+	                    final WorkbenchJob closeJob = new WorkbenchJob(closeJobDialogMsg) {
+	                        /*
+	                         * (non-Javadoc)
+	                         *
+	                         * @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor)
+	                         */
+	                        public IStatus runInUIThread(IProgressMonitor monitor) {
+	                            Shell currentShell = getShell();
+	                            if (currentShell == null || currentShell.isDisposed()) {
+	                                return Status.CANCEL_STATUS;
+	                            }
+	                            finishedRun();
+	                            return Status.OK_STATUS;
+	                        }
+	                    };
+	                    closeJob.setSystem(true);
+	                    closeJob.schedule();
+	                  }
+	                } );
+	            }
+	        };
+	    }
+
+	@Override
+	public int open() {
+        int result = super.open();
+
+        // add a listener that will close the dialog when the job completes.
+        final IJobChangeListener listener = createCloseListener();
+        job.addJobChangeListener(listener);
+        if (job.getState() == Job.NONE) {
+            // if the job completed before we had a chance to add
+            // the listener, just remove the listener and return
+            job.removeJobChangeListener(listener);
+            finishedRun();
+            cleanUpFinishedJob();
+        } else {
+          // RAP [fappel]: Ensure that job changed listener is removed in case
+          //               of session timeout before the job ends. Note that
+          //               this is still under investigation
+          final UISession uiSession = RWT.getUISession();
+          final AtomicReference<JobChangeAdapter> doneListener
+            = new AtomicReference<JobChangeAdapter>();
+          final AtomicBoolean isSessionAlive = new AtomicBoolean();
+          final UISessionListener cleanupListener = new UISessionListener() {
+            public void beforeDestroy( UISessionEvent event ) {
+              if( !isSessionAlive.get() ) {
+                job.removeJobChangeListener( listener );
+                job.removeJobChangeListener( doneListener.get() );
+                job.cancel();
+                job.addJobChangeListener( new JobCanceler() );
+              }
+            }
+          };
+          doneListener.set( new JobChangeAdapter() {
+            public void done( final IJobChangeEvent event ) {
+              job.removeJobChangeListener( this );
+              isSessionAlive.set( true );
+              uiSession.removeUISessionListener( cleanupListener );
+            }
+          } );
+          uiSession.addUISessionListener( cleanupListener );
+          job.addJobChangeListener( doneListener.get() );
+        }
+
+        return result;
+    }
+
+	/**
+	 * Opens this dialog for the duration that the given job is running.
+	 *
+	 * @param jobToWatch
+	 * @param originatingShell
+	 *            The shell this request was created from. Do not block on this
+	 *            shell.
+	 */
+	public void show(Job jobToWatch, final Shell originatingShell) {
+		job = jobToWatch;
+		// after the dialog is opened we can get access to its monitor
+		job.setProperty(IProgressConstants.PROPERTY_IN_DIALOG, Boolean.TRUE);
+
+		setOpenOnRun(false);
+		aboutToRun();
+
+		final Object jobIsDone = new Object();
+		final JobChangeAdapter jobListener = new JobChangeAdapter() {
+			@Override
+			public void done(IJobChangeEvent event) {
+				synchronized (jobIsDone) {
+					jobIsDone.notify();
+				}
+			}
+		};
+		job.addJobChangeListener(jobListener);
+
+		// start with a quick busy indicator. Lock the UI as we
+		// want to preserve modality
+		BusyIndicator.showWhile(PlatformUI.getWorkbench().getDisplay(),
+				() -> {
+					try {
+						synchronized (jobIsDone) {
+							if (job.getState() != Job.NONE) {
+								jobIsDone.wait(ProgressManagerUtil.SHORT_OPERATION_TIME);
+							}
+						}
+					} catch (InterruptedException e) {
+						// Do not log as this is a common operation from the
+						// lock listener
+					}
+				});
+		job.removeJobChangeListener(jobListener);
+
+		WorkbenchJob openJob = new WorkbenchJob(
+				ProgressMessages.get().ProgressMonitorFocusJobDialog_UserDialogJob) {
+			@Override
+			public IStatus runInUIThread(IProgressMonitor monitor) {
+
+				// if the job is done at this point, we don't need the dialog
+				if (job.getState() == Job.NONE) {
+					finishedRun();
+					cleanUpFinishedJob();
+					return Status.CANCEL_STATUS;
+				}
+
+				// now open the progress dialog if nothing else is
+				if (!ProgressManagerUtil.safeToOpen(
+						ProgressMonitorFocusJobDialog.this, originatingShell)) {
+					return Status.CANCEL_STATUS;
+				}
+
+				// Do not bother if the parent is disposed
+				if (getParentShell() != null && getParentShell().isDisposed()) {
+					return Status.CANCEL_STATUS;
+				}
+
+				// RAP [DM] no ProgressMonitorUtil
+//				JobMonitor jobMonitor = ProgressManager.getInstance().progressFor(job);
+//				Display d = Display.getCurrent();
+//				IProgressMonitorWithBlocking wrapper = ProgressMonitorUtil
+//						.createAccumulatingProgressMonitor(getProgressMonitor(), d);
+//				jobMonitor.addProgressListener(wrapper);
+//				open();
+
+				return Status.OK_STATUS;
+			}
+		};
+		openJob.setSystem(true);
+		openJob.schedule();
+
+	}
+
+	/**
+	 * The job finished before we did anything so clean up the finished
+	 * reference.
+	 */
+	private void cleanUpFinishedJob() {
+		ProgressManager.getInstance().checkForStaleness(job);
+	}
+
+	@Override
+	protected Control createDialogArea(Composite parent) {
+		Control area = super.createDialogArea(parent);
+		// Give the job info as the initial details
+		getProgressMonitor().setTaskName(
+				ProgressManager.getInstance().getJobInfo(this.job)
+                        .getDisplayString());
+		return area;
+	}
+
+	@Override
+	protected void createExtendedDialogArea(Composite parent) {
+
+		showDialog = WorkbenchPlugin.getDefault().getPreferenceStore()
+				.getBoolean(IPreferenceConstants.RUN_IN_BACKGROUND);
+		final Button showUserDialogButton = new Button(parent, SWT.CHECK);
+		showUserDialogButton
+				.setText(WorkbenchMessages.get().WorkbenchPreference_RunInBackgroundButton);
+		showUserDialogButton
+				.setToolTipText(WorkbenchMessages.get().WorkbenchPreference_RunInBackgroundToolTip);
+		GridData gd = new GridData();
+		gd.horizontalSpan = 2;
+		gd.horizontalAlignment = GridData.FILL;
+		showUserDialogButton.setLayoutData(gd);
+
+		showUserDialogButton.addSelectionListener(new SelectionAdapter()
+        {
+		    public void widgetSelected(SelectionEvent e) {
+		        showDialog = showUserDialogButton.getSelection();
+		    }
+        });
+
+		super.createExtendedDialogArea(parent);
+	}
+
+	@Override
+	public boolean close() {
+		if (getReturnCode() != CANCEL)
+			WorkbenchPlugin.getDefault().getPreferenceStore().setValue(
+					IPreferenceConstants.RUN_IN_BACKGROUND, showDialog);
+
+		return super.close();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressMonitorJobsDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressMonitorJobsDialog.java
new file mode 100644
index 0000000..b1c2ea7
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressMonitorJobsDialog.java
@@ -0,0 +1,422 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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 - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ui.internal.progress;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IProgressMonitorWithBlocking;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.ProgressMonitorDialog;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.rap.ui.internal.progress.ProgressUtil;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Cursor;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.internal.misc.Policy;
+
+/**
+ * The ProgressMonitorJobsDialog is the progress monitor dialog used by the
+ * progress service to allow locks to show the current jobs.
+ */
+public class ProgressMonitorJobsDialog extends ProgressMonitorDialog {
+    private DetailedProgressViewer viewer;
+
+    /**
+     * The height of the viewer. Set when the details button is selected.
+     */
+    private int viewerHeight = -1;
+
+    Composite viewerComposite;
+
+    private Button detailsButton;
+
+    private long watchTime = -1;
+
+    protected boolean alreadyClosed = false;
+
+    private IProgressMonitor wrapperedMonitor;
+
+    //Cache initial enablement in case the enablement state is set
+    //before the button is created
+    protected boolean enableDetailsButton = false;
+
+    /**
+     * Create a new instance of the receiver.
+     *
+     * @param parent
+     */
+    public ProgressMonitorJobsDialog(Shell parent) {
+        super(parent);
+    }
+
+    @Override
+	protected Control createDialogArea(Composite parent) {
+        Composite top = (Composite) super.createDialogArea(parent);
+        createExtendedDialogArea(parent);
+        return top;
+    }
+
+	/**
+	 * Create the extensions to the dialog area.
+	 * @param parent
+	 */
+	protected void createExtendedDialogArea(Composite parent) {
+		viewerComposite = new Composite(parent, SWT.NONE);
+        GridLayout layout = new GridLayout();
+        layout.marginHeight = 0;
+        layout.marginWidth = 0;
+        viewerComposite.setLayout(layout);
+        GridData viewerData = new GridData(GridData.FILL_BOTH);
+        viewerData.horizontalSpan = 2;
+        viewerData.heightHint = 0;
+        viewerComposite.setLayoutData(viewerData);
+	}
+
+    /**
+     * The details button has been selected. Open or close the progress viewer
+     * as appropriate.
+     *
+     */
+    void handleDetailsButtonSelect() {
+        Shell shell = getShell();
+        Point shellSize = shell.getSize();
+        Composite composite = (Composite) getDialogArea();
+        if (viewer != null) {
+            viewer.getControl().dispose();
+            viewer = null;
+            composite.layout();
+            shell.setSize(shellSize.x, shellSize.y - viewerHeight);
+            detailsButton.setText(ProgressMessages.get().ProgressMonitorJobsDialog_DetailsTitle);
+        } else {
+            //Abort if there are no jobs visible
+            if (ProgressManager.getInstance().getRootElements(Policy.DEBUG_SHOW_ALL_JOBS).length == 0) {
+                detailsButton.setEnabled(false);
+                return;
+            }
+
+            viewer = new DetailedProgressViewer(viewerComposite, SWT.MULTI
+                    | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
+            viewer.setComparator(new ViewerComparator() {
+                @Override
+				public int compare(Viewer testViewer, Object e1, Object e2) {
+                    return ((Comparable) e1).compareTo(e2);
+                }
+            });
+
+            viewer.setContentProvider(new ProgressViewerContentProvider(viewer,true,false){
+            	@Override
+				public Object[] getElements(Object inputElement) {
+            		return super.getElements(inputElement);
+            	}}
+            );
+
+            viewer.setLabelProvider(new ProgressLabelProvider());
+            viewer.setInput(this);
+            GridData viewerData = new GridData(GridData.FILL_BOTH);
+            viewer.getControl().setLayoutData(viewerData);
+            GridData viewerCompositeData = (GridData) viewerComposite.getLayoutData();
+            viewerCompositeData.heightHint = convertHeightInCharsToPixels(10);
+            viewerComposite.layout(true);
+            viewer.getControl().setVisible(true);
+            viewerHeight = viewerComposite.computeTrim(0, 0, 0, viewerCompositeData.heightHint).height;
+            detailsButton.setText(ProgressMessages.get().ProgressMonitorJobsDialog_HideTitle);
+            shell.setSize(shellSize.x, shellSize.y + viewerHeight);
+        }
+    }
+
+    @Override
+	protected void createButtonsForButtonBar(Composite parent) {
+        super.createButtonsForButtonBar(parent);
+        createDetailsButton(parent);
+    }
+
+    /**
+     * Create a spacer label to get the layout to not bunch the widgets.
+     *
+     * @param parent
+     *            The parent of the new button.
+     */
+    protected void createSpacer(Composite parent) {
+        //Make a label to force the spacing
+        Label spacer = new Label(parent, SWT.NONE);
+        spacer.setLayoutData(new GridData(GridData.FILL_HORIZONTAL
+                | GridData.GRAB_HORIZONTAL));
+    }
+
+    /**
+     * Create the details button for the receiver.
+     *
+     * @param parent
+     *            The parent of the new button.
+     */
+    protected void createDetailsButton(Composite parent) {
+        detailsButton = createButton(parent, IDialogConstants.DETAILS_ID,
+                ProgressMessages.get().ProgressMonitorJobsDialog_DetailsTitle,
+                false);
+        detailsButton.addSelectionListener(new SelectionAdapter()
+        {
+            /** {@inheritDoc} */
+            @Override
+            public void widgetSelected(SelectionEvent e)
+            {
+                handleDetailsButtonSelect();
+            }
+        });
+        detailsButton.setCursor(arrowCursor);
+        detailsButton.setEnabled(enableDetailsButton);
+    }
+
+    @Override
+	protected Control createButtonBar(Composite parent) {
+        Composite composite = new Composite(parent, SWT.NONE);
+        // create a layout with spacing and margins appropriate for the font
+        // size.
+        GridLayout layout = new GridLayout();
+        layout.numColumns = 1; // this is incremented by createButton
+        layout.makeColumnsEqualWidth = false;
+        layout.marginWidth = 0;
+        layout.marginHeight = 0;
+        layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
+        layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
+        composite.setLayout(layout);
+        GridData data = new GridData(GridData.FILL_HORIZONTAL);
+        data.horizontalSpan = 2;
+        data.horizontalAlignment = GridData.END;
+        data.grabExcessHorizontalSpace = true;
+        composite.setLayoutData(data);
+        composite.setFont(parent.getFont());
+        // Add the buttons to the button bar.
+        if (arrowCursor == null) {
+			arrowCursor = new Cursor(parent.getDisplay(), SWT.CURSOR_ARROW);
+		}
+        createButtonsForButtonBar(composite);
+        return composite;
+    }
+
+    @Override
+	protected void clearCursors() {
+        if (detailsButton != null && !detailsButton.isDisposed()) {
+            detailsButton.setCursor(null);
+        }
+        super.clearCursors();
+    }
+
+    @Override
+	protected void updateForSetBlocked(IStatus reason) {
+    	if(alreadyClosed)
+    		return;
+
+        super.updateForSetBlocked(reason);
+        enableDetails(true);
+        if (viewer == null) {
+			handleDetailsButtonSelect();
+		}
+    }
+
+    @Override
+	public void run(boolean fork, boolean cancelable,
+            IRunnableWithProgress runnable) throws InvocationTargetException,
+            InterruptedException {
+        //if it is run in the UI Thread don't do anything.
+        if (!fork) {
+            enableDetails(false);
+        }
+        super.run(fork, cancelable, runnable);
+    }
+
+    /**
+     * Set the enable state of the details button now or when it will be
+     * created.
+     *
+     * @param enableState
+     *            a boolean to indicate the preferred' state
+     */
+    protected void enableDetails(boolean enableState) {
+        if (detailsButton == null) {
+			enableDetailsButton = enableState;
+		} else {
+			detailsButton.setEnabled(enableState);
+		}
+    }
+
+    /**
+     * Start watching the ticks. When the long operation time has
+     * passed open the dialog.
+     */
+    public void watchTicks() {
+        watchTime = System.currentTimeMillis();
+    }
+
+    /**
+     * Create a monitor for the receiver that wrappers the superclasses monitor.
+     *
+     */
+    public void createWrapperedMonitor() {
+        wrapperedMonitor = new IProgressMonitorWithBlocking() {
+
+            IProgressMonitor superMonitor = ProgressMonitorJobsDialog.super
+                    .getProgressMonitor();
+
+            @Override
+			public void beginTask(String name, int totalWork) {
+                superMonitor.beginTask(name, totalWork);
+                checkTicking();
+            }
+
+            /**
+             * Check if we have ticked in the last 800ms.
+             */
+            private void checkTicking() {
+                if (watchTime < 0) {
+					return;
+				}
+                if ((System.currentTimeMillis() - watchTime) > ProgressManager
+                        .getInstance().getLongOperationTime()) {
+                    watchTime = -1;
+                    openDialog();
+                }
+            }
+
+            /**
+             * Open the dialog in the ui Thread
+             */
+            private void openDialog() {
+// RAP [fappel]: use session aware approach
+//                if (!PlatformUI.isWorkbenchRunning()) {
+//                  return;
+//              }
+//
+//                PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {
+                Display display = getShell().getDisplay();
+                if (!ProgressUtil.isWorkbenchRunning( display )) {
+                    return;
+                }
+
+                display.syncExec(new Runnable() {                    /* (non-Javadoc)
+                     * @see java.lang.Runnable#run()
+                     */
+                    public void run() {
+                        //Reset the watch if it is not safe to open
+                         if (!ProgressManagerUtil.safeToOpen(ProgressMonitorJobsDialog.this,null)){
+                              watchTicks();
+                              return;
+                         }
+
+                        if (!alreadyClosed) {
+                            open();
+                        }
+                    }
+                });
+            }
+
+            @Override
+			public void done() {
+                superMonitor.done();
+                checkTicking();
+            }
+
+            @Override
+			public void internalWorked(double work) {
+                superMonitor.internalWorked(work);
+                checkTicking();
+            }
+
+            @Override
+			public boolean isCanceled() {
+                return superMonitor.isCanceled();
+            }
+
+            @Override
+			public void setCanceled(boolean value) {
+                superMonitor.setCanceled(value);
+
+            }
+
+            @Override
+			public void setTaskName(String name) {
+                superMonitor.setTaskName(name);
+                checkTicking();
+
+            }
+
+            @Override
+			public void subTask(String name) {
+                superMonitor.subTask(name);
+                checkTicking();
+            }
+
+            @Override
+			public void worked(int work) {
+                superMonitor.worked(work);
+                checkTicking();
+
+            }
+
+            @Override
+			public void clearBlocked() {
+                //We want to open on blocking too
+                if (superMonitor instanceof IProgressMonitorWithBlocking) {
+					((IProgressMonitorWithBlocking) superMonitor)
+                            .clearBlocked();
+				}
+
+            }
+
+            @Override
+			public void setBlocked(IStatus reason) {
+                openDialog();
+                if (superMonitor instanceof IProgressMonitorWithBlocking) {
+					((IProgressMonitorWithBlocking) superMonitor)
+                            .setBlocked(reason);
+				}
+
+            }
+
+        };
+    }
+
+    @Override
+	public IProgressMonitor getProgressMonitor() {
+        if (wrapperedMonitor == null) {
+			createWrapperedMonitor();
+		}
+        return wrapperedMonitor;
+    }
+
+    @Override
+	public boolean close() {
+        alreadyClosed = true;//As this sometimes delayed cache if it was already closed
+        boolean result = super.close();
+        if (!result) {//If it fails reset the flag
+            alreadyClosed = false;
+        }
+        return result;
+    }
+
+    @Override
+	protected boolean isResizable() {
+    	return true;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressRegion.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressRegion.java
new file mode 100644
index 0000000..b1030bc
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressRegion.java
@@ -0,0 +1,227 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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 - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ui.internal.progress;
+
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.e4.ui.model.application.ui.MElementContainer;
+import org.eclipse.e4.ui.model.application.ui.SideValue;
+import org.eclipse.e4.ui.model.application.ui.basic.MTrimBar;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolControl;
+import org.eclipse.jface.viewers.IContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.internal.TrimUtil;
+import org.eclipse.ui.internal.WorkbenchWindow;
+
+/**
+ * The ProgressRegion is class for the region of the workbench where the
+ * progress line and the animation item are shown.
+ */
+public class ProgressRegion {
+	@Inject
+	MToolControl toolControl;
+
+	@Inject
+	IWorkbenchWindow workbenchWindow;
+
+    ProgressCanvasViewer viewer;
+
+    ProgressAnimationItem animationItem;
+
+    Composite region;
+
+	/**
+	 * the side the receiver is placed on
+	 */
+	private SideValue getLocation() {
+		if (toolControl == null) {
+			// if we don't have a ToolControl, assume bottom
+			return SideValue.BOTTOM;
+		}
+		MElementContainer<?> parent = toolControl.getParent();
+		while (parent != null) {
+			if (parent instanceof MTrimBar) {
+				return ((MTrimBar) parent).getSide();
+			}
+			parent = parent.getParent();
+		}
+		return SideValue.BOTTOM;
+	}
+
+	private boolean forceHorizontal;
+
+    /**
+     * Create the contents of the receiver in the parent. Use the window for the
+     * animation item.
+     *
+     * @param parent
+     *            The parent widget of the composite.
+     * @param workbenchWindow
+     *            The WorkbenchWindow this is in.
+     * @return Control
+     */
+	@PostConstruct
+	public Control createContents(Composite parent) {
+        // Test whether or not 'advanced' graphics are available
+        // If not then we'll 'force' the ProgressBar to always be
+        // HORIZONTAL...
+        //TODO: This should likely be at some 'global' level state
+        GC gc = new GC(parent);
+        gc.setAdvanced(true);
+        forceHorizontal = !gc.getAdvanced();
+        gc.dispose();
+
+        region = new Composite(parent, SWT.NONE) {
+			@Override
+			public Point computeSize(int wHint, int hHint, boolean changed) {
+				Point size = super.computeSize(wHint, hHint, changed);
+				if (isHorizontal())
+					size.y = TrimUtil.TRIM_DEFAULT_HEIGHT;
+				else {
+					size.x = TrimUtil.TRIM_DEFAULT_HEIGHT;
+				}
+				return size;
+			}
+		};
+
+        GridLayout gl = new GridLayout();
+        gl.marginHeight = 0;
+        gl.marginWidth = 0;
+		if (isHorizontal())
+        	gl.numColumns = 3;
+        region.setLayout(gl);
+
+		viewer = new ProgressCanvasViewer(region, SWT.NO_FOCUS, 1, 36, isHorizontal() ? SWT.HORIZONTAL : SWT.VERTICAL);
+        viewer.setUseHashlookup(true);
+        Control viewerControl = viewer.getControl();
+        GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
+        Point viewerSizeHints = viewer.getSizeHints();
+		if (isHorizontal()) {
+        	gd.widthHint = viewerSizeHints.x;
+        	gd.heightHint = viewerSizeHints.y;
+        } else {
+        	gd.widthHint = viewerSizeHints.y;
+        	gd.heightHint = viewerSizeHints.x;
+        }
+        viewerControl.setLayoutData(gd);
+
+        int widthPreference = AnimationManager.getInstance()
+                .getPreferredWidth() + 25;
+		animationItem = new ProgressAnimationItem(this, isHorizontal() ? SWT.HORIZONTAL : SWT.VERTICAL);
+        animationItem.createControl(region);
+
+        animationItem.setAnimationContainer(new AnimationItem.IAnimationContainer() {
+            @Override
+			public void animationDone() {
+                //Add an extra refresh to the viewer in case
+                //of stale input if the controls are not disposed
+                if (viewer.getControl().isDisposed()) {
+					return;
+				}
+                viewer.refresh();
+            }
+
+            @Override
+			public void animationStart() {
+                // Nothing by default here.
+
+            }
+        });
+		if (isHorizontal()) {
+        	gd = new GridData(GridData.FILL_VERTICAL);
+            gd.widthHint = widthPreference;
+        } else {
+        	gd = new GridData(GridData.FILL_HORIZONTAL);
+            gd.heightHint = widthPreference;
+        }
+
+        animationItem.getControl().setLayoutData(gd);
+
+        viewerControl.addMouseListener(new MouseAdapter() {
+            @Override
+			public void mouseDoubleClick(MouseEvent e) {
+                processDoubleClick();
+            }
+        });
+
+        //Never show debug info
+        IContentProvider provider = new ProgressViewerContentProvider(viewer,
+                false,false);
+        viewer.setContentProvider(provider);
+        viewer.setInput(provider);
+        viewer.setLabelProvider(new ProgressViewerLabelProvider(viewerControl));
+        viewer.setComparator(ProgressManagerUtil.getProgressViewerComparator());
+        viewer.addFilter(new ViewerFilter() {
+            @Override
+			public boolean select(Viewer viewer, Object parentElement, Object element) {
+                if (element instanceof JobInfo) {
+                    JobInfo info= (JobInfo)element;
+                    if (info.isBlocked() || info.getJob().getState() == Job.WAITING) {
+                    	return false;
+                    }
+                }
+                return true;
+            }
+
+		});
+        return region;
+    }
+
+    /**
+     * Return the animationItem for the receiver.
+     *
+     * @return AnimationItem
+     */
+    public AnimationItem getAnimationItem() {
+        return animationItem;
+    }
+
+    /**
+     * Return the control for the receiver.
+     *
+     * @return Control
+     */
+	public Control getControl() {
+        return region;
+    }
+
+    /**
+     * Process the double click event.
+     */
+    public void processDoubleClick() {
+		ProgressManagerUtil.openProgressView(workbenchWindow);
+    }
+
+	/**
+	 * Answer true if the side is a horizonal one
+	 *
+	 * @param dropSide
+	 * @return <code>true</code> if the side is horizontal
+	 */
+	private boolean isHorizontal() {
+		if (forceHorizontal)
+			return true;
+		SideValue loc = getLocation();
+		return loc == SideValue.TOP || loc == SideValue.BOTTOM;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressView.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressView.java
new file mode 100644
index 0000000..4c383fe
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressView.java
@@ -0,0 +1,205 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 422040
+ *******************************************************************************/
+package org.eclipse.ui.internal.progress;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IWorkbenchActionConstants;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.part.ViewPart;
+import org.eclipse.ui.preferences.ViewPreferencesAction;
+
+/**
+ * The ProgressView is the class that shows the details of the current workbench
+ * progress.
+ */
+public class ProgressView extends ViewPart {
+
+	DetailedProgressViewer viewer;
+
+	Action cancelAction;
+
+	Action clearAllAction;
+
+
+	@Override
+	public void createPartControl(Composite parent) {
+		viewer = new DetailedProgressViewer(parent, SWT.MULTI | SWT.H_SCROLL);
+		viewer.setComparator(ProgressManagerUtil.getProgressViewerComparator());
+
+// RAP [fappel]: seems to be a bug in original workbench, parent has no gridlayout
+// TODO: file bug
+//	    viewer.getControl().setLayoutData(
+//	            new GridData(SWT.FILL, SWT.FILL, true, true));
+
+		PlatformUI.getWorkbench().getHelpSystem().setHelp(parent,
+				IWorkbenchHelpContextIds.RESPONSIVE_UI);
+
+		initContentProvider();
+		createClearAllAction();
+		createCancelAction();
+		initContextMenu();
+		initPulldownMenu();
+		initToolBar();
+		getSite().setSelectionProvider(viewer);
+	}
+
+	@Override
+	public void setFocus() {
+		if (viewer != null) {
+			viewer.setFocus();
+		}
+	}
+
+	/**
+	 * Sets the content provider for the viewer.
+	 */
+	protected void initContentProvider() {
+		ProgressViewerContentProvider provider = new ProgressViewerContentProvider(viewer, true ,true);
+		viewer.setContentProvider(provider);
+		viewer.setInput(ProgressManager.getInstance());
+	}
+
+	/**
+	 * Initialize the context menu for the receiver.
+	 */
+	private void initContextMenu() {
+		MenuManager menuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$
+		Menu menu = menuMgr.createContextMenu(viewer.getControl());
+		menuMgr.add(cancelAction);
+		menuMgr.addMenuListener(manager -> {
+			JobInfo info = getSelectedInfo();
+			if (info == null) {
+				return;
+			}
+		});
+		menuMgr.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
+		getSite().registerContextMenu(menuMgr, viewer);
+		viewer.getControl().setMenu(menu);
+	}
+
+	private void initPulldownMenu() {
+		IMenuManager menuMgr = getViewSite().getActionBars().getMenuManager();
+		menuMgr.add(clearAllAction);
+		menuMgr.add(new ViewPreferencesAction() {
+			@Override
+			public void openViewPreferencesDialog() {
+				new JobsViewPreferenceDialog(viewer.getControl().getShell())
+						.open();
+
+			}
+		});
+
+	}
+
+	private void initToolBar() {
+		IActionBars bars = getViewSite().getActionBars();
+		IToolBarManager tm = bars.getToolBarManager();
+		tm.add(clearAllAction);
+	}
+
+	/**
+	 * Return the selected objects. If any of the selections are not JobInfos or
+	 * there is no selection then return null.
+	 *
+	 * @return JobInfo[] or <code>null</code>.
+	 */
+	private IStructuredSelection getSelection() {
+		// If the provider has not been set yet move on.
+		ISelectionProvider provider = getSite().getSelectionProvider();
+		if (provider == null) {
+			return null;
+		}
+		ISelection currentSelection = provider.getSelection();
+		if (currentSelection instanceof IStructuredSelection) {
+			return (IStructuredSelection) currentSelection;
+		}
+		return null;
+	}
+
+	/**
+	 * Get the currently selected job info. Only return it if it is the only
+	 * item selected and it is a JobInfo.
+	 *
+	 * @return JobInfo
+	 */
+	JobInfo getSelectedInfo() {
+		IStructuredSelection selection = getSelection();
+		if (selection != null && selection.size() == 1) {
+			JobTreeElement element = (JobTreeElement) selection
+					.getFirstElement();
+			if (element.isJobInfo()) {
+				return (JobInfo) element;
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Create the cancel action for the receiver.
+	 */
+	private void createCancelAction() {
+		cancelAction = new Action(ProgressMessages.get().ProgressView_CancelAction) {
+			@Override
+			public void run() {
+				viewer.cancelSelection();
+			}
+		};
+
+	}
+
+	/**
+	 * Create the clear all action for the receiver.
+	 */
+	private void createClearAllAction() {
+		clearAllAction = new Action(
+				ProgressMessages.get().ProgressView_ClearAllAction) {
+			@Override
+			public void run() {
+				FinishedJobs.getInstance().clearAll();
+			}
+		};
+		clearAllAction
+				.setToolTipText(ProgressMessages.get().NewProgressView_RemoveAllJobsToolTip);
+		ImageDescriptor id = WorkbenchImages
+				.getWorkbenchImageDescriptor("/elcl16/progress_remall.png"); //$NON-NLS-1$
+		if (id != null) {
+			clearAllAction.setImageDescriptor(id);
+		}
+		id = WorkbenchImages
+				.getWorkbenchImageDescriptor("/dlcl16/progress_remall.png"); //$NON-NLS-1$
+		if (id != null) {
+			clearAllAction.setDisabledImageDescriptor(id);
+		}
+	}
+
+	/**
+	 * @return Returns the viewer.
+	 */
+	public DetailedProgressViewer getViewer() {
+		return viewer;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressViewUpdater.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressViewUpdater.java
new file mode 100644
index 0000000..97a7db1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressViewUpdater.java
@@ -0,0 +1,345 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.internal.progress;
+
+import java.time.Duration;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import org.eclipse.ui.IWorkbenchPreferenceConstants;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.util.PrefUtil;
+
+/**
+ * The ProgressViewUpdater is the singleton that updates viewers.
+ */
+class ProgressViewUpdater implements IJobProgressManagerListener {
+
+    private static ProgressViewUpdater singleton;
+
+    private IProgressUpdateCollector[] collectors;
+
+    UpdatesInfo currentInfo = new UpdatesInfo();
+
+    boolean debug;
+
+	Throttler throttledUpdate = new Throttler(PlatformUI.getWorkbench().getDisplay(), Duration.ofMillis(100),
+			this::update);
+
+    /**
+     * The UpdatesInfo is a private class for keeping track of the updates
+     * required.
+     */
+    class UpdatesInfo {
+
+        Collection additions = new HashSet();
+
+        Collection deletions = new HashSet();
+
+        Collection refreshes = new HashSet();
+
+        boolean updateAll = false;
+
+        private UpdatesInfo() {
+            //Create a new instance of the info
+        }
+
+        /**
+         * Add an add update
+         *
+         * @param addition
+         */
+        void add(JobTreeElement addition) {
+            additions.add(addition);
+        }
+
+        /**
+         * Add a remove update
+         *
+         * @param removal
+         */
+        void remove(JobTreeElement removal) {
+            deletions.add(removal);
+        }
+
+        /**
+         * Add a refresh update
+         *
+         * @param refresh
+         */
+        void refresh(JobTreeElement refresh) {
+            refreshes.add(refresh);
+        }
+
+        /**
+         * Reset the caches after completion of an update.
+         */
+        void reset() {
+            additions.clear();
+            deletions.clear();
+            refreshes.clear();
+            updateAll = false;
+        }
+
+        void processForUpdate() {
+            HashSet staleAdditions = new HashSet();
+
+            Iterator additionsIterator = additions.iterator();
+            while (additionsIterator.hasNext()) {
+                JobTreeElement treeElement = (JobTreeElement) additionsIterator
+                        .next();
+                if (!treeElement.isActive()) {
+                    if (deletions.contains(treeElement)) {
+						staleAdditions.add(treeElement);
+					}
+                }
+            }
+
+            additions.removeAll(staleAdditions);
+
+            HashSet obsoleteRefresh = new HashSet();
+            Iterator refreshIterator = refreshes.iterator();
+            while (refreshIterator.hasNext()) {
+                JobTreeElement treeElement = (JobTreeElement) refreshIterator
+                        .next();
+                if (deletions.contains(treeElement)
+                        || additions.contains(treeElement)) {
+					obsoleteRefresh.add(treeElement);
+				}
+
+                //Also check for groups that are being added
+               Object parent = treeElement.getParent();
+               if(parent != null && (deletions.contains(parent)
+                       || additions.contains(parent))){
+            	   obsoleteRefresh.add(treeElement);
+               }
+
+                if (!treeElement.isActive()) {
+                    //If it is done then delete it
+                    obsoleteRefresh.add(treeElement);
+                    deletions.add(treeElement);
+                }
+            }
+
+            refreshes.removeAll(obsoleteRefresh);
+
+        }
+    }
+
+    /**
+     * Return a new instance of the receiver.
+     *
+     * @return ProgressViewUpdater
+     */
+   static ProgressViewUpdater getSingleton() {
+        if (singleton == null) {
+			singleton = new ProgressViewUpdater();
+		}
+        return singleton;
+    }
+
+    /**
+     * Return whether or not there is a singleton for updates to avoid creating
+     * extra listeners.
+     *
+     * @return boolean <code>true</code> if there is already
+     * a singleton
+     */
+    static boolean hasSingleton() {
+        return singleton != null;
+    }
+
+    static void clearSingleton() {
+        if (singleton != null) {
+			ProgressManager.getInstance().removeListener(singleton);
+		}
+        singleton = null;
+    }
+
+    /**
+     * Create a new instance of the receiver.
+     */
+    private ProgressViewUpdater() {
+        collectors = new IProgressUpdateCollector[0];
+        ProgressManager.getInstance().addListener(this);
+        debug =
+        	PrefUtil.getAPIPreferenceStore().
+        		getBoolean(IWorkbenchPreferenceConstants.SHOW_SYSTEM_JOBS);
+    }
+
+    /**
+     * Add the new collector to the list of collectors.
+     *
+     * @param newCollector
+     */
+    void addCollector(IProgressUpdateCollector newCollector) {
+        IProgressUpdateCollector[] newCollectors = new IProgressUpdateCollector[collectors.length + 1];
+        System.arraycopy(collectors, 0, newCollectors, 0, collectors.length);
+        newCollectors[collectors.length] = newCollector;
+        collectors = newCollectors;
+    }
+
+    /**
+     * Remove the collector from the list of collectors.
+     *
+     * @param provider
+     */
+    void removeCollector(IProgressUpdateCollector provider) {
+        HashSet newCollectors = new HashSet();
+        for (int i = 0; i < collectors.length; i++) {
+            if (!collectors[i].equals(provider)) {
+				newCollectors.add(collectors[i]);
+			}
+        }
+        IProgressUpdateCollector[] newArray = new IProgressUpdateCollector[newCollectors
+                .size()];
+        newCollectors.toArray(newArray);
+        collectors = newArray;
+        //Remove ourselves if there is nothing to update
+        if (collectors.length == 0) {
+			clearSingleton();
+		}
+    }
+
+	private void update() {
+		// Abort the update if there isn't anything
+		if (collectors.length == 0) {
+			return;
+		}
+
+		if (currentInfo.updateAll) {
+			currentInfo.reset();
+			for (IProgressUpdateCollector collector : collectors) {
+				collector.refresh();
+			}
+
+		} else {
+			// Lock while getting local copies of the caches.
+			Object[] updateItems;
+			Object[] additionItems;
+			Object[] deletionItems;
+			currentInfo.processForUpdate();
+
+			updateItems = currentInfo.refreshes.toArray();
+			additionItems = currentInfo.additions.toArray();
+			deletionItems = currentInfo.deletions.toArray();
+
+			currentInfo.reset();
+
+			for (IProgressUpdateCollector collector : collectors) {
+				if (updateItems.length > 0) {
+					collector.refresh(updateItems);
+				}
+				if (additionItems.length > 0) {
+					collector.add(additionItems);
+				}
+				if (deletionItems.length > 0) {
+					collector.remove(deletionItems);
+				}
+			}
+		}
+	}
+
+    /**
+     * Get the updates info that we are using in the receiver.
+     *
+     * @return Returns the currentInfo.
+     */
+    UpdatesInfo getCurrentInfo() {
+        return currentInfo;
+    }
+
+    /**
+     * Refresh the supplied JobInfo.
+     * @param info
+     */
+    public void refresh(JobInfo info) {
+		currentInfo.refresh(info);
+		GroupInfo group = info.getGroupInfo();
+		if (group != null) {
+			currentInfo.refresh(group);
+		}
+        //Add in a 100ms delay so as to keep priority low
+		throttledUpdate.throttledExec();
+
+    }
+
+    @Override
+	public void refreshJobInfo(JobInfo info) {
+		currentInfo.refresh(info);
+        //Add in a 100ms delay so as to keep priority low
+		throttledUpdate.throttledExec();
+
+    }
+
+    @Override
+	public void refreshGroup(GroupInfo info) {
+		currentInfo.refresh(info);
+        //Add in a 100ms delay so as to keep priority low
+		throttledUpdate.throttledExec();
+
+    }
+
+    @Override
+	public void addGroup(GroupInfo info) {
+
+		currentInfo.add(info);
+		throttledUpdate.throttledExec();
+
+    }
+
+    @Override
+	public void refreshAll() {
+
+		currentInfo.updateAll = true;
+
+        //Add in a 100ms delay so as to keep priority low
+		throttledUpdate.throttledExec();
+
+    }
+
+    @Override
+	public void addJob(JobInfo info) {
+		GroupInfo group = info.getGroupInfo();
+
+		if (group == null) {
+			currentInfo.add(info);
+		} else {
+			currentInfo.refresh(group);
+        }
+		throttledUpdate.throttledExec();
+
+    }
+
+    @Override
+	public void removeJob(JobInfo info) {
+		GroupInfo group = info.getGroupInfo();
+		if (group == null) {
+			currentInfo.remove(info);
+		} else {
+			currentInfo.refresh(group);
+        }
+		throttledUpdate.throttledExec();
+    }
+
+    @Override
+	public void removeGroup(GroupInfo group) {
+		currentInfo.remove(group);
+		throttledUpdate.throttledExec();
+
+    }
+
+    @Override
+	public boolean showsDebug() {
+        return debug;
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressViewerContentProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressViewerContentProvider.java
new file mode 100644
index 0000000..2800717
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressViewerContentProvider.java
@@ -0,0 +1,205 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.progress;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+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.internal.progress.FinishedJobs.KeptJobsListener;
+import org.eclipse.ui.progress.WorkbenchJob;
+
+/**
+ * The ProgressViewerContentProvider is the content provider progress viewers.
+ */
+public class ProgressViewerContentProvider extends ProgressContentProvider {
+	protected AbstractProgressViewer progressViewer;
+
+	private KeptJobsListener keptJobListener;
+
+	private boolean showFinished;
+
+	/**
+	 * Create a new instance of the receiver.
+	 *
+	 * @param structured
+	 *            The Viewer we are providing content for
+	 * @param debug
+	 *            If true debug information will be shown if the debug flag in
+	 *            the ProgressManager is true.
+	 * @param showFinished
+	 *            A boolean that indicates whether or not the finished jobs
+	 *            should be shown.
+	 */
+	public ProgressViewerContentProvider(AbstractProgressViewer structured,
+			boolean debug, boolean showFinished) {
+		super(debug);
+		progressViewer = structured;
+		this.showFinished = showFinished;
+		if (showFinished) {
+			FinishedJobs.getInstance().addListener(getKeptJobListener());
+		}
+	}
+
+	/**
+	 * Return a listener for kept jobs.
+	 *
+	 * @return KeptJobsListener
+	 */
+	private KeptJobsListener getKeptJobListener() {
+		keptJobListener = new KeptJobsListener() {
+
+			@Override
+			public void finished(JobTreeElement jte) {
+				final JobTreeElement element = jte;
+				Job updateJob = new WorkbenchJob("Refresh finished") {//$NON-NLS-1$
+					@Override
+					public IStatus runInUIThread(IProgressMonitor monitor) {
+						refresh(new Object[] { element });
+						return Status.OK_STATUS;
+					}
+
+					@Override
+					public boolean shouldSchedule() {
+						return !progressViewer.getControl().isDisposed();
+					}
+
+					@Override
+					public boolean shouldRun() {
+						return !progressViewer.getControl().isDisposed();
+					}
+				};
+				updateJob.setSystem(true);
+				updateJob.schedule();
+
+			}
+
+			@Override
+			public void removed(JobTreeElement jte) {
+				final JobTreeElement element = jte;
+				Job updateJob = new WorkbenchJob("Remove finished") {//$NON-NLS-1$
+					@Override
+					public IStatus runInUIThread(IProgressMonitor monitor) {
+						if (element == null) {
+							refresh();
+						} else {
+							ProgressViewerContentProvider.this.remove(new Object[] { element });
+						}
+						return Status.OK_STATUS;
+					}
+				};
+				updateJob.setSystem(true);
+				updateJob.schedule();
+
+			}
+
+		};
+		return keptJobListener;
+	}
+
+	@Override
+	public void refresh() {
+		progressViewer.refresh(true);
+	}
+
+	@Override
+	public void refresh(Object[] elements) {
+		for (Object refresh : getRoots(elements, true)) {
+			progressViewer.refresh(refresh, true);
+		}
+	}
+
+	@Override
+	public Object[] getElements(Object inputElement) {
+		Object[] elements = super.getElements(inputElement);
+
+		if (!showFinished)
+			return elements;
+
+		Set kept = FinishedJobs.getInstance().getKeptAsSet();
+
+		if (kept.size() == 0)
+			return elements;
+
+		Set all = new HashSet();
+
+		for (Object element : elements) {
+			all.add(element);
+		}
+
+		Iterator keptIterator = kept.iterator();
+		while (keptIterator.hasNext()) {
+			JobTreeElement next = (JobTreeElement) keptIterator.next();
+			if (next.getParent() != null && all.contains(next.getParent()))
+				continue;
+			all.add(next);
+
+		}
+
+		return all.toArray();
+	}
+
+	/**
+	 * Get the root elements of the passed elements as we only show roots.
+	 * Replace the element with its parent if subWithParent is true
+	 *
+	 * @param elements
+	 *            the array of elements.
+	 * @param subWithParent
+	 *            sub with parent flag.
+	 * @return Object[]
+	 */
+	private Object[] getRoots(Object[] elements, boolean subWithParent) {
+		if (elements.length == 0) {
+			return elements;
+		}
+		HashSet roots = new HashSet();
+		for (Object element : elements) {
+			JobTreeElement jobTreeElement = (JobTreeElement) element;
+			if (jobTreeElement.isJobInfo()) {
+				GroupInfo group = ((JobInfo) jobTreeElement).getGroupInfo();
+				if (group == null) {
+					roots.add(jobTreeElement);
+				} else {
+					if (subWithParent) {
+						roots.add(group);
+					}
+				}
+			} else {
+				roots.add(jobTreeElement);
+			}
+		}
+		return roots.toArray();
+	}
+
+	@Override
+	public void add(Object[] elements) {
+		progressViewer.add(elements);
+
+	}
+
+	@Override
+	public void remove(Object[] elements) {
+		progressViewer.remove(elements);
+
+	}
+
+	@Override
+	public void dispose() {
+		super.dispose();
+		if (keptJobListener != null) {
+			FinishedJobs.getInstance().removeListener(keptJobListener);
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressViewerLabelProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressViewerLabelProvider.java
new file mode 100644
index 0000000..16a343a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/ProgressViewerLabelProvider.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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 - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ui.internal.progress;
+
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.swt.widgets.Control;
+
+/**
+ * The ProgressViewerLabelProvider is the label provider for progress viewers.
+ */
+public class ProgressViewerLabelProvider extends LabelProvider {
+    private Control control;
+
+    @Override
+	public String getText(Object element) {
+        JobTreeElement info = (JobTreeElement) element;
+        return ProgressManagerUtil.shortenText(
+                info.getCondensedDisplayString(), control);
+    }
+
+    /**
+     * Create a new instance of the receiver within the control.
+     *
+     * @param progressControl The control that the label is
+     * being created for.
+     */
+    public ProgressViewerLabelProvider(Control progressControl) {
+        super();
+        control = progressControl;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/StatusAdapterHelper.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/StatusAdapterHelper.java
new file mode 100644
index 0000000..29477cd
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/StatusAdapterHelper.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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.ui.internal.progress;
+
+import java.util.HashMap;
+
+import org.eclipse.ui.progress.IProgressConstants;
+import org.eclipse.ui.statushandlers.StatusAdapter;
+
+/**
+ * StatusAdapterHelper is a class for caching {@link StatusAdapter} instances to make sure
+ * they are not created twice within the progress service.
+ * @since 3.3
+ */
+public class StatusAdapterHelper {
+	private static StatusAdapterHelper instance;
+
+	private HashMap map;
+
+	private StatusAdapterHelper() {
+	}
+
+	/**
+	 * Return the singleton.
+	 * @return StatusAdapterHelper
+	 */
+	public static StatusAdapterHelper getInstance() {
+		if (instance == null) {
+			instance = new StatusAdapterHelper();
+		}
+		return instance;
+	}
+
+	/**
+	 * Set the {@link StatusAdapter} for the {@link JobInfo}
+	 * @param info
+	 * @param statusAdapter
+	 */
+	public void putStatusAdapter(JobInfo info, StatusAdapter statusAdapter) {
+		if (map == null) {
+			map = new HashMap();
+		}
+		map.put(info, statusAdapter);
+	}
+
+	/**
+	 * Return the adapter for this info.
+	 * @param info
+	 * @return
+	 */
+	public StatusAdapter getStatusAdapter(JobInfo info) {
+		if (map == null) {
+			return null;
+		}
+		StatusAdapter statusAdapter = (StatusAdapter) map.remove(info);
+		statusAdapter.setProperty(
+				IProgressConstants.NO_IMMEDIATE_ERROR_PROMPT_PROPERTY,
+				Boolean.FALSE);
+		return statusAdapter;
+	}
+
+	public void clear() {
+		if (map != null) {
+			map.clear();
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/SubTaskInfo.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/SubTaskInfo.java
new file mode 100644
index 0000000..0cdb135
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/SubTaskInfo.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.internal.progress;
+
+/**
+ * SubTaskInfo is the class that displays a subtask in the tree.
+ */
+class SubTaskInfo extends JobTreeElement {
+	protected String taskName;
+	protected final JobInfo jobInfo;
+
+	/**
+	 * Creates a new instance of the receiver.
+	 *
+	 * @param parentJob
+	 * @param name
+	 */
+	SubTaskInfo(JobInfo parentJob, String name) {
+		taskName = name;
+		jobInfo = parentJob;
+	}
+
+	@Override
+	Object[] getChildren() {
+		return ProgressManagerUtil.EMPTY_OBJECT_ARRAY;
+	}
+
+	@Override
+	String getDisplayString() {
+		if (taskName == null) {
+			return ProgressMessages.get().SubTaskInfo_UndefinedTaskName;
+		}
+		return taskName;
+	}
+
+	@Override
+	boolean hasChildren() {
+		return false;
+	}
+
+	/**
+	 * Sets the taskName of the receiver.
+	 *
+	 * @param name
+	 */
+	void setTaskName(String name) {
+		if (name == null)
+			taskName = ProgressMessages.get().SubTaskInfo_UndefinedTaskName;
+		else
+			this.taskName = name;
+	}
+
+	/**
+	 * Returns the taskName of the receiver.
+	 */
+	String getTaskName() {
+		return taskName;
+	}
+
+	@Override
+	public Object getParent() {
+		return jobInfo;
+	}
+
+	@Override
+	boolean isJobInfo() {
+		return false;
+	}
+
+	@Override
+	boolean isActive() {
+		return jobInfo.isActive();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/TaskBarProgressManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/TaskBarProgressManager.java
new file mode 100644
index 0000000..4f26486
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/TaskBarProgressManager.java
@@ -0,0 +1,286 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2016 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:
+ *     Tasktop Technologies - initial API and implementation
+ *     Daniel Kruegler <daniel.kruegler@gmail.com> - Bug 471310
+ ******************************************************************************/
+
+package org.eclipse.ui.internal.progress;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.eclipse.core.runtime.Assert;
+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.resource.ImageDescriptor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.TaskItem;
+import org.eclipse.ui.progress.IProgressConstants;
+import org.eclipse.ui.progress.IProgressConstants2;
+import org.eclipse.ui.progress.WorkbenchJob;
+
+/**
+ * The TaskBarProgressManager is the class that displays progress in the
+ * application TaskBar if the job specifies that it should show progress (@see
+ * {@link IProgressConstants2#SHOW_IN_TASKBAR_ICON_PROPERTY}
+ *
+ * @since 3.6
+ */
+public class TaskBarProgressManager {
+
+	private IJobProgressManagerListener listener;
+
+	private WorkbenchJob animationUpdateJob;
+
+	private boolean isAnimated = false;
+
+	private List<Job> jobs = Collections.synchronizedList(new ArrayList<Job>());
+
+	private Map<Job, JobInfo> jobInfoMap = Collections.synchronizedMap(new HashMap<Job, JobInfo>());
+
+	private final TaskItem taskItem;
+
+	private ImageDescriptor overlayDescriptor;
+
+	private Image overlayImage;
+
+	public TaskBarProgressManager(TaskItem taskItem) {
+		Assert.isNotNull(taskItem);
+		this.taskItem = taskItem;
+		animationUpdateJob = getAnimationUpdateJob();
+		animationUpdateJob.setSystem(true);
+		listener = getProgressListener();
+
+		// Register the IJobProgressManagerListener so we can display progress
+		// on the application TaskBar
+		ProgressManager.getInstance().addListener(listener);
+
+		taskItem.addDisposeListener(e -> dispose());
+	}
+
+	/**
+	 * Remove the listener and stop the animation
+	 */
+	public void dispose() {
+		ProgressManager.getInstance().removeListener(listener);
+		setAnimated(false);
+		disposeOverlay();
+	}
+
+	private WorkbenchJob getAnimationUpdateJob() {
+		return new WorkbenchJob(ProgressMessages.get().AnimationManager_AnimationStart) {
+
+			@Override
+			public IStatus runInUIThread(IProgressMonitor monitor) {
+				if (isAnimated) {
+					if (!taskItem.isDisposed() && !jobs.isEmpty()) {
+						Job job = jobs.get(0);
+						JobInfo jobInfo = jobInfoMap.get(job);
+						if (job != null && jobInfo != null) {
+							int percentDone = getPercentDone(jobInfo);
+							if (percentDone == IProgressMonitor.UNKNOWN || (jobInfo.hasTaskInfo()
+									&& jobInfo.getTaskInfo().totalWork == IProgressMonitor.UNKNOWN)) {
+								setProgressState(SWT.INDETERMINATE);
+							} else {
+								setProgressState(SWT.NORMAL);
+								if (!taskItem.isDisposed()) {
+									taskItem.setProgress(percentDone);
+								}
+							}
+						} else {
+							setProgressState(SWT.DEFAULT);
+						}
+						updateImage(job);
+					} else {
+						updateImage(null);
+					}
+				} else {
+					setProgressState(SWT.DEFAULT);
+					updateImage(null);
+				}
+
+				if (isAnimated && taskItem != null && !taskItem.isDisposed()) {
+					schedule(400);
+				}
+				return Status.OK_STATUS;
+			}
+
+			private void setProgressState(int state) {
+				if (!taskItem.isDisposed() && taskItem.getProgressState() != state) {
+					taskItem.setProgressState(SWT.DEFAULT);
+					taskItem.setProgressState(state);
+				}
+			}
+
+			private int getPercentDone(JobTreeElement info) {
+				if (info.isJobInfo()) {
+					return ((JobInfo) info).getPercentDone();
+				}
+
+				if (info.hasChildren()) {
+					Object[] roots = ((GroupInfo) info).getChildren();
+					if (roots.length == 1 && roots[0] instanceof JobTreeElement) {
+						TaskInfo ti = ((JobInfo) roots[0]).getTaskInfo();
+						if (ti != null) {
+							return ti.getPercentDone();
+						}
+					}
+					return ((GroupInfo) info).getPercentDone();
+				}
+				return 0;
+			}
+		};
+	}
+
+	private void updateImage(Job job) {
+		if (taskItem == null || taskItem.isDisposed())
+			return;
+
+		if (job == null) {
+			disposeOverlay();
+			taskItem.setOverlayImage(null);
+			return;
+		}
+
+		// first check whether the job specifies image property
+		// if not check with progress manager for its family
+		ImageDescriptor descriptor = (ImageDescriptor) job.getProperty(IProgressConstants.ICON_PROPERTY);
+		if (descriptor != null) {
+
+			// if the description is same, do nothing.
+			// Else dispose old one and store this
+			if (!descriptor.equals(overlayDescriptor)) {
+				disposeOverlay();
+				setOverlay(descriptor);
+			}
+		} else if (ProgressManager.getInstance().getIconFor(job) != null) {
+			disposeOverlay();
+			Image newImage = ProgressManager.getInstance().getIconFor(job);
+			taskItem.setOverlayImage(newImage);
+		} else {
+			disposeOverlay();
+			taskItem.setOverlayImage(null);
+		}
+	}
+
+	private void setOverlay(ImageDescriptor descriptor) {
+		overlayDescriptor = descriptor;
+		overlayImage = descriptor.createImage();
+		taskItem.setOverlayImage(overlayImage);
+	}
+
+	private void disposeOverlay() {
+		overlayDescriptor = null;
+		if (overlayImage != null) {
+			overlayImage.dispose();
+			overlayImage = null;
+		}
+	}
+
+	private IJobProgressManagerListener getProgressListener() {
+		return new IJobProgressManagerListener() {
+
+			@Override
+			public void addJob(JobInfo info) {
+				// Don't count the animate job itself
+				if (isNotTracked(info)) {
+					return;
+				}
+				if (jobs.isEmpty()) {
+					setAnimated(true);
+				}
+				if (!jobs.contains(info.getJob())) {
+					jobs.add(info.getJob());
+				}
+				jobInfoMap.put(info.getJob(), info);
+			}
+
+			@Override
+			public void refreshJobInfo(JobInfo info) {
+				int state = info.getJob().getState();
+				if (state == Job.RUNNING) {
+					addJob(info);
+				} else {
+					removeJob(info);
+				}
+			}
+
+			@Override
+			public void refreshAll() {
+				ProgressManager manager = ProgressManager.getInstance();
+				jobs.clear();
+				jobInfoMap.clear();
+				setAnimated(false);
+				for (JobInfo currentInfo : manager.getJobInfos(showsDebug())) {
+					addJob(currentInfo);
+				}
+			}
+
+			@Override
+			public void removeJob(JobInfo info) {
+				jobs.remove(info.getJob());
+				jobInfoMap.remove(info.getJob());
+				if (jobs.isEmpty()) {
+					setAnimated(false);
+				}
+			}
+
+			@Override
+			public boolean showsDebug() {
+				return false;
+			}
+
+			/**
+			 * If the job isn't running or doesn't specify the
+			 * IProgressConstants#SHOW_IN_TASKBAR_ICON_PROPERTY property, don't
+			 * bother tracking it.
+			 */
+			private boolean isNotTracked(JobInfo info) {
+				Job job = info.getJob();
+				return job.getState() != Job.RUNNING || !shouldShowSystemProgress(info);
+			}
+
+			private boolean shouldShowSystemProgress(JobInfo info) {
+				Boolean showInTaskBarIcon = Boolean.FALSE;
+				Object property = info.getJob().getProperty(IProgressConstants2.SHOW_IN_TASKBAR_ICON_PROPERTY);
+
+				if (property instanceof Boolean) {
+					showInTaskBarIcon = (Boolean) property;
+				}
+				return showInTaskBarIcon.booleanValue();
+
+			}
+
+			@Override
+			public void addGroup(GroupInfo info) {
+				// Don't care about groups
+			}
+
+			@Override
+			public void removeGroup(GroupInfo group) {
+				// Don't care about groups
+			}
+
+			@Override
+			public void refreshGroup(GroupInfo info) {
+				// Don't care about groups
+			}
+		};
+	}
+
+	private synchronized void setAnimated(boolean animated) {
+		isAnimated = animated;
+		animationUpdateJob.schedule();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/TaskInfo.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/TaskInfo.java
new file mode 100644
index 0000000..b33f643
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/TaskInfo.java
@@ -0,0 +1,143 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.internal.progress;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * The TaskInfo is the info on a task with a job. It is assumed that there is
+ * only one task running at a time - any previous tasks in a Job will be
+ * deleted.
+ */
+public class TaskInfo extends SubTaskInfo {
+	double preWork;
+	int totalWork;
+
+	/**
+	 * Creates a new instance of the receiver with the supplied total work and
+	 * task name.
+	 *
+	 * @param parentJobInfo
+	 * @param infoName
+	 * @param total
+	 */
+	TaskInfo(JobInfo parentJobInfo, String infoName, int total) {
+		super(parentJobInfo, infoName);
+		totalWork = total;
+	}
+
+	/**
+	 * Adds the work increment to the total.
+	 *
+	 * @param workIncrement
+	 */
+	void addWork(double workIncrement) {
+		// Don't bother if we are indeterminate
+		if (totalWork == IProgressMonitor.UNKNOWN) {
+			return;
+		}
+		preWork += workIncrement;
+	}
+
+	/**
+	 * Adds the amount of work to the receiver. Update a parent monitor by the
+	 * increment scaled to the amount of ticks this represents.
+	 *
+	 * @param workIncrement
+	 *            int the amount of work in the receiver
+	 * @param parentMonitor
+	 *            The IProgressMonitor that is also listening
+	 * @param parentTicks
+	 *            the number of ticks this monitor represents
+	 */
+	void addWork(double workIncrement, IProgressMonitor parentMonitor, int parentTicks) {
+		// Don't bother if we are indeterminate.
+		if (totalWork == IProgressMonitor.UNKNOWN) {
+			return;
+		}
+
+		addWork(workIncrement);
+		parentMonitor.internalWorked(workIncrement * parentTicks / totalWork);
+	}
+
+	@Override
+	String getDisplayString(boolean showProgress) {
+		if (totalWork == IProgressMonitor.UNKNOWN) {
+			return unknownProgress();
+		}
+
+		if (taskName == null) {
+			return getDisplayStringWithoutTask(showProgress);
+		}
+
+		if (showProgress) {
+			String[] messageValues = new String[3];
+			messageValues[0] = String.valueOf(getPercentDone());
+			messageValues[1] = jobInfo.getJob().getName();
+			messageValues[2] = taskName;
+
+			return NLS.bind(ProgressMessages.get().JobInfo_DoneMessage, messageValues);
+		}
+		String[] messageValues = new String[2];
+		messageValues[0] = jobInfo.getJob().getName();
+		messageValues[1] = taskName;
+
+		return NLS.bind(ProgressMessages.get().JobInfo_DoneNoProgressMessage, messageValues);
+	}
+
+	/**
+	 * Returns the display String without the task name.
+	 *
+	 * @param showProgress
+	 *            Whether or not we are showing progress
+	 *
+	 * @return String
+	 */
+	String getDisplayStringWithoutTask(boolean showProgress) {
+		if (!showProgress || totalWork == IProgressMonitor.UNKNOWN) {
+			return jobInfo.getJob().getName();
+		}
+
+		return NLS.bind(ProgressMessages.get().JobInfo_NoTaskNameDoneMessage, jobInfo.getJob().getName(),
+				String.valueOf(getPercentDone()));
+	}
+
+	/**
+	 * Returns an integer representing the amount of work completed. If progress
+	 * is indeterminate return IProgressMonitor.UNKNOWN.
+	 *
+	 * @return int IProgressMonitor.UNKNOWN or a value between 0 and 100.
+	 */
+	int getPercentDone() {
+		if (totalWork == IProgressMonitor.UNKNOWN) {
+			return IProgressMonitor.UNKNOWN;
+		}
+
+		return Math.min((int) (preWork * 100 / totalWork), 100);
+	}
+
+	/**
+	 * Returns the progress for a monitor whose totalWork is
+	 * <code>IProgressMonitor.UNKNOWN</code>.
+	 *
+	 * @return String
+	 */
+	private String unknownProgress() {
+		if (taskName == null) {
+			return jobInfo.getJob().getName();
+		}
+		String[] messageValues = new String[2];
+		messageValues[0] = jobInfo.getJob().getName();
+		messageValues[1] = taskName;
+		return NLS.bind(ProgressMessages.get().JobInfo_UnknownProgress, messageValues);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/Throttler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/Throttler.java
new file mode 100644
index 0000000..544ad8d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/Throttler.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Eclipse Foundation 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:
+ *     Mikael Barbero (Eclipse Foundation) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ui.internal.progress;
+
+import java.time.Duration;
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * A utility class that throttles the execution of a runnable in the UI thread.
+ */
+public class Throttler {
+	private final Runnable timerExec;
+
+	private final Display display;
+
+	private volatile boolean scheduled;
+
+	/**
+	 * Initializes a new throttler object that will throttle the execution of
+	 * the given runnable in the {@link Display#getThread() UI thread} of the
+	 * given display. The throttler will ensure that the runnable will not run
+	 * more than every {@code minWaitTime}, even if it is
+	 * {@link #throttledExec() executed} more often.
+	 *
+	 * @param display
+	 *            the display owning the thread onto which the runnable will be
+	 *            executed.
+	 * @param minWaitTime
+	 *            the minimum duration between each execution of the given
+	 *            runnable.
+	 * @param runnable
+	 *            the runnable to throttle.
+	 */
+	public Throttler(Display display, Duration minWaitTime, Runnable runnable) {
+		this.display = display;
+		if (minWaitTime.isNegative()) {
+			throw new IllegalArgumentException("Minimum wait time must be positive"); //$NON-NLS-1$
+		}
+		if (minWaitTime.toMillis() > Integer.MAX_VALUE) {
+			throw new IllegalArgumentException(
+					"Minimum wait time must be smaller than " + Integer.MAX_VALUE); //$NON-NLS-1$
+		}
+		int minWaitBetweenRunMillis = (int) minWaitTime.toMillis();
+		this.timerExec = () -> {
+			if (!display.isDisposed()) {
+				display.timerExec(minWaitBetweenRunMillis, () -> {
+					scheduled = false;
+					runnable.run();
+				});
+			}
+		};
+	}
+
+	/**
+	 * Schedules the wrapped runnable to be run after the configured wait time
+	 * or do nothing if it has already been scheduled but not executed yet.
+	 */
+	public void throttledExec() {
+		if (!scheduled && !display.isDisposed()) {
+			scheduled = true;
+			if (Thread.currentThread() == display.getThread()) {
+				timerExec.run();
+			} else {
+				display.asyncExec(timerExec);
+			}
+		}
+	}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/WorkbenchSiteProgressService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/WorkbenchSiteProgressService.java
new file mode 100644
index 0000000..57d5658
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/WorkbenchSiteProgressService.java
@@ -0,0 +1,400 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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 - Initial API and implementation
+ * Remy Chi Jian Suen (Versant Corporation) - bug 255005
+ * Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ *******************************************************************************/
+package org.eclipse.ui.internal.progress;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.IJobChangeEvent;
+import org.eclipse.core.runtime.jobs.IJobChangeListener;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.core.runtime.jobs.JobChangeAdapter;
+import org.eclipse.e4.ui.internal.workbench.swt.CSSConstants;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.jface.operation.IRunnableContext;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.rap.ui.internal.progress.ProgressUtil;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Cursor;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.PartSite;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.part.WorkbenchPart;
+import org.eclipse.ui.progress.IProgressService;
+import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
+import org.eclipse.ui.progress.WorkbenchJob;
+
+/**
+ * The WorkbenchSiteProgressService is the concrete implementation of the
+ * WorkbenchSiteProgressService used by the workbench components.
+ */
+public class WorkbenchSiteProgressService implements
+        IWorkbenchSiteProgressService, IJobBusyListener {
+    PartSite site;
+
+	/**
+	 * Map from Job to Boolean (non-null). Interpretation of the value:
+	 * <ul>
+	 * <li>{@link Boolean#TRUE}: The half busy cursor has been requested.</li>
+	 * <li>{@link Boolean#FALSE}: The half busy cursor has not (yet) been
+	 * requested.</li>
+	 * </ul>
+	 */
+	private Map<Job, Boolean> busyJobs = new HashMap<>();
+
+    private Object busyLock = new Object();
+
+    IPropertyChangeListener[] changeListeners = new IPropertyChangeListener[0];
+
+    private Cursor waitCursor;
+
+    private int waitCursorJobCount;
+
+    private Object waitCursorLock = new Object();
+
+    private SiteUpdateJob updateJob;
+
+	/**
+	 * Flag that keeps state from calls to {@link #incrementBusy()} and
+	 * {@link #decrementBusy()}.
+	 */
+	private int busyCount = 0;
+
+    public class SiteUpdateJob extends WorkbenchJob {
+        private boolean busy;
+
+        Object lock = new Object();
+
+        /**
+         * Set whether we are updating with the wait or busy cursor.
+         *
+         * @param cursorState
+         */
+        void setBusy(boolean cursorState) {
+            synchronized (lock) {
+                busy = cursorState;
+            }
+        }
+
+        private SiteUpdateJob() {
+            super(ProgressMessages.get().WorkbenchSiteProgressService_CursorJob);
+        }
+
+        /**
+         * Get the wait cursor. Initialize it if required.
+         * @param display the display to create the cursor on.
+         * @return the created cursor
+         */
+        private Cursor getWaitCursor(Display display) {
+            if (waitCursor == null) {
+                waitCursor = new Cursor(display, SWT.CURSOR_APPSTARTING);
+            }
+            return waitCursor;
+        }
+
+        @Override
+		public IStatus runInUIThread(IProgressMonitor monitor) {
+			Control control = (Control) site.getModel().getWidget();
+            if (control == null || control.isDisposed()) {
+				return Status.CANCEL_STATUS;
+			}
+            synchronized (lock) {
+                //Update cursors if we are doing that
+                Cursor cursor = null;
+                if (waitCursorJobCount !=0) {
+                	// at least one job which is running has requested for wait cursor
+					cursor = getWaitCursor(control.getDisplay());
+				}
+                control.setCursor(cursor);
+				showBusy(busy);
+                IWorkbenchPart part = site.getPart();
+                 if (part instanceof WorkbenchPart) {
+					((WorkbenchPart) part).showBusy(busy);
+				}
+            }
+            return Status.OK_STATUS;
+        }
+
+        void clearCursors() {
+            if (waitCursor != null) {
+                waitCursor.dispose();
+                waitCursor = null;
+            }
+        }
+
+    }
+
+    /**
+     * Create a new instance of the receiver with a site of partSite
+     *
+     * @param partSite
+     *            PartSite.
+     */
+    public WorkbenchSiteProgressService(final PartSite partSite) {
+        site = partSite;
+        updateJob = new SiteUpdateJob();
+        updateJob.setSystem(true);
+    }
+
+    /**
+     * Dispose the resources allocated by the receiver.
+     *
+     */
+    public void dispose() {
+        if (updateJob != null) {
+			updateJob.cancel();
+		}
+
+        ProgressManager.getInstance().removeListener(this);
+		showBusy(false);
+
+        if (waitCursor == null) {
+			return;
+		}
+        waitCursor.dispose();
+        waitCursor = null;
+    }
+
+    @Override
+	public void busyCursorWhile(IRunnableWithProgress runnable)
+            throws InvocationTargetException, InterruptedException {
+        getWorkbenchProgressService().busyCursorWhile(runnable);
+    }
+
+    @Override
+	public void schedule(Job job, long delay, boolean useHalfBusyCursor) {
+        job.addJobChangeListener(getJobChangeListener(useHalfBusyCursor));
+        job.schedule(delay);
+    }
+
+    @Override
+	public void schedule(Job job, long delay) {
+        schedule(job, delay, false);
+    }
+
+    @Override
+	public void schedule(Job job) {
+        schedule(job, 0L, false);
+    }
+
+    @Override
+	public void showBusyForFamily(Object family) {
+        ProgressManager.getInstance().addListenerToFamily(family, this);
+    }
+
+    /**
+     * Get the job change listener for this site.
+     *
+     * @param useHalfBusyCursor
+     * @return IJobChangeListener
+     */
+	public IJobChangeListener getJobChangeListener(final boolean useHalfBusyCursor) {
+		return new JobChangeAdapter() {
+
+			@Override
+			public void aboutToRun(IJobChangeEvent event) {
+				incrementBusy(event.getJob(), useHalfBusyCursor);
+			}
+
+			@Override
+			public void done(IJobChangeEvent event) {
+				Job job = event.getJob();
+				decrementBusy(job);
+				job.removeJobChangeListener(this);
+			}
+		};
+	}
+
+    @Override
+	public void decrementBusy(Job job) {
+		Object halfBusyCursorState;
+        synchronized (busyLock) {
+			halfBusyCursorState = busyJobs.remove(job);
+			if (halfBusyCursorState == null) {
+				return;
+			}
+		}
+		if (halfBusyCursorState == Boolean.TRUE) {
+			synchronized (waitCursorLock) {
+				waitCursorJobCount--;
+			}
+        }
+        try {
+        	decrementBusy();
+        } catch (Exception ex) {
+        	// protecting against assertion failures
+        	WorkbenchPlugin.log(ex);
+        }
+    }
+
+    @Override
+	public void incrementBusy(Job job) {
+		incrementBusy(job, false);
+	}
+
+	private void incrementBusy(Job job, boolean useHalfBusyCursor) {
+		Object halfBusyCursorState;
+        synchronized (busyLock) {
+			halfBusyCursorState = busyJobs.get(job);
+			if (useHalfBusyCursor || halfBusyCursorState != Boolean.TRUE)
+				busyJobs.put(job, Boolean.valueOf(useHalfBusyCursor));
+        }
+		if (useHalfBusyCursor && halfBusyCursorState != Boolean.TRUE) {
+			// want to set busy cursor and it has not been set before
+			synchronized (waitCursorLock) {
+				waitCursorJobCount++;
+			}
+		}
+		if (halfBusyCursorState != null) {
+			// incrementBusy(Job, boolean) has been called before
+			if (useHalfBusyCursor && halfBusyCursorState == Boolean.FALSE) {
+				// need to update cursor without changing busy count:
+				synchronized (busyLock) {
+					updateJob.setBusy(true);
+				}
+				if (PlatformUI.isWorkbenchRunning()) {
+					updateJob.schedule(100);
+				} else {
+					updateJob.cancel();
+				}
+			}
+			return;
+		}
+        incrementBusy();
+    }
+
+    @Override
+	public void warnOfContentChange() {
+		MPart part = site.getModel();
+		if (!part.getTags().contains(CSSConstants.CSS_CONTENT_CHANGE_CLASS)) {
+			part.getTags().add(CSSConstants.CSS_CONTENT_CHANGE_CLASS);
+		}
+    }
+
+    @Override
+	public void showInDialog(Shell shell, Job job) {
+        getWorkbenchProgressService().showInDialog(shell, job);
+    }
+
+    /**
+     * Get the progress service for the workbnech,
+     *
+     * @return IProgressService
+     */
+    private IProgressService getWorkbenchProgressService() {
+        return site.getWorkbenchWindow().getWorkbench().getProgressService();
+    }
+
+    @Override
+	public void run(boolean fork, boolean cancelable,
+            IRunnableWithProgress runnable) throws InvocationTargetException,
+            InterruptedException {
+        getWorkbenchProgressService().run(fork, cancelable, runnable);
+    }
+
+    @Override
+	public void runInUI(IRunnableContext context,
+            IRunnableWithProgress runnable, ISchedulingRule rule)
+            throws InvocationTargetException, InterruptedException {
+        getWorkbenchProgressService().runInUI(context, runnable, rule);
+    }
+
+    @Override
+	public int getLongOperationTime() {
+        return getWorkbenchProgressService().getLongOperationTime();
+    }
+
+    @Override
+	public void registerIconForFamily(ImageDescriptor icon, Object family) {
+        getWorkbenchProgressService().registerIconForFamily(icon, family);
+    }
+
+    @Override
+	public Image getIconFor(Job job) {
+        return getWorkbenchProgressService().getIconFor(job);
+    }
+
+    @Override
+	public void incrementBusy() {
+		synchronized (busyLock) {
+			this.busyCount++;
+			if (busyCount != 1) {
+				return;
+			}
+			updateJob.setBusy(true);
+		}
+		// RAP [fappel]: use session aware approach
+//      if (PlatformUI.isWorkbenchRunning()) {
+//          updateJob.schedule(100);
+//      } else {
+//          updateJob.cancel();
+//      }
+        Display display = site.getShell().getDisplay();
+        if( !ProgressUtil.isWorkbenchRunning( display ) ) {
+            updateJob.schedule( 100 );
+        } else {
+          updateJob.cancel();
+        }
+    }
+	@Override
+	public void decrementBusy() {
+		synchronized (busyLock) {
+			Assert
+					.isTrue(
+							busyCount > 0,
+							"Ignoring unexpected call to IWorkbenchSiteProgressService.decrementBusy().  This might be due to an earlier call to this method."); //$NON-NLS-1$
+			this.busyCount--;
+			if (busyCount != 0) {
+				return;
+			}
+			updateJob.setBusy(false);
+		}
+		if (PlatformUI.isWorkbenchRunning()) {
+			updateJob.schedule(100);
+		} else {
+			updateJob.cancel();
+		}
+	}
+
+	/**
+	 * This method is made public only for the tests.
+	 * Clients should not be using this method
+	 *
+	 * @return the updateJob that updates the site
+	 */
+	public SiteUpdateJob getUpdateJob() {
+		return updateJob;
+	}
+
+	protected void showBusy(boolean busy) {
+		MPart part = site.getModel();
+		if (busy) {
+			part.getTags().add(CSSConstants.CSS_BUSY_CLASS);
+		} else {
+			part.getTags().remove(CSSConstants.CSS_BUSY_CLASS);
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/messages.properties b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/messages.properties
new file mode 100644
index 0000000..742bf2e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/progress/messages.properties
@@ -0,0 +1,68 @@
+###############################################################################
+# Copyright (c) 2003, 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
+#	  Sebastian Davids <sdavids@gmx.de>  - Fix for  Bug 132158 [Progress] Job, Operation, Task used interchangably
+###############################################################################
+PendingUpdateAdapter_PendingLabel=Pending...
+JobInfo_DoneMessage = ({0}%) {1}: {2}
+JobInfo_DoneNoProgressMessage = {0}: {1}
+JobInfo_NoTaskNameDoneMessage = {0}: ({1}%)
+JobsViewPreferenceDialog_Note=&Show sleeping and system operations
+JobErrorDialog_CustomJobText=Custom Operation Action
+JobInfo_UnknownProgress = {0}: {1}
+JobInfo_Waiting = {0} (Waiting)
+JobInfo_Sleeping = {0} (Sleeping)
+JobInfo_System = System: {0}
+JobInfo_Cancelled = {0} (Canceled)
+JobInfo_Cancel_Requested = {0} (Cancel Requested)
+JobInfo_Error = {0} (Time of error: {1})
+JobInfo_Blocked = {0} (Blocked: {1})
+JobInfo_Finished = {0} (Finished)
+JobInfo_FinishedAt = {0} (Finished at {1})
+JobErrorDialog_CloseDialogMessage=Performing this action will close the error dialog and clear the errors being displayed.
+InternalError = An internal error has occurred.
+DeferredTreeContentManager_NotDeferred=Not an IDeferredWorkbenchAdapter
+DeferredTreeContentManager_AddingChildren=Adding children
+DeferredTreeContentManager_FetchingName = Fetching children of {0}
+ProgressView_CancelAction=&Cancel
+ProgressView_ClearAllAction=Remove &All Finished Operations
+ProgressView_NoOperations=No operations to display at this time.
+
+NewProgressView_RemoveAllJobsToolTip=Remove All Finished Operations
+NewProgressView_CancelJobToolTip=Cancel Operation
+NewProgressView_ClearJobToolTip=Remove From View
+NewProgressView_errorDialogTitle= Error Occurred
+NewProgressView_errorDialogMessage= Operation Finished with Error
+ProgressAnimationItem_tasks=Shows background operations in Progress view
+ProgressAnimationItem_ok=Operation ''{0}'' returned result; press button for details
+ProgressAnimationItem_error=Operation ''{0}'' finished with errors; press button for details
+SubTaskInfo_UndefinedTaskName=Undefined
+DeferredTreeContentManager_ClearJob=Clear
+ProgressContentProvider_UpdateProgressJob=Update Progress
+JobErrorDialog_MultipleErrorsTitle=Multiple Errors have Occurred
+ProgressManager_openJobName=Open progress monitor
+ProgressManager_showInDialogName=Show In Dialog
+
+ProgressMonitorJobsDialog_DetailsTitle=&Details >>
+ProgressMonitorJobsDialog_HideTitle=<< &Details
+ErrorNotificationManager_OpenErrorDialogJob=Open error dialog
+AnimationManager_AnimationStart=Animation start
+ProgressFloatingWindow_EllipsisValue=...
+
+BlockedJobsDialog_UserInterfaceTreeElement=Waiting User Operation
+BlockedJobsDialog_BlockedTitle=User Operation is Waiting
+WorkbenchSiteProgressService_CursorJob=Change cursor
+ProgressMonitorFocusJobDialog_UserDialogJob=Open user dialog
+ProgressMonitorFocusJobDialog_CLoseDialogJob=Close dialog
+ProgressMonitorFocusJobDialog_RunInBackgroundButton=Run in &Background
+
+JobErrorDialog_MultipleErrorsMessage=Multiple operations have reported errors. Select an error to view its details.
+JobErrorDialog_CloseDialogTitle=OK to Close?
+JobsViewPreferenceDialog_Title=Progress Preferences
+JobErrorDialog_DoNotShowAgainMessage=Don't &show this again
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/provisional/application/IActionBarConfigurer2.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/provisional/application/IActionBarConfigurer2.java
new file mode 100644
index 0000000..c071433
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/provisional/application/IActionBarConfigurer2.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.provisional.application;
+
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.internal.provisional.action.IToolBarContributionItem;
+import org.eclipse.ui.application.IActionBarConfigurer;
+
+/**
+ * Extends <code>IActionBarConfigurer</code> with API to allow the advisor to
+ * be decoupled from the implementation types for tool bar managers and tool bar
+ * contribution items.
+ *
+ * @since 3.2
+ */
+public interface IActionBarConfigurer2 extends IActionBarConfigurer {
+
+	/**
+	 * Creates a tool bar manager for the workbench window's tool bar. The
+	 * action bar advisor should use this factory method rather than creating a
+	 * <code>ToolBarManager</code> directly.
+	 *
+	 * @return the tool bar manager
+	 */
+	public IToolBarManager createToolBarManager();
+
+	/**
+	 * Creates a toolbar contribution item for the window's tool bar. The action
+	 * bar advisor should use this factory method rather than creating a
+	 * <code>ToolBarContributionItem</code> directly.
+	 *
+	 * @param toolBarManager
+	 *            a tool bar manager for the workbench window's tool bar
+	 * @param id
+	 *            the id of the contribution
+	 * @return the tool bar contribution item
+	 */
+	public IToolBarContributionItem createToolBarContributionItem(
+			IToolBarManager toolBarManager, String id);
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/ActionElement.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/ActionElement.java
new file mode 100644
index 0000000..8f032d6
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/ActionElement.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.quickaccess;
+
+import org.eclipse.jface.action.ActionContributionItem;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.LegacyActionTools;
+import org.eclipse.jface.resource.ImageDescriptor;
+
+/**
+ * @since 3.3
+ *
+ */
+public class ActionElement extends QuickAccessElement {
+
+	private static final String separator = " - "; //$NON-NLS-1$
+
+	private ActionContributionItem item;
+
+	/* package */ActionElement(ActionContributionItem item, ActionProvider actionProvider) {
+		super(actionProvider);
+		this.item = item;
+	}
+
+	@Override
+	public void execute() {
+		item.getAction().run();
+	}
+
+	@Override
+	public String getId() {
+		return item.getId();
+	}
+
+	@Override
+	public ImageDescriptor getImageDescriptor() {
+		return item.getAction().getImageDescriptor();
+	}
+
+	@Override
+	public String getLabel() {
+		IAction action = item.getAction();
+		if (action.getToolTipText() != null
+				&& action.getToolTipText().length() != 0) {
+			return LegacyActionTools.removeMnemonics(action.getText()
+					+ separator + action.getToolTipText());
+		}
+		return LegacyActionTools.removeMnemonics(action.getText());
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result + ((item == null) ? 0 : item.hashCode());
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		final ActionElement other = (ActionElement) obj;
+		if (item == null) {
+			if (other.item != null)
+				return false;
+		} else if (!item.equals(other.item))
+			return false;
+		return true;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/ActionProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/ActionProvider.java
new file mode 100644
index 0000000..2c41470
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/ActionProvider.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.quickaccess;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import org.eclipse.jface.action.ActionContributionItem;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.SubContributionItem;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.internal.WorkbenchWindow;
+
+/**
+ * @since 3.3
+ *
+ */
+public class ActionProvider extends QuickAccessProvider {
+
+	private Map idToElement;
+
+	@Override
+	public String getId() {
+		return "org.eclipse.ui.actions"; //$NON-NLS-1$
+	}
+
+	@Override
+	public QuickAccessElement getElementForId(String id) {
+		getElements();
+		return (ActionElement) idToElement.get(id);
+	}
+
+	@Override
+	public QuickAccessElement[] getElements() {
+		if (idToElement == null) {
+			idToElement = new HashMap();
+			IWorkbenchWindow window = PlatformUI
+					.getWorkbench().getActiveWorkbenchWindow();
+			if (window instanceof WorkbenchWindow) {
+				MenuManager menu = ((WorkbenchWindow) window).getMenuManager();
+				Set result = new HashSet();
+				collectContributions(menu, result);
+				ActionContributionItem[] actions = (ActionContributionItem[]) result
+						.toArray(new ActionContributionItem[result.size()]);
+				for (ActionContributionItem action : actions) {
+					ActionElement actionElement = new ActionElement(action, this);
+					idToElement.put(actionElement.getId(), actionElement);
+				}
+			}
+		}
+		return (ActionElement[]) idToElement.values().toArray(
+				new ActionElement[idToElement.values().size()]);
+	}
+
+	private void collectContributions(MenuManager menu, Set result) {
+		for (IContributionItem item : menu.getItems()) {
+			if (item instanceof SubContributionItem) {
+				item = ((SubContributionItem) item).getInnerItem();
+			}
+			if (item instanceof MenuManager) {
+				collectContributions((MenuManager) item, result);
+			} else if (item instanceof ActionContributionItem
+					&& item.isEnabled()) {
+				result.add(item);
+			}
+		}
+	}
+
+	@Override
+	public ImageDescriptor getImageDescriptor() {
+		return WorkbenchImages
+				.getImageDescriptor(IWorkbenchGraphicConstants.IMG_OBJ_NODE);
+	}
+
+	@Override
+	public String getName() {
+		return QuickAccessMessages.QuickAccess_Menus;
+	}
+
+	@Override
+	protected void doReset() {
+		idToElement = null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/CamelUtil.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/CamelUtil.java
new file mode 100644
index 0000000..59a954c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/CamelUtil.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal.quickaccess;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Utility methods for camel case style matching.
+ *
+ * @since 3.3
+ *
+ */
+public class CamelUtil {
+
+	/**
+	 * Returns a lowercase string consisting of all initials of the words in the
+	 * given String. Words are separated by whitespace and other special
+	 * characters, or by uppercase letters in a word like CamelCase.
+	 *
+	 * @param s
+	 *            the string
+	 * @return a lowercase string containing the first character of every wordin
+	 *         the given string.
+	 */
+	public static String getCamelCase(String s) {
+		StringBuffer result = new StringBuffer();
+		if (s.length() > 0) {
+			int index = 0;
+			while (index != -1) {
+				result.append(s.charAt(index));
+				index = getNextCamelIndex(s, index + 1);
+			}
+		}
+		return result.toString().toLowerCase();
+	}
+
+	/**
+	 * Return an array with start/end indices for the characters used for camel
+	 * case matching, ignoring the first (start) many camel case characters.
+	 * For example, getCamelCaseIndices("some CamelCase", 1, 2) will return
+	 * {{5,5},{10,10}}.
+	 *
+	 * @param s the source string
+	 * @param start how many characters of getCamelCase(s) should be ignored
+	 * @param length for how many characters should indices be returned
+	 * @return an array of length start
+	 */
+	public static int[][] getCamelCaseIndices(String s, int start, int length) {
+		List result = new ArrayList();
+		int index = 0;
+		while (start > 0) {
+			index = getNextCamelIndex(s, index + 1);
+			start--;
+		}
+		while (length > 0) {
+			result.add(new int[] { index, index });
+			index = getNextCamelIndex(s, index + 1);
+			length--;
+		}
+		return (int[][]) result.toArray(new int[result.size()][]);
+	}
+
+	/**
+	 * Returns the next index to be used for camel case matching.
+	 *
+	 * @param s the string
+	 * @param index the index
+	 * @return the next index, or -1 if not found
+	 */
+	public static int getNextCamelIndex(String s, int index) {
+		char c;
+		while (index < s.length()
+				&& !(isSeparatorForCamelCase(c = s.charAt(index)))
+				&& Character.isLowerCase(c)) {
+			index++;
+		}
+		while (index < s.length() && isSeparatorForCamelCase(c = s.charAt(index))) {
+			index++;
+		}
+		if (index >= s.length()) {
+			index = -1;
+		}
+		return index;
+	}
+
+	/**
+	 * Returns true if the given character is to be considered a separator
+	 * for camel case matching purposes.
+	 *
+	 * @param c the character
+	 * @return true if the character is a separator
+	 */
+	public static boolean isSeparatorForCamelCase(char c) {
+		return !Character.isLetterOrDigit(c);
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/CommandElement.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/CommandElement.java
new file mode 100644
index 0000000..35d3d34
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/CommandElement.java
@@ -0,0 +1,178 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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
+ *     ARTAL Technologies <simon.chemouil@artal.fr> - Bug 293044 added keybindings display
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *     Patrik Suzzi <psuzzi@gmail.com> - Bug 476045
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.quickaccess;
+
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.jface.bindings.TriggerSequence;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.commands.ICommandImageService;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.internal.keys.BindingService;
+import org.eclipse.ui.internal.menus.CommandMessages;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.keys.IBindingService;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+/**
+ * @since 3.3
+ *
+ */
+public class CommandElement extends QuickAccessElement {
+
+	private ParameterizedCommand command;
+
+	private String id;
+
+	/* package */CommandElement(ParameterizedCommand command, String id,
+			CommandProvider commandProvider) {
+		super(commandProvider);
+		this.id = id;
+		this.command = command;
+	}
+
+	@Override
+	public void execute() {
+		Object o = getProvider();
+		if (o instanceof CommandProvider) {
+			CommandProvider provider = (CommandProvider) o;
+			if (provider.getHandlerService() != null && provider.getContextSnapshot() != null) {
+				try {
+					provider.getHandlerService().executeCommandInContext(command, null,
+							provider.getContextSnapshot());
+				} catch (Exception ex) {
+					StatusUtil.handleStatus(ex, StatusManager.SHOW
+							| StatusManager.LOG);
+				}
+				return;
+			}
+		}
+
+		// let's try the old fashioned way
+		IWorkbenchWindow window = PlatformUI.getWorkbench()
+				.getActiveWorkbenchWindow();
+		if (window != null) {
+			IHandlerService handlerService = window
+					.getWorkbench().getService(IHandlerService.class);
+			try {
+				handlerService.executeCommand(command, null);
+			} catch (Exception ex) {
+				StatusUtil.handleStatus(ex, StatusManager.SHOW
+						| StatusManager.LOG);
+			}
+		}
+	}
+
+	@Override
+	public String getId() {
+		return id;
+	}
+
+	@Override
+	public ImageDescriptor getImageDescriptor() {
+		ICommandImageService imgService = ((CommandProvider) getProvider()).getCommandImageService();
+		return (imgService == null) ? null : imgService.getImageDescriptor(getId());
+	}
+
+	/**
+	 * Returns a formatted string describes this command.
+	 *
+	 * @return a description of the command of this element
+	 * @since 3.6
+	 */
+	public String getCommand() {
+		final StringBuilder label = new StringBuilder();
+
+		try {
+			Command nestedCommand = command.getCommand();
+			label.append(command.getName());
+			if (nestedCommand != null && nestedCommand.getDescription() != null
+					&& nestedCommand.getDescription().length() != 0) {
+				label.append(separator).append(nestedCommand.getDescription());
+			}
+		} catch (NotDefinedException e) {
+			label.append(command.toString());
+		}
+
+		return label.toString();
+	}
+
+	@Override
+	public String getLabel() {
+		String command = getCommand();
+		String binding = getBinding();
+		if (binding != null) {
+			return NLS.bind(CommandMessages.Tooltip_Accelerator, command, binding);
+		}
+		return command;
+	}
+
+	/**
+	 * Returns a formatted string that can be used to invoke this element's
+	 * command. <code>null</code> may be returned if a binding cannot be found.
+	 *
+	 * @return the string keybinding for invoking this element's command, may be
+	 *         <code>null</code>
+	 * @since 3.6
+	 */
+	public String getBinding() {
+		BindingService service = (BindingService) PlatformUI.getWorkbench().getService(
+				IBindingService.class);
+		TriggerSequence[] triggerSeq = service.getBindingManager()
+				.getActiveBindingsDisregardingContextFor(command);
+		if (triggerSeq != null && triggerSeq.length > 0) {
+			return triggerSeq[0].format();
+		}
+		return null;
+	}
+
+	@Override
+	public String getSortLabel() {
+		try {
+			return command.getName();
+		} catch (NotDefinedException e) {
+			return command.toString();
+		}
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result + ((command == null) ? 0 : command.hashCode());
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		final CommandElement other = (CommandElement) obj;
+		if (command == null) {
+			if (other.command != null)
+				return false;
+		} else if (!command.equals(other.command))
+			return false;
+		return true;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/CommandProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/CommandProvider.java
new file mode 100644
index 0000000..ba015fb
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/CommandProvider.java
@@ -0,0 +1,175 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *     Patrik Suzzi <psuzzi@gmail.com> - Bug 476045
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.quickaccess;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.e4.core.commands.EHandlerService;
+import org.eclipse.e4.core.commands.ExpressionContext;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.commands.ICommandImageService;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
+import org.eclipse.ui.internal.WorkbenchImages;
+
+/**
+ * @since 3.3
+ *
+ */
+public class CommandProvider extends QuickAccessProvider {
+
+	private IEvaluationContext currentSnapshot;
+
+	void setSnapshot(IEvaluationContext c) {
+		reset();
+		currentSnapshot = c;
+	}
+
+	private Map idToElement;
+	private IHandlerService handlerService;
+	private ICommandService commandService;
+	private EHandlerService ehandlerService;
+	private ICommandImageService commandImageService;
+
+	public CommandProvider() {
+	}
+
+	@Override
+	public String getId() {
+		return "org.eclipse.ui.commands"; //$NON-NLS-1$
+	}
+
+	@Override
+	public QuickAccessElement getElementForId(String id) {
+		getElements();
+		return (CommandElement) idToElement.get(id);
+	}
+
+	@Override
+	public QuickAccessElement[] getElements() {
+		if (idToElement == null) {
+			idToElement = new HashMap();
+			ICommandService commandService = getCommandService();
+			EHandlerService ehandlerService = getEHandlerService();
+			final Collection commandIds = commandService.getDefinedCommandIds();
+			final Iterator commandIdItr = commandIds.iterator();
+			while (commandIdItr.hasNext()) {
+				final String currentCommandId = (String) commandIdItr.next();
+				final Command command = commandService
+						.getCommand(currentCommandId);
+				ParameterizedCommand pcmd = new ParameterizedCommand(command, null);
+				if (command != null && ehandlerService.canExecute(pcmd)) {
+					try {
+						Collection combinations = ParameterizedCommand
+								.generateCombinations(command);
+						for (Iterator it = combinations.iterator(); it
+								.hasNext();) {
+							ParameterizedCommand pc = (ParameterizedCommand) it.next();
+							String id = pc.serialize();
+							idToElement.put(id,
+									new CommandElement(pc, id, this));
+						}
+					} catch (final NotDefinedException e) {
+						// It is safe to just ignore undefined commands.
+					}
+				}
+			}
+		}
+		return (QuickAccessElement[]) idToElement.values().toArray(
+				new QuickAccessElement[idToElement.values().size()]);
+	}
+
+	@Override
+	public ImageDescriptor getImageDescriptor() {
+		return WorkbenchImages
+				.getImageDescriptor(IWorkbenchGraphicConstants.IMG_OBJ_NODE);
+	}
+
+	@Override
+	public String getName() {
+		return QuickAccessMessages.QuickAccess_Commands;
+	}
+
+	EHandlerService getEHandlerService() {
+		if (ehandlerService == null) {
+			if (currentSnapshot instanceof ExpressionContext) {
+				IEclipseContext ctx = ((ExpressionContext) currentSnapshot).eclipseContext;
+				ehandlerService = ctx.get(EHandlerService.class);
+			} else {
+				ehandlerService = PlatformUI.getWorkbench().getService(
+						EHandlerService.class);
+			}
+		}
+		return ehandlerService;
+	}
+
+	ICommandService getCommandService() {
+		if (commandService == null) {
+			if (currentSnapshot instanceof ExpressionContext) {
+				IEclipseContext ctx = ((ExpressionContext) currentSnapshot).eclipseContext;
+				commandService = ctx.get(ICommandService.class);
+			} else {
+				commandService = PlatformUI.getWorkbench().getService(
+						ICommandService.class);
+			}
+		}
+		return commandService;
+	}
+
+	IHandlerService getHandlerService() {
+		if (handlerService == null) {
+			if (currentSnapshot instanceof ExpressionContext) {
+				IEclipseContext ctx = ((ExpressionContext) currentSnapshot).eclipseContext;
+				handlerService = ctx.get(IHandlerService.class);
+			} else {
+				handlerService = PlatformUI.getWorkbench().getService(
+						IHandlerService.class);
+			}
+		}
+		return handlerService;
+	}
+
+	public ICommandImageService getCommandImageService() {
+		if (commandImageService == null) {
+			if (currentSnapshot instanceof ExpressionContext) {
+				IEclipseContext ctx = ((ExpressionContext) currentSnapshot).eclipseContext;
+				commandImageService = ctx.get(ICommandImageService.class);
+			} else {
+				commandImageService = PlatformUI.getWorkbench().getService(ICommandImageService.class);
+			}
+		}
+		return commandImageService;
+	}
+
+	IEvaluationContext getContextSnapshot() {
+		return currentSnapshot;
+	}
+
+	@Override
+	protected void doReset() {
+		idToElement = null;
+		if (currentSnapshot instanceof ExpressionContext) {
+			((ExpressionContext) currentSnapshot).eclipseContext.dispose();
+		}
+		currentSnapshot = null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/EditorElement.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/EditorElement.java
new file mode 100644
index 0000000..d7c7f9e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/EditorElement.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.quickaccess;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.IEditorReference;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * @since 3.3
+ *
+ */
+public class EditorElement extends QuickAccessElement {
+
+	private static final String DIRTY_MARK = "*"; //$NON-NLS-1$
+
+	private static final String separator = " - "; //$NON-NLS-1$
+
+	private IEditorReference editorReference;
+
+	/* package */EditorElement(IEditorReference editorReference, EditorProvider editorProvider) {
+		super(editorProvider);
+		this.editorReference = editorReference;
+	}
+
+	@Override
+	public void execute() {
+		IWorkbenchPart part = editorReference.getPart(true);
+		if (part != null) {
+			IWorkbenchPage activePage = PlatformUI.getWorkbench()
+					.getActiveWorkbenchWindow().getActivePage();
+			if (activePage != null) {
+				activePage.activate(part);
+			}
+		}
+	}
+
+	@Override
+	public String getId() {
+		return editorReference.getId() + editorReference.getTitleToolTip();
+	}
+
+	@Override
+	public ImageDescriptor getImageDescriptor() {
+		Image titleImage = editorReference.getTitleImage();
+		if (titleImage == null) {
+			return null;
+		}
+		return ImageDescriptor.createFromImage(titleImage);
+	}
+
+	@Override
+	public String getLabel() {
+		boolean dirty = editorReference.isDirty();
+		return (dirty ? DIRTY_MARK : "") + editorReference.getTitle() + separator + editorReference.getTitleToolTip(); //$NON-NLS-1$
+	}
+
+	@Override
+	public String getSortLabel() {
+		return editorReference.getTitle();
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result
+				+ ((editorReference == null) ? 0 : editorReference.hashCode());
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		final EditorElement other = (EditorElement) obj;
+		if (editorReference == null) {
+			if (other.editorReference != null)
+				return false;
+		} else if (!editorReference.equals(other.editorReference))
+			return false;
+		return true;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/EditorProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/EditorProvider.java
new file mode 100644
index 0000000..dd9c103
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/EditorProvider.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.quickaccess;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.IEditorReference;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
+import org.eclipse.ui.internal.WorkbenchImages;
+
+/**
+ * @since 3.3
+ *
+ */
+public class EditorProvider extends QuickAccessProvider {
+
+	private Map idToElement;
+
+	@Override
+	public QuickAccessElement getElementForId(String id) {
+		getElements();
+		return (EditorElement) idToElement.get(id);
+	}
+
+	@Override
+	public QuickAccessElement[] getElements() {
+		if (idToElement == null) {
+			idToElement = new HashMap();
+			IWorkbenchPage activePage = PlatformUI.getWorkbench()
+					.getActiveWorkbenchWindow().getActivePage();
+			if (activePage == null) {
+				return new QuickAccessElement[0];
+			}
+			for (IEditorReference editor : activePage.getEditorReferences()) {
+				EditorElement editorElement = new EditorElement(editor,
+						this);
+				idToElement.put(editorElement.getId(), editorElement);
+			}
+		}
+		return (QuickAccessElement[]) idToElement.values().toArray(
+				new QuickAccessElement[idToElement.values().size()]);
+	}
+
+	@Override
+	public String getId() {
+		return "org.eclipse.ui.editors"; //$NON-NLS-1$
+	}
+
+	@Override
+	public ImageDescriptor getImageDescriptor() {
+		return WorkbenchImages
+				.getImageDescriptor(IWorkbenchGraphicConstants.IMG_OBJ_NODE);
+	}
+
+	@Override
+	public String getName() {
+		return QuickAccessMessages.QuickAccess_Editors;
+	}
+
+	@Override
+	protected void doReset() {
+		idToElement = null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/PerspectiveElement.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/PerspectiveElement.java
new file mode 100644
index 0000000..4db58ca
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/PerspectiveElement.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.quickaccess;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.WorkbenchException;
+import org.eclipse.ui.internal.Workbench;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+/**
+ * @since 3.3
+ *
+ */
+public class PerspectiveElement extends QuickAccessElement {
+
+	private final IPerspectiveDescriptor descriptor;
+
+	/* package */PerspectiveElement(IPerspectiveDescriptor descriptor, PerspectiveProvider perspectiveProvider) {
+		super(perspectiveProvider);
+		this.descriptor = descriptor;
+	}
+
+	@Override
+	public void execute() {
+		IWorkbench workbench = PlatformUI.getWorkbench();
+		IWorkbenchWindow window = workbench
+				.getActiveWorkbenchWindow();
+		IWorkbenchPage activePage = window.getActivePage();
+		if (activePage != null) {
+			activePage.setPerspective(descriptor);
+		} else {
+			try {
+				window.openPage(descriptor.getId(), ((Workbench) workbench)
+						.getDefaultPageInput());
+			} catch (WorkbenchException e) {
+				IStatus errorStatus = WorkbenchPlugin.newError(NLS.bind(
+						WorkbenchMessages.get().Workbench_showPerspectiveError,
+						descriptor.getLabel()), e);
+				StatusManager.getManager().handle(errorStatus,
+						StatusManager.SHOW);
+			}
+		}
+	}
+
+	@Override
+	public String getId() {
+		return descriptor.getId();
+	}
+
+	@Override
+	public ImageDescriptor getImageDescriptor() {
+		return descriptor.getImageDescriptor();
+	}
+
+	@Override
+	public String getLabel() {
+		return descriptor.getLabel();
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result
+				+ ((descriptor == null) ? 0 : descriptor.hashCode());
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		final PerspectiveElement other = (PerspectiveElement) obj;
+		if (descriptor == null) {
+			if (other.descriptor != null)
+				return false;
+		} else if (!descriptor.equals(other.descriptor))
+			return false;
+		return true;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/PerspectiveProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/PerspectiveProvider.java
new file mode 100644
index 0000000..56737ed
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/PerspectiveProvider.java
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.quickaccess;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.activities.WorkbenchActivityHelper;
+import org.eclipse.ui.internal.WorkbenchImages;
+
+/**
+ * @since 3.3
+ *
+ */
+public class PerspectiveProvider extends QuickAccessProvider {
+
+	private QuickAccessElement[] cachedElements;
+	private Map<String, PerspectiveElement> idToElement = new HashMap<>();
+
+	@Override
+	public String getId() {
+		return "org.eclipse.ui.perspectives"; //$NON-NLS-1$
+	}
+
+	@Override
+	public QuickAccessElement getElementForId(String id) {
+		getElements();
+		return idToElement.get(id);
+	}
+
+	@Override
+	public QuickAccessElement[] getElements() {
+		if (cachedElements == null) {
+			IPerspectiveDescriptor[] perspectives = PlatformUI.getWorkbench()
+					.getPerspectiveRegistry().getPerspectives();
+			cachedElements = new QuickAccessElement[perspectives.length];
+			for (int i = 0; i < perspectives.length; i++) {
+				if (!WorkbenchActivityHelper.filterItem(perspectives[i])) {
+					PerspectiveElement perspectiveElement = new PerspectiveElement(perspectives[i],
+							this);
+					idToElement.put(perspectiveElement.getId(), perspectiveElement);
+				}
+			}
+			cachedElements = idToElement.values().toArray(
+					new QuickAccessElement[idToElement.size()]);
+		}
+		return cachedElements;
+	}
+
+	@Override
+	public ImageDescriptor getImageDescriptor() {
+		return WorkbenchImages
+				.getImageDescriptor(ISharedImages.IMG_ETOOL_DEF_PERSPECTIVE);
+	}
+
+	@Override
+	public String getName() {
+		return QuickAccessMessages.QuickAccess_Perspectives;
+	}
+
+	@Override
+	protected void doReset() {
+		cachedElements = null;
+		idToElement.clear();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/PreferenceElement.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/PreferenceElement.java
new file mode 100644
index 0000000..37cc83d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/PreferenceElement.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.quickaccess;
+
+import org.eclipse.jface.preference.IPreferenceNode;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.dialogs.WorkbenchPreferenceDialog;
+
+/**
+ * @since 3.3
+ *
+ */
+public class PreferenceElement extends QuickAccessElement {
+
+	private static final String separator = " - "; //$NON-NLS-1$
+
+	private IPreferenceNode preferenceNode;
+
+	private String prefix;
+
+	/* package */PreferenceElement(IPreferenceNode preferenceNode, String prefix, PreferenceProvider preferenceProvider) {
+		super(preferenceProvider);
+		this.preferenceNode = preferenceNode;
+		this.prefix = prefix;
+	}
+
+	@Override
+	public void execute() {
+		IWorkbenchWindow window = PlatformUI.getWorkbench()
+				.getActiveWorkbenchWindow();
+		if (window != null) {
+			WorkbenchPreferenceDialog dialog = WorkbenchPreferenceDialog
+					.createDialogOn(window.getShell(), preferenceNode.getId());
+			dialog.open();
+		}
+	}
+
+	@Override
+	public String getId() {
+		return preferenceNode.getId();
+	}
+
+	@Override
+	public ImageDescriptor getImageDescriptor() {
+		Image image = preferenceNode.getLabelImage();
+		if (image != null) {
+			ImageDescriptor descriptor = ImageDescriptor.createFromImage(image);
+			return descriptor;
+		}
+		return null;
+	}
+
+	@Override
+	public String getLabel() {
+		if (prefix != null && prefix.length() > 0) {
+			return preferenceNode.getLabelText() + separator
+					+ prefix;
+		}
+		return preferenceNode.getLabelText();
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result
+				+ ((preferenceNode == null) ? 0 : preferenceNode.hashCode());
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		final PreferenceElement other = (PreferenceElement) obj;
+		if (preferenceNode == null) {
+			if (other.preferenceNode != null)
+				return false;
+		} else if (!preferenceNode.equals(other.preferenceNode))
+			return false;
+		return true;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/PreferenceProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/PreferenceProvider.java
new file mode 100644
index 0000000..17688ad
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/PreferenceProvider.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.quickaccess;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.eclipse.jface.preference.IPreferenceNode;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.activities.WorkbenchActivityHelper;
+import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
+import org.eclipse.ui.internal.WorkbenchImages;
+
+/**
+ * @since 3.3
+ *
+ */
+public class PreferenceProvider extends QuickAccessProvider {
+
+	private QuickAccessElement[] cachedElements;
+	private Map<String, PreferenceElement> idToElement = new HashMap<>();
+
+	@Override
+	public String getId() {
+		return "org.eclipse.ui.preferences"; //$NON-NLS-1$
+	}
+
+	@Override
+	public QuickAccessElement getElementForId(String id) {
+		getElements();
+		return idToElement.get(id);
+	}
+
+	@Override
+	public QuickAccessElement[] getElements() {
+		if (cachedElements == null) {
+			List<PreferenceElement> list = new ArrayList<>();
+			collectElements("", PlatformUI.getWorkbench().getPreferenceManager().getRootSubNodes(), list); //$NON-NLS-1$
+			cachedElements = new PreferenceElement[list.size()];
+			for (int i = 0; i < list.size(); i++) {
+				PreferenceElement preferenceElement = list.get(i);
+				cachedElements[i] = preferenceElement;
+				idToElement.put(preferenceElement.getId(), preferenceElement);
+			}
+		}
+		return cachedElements;
+	}
+
+	private void collectElements(String prefix, IPreferenceNode[] subNodes,
+			List<PreferenceElement> result) {
+		for (int i = 0; i < subNodes.length; i++) {
+			if (!WorkbenchActivityHelper.filterItem(subNodes[i])) {
+				PreferenceElement preferenceElement = new PreferenceElement(subNodes[i], prefix,
+						this);
+				result.add(preferenceElement);
+				String nestedPrefix = prefix.length() == 0 ? subNodes[i].getLabelText() : (prefix
+						+ "/" + subNodes[i].getLabelText()); //$NON-NLS-1$
+				collectElements(nestedPrefix, subNodes[i].getSubNodes(), result);
+			}
+		}
+	}
+
+	@Override
+	public ImageDescriptor getImageDescriptor() {
+		return WorkbenchImages
+				.getImageDescriptor(IWorkbenchGraphicConstants.IMG_OBJ_NODE);
+	}
+
+	@Override
+	public String getName() {
+		return QuickAccessMessages.QuickAccess_Preferences;
+	}
+
+	@Override
+	protected void doReset() {
+		cachedElements = null;
+		idToElement.clear();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/PreviousPicksProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/PreviousPicksProvider.java
new file mode 100644
index 0000000..d6f9830
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/PreviousPicksProvider.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2013, 2014 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:
+ *     Tom Hochstein (Freescale) - Bug 393703 - NotHandledException selecting inactive command under 'Previous Choices' in Quick access
+ ******************************************************************************/
+
+package org.eclipse.ui.internal.quickaccess;
+
+import java.util.List;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
+import org.eclipse.ui.internal.WorkbenchImages;
+
+class PreviousPicksProvider extends QuickAccessProvider {
+
+	private List<QuickAccessElement> previousPicksList;
+
+	PreviousPicksProvider(List<QuickAccessElement> previousPicksList) {
+		this.previousPicksList = previousPicksList;
+	}
+
+	@Override
+	public QuickAccessElement getElementForId(String id) {
+		return null;
+	}
+
+	@Override
+	public QuickAccessElement[] getElements() {
+		return previousPicksList.toArray(new QuickAccessElement[previousPicksList.size()]);
+	}
+
+	@Override
+	public QuickAccessElement[] getElementsSorted() {
+		return getElements();
+	}
+
+	@Override
+	public String getId() {
+		return "org.eclipse.ui.previousPicks"; //$NON-NLS-1$
+	}
+
+	@Override
+	public ImageDescriptor getImageDescriptor() {
+		return WorkbenchImages.getImageDescriptor(IWorkbenchGraphicConstants.IMG_OBJ_NODE);
+	}
+
+	@Override
+	public String getName() {
+		return QuickAccessMessages.QuickAccess_Previous;
+	}
+
+	@Override
+	protected void doReset() {
+		// operation not applicable for this provider
+	}
+
+	@Override
+	public boolean isAlwaysPresent() {
+		return true;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/PropertiesElement.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/PropertiesElement.java
new file mode 100644
index 0000000..4f6b251
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/PropertiesElement.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.quickaccess;
+
+import org.eclipse.jface.preference.IPreferenceNode;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.dialogs.PropertyDialog;
+
+/**
+ * @since 3.3
+ *
+ */
+public class PropertiesElement extends QuickAccessElement {
+
+	private Object selectedElement;
+	private IPreferenceNode preferenceNode;
+
+	/* package */PropertiesElement(Object selectedElement, IPreferenceNode preferenceNode, PropertiesProvider propertiesProvider) {
+		super(propertiesProvider);
+		this.selectedElement = selectedElement;
+		this.preferenceNode = preferenceNode;
+	}
+
+	@Override
+	public void execute() {
+		IWorkbenchWindow window = PlatformUI.getWorkbench()
+				.getActiveWorkbenchWindow();
+		if (window != null) {
+			PropertyDialog dialog = PropertyDialog.createDialogOn(window
+					.getShell(), preferenceNode.getId(), selectedElement);
+			dialog.open();
+		}
+	}
+
+	@Override
+	public String getId() {
+		return preferenceNode.getId();
+	}
+
+	@Override
+	public ImageDescriptor getImageDescriptor() {
+		Image image = preferenceNode.getLabelImage();
+		if (image != null) {
+			ImageDescriptor descriptor = ImageDescriptor.createFromImage(image);
+			return descriptor;
+		}
+		return null;
+	}
+
+	@Override
+	public String getLabel() {
+		return preferenceNode.getLabelText();
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result
+				+ ((preferenceNode == null) ? 0 : preferenceNode.hashCode());
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		final PropertiesElement other = (PropertiesElement) obj;
+		if (preferenceNode == null) {
+			if (other.preferenceNode != null)
+				return false;
+		} else if (!preferenceNode.equals(other.preferenceNode))
+			return false;
+		return true;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/PropertiesProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/PropertiesProvider.java
new file mode 100644
index 0000000..08a639d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/PropertiesProvider.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.quickaccess;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.eclipse.jface.preference.IPreferenceNode;
+import org.eclipse.jface.preference.PreferenceManager;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.internal.dialogs.PropertyPageContributorManager;
+import org.eclipse.ui.internal.dialogs.PropertyPageManager;
+
+/**
+ * @since 3.3
+ *
+ */
+public class PropertiesProvider extends QuickAccessProvider {
+
+	private Map idToElement;
+
+	@Override
+	public QuickAccessElement getElementForId(String id) {
+		getElements();
+		return (PropertiesElement) idToElement.get(id);
+	}
+
+	@Override
+	public QuickAccessElement[] getElements() {
+		if (idToElement == null) {
+			idToElement = new HashMap();
+			IWorkbenchPage activePage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+			if (activePage != null) {
+				PropertyPageManager pageManager = new PropertyPageManager();
+				ISelection selection = activePage.getSelection();
+				if (selection instanceof IStructuredSelection
+						&& !selection.isEmpty()) {
+					Object element = ((IStructuredSelection) selection).getFirstElement();
+					PropertyPageContributorManager.getManager().contribute(pageManager, element);
+					List list = pageManager.getElements(PreferenceManager.PRE_ORDER);
+					IPreferenceNode[] properties = (IPreferenceNode[]) list.toArray(new IPreferenceNode[list.size()]);
+					for (IPreferenceNode property : properties) {
+						PropertiesElement propertiesElement = new PropertiesElement(
+								element, property, this);
+						idToElement.put(propertiesElement.getId(),
+								propertiesElement);
+					}
+				}
+			}
+		}
+		return (QuickAccessElement[]) idToElement.values().toArray(
+				new QuickAccessElement[idToElement.values().size()]);
+	}
+
+	@Override
+	public String getId() {
+		return "org.eclipse.ui.properties"; //$NON-NLS-1$
+	}
+
+	@Override
+	public ImageDescriptor getImageDescriptor() {
+		return WorkbenchImages
+				.getImageDescriptor(IWorkbenchGraphicConstants.IMG_OBJ_NODE);
+	}
+
+	@Override
+	public String getName() {
+		return QuickAccessMessages.QuickAccess_Properties;
+	}
+
+	@Override
+	protected void doReset() {
+		idToElement = null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/QuickAccessContents.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/QuickAccessContents.java
new file mode 100644
index 0000000..a7e208f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/QuickAccessContents.java
@@ -0,0 +1,879 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2016 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
+ *     Tom Hochstein (Freescale) - Bug 393703 - NotHandledException selecting inactive command under 'Previous Choices' in Quick access
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654, 491272, 491398
+ *     Leung Wang Hei <gemaspecial@yahoo.com.hk> - Bug 483343
+ *     Patrik Suzzi <psuzzi@gmail.com> - Bug 491291, 491529, 491293, 492434, 492452, 459989, 507322
+ *******************************************************************************/
+package org.eclipse.ui.internal.quickaccess;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
+
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.jface.bindings.TriggerSequence;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.TableColumnLayout;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.jface.util.Util;
+import org.eclipse.jface.viewers.ColumnWeightData;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ControlAdapter;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+//import org.eclipse.swt.graphics.TextLayout;
+//import org.eclipse.swt.graphics.TextStyle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.keys.IBindingService;
+
+
+/**
+ * Provides the contents for the quick access shell created by
+ * {@link SearchField}. This was also used by {@link QuickAccessDialog} prior to
+ * e4. The SearchField is responsible for handling opening and closing the shell
+ * as well as setting {@link #setShowAllMatches(boolean)}.
+ */
+public abstract class QuickAccessContents {
+	/**
+	 * When opened in a popup we were given the command used to open it. Now
+	 * that we have a shell, we are just using a hard coded command id.
+	 */
+	private static final String QUICK_ACCESS_COMMAND_ID = "org.eclipse.ui.window.quickAccess"; //$NON-NLS-1$
+	private static final int INITIAL_COUNT_PER_PROVIDER = 5;
+	private static final int MAX_COUNT_TOTAL = 20;
+	/** Minumum length to suggest the user to search typed text in the Help */
+	private static final int MIN_SEARCH_LENGTH = 3;
+
+	protected Text filterText;
+
+	private QuickAccessProvider[] providers;
+
+	protected Table table;
+	protected Label infoLabel;
+
+	private LocalResourceManager resourceManager = new LocalResourceManager(
+			JFaceResources.getResources());
+
+	protected String rememberedText;
+
+	/**
+	 * A color for dulled out items created by mixing the table foreground. Will
+	 * be disposed when the {@link #resourceManager} is disposed.
+	 */
+	private Color grayColor;
+//	private TextLayout textLayout;
+	private boolean showAllMatches = false;
+	protected boolean resized = false;
+	private TriggerSequence keySequence;
+
+	public QuickAccessContents(QuickAccessProvider[] providers) {
+		this.providers = providers;
+	}
+
+	/**
+	 * Returns the number of items the table can fit in its current layout
+	 */
+	private int computeNumberOfItems() {
+		Rectangle rect = table.getClientArea ();
+		int itemHeight = table.getItemHeight ();
+		int headerHeight = table.getHeaderHeight ();
+		return (rect.height - headerHeight + itemHeight - 1) / (itemHeight + table.getGridLineWidth());
+	}
+
+	/**
+	 * Refreshes the contents of the quick access shell
+	 *
+	 * @param filter
+	 *            The filter text to apply to results
+	 *
+	 */
+	public void refresh(String filter) {
+		if (table != null) {
+			boolean filterTextEmpty = filter.length() == 0;
+
+			// extra entry added when the user activates help search
+			// (extensible)
+			List<QuickAccessEntry> extraEntries = new ArrayList<>();
+			if (filter.length() > MIN_SEARCH_LENGTH) {
+				extraEntries.add(makeHelpSearchEntry(filter));
+			}
+
+			// perfect match, to be selected in the table if not null
+			QuickAccessElement perfectMatch = getPerfectMatch(filter);
+
+			List<QuickAccessEntry>[] entries = computeMatchingEntries(filter, perfectMatch, extraEntries);
+			int selectionIndex = refreshTable(perfectMatch, entries, extraEntries);
+
+			if (table.getItemCount() > 0) {
+				table.setSelection(selectionIndex);
+				hideHintText();
+			} else if (filterTextEmpty) {
+				showHintText(QuickAccessMessages.QuickAccess_StartTypingToFindMatches, grayColor);
+			} else {
+				showHintText(QuickAccessMessages.QuickAccessContents_NoMatchingResults, grayColor);
+			}
+
+			// update info as-you-type
+			updateInfoLabel();
+
+			updateFeedback(filterTextEmpty, showAllMatches);
+		}
+	}
+
+	QuickAccessEntry searchHelpEntry = null;
+	QuickAccessProvider searchHelpProvider = null;
+	QuickAccessSearchElement searchHelpElement = null;
+
+	/**
+	 * Instantiate a new {@link QuickAccessEntry} to search the given text in
+	 * the eclipse help
+	 *
+	 * @param text
+	 *            String to search in the Eclipse Help
+	 *
+	 * @return the {@link QuickAccessEntry} to perform the action
+	 */
+	private QuickAccessEntry makeHelpSearchEntry(String text) {
+		if (searchHelpEntry == null) {
+			searchHelpProvider = Stream.of(providers).filter(p -> p instanceof ActionProvider).findFirst().get();
+			searchHelpElement = new QuickAccessSearchElement(searchHelpProvider);
+			searchHelpEntry = new QuickAccessEntry(searchHelpElement, searchHelpProvider, new int[][] {},
+					new int[][] {}, QuickAccessEntry.MATCH_PERFECT);
+		}
+		searchHelpElement.searchText = text;
+		return searchHelpEntry;
+	}
+
+	static class QuickAccessSearchElement extends QuickAccessElement {
+
+		/** identifier */
+		private static final String SEARCH_IN_HELP_ID = "search.in.help"; //$NON-NLS-1$
+
+		String searchText;
+
+		/**
+		 * @param provider
+		 */
+		public QuickAccessSearchElement(QuickAccessProvider provider) {
+			super(provider);
+		}
+
+		@Override
+		public String getLabel() {
+			return NLS.bind(QuickAccessMessages.QuickAccessContents_SearchInHelpLabel, searchText);
+		}
+
+		@Override
+		public String getId() {
+			return SEARCH_IN_HELP_ID;
+		}
+
+		@Override
+		public void execute() {
+			PlatformUI.getWorkbench().getHelpSystem().search(searchText);
+		}
+
+		@Override
+		public ImageDescriptor getImageDescriptor() {
+			return null;
+		}
+
+	}
+
+	/**
+	 * Allows the quick access content owner to mark a quick access element as
+	 * being a perfect match, putting it at the start of the table.
+	 *
+	 * @param filter
+	 *            the filter text used to find a match
+	 * @return an element to be put at the top of the table or <code>null</code>
+	 */
+	protected abstract QuickAccessElement getPerfectMatch(String filter);
+
+	/**
+	 * Notifies the quick access content owner that the contents of the table
+	 * have been changed.
+	 *
+	 * @param filterTextEmpty
+	 *            whether the filter text used to calculate matches was empty
+	 * @param showAllMatches
+	 *            whether the results were constrained by the size of the dialog
+	 *
+	 */
+	protected abstract void updateFeedback(boolean filterTextEmpty, boolean showAllMatches);
+
+	/**
+	 * Sets whether to display all matches to the current filter or limit the
+	 * results. Will refresh the table contents and update the info label.
+	 *
+	 * @param showAll
+	 *            whether to display all matches
+	 */
+	public void setShowAllMatches(boolean showAll) {
+		if (showAllMatches != showAll) {
+			showAllMatches = showAll;
+			updateInfoLabel();
+			refresh(filterText.getText().toLowerCase());
+		}
+	}
+
+	private void updateInfoLabel() {
+		if (infoLabel != null) {
+			TriggerSequence sequence = getTriggerSequence();
+			boolean forceHide = (getNumberOfFilteredResults() == 0)
+					|| (showAllMatches && (table.getItemCount() <= computeNumberOfItems()));
+			if (sequence == null || forceHide) {
+				infoLabel.setText(""); //$NON-NLS-1$
+			} else if (showAllMatches) {
+				infoLabel.setText(
+						NLS.bind(QuickAccessMessages.QuickAccessContents_PressKeyToLimitResults, sequence.format()));
+			} else {
+				infoLabel
+						.setText(NLS.bind(QuickAccessMessages.QuickAccess_PressKeyToShowAllMatches, sequence.format()));
+			}
+			infoLabel.getParent().layout(true);
+		}
+	}
+
+	/**
+	 * Returns the trigger sequence that can be used to open the quick access
+	 * dialog as well as toggle the show all results feature. Can return
+	 * <code>null</code> if no trigger sequence is known.
+	 *
+	 * @return the trigger sequence used to open the quick access or
+	 *         <code>null</code>
+	 */
+	public TriggerSequence getTriggerSequence() {
+		if (keySequence == null) {
+			IBindingService bindingService =
+					Adapters.adapt(PlatformUI.getWorkbench(), IBindingService.class);
+			keySequence = bindingService.getBestActiveBindingFor(QUICK_ACCESS_COMMAND_ID);
+		}
+		return keySequence;
+	}
+
+	/**
+	 * Return whether the shell is currently set to display all matches or limit
+	 * the results.
+	 *
+	 * @return whether all matches will be displayed
+	 */
+	public boolean getShowAllMatches() {
+		return showAllMatches;
+	}
+
+	private int refreshTable(QuickAccessElement perfectMatch, List<QuickAccessEntry>[] entries,
+			List<QuickAccessEntry> extraEntries) {
+		// search help extra entry: not from search or previous picks.
+		int nExtraEntries = (extraEntries == null) ? 0 : extraEntries.size();
+		if (table.getItemCount() > (entries.length + nExtraEntries)
+				&& table.getItemCount() - (entries.length + nExtraEntries) > 20) {
+			table.removeAll();
+		}
+		TableItem[] items = table.getItems();
+		int selectionIndex = -1;
+		int index = 0;
+		for (int i = 0; i < providers.length; i++) {
+			if (entries[i] != null) {
+				boolean firstEntry = true;
+				for (Iterator<QuickAccessEntry> it = entries[i].iterator(); it.hasNext();) {
+					QuickAccessEntry entry = it.next();
+					entry.firstInCategory = firstEntry;
+					firstEntry = false;
+					if (!it.hasNext()) {
+						entry.lastInCategory = true;
+					}
+					TableItem item;
+					if (index < items.length) {
+						item = items[index];
+						table.clear(index);
+					} else {
+						item = new TableItem(table, SWT.NONE);
+					}
+					if (perfectMatch == entry.element && selectionIndex == -1) {
+						selectionIndex = index;
+					}
+					item.setData(entry);
+					item.setText(0, entry.provider.getName());
+					item.setText(1, entry.element.getLabel());
+					if (Util.isWpf()) {
+						item.setImage(1, entry.getImage(entry.element,
+							resourceManager));
+					}
+					index++;
+				}
+			}
+		}
+		// add extra entry
+		for (QuickAccessEntry entry : extraEntries) {
+			TableItem item = new TableItem(table, SWT.NONE);
+			item.setData(entry);
+		}
+		if (index < items.length) {
+			table.remove(index, items.length - 1);
+		}
+		if (selectionIndex == -1) {
+			selectionIndex = 0;
+		}
+		return selectionIndex;
+	}
+
+	int numberOfFilteredResults;
+
+	/**
+	 * Compute how many items are effectively filtered at a specific point in
+	 * time. So doing, the quick access content can perform operations that
+	 * depends on this number, i.e. hide the info label.
+	 *
+	 * @return number number of elements filtered
+	 */
+	protected int getNumberOfFilteredResults() {
+		return numberOfFilteredResults;
+	}
+
+	/**
+	 * Returns a list per provider containing matching {@link QuickAccessEntry}
+	 * that should be displayed in the table given a text filter and a perfect
+	 * match entry that should be given priority. The number of items returned
+	 * is affected by {@link #getShowAllMatches()} and the size of the table's
+	 * composite.
+	 *
+	 * @param filter
+	 *            the string text filter to apply, possibly empty
+	 * @param perfectMatch
+	 *            a quick access element that should be given priority or
+	 *            <code>null</code>
+	 * @param extraEntries
+	 *            extra entries that will be added to the tabular visualization
+	 *            after computing matching entries, i.e. Search in Help
+	 * @return the array of lists (one per provider) contains the quick access
+	 *         entries that should be added to the table, possibly empty
+	 */
+	private List<QuickAccessEntry>[] computeMatchingEntries(String filter,
+			QuickAccessElement perfectMatch, List<QuickAccessEntry> extraEntries) {
+		// collect matches in an array of lists
+		@SuppressWarnings("unchecked")
+		List<QuickAccessEntry>[] entries = new List[providers.length];
+		// extra entries are limiting the number of items for search results
+		int maxCount = computeNumberOfItems() - extraEntries.size();
+		int[] indexPerProvider = new int[providers.length];
+		int countPerProvider = Math.min(maxCount / 4, INITIAL_COUNT_PER_PROVIDER);
+		int prevPick = 0;
+		int countTotal = 0;
+		boolean perfectMatchAdded = true;
+		if (perfectMatch != null) {
+			// reserve one entry for the perfect match
+			maxCount--;
+			perfectMatchAdded = false;
+		}
+		boolean done;
+		String category = null;
+		Set<String> prevPickIds = new HashSet<>();
+		do {
+			// will be set to false if we find a provider with remaining
+			// elements
+			done = true;
+			// check for a category filter, like "Views: "
+			Matcher categoryMatcher = getCategoryPattern().matcher(filter);
+			if (categoryMatcher.matches()) {
+				category = categoryMatcher.group(1);
+				filter = category + " " + categoryMatcher.group(2); //$NON-NLS-1$
+			}
+			for (int i = 0; i < providers.length
+					&& (showAllMatches || countTotal < maxCount); i++) {
+				if (entries[i] == null) {
+					entries[i] = new ArrayList<>();
+					indexPerProvider[i] = 0;
+				}
+				int count = 0;
+				QuickAccessProvider provider = providers[i];
+				// when category is specified, skip providers except the
+				// specified one and the previous pick provider
+				boolean isPreviousPickProvider = (provider instanceof PreviousPicksProvider);
+				if (category != null && !category.equalsIgnoreCase(provider.getName()) && !isPreviousPickProvider) {
+					continue;
+				}
+				if (filter.length() > 0 || provider.isAlwaysPresent() || showAllMatches) {
+					QuickAccessElement[] sortedElements = provider.getElementsSorted();
+
+					// count previous picks and store ids
+					if (isPreviousPickProvider) {
+						prevPick = sortedElements.length;
+						Stream.of(sortedElements).forEach(e -> prevPickIds.add(e.getId()));
+					}
+
+					int j = indexPerProvider[i];
+					// loops on all the elements of a provider
+					while (j < sortedElements.length
+							&& (showAllMatches || (count < countPerProvider && countTotal < maxCount))) {
+						QuickAccessElement element = sortedElements[j];
+
+						// Skip element if already in contained amid previous picks
+						if (!isPreviousPickProvider && prevPickIds.contains(element.getId())) {
+							j++;
+							continue;
+						}
+
+						QuickAccessEntry entry = null;
+						if (filter.length() == 0) {
+							if (i == 0 || showAllMatches) {
+								entry = new QuickAccessEntry(element, provider, new int[0][0],
+										new int[0][0], QuickAccessEntry.MATCH_PERFECT);
+							} else {
+								entry = null;
+							}
+						} else {
+							QuickAccessEntry possibleMatch = element.match(filter, provider);
+							if (possibleMatch != null) {
+								entry = possibleMatch;
+							}
+
+						}
+						if (entryEnabled(provider, entry)) {
+							entries[i].add(entry);
+							count++;
+							countTotal++;
+							if (i == 0 && entry.element == perfectMatch) {
+								perfectMatchAdded = true;
+								maxCount = MAX_COUNT_TOTAL;
+							}
+						}
+
+						j++;
+					}
+
+					indexPerProvider[i] = j;
+
+					if (j < sortedElements.length) {
+						done = false;
+					}
+				}
+			}
+
+			// from now on, add one element per provider
+			countPerProvider = 1;
+
+		} while ((showAllMatches || countTotal < maxCount) && !done);
+
+		if (!perfectMatchAdded) {
+			QuickAccessEntry entry = perfectMatch.match(filter, providers[0]);
+			if (entryEnabled(providers[0], entry)) {
+				if (entries[0] == null) {
+					entries[0] = new ArrayList<>();
+					indexPerProvider[0] = 0;
+				}
+				entries[0].add(entry);
+			}
+		}
+
+		// number of items matching the filtered search
+		numberOfFilteredResults = countTotal - prevPick;
+		return entries;
+	}
+
+	Pattern categoryPattern;
+
+	/**
+	 * Return a pattern like {@code "^(:?Views|Perspective):\\s?(.*)"}, with all
+	 * the provider names separated by semicolon.
+	 *
+	 * @return Returns the patternProvider.
+	 */
+	protected Pattern getCategoryPattern() {
+		if (categoryPattern == null) {
+			// build regex like "^(:?Views|Perspective):\\s?(.*)"
+			StringBuilder sb = new StringBuilder();
+			sb.append("^(:?"); //$NON-NLS-1$
+			for (int i = 0; i < providers.length; i++) {
+				if (i != 0)
+					sb.append("|"); //$NON-NLS-1$
+				sb.append(providers[i].getName());
+			}
+			sb.append("):\\s?(.*)"); //$NON-NLS-1$
+			String regex = sb.toString();
+			categoryPattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
+		}
+		return categoryPattern;
+	}
+
+	/**
+	 * @param provider
+	 * @param entry
+	 * @return <code>true</code> if the entry is enabled
+	 */
+	private boolean entryEnabled(QuickAccessProvider provider, QuickAccessEntry entry) {
+		if (entry == null) {
+			return false;
+		}
+
+		// For a previous pick provider, check that the original provider does
+		// also provide the element
+		if (provider instanceof PreviousPicksProvider) {
+			QuickAccessElement element = entry.element;
+			final QuickAccessProvider originalProvider = element.getProvider();
+			QuickAccessElement match = originalProvider.getElementForId(element.getId());
+			return match != null;
+		}
+
+		return true;
+	}
+
+	private void doDispose() {
+//		if (textLayout != null && !textLayout.isDisposed()) {
+//			textLayout.dispose();
+//		}
+		if (resourceManager != null) {
+			// Disposing the resource manager will dispose the color
+			resourceManager.dispose();
+			resourceManager = null;
+		}
+	}
+
+	protected IDialogSettings getDialogSettings() {
+		final IDialogSettings workbenchDialogSettings = WorkbenchPlugin
+				.getDefault().getDialogSettings();
+		IDialogSettings result = workbenchDialogSettings.getSection(getId());
+		if (result == null) {
+			result = workbenchDialogSettings.addNewSection(getId());
+		}
+		return result;
+	}
+
+	protected String getId() {
+		return "org.eclipse.ui.internal.QuickAccess"; //$NON-NLS-1$
+	}
+
+	protected abstract void handleElementSelected(String text, Object selectedElement);
+
+	private void handleSelection() {
+		QuickAccessElement selectedElement = null;
+		String text = filterText.getText().toLowerCase();
+		if (table.getSelectionCount() == 1) {
+			QuickAccessEntry entry = (QuickAccessEntry) table
+					.getSelection()[0].getData();
+			selectedElement = entry == null ? null : entry.element;
+		}
+		if (selectedElement != null) {
+			doClose();
+			handleElementSelected(text, selectedElement);
+		}
+	}
+
+	/**
+	 * Should be called by the owner of the parent composite when the shell is
+	 * being activated (made visible). This allows the show all keybinding to be
+	 * updated.
+	 */
+	public void preOpen() {
+		// Make sure we always start filtering
+		setShowAllMatches(false);
+		// In case the key binding has changed, update the label
+		keySequence = null;
+		updateInfoLabel();
+	}
+
+	/**
+	 * Informs the owner of the parent composite that the quick access dialog
+	 * should be closed
+	 */
+	protected abstract void doClose();
+
+	/**
+	 * Allows the dialog contents to interact correctly with the text box used to open it
+	 * @param filterText text box to hook up
+	 */
+	public void hookFilterText(Text filterText) {
+		this.filterText = filterText;
+		filterText.addKeyListener(new KeyListener() {
+			@Override
+			public void keyPressed(KeyEvent e) {
+				switch (e.keyCode) {
+				case SWT.CR:
+				case SWT.KEYPAD_CR:
+					handleSelection();
+					break;
+				case SWT.ARROW_DOWN:
+					int index = table.getSelectionIndex();
+					if (index != -1 && table.getItemCount() > index + 1) {
+						table.setSelection(index + 1);
+					}
+					break;
+				case SWT.ARROW_UP:
+					index = table.getSelectionIndex();
+					if (index != -1 && index >= 1) {
+						table.setSelection(index - 1);
+					}
+					break;
+				case SWT.ESC:
+					doClose();
+					break;
+				}
+			}
+
+			@Override
+			public void keyReleased(KeyEvent e) {
+				// do nothing
+			}
+		});
+		filterText.addModifyListener(e -> {
+			String text = ((Text) e.widget).getText().toLowerCase();
+			refresh(text);
+		});
+	}
+
+	private Text hintText;
+	private boolean displayHintText;
+
+	/** Create HintText as child of the given parent composite */
+	Text createHintText(Composite composite, int defaultOrientation) {
+		hintText = new Text(composite, SWT.FILL);
+		hintText.setOrientation(defaultOrientation);
+		displayHintText = true;
+		return hintText;
+	}
+
+	/** Hide the hint text */
+	void hideHintText() {
+		if (displayHintText) {
+			setHintTextToDisplay(false);
+		}
+	}
+
+	/** Show the hint text with the given color */
+	void showHintText(String text, Color color) {
+		if (hintText == null) {
+			// toolbar hidden
+			return;
+		}
+		hintText.setText(text);
+		if (color != null) {
+			hintText.setForeground(color);
+		}
+		if (!displayHintText) {
+			setHintTextToDisplay(true);
+		}
+	}
+
+	/**
+	 * Sets hint text to be displayed and requests the layout
+	 *
+	 * @param toDisplay
+	 */
+	private void setHintTextToDisplay(boolean toDisplay) {
+		GridData data = (GridData) hintText.getLayoutData();
+		data.exclude = !toDisplay;
+		hintText.setVisible(toDisplay);
+		hintText.requestLayout();
+		this.displayHintText = toDisplay;
+	}
+
+	/**
+	 * Creates the table providing the contents for the quick access dialog
+	 *
+	 * @param composite parent composite with {@link GridLayout}
+	 * @param defaultOrientation the window orientation to use for the table {@link SWT#RIGHT_TO_LEFT} or {@link SWT#LEFT_TO_RIGHT}
+	 * @return the created table
+	 */
+	public Table createTable(Composite composite, int defaultOrientation) {
+		composite.addDisposeListener(e -> doDispose());
+		Composite tableComposite = new Composite(composite, SWT.NONE);
+		GridDataFactory.fillDefaults().grab(true, true).applyTo(tableComposite);
+		TableColumnLayout tableColumnLayout = new TableColumnLayout();
+		tableComposite.setLayout(tableColumnLayout);
+		table = new Table(tableComposite, SWT.SINGLE | SWT.FULL_SELECTION);
+//		textLayout = new TextLayout(table.getDisplay());
+//		textLayout.setOrientation(defaultOrientation);
+//		Font boldFont = resourceManager.createFont(FontDescriptor.createFrom(
+//				table.getFont()).setStyle(SWT.BOLD));
+//		textLayout.setFont(table.getFont());
+//		textLayout.setText(QuickAccessMessages.QuickAccess_AvailableCategories);
+//		int maxProviderWidth = (textLayout.getBounds().width);
+//		textLayout.setFont(boldFont);
+//		for (QuickAccessProvider provider : providers) {
+//			textLayout.setText(provider.getName());
+//			int width = (textLayout.getBounds().width);
+//			if (width > maxProviderWidth) {
+//				maxProviderWidth = width;
+//			}
+//		}
+//		tableColumnLayout.setColumnData(new TableColumn(table, SWT.NONE), new ColumnWeightData(0, maxProviderWidth));
+		tableColumnLayout.setColumnData(new TableColumn(table, SWT.NONE), new ColumnWeightData(100, 100));
+		table.getShell().addControlListener(new ControlAdapter() {
+			@Override
+			public void controlResized(ControlEvent e) {
+				if (!showAllMatches) {
+					if (!resized) {
+						resized = true;
+						e.display.timerExec(100, () -> {
+							if (table != null && !table.isDisposed() && filterText !=null && !filterText.isDisposed()) {
+								refresh(filterText.getText().toLowerCase());
+							}
+							resized = false;
+						});
+					}
+				}
+			}
+		});
+
+		table.addKeyListener(new KeyListener() {
+			@Override
+			public void keyPressed(KeyEvent e) {
+				if (e.keyCode == SWT.ARROW_UP && table.getSelectionIndex() == 0) {
+					filterText.setFocus();
+				} else if (e.character == SWT.ESC) {
+					doClose();
+				}
+			}
+
+			@Override
+			public void keyReleased(KeyEvent e) {
+				// do nothing
+			}
+		});
+		table.addMouseListener(new MouseAdapter() {
+			@Override
+			public void mouseUp(MouseEvent e) {
+
+				if (table.getSelectionCount() < 1)
+					return;
+
+				if (e.button != 1)
+					return;
+
+				if (table.equals(e.getSource())) {
+					Object o = table.getItem(new Point(e.x, e.y));
+					TableItem selection = table.getSelection()[0];
+					if (selection.equals(o))
+						handleSelection();
+				}
+			}
+		});
+
+//		table.addMouseMoveListener(new MouseMoveListener() {
+//			TableItem lastItem = null;
+//
+//			@Override
+//			public void mouseMove(MouseEvent e) {
+//				if (table.equals(e.getSource())) {
+//					Object o = table.getItem(new Point(e.x, e.y));
+//					if (lastItem == null ^ o == null) {
+//						table.setCursor(o == null ? null : table.getDisplay().getSystemCursor(
+//								SWT.CURSOR_HAND));
+//					}
+//					if (o instanceof TableItem) {
+//						if (!o.equals(lastItem)) {
+//							lastItem = (TableItem) o;
+//							table.setSelection(new TableItem[] { lastItem });
+//						}
+//					} else if (o == null) {
+//						lastItem = null;
+//					}
+//				}
+//			}
+//		});
+
+		table.addSelectionListener(new SelectionListener() {
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				// do nothing
+			}
+
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {
+				handleSelection();
+			}
+		});
+
+//		final TextStyle boldStyle;
+//		if (PlatformUI.getPreferenceStore().getBoolean(
+//				IWorkbenchPreferenceConstants.USE_COLORED_LABELS)) {
+//			boldStyle = new TextStyle(boldFont, null, null);
+//			grayColor = resourceManager.createColor(ColorUtil.blend(table.getBackground().getRGB(),
+//					table.getForeground().getRGB()));
+//		} else {
+//			boldStyle = null;
+//		}
+//		Listener listener = event -> {
+//			QuickAccessEntry entry = (QuickAccessEntry) event.item.getData();
+//			if (entry != null) {
+//				switch (event.type) {
+//				case SWT.MeasureItem:
+//					entry.measure(event, textLayout, resourceManager, boldStyle);
+//					break;
+//				case SWT.PaintItem:
+//					entry.paint(event, textLayout, resourceManager, boldStyle, grayColor);
+//					break;
+//				case SWT.EraseItem:
+//					entry.erase(event);
+//					break;
+//				}
+//			}
+//		};
+//		table.addListener(SWT.MeasureItem, listener);
+//		table.addListener(SWT.EraseItem, listener);
+//		table.addListener(SWT.PaintItem, listener);
+
+		return table;
+	}
+
+	/**
+	 * Creates a label which will display the key binding to expand
+	 * the search results.
+	 *
+	 * @param parent parent composite with {@link GridLayout}
+	 * @return the created label
+	 */
+	public Label createInfoLabel(Composite parent) {
+		infoLabel = new Label(parent, SWT.NONE);
+		infoLabel.setFont(parent.getFont());
+		infoLabel.setForeground(grayColor);
+		infoLabel.setBackground(table.getBackground());
+		GridData gd = new GridData(GridData.FILL_HORIZONTAL);
+		gd.horizontalAlignment = SWT.RIGHT;
+		gd.grabExcessHorizontalSpace = false;
+		infoLabel.setLayoutData(gd);
+		updateInfoLabel();
+		return infoLabel;
+	}
+
+	public void resetProviders() {
+		for (QuickAccessProvider provider : providers) {
+			provider.reset();
+		}
+	}
+
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/QuickAccessDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/QuickAccessDialog.java
new file mode 100644
index 0000000..dd57c0a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/QuickAccessDialog.java
@@ -0,0 +1,411 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2016 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
+ *     Tom Hochstein (Freescale) - Bug 393703 - NotHandledException selecting inactive command under 'Previous Choices' in Quick access
+ *     René Brandstetter - Bug 433778
+ *     Patrik Suzzi <psuzzi@gmail.com> - Bug 491410
+ *******************************************************************************/
+package org.eclipse.ui.internal.quickaccess;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.e4.core.commands.ExpressionContext;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
+import org.eclipse.jface.bindings.TriggerSequence;
+import org.eclipse.jface.bindings.keys.KeySequence;
+import org.eclipse.jface.bindings.keys.SWTKeySupport;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.dialogs.PopupDialog;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.jface.util.Util;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.graphics.FontMetrics;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.WorkbenchWindow;
+import org.eclipse.ui.internal.progress.ProgressManagerUtil;
+import org.eclipse.ui.keys.IBindingService;
+
+/**
+ * This is the quick access popup dialog used in 3.x. The new quick access is
+ * done through a shell in {@link SearchField}.
+ *
+ * @since 3.3
+ *
+ */
+public class QuickAccessDialog extends PopupDialog {
+	private TriggerSequence[] invokingCommandKeySequences;
+	private Command invokingCommand;
+	private QuickAccessContents contents;
+	private KeyAdapter keyAdapter;
+	private Text filterText;
+	private IWorkbenchWindow window;
+	private LinkedList previousPicksList = new LinkedList();
+	private static final String TEXT_ARRAY = "textArray"; //$NON-NLS-1$
+	private static final String TEXT_ENTRIES = "textEntries"; //$NON-NLS-1$
+	private static final String ORDERED_PROVIDERS = "orderedProviders"; //$NON-NLS-1$
+	private static final String ORDERED_ELEMENTS = "orderedElements"; //$NON-NLS-1$
+	static final int MAXIMUM_NUMBER_OF_ELEMENTS = 60;
+	static final int MAXIMUM_NUMBER_OF_TEXT_ENTRIES_PER_ELEMENT = 3;
+	protected Map textMap = new HashMap();
+	protected Map elementMap = new HashMap();
+	protected Map providerMap;
+
+	public QuickAccessDialog(final IWorkbenchWindow window, final Command invokingCommand) {
+		super(ProgressManagerUtil.getDefaultParent(), SWT.RESIZE, true, true, // persist
+																				// size
+				false, // but not location
+				true, true, null, QuickAccessMessages.QuickAccess_StartTypingToFindMatches);
+		this.window = window;
+
+		WorkbenchWindow workbenchWindow = (WorkbenchWindow) window;
+		final MWindow model = workbenchWindow.getModel();
+
+		BusyIndicator.showWhile(window.getShell() == null ? null : window.getShell().getDisplay(),
+				() -> {
+					final CommandProvider commandProvider = new CommandProvider();
+					commandProvider.setSnapshot(new ExpressionContext(model.getContext()
+							.getActiveLeaf()));
+					QuickAccessProvider[] providers = new QuickAccessProvider[] {
+							new PreviousPicksProvider(previousPicksList),
+							new EditorProvider(),
+							new ViewProvider(model.getContext().get(MApplication.class), model),
+							new PerspectiveProvider(), commandProvider, new ActionProvider(),
+							new WizardProvider(), new PreferenceProvider(),
+							new PropertiesProvider() };
+					providerMap = new HashMap();
+					for (QuickAccessProvider provider : providers) {
+						providerMap.put(provider.getId(), provider);
+					}
+					QuickAccessDialog.this.contents = new QuickAccessContents(providers) {
+						@Override
+						protected void updateFeedback(boolean filterTextEmpty,
+								boolean showAllMatches) {
+							if (filterTextEmpty) {
+								setInfoText(QuickAccessMessages.QuickAccess_StartTypingToFindMatches);
+							} else {
+								TriggerSequence[] sequences = getInvokingCommandKeySequences();
+								if (showAllMatches || sequences == null
+										|| sequences.length == 0) {
+									setInfoText(""); //$NON-NLS-1$
+								} else {
+									setInfoText(NLS
+											.bind(QuickAccessMessages.QuickAccess_PressKeyToShowAllMatches,
+													sequences[0].format()));
+								}
+							}
+						}
+
+						@Override
+						protected void doClose() {
+							QuickAccessDialog.this.close();
+						}
+
+						/**
+						 * @param element
+						 */
+						void addPreviousPick(String text, Object element) {
+							// previousPicksList:
+							// Remove element from previousPicksList so
+							// there are no duplicates
+							// If list is max size, remove last(oldest)
+							// element
+							// Remove entries for removed element from
+							// elementMap and textMap
+							// Add element to front of previousPicksList
+							previousPicksList.remove(element);
+							if (previousPicksList.size() == MAXIMUM_NUMBER_OF_ELEMENTS) {
+								Object removedElement = previousPicksList.removeLast();
+								ArrayList removedList = (ArrayList) textMap
+										.remove(removedElement);
+								for (int i = 0; i < removedList.size(); i++) {
+									elementMap.remove(removedList.get(i));
+								}
+							}
+							previousPicksList.addFirst(element);
+
+							// textMap:
+							// Get list of strings for element from textMap
+							// Create new list for element if there isn't
+							// one and put
+							// element->textList in textMap
+							// Remove rememberedText from list
+							// If list is max size, remove first(oldest)
+							// string
+							// Remove text from elementMap
+							// Add rememberedText to list of strings for
+							// element in textMap
+							ArrayList textList = (ArrayList) textMap.get(element);
+							if (textList == null) {
+								textList = new ArrayList();
+								textMap.put(element, textList);
+							}
+
+							textList.remove(text);
+							if (textList.size() == MAXIMUM_NUMBER_OF_TEXT_ENTRIES_PER_ELEMENT) {
+								Object removedText = textList.remove(0);
+								elementMap.remove(removedText);
+							}
+
+							if (text.length() > 0) {
+								textList.add(text);
+
+								// elementMap:
+								// Put rememberedText->element in elementMap
+								// If it replaced a different element update
+								// textMap and
+								// PreviousPicksList
+								Object replacedElement = elementMap.put(text, element);
+								if (replacedElement != null && !replacedElement.equals(element)) {
+									textList = (ArrayList) textMap.get(replacedElement);
+									if (textList != null) {
+										textList.remove(text);
+										if (textList.isEmpty()) {
+											textMap.remove(replacedElement);
+											previousPicksList.remove(replacedElement);
+										}
+									}
+								}
+							}
+						}
+
+						@Override
+						protected QuickAccessElement getPerfectMatch(String filter) {
+							QuickAccessElement perfectMatch = (QuickAccessElement) elementMap
+									.get(filter);
+							return perfectMatch;
+						}
+
+						@Override
+						protected void handleElementSelected(String text, Object selectedElement) {
+							if (selectedElement instanceof QuickAccessElement) {
+								addPreviousPick(text, selectedElement);
+								storeDialog(getDialogSettings());
+
+								/*
+								 * Execute after the dialog has been fully
+								 * closed/disposed and the correct
+								 * EclipseContext is in place.
+								 */
+								final QuickAccessElement element = (QuickAccessElement) selectedElement;
+								window.getShell().getDisplay().asyncExec(() -> element.execute());
+							}
+						}
+					};
+					restoreDialog();
+					QuickAccessDialog.this.invokingCommand = invokingCommand;
+					if (QuickAccessDialog.this.invokingCommand != null
+							&& !QuickAccessDialog.this.invokingCommand.isDefined()) {
+						QuickAccessDialog.this.invokingCommand = null;
+					} else {
+						// Pre-fetch key sequence - do not change because
+						// scope will
+						// change later.
+						getInvokingCommandKeySequences();
+					}
+					// create early
+					create();
+				});
+		QuickAccessDialog.this.contents.refresh(""); //$NON-NLS-1$
+	}
+
+	@Override
+	protected Control createTitleControl(Composite parent) {
+		filterText = new Text(parent, SWT.NONE);
+
+		GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).grab(true, false)
+				.applyTo(filterText);
+
+		contents.hookFilterText(filterText);
+		filterText.addKeyListener(getKeyAdapter());
+
+		return filterText;
+	}
+
+	@Override
+	protected Control createDialogArea(Composite parent) {
+		Composite composite = (Composite) super.createDialogArea(parent);
+		boolean isWin32 = Util.isWindows();
+		GridLayoutFactory.fillDefaults().extendedMargins(isWin32 ? 0 : 3, 3, 2, 2)
+				.applyTo(composite);
+
+		Table table = contents.createTable(composite, getDefaultOrientation());
+		table.addKeyListener(getKeyAdapter());
+
+		return composite;
+	}
+
+	final protected TriggerSequence[] getInvokingCommandKeySequences() {
+		if (invokingCommandKeySequences == null) {
+			if (invokingCommand != null) {
+				IBindingService bindingService =
+						Adapters.adapt(window.getWorkbench(), IBindingService.class);
+				invokingCommandKeySequences = bindingService.getActiveBindingsFor(invokingCommand.getId());
+			}
+		}
+		return invokingCommandKeySequences;
+	}
+
+	private KeyAdapter getKeyAdapter() {
+		if (keyAdapter == null) {
+			keyAdapter = new KeyAdapter() {
+				@Override
+				public void keyPressed(KeyEvent e) {
+					int accelerator = SWTKeySupport.convertEventToUnmodifiedAccelerator(e);
+					KeySequence keySequence = KeySequence.getInstance(SWTKeySupport
+							.convertAcceleratorToKeyStroke(accelerator));
+					TriggerSequence[] sequences = getInvokingCommandKeySequences();
+					if (sequences == null)
+						return;
+					for (TriggerSequence sequence : sequences) {
+						if (sequence.equals(keySequence)) {
+							e.doit = false;
+							contents.setShowAllMatches(!contents.getShowAllMatches());
+							return;
+						}
+					}
+				}
+			};
+		}
+		return keyAdapter;
+	}
+
+	@Override
+	protected Control getFocusControl() {
+		return filterText;
+	}
+
+	@Override
+	public boolean close() {
+		storeDialog(getDialogSettings());
+		return super.close();
+	}
+
+	@Override
+	protected Point getDefaultSize() {
+		GC gc = new GC(getContents());
+		FontMetrics fontMetrics = gc.getFontMetrics();
+		gc.dispose();
+		int x = Dialog.convertHorizontalDLUsToPixels(fontMetrics, 300);
+		if (x < 350) {
+			x = 350;
+		}
+		int y = Dialog.convertVerticalDLUsToPixels(fontMetrics, 270);
+		if (y < 420) {
+			y = 420;
+		}
+		return new Point(x, y);
+	}
+
+	@Override
+	protected Point getDefaultLocation(Point initialSize) {
+		Point size = new Point(400, 400);
+		Rectangle parentBounds = getParentShell().getBounds();
+		int x = parentBounds.x + parentBounds.width / 2 - size.x / 2;
+		int y = parentBounds.y + parentBounds.height / 2 - size.y / 2;
+		return new Point(x, y);
+	}
+
+	@Override
+	protected IDialogSettings getDialogSettings() {
+		final IDialogSettings workbenchDialogSettings = WorkbenchPlugin.getDefault()
+				.getDialogSettings();
+		IDialogSettings result = workbenchDialogSettings.getSection(getId());
+		if (result == null) {
+			result = workbenchDialogSettings.addNewSection(getId());
+		}
+		return result;
+	}
+
+	protected String getId() {
+		return "org.eclipse.ui.internal.QuickAccess"; //$NON-NLS-1$
+	}
+
+	private void storeDialog(IDialogSettings dialogSettings) {
+		String[] orderedElements = new String[previousPicksList.size()];
+		String[] orderedProviders = new String[previousPicksList.size()];
+		String[] textEntries = new String[previousPicksList.size()];
+		ArrayList arrayList = new ArrayList();
+		for (int i = 0; i < orderedElements.length; i++) {
+			QuickAccessElement quickAccessElement = (QuickAccessElement) previousPicksList.get(i);
+			ArrayList elementText = (ArrayList) textMap.get(quickAccessElement);
+			Assert.isNotNull(elementText);
+			orderedElements[i] = quickAccessElement.getId();
+			orderedProviders[i] = quickAccessElement.getProvider().getId();
+			arrayList.addAll(elementText);
+			textEntries[i] = elementText.size() + ""; //$NON-NLS-1$
+		}
+		String[] textArray = (String[]) arrayList.toArray(new String[arrayList.size()]);
+		dialogSettings.put(ORDERED_ELEMENTS, orderedElements);
+		dialogSettings.put(ORDERED_PROVIDERS, orderedProviders);
+		dialogSettings.put(TEXT_ENTRIES, textEntries);
+		dialogSettings.put(TEXT_ARRAY, textArray);
+	}
+
+	private void restoreDialog() {
+		IDialogSettings dialogSettings = getDialogSettings();
+		if (dialogSettings != null) {
+			String[] orderedElements = dialogSettings.getArray(ORDERED_ELEMENTS);
+			String[] orderedProviders = dialogSettings.getArray(ORDERED_PROVIDERS);
+			String[] textEntries = dialogSettings.getArray(TEXT_ENTRIES);
+			String[] textArray = dialogSettings.getArray(TEXT_ARRAY);
+			elementMap = new HashMap();
+			textMap = new HashMap();
+			previousPicksList = new LinkedList();
+			if (orderedElements != null && orderedProviders != null && textEntries != null
+					&& textArray != null) {
+				int arrayIndex = 0;
+				for (int i = 0; i < orderedElements.length; i++) {
+					QuickAccessProvider quickAccessProvider = (QuickAccessProvider) providerMap
+							.get(orderedProviders[i]);
+					int numTexts = Integer.parseInt(textEntries[i]);
+					if (quickAccessProvider != null) {
+						QuickAccessElement quickAccessElement = quickAccessProvider
+								.getElementForId(orderedElements[i]);
+						if (quickAccessElement != null) {
+							ArrayList arrayList = new ArrayList();
+							for (int j = arrayIndex; j < arrayIndex + numTexts; j++) {
+								String text = textArray[j];
+								// text length can be zero for old workspaces,
+								// see bug 190006
+								if (text.length() > 0) {
+									arrayList.add(text);
+									elementMap.put(text, quickAccessElement);
+								}
+							}
+							textMap.put(quickAccessElement, arrayList);
+							previousPicksList.add(quickAccessElement);
+						}
+					}
+					arrayIndex += numTexts;
+				}
+			}
+		}
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/QuickAccessElement.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/QuickAccessElement.java
new file mode 100644
index 0000000..711f5b4
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/QuickAccessElement.java
@@ -0,0 +1,263 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2016 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
+ *     Patrik Suzzi <psuzzi@gmail.com> - Bug 500661, 492180
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.quickaccess;
+
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+import org.eclipse.jface.resource.ImageDescriptor;
+
+/**
+ * @since 3.3
+ *
+ */
+public abstract class QuickAccessElement {
+
+	static final String separator = " - "; //$NON-NLS-1$
+
+	private static final int[][] EMPTY_INDICES = new int[0][0];
+	private QuickAccessProvider provider;
+
+	/**
+	 * @param provider
+	 */
+	public QuickAccessElement(QuickAccessProvider provider) {
+		super();
+		this.provider = provider;
+	}
+
+	/**
+	 * Returns the label to be displayed to the user.
+	 *
+	 * @return the label
+	 */
+	public abstract String getLabel();
+
+	/**
+	 * Returns the image descriptor for this element.
+	 *
+	 * @return an image descriptor, or null if no image is available
+	 */
+	public abstract ImageDescriptor getImageDescriptor();
+
+	/**
+	 * Returns the id for this element. The id has to be unique within the
+	 * QuickAccessProvider that provided this element.
+	 *
+	 * @return the id
+	 */
+	public abstract String getId();
+
+	/**
+	 * Executes the associated action for this element.
+	 */
+	public abstract void execute();
+
+	/**
+	 * Return the label to be used for sorting elements.
+	 *
+	 * @return the sort label
+	 */
+	public String getSortLabel() {
+		return getLabel();
+	}
+
+	/**
+	 * @return Returns the provider.
+	 */
+	public QuickAccessProvider getProvider() {
+		return provider;
+	}
+
+	private static final String WS_START = "^\\s+"; //$NON-NLS-1$
+	private static final String WS_END = "\\s+$"; //$NON-NLS-1$
+	private static final String ANY_WS = "\\s+"; //$NON-NLS-1$
+	private static final String EMPTY_STR = ""; //$NON-NLS-1$
+	private static final String PAR_START = "\\("; //$NON-NLS-1$
+	private static final String PAR_END = "\\)"; //$NON-NLS-1$
+	private static final String ONE_CHAR = ".?"; //$NON-NLS-1$
+
+	// whitespaces filter and patterns
+	private String wsFilter;
+	private Pattern wsPattern;
+
+	/**
+	 * Get the existing {@link Pattern} for the given filter, or create a new
+	 * one. The generated pattern will replace whitespaces with * to match all.
+	 *
+	 * @param filter
+	 * @return
+	 */
+	private Pattern getWhitespacesPattern(String filter) {
+		if (wsPattern == null || !filter.equals(wsFilter)) {
+			wsFilter = filter;
+			String sFilter = filter.replaceFirst(WS_START, EMPTY_STR).replaceFirst(WS_END, EMPTY_STR)
+					.replaceAll(PAR_START, ONE_CHAR).replaceAll(PAR_END, ONE_CHAR);
+			sFilter = String.format(".*(%s).*", sFilter.replaceAll(ANY_WS, ").*(")); //$NON-NLS-1$//$NON-NLS-2$
+			wsPattern = safeCompile(sFilter);
+		}
+		return wsPattern;
+	}
+
+	// wildcard filter and patterns
+	private String wcFilter;
+	private Pattern wcPattern;
+
+	/**
+	 * Get the existing {@link Pattern} for the given filter, or create a new
+	 * one. The generated pattern will handle '*' and '?' wildcards.
+	 *
+	 * @param filter
+	 * @return
+	 */
+	private Pattern getWildcardsPattern(String filter) {
+		if (wcPattern == null || !filter.equals(wcFilter)) {
+			wcFilter = filter;
+			String sFilter = filter.replaceFirst(WS_START, EMPTY_STR).replaceFirst(WS_END, EMPTY_STR)
+					.replaceAll(PAR_START, ONE_CHAR).replaceAll(PAR_END, ONE_CHAR);
+			// replace '*' and '?' with their matchers ").*(" and ").?("
+			StringBuilder sb = new StringBuilder();
+			for(int i=0; i<sFilter.length(); i++) {
+				char c = sFilter.charAt(i);
+				if(c=='*'||c=='?') {
+					sb.append(").").append(c).append("("); //$NON-NLS-1$ //$NON-NLS-2$
+				} else {
+					sb.append(c);
+				}
+			}
+			sFilter = String.format(".*(%s).*", sb.toString()); //$NON-NLS-1$
+			//
+			wcPattern = safeCompile(sFilter);
+		}
+		return wcPattern;
+	}
+
+	/**
+	 * A safe way to compile some unknown pattern, avoids possible
+	 * {@link PatternSyntaxException}. If the pattern can't be compiled, some
+	 * not matching pattern will be returned.
+	 *
+	 * @param pattern
+	 *            some pattern to compile, not null
+	 * @return a {@link Pattern} object compiled from given input or a dummy
+	 *         pattern which do not match anything
+	 */
+	private Pattern safeCompile(String pattern) {
+		try {
+			return Pattern.compile(pattern, Pattern.CASE_INSENSITIVE);
+		} catch (Exception e) {
+			// A "bell" special character: should not match anything we can get
+			return Pattern.compile("\\a"); //$NON-NLS-1$
+		}
+	}
+
+	int i = 0;
+	/**
+	 * If this element is a match (partial, complete, camel case, etc) to the
+	 * given filter, returns a {@link QuickAccessEntry}. Otherwise returns
+	 * <code>null</code>;
+	 *
+	 * @param filter
+	 *            filter for matching
+	 * @param providerForMatching
+	 *            the provider that will own the entry
+	 * @return a quick access entry or <code>null</code>
+	 */
+	public QuickAccessEntry match(String filter,
+			QuickAccessProvider providerForMatching) {
+		String sortLabel = getLabel();
+		// first occurrence of filter
+		int index = sortLabel.toLowerCase().indexOf(filter);
+		if (index != -1) {
+			int quality = sortLabel.toLowerCase().equals(filter) ? QuickAccessEntry.MATCH_PERFECT
+					: (sortLabel.toLowerCase().startsWith(filter) ? QuickAccessEntry.MATCH_EXCELLENT
+							: QuickAccessEntry.MATCH_GOOD);
+			return new QuickAccessEntry(this, providerForMatching,
+					new int[][] { { index, index + filter.length() - 1 } },
+ EMPTY_INDICES, quality);
+		}
+		Pattern p;
+		if (filter.contains("*") || filter.contains("?")) { //$NON-NLS-1$ //$NON-NLS-2$
+			// check for wildcards
+			p = getWildcardsPattern(filter);
+		} else {
+			// check for whitespaces
+			p = getWhitespacesPattern(filter);
+		}
+		Matcher m = p.matcher(sortLabel);
+		// if matches, return an entry and highlight the match
+		if (m.matches()) {
+			int groupCount = m.groupCount();
+			int[][] indices = new int[groupCount][];
+			for (int i = 0; i < groupCount; i++) {
+				int nGrp = i + 1;
+				// capturing group
+				indices[i] = new int[] { m.start(nGrp), m.end(nGrp) - 1 };
+			}
+			// return match and list of indices
+			int quality = QuickAccessEntry.MATCH_EXCELLENT;
+			return new QuickAccessEntry(this, providerForMatching,
+					indices,
+					EMPTY_INDICES, quality );
+		}
+		//
+		String combinedLabel = (providerForMatching.getName() + " " + getLabel()); //$NON-NLS-1$
+		index = combinedLabel.toLowerCase().indexOf(filter);
+		if (index != -1) {
+			int lengthOfElementMatch = index + filter.length()
+					- providerForMatching.getName().length() - 1;
+			if (lengthOfElementMatch > 0) {
+				return new QuickAccessEntry(this, providerForMatching,
+						new int[][] { { 0, lengthOfElementMatch - 1 } },
+ new int[][] { { index,
+						index + filter.length() - 1 } }, QuickAccessEntry.MATCH_GOOD);
+			}
+			return new QuickAccessEntry(this, providerForMatching,
+					EMPTY_INDICES, new int[][] { { index,
+ index + filter.length() - 1 } }, QuickAccessEntry.MATCH_GOOD);
+		}
+		String camelCase = CamelUtil.getCamelCase(sortLabel);
+		index = camelCase.indexOf(filter);
+		if (index != -1) {
+			int[][] indices = CamelUtil.getCamelCaseIndices(sortLabel, index, filter
+					.length());
+			return new QuickAccessEntry(this, providerForMatching, indices,
+ EMPTY_INDICES,
+					QuickAccessEntry.MATCH_GOOD);
+		}
+		String combinedCamelCase = CamelUtil.getCamelCase(combinedLabel);
+		index = combinedCamelCase.indexOf(filter);
+		if (index != -1) {
+			String providerCamelCase = CamelUtil.getCamelCase(providerForMatching
+					.getName());
+			int lengthOfElementMatch = index + filter.length()
+					- providerCamelCase.length();
+			if (lengthOfElementMatch > 0) {
+				return new QuickAccessEntry(
+						this,
+						providerForMatching,
+						CamelUtil.getCamelCaseIndices(sortLabel, 0, lengthOfElementMatch),
+						CamelUtil.getCamelCaseIndices(providerForMatching.getName(),
+ index,
+								filter.length() - lengthOfElementMatch),
+						QuickAccessEntry.MATCH_GOOD);
+			}
+			return new QuickAccessEntry(this, providerForMatching,
+					EMPTY_INDICES, CamelUtil.getCamelCaseIndices(providerForMatching
+.getName(), index,
+							filter.length()), QuickAccessEntry.MATCH_GOOD);
+		}
+		return null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/QuickAccessEntry.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/QuickAccessEntry.java
new file mode 100644
index 0000000..a56c5ec
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/QuickAccessEntry.java
@@ -0,0 +1,277 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2016 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
+ *     Manumitting Technologies Inc - bug 488721
+ ******************************************************************************/
+
+package org.eclipse.ui.internal.quickaccess;
+
+import org.eclipse.jface.resource.DeviceResourceException;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.ResourceManager;
+//import org.eclipse.jface.viewers.StyledCellLabelProvider;
+//import org.eclipse.jface.viewers.StyledString;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+//import org.eclipse.swt.graphics.TextLayout;
+//import org.eclipse.swt.graphics.TextStyle;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+
+class QuickAccessEntry {
+	boolean firstInCategory;
+	boolean lastInCategory;
+	QuickAccessElement element;
+	QuickAccessProvider provider;
+	int[][] elementMatchRegions;
+	int[][] providerMatchRegions;
+
+	/**
+	 * Provides a rough indicator of how good of a match this entry was to its
+	 * filter. Lower values indicate better match quality. A value of 0
+	 * indicates the filter string was an exact match to the label or that there
+	 * is no filter being applied.
+	 */
+	private int matchQuality;
+
+	/**
+	 * Indicates the filter string was a perfect match to the label or there is
+	 * no filter applied
+	 *
+	 * @see #getMatchQuality()
+	 */
+	public static final int MATCH_PERFECT = 0;
+
+	/**
+	 * Indicates this entry is very relevant for the filter string. Recommended
+	 * value for when the filter was found at the start of the element's label
+	 * or a complete case sensitive camel case match.
+	 *
+	 * @see #getMatchQuality()
+	 */
+	public static final int MATCH_EXCELLENT = 5;
+
+	/**
+	 * Indicates this entry is relevant for the filter string. Recommended value
+	 * for when the complete filter was found somewhere inside the element's
+	 * label or provider.
+	 *
+	 * @see #getMatchQuality()
+	 */
+	public static final int MATCH_GOOD = 10;
+
+	/**
+	 * Indicates only part of the filter string matches to the element's label.
+	 *
+	 * @see #getMatchQuality()
+	 */
+	public static final int MATCH_PARTIAL = 15;
+
+	/**
+	 * Creates a new quick access entry from the given element and provider. If
+	 * no filter was used to match this entry the element/provider match regions
+	 * may be empty and the match quality should be {@link #MATCH_PERFECT}
+	 *
+	 * @param element
+	 *            the element this entry will represent
+	 * @param provider
+	 *            the provider that owns this entry
+	 * @param elementMatchRegions
+	 *            list of text regions the filter string matched in the element
+	 *            label, possibly empty
+	 * @param providerMatchRegions
+	 *            list of text regions the filter string matches in the provider
+	 *            label, possible empty
+	 * @param matchQuality
+	 *            a rough indication of how closely the filter matched, lower
+	 *            values indicate a better match. It is recommended to use the
+	 *            constants available on this class: {@link #MATCH_PERFECT},
+	 *            {@link #MATCH_EXCELLENT}, {@link #MATCH_GOOD},
+	 *            {@link #MATCH_PARTIAL}
+	 */
+	QuickAccessEntry(QuickAccessElement element, QuickAccessProvider provider,
+			int[][] elementMatchRegions, int[][] providerMatchRegions, int matchQuality) {
+		this.element = element;
+		this.provider = provider;
+		this.elementMatchRegions = elementMatchRegions;
+		this.providerMatchRegions = providerMatchRegions;
+		this.matchQuality = matchQuality;
+	}
+
+	Image getImage(QuickAccessElement element, ResourceManager resourceManager) {
+		Image image = findOrCreateImage(element.getImageDescriptor(),
+				resourceManager);
+		if (image == null) {
+			image = WorkbenchImages
+					.getImage(IWorkbenchGraphicConstants.IMG_OBJ_ELEMENT);
+		}
+		return image;
+	}
+
+	private Image findOrCreateImage(ImageDescriptor imageDescriptor,
+			ResourceManager resourceManager) {
+		if (imageDescriptor == null) {
+			return null;
+		}
+		Image image = (Image) resourceManager.find(imageDescriptor);
+		if (image == null) {
+			try {
+				image = resourceManager.createImage(imageDescriptor);
+			} catch (DeviceResourceException e) {
+				WorkbenchPlugin.log(e);
+			}
+		}
+		return image;
+	}
+
+//	public void measure(Event event, TextLayout textLayout,
+//			ResourceManager resourceManager, TextStyle boldStyle) {
+//		Table table = ((TableItem) event.item).getParent();
+//		textLayout.setFont(table.getFont());
+//		event.width = 0;
+//		switch (event.index) {
+//		case 0:
+//			if (firstInCategory || providerMatchRegions.length > 0) {
+//				textLayout.setText(provider.getName());
+//				if (boldStyle != null) {
+//					for (int[] matchRegion : providerMatchRegions) {
+//						textLayout.setStyle(boldStyle, matchRegion[0], matchRegion[1]);
+//					}
+//				}
+//			} else {
+//				textLayout.setText(""); //$NON-NLS-1$
+//			}
+//			break;
+//		case 1:
+//			textLayout.setText(element.getLabel());
+//			// Two situations for measuring icons:
+//			// - command with very large icon image (500x500) [scale down]
+//			// - command with normal image (16x16) but small text-height (8pt)
+//			Image image = getImage(element, resourceManager);
+//			Rectangle imageRect = image.getBounds();
+//			Rectangle textBounds = textLayout.getBounds();
+//			int iconSize = imageRect.height;
+//			// Heuristic: only scale image if has double the pixels
+//			if (iconSize > 16 && iconSize >= 2 * textBounds.height) {
+//				// image will be scaled down to fit
+//				iconSize = textBounds.height;
+//			}
+//			// include additional line 1 for category separator
+//			event.height = Math.max(event.height, iconSize + 3);
+//			event.width += iconSize + 4;
+//			if (boldStyle != null) {
+//				for (int[] matchRegion : elementMatchRegions) {
+//					textLayout.setStyle(boldStyle, matchRegion[0], matchRegion[1]);
+//				}
+//			}
+//			break;
+//		}
+//		Rectangle rect = textLayout.getBounds();
+//		event.width += rect.width + 4;
+//		event.height = Math.max(event.height, rect.height + 2);
+//	}
+//
+//	public void paint(Event event, TextLayout textLayout,
+//			ResourceManager resourceManager, TextStyle boldStyle, Color grayColor) {
+//		final Table table = ((TableItem) event.item).getParent();
+//		textLayout.setFont(table.getFont());
+//		switch (event.index) {
+//		case 0:
+//			if (firstInCategory || providerMatchRegions.length > 0) {
+//				textLayout.setText(provider.getName());
+//				if (boldStyle != null) {
+//					for (int[] matchRegion : providerMatchRegions) {
+//						textLayout.setStyle(boldStyle, matchRegion[0],
+//								matchRegion[1]);
+//					}
+//				}
+//				if (grayColor != null && providerMatchRegions.length > 0 && !firstInCategory) {
+//					event.gc.setForeground(grayColor);
+//				}
+//				Rectangle availableBounds = ((TableItem) event.item).getTextBounds(event.index);
+//				Rectangle requiredBounds = textLayout.getBounds();
+//				textLayout.draw(event.gc, availableBounds.x + 1, availableBounds.y
+//						+ (availableBounds.height - requiredBounds.height) / 2);
+//			}
+//			break;
+//		case 1:
+//			String label = element.getLabel();
+//			if (element instanceof CommandElement) {
+//				CommandElement commandElement = (CommandElement) element;
+//				String binding = commandElement.getBinding();
+//				if (binding != null) {
+//					StyledString styledString = StyledCellLabelProvider.styleDecoratedString(label,
+//							StyledString.QUALIFIER_STYLER, new StyledString(commandElement
+//									.getCommand()));
+//					StyleRange[] styleRanges = styledString.getStyleRanges();
+//					for (StyleRange styleRange : styleRanges) {
+//						textLayout.setStyle(styleRange, styleRange.start,
+//								styleRange.start + styleRange.length);
+//					}
+//				}
+//			}
+//			// draw images to fit square area sized by the text area
+//			Image image = getImage(element, resourceManager);
+//			Rectangle availableBounds = ((TableItem) event.item).getTextBounds(event.index);
+//			Rectangle requiredBounds = textLayout.getBounds();
+//			Rectangle imageBounds = image.getBounds();
+//			// 3 = top + bottom + category lines
+//			int maxImageSize = availableBounds.height - 3;
+//			// preserve aspect ratio
+//			int destHeight = Math.min(imageBounds.height, maxImageSize);
+//			int destWidth = destHeight * imageBounds.width / imageBounds.height;
+//			// and centre within available space; remove 1 from height for
+//			// category separator
+//			int startX = (maxImageSize - destWidth) / 2;
+//			int startY = (availableBounds.height - 1 - destHeight) / 2;
+//			event.gc.drawImage(image, 0, 0, imageBounds.width, imageBounds.height,
+//					availableBounds.x + startX, availableBounds.y + startY,
+//					destWidth, destHeight);
+//			textLayout.setText(label);
+//			if (boldStyle != null) {
+//				for (int[] matchRegion : elementMatchRegions) {
+//					textLayout.setStyle(boldStyle, matchRegion[0], matchRegion[1]);
+//				}
+//			}
+//			textLayout.draw(event.gc, availableBounds.x + maxImageSize + 4,
+//					availableBounds.y + (availableBounds.height - requiredBounds.height) / 2);
+//			break;
+//		}
+//		if (lastInCategory) {
+//			if (grayColor != null)
+//				event.gc.setForeground(grayColor);
+//			Rectangle bounds = ((TableItem)event.item).getBounds(event.index);
+//			event.gc.drawLine(Math.max(0, bounds.x - 1), bounds.y + bounds.height - 1, bounds.x + bounds.width, bounds.y
+//					+ bounds.height - 1);
+//		}
+//	}
+
+	/**
+	 * @param event
+	 */
+	public void erase(Event event) {
+		// We are only custom drawing the foreground.
+		event.detail &= ~SWT.FOREGROUND;
+	}
+
+	/**
+	 * Provides a rough indicator of how good of a match this entry was to its
+	 * filter. Lower values indicate better match quality. A value of
+	 * {@link #MATCH_PERFECT} indicates the filter string was an exact match to
+	 * the label or that there is no filter being applied.
+	 *
+	 * @return Returns the match quality
+	 */
+	public int getMatchQuality() {
+		return matchQuality;
+	}
+
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/QuickAccessHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/QuickAccessHandler.java
new file mode 100644
index 0000000..f00f7cd
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/QuickAccessHandler.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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
+ *     René Brandstetter - Bug 431707 - [QuickAccess] Quick Access should open a dialog if hidden
+ *******************************************************************************/
+package org.eclipse.ui.internal.quickaccess;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
+import org.eclipse.e4.ui.model.application.ui.menu.MToolControl;
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+import org.eclipse.jface.dialogs.PopupDialog;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.eclipse.ui.internal.WorkbenchWindow;
+
+/**
+ * Handler for quick access pop-up dialog, showing UI elements such as editors,
+ * views, commands.
+ *
+ */
+public class QuickAccessHandler extends AbstractHandler {
+
+	@Override
+	public Object execute(ExecutionEvent executionEvent) {
+		final IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindow(executionEvent);
+		if (window == null) {
+			return null;
+		}
+
+		MWindow mWindow = ((WorkbenchWindow) window).getModel();
+		EModelService modelService = mWindow.getContext().get(EModelService.class);
+		MToolControl searchField = (MToolControl) modelService.find("SearchField", mWindow); //$NON-NLS-1$
+		if (searchField != null && searchField.isVisible()) {
+			Control control = (Control) searchField.getWidget();
+			// the workbench configurer may override visibility; if so,
+			// focus should not change
+			if (control != null && control.isVisible()) {
+				Control previousFocusControl = control.getDisplay().getFocusControl();
+				control.setFocus();
+				SearchField field = (SearchField) searchField.getObject();
+				field.activate(previousFocusControl);
+				return null;
+			}
+		}
+
+		// open the original/legacy QuickAccess Dialog if the toolbars are
+		// hidden or if the search field isn't available (maybe because the
+		// dialog is explicitly wanted)
+		displayQuickAccessDialog(window, executionEvent.getCommand());
+		return null;
+	}
+
+	/**
+	 * Utility method to displays the original/legacy QuickAccess dialog.
+	 *
+	 * @param window
+	 *            the active workbench window
+	 * @param command
+	 *            the command which invokes the open of the dialog
+	 */
+	private static void displayQuickAccessDialog(IWorkbenchWindow window, Command command) {
+		PopupDialog popupDialog = new QuickAccessDialog(window, command);
+		popupDialog.open();
+	}
+
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/QuickAccessMessages.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/QuickAccessMessages.java
new file mode 100644
index 0000000..f00deff
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/QuickAccessMessages.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2016 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
+ *     Patrik Suzzi <psuzzi@gmail.com> - Bug 488926, 459989
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.quickaccess;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * @since 3.2
+ *
+ */
+public class QuickAccessMessages extends NLS {
+	private static final String BUNDLE_NAME = "org.eclipse.ui.internal.quickaccess.messages"; //$NON-NLS-1$
+	public static String QuickAccess_TooltipDescription;
+	public static String QuickAccess_TooltipDescription_Empty;
+	public static String QuickAccess_Perspectives;
+	public static String QuickAccess_Commands;
+	public static String QuickAccess_Properties;
+	public static String QuickAccess_Editors;
+	public static String QuickAccess_Menus;
+	public static String QuickAccess_New;
+	public static String QuickAccess_Preferences;
+	public static String QuickAccess_Previous;
+	public static String QuickAccess_Views;
+	public static String QuickAccess_PressKeyToShowAllMatches;
+	public static String QuickAccess_StartTypingToFindMatches;
+	public static String QuickAccess_AvailableCategories;
+	public static String QuickAccess_EnterSearch;
+	public static String QuickAccess_SelectedString;
+	public static String QuickAccess_ViewWithCategory;
+	public static String QuickAccessContents_NoMatchingResults;
+	public static String QuickAccessContents_PressKeyToLimitResults;
+	public static String QuickAccessContents_QuickAccess;
+	public static String QuickAccessContents_SearchInHelpLabel;
+	static {
+		// initialize resource bundle
+		NLS.initializeMessages(BUNDLE_NAME, QuickAccessMessages.class);
+	}
+
+	private QuickAccessMessages() {
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/QuickAccessProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/QuickAccessProvider.java
new file mode 100644
index 0000000..56d363c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/QuickAccessProvider.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.quickaccess;
+
+import java.util.Arrays;
+import org.eclipse.jface.resource.ImageDescriptor;
+
+/**
+ * @since 3.3
+ *
+ */
+public abstract class QuickAccessProvider {
+
+	private QuickAccessElement[] sortedElements;
+
+	/**
+	 * Returns the unique ID of this provider.
+	 *
+	 * @return the unique ID
+	 */
+	public abstract String getId();
+
+	/**
+	 * Returns the name of this provider to be displayed to the user.
+	 *
+	 * @return the name
+	 */
+	public abstract String getName();
+
+	/**
+	 * Returns the image descriptor for this provider.
+	 *
+	 * @return the image descriptor, or null if not defined
+	 */
+	public abstract ImageDescriptor getImageDescriptor();
+
+	/**
+	 * Returns the elements provided by this provider.
+	 *
+	 * @return this provider's elements
+	 */
+	public abstract QuickAccessElement[] getElements();
+
+	public QuickAccessElement[] getElementsSorted() {
+		if (sortedElements == null) {
+			sortedElements = getElements();
+			Arrays.sort(sortedElements, (e1, e2) -> e1.getSortLabel().compareTo(e2.getSortLabel()));
+		}
+		return sortedElements;
+	}
+
+	/**
+	 * Returns the element for the given ID if available, or null if no matching
+	 * element is available.
+	 *
+	 * @param id
+	 *            the ID of an element
+	 * @return the element with the given ID, or null if not found.
+	 */
+	public abstract QuickAccessElement getElementForId(String id);
+
+	public boolean isAlwaysPresent() {
+		return false;
+	}
+
+	public void reset() {
+		sortedElements = null;
+		doReset();
+	}
+
+	protected abstract void doReset();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/SearchField.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/SearchField.java
new file mode 100644
index 0000000..199a7ca
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/SearchField.java
@@ -0,0 +1,769 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2016 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
+ *     Tom Hochstein (Freescale) - Bug 393703: NotHandledException selecting inactive command under 'Previous Choices' in Quick access
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 428050, 472654
+ *     Brian de Alwis - Fix size computation to account for trim
+ *     Markus Kuppe <bugs.eclipse.org@lemmster.de> - Bug 449485: [QuickAccess] "Widget is disposed" exception in errorlog during shutdown due to quickaccess.SearchField.storeDialog
+ *     Elena Laskavaia <elaskavaia.cdt@gmail.com> - Bug 433746: [QuickAccess] SWTException on closing quick access shell
+ *     Patrik Suzzi <psuzzi@gmail.com> - Bug 488926, 491278, 491291, 491312, 491293, 436788, 513436
+ ******************************************************************************/
+package org.eclipse.ui.internal.quickaccess;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.ExpressionInfo;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.e4.core.commands.ECommandService;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.di.annotations.Optional;
+import org.eclipse.e4.core.di.extensions.Preference;
+import org.eclipse.e4.ui.bindings.internal.BindingTableManager;
+import org.eclipse.e4.ui.bindings.internal.ContextSet;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
+import org.eclipse.e4.ui.workbench.IPresentationEngine;
+import org.eclipse.e4.ui.workbench.modeling.EPartService;
+import org.eclipse.jface.bindings.Binding;
+import org.eclipse.jface.bindings.TriggerSequence;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.jface.util.Geometry;
+import org.eclipse.jface.util.Util;
+import org.eclipse.jface.window.Window;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.accessibility.ACC;
+import org.eclipse.swt.accessibility.AccessibleAdapter;
+import org.eclipse.swt.accessibility.AccessibleEvent;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.ControlListener;
+import org.eclipse.swt.events.FocusAdapter;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.graphics.FontMetrics;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Monitor;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.contexts.IContextService;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.keys.IBindingService;
+import org.eclipse.ui.swt.IFocusService;
+
+
+public class SearchField {
+
+	private static final String QUICK_ACCESS_COMMAND_ID = "org.eclipse.ui.window.quickAccess"; //$NON-NLS-1$
+
+	private static final String TEXT_ARRAY = "textArray"; //$NON-NLS-1$
+	private static final String TEXT_ENTRIES = "textEntries"; //$NON-NLS-1$
+	private static final String ORDERED_PROVIDERS = "orderedProviders"; //$NON-NLS-1$
+	private static final String ORDERED_ELEMENTS = "orderedElements"; //$NON-NLS-1$
+	private static final int MAXIMUM_NUMBER_OF_ELEMENTS = 60;
+	private static final int MAXIMUM_NUMBER_OF_TEXT_ENTRIES_PER_ELEMENT = 3;
+	private static final String DIALOG_HEIGHT = "dialogHeight"; //$NON-NLS-1$
+	private static final String DIALOG_WIDTH = "dialogWidth"; //$NON-NLS-1$
+
+	Shell shell;
+	private Text txtQuickAccess;
+
+	private QuickAccessContents quickAccessContents;
+
+	private MWindow window;
+
+	private Map<String, QuickAccessProvider> providerMap = new HashMap<>();
+
+	private Map<String, QuickAccessElement> elementMap = new HashMap<>();
+
+	private Map<QuickAccessElement, ArrayList<String>> textMap = new HashMap<>();
+
+	private LinkedList<QuickAccessElement> previousPicksList = new LinkedList<>();
+	private int dialogHeight = -1;
+	private int dialogWidth = -1;
+	private Control previousFocusControl;
+	boolean activated = false;
+
+	@Inject
+	private EPartService partService;
+	private Table table;
+
+	private String selectedString = ""; //$NON-NLS-1$
+	private AccessibleAdapter accessibleListener;
+
+	@Inject
+	private IBindingService bindingService;
+
+	private TriggerSequence triggerSequence = null;
+
+	@PostConstruct
+	void createControls(final Composite parent, MApplication application, MWindow window) {
+		this.window = window;
+		final Composite comp = new Composite(parent, SWT.NONE);
+		comp.setLayout(new GridLayout());
+		txtQuickAccess = createText(comp);
+		updateQuickAccessText();
+
+		parent.getShell().addControlListener(new ControlListener() {
+			@Override
+			public void controlResized(ControlEvent e) {
+				closeDropDown();
+			}
+
+			@Override
+			public void controlMoved(ControlEvent e) {
+				closeDropDown();
+			}
+
+			private void closeDropDown() {
+				if (shell == null || shell.isDisposed() || txtQuickAccess.isDisposed() || !shell.isVisible())
+					return;
+				quickAccessContents.doClose();
+			}
+		});
+
+		hookUpSelectAll();
+
+		final CommandProvider commandProvider = new CommandProvider();
+		QuickAccessProvider[] providers = new QuickAccessProvider[] {
+				new PreviousPicksProvider(previousPicksList),
+				new EditorProvider(), new ViewProvider(application, window),
+				new PerspectiveProvider(), commandProvider, new ActionProvider(),
+				new WizardProvider(), new PreferenceProvider(), new PropertiesProvider() };
+		for (QuickAccessProvider provider : providers) {
+			providerMap.put(provider.getId(), provider);
+		}
+		restoreDialog();
+
+		quickAccessContents = new QuickAccessContents(providers) {
+			@Override
+			protected void updateFeedback(boolean filterTextEmpty, boolean showAllMatches) {
+			}
+
+			@Override
+			protected void doClose() {
+				txtQuickAccess.setText(""); //$NON-NLS-1$
+				resetProviders();
+				dialogHeight = shell.getSize().y;
+				dialogWidth = shell.getSize().x;
+				shell.setVisible(false);
+				removeAccessibleListener();
+			}
+
+			@Override
+			protected QuickAccessElement getPerfectMatch(String filter) {
+				return elementMap.get(filter);
+			}
+
+			@Override
+			protected void handleElementSelected(String string, Object selectedElement) {
+				if (selectedElement instanceof QuickAccessElement) {
+					QuickAccessElement element = (QuickAccessElement) selectedElement;
+					addPreviousPick(string, element);
+					txtQuickAccess.setText(""); //$NON-NLS-1$
+					element.execute();
+
+					// after execution, the search box might be disposed
+					if (txtQuickAccess.isDisposed()) {
+						return;
+					}
+
+					/*
+					 * By design, attempting to activate a part that is already
+					 * active does not change the focus. However in the case of
+					 * using Quick Access, focus is not in the active part, so
+					 * re-activating the active part results in focus being left
+					 * behind in the text field. If this happens then assign
+					 * focus to the active part explicitly.
+					 */
+					if (txtQuickAccess.isFocusControl()) {
+						MPart activePart = partService.getActivePart();
+						if (activePart != null) {
+							IPresentationEngine pe = activePart.getContext().get(
+									IPresentationEngine.class);
+							pe.focusGui(activePart);
+						}
+					}
+
+					if (shell.isVisible()) {
+						// after selection, closes the shell
+						quickAccessContents.doClose();
+					}
+				}
+			}
+		};
+		quickAccessContents.hookFilterText(txtQuickAccess);
+		shell = new Shell(parent.getShell(), SWT.RESIZE | SWT.ON_TOP);
+		shell.setBackground(shell.getDisplay().getSystemColor(SWT.COLOR_WHITE));
+		shell.setText(QuickAccessMessages.QuickAccess_EnterSearch); // just for debugging, not shown anywhere
+		GridLayoutFactory.fillDefaults().applyTo(shell);
+		quickAccessContents.createHintText(shell, Window.getDefaultOrientation());
+		table = quickAccessContents.createTable(shell, Window.getDefaultOrientation());
+		txtQuickAccess.addMouseListener(new MouseAdapter() {
+			@Override
+			public void mouseUp(MouseEvent e) {
+				// release mouse button = click = CTRL+3 -> activate QuickAccess
+				showList();
+			}
+		});
+		txtQuickAccess.addFocusListener(new FocusListener() {
+			@Override
+			public void focusLost(FocusEvent e) {
+				// Once the focus event is complete, check if we should close the shell
+				table.getDisplay().asyncExec(() -> checkFocusLost(table, txtQuickAccess));
+				activated = false;
+			}
+
+			@Override
+			public void focusGained(FocusEvent e) {
+				IHandlerService hs = SearchField.this.window.getContext().get(IHandlerService.class);
+				if (commandProvider.getContextSnapshot() == null) {
+					commandProvider.setSnapshot(hs.createContextSnapshot(true));
+				}
+				previousFocusControl = (Control) e.getSource();
+				activated = true;
+			}
+		});
+		table.addFocusListener(new FocusAdapter() {
+			@Override
+			public void focusLost(FocusEvent e) {
+				// Once the focus event is complete, check if we should close
+				// the shell
+				table.getDisplay().asyncExec(() -> checkFocusLost(table, txtQuickAccess));
+			}
+		});
+		txtQuickAccess.addModifyListener(e -> showList());
+		txtQuickAccess.addKeyListener(new KeyAdapter() {
+			@Override
+			public void keyPressed(KeyEvent e) {
+				if (e.keyCode == SWT.ESC) {
+					activated = false;
+					txtQuickAccess.setText(""); //$NON-NLS-1$
+					if (txtQuickAccess == previousFocusControl) {
+						txtQuickAccess.getShell().forceFocus();
+					} else if (previousFocusControl != null && !previousFocusControl.isDisposed())
+						previousFocusControl.setFocus();
+				} else if (e.keyCode == SWT.ARROW_UP) {
+					// Windows moves caret left/right when pressing up/down,
+					// avoid this as the table selection changes for up/down
+					e.doit = false;
+				} else if (e.keyCode == SWT.ARROW_DOWN) {
+					e.doit = false;
+				}
+				if (e.doit == false) {
+					// arrow key pressed
+					notifyAccessibleTextChanged();
+				}
+			}
+		});
+		quickAccessContents.createInfoLabel(shell);
+	}
+
+
+	@Inject
+	@Optional
+	protected void keybindingPreferencesChanged(
+			@SuppressWarnings("restriction") @Preference(nodePath = "org.eclipse.ui.workbench", value = "org.eclipse.ui.commands") String preferenceValue) {
+		if (preferenceValue != null) {
+			updateQuickAccessText();
+		}
+
+	}
+
+	private void showList() {
+		boolean wasVisible = shell.getVisible();
+		boolean nowVisible = txtQuickAccess.getText().length() > 0 || activated;
+		if (!wasVisible && nowVisible) {
+			layoutShell();
+			addAccessibleListener();
+			quickAccessContents.preOpen();
+		}
+		if (wasVisible && !nowVisible) {
+			removeAccessibleListener();
+		}
+		if (nowVisible) {
+			notifyAccessibleTextChanged();
+		}
+		shell.setVisible(nowVisible);
+	}
+
+
+	@Inject
+	private BindingTableManager manager;
+	@Inject
+	private ECommandService eCommandService;
+	@Inject
+	private IContextService contextService;
+
+	/**
+	 * Compute the best binding for the command and sets the trigger
+	 *
+	 */
+	protected void updateQuickAccessTriggerSequence() {
+		triggerSequence = bindingService.getBestActiveBindingFor(QUICK_ACCESS_COMMAND_ID);
+		// FIXME Bug 491701 - [KeyBinding] get best active binding is not working
+		if (triggerSequence == null) {
+			ParameterizedCommand cmd = eCommandService.createCommand(QUICK_ACCESS_COMMAND_ID, null);
+			ContextSet contextSet = manager.createContextSet(Arrays.asList(contextService.getDefinedContexts()));
+			Binding binding = manager.getBestSequenceFor(contextSet, cmd);
+			triggerSequence = (binding == null) ? null : binding.getTriggerSequence();
+		}
+	}
+
+	private Text createText(Composite parent) {
+		Text text = new Text(parent, SWT.SEARCH);
+		text.setMessage(QuickAccessMessages.QuickAccess_EnterSearch);
+		return text;
+	}
+
+	private void updateQuickAccessText() {
+		if (txtQuickAccess == null || txtQuickAccess.isDisposed()) {
+			return;
+		}
+		updateQuickAccessTriggerSequence();
+
+		if (triggerSequence != null) {
+			txtQuickAccess.setToolTipText(
+					NLS.bind(QuickAccessMessages.QuickAccess_TooltipDescription, triggerSequence.format()));
+		} else {
+			txtQuickAccess.setToolTipText(QuickAccessMessages.QuickAccess_TooltipDescription_Empty);
+		}
+
+		GC gc = new GC(txtQuickAccess);
+
+		// workaround for Bug 491317
+		if (Util.isWin32() || Util.isGtk()) {
+			FontMetrics fm = gc.getFontMetrics();
+			int wHint = QuickAccessMessages.QuickAccess_EnterSearch.length() * fm.getAverageCharWidth();
+			int hHint = fm.getHeight();
+			gc.dispose();
+			txtQuickAccess.setSize(txtQuickAccess.computeSize(wHint, hHint));
+		} else {
+			Point p = gc.textExtent(QuickAccessMessages.QuickAccess_EnterSearch);
+			Rectangle r = txtQuickAccess.computeTrim(0, 0, p.x, p.y);
+			gc.dispose();
+
+			// computeTrim() may result in r.x < 0
+			GridDataFactory.fillDefaults().hint(r.width - r.x, SWT.DEFAULT).applyTo(txtQuickAccess);
+		}
+		txtQuickAccess.requestLayout();
+
+	}
+
+	private void hookUpSelectAll() {
+		final IEclipseContext windowContext = window.getContext();
+		IFocusService focus = windowContext.get(IFocusService.class);
+		focus.addFocusTracker(txtQuickAccess, SearchField.class.getName());
+
+		Expression focusExpr = new Expression() {
+			@Override
+			public void collectExpressionInfo(ExpressionInfo info) {
+				info.addVariableNameAccess(ISources.ACTIVE_FOCUS_CONTROL_ID_NAME);
+			}
+
+			@Override
+			public EvaluationResult evaluate(IEvaluationContext context) {
+				return EvaluationResult.valueOf(SearchField.class.getName().equals(
+						context.getVariable(ISources.ACTIVE_FOCUS_CONTROL_ID_NAME)));
+			}
+		};
+
+		IHandlerService whService = windowContext.get(IHandlerService.class);
+		whService.activateHandler(IWorkbenchCommandConstants.EDIT_SELECT_ALL,
+				new AbstractHandler() {
+					@Override
+					public Object execute(ExecutionEvent event) {
+						txtQuickAccess.selectAll();
+						return null;
+					}
+				}, focusExpr);
+		whService.activateHandler(IWorkbenchCommandConstants.EDIT_CUT, new AbstractHandler() {
+			@Override
+			public Object execute(ExecutionEvent event) {
+                // RAP
+//              text.cut();
+				return null;
+			}
+		}, focusExpr);
+		whService.activateHandler(IWorkbenchCommandConstants.EDIT_COPY, new AbstractHandler() {
+			@Override
+			public Object execute(ExecutionEvent event) {
+                // RAP
+//              text.copy();
+				return null;
+			}
+		}, focusExpr);
+		whService.activateHandler(IWorkbenchCommandConstants.EDIT_PASTE, new AbstractHandler() {
+			@Override
+			public Object execute(ExecutionEvent event) {
+                // RAP
+//              text.paste();
+				return null;
+			}
+		}, focusExpr);
+	}
+
+	/**
+	 * This method was copy/pasted from JFace.
+	 */
+	private static Monitor getClosestMonitor(Display toSearch, Point toFind) {
+		int closest = Integer.MAX_VALUE;
+
+		Monitor[] monitors = toSearch.getMonitors();
+		Monitor result = monitors[0];
+
+		for (Monitor currentMonitor : monitors) {
+			Rectangle clientArea = currentMonitor.getClientArea();
+
+			if (clientArea.contains(toFind)) {
+				return currentMonitor;
+			}
+
+			int distance = Geometry.distanceSquared(Geometry.centerPoint(clientArea), toFind);
+			if (distance < closest) {
+				closest = distance;
+				result = currentMonitor;
+			}
+		}
+
+		return result;
+	}
+
+	/**
+	 * This method was copy/pasted from JFace.
+	 */
+	private Rectangle getConstrainedShellBounds(Display display, Rectangle preferredSize) {
+		Rectangle result = new Rectangle(preferredSize.x, preferredSize.y, preferredSize.width,
+				preferredSize.height);
+
+		Point topLeft = new Point(preferredSize.x, preferredSize.y);
+		Monitor mon = getClosestMonitor(display, topLeft);
+		Rectangle bounds = mon.getClientArea();
+
+		if (result.height > bounds.height) {
+			result.height = bounds.height;
+		}
+
+		if (result.width > bounds.width) {
+			result.width = bounds.width;
+		}
+
+		result.x = Math.max(bounds.x, Math.min(result.x, bounds.x + bounds.width - result.width));
+		result.y = Math.max(bounds.y, Math.min(result.y, bounds.y + bounds.height - result.height));
+
+		return result;
+	}
+
+	void layoutShell() {
+		Display display = txtQuickAccess.getDisplay();
+		Rectangle tempBounds = txtQuickAccess.getBounds();
+		Rectangle compBounds = display.map(txtQuickAccess, null, tempBounds);
+		int preferredWidth = dialogWidth == -1 ? 350 : dialogWidth;
+		int width = Math.max(preferredWidth, compBounds.width);
+		int height = dialogHeight == -1 ? 250 : dialogHeight;
+
+		// If size would extend past the right edge of the shell, try to move it
+		// to the left of the text
+		Rectangle shellBounds = txtQuickAccess.getShell().getBounds();
+		if (compBounds.x + width > shellBounds.x + shellBounds.width){
+			compBounds.x = Math.max(shellBounds.x, (compBounds.x + compBounds.width - width));
+		}
+
+		shell.setBounds(getConstrainedShellBounds(display, new Rectangle(compBounds.x, compBounds.y
+				+ compBounds.height, width, height)));
+		shell.layout();
+	}
+
+	public void activate(Control previousFocusControl) {
+		this.previousFocusControl = previousFocusControl;
+		if (!shell.isVisible()) {
+			layoutShell();
+			quickAccessContents.preOpen();
+			shell.setVisible(true);
+			addAccessibleListener();
+			quickAccessContents.refresh(txtQuickAccess.getText().toLowerCase());
+		} else {
+			quickAccessContents.setShowAllMatches(!quickAccessContents.getShowAllMatches());
+		}
+	}
+
+	/**
+	 * Checks if the text or shell has focus. If not, closes the shell.
+	 *
+	 * @param table
+	 *            the shell's table
+	 * @param text
+	 *            the search text field
+	 */
+	protected void checkFocusLost(final Table table, final Text text) {
+		if (!shell.isDisposed() && !table.isDisposed() && !text.isDisposed()) {
+			if (table.getDisplay().getActiveShell() == table.getShell()) {
+				// If the user selects the trim shell, leave focus on the text
+				// so shell stays open
+				text.setFocus();
+				return;
+			}
+			if (!shell.isFocusControl() && !table.isFocusControl()
+					&& !text.isFocusControl()) {
+				quickAccessContents.doClose();
+			}
+		}
+	}
+
+	/**
+	 * Adds a listener to the
+	 * <code>org.eclipse.swt.accessibility.Accessible</code> object assigned to
+	 * the Quick Access search box. The listener sets a name of a selected
+	 * element in the search result list as a text to read for a screen reader.
+	 */
+	private void addAccessibleListener() {
+		if (accessibleListener == null) {
+			accessibleListener = new AccessibleAdapter() {
+				@Override
+				public void getName(AccessibleEvent e) {
+					e.result = selectedString;
+				}
+			};
+			txtQuickAccess.getAccessible().addAccessibleListener(accessibleListener);
+		}
+	}
+
+	/**
+	 * Removes a listener from the
+	 * <code>org.eclipse.swt.accessibility.Accessible</code> object assigned to
+	 * the Quick Access search box.
+	 */
+	private void removeAccessibleListener() {
+		if (accessibleListener != null) {
+			txtQuickAccess.getAccessible().removeAccessibleListener(accessibleListener);
+			accessibleListener = null;
+		}
+		selectedString = ""; //$NON-NLS-1$
+	}
+
+	/**
+	 * Notifies <code>org.eclipse.swt.accessibility.Accessible<code> object
+	 * that selected item has been changed.
+	 */
+	private void notifyAccessibleTextChanged() {
+		if (table.getSelection().length == 0) {
+			return;
+		}
+		TableItem item = table.getSelection()[0];
+		selectedString = NLS.bind(QuickAccessMessages.QuickAccess_SelectedString, item.getText(0),
+				item.getText(1));
+		txtQuickAccess.getAccessible().sendEvent(ACC.EVENT_NAME_CHANGED, null);
+	}
+
+	private void restoreDialog() {
+		IDialogSettings dialogSettings = getDialogSettings();
+		if (dialogSettings != null) {
+			String[] orderedElements = dialogSettings.getArray(ORDERED_ELEMENTS);
+			String[] orderedProviders = dialogSettings.getArray(ORDERED_PROVIDERS);
+			String[] textEntries = dialogSettings.getArray(TEXT_ENTRIES);
+			String[] textArray = dialogSettings.getArray(TEXT_ARRAY);
+			try {
+				dialogHeight = dialogSettings.getInt(DIALOG_HEIGHT);
+				dialogWidth = dialogSettings.getInt(DIALOG_WIDTH);
+			} catch (NumberFormatException e) {
+				dialogHeight = -1;
+				dialogWidth = -1;
+			}
+
+			if (orderedElements != null && orderedProviders != null && textEntries != null
+					&& textArray != null) {
+				int arrayIndex = 0;
+				for (int i = 0; i < orderedElements.length; i++) {
+					QuickAccessProvider quickAccessProvider = providerMap.get(orderedProviders[i]);
+					int numTexts = Integer.parseInt(textEntries[i]);
+					if (quickAccessProvider != null) {
+						QuickAccessElement quickAccessElement = quickAccessProvider
+								.getElementForId(orderedElements[i]);
+						if (quickAccessElement != null) {
+							ArrayList<String> arrayList = new ArrayList<>();
+							for (int j = arrayIndex; j < arrayIndex + numTexts; j++) {
+								String text = textArray[j];
+								// text length can be zero for old workspaces,
+								// see bug 190006
+								if (text.length() > 0) {
+									arrayList.add(text);
+									elementMap.put(text, quickAccessElement);
+								}
+							}
+							textMap.put(quickAccessElement, arrayList);
+							previousPicksList.add(quickAccessElement);
+						}
+					}
+					arrayIndex += numTexts;
+				}
+			}
+		}
+	}
+
+	@PreDestroy
+	void dispose() {
+		storeDialog();
+	}
+
+	private void storeDialog() {
+		String[] orderedElements = new String[previousPicksList.size()];
+		String[] orderedProviders = new String[previousPicksList.size()];
+		String[] textEntries = new String[previousPicksList.size()];
+		ArrayList<String> arrayList = new ArrayList<>();
+		for (int i = 0; i < orderedElements.length; i++) {
+			QuickAccessElement quickAccessElement = previousPicksList.get(i);
+			ArrayList<String> elementText = textMap.get(quickAccessElement);
+			Assert.isNotNull(elementText);
+			orderedElements[i] = quickAccessElement.getId();
+			orderedProviders[i] = quickAccessElement.getProvider().getId();
+			arrayList.addAll(elementText);
+			textEntries[i] = elementText.size() + ""; //$NON-NLS-1$
+		}
+		String[] textArray = arrayList.toArray(new String[arrayList.size()]);
+		IDialogSettings dialogSettings = getDialogSettings();
+		dialogSettings.put(ORDERED_ELEMENTS, orderedElements);
+		dialogSettings.put(ORDERED_PROVIDERS, orderedProviders);
+		dialogSettings.put(TEXT_ENTRIES, textEntries);
+		dialogSettings.put(TEXT_ARRAY, textArray);
+		dialogSettings.put(DIALOG_HEIGHT, dialogHeight);
+		dialogSettings.put(DIALOG_WIDTH, dialogWidth);
+	}
+
+	private IDialogSettings getDialogSettings() {
+		final IDialogSettings workbenchDialogSettings = WorkbenchPlugin.getDefault()
+				.getDialogSettings();
+		IDialogSettings result = workbenchDialogSettings.getSection(getId());
+		if (result == null) {
+			result = workbenchDialogSettings.addNewSection(getId());
+		}
+		return result;
+	}
+
+	private String getId() {
+		return "org.eclipse.ui.internal.QuickAccess"; //$NON-NLS-1$
+	}
+
+	/**
+	 * @param element
+	 */
+	private void addPreviousPick(String text, QuickAccessElement element) {
+		// previousPicksList:
+		// Remove element from previousPicksList so there are no duplicates
+		// If list is max size, remove last(oldest) element
+		// Remove entries for removed element from elementMap and textMap
+		// Add element to front of previousPicksList
+		previousPicksList.remove(element);
+		if (previousPicksList.size() == MAXIMUM_NUMBER_OF_ELEMENTS) {
+			Object removedElement = previousPicksList.removeLast();
+			ArrayList<String> removedList = textMap.remove(removedElement);
+			for (int i = 0; i < removedList.size(); i++) {
+				elementMap.remove(removedList.get(i));
+			}
+		}
+		previousPicksList.addFirst(element);
+
+		// textMap:
+		// Get list of strings for element from textMap
+		// Create new list for element if there isn't one and put
+		// element->textList in textMap
+		// Remove rememberedText from list
+		// If list is max size, remove first(oldest) string
+		// Remove text from elementMap
+		// Add rememberedText to list of strings for element in textMap
+		ArrayList<String> textList = textMap.get(element);
+		if (textList == null) {
+			textList = new ArrayList<>();
+			textMap.put(element, textList);
+		}
+
+		textList.remove(text);
+		if (textList.size() == MAXIMUM_NUMBER_OF_TEXT_ENTRIES_PER_ELEMENT) {
+			Object removedText = textList.remove(0);
+			elementMap.remove(removedText);
+		}
+
+		if (text.length() > 0) {
+			textList.add(text);
+
+			// elementMap:
+			// Put rememberedText->element in elementMap
+			// If it replaced a different element update textMap and
+			// PreviousPicksList
+			QuickAccessElement replacedElement = elementMap.put(text, element);
+			if (replacedElement != null && !replacedElement.equals(element)) {
+				textList = textMap.get(replacedElement);
+				if (textList != null) {
+					textList.remove(text);
+					if (textList.isEmpty()) {
+						textMap.remove(replacedElement);
+						previousPicksList.remove(replacedElement);
+					}
+				}
+			}
+		}
+	}
+
+	/**
+	 * Returns the quick access shell for testing. Should not be referenced
+	 * outside of the tests.
+	 *
+	 * @return the current quick access shell or <code>null</code>
+	 */
+	public Shell getQuickAccessShell() {
+		return shell;
+	}
+
+	/**
+	 * Returns the quick access search text for testing. Should not be
+	 * referenced outside of the tests.
+	 *
+	 * @return the search text in the workbench window or <code>null</code>
+	 */
+	public Text getQuickAccessSearchText() {
+		return txtQuickAccess;
+	}
+
+	/**
+	 * Returns the table in the shell for testing. Should not be referenced
+	 * outside of the tests.
+	 *
+	 * @return the table created in the shell or <code>null</code>
+	 */
+	public Table getQuickAccessTable(){
+		return table;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/ViewElement.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/ViewElement.java
new file mode 100644
index 0000000..cae3cd4
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/ViewElement.java
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.quickaccess;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import org.eclipse.e4.ui.model.LocalizationHelper;
+import org.eclipse.e4.ui.model.application.descriptor.basic.MPartDescriptor;
+import org.eclipse.e4.ui.model.application.ui.advanced.MPlaceholder;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
+import org.eclipse.e4.ui.workbench.modeling.EPartService;
+import org.eclipse.e4.ui.workbench.modeling.EPartService.PartState;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.e4.compatibility.CompatibilityPart;
+
+/**
+ * @since 3.3
+ *
+ */
+public class ViewElement extends QuickAccessElement {
+
+	private MWindow window;
+	private MPartDescriptor viewDescriptor;
+	private ImageDescriptor imageDescriptor;
+
+	public ViewElement(QuickAccessProvider provider, MWindow window, MPartDescriptor descriptor) {
+		super(provider);
+		this.window = window;
+		this.viewDescriptor = descriptor;
+
+		imageDescriptor = createImageDescriptor();
+	}
+
+	private ImageDescriptor createImageDescriptor() {
+		String iconURI = viewDescriptor.getIconURI();
+		if (iconURI == null) {
+			return null;
+		}
+
+		try {
+			return ImageDescriptor.createFromURL(new URL(iconURI));
+		} catch (MalformedURLException e) {
+			return null;
+		}
+	}
+
+	@Override
+	public void execute() {
+		/*
+		 * TODO: see bug 483699: the code below duplicates the code in
+		 * org.eclipse.ui.handlers.ShowViewHandler#openView() and should be
+		 * refactored to some user friendly API
+		 */
+		String id = viewDescriptor.getElementId();
+		if (id != null) {
+			if (CompatibilityPart.COMPATIBILITY_VIEW_URI
+					.equals(viewDescriptor.getContributionURI())) {
+				IWorkbenchWindow workbenchWindow = window.getContext().get(IWorkbenchWindow.class);
+				IWorkbenchPage page = workbenchWindow.getActivePage();
+				if (page != null) {
+					try {
+						page.showView(viewDescriptor.getElementId());
+					} catch (PartInitException e) {
+						WorkbenchPlugin.log(e);
+					}
+				}
+			} else {
+				EPartService partService = window.getContext().get(EPartService.class);
+				MPart part = partService.findPart(id);
+				if (part == null) {
+					MPlaceholder placeholder = partService.createSharedPart(id);
+					part = (MPart) placeholder.getRef();
+				}
+				partService.showPart(part, PartState.ACTIVATE);
+			}
+		}
+	}
+
+	@Override
+	public String getId() {
+		return viewDescriptor.getElementId();
+	}
+
+	@Override
+	public ImageDescriptor getImageDescriptor() {
+		return imageDescriptor;
+	}
+
+	@Override
+	public String getLabel() {
+		String viewLabel = LocalizationHelper.getLocalized(viewDescriptor.getLabel(), viewDescriptor,
+				window.getContext());
+		String categoryLabel = LocalizationHelper.getLocalized(viewDescriptor.getCategory(), viewDescriptor,
+				window.getContext());
+		if (categoryLabel != null) {
+			return NLS.bind(QuickAccessMessages.QuickAccess_ViewWithCategory, viewLabel, categoryLabel);
+		}
+		return viewLabel;
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result
+				+ ((viewDescriptor == null) ? 0 : viewDescriptor.hashCode());
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		final ViewElement other = (ViewElement) obj;
+		if (viewDescriptor == null) {
+			if (other.viewDescriptor != null)
+				return false;
+		} else if (!viewDescriptor.equals(other.viewDescriptor))
+			return false;
+		return true;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/ViewProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/ViewProvider.java
new file mode 100644
index 0000000..eb29a7c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/ViewProvider.java
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.quickaccess;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.descriptor.basic.MPartDescriptor;
+import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.activities.WorkbenchActivityHelper;
+import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.internal.e4.compatibility.CompatibilityEditor;
+import org.eclipse.ui.internal.e4.compatibility.CompatibilityPart;
+import org.eclipse.ui.views.IViewDescriptor;
+import org.eclipse.ui.views.IViewRegistry;
+
+/**
+ * @since 3.3
+ *
+ */
+public class ViewProvider extends QuickAccessProvider {
+
+	private MApplication application;
+	private MWindow window;
+	private Map<String, QuickAccessElement> idToElement = new HashMap<>();
+	private IViewRegistry viewRegistry;
+
+	public ViewProvider(MApplication application, MWindow window) {
+		this.application = application;
+		this.window = window;
+		this.viewRegistry = PlatformUI.getWorkbench().getViewRegistry();
+	}
+
+	@Override
+	public String getId() {
+		return "org.eclipse.e4.ui.parts"; //$NON-NLS-1$
+	}
+
+	@Override
+	public QuickAccessElement getElementForId(String id) {
+		getElements();
+		return idToElement.get(id);
+	}
+
+	@Override
+	public QuickAccessElement[] getElements() {
+		IWorkbenchWindow workbenchWindow = window.getContext().get(IWorkbenchWindow.class);
+		if (workbenchWindow == null || workbenchWindow.getActivePage() == null) {
+			return new QuickAccessElement[0];
+		}
+
+		if (idToElement.isEmpty()) {
+			List<MPartDescriptor> descriptors = application.getDescriptors();
+			for (int i = 0; i < descriptors.size(); i++) {
+				MPartDescriptor descriptor = descriptors.get(i);
+				String uri = descriptor.getContributionURI();
+				if (uri != null) {
+					String id = descriptor.getElementId();
+					if (id != null && !id.equals(CompatibilityEditor.MODEL_ELEMENT_ID)) {
+						ViewElement element = new ViewElement(this, window, descriptor);
+						if (uri.equals(CompatibilityPart.COMPATIBILITY_VIEW_URI)) {
+							IViewDescriptor viewDescriptor = viewRegistry.find(element.getId());
+							// Ignore if restricted
+							if (viewDescriptor == null)
+								continue;
+							// Ignore if filtered
+							if (!WorkbenchActivityHelper.filterItem(viewDescriptor)) {
+								idToElement.put(element.getId(), element);
+							}
+						} else {
+							idToElement.put(id, element);
+						}
+					}
+				}
+			}
+		}
+		return idToElement.values().toArray(new QuickAccessElement[idToElement.size()]);
+	}
+
+	@Override
+	public ImageDescriptor getImageDescriptor() {
+		return WorkbenchImages
+				.getImageDescriptor(IWorkbenchGraphicConstants.IMG_VIEW_DEFAULTVIEW_MISC);
+	}
+
+	@Override
+	public String getName() {
+		return QuickAccessMessages.QuickAccess_Views;
+	}
+
+	@Override
+	protected void doReset() {
+		idToElement.clear();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/WizardElement.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/WizardElement.java
new file mode 100644
index 0000000..65502e6
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/WizardElement.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.quickaccess;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.actions.NewWizardShortcutAction;
+import org.eclipse.ui.wizards.IWizardDescriptor;
+
+/**
+ * @since 3.3
+ *
+ */
+public class WizardElement extends QuickAccessElement {
+
+	private static final String separator = " - "; //$NON-NLS-1$
+
+	private IWizardDescriptor wizardDescriptor;
+
+	/* package */WizardElement(IWizardDescriptor wizardDescriptor, WizardProvider wizardProvider) {
+		super(wizardProvider);
+		this.wizardDescriptor = wizardDescriptor;
+	}
+
+	@Override
+	public void execute() {
+		IWorkbenchWindow window = PlatformUI.getWorkbench()
+				.getActiveWorkbenchWindow();
+		if (window != null) {
+			NewWizardShortcutAction wizardAction = new NewWizardShortcutAction(
+					window, wizardDescriptor);
+			wizardAction.run();
+		}
+	}
+
+	@Override
+	public String getId() {
+		return wizardDescriptor.getId();
+	}
+
+	@Override
+	public ImageDescriptor getImageDescriptor() {
+		return wizardDescriptor.getImageDescriptor();
+	}
+
+	@Override
+	public String getLabel() {
+		return wizardDescriptor.getLabel() + separator
+				+ wizardDescriptor.getDescription();
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime
+				* result
+				+ ((wizardDescriptor == null) ? 0 : wizardDescriptor.hashCode());
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		final WizardElement other = (WizardElement) obj;
+		if (wizardDescriptor == null) {
+			if (other.wizardDescriptor != null)
+				return false;
+		} else if (!wizardDescriptor.equals(other.wizardDescriptor))
+			return false;
+		return true;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/WizardProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/WizardProvider.java
new file mode 100644
index 0000000..cd956cf
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/WizardProvider.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.quickaccess;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.activities.WorkbenchActivityHelper;
+import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.wizards.IWizardCategory;
+import org.eclipse.ui.wizards.IWizardDescriptor;
+
+/**
+ * @since 3.3
+ *
+ */
+public class WizardProvider extends QuickAccessProvider {
+
+	private QuickAccessElement[] cachedElements;
+	private Map<String, WizardElement> idToElement = new HashMap<>();
+
+	@Override
+	public QuickAccessElement getElementForId(String id) {
+		getElements();
+		return idToElement.get(id);
+	}
+
+	@Override
+	public QuickAccessElement[] getElements() {
+		if (cachedElements == null) {
+			IWizardCategory rootCategory = WorkbenchPlugin.getDefault()
+					.getNewWizardRegistry().getRootCategory();
+			List<IWizardDescriptor> result = new ArrayList<>();
+			collectWizards(rootCategory, result);
+			IWizardDescriptor[] wizards = result
+					.toArray(new IWizardDescriptor[result.size()]);
+			for (int i = 0; i < wizards.length; i++) {
+				if (!WorkbenchActivityHelper.filterItem(wizards[i])) {
+					WizardElement wizardElement = new WizardElement(wizards[i], this);
+					idToElement.put(wizardElement.getId(), wizardElement);
+				}
+			}
+			cachedElements = idToElement.values().toArray(
+					new QuickAccessElement[idToElement.size()]);
+		}
+		return cachedElements;
+	}
+
+	private void collectWizards(IWizardCategory category, List<IWizardDescriptor> result) {
+		result.addAll(Arrays.asList(category.getWizards()));
+		for (IWizardCategory childCategory : category.getCategories()) {
+			collectWizards(childCategory, result);
+		}
+	}
+
+	@Override
+	public String getId() {
+		return "org.eclipse.ui.wizards"; //$NON-NLS-1$
+	}
+
+	@Override
+	public ImageDescriptor getImageDescriptor() {
+		return WorkbenchImages
+				.getImageDescriptor(IWorkbenchGraphicConstants.IMG_OBJ_NODE);
+	}
+
+	@Override
+	public String getName() {
+		return QuickAccessMessages.QuickAccess_New;
+	}
+
+	@Override
+	protected void doReset() {
+		cachedElements = null;
+		idToElement.clear();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/messages.properties b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/messages.properties
new file mode 100644
index 0000000..99b7a45
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/quickaccess/messages.properties
@@ -0,0 +1,32 @@
+###############################################################################
+# Copyright (c) 2005, 2016 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
+#     Patrik Suzzi <psuzzi@gmail.com> - Bug 488926, 491293, 492907, 459989
+###############################################################################
+QuickAccess_Editors=Editors
+QuickAccess_Views=Views
+QuickAccess_Perspectives=Perspectives
+QuickAccess_Commands=Commands
+QuickAccess_Menus=Menus
+QuickAccess_New=New
+QuickAccess_Preferences=Preferences
+QuickAccess_Previous=Previous Choices
+QuickAccess_Properties=Properties
+QuickAccess_PressKeyToShowAllMatches=Results per category are limited. Press ''{0}'' to see all
+QuickAccess_StartTypingToFindMatches=Start typing to search commands and more...
+QuickAccess_AvailableCategories=Available categories:
+QuickAccess_EnterSearch=Quick Access
+QuickAccess_TooltipDescription=Access commands and other items ({0})
+QuickAccess_TooltipDescription_Empty=Access commands and other items
+QuickAccess_SelectedString={0}: {1}
+QuickAccess_ViewWithCategory={0} ({1})
+QuickAccessContents_NoMatchingResults=No matches found
+QuickAccessContents_PressKeyToLimitResults=Press ''{0}'' to restrict results per category
+QuickAccessContents_QuickAccess=Quick Access
+QuickAccessContents_SearchInHelpLabel=Search ''{0}'' in Help
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/ActionSetDescriptor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/ActionSetDescriptor.java
new file mode 100644
index 0000000..853f432
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/ActionSetDescriptor.java
@@ -0,0 +1,231 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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.ui.internal.registry;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Preferences;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.IPluginContribution;
+import org.eclipse.ui.internal.PluginActionSet;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.model.IWorkbenchAdapter;
+
+/**
+ * ActionSetDescriptor
+ */
+public class ActionSetDescriptor implements IActionSetDescriptor, IAdaptable,
+        IWorkbenchAdapter, IPluginContribution {
+    private static final Object[] NO_CHILDREN = new Object[0];
+
+    private static final String INITIALLY_HIDDEN_PREF_ID_PREFIX = "actionSet.initiallyHidden."; //$NON-NLS-1$
+
+    private String id;
+
+    private String pluginId;
+
+    private String label;
+
+    private boolean visible;
+
+    private String description;
+
+    private IConfigurationElement configElement;
+
+    /**
+     * Create a descriptor from a configuration element.
+     *
+     * @param configElement the configuration element
+     * @throws CoreException thrown if there is an issue creating the descriptor
+     */
+    public ActionSetDescriptor(IConfigurationElement configElement)
+            throws CoreException {
+        super();
+        this.configElement = configElement;
+        id = configElement.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+        pluginId = configElement.getNamespace();
+        label = configElement.getAttribute(IWorkbenchRegistryConstants.ATT_LABEL);
+        description = configElement.getAttribute(IWorkbenchRegistryConstants.TAG_DESCRIPTION);
+        String str = configElement.getAttribute(IWorkbenchRegistryConstants.ATT_VISIBLE);
+        if (str != null && str.equals("true")) { //$NON-NLS-1$
+			visible = true;
+		}
+
+        // Sanity check.
+        if (label == null) {
+            throw new CoreException(new Status(IStatus.ERROR,
+                    WorkbenchPlugin.PI_WORKBENCH, 0,
+                    "Invalid extension (missing label): " + id,//$NON-NLS-1$
+                    null));
+        }
+    }
+
+    /**
+     * Returns the action set for this descriptor.
+     *
+     * @return the action set
+     */
+    @Override
+	public IActionSet createActionSet() throws CoreException {
+        return new PluginActionSet(this);
+    }
+
+    /**
+     * Returns an object which is an instance of the given class
+     * associated with this object. Returns <code>null</code> if
+     * no such object can be found.
+     */
+	@Override
+	public <T> T getAdapter(Class<T> adapter) {
+        if (adapter == IWorkbenchAdapter.class) {
+			return adapter.cast(this);
+		}
+        return null;
+    }
+
+    /**
+     * @see IWorkbenchAdapter#getChildren
+     */
+    @Override
+	public Object[] getChildren(Object o) {
+
+
+        return NO_CHILDREN;
+    }
+
+
+    @Override
+	public IConfigurationElement getConfigurationElement() {
+        return configElement;
+    }
+
+    /**
+     * Returns this action set's description.
+     * This is the value of its <code>"description"</code> attribute.
+     *
+     * @return the description
+     */
+    @Override
+	public String getDescription() {
+        return description;
+    }
+
+    /**
+     * Returns this action set's id.
+     * This is the value of its <code>"id"</code> attribute.
+     * <p>
+     *
+     * @return the action set id
+     */
+    @Override
+	public String getId() {
+        return id;
+    }
+
+    /**
+     * Returns this action set's label.
+     * This is the value of its <code>"label"</code> attribute.
+     *
+     * @return the label
+     */
+    @Override
+	public String getLabel() {
+        return label;
+    }
+
+    /**
+     * @see IWorkbenchAdapter#getLabel
+     */
+    @Override
+	public String getLabel(Object o) {
+        if (o == this) {
+			return getLabel();
+		}
+        return "Unknown Label";//$NON-NLS-1$
+    }
+
+    /**
+     * Returns whether this action set is initially visible.
+     */
+    @Override
+	public boolean isInitiallyVisible() {
+        if (id == null) {
+			return visible;
+		}
+        Preferences prefs = WorkbenchPlugin.getDefault().getPluginPreferences();
+        String prefId = INITIALLY_HIDDEN_PREF_ID_PREFIX + getId();
+        if (prefs.getBoolean(prefId)) {
+			return false;
+		}
+        return visible;
+    }
+
+    /**
+     * Sets whether this action set is initially visible.
+     * If the action set identifier is undefined, then this is ignored.
+     *
+     * @since 3.0
+     */
+    @Override
+	public void setInitiallyVisible(boolean newValue) {
+        if (id == null) {
+			return;
+		}
+        Preferences prefs = WorkbenchPlugin.getDefault().getPluginPreferences();
+        String prefId = INITIALLY_HIDDEN_PREF_ID_PREFIX + getId();
+        prefs.setValue(prefId, !newValue);
+    }
+
+    @Override
+	public ImageDescriptor getImageDescriptor(Object object) {
+        return null;
+    }
+
+    @Override
+	public Object getParent(Object o) {
+        return null;
+    }
+
+    @Override
+	public String getLocalId() {
+        return id;
+    }
+
+    @Override
+	public String getPluginId() {
+        return pluginId;
+    }
+
+    @Override
+	public boolean equals(Object arg0) {
+        if (!(arg0 instanceof ActionSetDescriptor)) {
+            return false;
+        }
+
+        ActionSetDescriptor descr = (ActionSetDescriptor) arg0;
+
+        return id.equals(descr.id) && descr.pluginId.equals(pluginId);
+    }
+
+    @Override
+	public int hashCode() {
+        return id.hashCode() + pluginId.hashCode();
+    }
+
+	@Override
+	public String toString() {
+		return "ActionSetDescriptor [id=" + id + ", visible=" + visible + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/ActionSetRegistry.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/ActionSetRegistry.java
new file mode 100644
index 0000000..366693b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/ActionSetRegistry.java
@@ -0,0 +1,354 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *******************************************************************************/
+package org.eclipse.ui.internal.registry;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import org.eclipse.core.commands.contexts.Context;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.dynamichelpers.ExtensionTracker;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.contexts.IContextService;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+
+/**
+ * The registry of action set extensions.
+ */
+public class ActionSetRegistry implements IExtensionChangeHandler {
+
+    /**
+     * @since 3.1
+     */
+    private class ActionSetPartAssociation {
+        /**
+         * @param partId
+         * @param actionSetId
+         */
+        public ActionSetPartAssociation(String partId, String actionSetId) {
+            this.partId = partId;
+            this.actionSetId = actionSetId;
+        }
+
+
+        String partId;
+        String actionSetId;
+    }
+
+    private ArrayList children = new ArrayList();
+
+    private Map mapPartToActionSetIds = new HashMap();
+
+    private Map mapPartToActionSets = new HashMap();
+
+	private IContextService contextService;
+
+    /**
+     * Creates the action set registry.
+     */
+    public ActionSetRegistry() {
+    	contextService = PlatformUI
+				.getWorkbench().getService(IContextService.class);
+		PlatformUI.getWorkbench().getExtensionTracker().registerHandler(
+                this,
+                ExtensionTracker
+                        .createExtensionPointFilter(new IExtensionPoint[] {
+                                getActionSetExtensionPoint(),
+                                getActionSetPartAssociationExtensionPoint() }));
+        readFromRegistry();
+    }
+
+    /**
+     * Return the action set part association extension point.
+     *
+     * @return the action set part association extension point
+     * @since 3.1
+     */
+    private IExtensionPoint getActionSetPartAssociationExtensionPoint() {
+        return Platform
+        .getExtensionRegistry().getExtensionPoint(
+                PlatformUI.PLUGIN_EXTENSION_NAME_SPACE,
+                IWorkbenchRegistryConstants.PL_ACTION_SET_PART_ASSOCIATIONS);
+    }
+
+    /**
+     * Return the action set extension point.
+     *
+     * @return the action set extension point
+     * @since 3.1
+     */
+    private IExtensionPoint getActionSetExtensionPoint() {
+        return Platform
+                .getExtensionRegistry().getExtensionPoint(
+                        PlatformUI.PLUGIN_EXTENSION_NAME_SPACE,
+                        IWorkbenchRegistryConstants.PL_ACTION_SETS);
+    }
+
+    /**
+     * Adds an action set.
+     * @param desc
+     */
+    private void addActionSet(ActionSetDescriptor desc) {
+		children.add(desc);
+		Context actionSetContext = contextService.getContext(desc.getId());
+		if (!actionSetContext.isDefined()) {
+			actionSetContext.define(desc.getLabel(), desc.getDescription(),
+					"org.eclipse.ui.contexts.actionSet"); //$NON-NLS-1$
+		}
+	}
+
+	/**
+	 * Remove the action set.
+	 *
+	 * @param desc
+	 */
+	private void removeActionSet(IActionSetDescriptor desc) {
+		Context actionSetContext = contextService.getContext(desc.getId());
+		if (actionSetContext.isDefined()) {
+			actionSetContext.undefine();
+		}
+		children.remove(desc);
+	}
+
+	/**
+     * Adds an association between an action set an a part.
+     */
+    private Object addAssociation(String actionSetId, String partId) {
+        // get the action set ids for this part
+        ArrayList actionSets = (ArrayList) mapPartToActionSetIds.get(partId);
+        if (actionSets == null) {
+            actionSets = new ArrayList();
+            mapPartToActionSetIds.put(partId, actionSets);
+        }
+        actionSets.add(actionSetId);
+
+        ActionSetPartAssociation association = new ActionSetPartAssociation(partId, actionSetId);
+        return association;
+    }
+
+    /**
+     * Finds and returns the registered action set with the given id.
+     *
+     * @param id the action set id
+     * @return the action set, or <code>null</code> if none
+     * @see IActionSetDescriptor#getId
+     */
+    public IActionSetDescriptor findActionSet(String id) {
+        Iterator i = children.iterator();
+        while (i.hasNext()) {
+            IActionSetDescriptor desc = (IActionSetDescriptor) i.next();
+            if (desc.getId().equals(id)) {
+				return desc;
+			}
+        }
+        return null;
+    }
+
+    /**
+     * Returns a list of the action sets known to the workbench.
+     *
+     * @return a list of action sets
+     */
+    public IActionSetDescriptor[] getActionSets() {
+        return (IActionSetDescriptor []) children.toArray(new IActionSetDescriptor [children.size()]);
+    }
+
+    /**
+     * Returns a list of the action sets associated with the given part id.
+     *
+     * @param partId the part id
+     * @return a list of action sets
+     */
+    public IActionSetDescriptor[] getActionSetsFor(String partId) {
+        // check the resolved map first
+        ArrayList actionSets = (ArrayList) mapPartToActionSets.get(partId);
+        if (actionSets != null) {
+            return (IActionSetDescriptor[]) actionSets
+                    .toArray(new IActionSetDescriptor[actionSets.size()]);
+        }
+
+        // get the action set ids for this part
+        ArrayList actionSetIds = (ArrayList) mapPartToActionSetIds.get(partId);
+        if (actionSetIds == null) {
+			return new IActionSetDescriptor[0];
+		}
+
+        // resolve to action sets
+        actionSets = new ArrayList(actionSetIds.size());
+        for (Iterator i = actionSetIds.iterator(); i.hasNext();) {
+            String actionSetId = (String) i.next();
+            IActionSetDescriptor actionSet = findActionSet(actionSetId);
+            if (actionSet != null) {
+				actionSets.add(actionSet);
+			} else {
+               WorkbenchPlugin.log("Unable to associate action set with part: " + //$NON-NLS-1$
+                        partId + ". Action set " + actionSetId + " not found."); //$NON-NLS-2$ //$NON-NLS-1$
+            }
+        }
+
+        mapPartToActionSets.put(partId, actionSets);
+
+        return (IActionSetDescriptor[]) actionSets
+                .toArray(new IActionSetDescriptor[actionSets.size()]);
+    }
+
+    /**
+     * Reads the registry.
+     */
+    private void readFromRegistry() {
+		for (IExtension extension : getActionSetExtensionPoint().getExtensions()) {
+			addActionSets(PlatformUI.getWorkbench().getExtensionTracker(), extension);
+        }
+
+		for (IExtension extension : getActionSetPartAssociationExtensionPoint().getExtensions()) {
+			addActionSetPartAssociations(PlatformUI.getWorkbench().getExtensionTracker(), extension);
+        }
+    }
+
+    @Override
+	public void addExtension(IExtensionTracker tracker, IExtension extension) {
+        String extensionPointUniqueIdentifier = extension.getExtensionPointUniqueIdentifier();
+        if (extensionPointUniqueIdentifier.equals(getActionSetExtensionPoint().getUniqueIdentifier())) {
+            addActionSets(tracker, extension);
+        }
+        else if (extensionPointUniqueIdentifier.equals(getActionSetPartAssociationExtensionPoint().getUniqueIdentifier())){
+            addActionSetPartAssociations(tracker, extension);
+        }
+    }
+
+    /**
+     * @param tracker
+     * @param extension
+     */
+    private void addActionSetPartAssociations(IExtensionTracker tracker, IExtension extension) {
+		for (IConfigurationElement element : extension.getConfigurationElements()) {
+            if (element.getName().equals(IWorkbenchRegistryConstants.TAG_ACTION_SET_PART_ASSOCIATION)) {
+                String actionSetId = element.getAttribute(IWorkbenchRegistryConstants.ATT_TARGET_ID);
+				for (IConfigurationElement child : element.getChildren()) {
+                    if (child.getName().equals(IWorkbenchRegistryConstants.TAG_PART)) {
+                        String partId = child.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+                        if (partId != null) {
+                            Object trackingObject = addAssociation(actionSetId, partId);
+                            if (trackingObject != null) {
+                                tracker.registerObject(extension,
+                                        trackingObject,
+                                        IExtensionTracker.REF_STRONG);
+
+                            }
+
+                        }
+                    } else {
+                        WorkbenchPlugin.log("Unable to process element: " + //$NON-NLS-1$
+                                child.getName() + " in action set part associations extension: " + //$NON-NLS-1$
+                                extension.getUniqueIdentifier());
+                    }
+                }
+            }
+        }
+
+        // TODO: optimize
+        mapPartToActionSets.clear();
+    }
+
+    /**
+     * @param tracker
+     * @param extension
+     */
+    private void addActionSets(IExtensionTracker tracker, IExtension extension) {
+		for (IConfigurationElement element : extension.getConfigurationElements()) {
+            if (element.getName().equals(IWorkbenchRegistryConstants.TAG_ACTION_SET)) {
+                try {
+                    ActionSetDescriptor desc = new ActionSetDescriptor(element);
+                    addActionSet(desc);
+                    tracker.registerObject(extension, desc, IExtensionTracker.REF_WEAK);
+
+                } catch (CoreException e) {
+                    // log an error since its not safe to open a dialog here
+                    WorkbenchPlugin
+                            .log(
+                                    "Unable to create action set descriptor.", e.getStatus());//$NON-NLS-1$
+                }
+            }
+        }
+
+        // TODO: optimize
+        mapPartToActionSets.clear();
+    }
+
+    @Override
+	public void removeExtension(IExtension extension, Object[] objects) {
+        String extensionPointUniqueIdentifier = extension.getExtensionPointUniqueIdentifier();
+        if (extensionPointUniqueIdentifier.equals(getActionSetExtensionPoint().getUniqueIdentifier())) {
+            removeActionSets(objects);
+        }
+        else if (extensionPointUniqueIdentifier.equals(getActionSetPartAssociationExtensionPoint().getUniqueIdentifier())){
+            removeActionSetPartAssociations(objects);
+        }
+    }
+
+    /**
+     * @param objects
+     */
+    private void removeActionSetPartAssociations(Object[] objects) {
+        for (Object object : objects) {
+            if (object instanceof ActionSetPartAssociation) {
+                ActionSetPartAssociation association = (ActionSetPartAssociation) object;
+                String actionSetId = association.actionSetId;
+                ArrayList actionSets = (ArrayList) mapPartToActionSetIds.get(association.partId);
+                if (actionSets == null) {
+					return;
+				}
+                actionSets.remove(actionSetId);
+                if (actionSets.isEmpty()) {
+					mapPartToActionSetIds.remove(association.partId);
+				}
+            }
+        }
+        // TODO: optimize
+        mapPartToActionSets.clear();
+
+    }
+
+    /**
+     * @param objects
+     */
+    private void removeActionSets(Object[] objects) {
+        for (Object object : objects) {
+            if (object instanceof IActionSetDescriptor) {
+                IActionSetDescriptor desc = (IActionSetDescriptor) object;
+                removeActionSet(desc);
+
+                // now clean up the part associations
+                // TODO: this is expensive. We should consider another map from
+                // actionsets
+                // to parts.
+                for (Iterator j = mapPartToActionSetIds.values().iterator(); j
+                        .hasNext();) {
+                    ArrayList list = (ArrayList) j.next();
+                    list.remove(desc.getId());
+                    if (list.isEmpty()) {
+						j.remove();
+					}
+                }
+            }
+        }
+        // TODO: optimize
+        mapPartToActionSets.clear();
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/CategorizedPageRegistryReader.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/CategorizedPageRegistryReader.java
new file mode 100644
index 0000000..3313ab7
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/CategorizedPageRegistryReader.java
@@ -0,0 +1,271 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Oakland Software (Francis Upton) <francisu@ieee.org> - bug 219273
+ *******************************************************************************/
+package org.eclipse.ui.internal.registry;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.StringTokenizer;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.misc.StatusUtil;
+
+/**
+ * The CategorizedPageRegistryReader is the abstract super class
+ * of registry readers for page that have categorization.
+ */
+public abstract class CategorizedPageRegistryReader extends RegistryReader {
+
+	public static final String ATT_CATEGORY = "category"; //$NON-NLS-1$
+
+	static final String PREFERENCE_SEPARATOR = "/"; //$NON-NLS-1$
+
+	List topLevelNodes;
+
+	/**
+	 * Internal class used to sort all the preference page nodes
+	 * based on the category.
+	 */
+	abstract class CategoryNode {
+		/**
+		 * Comment for <code>reader</code>
+		 */
+		private final CategorizedPageRegistryReader reader;
+
+		//private WorkbenchPreferenceNode node;
+
+		private String flatCategory;
+
+		/**
+		 * Default constructor
+		 */
+		public CategoryNode(CategorizedPageRegistryReader reader) {
+			this.reader = reader;
+		}
+
+		/**
+		 * Return the flatten category
+		 */
+		public String getFlatCategory() {
+			if (flatCategory == null) {
+				initialize();
+				if (flatCategory == null) {
+					flatCategory = getLabelText();
+				}
+			}
+			return flatCategory;
+		}
+
+		/**
+		 * Get the label text for this node.
+		 * @return String
+		 */
+		abstract String getLabelText();
+
+		/*
+		 * Initialize the flat category to include the parents'
+		 * category names and the current node's label
+		 */
+		private void initialize() {
+			String category = reader.getCategory(getNode());
+			if (category == null) {
+				return;
+			}
+
+			StringBuffer sb = new StringBuffer();
+			StringTokenizer stok = new StringTokenizer(category, PREFERENCE_SEPARATOR);
+			Object immediateParent = null;
+			while (stok.hasMoreTokens()) {
+				String pathID = stok.nextToken();
+				immediateParent = this.reader.findNode(pathID);
+				if (immediateParent == null) {
+					return;
+				}
+				if (sb.length() > 0) {
+					sb.append(PREFERENCE_SEPARATOR);
+				}
+				sb.append(getLabelText(immediateParent));
+			}
+
+			if (sb.length() > 0) {
+				sb.append(PREFERENCE_SEPARATOR);
+			}
+			sb.append(getLabelText());
+			flatCategory = sb.toString();
+		}
+
+		/**
+		 * Return the label text for the passed element.
+		 * @param element
+		 * @return String
+		 */
+		abstract String getLabelText(Object element);
+
+		/**
+		 * Get the node the receiver represents.
+		 * @return Object
+		 */
+		abstract Object getNode();
+	}
+
+	/**
+	 * Create a new instance of the receiver.
+	 */
+	public CategorizedPageRegistryReader() {
+		super();
+	}
+
+	/**
+	 * Process the preference page nodes.
+	 */
+	void processNodes() {
+		topLevelNodes = new ArrayList();
+		//root nodes (which contain subnodes)
+
+		//Add root nodes to the contributions vector
+		StringTokenizer tokenizer;
+		String currentToken;
+
+
+		CategoryNode[] nodes = createCategoryNodes(getNodes());
+		// flag to indicate that some work was done in the inner loop over the nodes
+		boolean workDone;
+		do {
+			//reset the flag
+			workDone = false;
+			List deferred = new ArrayList();
+			for (CategoryNode categoryNode : nodes) {
+				Object node = categoryNode.getNode();
+
+				String category = getCategory(node);
+				if (category == null) {
+					topLevelNodes.add(node);
+					continue;
+				}
+				// has category
+				tokenizer = new StringTokenizer(category, PREFERENCE_SEPARATOR);
+				Object parent = null;
+				while (tokenizer.hasMoreElements()) {
+					currentToken = tokenizer.nextToken();
+					Object child = null;
+					if (parent == null) {
+						child = findNode(currentToken);
+					} else {
+						child = findNode(parent, currentToken);
+					}
+
+					if (child == null) {
+						parent = null;
+						break;
+					}
+					parent = child;
+				}
+				if (parent != null) {
+					//we've done some work - the number of nodes to process has decreased
+					workDone = true;
+					add(parent, node);
+				} else {
+					// we haven't done any work - the parent for this node has not been found.
+					deferred.add(categoryNode);
+				}
+			}
+			// reset the nodes to all that have yet to find their proper parent
+			nodes = (CategoryNode[]) deferred.toArray(new CategoryNode[deferred
+					.size()]);
+		} while (nodes.length > 0 && workDone); // loop while we still have nodes to work on and the list is shrinking
+
+		// log anything left over.
+		for (CategoryNode categoryNode : nodes) {
+			// Could not find the parent - log
+			WorkbenchPlugin.log(StatusUtil.newStatus(IStatus.WARNING,
+					invalidCategoryNodeMessage(categoryNode), null));
+			topLevelNodes.add(categoryNode.getNode());
+		}
+	}
+
+	/**
+	 * Return a warning message for an invalid category path.
+	 *
+	 * @param categoryNode
+	 *            the unknown category node
+	 * @return an english string suitable for logging
+	 */
+	protected abstract String invalidCategoryNodeMessage(CategoryNode categoryNode);
+
+	/**
+	 * Get the category for the node if there is one. If there isn't return
+	 * <code>null</code>.
+	 *
+	 * @param node
+	 * @return String or <code>null</code>.
+	 */
+	abstract String getCategory(Object node);
+
+	/**
+	 * Add the node to the parent.
+	 * @param parent
+	 * @param node
+	 */
+	abstract void add(Object parent, Object node);
+
+	/**
+	 * Get the nodes for the receiver.
+	 * @return Collection of Object
+	 */
+	abstract Collection getNodes();
+
+	/**
+	 * Sort the nodes based on full category + name. Category used for sorting
+	 * is created by substituting node IDs with labels of the referenced
+	 * nodes. workbench node is excluded from sorting because it always
+	 * appears first in the dialog.
+	 */
+	CategoryNode[] createCategoryNodes(Collection nodesToCategorize) {
+		//sort by categories
+		List nodes = new ArrayList();
+
+		Iterator nodesIterator = nodesToCategorize.iterator();
+		while (nodesIterator.hasNext()) {
+			nodes.add(createCategoryNode(this, nodesIterator.next()));
+		}
+
+		return (CategoryNode[]) nodes.toArray(new CategoryNode[nodes.size()]);
+	}
+
+	/**
+	 * Create a node for categorization from the reader
+	 * and the supplied object.
+	 * @param reader
+	 * @param object
+	 * @return CategoryNode
+	 */
+	abstract CategoryNode createCategoryNode(CategorizedPageRegistryReader reader, Object object);
+
+	/**
+	 * Searches for the top-level node with the given id.
+	 * @param id
+	 * @return Object of the type being categorized or
+	 * <code>null</code>
+	 */
+	abstract Object findNode(String id);
+
+	/**
+	 * Find the node with the given parent with the id
+	 * of currentToken.
+	 * @param parent
+	 * @param currentToken
+	 * @return
+	 */
+	abstract Object findNode(Object parent, String currentToken);
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/Category.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/Category.java
new file mode 100644
index 0000000..aa1e46d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/Category.java
@@ -0,0 +1,264 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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.ui.internal.registry;
+
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.IPluginContribution;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.WorkbenchException;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.model.IWorkbenchAdapter;
+
+/**
+ * Category provides for hierarchical grouping of elements
+ * registered in the registry. One extension normally defines
+ * a category, and other reference it via its ID.
+ * <p>
+ * A category may specify its parent category in order to
+ * achieve hierarchy.
+ * </p>
+ */
+public class Category implements IWorkbenchAdapter, IPluginContribution, IAdaptable {
+    /**
+     * Name of the miscellaneous category
+     */
+    public final static String MISC_NAME = WorkbenchMessages.get().ICategory_other;
+
+    /**
+     * Identifier of the miscellaneous category
+     */
+    public final static String MISC_ID = "org.eclipse.ui.internal.otherCategory"; //$NON-NLS-1$
+
+    private String id;
+
+    private String name;
+
+    private String[] parentPath;
+
+    private ArrayList elements;
+
+    private IConfigurationElement configurationElement;
+
+	private String pluginId;
+
+    /**
+     * Creates an instance of <code>Category</code> as a
+     * miscellaneous category.
+     */
+    public Category() {
+        this.id = MISC_ID;
+        this.name = MISC_NAME;
+        this.pluginId = MISC_ID; // TODO: remove hack for bug 55172
+    }
+
+    /**
+     * Creates an instance of <code>Category</code> with
+     * an ID and label.
+     *
+     * @param id the unique identifier for the category
+     * @param label the presentation label for this category
+     */
+    public Category(String id, String label) {
+        this.id = id;
+        this.name = label;
+    }
+
+    /**
+     * Creates an instance of <code>Category</code> using the
+     * information from the specified configuration element.
+     *
+     * @param configElement the <code>IConfigurationElement<code> containing
+     * 		the ID, label, and optional parent category path.
+     * @throws WorkbenchException if the ID or label is <code>null</code
+     */
+    public Category(IConfigurationElement configElement)
+            throws WorkbenchException {
+        id = configElement.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+
+        configurationElement = configElement;
+        if (id == null || getLabel() == null) {
+			throw new WorkbenchException("Invalid category: " + id); //$NON-NLS-1$
+		}
+    }
+
+
+    /**
+     * Add an element to this category.
+     *
+     * @param element the element to add
+     */
+    public void addElement(Object element) {
+        if (elements == null) {
+			elements = new ArrayList(5);
+		}
+        elements.add(element);
+    }
+
+	@Override
+	public <T> T getAdapter(Class<T> adapter) {
+        if (adapter == IWorkbenchAdapter.class) {
+			return adapter.cast(this);
+		} else if (adapter == IConfigurationElement.class) {
+			return adapter.cast(configurationElement);
+		} else {
+			return null;
+		}
+    }
+
+    @Override
+	public Object[] getChildren(Object o) {
+        return getElements().toArray();
+    }
+
+    @Override
+	public ImageDescriptor getImageDescriptor(Object object) {
+        return WorkbenchImages.getImageDescriptor(ISharedImages.IMG_OBJ_FOLDER);
+    }
+
+    @Override
+	public String getLabel(Object o) {
+        return getLabel();
+    }
+
+    /**
+     * Return the id for this category.
+     * @return the id
+     */
+    public String getId() {
+        return id;
+    }
+
+    /**
+     * Return the label for this category.
+     *
+     * @return the label
+     */
+    public String getLabel() {
+        return configurationElement == null ? name : configurationElement
+				.getAttribute(IWorkbenchRegistryConstants.ATT_NAME);
+    }
+
+    /**
+     * Return the parent path for this category.
+     *
+     * @return the parent path
+     */
+    public String[] getParentPath() {
+    	if (parentPath != null) {
+			return parentPath;
+		}
+
+    	String unparsedPath = getRawParentPath();
+        if (unparsedPath != null) {
+            StringTokenizer stok = new StringTokenizer(unparsedPath, "/"); //$NON-NLS-1$
+            parentPath = new String[stok.countTokens()];
+            for (int i = 0; stok.hasMoreTokens(); i++) {
+                parentPath[i] = stok.nextToken();
+            }
+        }
+
+        return parentPath;
+    }
+
+    /**
+     * Return the unparsed parent path.  May be <code>null</code>.
+     *
+     * @return the unparsed parent path or <code>null</code>
+     */
+    public String getRawParentPath() {
+        return configurationElement == null ? null
+                : configurationElement.getAttribute(IWorkbenchRegistryConstants.ATT_PARENT_CATEGORY);
+    }
+
+    /**
+     * Return the root path for this category.
+     *
+     * @return the root path
+     */
+    public String getRootPath() {
+        String[] path = getParentPath();
+        if (path != null && path.length > 0) {
+			return path[0];
+		}
+
+        return id;
+    }
+
+    /**
+     * Return the elements contained in this category.
+     *
+     * @return the elements
+     */
+    public ArrayList getElements() {
+        return elements;
+    }
+
+    /**
+     * Return whether a given object exists in this category.
+     *
+     * @param o the object to search for
+     * @return whether the object is in this category
+     */
+    public boolean hasElement(Object o) {
+        if (elements == null) {
+			return false;
+		}
+        if (elements.isEmpty()) {
+			return false;
+		}
+        return elements.contains(o);
+    }
+
+    /**
+     * Return whether this category has child elements.
+     *
+     * @return whether this category has child elements
+     */
+    public boolean hasElements() {
+        if (elements != null) {
+			return !elements.isEmpty();
+		}
+
+        return false;
+    }
+
+    @Override
+	public Object getParent(Object o) {
+        return null;
+    }
+
+    @Override
+	public String getLocalId() {
+        return id;
+    }
+
+    @Override
+	public String getPluginId() {
+        return configurationElement == null ? pluginId : configurationElement
+				.getNamespace();
+    }
+
+	/**
+	 * Clear all elements from this category.
+	 *
+	 * @since 3.1
+	 */
+	public void clear() {
+		if (elements != null) {
+			elements.clear();
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/EditorDescriptor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/EditorDescriptor.java
new file mode 100644
index 0000000..0184da0
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/EditorDescriptor.java
@@ -0,0 +1,639 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     James Blackburn - Bug 256316 getImageDescriptor() is not thread safe
+ *******************************************************************************/
+package org.eclipse.ui.internal.registry;
+
+import java.io.Serializable;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.IEditorActionBarContributor;
+import org.eclipse.ui.IEditorDescriptor;
+import org.eclipse.ui.IEditorMatchingStrategy;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IPluginContribution;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.internal.IWorkbenchConstants;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.tweaklets.InterceptContributions;
+import org.eclipse.ui.internal.tweaklets.Tweaklets;
+import org.eclipse.ui.internal.util.Util;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+/**
+ * @see IEditorDescriptor
+ */
+public final class EditorDescriptor implements IEditorDescriptor, Serializable,
+        IPluginContribution {
+
+    /**
+     * Generated serial version UID for this class.
+     * @since 3.1
+     */
+    private static final long serialVersionUID = 3905241225668998961L;
+
+    // @issue the following constants need not be public; see bug 47600
+    /**
+     * Open internal constant.  Value <code>0x01</code>.
+     */
+    public static final int OPEN_INTERNAL = 0x01;
+
+    /**
+     * Open in place constant.  Value <code>0x02</code>.
+     */
+    public static final int OPEN_INPLACE = 0x02;
+
+    /**
+     * Open external constant.  Value <code>0x04</code>.
+     */
+    public static final int OPEN_EXTERNAL = 0x04;
+
+    private String editorName;
+
+    private String imageFilename;
+
+    private transient ImageDescriptor imageDesc;
+    private transient Object imageDescLock = new Object();
+
+    private boolean testImage = true;
+
+    private String className;
+
+    private String launcherName;
+
+    private String fileName;
+
+    private String id = Util.ZERO_LENGTH_STRING;
+
+    private boolean matchingStrategyChecked = false;
+    private IEditorMatchingStrategy matchingStrategy;
+
+    // RAP [bm]: Program
+//  private Program program;
+
+    //The id of the plugin which contributed this editor, null for external editors
+    private String pluginIdentifier;
+
+    private int openMode = 0;
+
+    private transient IConfigurationElement configurationElement;
+
+	/**
+     * Create a new instance of an editor descriptor. Limited
+     * to internal framework calls.
+     * @param element
+     * @param id2
+     */
+    /* package */EditorDescriptor(String id2, IConfigurationElement element) {
+        setID(id2);
+        setConfigurationElement(element);
+    }
+
+
+
+	/**
+	 * Create a new instance of an editor descriptor. Limited
+     * to internal framework calls.
+	 */
+    /* package */ EditorDescriptor() {
+		super();
+	}
+
+
+
+//	/**
+//     * Creates a descriptor for an external program.
+//     *
+//     * @param filename the external editor full path and filename
+//     * @return the editor descriptor
+//     */
+//    public static EditorDescriptor createForProgram(String filename) {
+//        if (filename == null) {
+//            throw new IllegalArgumentException();
+//        }
+//        EditorDescriptor editor = new EditorDescriptor();
+//
+//        editor.setFileName(filename);
+//        editor.setID(filename);
+//        editor.setOpenMode(OPEN_EXTERNAL);
+//
+//        //Isolate the program name (no directory or extension)
+//        int start = filename.lastIndexOf(File.separator);
+//        String name;
+//        if (start != -1) {
+//            name = filename.substring(start + 1);
+//        } else {
+//            name = filename;
+//        }
+//        int end = name.lastIndexOf('.');
+//        if (end != -1) {
+//            name = name.substring(0, end);
+//        }
+//        editor.setName(name);
+//
+//        // get the program icon without storing it in the registry
+//        ImageDescriptor imageDescriptor = new ProgramImageDescriptor(filename,
+//                0);
+//        editor.setImageDescriptor(imageDescriptor);
+//
+//        return editor;
+//    }
+//
+//    /**
+//     * Return the program called programName. Return null if it is not found.
+//     * @return org.eclipse.swt.program.Program
+//     */
+//    private static Program findProgram(String programName) {
+//		for (Program program : Program.getPrograms()) {
+//			if (program.getName().equals(programName)) {
+//				return program;
+//			}
+//        }
+//
+//        return null;
+//    }
+
+    /**
+     * Create the editor action bar contributor for editors of this type.
+     *
+     * @return the action bar contributor, or <code>null</code>
+     */
+    public IEditorActionBarContributor createActionBarContributor() {
+        // Handle case for predefined editor descriptors, like the
+        // one for IEditorRegistry.SYSTEM_INPLACE_EDITOR_ID, which
+        // don't have a configuration element.
+        if (configurationElement == null) {
+            return null;
+        }
+
+        // Get the contributor class name.
+        String className = configurationElement
+                .getAttribute(IWorkbenchRegistryConstants.ATT_CONTRIBUTOR_CLASS);
+        if (className == null) {
+			return null;
+		}
+
+        // Create the contributor object.
+        IEditorActionBarContributor contributor = null;
+        try {
+            contributor = (IEditorActionBarContributor) WorkbenchPlugin
+                    .createExtension(configurationElement,
+                            IWorkbenchRegistryConstants.ATT_CONTRIBUTOR_CLASS);
+        } catch (CoreException e) {
+            WorkbenchPlugin.log("Unable to create editor contributor: " + //$NON-NLS-1$
+                    id, e.getStatus());
+        }
+        return contributor;
+    }
+
+    /**
+     * Return the editor class name.
+     *
+     * @return the class name
+     */
+    public String getClassName() {
+    	if (configurationElement == null) {
+    		return className;
+    	}
+    	return RegistryReader.getClassValue(configurationElement,
+                IWorkbenchRegistryConstants.ATT_CLASS);
+    }
+
+    /**
+     * Return the configuration element used to define this editor, or <code>null</code>.
+     *
+     * @return the element or null
+     */
+    public IConfigurationElement getConfigurationElement() {
+        return configurationElement;
+    }
+
+    /**
+     * Create an editor part based on this descriptor.
+     *
+     * @return the editor part
+     * @throws CoreException thrown if there is an issue creating the editor
+     */
+    public IEditorPart createEditor() throws CoreException {
+        Object extension = WorkbenchPlugin.createExtension(getConfigurationElement(), IWorkbenchRegistryConstants.ATT_CLASS);
+        return ((InterceptContributions)Tweaklets.get(InterceptContributions.KEY)).tweakEditor(extension);
+    }
+
+    /**
+     * Return the file name of the command to execute for this editor.
+     *
+     * @return the file name to execute
+     */
+    public String getFileName() {
+        // RAP [bm]: program 
+//      if (program == null) {
+        	if (configurationElement == null) {
+        		return fileName;
+        	}
+        	return configurationElement.getAttribute(IWorkbenchRegistryConstants.ATT_COMMAND);
+//          }
+//          return program.getName();
+    }
+
+    /**
+     * Return the id for this editor.
+     *
+     * @return the id
+     */
+    @Override
+	public String getId() {
+        // RAP [bm]: Program
+//      if (program == null) {
+        	if (configurationElement == null) {
+        		return Util.safeString(id);
+        	}
+        	return Util.safeString(configurationElement.getAttribute(IWorkbenchRegistryConstants.ATT_ID));
+
+//          }
+//          return Util.safeString(program.getName());
+    }
+
+    /**
+     * Return the image descriptor describing this editor.
+     *
+     * @return the image descriptor
+     */
+    @Override
+	public ImageDescriptor getImageDescriptor() {
+    	ImageDescriptor tempDescriptor = null;
+
+    	synchronized (imageDescLock) {
+	    	if (!testImage)
+	            return imageDesc;
+
+			if (imageDesc == null) {
+				String imageFileName = getImageFilename();
+// RAP [rh] unused code                 
+//              String command = getFileName();
+				if (imageFileName != null && configurationElement != null)
+					tempDescriptor = AbstractUIPlugin.imageDescriptorFromPlugin(configurationElement.getNamespaceIdentifier(), imageFileName);
+// RAP [rh] program image descriptors not supported                 
+//              } else if (command != null) {
+//                  imageDesc = WorkbenchImages.getImageDescriptorFromProgram(
+//                          command, 0);
+                }
+
+			if (tempDescriptor == null) { // still null? return default image
+				imageDesc = WorkbenchImages.getImageDescriptor(ISharedImages.IMG_OBJ_FILE);
+				testImage = false;
+		        return imageDesc;
+			}
+    	}
+
+		// Verifies that the image descriptor generates an image.  If not, the descriptor is
+    	// replaced with the default image.
+    	// We must create the image without holding any locks, since there is a potential for deadlock
+    	// on Linux due to SWT's implementation of Image. See bugs 265028 and 256316 for details.
+		Image img = tempDescriptor.createImage(false);
+		if (img == null) // @issue what should be the default image?
+			tempDescriptor = WorkbenchImages.getImageDescriptor(ISharedImages.IMG_OBJ_FILE);
+		else
+		    img.dispose();
+		// <----- End of must-not-lock part
+
+		// reenter synchronized block
+		synchronized (imageDescLock) {
+			// if another thread has set the image description, use it
+			if (!testImage)
+				return imageDesc;
+			// otherwise set the image description we calculated above
+			imageDesc = tempDescriptor;
+			testImage = false;
+			return imageDesc;
+		}
+    }
+
+    /**
+     * The Image to use to repesent this editor
+     */
+    /* package */void setImageDescriptor(ImageDescriptor desc) {
+    	synchronized (imageDescLock) {
+	        imageDesc = desc;
+	        testImage = true;
+    	}
+    }
+
+    /**
+     * The name of the image describing this editor.
+     *
+     * @return the image file name
+     */
+    public String getImageFilename() {
+    	if (configurationElement == null) {
+			return imageFilename;
+		}
+    	return configurationElement.getAttribute(IWorkbenchRegistryConstants.ATT_ICON);
+    }
+
+    /**
+     * Return the user printable label for this editor.
+     *
+     * @return the label
+     */
+    @Override
+	public String getLabel() {
+// RAP [bm]: Program
+//      if (program == null) {
+        	if (configurationElement == null) {
+        		return editorName;
+        	}
+        	return configurationElement.getAttribute(IWorkbenchRegistryConstants.ATT_NAME);
+//          }
+//          return program.getName();
+    }
+
+    /**
+     * Returns the class name of the launcher.
+     *
+     * @return the launcher class name
+     */
+    public String getLauncher() {
+    	if (configurationElement == null) {
+			return launcherName;
+		}
+    	return configurationElement.getAttribute(IWorkbenchRegistryConstants.ATT_LAUNCHER);
+    }
+
+    /**
+     * Return the contributing plugin id.
+     *
+     * @return the contributing plugin id
+     */
+    public String getPluginID() {
+    	if (configurationElement != null) {
+			return configurationElement.getNamespace();
+		}
+    	return pluginIdentifier;
+    }
+
+    // RAP [bm]: 
+//  /**
+//   * Get the program for the receiver if there is one.
+//   * @return Program
+//   */
+//  public Program getProgram() {
+//      return this.program;
+//  }
+
+    @Override
+	public boolean isInternal() {
+        return getOpenMode() == OPEN_INTERNAL;
+    }
+
+    @Override
+	public boolean isOpenInPlace() {
+        return getOpenMode() == OPEN_INPLACE;
+    }
+
+    @Override
+	public boolean isOpenExternal() {
+        return getOpenMode() == OPEN_EXTERNAL;
+    }
+
+    /**
+     * Load the object properties from a memento.
+     *
+     * @return <code>true</code> if the values are valid, <code>false</code> otherwise
+     */
+    protected boolean loadValues(IMemento memento) {
+        editorName = memento.getString(IWorkbenchConstants.TAG_LABEL);
+        imageFilename = memento.getString(IWorkbenchConstants.TAG_IMAGE);
+        className = memento.getString(IWorkbenchConstants.TAG_CLASS);
+        launcherName = memento.getString(IWorkbenchConstants.TAG_LAUNCHER);
+        fileName = memento.getString(IWorkbenchConstants.TAG_FILE);
+        id = Util.safeString(memento.getString(IWorkbenchConstants.TAG_ID));
+        pluginIdentifier = memento.getString(IWorkbenchConstants.TAG_PLUGIN);
+
+        Integer openModeInt = memento
+                .getInteger(IWorkbenchConstants.TAG_OPEN_MODE);
+        if (openModeInt != null) {
+            openMode = openModeInt.intValue();
+        } else {
+            // legacy: handle the older attribute names, needed to allow reading of pre-3.0-RCP workspaces
+            boolean internal = Boolean.parseBoolean(memento
+                    .getString(IWorkbenchConstants.TAG_INTERNAL));
+            boolean openInPlace = Boolean.parseBoolean(memento
+                    .getString(IWorkbenchConstants.TAG_OPEN_IN_PLACE));
+            if (internal) {
+                openMode = OPEN_INTERNAL;
+            } else {
+                if (openInPlace) {
+                    openMode = OPEN_INPLACE;
+                } else {
+                    openMode = OPEN_EXTERNAL;
+                }
+            }
+        }
+        if (openMode != OPEN_EXTERNAL && openMode != OPEN_INTERNAL
+                && openMode != OPEN_INPLACE) {
+            WorkbenchPlugin
+                    .log("Ignoring editor descriptor with invalid openMode: " + this); //$NON-NLS-1$
+            return false;
+        }
+
+        // RAP [bm]: 
+//      String programName = memento
+//              .getString(IWorkbenchConstants.TAG_PROGRAM_NAME);
+//      if (programName != null) {
+//          this.program = findProgram(programName);
+//      }
+      // RAPEND: [bm] 
+        
+        return true;
+    }
+
+    /**
+     * Save the object values in a IMemento
+     */
+    protected void saveValues(IMemento memento) {
+        memento.putString(IWorkbenchConstants.TAG_LABEL, getLabel());
+        memento.putString(IWorkbenchConstants.TAG_IMAGE, getImageFilename());
+        memento.putString(IWorkbenchConstants.TAG_CLASS, getClassName());
+        memento.putString(IWorkbenchConstants.TAG_LAUNCHER, getLauncher());
+        memento.putString(IWorkbenchConstants.TAG_FILE, getFileName());
+        memento.putString(IWorkbenchConstants.TAG_ID, getId());
+        memento.putString(IWorkbenchConstants.TAG_PLUGIN, getPluginId());
+
+        memento.putInteger(IWorkbenchConstants.TAG_OPEN_MODE, getOpenMode());
+        // legacy: handle the older attribute names, needed to allow reading of workspace by pre-3.0-RCP eclipses
+        memento.putString(IWorkbenchConstants.TAG_INTERNAL, String
+                .valueOf(isInternal()));
+        memento.putString(IWorkbenchConstants.TAG_OPEN_IN_PLACE, String
+                .valueOf(isOpenInPlace()));
+
+        // RAP [bm]: Program
+//      if (this.program != null) {
+//          memento.putString(IWorkbenchConstants.TAG_PROGRAM_NAME,
+//                  this.program.getName());
+//      }
+    }
+
+    /**
+     * Return the open mode of this editor.
+     *
+	 * @return the open mode of this editor
+	 * @since 3.1
+	 */
+	private int getOpenMode() {
+		if (configurationElement == null) { // if we've been serialized, return our serialized value
+			return openMode;
+		}
+		else if (getLauncher() != null) {
+            // open using a launcer
+        	return EditorDescriptor.OPEN_EXTERNAL;
+        } else if (getFileName() != null) {
+            // open using an external editor
+            return EditorDescriptor.OPEN_EXTERNAL;
+        } else if (getPluginId() != null) {
+        	// open using an internal editor
+        	return EditorDescriptor.OPEN_INTERNAL;
+        }
+        else {
+        	return 0; // default for system editor
+        }
+	}
+
+	/**
+     * Set the class name of an internal editor.
+     */
+    /* package */void setClassName(String newClassName) {
+        className = newClassName;
+    }
+
+    /**
+     * Set the configuration element which contributed this editor.
+     */
+    /* package */void setConfigurationElement(
+            IConfigurationElement newConfigurationElement) {
+        configurationElement = newConfigurationElement;
+    }
+
+    /**
+     * Set the filename of an external editor.
+     */
+    /* package */void setFileName(String aFileName) {
+        fileName = aFileName;
+    }
+
+    /**
+     * Set the id of the editor.
+     * For internal editors this is the id as provided in the extension point
+     * For external editors it is path and filename of the editor
+     */
+    /* package */void setID(String anID) {
+        Assert.isNotNull(anID);
+        id = anID;
+    }
+
+    /**
+     * The name of the image to use for this editor.
+     */
+    /* package */void setImageFilename(String aFileName) {
+        imageFilename = aFileName;
+    }
+
+    /**
+     * Sets the new launcher class name
+     *
+     * @param newLauncher the new launcher
+     */
+    /* package */void setLauncher(String newLauncher) {
+        launcherName = newLauncher;
+    }
+
+    /**
+     * The label to show for this editor.
+     */
+    /* package */void setName(String newName) {
+        editorName = newName;
+    }
+
+    /**
+     * Sets the open mode of this editor descriptor.
+     *
+     * @param mode the open mode
+     *
+     * @issue this method is public as a temporary fix for bug 47600
+     */
+    public void setOpenMode(int mode) {
+        openMode = mode;
+    }
+
+    /**
+     * The id of the plugin which contributed this editor, null for external editors.
+     */
+    /* package */void setPluginIdentifier(String anID) {
+        pluginIdentifier = anID;
+    }
+
+    // RAP [bm]: 
+//  /**
+//   * Set the receivers program.
+//   * @param newProgram
+//   */
+//  /* package */void setProgram(Program newProgram) {
+//
+//      this.program = newProgram;
+//      if (editorName == null) {
+//          setName(newProgram.getName());
+//      }
+//  }
+
+    /**
+     * For debugging purposes only.
+     */
+    @Override
+	public String toString() {
+        return "EditorDescriptor(id=" + getId() + ", label=" + getLabel() + ")"; //$NON-NLS-2$ //$NON-NLS-3$//$NON-NLS-1$
+    }
+
+    @Override
+	public String getLocalId() {
+        return getId();
+    }
+
+    @Override
+	public String getPluginId() {
+        return getPluginID();
+    }
+
+    @Override
+    public IEditorMatchingStrategy getEditorMatchingStrategy() {
+        if (matchingStrategy == null && !matchingStrategyChecked) {
+            matchingStrategyChecked = true;
+            // RAP [bm]: Program
+//            if (program == null && configurationElement != null) {
+            if (configurationElement != null) {
+            // RAPEND: [bm] 
+                if (configurationElement.getAttribute(IWorkbenchRegistryConstants.ATT_MATCHING_STRATEGY) != null) {
+                    try {
+                        matchingStrategy = (IEditorMatchingStrategy) WorkbenchPlugin.createExtension(configurationElement, IWorkbenchRegistryConstants.ATT_MATCHING_STRATEGY);
+                    } catch (CoreException e) {
+                        WorkbenchPlugin.log("Error creating editor management policy for editor id " + getId(), e); //$NON-NLS-1$
+                    }
+                }
+            }
+        }
+        return matchingStrategy;
+    }
+
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/EditorRegistry.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/EditorRegistry.java
new file mode 100644
index 0000000..673e06b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/EditorRegistry.java
@@ -0,0 +1,1699 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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
+ *     Jan-Hendrik Diederich, Bredex GmbH - bug 201052
+ *     Carsten Pfeiffer, Gebit Solutions GmbH - bug 259536
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ *******************************************************************************/
+package org.eclipse.ui.internal.registry;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.StringTokenizer;
+
+import org.eclipse.core.commands.common.EventManager;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.core.runtime.content.IContentType;
+import org.eclipse.core.runtime.dynamichelpers.ExtensionTracker;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
+import org.eclipse.jface.dialogs.ErrorDialog;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.util.SafeRunnable;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IEditorDescriptor;
+import org.eclipse.ui.IEditorRegistry;
+import org.eclipse.ui.IFileEditorMapping;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IPropertyListener;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.WorkbenchException;
+import org.eclipse.ui.XMLMemento;
+import org.eclipse.ui.activities.WorkbenchActivityHelper;
+import org.eclipse.ui.internal.IPreferenceConstants;
+import org.eclipse.ui.internal.IWorkbenchConstants;
+import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.editorsupport.ComponentSupport;
+import org.eclipse.ui.internal.util.Util;
+
+import com.ibm.icu.text.Collator;
+
+
+/**
+ * Provides access to the collection of defined editors for resource types.
+ */
+public class EditorRegistry extends EventManager implements IEditorRegistry, IExtensionChangeHandler {
+
+	private final static IEditorDescriptor [] EMPTY = new IEditorDescriptor[0];
+
+	class RelatedRegistry {
+
+		/**
+         * Return the objects related to the type.
+         *
+         * @param type
+         * @return the objects related to the type
+		 */
+		public IEditorDescriptor[] getRelatedObjects(IContentType type) {
+			IEditorDescriptor[] relatedObjects = contentTypeToEditorMappings.get(type);
+			if (relatedObjects == null) {
+				return EMPTY;
+			}
+			return (IEditorDescriptor[]) WorkbenchActivityHelper.restrictArray(relatedObjects);
+		}
+
+		/**
+         * Return the objects related to the filename
+         * @param fileName
+         * @return the objects related to the filename
+		 */
+		public IEditorDescriptor[] getRelatedObjects(String fileName) {
+			IFileEditorMapping mapping = getMappingFor(fileName);
+			if (mapping == null) {
+				return EMPTY;
+			}
+
+			return (IEditorDescriptor[]) WorkbenchActivityHelper.restrictArray(mapping.getEditors());
+		}
+
+	}
+
+	private Map<IContentType, IEditorDescriptor[]> contentTypeToEditorMappings = new HashMap<>();
+
+	/**
+	 * Cached images - these include images from registered editors (via
+	 * plugins) and others hence this table is not one to one with the mappings
+	 * table. It is in fact a superset of the keys one would find in
+	 * typeEditorMappings
+	 */
+	private Map<Object, ImageDescriptor> extensionImages = new HashMap<>();
+
+    /**
+     * Vector of EditorDescriptor - all the editors loaded from plugin files.
+     * The list is kept in order to be able to show in the editor selection
+     * dialog of the resource associations page.  This list is sorted based on the
+     * human readable label of the editor descriptor.
+     *
+     * @see #comparer
+     */
+	private List<IEditorDescriptor> sortedEditorsFromPlugins = new ArrayList<>();
+
+    // Map of EditorDescriptor - map editor id to editor.
+    private Map<String, IEditorDescriptor> mapIDtoEditor = initialIdToEditorMap(10);
+
+    // Map of FileEditorMapping (extension to FileEditorMapping)
+    private EditorMap typeEditorMappings;
+
+    /*
+     * Compares the labels from two IEditorDescriptor objects
+     */
+	private static final Comparator<IEditorDescriptor> comparer = new Comparator<IEditorDescriptor>() {
+        private Collator collator = Collator.getInstance();
+
+		@Override
+		public int compare(IEditorDescriptor arg0, IEditorDescriptor arg1) {
+			String s1 = arg0.getLabel();
+			String s2 = arg1.getLabel();
+			return collator.compare(s1, s2);
+		}
+	};
+
+	private RelatedRegistry relatedRegistry;
+
+	public static final String EMPTY_EDITOR_ID = "org.eclipse.ui.internal.emptyEditorTab"; //$NON-NLS-1$
+
+    /**
+     * Return an instance of the receiver. Adds listeners into the extension
+     * registry for dynamic UI purposes.
+     */
+    public EditorRegistry() {
+        super();
+        initializeFromStorage();
+        IExtensionTracker tracker = PlatformUI.getWorkbench().getExtensionTracker();
+        tracker.registerHandler(this, ExtensionTracker.createExtensionPointFilter(getExtensionPointFilter()));
+		relatedRegistry = new RelatedRegistry();
+    }
+
+    /**
+     * Add an editor for the given extensions with the specified (possibly null)
+     * extended type. The editor is being registered from a plugin
+     *
+     * @param editor
+     *            The description of the editor (as obtained from the plugin
+     *            file and built by the registry reader)
+     * @param extensions
+     *            Collection of file extensions the editor applies to
+     * @param filenames
+     *            Collection of filenames the editor applies to
+     * @param contentTypeVector
+     * @param bDefault
+     *            Indicates whether the editor should be made the default editor
+     *            and hence appear first inside a FileEditorMapping
+     *
+     * This method is not API and should not be called outside the workbench
+     * code.
+     */
+	public void addEditorFromPlugin(EditorDescriptor editor, List<String> extensions, List<String> filenames,
+			List<String> contentTypeVector, boolean bDefault) {
+
+    	PlatformUI.getWorkbench().getExtensionTracker().registerObject(
+				editor.getConfigurationElement().getDeclaringExtension(),
+				editor, IExtensionTracker.REF_WEAK);
+        // record it in our quick reference list
+        sortedEditorsFromPlugins.add(editor);
+
+        // add it to the table of mappings
+		for (String fileExtension : extensions) {
+            if (fileExtension != null && fileExtension.length() > 0) {
+                FileEditorMapping mapping = getMappingFor("*." + fileExtension); //$NON-NLS-1$
+                if (mapping == null) { // no mapping for that extension
+                    mapping = new FileEditorMapping(fileExtension);
+                    typeEditorMappings.putDefault(mappingKeyFor(mapping),
+                            mapping);
+                }
+                mapping.addEditor(editor);
+                if (bDefault) {
+					mapping.setDefaultEditor(editor);
+				}
+            }
+        }
+
+        // add it to the table of mappings
+		for (String filename : filenames) {
+            if (filename != null && filename.length() > 0) {
+                FileEditorMapping mapping = getMappingFor(filename);
+                if (mapping == null) { // no mapping for that extension
+                    String name;
+                    String extension;
+                    int index = filename.indexOf('.');
+                    if (index < 0) {
+                        name = filename;
+                        extension = ""; //$NON-NLS-1$
+                    } else {
+                        name = filename.substring(0, index);
+                        extension = filename.substring(index + 1);
+                    }
+                    mapping = new FileEditorMapping(name, extension);
+                    typeEditorMappings.putDefault(mappingKeyFor(mapping),
+                            mapping);
+                }
+                mapping.addEditor(editor);
+                if (bDefault) {
+					mapping.setDefaultEditor(editor);
+				}
+            }
+        }
+
+		for (String contentTypeId : contentTypeVector) {
+			if (contentTypeId != null && contentTypeId.length() > 0) {
+				IContentType contentType = Platform.getContentTypeManager().getContentType(contentTypeId);
+				if (contentType != null) {
+					addContentTypeBinding(contentType, editor, bDefault);
+				}
+			}
+		}
+
+        // Update editor map.
+        mapIDtoEditor.put(editor.getId(), editor);
+    }
+
+	void addContentTypeBinding(IContentType contentType, IEditorDescriptor editor, boolean bDefault) {
+		IEditorDescriptor [] editorArray = contentTypeToEditorMappings.get(contentType);
+		if (editorArray == null) {
+			editorArray = new IEditorDescriptor[] {editor};
+			contentTypeToEditorMappings.put(contentType, editorArray);
+		}
+		else {
+			IEditorDescriptor [] newArray = new IEditorDescriptor[editorArray.length + 1];
+			if (bDefault) { // default editors go to the front of the line
+				newArray[0] = editor;
+				System.arraycopy(editorArray, 0, newArray, 1, editorArray.length);
+			}
+			else {
+				newArray[editorArray.length] = editor;
+				System.arraycopy(editorArray, 0, newArray, 0, editorArray.length);
+			}
+			contentTypeToEditorMappings.put(contentType, newArray);
+		}
+	}
+
+    /**
+     * Add external editors to the editor mapping.
+     */
+    private void addExternalEditorsToEditorMap() {
+        // Add registered editors (may include external editors).
+		for (FileEditorMapping map : typeEditorMappings.allMappings()) {
+            IEditorDescriptor[] descArray = map.getEditors();
+            for (IEditorDescriptor desc : descArray) {
+				mapIDtoEditor.put(desc.getId(), desc);
+            }
+        }
+    }
+
+    @Override
+	public void addPropertyListener(IPropertyListener l) {
+        addListenerObject(l);
+    }
+
+    @Override
+	public IEditorDescriptor findEditor(String id) {
+		IEditorDescriptor desc = mapIDtoEditor.get(id);
+        if (WorkbenchActivityHelper.restrictUseOf(desc)) {
+        	return null;
+        }
+		return desc;
+    }
+
+    /**
+     * Fires a property changed event to all registered listeners.
+     *
+     * @param type the type of event
+     * @see IEditorRegistry#PROP_CONTENTS
+     */
+    private void firePropertyChange(final int type) {
+		for (Object listener : getListeners()) {
+			final IPropertyListener propertyListener = (IPropertyListener) listener;
+            SafeRunner.run(new SafeRunnable() {
+                @Override
+				public void run() {
+					propertyListener.propertyChanged(EditorRegistry.this, type);
+                }
+            });
+        }
+    }
+
+    @Override
+	public IEditorDescriptor getDefaultEditor() {
+        // the default editor will always be the system external editor
+        // this should never return null
+        return findEditor(IEditorRegistry.SYSTEM_EXTERNAL_EDITOR_ID);
+    }
+
+    @Override
+	public IEditorDescriptor getDefaultEditor(String filename) {
+		IEditorDescriptor defaultEditor = getDefaultEditor(filename, guessAtContentType(filename));
+		if (defaultEditor != null) {
+			return defaultEditor;
+		}
+
+		IContentType[] contentTypes = Platform.getContentTypeManager().findContentTypesFor(filename);
+		for (IContentType contentType : contentTypes) {
+			IEditorDescriptor editor = getDefaultEditor(filename, contentType);
+			if (editor != null) {
+				return editor;
+			}
+		}
+		return null;
+    }
+
+	/**
+	 * Return the (approximated) content type for a file with the given name.
+	 *
+	 * @param filename the filename
+	 * @return the content type or <code>null</code> if it could not be determined
+	 * @since 3.1
+	 */
+	private IContentType guessAtContentType(String filename) {
+		return Platform.getContentTypeManager().findContentTypeFor(filename);
+	}
+
+    /**
+     * Returns the default file image descriptor.
+     *
+     * @return the image descriptor
+     */
+    private ImageDescriptor getDefaultImage() {
+        // @issue what should be the default image?
+        return WorkbenchImages.getImageDescriptor(ISharedImages.IMG_OBJ_FILE);
+    }
+
+    @Override
+	public IEditorDescriptor[] getEditors(String filename) {
+		return getEditors(filename, guessAtContentType(filename));
+	}
+
+    @Override
+	public IFileEditorMapping[] getFileEditorMappings() {
+        FileEditorMapping[] array = typeEditorMappings.allMappings();
+        final Collator collator = Collator.getInstance();
+		Arrays.sort(array, (o1, o2) -> {
+			String s1 = o1.getLabel();
+			String s2 = o2.getLabel();
+		    return collator.compare(s1, s2);
+		});
+        return array;
+    }
+
+    @Override
+	public ImageDescriptor getImageDescriptor(String filename) {
+		return getImageDescriptor(filename, guessAtContentType(filename));
+	}
+
+	/**
+     * Find the file editor mapping for the file extension. Returns
+     * <code>null</code> if not found.
+     *
+     * @param ext
+     *            the file extension
+     * @return the mapping, or <code>null</code>
+     */
+    private FileEditorMapping getMappingFor(String ext) {
+        if (ext == null) {
+			return null;
+		}
+        String key = mappingKeyFor(ext);
+        return typeEditorMappings.get(key);
+    }
+
+    /**
+     * Find the file editor mappings for the given filename.
+     * <p>
+     * Return an array of two FileEditorMapping items, where the first mapping
+     * is for the entire filename, and the second mapping is for the filename's
+     * extension only. These items can be null if no mapping exist on the
+     * filename and/or filename's extension.</p>
+     *
+     * @param filename the filename
+     * @return the mappings
+     */
+    private FileEditorMapping[] getMappingForFilename(String filename) {
+        FileEditorMapping[] mapping = new FileEditorMapping[2];
+
+        // Lookup on entire filename
+        mapping[0] = getMappingFor(filename);
+
+        // Lookup on filename's extension
+        int index = filename.lastIndexOf('.');
+        if (index > -1) {
+            String extension = filename.substring(index);
+            mapping[1] = getMappingFor("*" + extension); //$NON-NLS-1$
+        }
+
+        return mapping;
+    }
+
+ // RAP [bm]: 
+//    /**
+//     * Return the editor descriptors pulled from the OS.
+//     * <p>
+//     * WARNING! The image described by each editor descriptor is *not* known by
+//     * the workbench's graphic registry. Therefore clients must take care to
+//     * ensure that if they access any of the images held by these editors that
+//     * they also dispose them
+//     * </p>
+//     * @return the editor descriptors
+//     */
+//    public IEditorDescriptor[] getSortedEditorsFromOS() {
+//		List<IEditorDescriptor> externalEditors = new ArrayList<>();
+//		for (Program program : Program.getPrograms()) {
+//            //1FPLRL2: ITPUI:WINNT - NOTEPAD editor cannot be launched
+//            //Some entries start with %SystemRoot%
+//            //For such cases just use the file name as they are generally
+//            //in directories which are on the path
+//            /*
+//             * if (fileName.charAt(0) == '%') { fileName = name + ".exe"; }
+//             */
+//
+//            EditorDescriptor editor = new EditorDescriptor();
+//            editor.setOpenMode(EditorDescriptor.OPEN_EXTERNAL);
+//            editor.setProgram(program);
+//
+//            // determine the program icon this editor would need (do not let it
+//            // be cached in the workbench registry)
+//			ImageDescriptor desc = new ExternalProgramImageDescriptor(program);
+//            editor.setImageDescriptor(desc);
+//            externalEditors.add(editor);
+//        }
+//
+//        Object[] tempArray = sortEditors(externalEditors);
+//		IEditorDescriptor[] array = new IEditorDescriptor[externalEditors.size()];
+//        for (int i = 0; i < tempArray.length; i++) {
+//            array[i] = (IEditorDescriptor) tempArray[i];
+//        }
+//        return array;
+//    }
+
+    /**
+     * Return the editors loaded from plugins.
+     *
+     * @return the sorted array of editors declared in plugins
+     */
+	public IEditorDescriptor[] getSortedEditorsFromPlugins() {
+		// see #comparer
+		Collection<IEditorDescriptor> descs = WorkbenchActivityHelper.restrictCollection(sortedEditorsFromPlugins,
+				new ArrayList<IEditorDescriptor>());
+		return descs.toArray(new IEditorDescriptor[descs.size()]);
+	}
+
+    /**
+	 * Answer an intial id to editor map. This will create a new map and
+	 * populate it with the default system editors.
+	 *
+	 * @param initialSize
+	 *            the initial size of the map
+	 * @return the new map
+	 */
+	private Map<String, IEditorDescriptor> initialIdToEditorMap(int initialSize) {
+        Map<String, IEditorDescriptor> map = new HashMap<>(initialSize);
+        addSystemEditors(map);
+        return map;
+    }
+
+    /**
+     * Add the system editors to the provided map. This will always add an
+     * editor with an id of {@link #SYSTEM_EXTERNAL_EDITOR_ID} and may also add
+     * an editor with id of {@link #SYSTEM_INPLACE_EDITOR_ID} if the system
+     * configuration supports it.
+     *
+     * @param map the map to augment
+     */
+    private void addSystemEditors(Map<String, IEditorDescriptor> map) {
+        // there will always be a system external editor descriptor
+        EditorDescriptor editor = new EditorDescriptor();
+        editor.setID(IEditorRegistry.SYSTEM_EXTERNAL_EDITOR_ID);
+        editor.setName(WorkbenchMessages.get().SystemEditorDescription_name);
+        editor.setOpenMode(EditorDescriptor.OPEN_EXTERNAL);
+        // @issue we need a real icon for this editor?
+        map.put(IEditorRegistry.SYSTEM_EXTERNAL_EDITOR_ID, editor);
+
+        // there may be a system in-place editor if supported by platform
+        if (ComponentSupport.inPlaceEditorSupported()) {
+            editor = new EditorDescriptor();
+            editor.setID(IEditorRegistry.SYSTEM_INPLACE_EDITOR_ID);
+            editor.setName(WorkbenchMessages.get().SystemInPlaceDescription_name);
+            editor.setOpenMode(EditorDescriptor.OPEN_INPLACE);
+            // @issue we need a real icon for this editor?
+            map.put(IEditorRegistry.SYSTEM_INPLACE_EDITOR_ID, editor);
+        }
+
+		EditorDescriptor emptyEditorDescriptor = new EditorDescriptor();
+		emptyEditorDescriptor.setID(EMPTY_EDITOR_ID);
+		emptyEditorDescriptor.setName("(Empty)"); //$NON-NLS-1$
+		emptyEditorDescriptor
+				.setImageDescriptor(WorkbenchImages
+						.getImageDescriptor(IWorkbenchGraphicConstants.IMG_OBJ_ELEMENT));
+		map.put(EMPTY_EDITOR_ID, emptyEditorDescriptor);
+    }
+
+    /**
+     * Initialize the registry state from plugin declarations and preference
+     * overrides.
+     */
+    private void initializeFromStorage() {
+        typeEditorMappings = new EditorMap();
+        extensionImages = new HashMap<>();
+
+        //Get editors from the registry
+        EditorRegistryReader registryReader = new EditorRegistryReader();
+        registryReader.addEditors(this);
+        sortInternalEditors();
+        rebuildInternalEditorMap();
+
+        IPreferenceStore store = PlatformUI.getPreferenceStore();
+        String defaultEditors = store
+                .getString(IPreferenceConstants.DEFAULT_EDITORS);
+        String chachedDefaultEditors = store
+                .getString(IPreferenceConstants.DEFAULT_EDITORS_CACHE);
+
+        //If defaults has changed load it afterwards so it overrides the users
+        // associations.
+        if (defaultEditors == null
+                || defaultEditors.equals(chachedDefaultEditors)) {
+            setProductDefaults(defaultEditors);
+            loadAssociations(); //get saved earlier state
+        } else {
+            loadAssociations(); //get saved earlier state
+            setProductDefaults(defaultEditors);
+            store.putValue(IPreferenceConstants.DEFAULT_EDITORS_CACHE,
+                    defaultEditors);
+        }
+        addExternalEditorsToEditorMap();
+    }
+
+    /**
+     * Set the default editors according to the preference store which can be
+     * overwritten in the file properties.ini.  In the form:
+     * <p>
+     * <code>ext1:id1;ext2:id2;...</code>
+     * </p>
+     *
+     * @param defaultEditors the default editors to set
+     */
+    private void setProductDefaults(String defaultEditors) {
+        if (defaultEditors == null || defaultEditors.length() == 0) {
+			return;
+		}
+
+        StringTokenizer extEditors = new StringTokenizer(defaultEditors,
+				new Character(IPreferenceConstants.SEPARATOR).toString());
+        while (extEditors.hasMoreTokens()) {
+            String extEditor = extEditors.nextToken().trim();
+            int index = extEditor.indexOf(':');
+            if (extEditor.length() < 3 || index <= 0
+                    || index >= (extEditor.length() - 1)) {
+                //Extension and id must have at least one char.
+                WorkbenchPlugin
+                        .log("Error setting default editor. Could not parse '" + extEditor + "'. Default editors should be specified as '*.ext1:editorId1;*.ext2:editorId2'"); //$NON-NLS-1$ //$NON-NLS-2$
+                return;
+            }
+            String ext = extEditor.substring(0, index).trim();
+            String editorId = extEditor.substring(index + 1).trim();
+            FileEditorMapping mapping = getMappingFor(ext);
+            if (mapping == null) {
+                WorkbenchPlugin
+                        .log("Error setting default editor. Could not find mapping for '" + ext + "'."); //$NON-NLS-1$ //$NON-NLS-2$
+                continue;
+            }
+			IEditorDescriptor editor = findEditor(editorId);
+            if (editor == null) {
+                WorkbenchPlugin
+                        .log("Error setting default editor. Could not find editor: '" + editorId + "'."); //$NON-NLS-1$ //$NON-NLS-2$
+                continue;
+            }
+            mapping.setDefaultEditor(editor);
+        }
+    }
+
+    /**
+     * Read the editors defined in the preferences store.
+     *
+     * @param editorTable
+     *            Editor table to store the editor definitions.
+     * @return true if the table is built succesfully.
+     */
+	private boolean readEditors(Map<String, IEditorDescriptor> editorTable) {
+        //Get the workbench plugin's working directory
+        IPath workbenchStatePath = WorkbenchPlugin.getDefault().getDataLocation();
+        if(workbenchStatePath == null) {
+			return false;
+		}
+        IPreferenceStore store = WorkbenchPlugin.getDefault()
+                .getPreferenceStore();
+        Reader reader = null;
+        FileInputStream stream = null;
+        try {
+            // Get the editors defined in the preferences store
+            String xmlString = store.getString(IPreferenceConstants.EDITORS);
+            if (xmlString == null || xmlString.length() == 0) {
+                stream = new FileInputStream(workbenchStatePath
+                        .append(IWorkbenchConstants.EDITOR_FILE_NAME)
+                        .toOSString());
+                reader = new BufferedReader(new InputStreamReader(stream,
+						StandardCharsets.UTF_8));
+            } else {
+                reader = new StringReader(xmlString);
+            }
+            XMLMemento memento = XMLMemento.createReadRoot(reader);
+            // Get the editors and validate each one
+			for (IMemento childMemento : memento.getChildren(IWorkbenchConstants.TAG_DESCRIPTOR)) {
+				EditorDescriptor editor = new EditorDescriptor();
+				boolean valid = editor.loadValues(childMemento);
+                if (!valid) {
+                    continue;
+                }
+				if (isSystem(editor.getId())) {
+					// bug 502514: check if there is internal editor
+					// descriptor (they are always recreated via
+					// addSystemEditors(Map<String, IEditorDescriptor>))
+					lookupEditorFromTable(editorTable, editor);
+					continue;
+				}
+				if (editor.getPluginID() != null) {
+                    //If the editor is from a plugin we use its ID to look it
+                    // up in the mapping of editors we
+                    //have obtained from plugins. This allows us to verify that
+                    // the editor is still valid
+                    //and allows us to get the editor description from the
+                    // mapping table which has
+                    //a valid config element field.
+					lookupEditorFromTable(editorTable, editor);
+					continue;
+				}
+				// RAP [bm]: no external programs
+				// This is either from a program or a user defined editor
+//				ImageDescriptor descriptor;
+//				if (editor.getProgram() == null) {
+//					String fileName = editor.getFileName();
+//					if (fileName == null) {
+//						String error = "Both editor program and path are null for descriptor id: "; //$NON-NLS-1$
+//						error += editor.getId() + " with name: " + editor.getLabel(); //$NON-NLS-1$
+//						WorkbenchPlugin.log(error, new IllegalStateException());
+//						continue;
+//					}
+//					descriptor = new ProgramImageDescriptor(fileName, 0);
+//				} else {
+//					descriptor = new ExternalProgramImageDescriptor(editor.getProgram());
+//				}
+				// RAPEND: [bm] 
+				
+//				editor.setImageDescriptor(descriptor);
+//				editorTable.put(editor.getId(), editor);
+				// RAPEND: [bm] 
+            }
+        } catch (IOException e) {
+            //Ignore this as the workbench may not yet have saved any state
+            return false;
+        } catch (WorkbenchException e) {
+            ErrorDialog.openError((Shell) null, WorkbenchMessages.get().EditorRegistry_errorTitle,
+                    WorkbenchMessages.get().EditorRegistry_errorMessage,
+                    e.getStatus());
+            return false;
+		} finally {
+			try {
+				if (reader != null) {
+					reader.close();
+				} else if (stream != null)
+					stream.close();
+			} catch (IOException ex) {
+				WorkbenchPlugin.log("Error reading editors: Could not close steam", ex); //$NON-NLS-1$
+			}
+        }
+
+        return true;
+    }
+
+    /**
+	 * @param id
+	 *            descriptor id
+	 * @return true if the id is one of the system internal id's:
+	 *         {@link IEditorRegistry#SYSTEM_EXTERNAL_EDITOR_ID} or
+	 *         {@link IEditorRegistry#SYSTEM_INPLACE_EDITOR_ID}
+	 */
+	private static boolean isSystem(String id) {
+		return IEditorRegistry.SYSTEM_EXTERNAL_EDITOR_ID.equals(id)
+				|| IEditorRegistry.SYSTEM_INPLACE_EDITOR_ID.equals(id);
+	}
+
+	private void lookupEditorFromTable(Map<String, IEditorDescriptor> editorTable, EditorDescriptor editor) {
+		IEditorDescriptor validEditorDescritor = mapIDtoEditor.get(editor.getId());
+		if (validEditorDescritor != null) {
+			editorTable.put(validEditorDescritor.getId(), validEditorDescritor);
+		}
+	}
+
+    /**
+     * Read the file types and associate them to their defined editor(s).
+     *
+     * @param editorTable
+     *            The editor table containing the defined editors.
+     * @param reader
+     *            Reader containing the preferences content for the resources.
+     *
+     * @throws WorkbenchException
+     */
+	public void readResources(Map<String, IEditorDescriptor> editorTable, Reader reader) throws WorkbenchException {
+        XMLMemento memento = XMLMemento.createReadRoot(reader);
+        String versionString = memento.getString(IWorkbenchConstants.TAG_VERSION);
+        boolean versionIs31 = "3.1".equals(versionString); //$NON-NLS-1$
+
+		for (IMemento childMemento : memento.getChildren(IWorkbenchConstants.TAG_INFO)) {
+			String name = childMemento.getString(IWorkbenchConstants.TAG_NAME);
+            if (name == null) {
+				name = "*"; //$NON-NLS-1$
+			}
+			String extension = childMemento.getString(IWorkbenchConstants.TAG_EXTENSION);
+			IMemento[] idMementos = childMemento.getChildren(IWorkbenchConstants.TAG_EDITOR);
+            String[] editorIDs = new String[idMementos.length];
+            for (int j = 0; j < idMementos.length; j++) {
+				editorIDs[j] = idMementos[j].getString(IWorkbenchConstants.TAG_ID);
+            }
+			idMementos = childMemento.getChildren(IWorkbenchConstants.TAG_DELETED_EDITOR);
+            String[] deletedEditorIDs = new String[idMementos.length];
+            for (int j = 0; j < idMementos.length; j++) {
+				deletedEditorIDs[j] = idMementos[j].getString(IWorkbenchConstants.TAG_ID);
+            }
+			String key = name;
+			if (extension != null && extension.length() > 0) {
+				key = key + "." + extension; //$NON-NLS-1$
+			}
+			FileEditorMapping mapping = getMappingFor(key);
+            if (mapping == null) {
+                mapping = new FileEditorMapping(name, extension);
+            }
+			List<IEditorDescriptor> editors = new ArrayList<>();
+            for (String editorID : editorIDs) {
+                if (editorID != null) {
+					IEditorDescriptor editor = editorTable.get(editorID);
+                    if (editor != null) {
+                        editors.add(editor);
+                    }
+                }
+            }
+			List<IEditorDescriptor> deletedEditors = new ArrayList<>();
+            for (String deletedEditorID : deletedEditorIDs) {
+                if (deletedEditorID != null) {
+					IEditorDescriptor editor = editorTable.get(deletedEditorID);
+                    if (editor != null) {
+                        deletedEditors.add(editor);
+                    }
+                }
+            }
+
+			List<IEditorDescriptor> defaultEditors = new ArrayList<>();
+
+            if (versionIs31) { // parse the new format
+				idMementos = childMemento
+						.getChildren(IWorkbenchConstants.TAG_DEFAULT_EDITOR);
+				String[] defaultEditorIds = new String[idMementos.length];
+				for (int j = 0; j < idMementos.length; j++) {
+					defaultEditorIds[j] = idMementos[j]
+							.getString(IWorkbenchConstants.TAG_ID);
+				}
+				for (String defaultEditorId : defaultEditorIds) {
+					if (defaultEditorId != null) {
+						IEditorDescriptor editor = editorTable.get(defaultEditorId);
+						if (editor != null) {
+							defaultEditors.add(editor);
+						}
+					}
+				}
+			}
+            else { // guess at pre 3.1 format defaults
+				if (!editors.isEmpty()) {
+					IEditorDescriptor editor = editors.get(0);
+					defaultEditors.add(editor);
+				}
+				defaultEditors.addAll(Arrays.asList(mapping.getDeclaredDefaultEditors()));
+            }
+
+            // Add any new editors that have already been read from the registry
+            // which were not deleted.
+			for (IEditorDescriptor descriptor : mapping.getEditors()) {
+				if (descriptor != null && !contains(editors, descriptor) && !deletedEditors.contains(descriptor)) {
+					editors.add(descriptor);
+                }
+            }
+            // Map the editor(s) to the file type
+            mapping.setEditorsList(editors);
+            mapping.setDeletedEditorsList(deletedEditors);
+            mapping.setDefaultEditors(defaultEditors);
+            typeEditorMappings.put(mappingKeyFor(mapping), mapping);
+        }
+    }
+
+    /**
+     * Determine if the editors list contains the editor descriptor.
+     *
+     * @param editors
+     * 			The list of editors
+     * @param editorDescriptor
+     * 			The editor descriptor
+     * @return <code>true</code> if the editors list contains the editor descriptor
+     */
+    private boolean contains(List<IEditorDescriptor> editors, IEditorDescriptor editorDescriptor) {
+        for (IEditorDescriptor currentEditorDescriptor : editors) {
+            if (currentEditorDescriptor.getId().equals(editorDescriptor.getId())) {
+				return true;
+			}
+        }
+        return false;
+    }
+
+    /**
+     * Creates the reader for the resources preferences defined in the
+     * preference store.
+     *
+     * @param editorTable
+     *            The editor table containing the defined editors.
+     * @return true if the resources are read succesfully.
+     */
+	private boolean readResources(Map<String, IEditorDescriptor> editorTable) {
+        //Get the workbench plugin's working directory
+        IPath workbenchStatePath = WorkbenchPlugin.getDefault().getDataLocation();
+        // XXX: nobody cares about this return value
+        if(workbenchStatePath == null) {
+			return false;
+		}
+        IPreferenceStore store = WorkbenchPlugin.getDefault()
+                .getPreferenceStore();
+        Reader reader = null;
+        FileInputStream stream = null;
+        try {
+            // Get the resource types
+            String xmlString = store.getString(IPreferenceConstants.RESOURCES);
+            if (xmlString == null || xmlString.length() == 0) {
+                stream = new FileInputStream(workbenchStatePath
+                        .append(IWorkbenchConstants.RESOURCE_TYPE_FILE_NAME)
+                        .toOSString());
+                reader = new BufferedReader(new InputStreamReader(stream,
+						StandardCharsets.UTF_8));
+            } else {
+                reader = new StringReader(xmlString);
+            }
+            // Read the defined resources into the table
+            readResources(editorTable, reader);
+        } catch (IOException e) {
+            MessageDialog.openError((Shell) null, WorkbenchMessages.get().EditorRegistry_errorTitle,
+                    WorkbenchMessages.get().EditorRegistry_errorMessage);
+            return false;
+        } catch (WorkbenchException e) {
+            ErrorDialog.openError((Shell) null, WorkbenchMessages.get().EditorRegistry_errorTitle,
+                    WorkbenchMessages.get().EditorRegistry_errorMessage,
+                    e.getStatus());
+            return false;
+        } finally {
+            try {
+                if (reader != null) {
+					reader.close();
+				} else if (stream != null) {
+                	stream.close();
+				}
+            } catch (IOException ex) {
+				WorkbenchPlugin.log("Error reading resources: Could not close steam", ex); //$NON-NLS-1$
+            }
+        }
+        return true;
+
+    }
+
+    /**
+     * Load the serialized resource associations Return true if the operation
+     * was successful, false otherwise
+     */
+    private boolean loadAssociations() {
+		Map<String, IEditorDescriptor> editorTable = new HashMap<>();
+        if (!readEditors(editorTable)) {
+            return false;
+        }
+        return readResources(editorTable);
+    }
+
+    /**
+     * Return a friendly version of the given key suitable for use in the editor
+     * map.
+     */
+    private String mappingKeyFor(String type) {
+		// keep everything lower case for case-sensitive platforms
+        return type.toLowerCase();
+    }
+
+    /**
+     * Return a key that combines the file's name and extension of the given
+     * mapping
+     *
+     * @param mapping the mapping to generate a key for
+     */
+    private String mappingKeyFor(FileEditorMapping mapping) {
+        return mappingKeyFor(mapping.getName()
+                + (mapping.getExtension().length() == 0 ? "" : "." + mapping.getExtension())); //$NON-NLS-1$ //$NON-NLS-2$
+    }
+
+    /**
+     * Rebuild the editor map
+     */
+    private void rebuildEditorMap() {
+        rebuildInternalEditorMap();
+        addExternalEditorsToEditorMap();
+    }
+
+    /**
+     * Rebuild the internal editor mapping.
+     */
+    private void rebuildInternalEditorMap() {
+        // Allocate a new map.
+        mapIDtoEditor = initialIdToEditorMap(mapIDtoEditor.size());
+
+        // Add plugin editors.
+        for (IEditorDescriptor desc : sortedEditorsFromPlugins) {
+            mapIDtoEditor.put(desc.getId(), desc);
+        }
+    }
+
+    @Override
+	public void removePropertyListener(IPropertyListener l) {
+        removeListenerObject(l);
+    }
+
+    /**
+     * Save the registry to the filesystem by serializing the current resource
+     * associations.
+     */
+    public void saveAssociations() {
+        //Save the resource type descriptions
+		List<IEditorDescriptor> editors = new ArrayList<>();
+        IPreferenceStore store = WorkbenchPlugin.getDefault()
+                .getPreferenceStore();
+
+        XMLMemento memento = XMLMemento
+                .createWriteRoot(IWorkbenchConstants.TAG_EDITORS);
+        memento.putString(IWorkbenchConstants.TAG_VERSION, "3.1"); //$NON-NLS-1$
+		for (FileEditorMapping fileEditorMapping : typeEditorMappings.userMappings()) {
+            IMemento editorMemento = memento.createChild(IWorkbenchConstants.TAG_INFO);
+			editorMemento.putString(IWorkbenchConstants.TAG_NAME, fileEditorMapping.getName());
+			editorMemento.putString(IWorkbenchConstants.TAG_EXTENSION, fileEditorMapping.getExtension());
+            IEditorDescriptor[] editorArray = fileEditorMapping.getEditors();
+			for (IEditorDescriptor editor : editorArray) {
+				if (editor == null) {
+					continue;
+				}
+				if (!editors.contains(editor)) {
+                    editors.add(editor);
+                }
+				IMemento idMemento = editorMemento.createChild(IWorkbenchConstants.TAG_EDITOR);
+				idMemento.putString(IWorkbenchConstants.TAG_ID, editor.getId());
+            }
+            editorArray = fileEditorMapping.getDeletedEditors();
+			for (IEditorDescriptor editor : editorArray) {
+				if (editor == null) {
+					continue;
+				}
+				if (!editors.contains(editor)) {
+                    editors.add(editor);
+                }
+				IMemento idMemento = editorMemento.createChild(IWorkbenchConstants.TAG_DELETED_EDITOR);
+				idMemento.putString(IWorkbenchConstants.TAG_ID, editor.getId());
+            }
+            editorArray = fileEditorMapping.getDeclaredDefaultEditors();
+			for (IEditorDescriptor editor : editorArray) {
+				if (editor == null) {
+					continue;
+				}
+				if (!editors.contains(editor)) {
+                    editors.add(editor);
+                }
+				IMemento idMemento = editorMemento.createChild(IWorkbenchConstants.TAG_DEFAULT_EDITOR);
+				idMemento.putString(IWorkbenchConstants.TAG_ID, editor.getId());
+            }
+        }
+		try (Writer writer = new StringWriter()) {
+            memento.save(writer);
+            writer.close();
+            store.setValue(IPreferenceConstants.RESOURCES, writer.toString());
+        } catch (IOException e) {
+            MessageDialog.openError((Shell) null, "Saving Problems", //$NON-NLS-1$
+                    "Unable to save resource associations."); //$NON-NLS-1$
+            return;
+        }
+
+        memento = XMLMemento.createWriteRoot(IWorkbenchConstants.TAG_EDITORS);
+		for (IEditorDescriptor editor : editors) {
+			if (isSystem(editor.getId())) {
+				// bug 502514: don't persist internal editor descriptors,
+				// they are always recreated via addSystemEditors(Map<String,
+				// IEditorDescriptor>)
+				continue;
+			}
+            IMemento editorMemento = memento
+                    .createChild(IWorkbenchConstants.TAG_DESCRIPTOR);
+			((EditorDescriptor) editor).saveValues(editorMemento);
+        }
+		try (Writer writer = new StringWriter()) {
+            memento.save(writer);
+            writer.close();
+            store.setValue(IPreferenceConstants.EDITORS, writer.toString());
+        } catch (IOException e) {
+            MessageDialog.openError((Shell) null,
+                    "Error", "Unable to save resource associations."); //$NON-NLS-1$ //$NON-NLS-2$
+            return;
+        }
+    }
+
+    /**
+     * Set the collection of FileEditorMappings. The given collection is
+     * converted into the internal hash table for faster lookup Each mapping
+     * goes from an extension to the collection of editors that work on it. This
+     * operation will rebuild the internal editor mappings.
+     *
+     * @param newResourceTypes
+     *            te new file editor mappings.
+     */
+    public void setFileEditorMappings(FileEditorMapping[] newResourceTypes) {
+        typeEditorMappings = new EditorMap();
+        for (FileEditorMapping mapping : newResourceTypes) {
+            typeEditorMappings.put(mappingKeyFor(mapping), mapping);
+        }
+        extensionImages = new HashMap<>();
+        rebuildEditorMap();
+        firePropertyChange(PROP_CONTENTS);
+    }
+
+    @Override
+	public void setDefaultEditor(String fileName, String editorId) {
+		IEditorDescriptor desc = findEditor(editorId);
+		setDefaultEditor(fileName, desc);
+	}
+
+	public void setDefaultEditor(String fileName, IEditorDescriptor desc) {
+		FileEditorMapping[] mapping = getMappingForFilename(fileName);
+		if (mapping[0] != null) {
+			mapping[0].setDefaultEditor(desc);
+		}
+		if (mapping[1] != null) {
+			mapping[1].setDefaultEditor(desc);
+		}
+    }
+
+    /**
+     * Alphabetically sort the internal editors.
+     *
+     * @see #comparer
+     */
+	private IEditorDescriptor[] sortEditors(List<IEditorDescriptor> unsortedList) {
+		IEditorDescriptor[] array = new IEditorDescriptor[unsortedList.size()];
+        unsortedList.toArray(array);
+
+        Collections.sort(Arrays.asList(array), comparer);
+        return array;
+    }
+
+    /**
+     * Alphabetically sort the internal editors.
+     *
+     * @see #comparer
+     */
+    private void sortInternalEditors() {
+		IEditorDescriptor[] array = sortEditors(sortedEditorsFromPlugins);
+		sortedEditorsFromPlugins = new ArrayList<>();
+        for (IEditorDescriptor element : array) {
+            sortedEditorsFromPlugins.add(element);
+        }
+    }
+
+    /**
+     * Map of FileEditorMapping (extension to FileEditorMapping) Uses two
+     * java.util.HashMap: one keeps the default which are set by the plugins and
+     * the other keeps the changes made by the user through the preference page.
+     */
+    private static class EditorMap {
+		HashMap<String, FileEditorMapping> defaultMap = new HashMap<>();
+
+		HashMap<String, FileEditorMapping> map = new HashMap<>();
+
+        /**
+         * Put a default mapping into the editor map.
+         *
+         * @param key the key to set
+         * @param value the value to associate
+         */
+        public void putDefault(String key, FileEditorMapping value) {
+            defaultMap.put(key, value);
+        }
+
+        /**
+         * Put a mapping into the user editor map.
+         *
+         * @param key the key to set
+         * @param value the value to associate
+         */
+        public void put(String key, FileEditorMapping value) {
+            Object result = defaultMap.get(key);
+            if (value.equals(result)) {
+				map.remove(key);
+			} else {
+				map.put(key, value);
+			}
+        }
+
+        /**
+         * Return the mapping associated to the key. First searches user
+         * map, and then falls back to the default map if there is no match. May
+         * return <code>null</code>
+         *
+         * @param key
+         *            the key to search for
+         * @return the mapping associated to the key or <code>null</code>
+         */
+        public FileEditorMapping get(String key) {
+            Object result = map.get(key);
+            if (result == null) {
+				result = defaultMap.get(key);
+			}
+            return (FileEditorMapping) result;
+        }
+
+        /**
+         * Return all mappings. This will return default mappings overlayed with
+         * user mappings.
+         *
+         * @return the mappings
+         */
+        public FileEditorMapping[] allMappings() {
+			@SuppressWarnings("unchecked")
+			HashMap<String, FileEditorMapping> merge = (HashMap<String, FileEditorMapping>) defaultMap.clone();
+            merge.putAll(map);
+            Collection<FileEditorMapping> values = merge.values();
+            FileEditorMapping result[] = new FileEditorMapping[values.size()];
+            return values.toArray(result);
+        }
+
+        /**
+         * Return all user mappings.
+         *
+         * @return the mappings
+         */
+        public FileEditorMapping[] userMappings() {
+            Collection<FileEditorMapping> values = map.values();
+            FileEditorMapping result[] = new FileEditorMapping[values.size()];
+            return values.toArray(result);
+        }
+    }
+
+    @Override
+	public boolean isSystemInPlaceEditorAvailable(String filename) {
+        return ComponentSupport.inPlaceEditorAvailable(filename);
+    }
+
+    @Override
+	public boolean isSystemExternalEditorAvailable(String filename) {
+        // RAP [bm]: no external programs
+//      int nDot = filename.lastIndexOf('.');
+//      if (nDot >= 0) {
+//          String strName = filename.substring(nDot);
+//          return Program.findProgram(strName) != null;
+//      }
+        // RAPEND: [bm] 
+        return false;
+    }
+
+    @Override
+	public ImageDescriptor getSystemExternalEditorImageDescriptor(
+            String filename) {
+     // RAP [bm]: no external editors
+//      Program externalProgram = null;
+//      int extensionIndex = filename.lastIndexOf('.');
+//      if (extensionIndex >= 0) {
+//          externalProgram = Program.findProgram(filename
+//                  .substring(extensionIndex));
+//      }
+//      if (externalProgram == null) {
+//          return null;
+//      } 
+//      
+//      return new ExternalProgramImageDescriptor(externalProgram);
+        return null;
+    }
+
+    /**
+     * Removes the entry with the value of the editor descriptor from the given
+     * map. If the descriptor is the last descriptor in a given
+     * FileEditorMapping then the mapping is removed from the map.
+     *
+     * @param map
+     *            the map to search
+     * @param desc
+     *            the descriptor value to remove
+     */
+    private void removeEditorFromMapping(HashMap<String, FileEditorMapping> map, IEditorDescriptor desc) {
+        Iterator<FileEditorMapping> iter = map.values().iterator();
+		while (iter.hasNext()) {
+        	FileEditorMapping mapping = iter.next();
+			for (IEditorDescriptor editor : mapping.getUnfilteredEditors()) {
+				if (editor == desc) {
+					mapping.removeEditor(editor);
+                    break;
+                }
+			}
+			IEditorDescriptor[] editors = mapping.getUnfilteredEditors();
+			if (editors.length == 0) {
+				iter.remove();
+            }
+        }
+    }
+
+    @Override
+	public void removeExtension(IExtension source, Object[] objects) {
+        for (Object object : objects) {
+			if (object instanceof IEditorDescriptor) {
+				IEditorDescriptor desc = (IEditorDescriptor) object;
+
+                sortedEditorsFromPlugins.remove(desc);
+                mapIDtoEditor.values().remove(desc);
+                removeEditorFromMapping(typeEditorMappings.defaultMap, desc);
+                removeEditorFromMapping(typeEditorMappings.map, desc);
+                removeEditorFromContentTypeMappings(contentTypeToEditorMappings, desc);
+            }
+
+        }
+    }
+
+    /**
+     * Removes all occurrences of the given editor descriptor from the map of content types.
+     * If the descriptor was the only editor, the whole content type is removed from the map.
+     */
+	private void removeEditorFromContentTypeMappings(Map<IContentType, IEditorDescriptor[]> map, IEditorDescriptor desc) {
+		for (Iterator<Entry<IContentType, IEditorDescriptor[]>> iter = map.entrySet().iterator(); iter.hasNext();) {
+			Entry<IContentType, IEditorDescriptor[]> entry = iter.next();
+			IEditorDescriptor[] descriptors = entry.getValue();
+			IEditorDescriptor[] newDescriptors = removeDescriptor(descriptors, desc);
+			if (descriptors != newDescriptors) {
+				if (newDescriptors == null) {
+					iter.remove();
+				} else {
+					entry.setValue(newDescriptors);
+				}
+			}
+		}
+	}
+
+	/**
+	 * Checks the given IEditorDescriptor for an occurrence of the given descriptor and
+	 * returns an array not containing this descriptor.
+	 * If the result would then be an empty array, <code>null</code> is returned.
+	 * If the descriptor is not contained at all in the given array, it is returned as is.
+	 */
+	private IEditorDescriptor[] removeDescriptor(IEditorDescriptor[] descriptors, IEditorDescriptor desc) {
+		for (int i = 0; i < descriptors.length; i++) {
+			if (descriptors[i] == desc) {
+				// remove the whole mapping
+				if (descriptors.length == 1) {
+					return null;
+				}
+
+				IEditorDescriptor[] newDescriptors = new IEditorDescriptor[descriptors.length - 1];
+				if (i == 0) {
+					System.arraycopy(descriptors, 1, newDescriptors, 0, newDescriptors.length);
+				} else {
+					System.arraycopy(descriptors, 0, newDescriptors, 0, i);
+					if (i < newDescriptors.length) {
+						System.arraycopy(descriptors, i + 1, newDescriptors, i, newDescriptors.length - i);
+					}
+				}
+				return newDescriptors;
+			}
+		}
+
+		return descriptors;
+	}
+
+	@Override
+	public void addExtension(IExtensionTracker tracker, IExtension extension) {
+        EditorRegistryReader eReader = new EditorRegistryReader();
+        IConfigurationElement[] elements = extension.getConfigurationElements();
+        for (IConfigurationElement element : elements) {
+            String id = element.getAttribute(IWorkbenchConstants.TAG_ID);
+            if (id != null && findEditor(id) != null) {
+				continue;
+			}
+            eReader.readElement(this, element);
+        }
+	}
+
+	private IExtensionPoint getExtensionPointFilter() {
+	//  RAP [bm] namespace
+	    return Platform.getExtensionRegistry().getExtensionPoint(PlatformUI.PLUGIN_EXTENSION_NAME_SPACE, IWorkbenchRegistryConstants.PL_EDITOR);
+	}
+
+	@Override
+	public IEditorDescriptor getDefaultEditor(String fileName, IContentType contentType) {
+        return getEditorForContentType(fileName, contentType);
+	}
+
+	/**
+	 * Return the editor for a file with a given content type.
+	 *
+	 * @param filename the file name
+	 * @param contentType the content type
+	 * @return the editor for a file with a given content type
+	 * @since 3.1
+	 */
+	private IEditorDescriptor getEditorForContentType(String filename,
+			IContentType contentType) {
+		IEditorDescriptor desc = null;
+		Object[] contentTypeResults = findRelatedObjects(contentType, filename, relatedRegistry);
+		if (contentTypeResults != null && contentTypeResults.length > 0) {
+			desc = (IEditorDescriptor) contentTypeResults[0];
+		}
+		return desc;
+	}
+
+	@Override
+	public IEditorDescriptor[] getEditors(String fileName, IContentType contentType) {
+		return findRelatedObjects(contentType, fileName, relatedRegistry);
+	}
+
+	@Override
+	public ImageDescriptor getImageDescriptor(String filename, IContentType contentType) {
+        if (filename == null) {
+			return getDefaultImage();
+		}
+
+		if (contentType != null) {
+			IEditorDescriptor desc = getEditorForContentType(filename, contentType);
+			if (desc != null) {
+				ImageDescriptor anImage = extensionImages.get(desc);
+				if (anImage != null) {
+					return anImage;
+				}
+				anImage = desc.getImageDescriptor();
+				extensionImages.put(desc, anImage);
+				return anImage;
+			}
+		}
+        // Lookup in the cache first...
+        String key = mappingKeyFor(filename);
+        ImageDescriptor anImage = extensionImages.get(key);
+        if (anImage != null) {
+			return anImage;
+		}
+
+        // See if we have a mapping for the filename or extension
+        FileEditorMapping[] mapping = getMappingForFilename(filename);
+        for (int i = 0; i < 2; i++) {
+            if (mapping[i] != null) {
+                // Lookup in the cache first...
+                String mappingKey = mappingKeyFor(mapping[i]);
+                ImageDescriptor mappingImage = extensionImages.get(key);
+                if (mappingImage != null) {
+					return mappingImage;
+				}
+                // Create it and cache it
+                IEditorDescriptor editor = mapping[i].getDefaultEditor();
+                if (editor != null) {
+                    mappingImage = editor.getImageDescriptor();
+                    extensionImages.put(mappingKey, mappingImage);
+                    return mappingImage;
+                }
+            }
+        }
+
+        // Nothing - time to look externally for the icon
+        anImage = getSystemExternalEditorImageDescriptor(filename);
+        if (anImage == null) {
+			anImage = getDefaultImage();
+		}
+        //	for dynamic UI - comment out the next line
+        //extensionImages.put(key, anImage);
+        return anImage;
+
+	}
+
+    /**
+	 * Find objects related to the content type.
+	 *
+	 * This method is temporary and exists only to back us off of the
+	 * soon-to-be-removed IContentTypeManager.IRelatedRegistry API.
+	 *
+	 * @param type
+	 * @param fileName
+	 * @param registry
+	 * @return the related objects
+	 */
+	private IEditorDescriptor [] findRelatedObjects(IContentType type, String fileName,
+			RelatedRegistry registry) {
+		List<IEditorDescriptor> allRelated = new ArrayList<>();
+		List<IEditorDescriptor> nonDefaultFileEditors = new ArrayList<>();
+
+		if (fileName != null) {
+			FileEditorMapping mapping = getMappingFor(fileName);
+			if (mapping != null) {
+				// backwards compatibility - add editors flagged as "default"
+				IEditorDescriptor[] related = mapping.getDeclaredDefaultEditors();
+				for (IEditorDescriptor editor : related) {
+					// we don't want to return duplicates
+					if (editor != null && !allRelated.contains(editor)) {
+						// if it's not filtered, add it to the list
+						if (!WorkbenchActivityHelper.filterItem(editor)) {
+							allRelated.add(editor);
+						}
+					}
+				}
+
+				// add all filename editors to the nonDefaultList
+				// we'll later try to add them all after content types are resolved
+				// duplicates (ie: default editors) will be ignored
+				nonDefaultFileEditors.addAll(Arrays.asList(mapping.getEditors()));
+			}
+
+			int index = fileName.lastIndexOf('.');
+			if (index > -1) {
+				String extension = "*" + fileName.substring(index); //$NON-NLS-1$
+				mapping = getMappingFor(extension);
+				if (mapping != null) {
+					IEditorDescriptor[] related = mapping.getDeclaredDefaultEditors();
+					for (IEditorDescriptor editor : related) {
+						// we don't want to return duplicates
+						if (editor != null && !allRelated.contains(editor)) {
+							// if it's not filtered, add it to the list
+							if (!WorkbenchActivityHelper.filterItem(editor)) {
+								allRelated.add(editor);
+							}
+						}
+					}
+					nonDefaultFileEditors.addAll(Arrays.asList(mapping.getEditors()));
+				}
+			}
+		}
+
+		if (type != null) {
+			// now add any objects directly related to the content type
+			IEditorDescriptor[] related = registry.getRelatedObjects(type);
+			for (int i = 0; i < related.length; i++) {
+				// we don't want to return duplicates
+				if (!allRelated.contains(related[i])) {
+					// if it's not filtered, add it to the list
+					if (!WorkbenchActivityHelper.filterItem(related[i])) {
+						allRelated.add(related[i]);
+					}
+				}
+			}
+
+		}
+
+		if (type != null) {
+			// now add any indirectly related objects, walking up the content type hierarchy
+			while ((type = type.getBaseType()) != null) {
+				IEditorDescriptor[] related = registry.getRelatedObjects(type);
+				for (int i = 0; i < related.length; i++) {
+					// we don't want to return duplicates
+					if (!allRelated.contains(related[i])) {
+						// if it's not filtered, add it to the list
+						if (!WorkbenchActivityHelper.filterItem(related[i])) {
+							allRelated.add(related[i]);
+						}
+					}
+				}
+			}
+		}
+
+		// add all non-default editors to the list
+		for (IEditorDescriptor editor : nonDefaultFileEditors) {
+			if (editor != null && !allRelated.contains(editor) && !WorkbenchActivityHelper.filterItem(editor)) {
+				allRelated.add(editor);
+			}
+		}
+
+		return allRelated.toArray(new IEditorDescriptor [allRelated.size()]);
+	}
+
+	/**
+	 * Return the editors bound to this content type, either directly or indirectly.
+	 *
+	 * @param type the content type to check
+	 * @return the editors
+	 * @since 3.1
+     *
+     * TODO: this should be rolled in with the above findRelatedObjects code
+	 */
+	public IEditorDescriptor [] getEditorsForContentType(IContentType type) {
+		List<IEditorDescriptor> allRelated = new ArrayList<>();
+		if (type == null) {
+			return new IEditorDescriptor [0];
+		}
+
+		IEditorDescriptor[] related = relatedRegistry.getRelatedObjects(type);
+		for (int i = 0; i < related.length; i++) {
+			// we don't want to return duplicates
+			if (!allRelated.contains(related[i])) {
+				// if it's not filtered, add it to the list
+				if (!WorkbenchActivityHelper.filterItem(related[i])) {
+					allRelated.add(related[i]);
+				}
+
+			}
+		}
+
+		// now add any indirectly related objects, walking up the content type hierarchy
+		while ((type = type.getBaseType()) != null) {
+			related = relatedRegistry.getRelatedObjects(type);
+			for (int i = 0; i < related.length; i++) {
+				// we don't want to return duplicates
+				if (!allRelated.contains(related[i])) {
+					// if it's not filtered, add it to the list
+					if (!WorkbenchActivityHelper.filterItem(related[i])) {
+						allRelated.add(related[i]);
+					}
+				}
+			}
+		}
+
+		return allRelated.toArray(new IEditorDescriptor[allRelated.size()]);
+	}
+
+	/**
+	 * Get file mappings for all defined file types, including those defined by
+	 * content type.
+	 *
+	 * @return the file types
+	 * @since 3.1
+	 */
+	public IFileEditorMapping [] getUnifiedMappings() {
+        IFileEditorMapping[] standardMappings = PlatformUI.getWorkbench()
+                .getEditorRegistry().getFileEditorMappings();
+
+        List<IFileEditorMapping> allMappings = new ArrayList<>(Arrays.asList(standardMappings));
+        // mock-up content type extensions into IFileEditorMappings
+		for (IContentType type : Platform.getContentTypeManager().getAllContentTypes()) {
+			for (String extension : type.getFileSpecs(IContentType.FILE_EXTENSION_SPEC)) {
+				boolean found = false;
+				for (IFileEditorMapping mapping : allMappings) {
+					if ("*".equals(mapping.getName()) && extension.equals(mapping.getExtension())) { //$NON-NLS-1$
+						found = true;
+						break;
+					}
+				}
+				if (!found) {
+					MockMapping mockMapping = new MockMapping(type, "*", extension); //$NON-NLS-1$
+					allMappings.add(mockMapping);
+				}
+			}
+
+			for (String wholename : type.getFileSpecs(IContentType.FILE_NAME_SPEC)) {
+				int idx = wholename.indexOf('.');
+				String name = idx == -1 ? wholename : wholename.substring(0, idx);
+				String extension = idx == -1 ? "" : wholename.substring(idx + 1); //$NON-NLS-1$
+
+				boolean found = false;
+				for (IFileEditorMapping mapping : allMappings) {
+					if (name.equals(mapping.getName()) && extension.equals(mapping.getExtension())) {
+						found = true;
+						break;
+					}
+				}
+				if (!found) {
+					MockMapping mockMapping = new MockMapping(type, name, extension);
+					allMappings.add(mockMapping);
+				}
+			}
+		}
+
+        return allMappings.toArray(new IFileEditorMapping [allMappings.size()]);
+	}
+
+}
+
+
+class MockMapping implements IFileEditorMapping {
+
+	private IContentType contentType;
+	private String extension;
+	private String filename;
+
+	MockMapping(IContentType type, String name, String ext) {
+		this.contentType = type;
+		this.filename = name;
+		this.extension = ext;
+	}
+
+	@Override
+	public IEditorDescriptor getDefaultEditor() {
+		IEditorDescriptor[] candidates = ((EditorRegistry) PlatformUI
+				.getWorkbench().getEditorRegistry())
+				.getEditorsForContentType(contentType);
+		if (candidates.length == 0
+				|| WorkbenchActivityHelper.restrictUseOf(candidates[0])) {
+			return null;
+		}
+		return candidates[0];
+	}
+
+	@Override
+	public IEditorDescriptor[] getEditors() {
+		IEditorDescriptor[] editorsForContentType = ((EditorRegistry) PlatformUI
+				.getWorkbench().getEditorRegistry())
+				.getEditorsForContentType(contentType);
+		return (IEditorDescriptor[]) WorkbenchActivityHelper
+				.restrictArray(editorsForContentType);
+	}
+
+	@Override
+	public IEditorDescriptor[] getDeletedEditors() {
+		return new IEditorDescriptor[0];
+	}
+
+	@Override
+	public String getExtension() {
+		return extension;
+	}
+
+	@Override
+	public ImageDescriptor getImageDescriptor() {
+		IEditorDescriptor editor = getDefaultEditor();
+		if (editor == null) {
+			return WorkbenchImages
+					.getImageDescriptor(ISharedImages.IMG_OBJ_FILE);
+		}
+
+		return editor.getImageDescriptor();
+	}
+
+	@Override
+	public String getLabel() {
+		return filename + '.' + extension;
+	}
+
+	@Override
+	public String getName() {
+		return filename;
+    }
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj) {
+			return true;
+		}
+
+		if (!(obj instanceof MockMapping)) {
+			return false;
+		}
+
+		MockMapping mapping = (MockMapping) obj;
+		if (!this.filename.equals(mapping.filename)) {
+			return false;
+		}
+
+		if (!this.extension.equals(mapping.extension)) {
+			return false;
+		}
+
+		if (!Util.equals(this.getEditors(), mapping.getEditors())) {
+			return false;
+		}
+		return Util.equals(this.getDeletedEditors(), mapping
+				.getDeletedEditors());
+	}
+}
+
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/EditorRegistryReader.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/EditorRegistryReader.java
new file mode 100644
index 0000000..00d1317
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/EditorRegistryReader.java
@@ -0,0 +1,164 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.registry;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.content.IContentType;
+import org.eclipse.ui.IEditorDescriptor;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * This class is used to read resource editor registry descriptors from
+ * the platform registry.
+ */
+public class EditorRegistryReader extends RegistryReader {
+
+    private EditorRegistry editorRegistry;
+
+    /**
+     * Get the editors that are defined in the registry
+     * and add them to the ResourceEditorRegistry
+     *
+     * Warning:
+     * The registry must be passed in because this method is called during the
+     * process of setting up the registry and at this time it has not been
+     * safely setup with the plugin.
+     */
+    protected void addEditors(EditorRegistry registry) {
+        IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry();
+        this.editorRegistry = registry;
+        readRegistry(extensionRegistry, PlatformUI.PLUGIN_EXTENSION_NAME_SPACE,
+                IWorkbenchRegistryConstants.PL_EDITOR);
+    }
+
+    /**
+     * Implementation of the abstract method that
+     * processes one configuration element.
+     */
+    @Override
+	protected boolean readElement(IConfigurationElement element) {
+		if (element.getName().equals(IWorkbenchRegistryConstants.TAG_EDITOR)) {
+			return readEditorElement(element);
+		}
+		if (element.getName().equals(IWorkbenchRegistryConstants.TAG_EDITOR_CONTENT_TYPTE_BINDING)) {
+			return readEditorContentTypeBinding(element);
+		}
+		return false;
+    }
+
+	/**
+	 * @param element
+	 * @return
+	 */
+	private boolean readEditorContentTypeBinding(IConfigurationElement element) {
+		IEditorDescriptor descriptor = null;
+		String editorId = element.getAttribute(IWorkbenchRegistryConstants.ATT_EDITOR_ID);
+		if (editorId == null) {
+			logMissingAttribute(element, IWorkbenchRegistryConstants.ATT_EDITOR_ID);
+		} else {
+			descriptor = editorRegistry.findEditor(editorId);
+			if (descriptor == null) {
+				logError(element, "Unknown editor with id: " + editorId); //$NON-NLS-1$
+			}
+		}
+
+		IContentType contentType = null;
+		String contentTypeId = element.getAttribute(IWorkbenchRegistryConstants.ATT_CONTENT_TYPE_ID);
+		if (contentTypeId == null) {
+			logMissingAttribute(element, IWorkbenchRegistryConstants.ATT_CONTENT_TYPE_ID);
+		} else {
+			contentType = Platform.getContentTypeManager().getContentType(contentTypeId);
+			if (contentType == null) {
+				logError(element, "Unknown content-type with id: " + contentTypeId); //$NON-NLS-1$
+			}
+		}
+
+		if (descriptor != null && contentType != null) {
+			editorRegistry.addContentTypeBinding(contentType, descriptor, false);
+		}
+		return true;
+	}
+
+	private boolean readEditorElement(IConfigurationElement element) {
+		String id = element.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+        if (id == null) {
+            logMissingAttribute(element, IWorkbenchRegistryConstants.ATT_ID);
+            return true;
+        }
+
+        EditorDescriptor editor = new EditorDescriptor(id, element);
+
+        List extensionsVector = new ArrayList();
+        List filenamesVector = new ArrayList();
+		List contentTypeVector = new ArrayList();
+        boolean defaultEditor = false;
+
+        // Get editor name (required field).
+        if (element.getAttribute(IWorkbenchRegistryConstants.ATT_NAME) == null) {
+            logMissingAttribute(element, IWorkbenchRegistryConstants.ATT_NAME);
+            return true;
+        }
+
+        // Get target extensions (optional field)
+        String extensionsString = element.getAttribute(IWorkbenchRegistryConstants.ATT_EXTENSIONS);
+        if (extensionsString != null) {
+            StringTokenizer tokenizer = new StringTokenizer(extensionsString,
+                    ",");//$NON-NLS-1$
+            while (tokenizer.hasMoreTokens()) {
+                extensionsVector.add(tokenizer.nextToken().trim());
+            }
+        }
+        String filenamesString = element.getAttribute(IWorkbenchRegistryConstants.ATT_FILENAMES);
+        if (filenamesString != null) {
+            StringTokenizer tokenizer = new StringTokenizer(filenamesString,
+                    ",");//$NON-NLS-1$
+            while (tokenizer.hasMoreTokens()) {
+                filenamesVector.add(tokenizer.nextToken().trim());
+            }
+        }
+
+		IConfigurationElement [] bindings = element.getChildren(IWorkbenchRegistryConstants.TAG_CONTENT_TYPE_BINDING);
+		for (IConfigurationElement binding : bindings) {
+			String contentTypeId = binding.getAttribute(IWorkbenchRegistryConstants.ATT_CONTENT_TYPE_ID);
+			if (contentTypeId == null) {
+				continue;
+			}
+			contentTypeVector.add(contentTypeId);
+		}
+
+        // Is this the default editor?
+        String def = element.getAttribute(IWorkbenchRegistryConstants.ATT_DEFAULT);
+        if (def != null) {
+			defaultEditor = Boolean.valueOf(def).booleanValue();
+		}
+
+        // Add the editor to the manager.
+        editorRegistry.addEditorFromPlugin(editor, extensionsVector,
+                filenamesVector, contentTypeVector, defaultEditor);
+        return true;
+	}
+
+
+    /**
+     * @param editorRegistry
+     * @param element
+     */
+    public void readElement(EditorRegistry editorRegistry,
+            IConfigurationElement element) {
+        this.editorRegistry = editorRegistry;
+        readElement(element);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/FileEditorMapping.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/FileEditorMapping.java
new file mode 100644
index 0000000..6aca357
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/FileEditorMapping.java
@@ -0,0 +1,328 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Jan-Hendrik Diederich, Bredex GmbH - bug 201052
+ *     Carsten Pfeiffer, Gebit Solutions GmbH - bug 259536
+ *******************************************************************************/
+package org.eclipse.ui.internal.registry;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.osgi.util.TextProcessor;
+import org.eclipse.ui.IEditorDescriptor;
+import org.eclipse.ui.IFileEditorMapping;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.activities.WorkbenchActivityHelper;
+import org.eclipse.ui.internal.WorkbenchImages;
+
+/**
+ * Implementation of IFileEditorMapping.
+ *
+ */
+public class FileEditorMapping extends Object implements IFileEditorMapping,
+    Cloneable {
+
+	private static final String STAR = "*"; //$NON-NLS-1$
+	private static final String DOT = ".";	//$NON-NLS-1$
+
+    private String name = STAR;
+
+    private String extension;
+
+    // Collection of EditorDescriptor, where the first one
+    // if considered the default one.
+	private List<IEditorDescriptor> editors = new ArrayList<>(1);
+
+	private List<IEditorDescriptor> deletedEditors = new ArrayList<>(1);
+
+	private List<IEditorDescriptor> declaredDefaultEditors = new ArrayList<>(1);
+
+    /**
+     *  Create an instance of this class.
+     *
+     *  @param extension java.lang.String
+     */
+    public FileEditorMapping(String extension) {
+        this(STAR, extension);
+    }
+
+    /**
+     *  Create an instance of this class.
+     *
+     *  @param name java.lang.String
+     *  @param extension java.lang.String
+     */
+    public FileEditorMapping(String name, String extension) {
+        super();
+        if (name == null || name.length() < 1) {
+            setName(STAR);
+        } else {
+			setName(name);
+		}
+        if (extension == null) {
+			setExtension("");//$NON-NLS-1$
+		} else {
+			setExtension(extension);
+		}
+    }
+
+    /**
+     * Add the given editor to the list of editors registered.
+     *
+     * @param editor the editor to add
+     */
+	public void addEditor(EditorDescriptor editor) {
+		Assert.isNotNull(editor);
+        editors.add(editor);
+        deletedEditors.remove(editor);
+    }
+
+    /**
+     * Clone the receiver.
+     */
+	@SuppressWarnings("unchecked")
+	@Override
+	public Object clone() {
+        try {
+            FileEditorMapping clone = (FileEditorMapping) super.clone();
+			clone.editors = (List<IEditorDescriptor>) ((ArrayList<IEditorDescriptor>) editors).clone();
+			clone.deletedEditors = (List<IEditorDescriptor>) ((ArrayList<IEditorDescriptor>) deletedEditors).clone();
+			clone.declaredDefaultEditors = (List<IEditorDescriptor>) ((ArrayList<IEditorDescriptor>) declaredDefaultEditors)
+					.clone();
+            return clone;
+        } catch (CloneNotSupportedException e) {
+            return null;
+        }
+    }
+
+    @Override
+	public boolean equals(Object obj) {
+        if (this == obj) {
+			return true;
+		}
+        if (!(obj instanceof FileEditorMapping)) {
+			return false;
+		}
+        FileEditorMapping mapping = (FileEditorMapping) obj;
+        if (!this.name.equals(mapping.name)) {
+			return false;
+		}
+        if (!this.extension.equals(mapping.extension)) {
+			return false;
+		}
+
+        if (!compareList(this.editors, mapping.editors)) {
+			return false;
+		}
+		if (!compareList(this.declaredDefaultEditors, mapping.declaredDefaultEditors)) {
+			return false;
+		}
+        return compareList(this.deletedEditors, mapping.deletedEditors);
+    }
+
+    /**
+     * Compare the editor ids from both lists and return true if they
+     * are equals.
+     */
+	private boolean compareList(List<IEditorDescriptor> l1, List<IEditorDescriptor> l2) {
+        if (l1.size() != l2.size()) {
+			return false;
+		}
+
+		Iterator<IEditorDescriptor> i1 = l1.iterator();
+		Iterator<IEditorDescriptor> i2 = l2.iterator();
+        while (i1.hasNext() && i2.hasNext()) {
+            Object o1 = i1.next();
+            Object o2 = i2.next();
+            if (!(o1 == null ? o2 == null : o1.equals(o2))) {
+				return false;
+			}
+        }
+        return true;
+    }
+
+    @Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result
+				+ ((declaredDefaultEditors == null) ? 0 : declaredDefaultEditors.hashCode());
+		result = prime * result + ((deletedEditors == null) ? 0 : deletedEditors.hashCode());
+		result = prime * result + ((editors == null) ? 0 : editors.hashCode());
+		result = prime * result + ((extension == null) ? 0 : extension.hashCode());
+		result = prime * result + ((name == null) ? 0 : name.hashCode());
+		return result;
+	}
+
+    @Override
+	public IEditorDescriptor getDefaultEditor() {
+        if (editors.size() == 0 || WorkbenchActivityHelper.restrictUseOf(editors.get(0))) {
+			return null;
+		}
+        return editors.get(0);
+    }
+
+    /**
+     * Returns all editor descriptors of this mapping, not filtered by activities.
+     */
+    IEditorDescriptor[] getUnfilteredEditors() {
+    	return editors.toArray(new IEditorDescriptor[editors.size()]);
+    }
+
+    @Override
+	public IEditorDescriptor[] getEditors() {
+		Collection<IEditorDescriptor> descs = WorkbenchActivityHelper.restrictCollection(editors, new ArrayList<>());
+		return descs.toArray(new IEditorDescriptor[descs.size()]);
+    }
+
+    @Override
+	public IEditorDescriptor[] getDeletedEditors() {
+        IEditorDescriptor[] array = new IEditorDescriptor[deletedEditors.size()];
+        deletedEditors.toArray(array);
+        return array;
+    }
+
+    @Override
+	public String getExtension() {
+        return extension;
+    }
+
+    @Override
+	public ImageDescriptor getImageDescriptor() {
+        IEditorDescriptor editor = getDefaultEditor();
+        if (editor == null) {
+            return WorkbenchImages
+                    .getImageDescriptor(ISharedImages.IMG_OBJ_FILE);
+        }
+        return editor.getImageDescriptor();
+    }
+
+    @Override
+	public String getLabel() {
+        return TextProcessor.process(name + (extension.length() == 0 ? "" : DOT + extension), STAR + DOT); 	//$NON-NLS-1$
+    }
+
+    @Override
+	public String getName() {
+        return name;
+    }
+
+    /**
+     * Remove the given editor from the set of editors registered.
+     *
+     * @param editor the editor to remove
+     */
+	public void removeEditor(IEditorDescriptor editor) {
+		Assert.isNotNull(editor);
+        editors.remove(editor);
+        deletedEditors.add(editor);
+        declaredDefaultEditors.remove(editor);
+    }
+
+    /**
+     * Set the default editor registered for file type
+     * described by this mapping.
+     *
+     * @param editor the editor to be set as default
+     */
+	public void setDefaultEditor(IEditorDescriptor editor) {
+		Assert.isNotNull(editor);
+        editors.remove(editor);
+        editors.add(0, editor);
+        declaredDefaultEditors.remove(editor);
+        declaredDefaultEditors.add(0, editor);
+    }
+
+    /**
+     * Set the collection of all editors (EditorDescriptor)
+     * registered for the file type described by this mapping.
+     * Typically an editor is registered either through a plugin or explicitly by
+     * the user modifying the associations in the preference pages.
+     * This modifies the internal list to share the passed list.
+     * (hence the clear indication of list in the method name)
+     *
+     * @param newEditors the new list of associated editors
+     */
+	public void setEditorsList(List<IEditorDescriptor> newEditors) {
+        editors = newEditors;
+        declaredDefaultEditors.retainAll(newEditors);
+    }
+
+    /**
+     * Set the collection of all editors (EditorDescriptor)
+     * formally registered for the file type described by this mapping
+     * which have been deleted by the user.
+     * This modifies the internal list to share the passed list.
+     * (hence the clear indication of list in the method name)
+     *
+     * @param newDeletedEditors the new list of associated (but deleted) editors
+     */
+	public void setDeletedEditorsList(List<IEditorDescriptor> newDeletedEditors) {
+        deletedEditors = newDeletedEditors;
+    }
+
+    /**
+     * Set the file's extension.
+     *
+     * @param extension the file extension for this mapping
+     */
+    public void setExtension(String extension) {
+        this.extension = extension;
+    }
+
+    /**
+     * Set the file's name.
+     *
+     * @param name the file name for this mapping
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+	 * Get the editors that have been declared as default. This may be via plugin
+	 * declarations or the preference page.
+	 *
+	 * @return the editors the default editors
+	 * @since 3.1
+	 */
+	public IEditorDescriptor [] getDeclaredDefaultEditors() {
+		Collection<IEditorDescriptor> descs = WorkbenchActivityHelper.restrictCollection(declaredDefaultEditors,
+				new ArrayList<>());
+		return descs.toArray(new IEditorDescriptor[descs.size()]);
+	}
+
+	/**
+	 * Return whether the editor is declared default.
+	 * If this is EditorDescriptor fails the ExpressionsCheck it will always
+	 * return <code>false</code>, even if it's the original default editor.
+	 *
+	 * @param editor the editor to test
+	 * @return whether the editor is declared default
+	 * @since 3.1
+	 */
+	public boolean isDeclaredDefaultEditor (IEditorDescriptor editor) {
+		return declaredDefaultEditors.contains(editor)
+				&& !WorkbenchActivityHelper.restrictUseOf(editor);
+	}
+
+	/**
+	 * Set the default editors for this mapping.
+	 *
+	 * @param defaultEditors the editors
+	 * @since 3.1
+	 */
+	public void setDefaultEditors(List<IEditorDescriptor> defaultEditors) {
+		declaredDefaultEditors = defaultEditors;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/IActionSet.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/IActionSet.java
new file mode 100644
index 0000000..2ec57e3
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/IActionSet.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.registry;
+
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IWorkbenchWindow;
+
+/**
+ * An action set is responsible for the creation of actions.
+ * The end user may add these actions to a workbench page menu and tool bar
+ * if they are deemed useful to the particular task at hand.
+ * <p>
+ * [Issue: This interface is not exposed in API, but time may
+ * demonstrate that it should be.  For the short term leave it be.
+ * In the long term its use should be re-evaluated. ]
+ * </p>
+ * <p>
+ * In the current workbench implementation the desktop provides the
+ * only implementation of this class in PluginActionSet.  So, it may
+ * be useful to phase this interface out at some point.  PluginActionSet
+ * provides a lazy load strategy, where the actions are declared in
+ * XML and represented at runtime by a PluginAction.
+ * </p>
+ */
+public interface IActionSet {
+    /**
+     * Disposes of this action set.
+     * <p>
+     * Implementation should remove any references to the window and action bars
+     * created in the <code>init</code>.
+     * </p>
+     * <p>
+     * [Issue: Should this say: "...should remove anything they contributed
+     *  in <code>init</code>? Or is most of the withdrawal done automatically?
+     * ]
+     * </p>
+     */
+    public void dispose();
+
+    /**
+     * Initializes this action set, which is expected to add it actions as required
+     * to the given workbench window and action bars.
+     *
+     * @param window the workbench window
+     * @param bars the action bars
+     */
+    public void init(IWorkbenchWindow window, IActionBars bars);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/IActionSetDescriptor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/IActionSetDescriptor.java
new file mode 100644
index 0000000..14a7512
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/IActionSetDescriptor.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.registry;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+
+/**
+ * A named set of actions which is defined as an extension to the workbench
+ * via the standard workbench actions extension point
+ * (<code>"org.eclipse.ui.workbenchActions"</code>).
+ * <p>
+ * [Issue: This interface is not exposed in API, but time may
+ * demonstrate that it should be.  For the short term leave it be.
+ * In the long term its use should be re-evaluated. ]
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ * @see ActionSetRegistry
+ */
+public interface IActionSetDescriptor {
+
+    /**
+     * Creates a new action set from this descriptor.
+     * <p>
+     * [Issue: Consider throwing WorkbenchException rather than CoreException.]
+     * </p>
+     *
+     * @return the new action set
+     * @exception CoreException if the action set cannot be created
+     */
+    public IActionSet createActionSet() throws CoreException;
+
+    /**
+     * Returns the description of this action set.
+     * This is the value of its <code>"description"</code> attribute.
+     *
+     * @return the description
+     */
+    public String getDescription();
+
+    /**
+     * Returns the id of this action set.
+     * This is the value of its <code>"id"</code> attribute.
+     *
+     * @return the action set id
+     */
+    public String getId();
+
+    /**
+     * Returns the label of this action set.
+     * This is the value of its <code>"label"</code> attribute.
+     *
+     * @return the label
+     */
+    public String getLabel();
+
+    /**
+     * Returns whether this action set is initially visible.
+     *
+     * @return whether this action set is initially visible
+     */
+    public boolean isInitiallyVisible();
+
+    /**
+     * Sets whether this action set is initially visible.
+     *
+     * @param visible whether the action set should be visible initially.
+     * @since 3.0
+     */
+    public void setInitiallyVisible(boolean visible);
+
+    /**
+     * Returns the conconfigurationfig element.
+     *
+     * @return the configuration element
+     * @since 3.1
+     */
+    public IConfigurationElement getConfigurationElement();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/IWorkbenchRegistryConstants.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/IWorkbenchRegistryConstants.java
new file mode 100644
index 0000000..eb1f374
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/IWorkbenchRegistryConstants.java
@@ -0,0 +1,1378 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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
+ *     Dan Rubel <dan_rubel@instantiations.com>
+ *     - Fix for bug 11490 - define hidden view (placeholder for view) in plugin.xml
+ *     Markus Alexander Kuppe, Versant Corporation - bug #215797
+ *     Semion Chichelnitsky (semion@il.ibm.com) - bug 208564
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 441184, 441280
+ *     Denis Zygann <d.zygann@web.de> - Bug 457390
+ *******************************************************************************/
+package org.eclipse.ui.internal.registry;
+
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * Interface containing various registry constants (tag and attribute names).
+ *
+ * @since 3.1
+ */
+public interface IWorkbenchRegistryConstants {
+
+	/**
+	 * Accelerator attribute. Value <code>accelerator</code>.
+	 */
+	public static String ATT_ACCELERATOR = "accelerator"; //$NON-NLS-1$
+
+	/**
+	 * Adaptable attribute. Value <code>adaptable</code>.
+	 */
+	public static String ATT_ADAPTABLE = "adaptable"; //$NON-NLS-1$
+
+	/**
+	 * Advisor id attribute. Value <code>triggerPointAdvisorId</code>.
+	 */
+	public static String ATT_ADVISORID = "triggerPointAdvisorId"; //$NON-NLS-1$
+
+	/**
+	 * Allow label update attribute. Value <code>allowLabelUpdate</code>.
+	 */
+	public static String ATT_ALLOW_LABEL_UPDATE = "allowLabelUpdate";//$NON-NLS-1$
+
+	/**
+	 * View multiple attribute. Value <code>allowMultiple</code>.
+	 */
+	public static String ATT_ALLOW_MULTIPLE = "allowMultiple"; //$NON-NLS-1$
+
+	/**
+	 * Attribute that specifies whether a view gets restored upon workbench restart. Value <code>restorable</code>.
+	 */
+	public static String ATT_RESTORABLE = "restorable"; //$NON-NLS-1$
+
+	/**
+	 * Attribute that specifies whether a wizard is immediately capable of
+	 * finishing. Value <code>canFinishEarly</code>.
+	 */
+	public static String ATT_CAN_FINISH_EARLY = "canFinishEarly"; //$NON-NLS-1$
+
+	/**
+	 * The name of the category attribute, which appears on a command
+	 * definition.
+	 */
+	public static String ATT_CATEGORY = "category"; //$NON-NLS-1$
+
+	/**
+	 * Category id attribute. Value <code>categoryId</code>.
+	 */
+	public static String ATT_CATEGORY_ID = "categoryId"; //$NON-NLS-1$
+
+	/**
+	 * The name of the attribute storing checkEnabled for the visibleWhen
+	 * element. Value <code>checkEnabled</code>.
+	 */
+	public static String ATT_CHECK_ENABLED = "checkEnabled"; //$NON-NLS-1$
+
+	/**
+	 * Class attribute. Value <code>class</code>.
+	 */
+	public static String ATT_CLASS = "class"; //$NON-NLS-1$
+
+	/**
+	 * Sticky view closable attribute. Value <code>closable</code>.
+	 */
+	public static String ATT_CLOSEABLE = "closeable"; //$NON-NLS-1$
+
+	/**
+	 * Color factory attribute. Value <code>colorFactory</code>.
+	 */
+	public static String ATT_COLORFACTORY = "colorFactory"; //$NON-NLS-1$
+
+	/**
+	 * Editor command attribute. Value <code>command</code>.
+	 */
+	public static String ATT_COMMAND = "command";//$NON-NLS-1$
+
+	/**
+	 * The name of the attribute storing the command id.
+	 */
+	public static String ATT_COMMAND_ID = "commandId"; //$NON-NLS-1$
+
+	/**
+	 * The name of the configuration attribute storing the scheme id for a
+	 * binding.
+	 */
+	public static String ATT_CONFIGURATION = "configuration"; //$NON-NLS-1$
+
+	/**
+	 * Intro content detector class attribute (optional). Value <code>contentDetector</code>.
+	 */
+	public static String ATT_CONTENT_DETECTOR = "contentDetector"; //$NON-NLS-1$
+
+	/**
+	 * Editor content type id binding attribute. Value
+	 * <code>contentTypeId</code>.
+	 */
+	public static String ATT_CONTENT_TYPE_ID = "contentTypeId"; //$NON-NLS-1$
+
+	/**
+	 * The name of the attribute storing the context id for a binding.
+	 */
+	public static String ATT_CONTEXT_ID = "contextId"; //$NON-NLS-1$
+
+	/**
+	 * Editor contributor class attribute. Value <code>contributorClass</code>.
+	 */
+	public static String ATT_CONTRIBUTOR_CLASS = "contributorClass"; //$NON-NLS-1$
+
+	/**
+	 * The name of the attribute storing the AbstractParameterValueConverter for
+	 * a commandParameterType.
+	 */
+	public static String ATT_CONVERTER = "converter"; //$NON-NLS-1$
+
+	/**
+	 * Perspective default attribute. Value <code>default</code>.
+	 */
+	public static String ATT_DEFAULT = "default";//$NON-NLS-1$
+
+	/**
+	 * The name of the default handler attribute, which appears on a command
+	 * definition.
+	 */
+	public static String ATT_DEFAULT_HANDLER = "defaultHandler"; //$NON-NLS-1$
+
+	/**
+	 * Defaults-to attribute. Value <code>defaultsTo</code>.
+	 */
+	public static String ATT_DEFAULTS_TO = "defaultsTo"; //$NON-NLS-1$
+
+	/**
+	 * Action definition id attribute. Value <code>definitionId</code>.
+	 */
+	public static String ATT_DEFINITION_ID = "definitionId";//$NON-NLS-1$
+
+	/**
+	 * Resembles a deactivated SYSTEM binding. Value <code>deleted</code>.
+	 */
+	public static String ATT_DELETED = "deleted";//$NON-NLS-1$
+
+	/**
+	 * The name of the description attribute, which appears on named handle
+	 * objects.
+	 */
+	public static String ATT_DESCRIPTION = "description"; //$NON-NLS-1$
+
+	/**
+	 * Description image attribute. Value <code>descriptionImage</code>.
+	 */
+	public static String ATT_DESCRIPTION_IMAGE = "descriptionImage"; //$NON-NLS-1$
+
+	/**
+	 * Disabled icon attribute. Value <code>disabledIcon</code>.
+	 */
+	public static String ATT_DISABLEDICON = "disabledIcon";//$NON-NLS-1$
+
+	/**
+	 * Editor id attribute. Value <code>editorId</code>.
+	 */
+	public static String ATT_EDITOR_ID = "editorId"; //$NON-NLS-1$
+
+	/**
+	 * Enables-for attribute. Value <code>enablesFor</code>.
+	 */
+	public static String ATT_ENABLES_FOR = "enablesFor"; //$NON-NLS-1$
+
+	/**
+	 * Editor extensions attribute. Value <code>extensions</code>.
+	 */
+	public static String ATT_EXTENSIONS = "extensions";//$NON-NLS-1$
+
+	/**
+	 * Editor filenames attribute. Value <code>filenames</code>.
+	 */
+	public static String ATT_FILENAMES = "filenames";//$NON-NLS-1$
+
+	/**
+	 * Trim fill major attribute. Value <code>fillMajor</code>.
+	 */
+	public static String ATT_FILL_MAJOR = "fillMajor";//$NON-NLS-1$
+
+	/**
+	 * Trim fill minor attribute. Value <code>fillMinor</code>.
+	 */
+	public static String ATT_FILL_MINOR = "fillMinor";//$NON-NLS-1$
+
+	/**
+	 * Perspective fixed attribute. Value <code>fixed</code>.
+	 */
+	public static String ATT_FIXED = "fixed";//$NON-NLS-1$
+
+	/**
+	 * Attribute that specifies whether a wizard has any pages. Value
+	 * <code>hasPages</code>.
+	 */
+	public static String ATT_HAS_PAGES = "hasPages"; //$NON-NLS-1$
+
+	/**
+	 * Help context id attribute. Value <code>helpContextId</code>.
+	 */
+	public static String ATT_HELP_CONTEXT_ID = "helpContextId";//$NON-NLS-1$
+
+	/**
+	 * Help url attribute. Value <code>helpHref</code>.
+	 */
+	public static String ATT_HELP_HREF = "helpHref"; //$NON-NLS-1$
+
+	/**
+	 * Hover icon attribute. Value <code>hoverIcon</code>.
+	 */
+	public static String ATT_HOVERICON = "hoverIcon";//$NON-NLS-1$
+
+	/**
+	 * Icon attribute. Value <code>icon</code>.
+	 */
+	public static String ATT_ICON = "icon"; //$NON-NLS-1$
+
+	/**
+	 * Id attribute. Value <code>id</code>.
+	 */
+	public static String ATT_ID = "id"; //$NON-NLS-1$
+
+	/**
+	 * The name of the image style attribute, which is used on location elements
+	 * in the menus extension point.
+	 */
+	public static String ATT_IMAGE_STYLE = "imageStyle"; //$NON-NLS-1$
+
+	/**
+	 * Is-editable attribute. Value <code>isEditable</code>.
+	 */
+	public static String ATT_IS_EDITABLE = "isEditable"; //$NON-NLS-1$
+
+	/**
+	 * Keys attribute. Value <code>keys</code>.
+	 */
+	public static String ATT_KEY = "key"; //$NON-NLS-1$
+
+	/**
+	 * The name of the attribute storing the identifier for the active key
+	 * configuration identifier. This provides legacy support for the
+	 * <code>activeKeyConfiguration</code> element in the commands extension
+	 * point.
+	 */
+	public static String ATT_KEY_CONFIGURATION_ID = "keyConfigurationId"; //$NON-NLS-1$
+
+	/**
+	 * The name of the attribute storing the trigger sequence for a binding.
+	 * This is called a 'keySequence' for legacy reasons.
+	 */
+	public static String ATT_KEY_SEQUENCE = "keySequence"; //$NON-NLS-1$
+
+	/**
+	 * Label attribute. Value <code>label</code>.
+	 */
+	public static String ATT_LABEL = "label"; //$NON-NLS-1$
+
+	/**
+	 * Editor launcher attribute. Value <code>launcher</code>.
+	 */
+	public static String ATT_LAUNCHER = "launcher";//$NON-NLS-1$
+
+	/**
+	 * Lightweight decorator tag. Value <code>lightweight</code>.
+	 */
+	public static String ATT_LIGHTWEIGHT = "lightweight"; //$NON-NLS-1$
+
+	/**
+	 * The name of the attribute storing the locale for a binding.
+	 */
+	public static String ATT_LOCALE = "locale"; //$NON-NLS-1$
+
+	/**
+	 * Sticky view location attribute. Value <code>location</code>.
+	 */
+	public static String ATT_LOCATION = "location"; //$NON-NLS-1$
+
+	/**
+	 * Editor management strategy attribute. Value <code>matchingStrategy</code>.
+	 */
+	public static String ATT_MATCHING_STRATEGY = "matchingStrategy"; //$NON-NLS-1$
+
+	/**
+	 * The name of the menu identifier attribute, which appears on items.
+	 */
+	public static String ATT_MENU_ID = "menuId"; //$NON-NLS-1$
+
+	/**
+	 * Menubar path attribute. Value <code>menubarPath</code>.
+	 */
+	public static String ATT_MENUBAR_PATH = "menubarPath";//$NON-NLS-1$
+
+	/**
+	 * The name of the mnemonic attribute, which appears on locations.
+	 */
+	public static String ATT_MNEMONIC = "mnemonic"; //$NON-NLS-1$
+
+	/**
+	 * The name of the minimized attribute, which appears
+	 * when adding a view in a perspectiveExtension.
+	 */
+	public static String ATT_MINIMIZED = "minimized"; //$NON-NLS-1$
+
+	/**
+	 * Sticky view moveable attribute. Value <code>moveable</code>.
+	 */
+	public static String ATT_MOVEABLE = "moveable"; //$NON-NLS-1$
+
+	/**
+	 * Name attribute. Value <code>name</code>.
+	 */
+	public static String ATT_NAME = "name"; //$NON-NLS-1$
+
+	/**
+	 * Match type attribute. Value <code>match</code>.
+	 */
+	public static String ATT_MATCH_TYPE = "match"; //$NON-NLS-1$
+
+	/**
+	 * Name filter attribute. Value <code>nameFilter</code>.
+	 */
+	public static String ATT_NAME_FILTER = "nameFilter"; //$NON-NLS-1$
+
+	/**
+	 * Node attribute. Value <code>node</code>.
+	 */
+	public static String ATT_NODE = "node"; //$NON-NLS-1$
+
+	/**
+	 * Object class attribute. Value <code>objectClass</code>.
+	 */
+	public static String ATT_OBJECTCLASS = "objectClass";//$NON-NLS-1$
+
+	/**
+	 * The name of the optional attribute, which appears on parameter
+	 * definitions.
+	 */
+	public static String ATT_OPTIONAL = "optional"; //$NON-NLS-1$
+
+	/**
+	 * Operating system attribute. Value <code>os</code>.
+	 */
+	public static String ATT_OS = "os"; //$NON-NLS-1$
+
+	/**
+	 * The name of the deprecated parent attribute, which appears on scheme
+	 * definitions.
+	 */
+	public static String ATT_PARENT = "parent"; //$NON-NLS-1$
+
+	/**
+	 * View parent category attribute. Value <code>parentCategory</code>.
+	 */
+	public static String ATT_PARENT_CATEGORY = "parentCategory"; //$NON-NLS-1$
+
+	/**
+	 * Parent id attribute. Value <code>parentId</code>.
+	 */
+	public static String ATT_PARENT_ID = "parentId"; //$NON-NLS-1$
+
+	/**
+	 * The name of the deprecated parent scope attribute, which appears on
+	 * contexts definitions.
+	 */
+	public static String ATT_PARENT_SCOPE = "parentScope"; //$NON-NLS-1$
+
+	/**
+	 * Path attribute. Value <code>path</code>.
+	 */
+	public static String ATT_PATH = "path"; //$NON-NLS-1$
+
+	/**
+	 * The name of the attribute storing the platform for a binding.
+	 */
+	public static String ATT_PLATFORM = "platform"; //$NON-NLS-1$
+
+	/**
+	 * The name of the position attribute, which appears on order elements.
+	 */
+	public static String ATT_POSITION = "position"; //$NON-NLS-1$
+
+	/**
+	 * Presentation id attribute. Value <code>presentationId</code>.
+	 */
+	public static String ATT_PRESENTATIONID = "presentationId"; //$NON-NLS-1$
+
+	/**
+	 * Product id attribute. Value <code>productId</code>.
+	 */
+	public static String ATT_PRODUCTID = "productId"; //$NON-NLS-1$
+
+	/**
+	 * Project attribute. Value <code>project</code>.
+	 */
+	// @issue project-specific attribute and behavior
+	public static String ATT_PROJECT = "project";//$NON-NLS-1$	/**
+
+	/**
+	 * The name of the pulldown attribute, which indicates whether the class is
+	 * a pulldown delegate.
+	 */
+	public static String ATT_PULLDOWN = "pulldown"; //$NON-NLS-1$
+
+	/**
+	 * View ratio attribute. Value <code>ratio</code>.
+	 */
+	public static String ATT_RATIO = "ratio"; //$NON-NLS-1$
+
+	/**
+	 * Relationship attribute. Value <code>relationship</code>.
+	 */
+	public static String ATT_RELATIONSHIP = "relationship";//$NON-NLS-1$
+
+	/**
+	 * Relative attribute. Value <code>relative</code>.
+	 */
+	public static String ATT_RELATIVE = "relative";//$NON-NLS-1$
+
+	/**
+	 * The name of the relativeTo attribute, which appears on order elements.
+	 */
+	public static String ATT_RELATIVE_TO = "relativeTo"; //$NON-NLS-1$
+
+	/**
+	 * Retarget attribute. Value <code>retarget</code>.
+	 */
+	public static String ATT_RETARGET = "retarget";//$NON-NLS-1$
+
+	/**
+	 * The name of the returnTypeId attribute, which appears on command
+	 * elements.
+	 */
+	public static String ATT_RETURN_TYPE_ID = "returnTypeId"; //$NON-NLS-1$
+
+	/**
+	 * The name of the attribute storing the identifier for the active scheme.
+	 * This is called a 'keyConfigurationId' for legacy reasons.
+	 */
+	public static String ATT_SCHEME_ID = "schemeId"; //$NON-NLS-1$
+
+	/**
+	 * Scope attribute. Value <code>scope</code>.
+	 */
+	public static String ATT_SCOPE = "scope"; //$NON-NLS-1$
+
+	/**
+	 * The name of the separatorsVisible attribute, which appears on group
+	 * elements.
+	 */
+	public static String ATT_SEPARATORS_VISIBLE = "separatorsVisible"; //$NON-NLS-1$
+
+	/**
+	 * The name of the sequence attribute for a key binding.
+	 */
+	public static String ATT_SEQUENCE = "sequence"; //$NON-NLS-1$
+
+	/**
+	 * Show title attribute. Value <code>showTitle</code>.
+	 */
+	public static String ATT_SHOW_TITLE = "showTitle";//$NON-NLS-1$
+
+	/**
+	 * Perspective singleton attribute. Value <code>singleton</code>.
+	 */
+	public static String ATT_SINGLETON = "singleton";//$NON-NLS-1$
+
+	/**
+	 * Splash id attribute.  Value <code>splashId</code>.
+	 *
+	 * @since 3.3
+	 */
+	public static String ATT_SPLASH_ID = "splashId"; //$NON-NLS-1$
+
+	/**
+	 * Standalone attribute. Value <code>standalone</code>.
+	 */
+	public static String ATT_STANDALONE = "standalone";//$NON-NLS-1$
+
+	/**
+	 * Action state attribute. Value <code>state</code>.
+	 */
+	public static String ATT_STATE = "state";//$NON-NLS-1$
+
+	/**
+	 * The name of the string attribute (key sequence) for a binding in the
+	 * commands extension point.
+	 */
+	public static String ATT_STRING = "string"; //$NON-NLS-1$
+
+	/**
+	 * Action style attribute. Value <code>style</code>.
+	 */
+	public static String ATT_STYLE = "style";//$NON-NLS-1$
+
+	/**
+	 * Target attribute. Value <code>targetID</code>.
+	 */
+	public static String ATT_TARGET_ID = "targetID";//$NON-NLS-1$
+
+	/**
+	 * Toolbar path attribute. Value <code>toolbarPath</code>.
+	 */
+	public static String ATT_TOOLBAR_PATH = "toolbarPath";//$NON-NLS-1$
+
+	/**
+	 * Tooltip attribute. Value <code>tooltip</code>.
+	 */
+	public static String ATT_TOOLTIP = "tooltip";//$NON-NLS-1$
+
+	/**
+	 * The name of the type attribute, which appears on bar elements and
+	 * commandParameterType elments.
+	 */
+	public static String ATT_TYPE = "type"; //$NON-NLS-1$
+
+	/**
+	 * The name of the typeId attribute, which appears on commandParameter
+	 * elements.
+	 */
+	public static String ATT_TYPE_ID = "typeId"; //$NON-NLS-1$
+
+	/**
+	 * Value attribute. Value <code>value</code>.
+	 */
+	public static String ATT_VALUE = "value"; //$NON-NLS-1$
+
+	/**
+	 * Visible attribute. Value <code>visible</code>.
+	 */
+	// ATT_VISIBLE added by dan_rubel@instantiations.com
+	public static String ATT_VISIBLE = "visible";//$NON-NLS-1$
+
+	/**
+	 * Windowing system attribute. Value <code>ws</code>.
+	 */
+	public static String ATT_WS = "ws"; //$NON-NLS-1$
+
+	/**
+	 * The prefix that all auto-generated identifiers start with. This makes the
+	 * identifier recognizable as auto-generated, and further helps ensure that
+	 * it does not conflict with existing identifiers.
+	 */
+	public static String AUTOGENERATED_PREFIX = "AUTOGEN:::"; //$NON-NLS-1$
+
+	/**
+	 * The legacy extension point (2.1.x and earlier) for specifying a key
+	 * binding scheme.
+	 *
+	 * @since 3.1.1
+	 */
+	public static String PL_ACCELERATOR_CONFIGURATIONS = "acceleratorConfigurations"; //$NON-NLS-1$
+
+	/**
+	 * The legacy extension point (2.1.x and earlier) for specifying a context.
+	 *
+	 * @since 3.1.1
+	 */
+	public static String PL_ACCELERATOR_SCOPES = "acceleratorScopes"; //$NON-NLS-1$
+
+	/**
+	 * The legacy extension point (2.1.x and earlier) for specifying a command.
+	 *
+	 * @since 3.1.1
+	 */
+	public static String PL_ACTION_DEFINITIONS = "actionDefinitions"; //$NON-NLS-1$
+
+	public static String PL_ACTION_SET_PART_ASSOCIATIONS = "actionSetPartAssociations"; //$NON-NLS-1$
+
+	public static String PL_ACTION_SETS = "actionSets"; //$NON-NLS-1$
+
+	public static String PL_ACTIVITIES = "activities"; //$NON-NLS-1$
+
+	public static String PL_ACTIVITYSUPPORT = "activitySupport"; //$NON-NLS-1$
+
+	/**
+	 * The extension point (3.1 and later) for specifying bindings, such as
+	 * keyboard shortcuts.
+	 *
+	 * @since 3.1.1
+	 */
+	public static String PL_BINDINGS = "bindings"; //$NON-NLS-1$
+
+	public static String PL_BROWSER_SUPPORT = "browserSupport"; //$NON-NLS-1$
+
+	public static String PL_COLOR_DEFINITIONS = "colorDefinitions"; //$NON-NLS-1$
+
+	/**
+	 * The extension point (3.2 and later) for associating images with commands.
+	 *
+	 * @since 3.2
+	 */
+	public static String PL_COMMAND_IMAGES = "commandImages"; //$NON-NLS-1$
+
+	/**
+	 * The extension point (2.1.x and later) for specifying a command. A lot of
+	 * other things have appeared first in this extension point and then been
+	 * moved to their own extension point.
+	 *
+	 * @since 3.1.1
+	 */
+	public static String PL_COMMANDS = "commands"; //$NON-NLS-1$
+
+	/**
+	 * The extension point (3.0 and later) for specifying a context.
+	 *
+	 * @since 3.1.1
+	 */
+	public static String PL_CONTEXTS = "contexts"; //$NON-NLS-1$
+
+	public static String PL_DECORATORS = "decorators"; //$NON-NLS-1$
+
+	public static String PL_DROP_ACTIONS = "dropActions"; //$NON-NLS-1$
+
+	public static String PL_EDITOR = "editors"; //$NON-NLS-1$
+
+	public static String PL_EDITOR_ACTIONS = "editorActions"; //$NON-NLS-1$
+
+	public static String PL_ELEMENT_FACTORY = "elementFactories"; //$NON-NLS-1$
+
+	/**
+	 * The extension point for encoding definitions.
+	 */
+	public static String PL_ENCODINGS = "encodings"; //$NON-NLS-1$
+
+	public static String PL_EXPORT = "exportWizards"; //$NON-NLS-1$
+
+	public static String PL_FONT_DEFINITIONS = "fontDefinitions"; //$NON-NLS-1$
+
+	/**
+	 * The extension point (3.1 and later) for specifying handlers.
+	 *
+	 * @since 3.1.1
+	 */
+	public static String PL_HANDLERS = "handlers"; //$NON-NLS-1$
+
+	public static String PL_HELPSUPPORT = "helpSupport"; //$NON-NLS-1$
+
+	public static String PL_IMPORT = "importWizards"; //$NON-NLS-1$
+
+	public static String PL_INTRO = "intro"; //$NON-NLS-1$
+
+	/**
+	 * The extension point for keyword definitions.
+	 *
+	 * @since 3.1
+	 */
+	public static String PL_KEYWORDS = "keywords"; //$NON-NLS-1$
+
+	/**
+	 * The extension point (3.2 and later) for specifying menu contributions.
+	 *
+	 * @since 3.2
+	 */
+	public static String PL_MENUS = "menus"; //$NON-NLS-1$
+
+	/**
+	 * The extension point (3.3 and later) for specifying menu contributions.
+	 *
+	 * @since 3.3
+	 */
+	public static String PL_MENU_CONTRIBUTION = "menuContribution"; //$NON-NLS-1$
+
+	public static String PL_NEW = "newWizards"; //$NON-NLS-1$
+
+	public static String PL_PERSPECTIVE_EXTENSIONS = "perspectiveExtensions"; //$NON-NLS-1$
+
+	public static String PL_PERSPECTIVES = "perspectives"; //$NON-NLS-1$
+
+	public static String PL_POPUP_MENU = "popupMenus"; //$NON-NLS-1$
+
+	public static String PL_PREFERENCE_TRANSFER = "preferenceTransfer"; //$NON-NLS-1$
+
+	public static String PL_PREFERENCES = "preferencePages"; //$NON-NLS-1$
+
+	public static String PL_PROPERTY_PAGES = "propertyPages"; //$NON-NLS-1$
+
+	public static String PL_STARTUP = "startup"; //$NON-NLS-1$
+
+	/**
+	 * @since 3.3
+	 */
+	public static String PL_SPLASH_HANDLERS = "splashHandlers"; //$NON-NLS-1$
+
+	public static String PL_SYSTEM_SUMMARY_SECTIONS = "systemSummarySections"; //$NON-NLS-1$
+
+	public static String PL_THEMES = "themes"; //$NON-NLS-1$
+
+	public static String PL_VIEW_ACTIONS = "viewActions"; //$NON-NLS-1$
+
+	public static String PL_VIEWS = "views"; //$NON-NLS-1$
+
+	public static String PL_WORKINGSETS = "workingSets"; //$NON-NLS-1$
+
+	/**
+	 * The name of the deprecated accelerator configurations extension point.
+	 */
+	public static String EXTENSION_ACCELERATOR_CONFIGURATIONS = PlatformUI.PLUGIN_EXTENSION_NAME_SPACE
+			+ '.' + PL_ACCELERATOR_CONFIGURATIONS;
+
+	/**
+	 * The name of the accelerator scopes extension point.
+	 */
+	public static String EXTENSION_ACCELERATOR_SCOPES = PlatformUI.PLUGIN_EXTENSION_NAME_SPACE
+			+ '.' + PL_ACCELERATOR_SCOPES;
+
+	/**
+	 * The name of the action definitions extension point.
+	 */
+	public static String EXTENSION_ACTION_DEFINITIONS = PlatformUI.PLUGIN_EXTENSION_NAME_SPACE
+			+ '.' + PL_ACTION_DEFINITIONS;
+
+	/**
+	 * The name of the <code>org.eclipse.ui.actionSets</code> extension point.
+	 */
+	public static String EXTENSION_ACTION_SETS = PlatformUI.PLUGIN_EXTENSION_NAME_SPACE
+			+ '.' + IWorkbenchRegistryConstants.PL_ACTION_SETS;
+
+	/**
+	 * The name of the bindings extension point.
+	 */
+	public static String EXTENSION_BINDINGS = PlatformUI.PLUGIN_EXTENSION_NAME_SPACE + '.'
+			+ PL_BINDINGS;
+
+	/**
+	 * The name of the commands extension point.
+	 */
+	public static String EXTENSION_COMMAND_IMAGES = PlatformUI.PLUGIN_EXTENSION_NAME_SPACE
+			+ '.' + PL_COMMAND_IMAGES;
+
+	/**
+	 * The name of the commands extension point, and the name of the key for the
+	 * commands preferences.
+	 */
+	public static String EXTENSION_COMMANDS = PlatformUI.PLUGIN_EXTENSION_NAME_SPACE + '.'
+			+ PL_COMMANDS;
+
+	/**
+	 * The name of the contexts extension point.
+	 */
+	public static String EXTENSION_CONTEXTS = PlatformUI.PLUGIN_EXTENSION_NAME_SPACE + '.'
+			+ PL_CONTEXTS;
+
+	/**
+	 * The name of the <code>org.eclipse.ui.editorActions</code> extension
+	 * point.
+	 */
+	public static String EXTENSION_EDITOR_ACTIONS = PlatformUI.PLUGIN_EXTENSION_NAME_SPACE
+			+ '.' + PL_EDITOR_ACTIONS;
+
+	/**
+	 * The name of the commands extension point.
+	 */
+	public static String EXTENSION_HANDLERS = PlatformUI.PLUGIN_EXTENSION_NAME_SPACE + '.'
+			+ PL_HANDLERS;
+
+	/**
+	 * The name of the <code>org.eclipse.ui.menus</code> extension point.
+	 */
+	public static String EXTENSION_MENUS = PlatformUI.PLUGIN_EXTENSION_NAME_SPACE + '.'
+			+ PL_MENUS;
+
+	/**
+	 * The name of the <code>org.eclipse.ui.menus2</code> extension point.
+	 */
+	public static String COMMON_MENU_ADDITIONS = PlatformUI.PLUGIN_ID + '.'
+			+ PL_MENUS + '2';
+
+	/**
+	 * The name of the <code>org.eclipse.ui.popupMenus</code> extension point.
+	 */
+	public static String EXTENSION_POPUP_MENUS = PlatformUI.PLUGIN_ID
+			+ '.' + PL_POPUP_MENU;
+
+	/**
+	 * The name of the <code>org.eclipse.ui.viewActions</code> extension
+	 * point.
+	 */
+	public static String EXTENSION_VIEW_ACTIONS = PlatformUI.PLUGIN_ID
+			+ '.' + PL_VIEW_ACTIONS;
+
+	/**
+	 * The constant for the position attribute corresponding to
+	 * {@link SOrder#POSITION_AFTER}.
+	 */
+	public static String POSITION_AFTER = "after"; //$NON-NLS-1$
+
+	/**
+	 * The constant for the position attribute corresponding to
+	 * {@link SOrder#POSITION_BEFORE}.
+	 */
+	public static String POSITION_BEFORE = "before"; //$NON-NLS-1$
+
+	/**
+	 * The constant for the position attribute corresponding to
+	 * {@link SOrder#POSITION_END}.
+	 */
+	public static String POSITION_END = "end"; //$NON-NLS-1$
+
+	/**
+	 * The constant for the position attribute corresponding to
+	 * {@link SOrder#POSITION_START}.
+	 */
+	public static String POSITION_START = "start"; //$NON-NLS-1$
+
+	/**
+	 * The action style for drop-down menus.
+	 */
+	public static String STYLE_PULLDOWN = "pulldown"; //$NON-NLS-1$
+
+	/**
+	 * The action style for radio buttons.
+	 */
+	public static String STYLE_RADIO = "radio"; //$NON-NLS-1$
+
+	/**
+	 * The action style for check boxes.
+	 */
+	public static String STYLE_TOGGLE = "toggle"; //$NON-NLS-1$
+
+	/**
+	 * The name of the deprecated accelerator configuration element. This
+	 * element was used in 2.1.x and earlier to define groups of what are now
+	 * called schemes.
+	 */
+	public static String TAG_ACCELERATOR_CONFIGURATION = "acceleratorConfiguration"; //$NON-NLS-1$
+
+	/**
+	 * The name of the element storing a deprecated accelerator scope.
+	 */
+	public static String TAG_ACCELERATOR_SCOPE = "acceleratorScope"; //$NON-NLS-1$
+
+	/**
+	 * Action tag. Value <code>action</code>.
+	 */
+	public static String TAG_ACTION = "action"; //$NON-NLS-1$
+
+	/**
+	 * The name of the element storing an action definition. This element only
+	 * existed in
+	 */
+	public static String TAG_ACTION_DEFINITION = "actionDefinition"; //$NON-NLS-1$
+
+	/**
+	 * Action set tag. Value <code>actionSet</code>.
+	 */
+	public static String TAG_ACTION_SET = "actionSet";//$NON-NLS-1$
+
+	/**
+	 * Part association tag. Value <code>actionSetPartAssociation</code>.
+	 */
+	public static String TAG_ACTION_SET_PART_ASSOCIATION = "actionSetPartAssociation";//$NON-NLS-1$
+
+	/**
+	 * The name of the element storing the active key configuration from the
+	 * commands extension point.
+	 */
+	public static String TAG_ACTIVE_KEY_CONFIGURATION = "activeKeyConfiguration"; //$NON-NLS-1$
+
+	public static String TAG_SEQUENCE_MODIFIER = "sequenceModifier"; //$NON-NLS-1$
+
+	/**
+	 * The name of the active when element, which appears on a handler
+	 * definition.
+	 */
+	public static String TAG_ACTIVE_WHEN = "activeWhen"; //$NON-NLS-1$
+
+	/**
+	 * Activity image binding tag. Value <code>activityImageBindingw</code>.
+	 */
+	public static String TAG_ACTIVITY_IMAGE_BINDING = "activityImageBinding"; //$NON-NLS-1$
+
+	/**
+	 * Advisor to product binding element. Value
+	 * <code>triggerPointAdvisorProductBinding</code>.
+	 */
+	public static String TAG_ADVISORPRODUCTBINDING = "triggerPointAdvisorProductBinding"; //$NON-NLS-1$
+
+	/**
+	 * The name of the bar element, which appears in a location definition.
+	 */
+	public static String TAG_BAR = "bar"; //$NON-NLS-1$
+
+	/**
+	 * Category tag. Value <code>category</code>.
+	 */
+	public static String TAG_CATEGORY = "category";//$NON-NLS-1$
+
+	/**
+	 * Category image binding tag. Value <code>categoryImageBinding</code>.
+	 */
+	public static String TAG_CATEGORY_IMAGE_BINDING = "categoryImageBinding"; //$NON-NLS-1$
+
+	/**
+	 * Element category tag. Value <code>themeElementCategory</code>.
+	 */
+	public static String TAG_CATEGORYDEFINITION = "themeElementCategory"; //$NON-NLS-1$
+
+	/**
+	 * Category presentation tag. Value <code>categoryPresentationBinding</code>
+	 * .
+	 *
+	 * @deprecated used by the removal presentation API
+	 */
+	@Deprecated
+	public static String TAG_CATEGORYPRESENTATIONBINDING = "categoryPresentationBinding"; //$NON-NLS-1$
+
+	/**
+	 * The name of the class element, which appears on an executable extension.
+	 */
+	public static String TAG_CLASS = ATT_CLASS;
+
+	/**
+	 * Color definition tag. Value <code>colorDefinition</code>.
+	 */
+	public static String TAG_COLORDEFINITION = "colorDefinition"; //$NON-NLS-1$
+
+	/**
+	 * Color override tag. Value <code>colorOverride</code>.
+	 */
+	public static String TAG_COLOROVERRIDE = "colorOverride"; //$NON-NLS-1$
+
+	/**
+	 * Color value tag. Value <code>colorValue</code>.
+	 */
+	public static String TAG_COLORVALUE = "colorValue"; //$NON-NLS-1$
+
+	/**
+	 * The name of the element storing a command.
+	 */
+	public static String TAG_COMMAND = "command"; //$NON-NLS-1$
+
+	/**
+	 * The name of the element storing a parameter.
+	 */
+	public static String TAG_COMMAND_PARAMETER = "commandParameter"; //$NON-NLS-1$
+
+	/**
+	 * The name of the element storing a parameter type.
+	 */
+	public static String TAG_COMMAND_PARAMETER_TYPE = "commandParameterType"; //$NON-NLS-1$
+
+	/**
+	 * Editor content type binding tag. Value <code>contentTypeBinding</code>.
+	 */
+	public static String TAG_CONTENT_TYPE_BINDING = "contentTypeBinding"; //$NON-NLS-1$
+
+	/**
+	 * The name of the element storing a context.
+	 */
+	public static String TAG_CONTEXT = "context"; //$NON-NLS-1$
+
+	/**
+	 * Data tag. Value <code>data</code>.
+	 */
+	public static String TAG_DATA = "data"; //$NON-NLS-1$
+
+	/**
+	 * The name of the default handler element, which appears on a command
+	 * definition.
+	 */
+	public static String TAG_DEFAULT_HANDLER = ATT_DEFAULT_HANDLER;
+
+	/**
+	 * Description element. Value <code>description</code>.
+	 */
+	public static String TAG_DESCRIPTION = "description"; //$NON-NLS-1$
+
+	/**
+	 * The name of the dynamic menu element, which appears in a group or menu
+	 * definition.
+	 */
+	public static String TAG_DYNAMIC = "dynamic"; //$NON-NLS-1$
+
+	/**
+	 * Editor tag. Value <code>editor</code>.
+	 */
+	public static String TAG_EDITOR = "editor";//$NON-NLS-1$
+
+	/**
+	 * Editor tag. Value <code>editor</code>.
+	 */
+	public static String TAG_EDITOR_CONTENT_TYPTE_BINDING = "editorContentTypeBinding";//$NON-NLS-1$
+
+	/**
+	 * The name of the deprecated editorContribution element. This is used for
+	 * contributing actions to the top-level menus and tool bars when particular
+	 * editors are visible.
+	 */
+	public static String TAG_EDITOR_CONTRIBUTION = "editorContribution"; //$NON-NLS-1$
+
+	/**
+	 * The name of the enabled when element, which appears on a handler
+	 * definition.
+	 */
+	public static String TAG_ENABLED_WHEN = "enabledWhen"; //$NON-NLS-1$
+
+	/**
+	 * Enablement tag. Value <code>enablement</code>.
+	 */
+	public static String TAG_ENABLEMENT = "enablement"; //$NON-NLS-1$
+
+	/**
+	 * Entry tag. Value <code>entry</code>.
+	 */
+	public static String TAG_ENTRY = "entry"; //$NON-NLS-1$
+
+	/**
+	 * Filter tag. Value <code>filter</code>.
+	 */
+	public static String TAG_FILTER = "filter"; //$NON-NLS-1$
+
+	/***************************************************************************
+	 * Font definition tag. Value <code>fontDefinition</code>.
+	 */
+	public static String TAG_FONTDEFINITION = "fontDefinition"; //$NON-NLS-1$
+
+	/**
+	 * Font override tag. Value <code>fontOverride</code>.
+	 */
+	public static String TAG_FONTOVERRIDE = "fontOverride"; //$NON-NLS-1$
+
+	/**
+	 * Font value tag. Value <code>fontValue</code>.
+	 */
+	public static String TAG_FONTVALUE = "fontValue"; //$NON-NLS-1$
+
+	/**
+	 * The name of the element storing a group.
+	 */
+	public static String TAG_GROUP = "group"; //$NON-NLS-1$
+
+	/**
+	 * Group marker tag. Value <code>groupMarker</code>.
+	 */
+	public static String TAG_GROUP_MARKER = "groupMarker"; //$NON-NLS-1$
+
+	/**
+	 * The name of the element storing a handler.
+	 */
+	public static String TAG_HANDLER = "handler"; //$NON-NLS-1$
+
+	/**
+	 * The name of the element storing a handler submission.
+	 */
+	public static String TAG_HANDLER_SUBMISSION = "handlerSubmission"; //$NON-NLS-1$
+
+	/**
+	 * The name of the element storing the id of a menu item to hide
+	 */
+	public static String TAG_HIDDEN_MENU_ITEM = "hiddenMenuItem"; //$NON-NLS-1$
+
+	/**
+	 * The name of the element storing the id of a toolbar item to hide
+	 */
+	public static String TAG_HIDDEN_TOOLBAR_ITEM = "hiddenToolBarItem"; //$NON-NLS-1$
+
+	/**
+	 * Trigger point hint tag. Value <code>hint</code>.
+	 */
+	public static String TAG_HINT = "hint"; //$NON-NLS-1$
+
+	/**
+	 * The name of the element storing an image.
+	 */
+	public static String TAG_IMAGE = "image"; //$NON-NLS-1$
+
+	/**
+	 * The name of the element storing a key binding.
+	 */
+	public static String TAG_KEY = "key"; //$NON-NLS-1$
+
+	/**
+	 * The name of the key binding element in the commands extension point.
+	 */
+	public static String TAG_KEY_BINDING = "keyBinding"; //$NON-NLS-1$
+
+	/**
+	 * The name of the deprecated key configuration element in the commands
+	 * extension point. This element has been replaced with the scheme element
+	 * in the bindings extension point.
+	 */
+	public static String TAG_KEY_CONFIGURATION = "keyConfiguration"; //$NON-NLS-1$
+
+	/**
+	 * The name of the element storing a location.
+	 */
+	public static String TAG_LOCATION = "location"; //$NON-NLS-1$
+
+	/**
+	 * The name of the element defining the insertion point for menu
+	 * additions.
+	 *
+	 * @since 3.3
+	 */
+	public static String TAG_LOCATION_URI = "locationURI"; //$NON-NLS-1$
+
+	/**
+	 * The name of the element storing trim layout info for a widget.
+	 */
+	public static String TAG_LAYOUT = "layout"; //$NON-NLS-1$
+
+	/**
+	 * Mapping tag. Value <code>mapping</code>.
+	 */
+	public static String TAG_MAPPING = "mapping"; //$NON-NLS-1$
+
+	/**
+	 * Menu tag. Value <code>menu</code>.
+	 */
+	public static String TAG_MENU = "menu"; //$NON-NLS-1$
+
+	/**
+	 * Wizard shortcut tag. Value <code>newWizardShortcut</code>.
+	 */
+	public static String TAG_NEW_WIZARD_SHORTCUT = "newWizardShortcut";//$NON-NLS-1$
+
+	/**
+	 * Object contribution tag. Value <code>objectContribution</code>.
+	 */
+	public static String TAG_OBJECT_CONTRIBUTION = "objectContribution";//$NON-NLS-1$
+
+	/**
+	 * The name of the element storing the ordering information.
+	 */
+	public static String TAG_ORDER = "order"; //$NON-NLS-1$
+
+	/**
+	 * The name of the element storing a parameter.
+	 */
+	public static String TAG_PARAMETER = "parameter"; //$NON-NLS-1$
+
+	/**
+	 * Part tag. Value <code>part</code>.
+	 */
+	public static String TAG_PART = "part";//$NON-NLS-1$
+
+	/**
+	 * Perspective shortcut tag. Value <code>perspectiveShortcut</code>.
+	 */
+	public static String TAG_PERSP_SHORTCUT = "perspectiveShortcut";//$NON-NLS-1$
+
+	/**
+	 * Perspective tag. Value <code>perspective</code>.
+	 */
+	public static String TAG_PERSPECTIVE = "perspective";//$NON-NLS-1$
+
+	/**
+	 * Perspective extension tag. Value <code>perspectiveExtension</code>.
+	 */
+	public static String TAG_PERSPECTIVE_EXTENSION = "perspectiveExtension";//$NON-NLS-1$
+
+	/**
+	 * Primary wizard tag. Value <code>primaryWizard</code>.
+	 */
+	public static String TAG_PRIMARYWIZARD = "primaryWizard"; //$NON-NLS-1$
+
+	/**
+	 * The name of the element storing the a menu element reference.
+	 */
+	public static String TAG_REFERENCE = "reference"; //$NON-NLS-1$
+
+	/**
+	 * The name of the scheme element in the bindings extension point.
+	 */
+	public static String TAG_SCHEME = "scheme"; //$NON-NLS-1$
+
+	/**
+	 * The name of the element storing a deprecated scope.
+	 */
+	public static String TAG_SCOPE = "scope"; //$NON-NLS-1$
+
+	/**
+	 * Selectiont tag. Value <code>selection</code>.
+	 */
+	public static String TAG_SELECTION = "selection"; //$NON-NLS-1$
+
+	/**
+	 * Separator tag. Value <code>separator</code>.
+	 */
+	public static String TAG_SEPARATOR = "separator"; //$NON-NLS-1$
+
+
+	/**
+	 * Tag for the settings transfer entry.
+	 */
+	public static String TAG_SETTINGS_TRANSFER = "settingsTransfer"; //$NON-NLS-1$
+
+	/**
+	 * Show in part tag. Value <code>showInPart</code>.
+	 */
+	public static String TAG_SHOW_IN_PART = "showInPart";//$NON-NLS-1$
+
+	/**
+	 * The name of the element storing some state.
+	 */
+	public static String TAG_STATE = "state"; //$NON-NLS-1$
+
+	/**
+	 * The name of the element describing splash handlers. Value
+	 * <code>splashHandler</code>.
+	 * @since 3.3
+	 */
+	public static String TAG_SPLASH_HANDLER = "splashHandler"; //$NON-NLS-1$
+
+
+	/**
+	 * The name of the element describing splash handler product bindings. Value
+	 * <code>splashHandlerProductBinding</code>.
+	 * @since 3.3
+	 */
+	public static String TAG_SPLASH_HANDLER_PRODUCT_BINDING = "splashHandlerProductBinding"; //$NON-NLS-1$
+
+	/**
+	 * Sticky view tag. Value <code>stickyView</code>.
+	 */
+	public static String TAG_STICKYVIEW = "stickyView";//$NON-NLS-1$
+
+	/**
+	 * Browser support tag. Value <code>support</code>.
+	 */
+	public static String TAG_SUPPORT = "support"; //$NON-NLS-1$
+
+	/**
+	 * Theme tag. Value <code>theme</code>.
+	 */
+	public static String TAG_THEME = "theme";//$NON-NLS-1$
+
+	/**
+	 * Transfer tag. Value <code>transfer</code>.
+	 */
+	public static String TAG_TRANSFER = "transfer";//$NON-NLS-1$
+
+	/**
+	 * Trigger point tag. Value <code>triggerPoint</code>.
+	 */
+	public static String TAG_TRIGGERPOINT = "triggerPoint"; //$NON-NLS-1$
+
+	/**
+	 * Advisor tag. Value <code>triggerPointAdvisor</code>.
+	 */
+	public static String TAG_TRIGGERPOINTADVISOR = "triggerPointAdvisor"; //$NON-NLS-1$
+
+	/**
+	 * View tag. Value <code>view</code>.
+	 */
+	public static String TAG_VIEW = "view";//$NON-NLS-1$
+
+	/**
+	 * E4 view tag, used in the <code>org.eclipse.ui.view</code> extension point
+	 * to point to a POJO class. Value <code>e4view</code>.
+	 */
+	public static String TAG_E4VIEW = "e4view";//$NON-NLS-1$
+
+	/**
+	 * View shortcut tag. Value <code>viewShortcut</code>.
+	 */
+	public static String TAG_VIEW_SHORTCUT = "viewShortcut";//$NON-NLS-1$
+
+	/**
+	 * The name of the element storing a view contribution.
+	 */
+	public static String TAG_VIEW_CONTRIBUTION = "viewContribution"; //$NON-NLS-1$
+
+	/**
+	 * Viewer contribution tag. Value <code>viewerContribution</code>.
+	 */
+	public static String TAG_VIEWER_CONTRIBUTION = "viewerContribution"; //$NON-NLS-1$
+
+	/**
+	 * Visibility tag. Value <code>visibility</code>.
+	 */
+	public static String TAG_VISIBILITY = "visibility"; //$NON-NLS-1$
+
+	/**
+	 * The name of the element storing the visible when condition.
+	 */
+	public static String TAG_VISIBLE_WHEN = "visibleWhen"; //$NON-NLS-1$
+
+	/**
+	 * The name of the element storing a widget.
+	 */
+	public static String TAG_WIDGET = "widget"; //$NON-NLS-1$
+
+	/**
+	 * The name of the element storing a control hosted in a ToolBar.
+	 */
+	public static String TAG_CONTROL = "control"; //$NON-NLS-1$
+
+	/**
+	 * Wizard tag. Value <code>wizard</code>.
+	 */
+	public static String TAG_WIZARD = "wizard";//$NON-NLS-1$
+
+	/**
+	 * Working set tag. Value <code>workingSet</code>.
+	 */
+	public static String TAG_WORKING_SET = "workingSet"; //$NON-NLS-1$
+
+	/**
+	 * The type of reference which refers to a group.
+	 */
+	public static String TYPE_GROUP = "group"; //$NON-NLS-1$
+
+	/**
+	 * The type of reference which refers to an item.
+	 */
+	public static String TYPE_ITEM = "item"; //$NON-NLS-1$
+
+	/**
+	 * The type of reference which refers to an menu.
+	 */
+	public static String TYPE_MENU = "menu"; //$NON-NLS-1$
+
+	/**
+	 * The type of reference which refers to the widget.
+	 */
+	public static String TYPE_WIDGET = "widget"; //$NON-NLS-1$
+
+	public static String TAG_TOOLBAR = "toolbar"; //$NON-NLS-1$
+
+	public static String TAG_SERVICE_FACTORY = "serviceFactory"; //$NON-NLS-1$
+
+	public static String TAG_SERVICE = "service"; //$NON-NLS-1$
+
+	public static final String ATTR_FACTORY_CLASS = "factoryClass"; //$NON-NLS-1$
+
+	public static final String ATTR_SERVICE_CLASS = "serviceClass"; //$NON-NLS-1$
+
+	public static final String TAG_SOURCE_PROVIDER = "sourceProvider"; //$NON-NLS-1$
+
+	public static final String ATTR_PROVIDER = "provider"; //$NON-NLS-1$
+
+	public static final String TAG_VARIABLE = "variable"; //$NON-NLS-1$
+
+	public static final String ATT_PRIORITY_LEVEL = "priorityLevel"; //$NON-NLS-1$
+
+	public static final String ATT_MODE = "mode"; //$NON-NLS-1$
+
+	public static final String ATT_PLATFORMS = "platforms"; //$NON-NLS-1$
+
+	public static final String ATT_REPLACE = "replace"; //$NON-NLS-1$
+
+	public static final String ATT_FIND = "find"; //$NON-NLS-1$
+
+	public static final String TAG_KEYWORD_REFERENCE = "keywordReference"; //$NON-NLS-1$
+
+	public static final String ATT_THEME_ASSOCIATION = "themeAssociation"; //$NON-NLS-1$
+
+	public static final String ATT_THEME_ID = "themeId"; //$NON-NLS-1$
+
+	public static final String ATT_COLOR_AND_FONT_ID = "colorAndFontId"; //$NON-NLS-1$
+
+	public static final String ATT_OS_VERSION = "os_version"; //$NON-NLS-1$
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/ImportExportPespectiveHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/ImportExportPespectiveHandler.java
new file mode 100644
index 0000000..3f9d1f8
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/ImportExportPespectiveHandler.java
@@ -0,0 +1,324 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.ui.internal.registry;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent;
+import org.eclipse.e4.core.contexts.ContextInjectionFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.di.extensions.Preference;
+import org.eclipse.e4.core.services.events.IEventBroker;
+import org.eclipse.e4.core.services.log.Logger;
+import org.eclipse.e4.ui.internal.workbench.E4XMIResourceFactory;
+import org.eclipse.e4.ui.model.application.MAddon;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.ui.MUIElement;
+import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective;
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.WorkbenchException;
+import org.eclipse.ui.XMLMemento;
+import org.eclipse.ui.internal.e4.compatibility.ModeledPageLayout;
+import org.eclipse.ui.internal.e4.migration.PerspectiveBuilder;
+import org.eclipse.ui.internal.e4.migration.PerspectiveReader;
+import org.eclipse.ui.internal.wizards.preferences.PreferencesExportWizard;
+import org.eclipse.ui.internal.wizards.preferences.PreferencesImportWizard;
+import org.osgi.service.event.EventHandler;
+
+@SuppressWarnings("restriction")
+public class ImportExportPespectiveHandler {
+
+	private static final String PERSPECTIVE_SUFFIX_4X = "_e4persp"; //$NON-NLS-1$
+
+	private static final String PERSPECTIVE_SUFFIX_3X = "_persp"; //$NON-NLS-1$
+
+	private static final String ASCII_ENCODING = "ASCII"; //$NON-NLS-1$
+
+	private static final String TRIMS_KEY = "trims"; //$NON-NLS-1$
+
+	@Inject
+	private EModelService modelService;
+
+	@Inject
+	private MApplication application;
+
+	@Inject
+	private IEventBroker eventBroker;
+
+	@Inject
+	private Logger logger;
+
+	@Inject @Preference(nodePath="org.eclipse.ui.workbench")
+	private IEclipsePreferences preferences;
+
+	@Inject
+	private IEclipseContext context;
+
+	@Inject
+	private PerspectiveRegistry perspectiveRegistry;
+
+	private EventHandler importPreferencesEnd;
+	private EventHandler exportPreferencesBegin;
+	private EventHandler exportPreferencesEnd;
+	private IPreferenceChangeListener preferenceListener;
+	private boolean ignoreEvents;
+
+	private List<MPerspective> exportedPersps = new ArrayList<>();
+	private List<String> importedPersps = new ArrayList<>();
+	private Map<String, String> minMaxPersistedState;
+
+	@PostConstruct
+	private void init() {
+		initializeEventHandlers();
+		preferences.addPreferenceChangeListener(preferenceListener);
+		eventBroker.subscribe(PreferencesExportWizard.EVENT_EXPORT_BEGIN, exportPreferencesBegin);
+		eventBroker.subscribe(PreferencesExportWizard.EVENT_EXPORT_END, exportPreferencesEnd);
+		eventBroker.subscribe(PreferencesImportWizard.EVENT_IMPORT_END, importPreferencesEnd);
+	}
+
+	@PreDestroy
+	private void dispose() {
+		preferences.removePreferenceChangeListener(preferenceListener);
+		eventBroker.unsubscribe(exportPreferencesBegin);
+		eventBroker.unsubscribe(exportPreferencesEnd);
+		eventBroker.unsubscribe(importPreferencesEnd);
+	}
+
+	private void importPerspective4x(PreferenceChangeEvent event) {
+		importedPersps.add(event.getKey());
+		MPerspective perspective = null;
+		try {
+			perspective = perspFromString((String) event.getNewValue());
+			addShowInTags(perspective);
+		} catch (IOException e) {
+			logError(event, e);
+		}
+		addPerspectiveToWorkbench(perspective);
+	}
+
+	private void addShowInTags(MPerspective perspective) {
+		if (perspective != null) {
+			String targetId = getOriginalId(perspective.getElementId());
+			ArrayList<String> showInTags = PerspectiveBuilder.getShowInPartFromRegistry(targetId);
+			if (showInTags != null) {
+				List<String> newTags = new ArrayList<>();
+				for (String showIn : showInTags) {
+					newTags.add(ModeledPageLayout.SHOW_IN_PART_TAG + showIn);
+				}
+				perspective.getTags().addAll(newTags);
+			}
+		}
+	}
+
+	private String getOriginalId(String id) {
+		int index = id.lastIndexOf('.');
+		if (index == -1)
+			return id;
+		return id.substring(0, index);
+	}
+
+	private void importPerspective3x(PreferenceChangeEvent event) {
+		importedPersps.add(event.getKey());
+		StringReader reader = new StringReader((String) event.getNewValue());
+		MPerspective perspective = null;
+		IEclipseContext childContext = context.createChild();
+		try {
+			childContext.set(PerspectiveReader.class, new PerspectiveReader(XMLMemento.createReadRoot(reader)));
+			perspective = ContextInjectionFactory.make(PerspectiveBuilder.class, childContext).createPerspective();
+		} catch (WorkbenchException e) {
+			logError(event, e);
+		} finally {
+			reader.close();
+			childContext.dispose();
+		}
+		addPerspectiveToWorkbench(perspective);
+	}
+
+	private void addPerspectiveToWorkbench(MPerspective perspective) {
+		if (perspective == null) {
+			return;
+		}
+
+		IPerspectiveDescriptor perspToOverwrite = perspectiveRegistry.findPerspectiveWithLabel(perspective.getLabel());
+
+		// a new perspective
+		if (perspToOverwrite == null) {
+			perspectiveRegistry.addPerspective(perspective);
+			importToolbarsLocation(perspective);
+			return;
+		}
+
+		String perspToOverwriteId = perspToOverwrite.getId();
+		// a perspective with the same label exists, but has different ID
+		if (!perspective.getElementId().equals(perspToOverwriteId)) {
+			perspective.setElementId(perspToOverwriteId);
+		}
+		perspectiveRegistry.deletePerspective(perspToOverwrite);
+		perspectiveRegistry.addPerspective(perspective);
+		importToolbarsLocation(perspective);
+	}
+
+	private void logError(PreferenceChangeEvent event, Exception e) {
+		logger.error(e, String.format("Cannot read perspective \"%s\" from preferences", event.getKey())); //$NON-NLS-1$
+	}
+
+	private void copyPerspToPreferences(MPerspective persp) throws IOException {
+		MPerspective perspClone = (MPerspective) modelService.cloneElement(persp, null);
+		exportToolbarsLocation(perspClone);
+		String perspAsString = perspToString(perspClone);
+		preferences.put(perspClone.getLabel() + PERSPECTIVE_SUFFIX_4X, perspAsString);
+	}
+
+	private void exportToolbarsLocation(MPerspective persp) {
+		Map<String, String> minMaxPersState = getMinMaxPersistedState();
+		if (minMaxPersState == null) {
+			return;
+		}
+		String trimsData = minMaxPersState.get(persp.getElementId());
+		persp.getPersistedState().put(TRIMS_KEY, trimsData);
+	}
+
+	private void importToolbarsLocation(MPerspective persp) {
+		String trimsData = persp.getPersistedState().get(TRIMS_KEY);
+		if (trimsData == null || trimsData.trim().isEmpty()) {
+			return;
+		}
+		persp.getPersistedState().remove(TRIMS_KEY);
+		Map<String, String> minMaxPersState = getMinMaxPersistedState();
+		if (minMaxPersState == null) {
+			return;
+		}
+		minMaxPersState.put(persp.getElementId(), trimsData);
+	}
+
+	private Map<String, String> getMinMaxPersistedState() {
+		if (minMaxPersistedState != null) {
+			return minMaxPersistedState;
+		}
+		for (MAddon addon : application.getAddons()) {
+			if ("MinMax Addon".equals(addon.getElementId())) { //$NON-NLS-1$
+				minMaxPersistedState = addon.getPersistedState();
+				break;
+			}
+		}
+		return minMaxPersistedState;
+	}
+
+	private String perspToString(MPerspective persp) throws IOException {
+		Resource resource = new E4XMIResourceFactory().createResource(null);
+		resource.getContents().add((EObject) persp);
+		ByteArrayOutputStream output = new ByteArrayOutputStream();
+		try {
+			resource.save(output, null);
+		} finally {
+			try {
+				output.close();
+			} catch (IOException e) {
+				logger.error(e, "Cannot close output stream"); //$NON-NLS-1$
+			}
+		}
+		resource.getContents().clear();
+		return new String(output.toByteArray(), ASCII_ENCODING);
+	}
+
+	private MPerspective perspFromString(String perspAsString) throws IOException {
+		Resource resource = new E4XMIResourceFactory().createResource(null);
+		InputStream input = new ByteArrayInputStream(perspAsString.getBytes(ASCII_ENCODING));
+		try {
+			resource.load(input, null);
+		} finally {
+			try {
+				input.close();
+			} catch (IOException e) {
+				logger.error(e, "Cannot close input stream"); //$NON-NLS-1$
+			}
+		}
+		MPerspective perspective = (MPerspective) resource.getContents().get(0);
+		resource.getContents().clear();
+		return perspective;
+	}
+
+	private void copyPerspsToPreferences() {
+		for (MUIElement snippet : application.getSnippets()) {
+			if (snippet instanceof MPerspective) {
+				MPerspective persp = (MPerspective) snippet;
+				exportedPersps.add(persp);
+			}
+		}
+		ignoreEvents = true;
+		for (MPerspective persp : exportedPersps) {
+			try {
+				copyPerspToPreferences(persp);
+			} catch (IOException e) {
+				logger.error(e, String.format("Cannot save perspective \"%s\" to preferences", persp.getElementId())); //$NON-NLS-1$
+			}
+		}
+		ignoreEvents = false;
+	}
+
+	private void removeExportedPreferences() {
+		ignoreEvents = true;
+		for (MPerspective persp : exportedPersps) {
+			preferences.remove(persp.getLabel() + PERSPECTIVE_SUFFIX_4X);
+		}
+		ignoreEvents = false;
+		exportedPersps.clear();
+	}
+
+	private void removeImportedPreferences() {
+		ignoreEvents = true;
+		for (String key : importedPersps) {
+			preferences.remove(key);
+		}
+		ignoreEvents = false;
+		importedPersps.clear();
+
+		// remove unused preference imported from Eclipse 3.x
+		preferences.remove("perspectives"); //$NON-NLS-1$
+	}
+
+	private void initializeEventHandlers() {
+
+		importPreferencesEnd = event -> removeImportedPreferences();
+
+		exportPreferencesBegin = event -> copyPerspsToPreferences();
+
+		exportPreferencesEnd = event -> removeExportedPreferences();
+
+		preferenceListener = event -> {
+			if (ignoreEvents) {
+				return;
+			}
+
+			if (event.getKey().endsWith(PERSPECTIVE_SUFFIX_4X)) {
+				importPerspective4x(event);
+			} else if (event.getKey().endsWith(PERSPECTIVE_SUFFIX_3X)) {
+				importPerspective3x(event);
+			}
+		};
+
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/KeywordRegistry.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/KeywordRegistry.java
new file mode 100644
index 0000000..6521553
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/KeywordRegistry.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.registry;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.dynamichelpers.ExtensionTracker;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * Contains extensions defined on the <code>keywords</code> extension point.
+ *
+ * @since 3.1
+ */
+public final class KeywordRegistry implements IExtensionChangeHandler {
+
+	private static final String ATT_ID = "id"; //$NON-NLS-1$
+
+	private static final String ATT_LABEL = "label"; //$NON-NLS-1$
+
+	private static KeywordRegistry instance;
+
+	private static final String TAG_KEYWORD = "keyword"; //$NON-NLS-1$
+
+	/**
+	 * Return the singleton instance of the <code>KeywordRegistry</code>.
+	 *
+	 * @return the singleton registry
+	 */
+	public static KeywordRegistry getInstance() {
+		if (instance == null) {
+			instance = new KeywordRegistry();
+		}
+
+		return instance;
+	}
+
+	/**
+	 * Map of id->labels.
+	 */
+	private Map internalKeywordMap = new HashMap();
+
+	/**
+	 * Private constructor.
+	 */
+	private KeywordRegistry() {
+		IExtensionTracker tracker = PlatformUI.getWorkbench().getExtensionTracker();
+        tracker.registerHandler(this, ExtensionTracker.createExtensionPointFilter(getExtensionPointFilter()));
+		for (IExtension extension : getExtensionPointFilter().getExtensions()) {
+			addExtension(PlatformUI.getWorkbench().getExtensionTracker(), extension);
+		}
+	}
+
+	@Override
+	public void addExtension(IExtensionTracker tracker, IExtension extension) {
+		for (IConfigurationElement element : extension.getConfigurationElements()) {
+			if (element.getName().equals(TAG_KEYWORD)) {
+				String name = element.getAttribute(ATT_LABEL);
+				String id = element.getAttribute(ATT_ID);
+				internalKeywordMap.put(id, name);
+				PlatformUI.getWorkbench().getExtensionTracker().registerObject(
+						extension, id, IExtensionTracker.REF_WEAK);
+			}
+		}
+	}
+
+	private IExtensionPoint getExtensionPointFilter() {
+		return Platform.getExtensionRegistry().getExtensionPoint(
+				PlatformUI.PLUGIN_EXTENSION_NAME_SPACE, IWorkbenchRegistryConstants.PL_KEYWORDS);
+	}
+
+	/**
+	 * Return the label associated with the given keyword.
+	 *
+	 * @param id the keyword id
+	 * @return the label or <code>null</code>
+	 */
+	public String getKeywordLabel(String id) {
+		return (String) internalKeywordMap.get(id);
+	}
+
+	@Override
+	public void removeExtension(IExtension extension, Object[] objects) {
+		for (Object object : objects) {
+			if (object instanceof String) {
+				internalKeywordMap.remove(object);
+			}
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/PerspectiveDescriptor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/PerspectiveDescriptor.java
new file mode 100644
index 0000000..0b2b873
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/PerspectiveDescriptor.java
@@ -0,0 +1,186 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012, 2015 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
+ *     Brock Janiczak (brockj_eclipse@ihug.com.au) - handler registration
+ *     Dirk Fauth <dirk.fauth@googlemail.com> - Bug 473063
+ *******************************************************************************/
+package org.eclipse.ui.internal.registry;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.IPerspectiveFactory;
+import org.eclipse.ui.IPluginContribution;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+/**
+ * PerspectiveDescriptor.
+ * <p>
+ * A PerspectiveDesciptor has 3 states:
+ * </p>
+ * <ol>
+ * <li>It <code>isPredefined()</code>, in which case it was defined from an
+ * extension point.</li>
+ * <li>It <code>isPredefined()</code> and <code>hasCustomFile</code>, in
+ * which case the user has customized a predefined perspective.</li>
+ * <li>It <code>hasCustomFile</code>, in which case the user created a new
+ * perspective.</li>
+ * </ol>
+ *
+ */
+public class PerspectiveDescriptor implements IPerspectiveDescriptor,
+		IPluginContribution {
+
+	private String id;
+	private String label;
+	private ImageDescriptor image;
+	private IConfigurationElement configElement;
+	private boolean hasCustomDefinition;
+	private String pluginId;
+	private String originalId; // ID of ancestor that was based on a config
+								// element
+
+	public PerspectiveDescriptor(String id, String label, PerspectiveDescriptor originalDescriptor) {
+		this.id = id;
+		this.label = label;
+		if (originalDescriptor != null) {
+			this.originalId = originalDescriptor.getOriginalId();
+			this.image = originalDescriptor.getImageDescriptor();
+			this.pluginId = originalDescriptor.getPluginId();
+			this.hasCustomDefinition = true;
+		}
+	}
+
+	PerspectiveDescriptor(String id, IConfigurationElement element) {
+		this.id = id;
+		this.configElement = element;
+	}
+
+	public IConfigurationElement getConfigElement() {
+		return configElement;
+	}
+
+	public IPerspectiveFactory createFactory() {
+		try {
+			return (IPerspectiveFactory) configElement
+					.createExecutableExtension(IWorkbenchRegistryConstants.ATT_CLASS);
+		} catch (CoreException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+			throw new RuntimeException(e);
+		}
+	}
+
+	@Override
+	public String getDescription() {
+		return configElement == null ? null : RegistryReader.getDescription(configElement);
+	}
+
+	@Override
+	public String getId() {
+		return id;
+	}
+
+	public String getOriginalId() {
+		if (originalId == null) {
+			originalId = getId();
+		}
+
+		return originalId;
+	}
+
+	@Override
+	public ImageDescriptor getImageDescriptor() {
+		if (image != null)
+			return image;
+
+		// Try and get an image from the IConfigElement
+		if (configElement != null) {
+			String icon = configElement.getAttribute(IWorkbenchRegistryConstants.ATT_ICON);
+			if (icon != null) {
+				image = AbstractUIPlugin.imageDescriptorFromPlugin(
+						configElement.getNamespaceIdentifier(), icon);
+			}
+		}
+
+		// Get a default image
+		if (image == null)
+			image = WorkbenchImages.getImageDescriptor(ISharedImages.IMG_ETOOL_DEF_PERSPECTIVE);
+
+		return image;
+	}
+
+	/**
+	 * Set the {@link ImageDescriptor} that should be used to provide the
+	 * perspective icon. Needed for contributing perspectives via model
+	 * fragments.
+	 *
+	 * @param image
+	 *            The {@link ImageDescriptor} to use
+	 */
+	public void setImageDescriptor(ImageDescriptor image) {
+		this.image = image;
+	}
+
+	@Override
+	public String getLabel() {
+		return configElement == null ? label : configElement
+				.getAttribute(IWorkbenchRegistryConstants.ATT_NAME);
+	}
+
+	@Override
+	public String getLocalId() {
+		return getId();
+	}
+
+	@Override
+	public String getPluginId() {
+		return configElement == null ? pluginId : configElement.getNamespaceIdentifier();
+	}
+
+	/**
+	 * Returns <code>true</code> if this perspective has a custom definition.
+	 *
+	 * @return whether this perspective has a custom definition
+	 */
+	public boolean hasCustomDefinition() {
+		return hasCustomDefinition;
+	}
+
+	public void setHasCustomDefinition(boolean value) {
+		hasCustomDefinition = value;
+	}
+
+	/**
+	 * Returns <code>true</code> if this perspective is predefined by an
+	 * extension.
+	 *
+	 * @return boolean whether this perspective is predefined by an extension
+	 */
+	public boolean isPredefined() {
+		return configElement != null;
+	}
+
+	/**
+	 * Returns <code>true</code> if this perspective is a singleton.
+	 *
+	 * @return whether this perspective is a singleton
+	 */
+	public boolean isSingleton() {
+		return false;
+	}
+
+	@Override
+	public String toString() {
+		return this.getClass().getName() + " {id=" + getId() + "}"; //$NON-NLS-1$//$NON-NLS-2$
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/PerspectiveParameterValues.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/PerspectiveParameterValues.java
new file mode 100644
index 0000000..d34af8d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/PerspectiveParameterValues.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.registry;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.commands.IParameterValues;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * Provides the parameter values for the show perspective command.
+ *
+ * @since 3.1
+ */
+public final class PerspectiveParameterValues implements IParameterValues {
+
+	@Override
+	public final Map getParameterValues() {
+		final Map values = new HashMap();
+
+		final IPerspectiveDescriptor[] perspectives = PlatformUI.getWorkbench()
+				.getPerspectiveRegistry().getPerspectives();
+		for (final IPerspectiveDescriptor perspective : perspectives) {
+			values.put(perspective.getLabel(), perspective.getId());
+		}
+
+		return values;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/PerspectiveRegistry.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/PerspectiveRegistry.java
new file mode 100644
index 0000000..04ae03b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/PerspectiveRegistry.java
@@ -0,0 +1,343 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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
+ *     Jan-Hendrik Diederich, Bredex GmbH - bug 201052
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ *     Dirk Fauth <dirk.fauth@googlemail.com> - Bug 473063
+ *     Patrik Suzzi <psuzzi@gmail.com> - Bug 500420
+ *     Sopot Cela <scela@redhat.com> - Bug 502004
+ *******************************************************************************/
+package org.eclipse.ui.internal.registry;
+
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
+import org.eclipse.e4.core.contexts.ContextInjectionFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.services.log.Logger;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.ui.MSnippetContainer;
+import org.eclipse.e4.ui.model.application.ui.MUIElement;
+import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective;
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.IPerspectiveRegistry;
+import org.eclipse.ui.IWorkbenchPreferenceConstants;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.activities.WorkbenchActivityHelper;
+import org.eclipse.ui.internal.Workbench;
+import org.eclipse.ui.internal.e4.compatibility.E4Util;
+import org.eclipse.ui.internal.util.PrefUtil;
+
+/**
+ * Perspective registry.
+ */
+public class PerspectiveRegistry implements IPerspectiveRegistry, IExtensionChangeHandler {
+
+	@Inject
+	private IExtensionRegistry extensionRegistry;
+
+	@Inject
+	EModelService modelService;
+
+	@Inject
+	MApplication application;
+
+	@Inject
+	IEclipseContext context;
+
+	private IEclipseContext impExpHandlerContext;
+
+	@Inject
+	Logger logger;
+
+	private Map<String, PerspectiveDescriptor> descriptors = new HashMap<>();
+
+	@PostConstruct
+	void postConstruct(MApplication application) {
+		IExtensionPoint point = extensionRegistry.getExtensionPoint("org.eclipse.ui.perspectives"); //$NON-NLS-1$
+		for (IConfigurationElement element : point.getConfigurationElements()) {
+			String id = element.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+			descriptors.put(id, new PerspectiveDescriptor(id, element));
+		}
+
+		List<MUIElement> snippets = application.getSnippets();
+		for (MUIElement snippet : snippets) {
+			if (snippet instanceof MPerspective) {
+				MPerspective perspective = (MPerspective) snippet;
+				String id = perspective.getElementId();
+
+				// See if the clone is customizing an a predefined perspective without changing its name
+				PerspectiveDescriptor existingDescriptor = descriptors.get(id);
+
+				if (existingDescriptor == null) {
+					// A custom perspective with its own name.
+					createDescriptor(perspective);
+				} else {
+					// A custom perspecitve with a name of a pre-defined perspective
+					existingDescriptor.setHasCustomDefinition(true);
+				}
+			}
+		}
+
+		impExpHandlerContext = context.createChild();
+		impExpHandlerContext.set(PerspectiveRegistry.class, this);
+		ContextInjectionFactory.make(ImportExportPespectiveHandler.class, impExpHandlerContext);
+	}
+
+	public void addPerspective(MPerspective perspective) {
+		application.getSnippets().add(perspective);
+		createDescriptor(perspective);
+	}
+
+	private void createDescriptor(MPerspective perspective) {
+		String label = perspective.getLocalizedLabel();
+		String originalId = getOriginalId(perspective);
+		PerspectiveDescriptor originalDescriptor = descriptors.get(originalId);
+		String id = perspective.getElementId();
+		PerspectiveDescriptor newDescriptor = new PerspectiveDescriptor(id, label, originalDescriptor);
+
+		if (perspective.getIconURI() != null) {
+			try {
+				ImageDescriptor img = ImageDescriptor.createFromURL(new URI(perspective.getIconURI()).toURL());
+				newDescriptor.setImageDescriptor(img);
+			} catch (MalformedURLException | URISyntaxException | IllegalArgumentException e) {
+				logger.warn(e, MessageFormat.format("Error on applying configured perspective icon: {0}", //$NON-NLS-1$
+						perspective.getIconURI()));
+			}
+		}
+
+		descriptors.put(id, newDescriptor);
+	}
+
+	/**
+	 * Construct a new registry.
+	 */
+	public PerspectiveRegistry() {
+		IExtensionTracker tracker = PlatformUI.getWorkbench().getExtensionTracker();
+		tracker.registerHandler(this, null);
+
+	}
+
+	@Override
+	public IPerspectiveDescriptor clonePerspective(String id, String label,
+			IPerspectiveDescriptor desc) throws IllegalArgumentException {
+		// FIXME: compat clonePerspective. Not called in 3.8
+		E4Util.unsupported("clonePerspective"); //$NON-NLS-1$
+		return null;
+	}
+
+	@Override
+	public void deletePerspective(IPerspectiveDescriptor toDelete) {
+		PerspectiveDescriptor perspective = (PerspectiveDescriptor) toDelete;
+		if (perspective.isPredefined())
+			return;
+
+		descriptors.remove(perspective.getId());
+		removeSnippet(application, perspective.getId());
+	}
+
+	private MUIElement removeSnippet(MSnippetContainer snippetContainer, String id) {
+		MUIElement snippet = modelService.findSnippet(snippetContainer, id);
+		if (snippet != null)
+			snippetContainer.getSnippets().remove(snippet);
+		return snippet;
+	}
+
+	/**
+	 * Deletes a list of perspectives
+	 *
+	 * @param perspToDelete
+	 */
+	public void deletePerspectives(ArrayList<IPerspectiveDescriptor> perspToDelete) {
+		for (int i = 0; i < perspToDelete.size(); i++) {
+			deletePerspective(perspToDelete.get(i));
+		}
+	}
+
+
+	@Override
+	public IPerspectiveDescriptor findPerspectiveWithId(String perspectiveId) {
+		return findPerspectiveWithId(perspectiveId, true);
+	}
+
+	public IPerspectiveDescriptor findPerspectiveWithId(String perspectiveId,
+			boolean considerRestrictRules) {
+		IPerspectiveDescriptor candidate = descriptors.get(perspectiveId);
+		if (considerRestrictRules && WorkbenchActivityHelper.restrictUseOf(candidate)) {
+			return null;
+		}
+		return candidate;
+	}
+
+	@Override
+	public IPerspectiveDescriptor findPerspectiveWithLabel(String label) {
+		for (IPerspectiveDescriptor descriptor : descriptors.values()) {
+			if (descriptor.getLabel().equals(label)) {
+				if (WorkbenchActivityHelper.restrictUseOf(descriptor)) {
+					return null;
+				}
+				return descriptor;
+			}
+		}
+		return null;
+	}
+
+	@Override
+	public String getDefaultPerspective() {
+		String defaultId = PrefUtil.getAPIPreferenceStore().getString(
+				IWorkbenchPreferenceConstants.DEFAULT_PERSPECTIVE_ID);
+		// empty string may be returned but we want to return null if nothing
+		// found
+		if (defaultId.length() == 0 || findPerspectiveWithId(defaultId) == null) {
+			Workbench instance = Workbench.getInstance();
+			return instance == null ? null : instance.getDefaultPerspectiveId();
+		}
+
+		return defaultId;
+	}
+
+	@Override
+	public IPerspectiveDescriptor[] getPerspectives() {
+		Collection<?> descs = WorkbenchActivityHelper.restrictCollection(descriptors.values(),
+				new ArrayList<>());
+		return descs.toArray(new IPerspectiveDescriptor[descs.size()]);
+	}
+
+	/**
+	 * @see IPerspectiveRegistry#setDefaultPerspective(String)
+	 */
+	@Override
+	public void setDefaultPerspective(String id) {
+		IPerspectiveDescriptor desc = findPerspectiveWithId(id);
+		if (desc != null) {
+			PrefUtil.getAPIPreferenceStore().setValue(
+					IWorkbenchPreferenceConstants.DEFAULT_PERSPECTIVE_ID, id);
+		}
+	}
+
+	/**
+	 * Return <code>true</code> if a label is valid. This checks only the given
+	 * label in isolation. It does not check whether the given label is used by
+	 * any existing perspectives.
+	 *
+	 * @param label
+	 *            the label to test
+	 * @return whether the label is valid
+	 */
+	public boolean validateLabel(String label) {
+		label = label.trim();
+		if (label.length() <= 0) {
+			return false;
+		}
+		return true;
+	}
+
+
+	@Override
+	public void revertPerspective(IPerspectiveDescriptor perspToRevert) {
+		PerspectiveDescriptor perspective = (PerspectiveDescriptor) perspToRevert;
+		if (!perspective.isPredefined())
+			return;
+
+		perspective.setHasCustomDefinition(false);
+		removeSnippet(application, perspective.getId());
+	}
+
+	/**
+	 * Dispose the receiver.
+	 */
+	public void dispose() {
+		if (impExpHandlerContext != null) {
+			impExpHandlerContext.dispose();
+		}
+		PlatformUI.getWorkbench().getExtensionTracker().unregisterHandler(this);
+		// FIXME: what was this listener for?
+		// WorkbenchPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(
+		// preferenceListener);
+	}
+
+	@Override
+	public void removeExtension(IExtension source, Object[] objects) {
+		// TODO compat: what do we do about disappearing extensions
+	}
+
+	@Override
+	public void addExtension(IExtensionTracker tracker, IExtension addedExtension) {
+		// TODO compat: what do we do about appeaering extensions
+	}
+
+	/**
+	 * Create a new perspective.
+	 *
+	 * @param label
+	 *            the name of the new descriptor
+	 * @param originalDescriptor
+	 *            the descriptor on which to base the new descriptor
+	 * @return a new perspective descriptor or <code>null</code> if the creation
+	 *         failed.
+	 */
+	public PerspectiveDescriptor createPerspective(String label,
+			PerspectiveDescriptor originalDescriptor) {
+
+		String newID = createNewId(label, originalDescriptor);
+		PerspectiveDescriptor newDescriptor = new PerspectiveDescriptor(newID, label,
+				originalDescriptor);
+		descriptors.put(newDescriptor.getId(), newDescriptor);
+		return newDescriptor;
+	}
+
+	/**
+	 * Return an id for the new descriptor.
+	 *
+	 * The id must encode the original id. id is of the form <originalId>.label
+	 *
+	 * @param label
+	 * @param originalDescriptor
+	 * @return the new id
+	 */
+	private String createNewId(String label, PerspectiveDescriptor originalDescriptor) {
+		return originalDescriptor.getOriginalId() + '.' + label;
+	}
+
+	private String getOriginalId(MPerspective p) {
+		String id = p.getElementId();
+		String label = p.getLabel();
+		int index = id.lastIndexOf('.');
+		// Custom perspectives store the user defined names in their labels
+		String trimE4 = label.trim();
+		String trimE3 = label.replace(' ', '_').trim();
+		if (id.endsWith(label)) {
+			index = id.lastIndexOf(label) - 1;
+		} else if (id.endsWith(trimE4)) {
+			index = id.lastIndexOf(trimE4) - 1;
+		} else if (id.endsWith(trimE3)) {
+			index = id.lastIndexOf(trimE3) - 1;
+		}
+		if (index >= 0 && index < id.length()) {
+			return id.substring(0, index);
+		}
+		return id;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/PreferencePageParameterValues.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/PreferencePageParameterValues.java
new file mode 100644
index 0000000..a90aebd
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/PreferencePageParameterValues.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.registry;
+
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.eclipse.core.commands.IParameterValues;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.preference.IPreferenceNode;
+import org.eclipse.jface.preference.PreferenceManager;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchMessages;
+
+/**
+ * <p>
+ * Provides the parameter values for the show preferences command.
+ * </p>
+ * <p>
+ * To disambiguate preference pages with the same local label, names are
+ * constructed incorporating the full path of preference page labels. For
+ * instance names like <code>General > Appearance</code> and
+ * <code>Java > Appearance</code> avoid the problem of trying to put two
+ * <code>Appearance</code> keys into the parameter values map.
+ * </p>
+ * <p>
+ * This is only intended for use within the
+ * <code>org.eclipse.ui.workbench</code> plug-in.
+ * </p>
+ *
+ * @since 3.2
+ */
+public final class PreferencePageParameterValues implements IParameterValues {
+
+	public PreferencePageParameterValues() {
+		Platform.getExtensionRegistry().addRegistryChangeListener(
+				event -> {
+				    // RAP [bm]: namespace
+				    if (event.getExtensionDeltas(PlatformUI.PLUGIN_EXTENSION_NAME_SPACE,
+							IWorkbenchRegistryConstants.PL_PREFERENCES).length > 0) {
+						preferenceMap = null;
+					}
+				});
+	}
+
+	private Map preferenceMap;
+
+	/**
+	 * Iterate through the preference page and build the map of preference page
+	 * names to ids.
+	 *
+	 * @param values
+	 *            The Map being populated with parameter values.
+	 * @param preferenceNodes
+	 *            An array of <code>IPreferenceNode</code> to process.
+	 * @param namePrefix
+	 *            A string incorporating the names of each parent
+	 *            <code>IPreferenceNode</code> up to the root of the
+	 *            preference page tree. This will be <code>null</code> for the
+	 *            root level preference page nodes.
+	 */
+	private final void collectParameterValues(final Map values,
+			final IPreferenceNode[] preferenceNodes, final String namePrefix) {
+
+		for (final IPreferenceNode preferenceNode : preferenceNodes) {
+			final String name;
+			if (namePrefix == null) {
+				name = preferenceNode.getLabelText();
+			} else {
+				name = namePrefix
+						+ WorkbenchMessages.get().PreferencePageParameterValues_pageLabelSeparator
+						+ preferenceNode.getLabelText();
+			}
+			final String value = preferenceNode.getId();
+			values.put(name, value);
+
+			collectParameterValues(values, preferenceNode.getSubNodes(), name);
+		}
+	}
+
+	@Override
+	public final Map getParameterValues() {
+		if (preferenceMap == null) {
+			preferenceMap = new TreeMap();
+
+			final PreferenceManager preferenceManager = PlatformUI
+					.getWorkbench().getPreferenceManager();
+			collectParameterValues(preferenceMap, preferenceManager
+					.getRootSubNodes(), null);
+		}
+
+		return preferenceMap;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/PreferencePageRegistryReader.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/PreferencePageRegistryReader.java
new file mode 100644
index 0000000..1a9da4c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/PreferencePageRegistryReader.java
@@ -0,0 +1,205 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Jan-Hendrik Diederich, Bredex GmbH - bug 201052
+ *******************************************************************************/
+package org.eclipse.ui.internal.registry;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.jface.preference.IPreferenceNode;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.activities.WorkbenchActivityHelper;
+import org.eclipse.ui.internal.Workbench;
+import org.eclipse.ui.internal.dialogs.WorkbenchPreferenceNode;
+
+/**
+ *  Instances access the registry that is provided at creation time in order
+ *  to determine the contributed preference pages
+ */
+public class PreferencePageRegistryReader extends CategorizedPageRegistryReader {
+
+	private static final String TAG_PAGE = "page"; //$NON-NLS-1$
+
+	private List nodes;
+
+	private IWorkbench workbench;
+
+
+	class PreferencesCategoryNode extends CategoryNode {
+
+		WorkbenchPreferenceNode node;
+
+		/**
+		 * Create a new instance of the receiver.
+		 * @param reader
+		 * @param nodeToCategorize
+		 */
+		public PreferencesCategoryNode(CategorizedPageRegistryReader reader,
+				WorkbenchPreferenceNode nodeToCategorize) {
+			super(reader);
+			this.node = nodeToCategorize;
+		}
+
+		@Override
+		String getLabelText() {
+			return node.getLabelText();
+		}
+
+		@Override
+		String getLabelText(Object element) {
+			return ((WorkbenchPreferenceNode) element).getLabelText();
+		}
+
+		@Override
+		Object getNode() {
+			return node;
+		}
+	}
+
+	/**
+	 * Create a new instance configured with the workbench
+	 *
+	 * @param newWorkbench the workbench
+	 */
+	public PreferencePageRegistryReader(IWorkbench newWorkbench) {
+		workbench = newWorkbench;
+	}
+
+	@Override
+	Object findNode(String id) {
+		for (int i = 0; i < nodes.size(); i++) {
+			WorkbenchPreferenceNode node = (WorkbenchPreferenceNode) nodes.get(i);
+			if (node.getId().equals(id)) {
+				return node;
+			}
+		}
+		return null;
+	}
+
+	@Override
+	Object findNode(Object parent, String currentToken) {
+		IPreferenceNode[] subNodes = ((WorkbenchPreferenceNode) parent).getSubNodes();
+		for (IPreferenceNode subNode : subNodes) {
+			WorkbenchPreferenceNode node = (WorkbenchPreferenceNode) subNode;
+			if (node.getId().equals(currentToken)) {
+				return node;
+			}
+		}
+		return null;
+	}
+
+	@Override
+	void add(Object parent, Object node) {
+		((IPreferenceNode) parent).add((IPreferenceNode) node);
+	}
+
+	@Override
+	CategoryNode createCategoryNode(CategorizedPageRegistryReader reader, Object object) {
+		return new PreferencesCategoryNode(reader, (WorkbenchPreferenceNode) object);
+	}
+
+	@Override
+	String getCategory(Object node) {
+		return ((WorkbenchPreferenceNode) node).getCategory();
+	}
+
+	@Override
+	protected String invalidCategoryNodeMessage(CategoryNode categoryNode) {
+		WorkbenchPreferenceNode wpn = (WorkbenchPreferenceNode) categoryNode.getNode();
+		return "Invalid preference category path: " + wpn.getCategory() + " (bundle: " + wpn.getPluginId() + ", page: " + wpn.getLocalId() + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+	}
+
+	@Override
+	Collection getNodes() {
+		return nodes;
+	}
+
+	/**
+	 * Load the preference page contirbutions from the registry and
+	 * organize preference node contributions by category into hierarchies
+	 * If there is no page for a given node in the hierarchy then a blank
+	 * page will be created.
+	 * If no category has been specified or category information
+	 * is incorrect, page will appear at the root level. workbench
+	 * log entry will be created for incorrect category information.
+	 *
+	 * @param registry the extension registry
+	 */
+	public void loadFromRegistry(IExtensionRegistry registry) {
+		nodes = new ArrayList();
+
+		// RAP [bm]: namespace
+		readRegistry(registry, PlatformUI.PLUGIN_EXTENSION_NAME_SPACE, IWorkbenchRegistryConstants.PL_PREFERENCES);
+
+		processNodes();
+
+	}
+
+	/**
+	 * Read preference page element.
+	 */
+	@Override
+	protected boolean readElement(IConfigurationElement element) {
+		if (element.getName().equals(TAG_PAGE) == false) {
+			return false;
+		}
+		WorkbenchPreferenceNode node = createNode(element);
+		if (node != null) {
+			if (workbench instanceof Workbench) {
+				if (node.getId().equals(
+						((Workbench) workbench).getMainPreferencePageId()))
+					node.setPriority(-1);
+			}
+			nodes.add(node);
+		}
+		return true;
+	}
+
+	/**
+	 * Create a workbench preference node.
+	 * @param element
+	 * @return WorkbenchPreferenceNode
+	 */
+	public static WorkbenchPreferenceNode createNode(IConfigurationElement element) {
+		boolean nameMissing = element.getAttribute(IWorkbenchRegistryConstants.ATT_NAME) == null;
+		String id = element.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+		boolean classMissing = getClassValue(element, IWorkbenchRegistryConstants.ATT_CLASS) == null;
+
+		if (nameMissing) {
+			logMissingAttribute(element, IWorkbenchRegistryConstants.ATT_NAME);
+		}
+		if (id == null) {
+			logMissingAttribute(element, IWorkbenchRegistryConstants.ATT_ID);
+		}
+		if (classMissing) {
+			logMissingAttribute(element, IWorkbenchRegistryConstants.ATT_CLASS);
+		}
+
+		if (nameMissing || id == null || classMissing) {
+			return null;
+		}
+
+		WorkbenchPreferenceNode node = new WorkbenchPreferenceNode(id, element);
+		return node;
+	}
+
+	/**
+	 * Return the top level IPreferenceNodes, minus the one which fail the
+	 * Expression check.
+	 * @return  Collection of IPreferenceNode.
+	 */
+	public Collection getTopLevelNodes() {
+		return WorkbenchActivityHelper.restrictCollection(topLevelNodes, new ArrayList());
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/PreferenceTransferRegistryReader.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/PreferenceTransferRegistryReader.java
new file mode 100644
index 0000000..b12562f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/PreferenceTransferRegistryReader.java
@@ -0,0 +1,176 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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
+ *     Semion Chichelnitsky (semion@il.ibm.com) - bug 208564
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.registry;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.preferences.PreferenceFilterEntry;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.preferences.PreferenceTransferElement;
+
+import com.ibm.icu.text.Collator;
+
+/**
+ * Preference Transfer registry reader to read extenders of the
+ * preferenceTransfer schema.
+ *
+ * @since 3.1
+ */
+public class PreferenceTransferRegistryReader extends RegistryReader {
+	private List preferenceTransfers;
+
+	private String pluginPoint;
+
+	/**
+	 * Create an instance of this class.
+	 *
+	 * @param pluginPointId
+	 *            java.lang.String
+	 */
+	public PreferenceTransferRegistryReader(String pluginPointId) {
+		pluginPoint = pluginPointId;
+	}
+
+	/**
+	 * Returns a new PreferenceTransferElement configured according to the
+	 * parameters contained in the passed element.
+	 *
+	 * @param element
+	 *            the configuration element
+	 * @return the preference transfer element or <code>null</code> if there was
+	 *         not enough information in the element
+	 */
+	protected PreferenceTransferElement createPreferenceTransferElement(
+			IConfigurationElement element) {
+		// PreferenceTransfers must have a class attribute
+		if (element.getAttribute(IWorkbenchRegistryConstants.ATT_NAME) == null) {
+			logMissingAttribute(element, IWorkbenchRegistryConstants.ATT_NAME);
+			return null;
+		}
+
+		// must specify a mapping
+		if (element.getChildren(IWorkbenchRegistryConstants.TAG_MAPPING) == null) {
+			logMissingElement(element, IWorkbenchRegistryConstants.TAG_MAPPING);
+			return null;
+		}
+
+		return new PreferenceTransferElement(element);
+	}
+
+	/**
+	 * Returns a sorted list of preference transfers.
+	 *
+	 * @return an array of <code>IPreferenceTransfer</code> objects
+	 */
+	public PreferenceTransferElement[] getPreferenceTransfers() {
+		readPreferenceTransfers();
+		PreferenceTransferElement[] transfers = new PreferenceTransferElement[preferenceTransfers
+				.size()];
+		Collections.sort(preferenceTransfers, (o1, o2) -> {
+			String name1 = ((PreferenceTransferElement) o1).getName();
+			String name2 = ((PreferenceTransferElement) o2).getName();
+
+			return Collator.getInstance().compare(name1, name2);
+		});
+		preferenceTransfers.toArray(transfers);
+		return transfers;
+	}
+
+	@Override
+	protected boolean readElement(IConfigurationElement element) {
+		if (element.getName().equals(IWorkbenchRegistryConstants.TAG_TRANSFER)) {
+
+			PreferenceTransferElement transfer = createPreferenceTransferElement(element);
+			if (transfer != null)
+				preferenceTransfers.add(transfer);
+			return true;
+		}
+
+		// Allow settings transfers as well.
+
+		return element.getName().equals(
+				IWorkbenchRegistryConstants.TAG_SETTINGS_TRANSFER);
+	}
+
+	/**
+	 * Reads the wizards in a registry.
+	 */
+	protected void readPreferenceTransfers() {
+		preferenceTransfers = new ArrayList();
+		IExtensionRegistry registry = Platform.getExtensionRegistry();
+		// RAP [bm]: namespace
+		readRegistry(registry, PlatformUI.PLUGIN_EXTENSION_NAME_SPACE, pluginPoint);
+	}
+
+	/**
+	 * Get the preference mappings.
+	 *
+	 * @param configElement
+	 * @return the child configuration elements
+	 */
+	public static IConfigurationElement[] getMappings(
+			IConfigurationElement configElement) {
+		IConfigurationElement[] children = configElement
+				.getChildren(IWorkbenchRegistryConstants.TAG_MAPPING);
+		if (children.length < 1) {
+			logMissingElement(configElement,
+					IWorkbenchRegistryConstants.TAG_MAPPING);
+			return new IConfigurationElement[0];
+		}
+		return children;
+	}
+
+	/**
+	 * @param element
+	 * @return the scope attribute for this element
+	 */
+	public static String getScope(IConfigurationElement element) {
+		return element.getAttribute(IWorkbenchRegistryConstants.ATT_SCOPE);
+	}
+
+	/**
+	 * @param element
+	 *            the configuration element
+	 * @return a map that maps nodes to keys for this element or
+	 *         <code>null</code> for all nodes
+	 */
+	public static Map getEntry(IConfigurationElement element) {
+		IConfigurationElement[] entries = element.getChildren(IWorkbenchRegistryConstants.TAG_ENTRY);
+		if (entries.length == 0) {
+			return null;
+		}
+		Map map = new HashMap(entries.length);
+		for (IConfigurationElement entry : entries) {
+			IConfigurationElement[] keys = entry.getChildren(IWorkbenchRegistryConstants.ATT_KEY);
+			PreferenceFilterEntry[] prefFilters = null;
+			if (keys.length > 0) {
+				prefFilters = new PreferenceFilterEntry[keys.length];
+				for (int j = 0; j < keys.length; j++) {
+					IConfigurationElement keyElement = keys[j];
+					prefFilters[j] = new PreferenceFilterEntry(
+							keyElement.getAttribute(IWorkbenchRegistryConstants.ATT_NAME),
+							keyElement.getAttribute(IWorkbenchRegistryConstants.ATT_MATCH_TYPE));
+				}
+			}
+			map.put(entry.getAttribute(IWorkbenchRegistryConstants.ATT_NODE), prefFilters);
+		}
+		return map;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/PropertyPagesRegistryReader.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/PropertyPagesRegistryReader.java
new file mode 100644
index 0000000..84e06fe
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/PropertyPagesRegistryReader.java
@@ -0,0 +1,261 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     James Blackburn (Broadcom Corp.) - Bug 294628 multiple selection
+ *******************************************************************************/
+package org.eclipse.ui.internal.registry;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.dialogs.PropertyPageContributorManager;
+import org.eclipse.ui.internal.dialogs.RegistryPageContributor;
+
+/**
+ * This class loads property pages from the registry.
+ */
+public class PropertyPagesRegistryReader extends CategorizedPageRegistryReader {
+
+	/**
+	 * Value "<code>nameFilter</code>".
+	 */
+	public static final String ATT_NAME_FILTER = "nameFilter";//$NON-NLS-1$
+
+	/**
+	 * Value "<code>name</code>".
+	 */
+	public static final String ATT_FILTER_NAME = "name";//$NON-NLS-1$
+
+	/**
+	 * Value "<code>value</code>".
+	 */
+	public static final String ATT_FILTER_VALUE = "value";//$NON-NLS-1$
+
+	/**
+	 * Value "<code>selectionFilter</code>". Is an enum allowing propertyPages to
+	 * support multiple selection when enum value is <code>ATT_SELECTION_FILTER_MULTI</code>
+	 * @since 3.7
+	 */
+	public static final String ATT_SELECTION_FILTER = "selectionFilter";//$NON-NLS-1$
+
+	/**
+	 * Selection filter attribute value indicating support for multiple selection.
+	 * @since 3.7
+	 */
+	public static final String ATT_SELECTION_FILTER_MULTI = "multi";//$NON-NLS-1$
+
+	private static final String TAG_PAGE = "page";//$NON-NLS-1$
+
+	/**
+	 * Value "<code>filter</code>".
+	 */
+	public static final String TAG_FILTER = "filter";//$NON-NLS-1$
+
+	/**
+	 * Value "<code>keywordReference</code>".
+	 */
+	public static final String TAG_KEYWORD_REFERENCE = "keywordReference";//$NON-NLS-1$
+
+	/**
+	 * Value "<code>objectClass</code>".
+	 */
+	public static final String ATT_OBJECTCLASS = "objectClass";//$NON-NLS-1$
+
+	/**
+	 * Value "<code>adaptable</code>".
+	 */
+	public static final String ATT_ADAPTABLE = "adaptable";//$NON-NLS-1$
+
+	private static final String CHILD_ENABLED_WHEN = "enabledWhen"; //$NON-NLS-1$;
+
+	private Collection pages = new ArrayList();
+
+	private PropertyPageContributorManager manager;
+
+	class PropertyCategoryNode extends CategoryNode {
+
+		RegistryPageContributor page;
+
+		/**
+		 * Create a new category node on the given reader for the property page.
+		 *
+		 * @param reader
+		 * @param propertyPage
+		 */
+		PropertyCategoryNode(CategorizedPageRegistryReader reader,
+				RegistryPageContributor propertyPage) {
+			super(reader);
+			page = propertyPage;
+		}
+
+		@Override
+		String getLabelText() {
+			return page.getPageName();
+		}
+
+		@Override
+		String getLabelText(Object element) {
+			return ((RegistryPageContributor) element).getPageName();
+		}
+
+		@Override
+		Object getNode() {
+			return page;
+		}
+	}
+
+	/**
+	 * The constructor.
+	 *
+	 * @param manager
+	 *            the manager
+	 */
+	public PropertyPagesRegistryReader(PropertyPageContributorManager manager) {
+		this.manager = manager;
+	}
+
+	/**
+	 * Reads static property page specification.
+	 */
+	private void processPageElement(IConfigurationElement element) {
+		String pageId = element
+				.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+
+		if (pageId == null) {
+			logMissingAttribute(element, IWorkbenchRegistryConstants.ATT_ID);
+			return;
+		}
+
+		RegistryPageContributor contributor = new RegistryPageContributor(
+				pageId, element);
+
+		String pageClassName = getClassValue(element,
+				IWorkbenchRegistryConstants.ATT_CLASS);
+		if (pageClassName == null) {
+			logMissingAttribute(element, IWorkbenchRegistryConstants.ATT_CLASS);
+			return;
+		}
+		if (element.getAttribute(ATT_OBJECTCLASS) == null) {
+			pages.add(contributor);
+			manager.registerContributor(contributor, Object.class.getName());
+		} else {
+			List objectClassNames = new ArrayList();
+			objectClassNames.add(element.getAttribute(ATT_OBJECTCLASS));
+			registerContributors(contributor, objectClassNames);
+		}
+	}
+
+	/**
+	 * Register the contributor for all of the relevant classes.
+	 *
+	 * @param contributor
+	 * @param objectClassNames
+	 */
+	private void registerContributors(RegistryPageContributor contributor,
+			List objectClassNames) {
+
+		pages.add(contributor);
+		for (Iterator iter = objectClassNames.iterator(); iter.hasNext();) {
+			manager.registerContributor(contributor, (String) iter.next());
+		}
+
+	}
+
+
+	/**
+	 * Reads the next contribution element.
+	 *
+	 * public for dynamic UI
+	 */
+	@Override
+	public boolean readElement(IConfigurationElement element) {
+		if (element.getName().equals(TAG_PAGE)) {
+			processPageElement(element);
+			readElementChildren(element);
+			return true;
+		}
+		if (element.getName().equals(TAG_FILTER)) {
+			return true;
+		}
+
+		if (element.getName().equals(CHILD_ENABLED_WHEN)) {
+			return true;
+		}
+
+		if (element.getName().equals(TAG_KEYWORD_REFERENCE)) {
+			return true;
+		}
+
+		return false;
+	}
+
+	/**
+	 * Reads all occurances of propertyPages extension in the registry.
+	 *
+	 * @param registry
+	 *            the registry
+	 */
+	public void registerPropertyPages(IExtensionRegistry registry) {
+	    // RAP [bm]: namespace
+	    readRegistry(registry, PlatformUI.PLUGIN_EXTENSION_NAME_SPACE,
+				IWorkbenchRegistryConstants.PL_PROPERTY_PAGES);
+		processNodes();
+	}
+
+	@Override
+	void add(Object parent, Object node) {
+		((RegistryPageContributor) parent)
+				.addSubPage((RegistryPageContributor) node);
+
+	}
+
+	@Override
+	CategoryNode createCategoryNode(CategorizedPageRegistryReader reader,
+			Object object) {
+		return new PropertyCategoryNode(reader,
+				(RegistryPageContributor) object);
+	}
+
+	@Override
+	Object findNode(Object parent, String currentToken) {
+		return ((RegistryPageContributor) parent).getChild(currentToken);
+	}
+
+	@Override
+	Object findNode(String id) {
+		Iterator iterator = pages.iterator();
+		while (iterator.hasNext()) {
+			RegistryPageContributor next = (RegistryPageContributor) iterator
+					.next();
+			if (next.getPageId().equals(id))
+				return next;
+		}
+		return null;
+	}
+
+	@Override
+	String getCategory(Object node) {
+		return ((RegistryPageContributor) node).getCategory();
+	}
+
+	@Override
+	protected String invalidCategoryNodeMessage(CategoryNode categoryNode) {
+		RegistryPageContributor rpc = (RegistryPageContributor) categoryNode.getNode();
+		return "Invalid property category path: " + rpc.getCategory() + " (bundle: " + rpc.getPluginId() + ", propertyPage: " + rpc.getLocalId() + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+	}
+
+	@Override
+	Collection getNodes() {
+		return pages;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/RegistryReader.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/RegistryReader.java
new file mode 100644
index 0000000..18b15ec
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/RegistryReader.java
@@ -0,0 +1,204 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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
+ *     Mickael Istria (Red Hat Inc) - [507295] orderExtensions
+ *******************************************************************************/
+package org.eclipse.ui.internal.registry;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.e4.ui.internal.workbench.ExtensionsSort;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+
+/**
+ *	Template implementation of a registry reader that creates objects
+ *	representing registry contents. Typically, an extension
+ * contains one element, but this reader handles multiple
+ * elements per extension.
+ *
+ * To start reading the extensions from the registry for an
+ * extension point, call the method <code>readRegistry</code>.
+ *
+ * To read children of an IConfigurationElement, call the
+ * method <code>readElementChildren</code> from your implementation
+ * of the method <code>readElement</code>, as it will not be
+ * done by default.
+ */
+public abstract class RegistryReader {
+
+    // for dynamic UI - remove this cache to avoid inconsistency
+    //protected static Hashtable extensionPoints = new Hashtable();
+    /**
+     * The constructor.
+     */
+    protected RegistryReader() {
+    }
+
+    /**
+     * Logs the error in the workbench log using the provided
+     * text and the information in the configuration element.
+     */
+    protected static void logError(IConfigurationElement element, String text) {
+        IExtension extension = element.getDeclaringExtension();
+        StringBuffer buf = new StringBuffer();
+        buf
+				.append("Plugin " + extension.getNamespace() + ", extension " //$NON-NLS-1$//$NON-NLS-2$
+						+ extension.getExtensionPointUniqueIdentifier());
+        // look for an ID if available - this should help debugging
+        String id = element.getAttribute("id"); //$NON-NLS-1$
+        if (id != null) {
+        	buf.append(", id "); //$NON-NLS-1$
+        	buf.append(id);
+        }
+        buf.append(": " + text);//$NON-NLS-1$
+        WorkbenchPlugin.log(buf.toString());
+    }
+
+    /**
+     * Logs a very common registry error when a required attribute is missing.
+     */
+    protected static void logMissingAttribute(IConfigurationElement element,
+            String attributeName) {
+        logError(element,
+                "Required attribute '" + attributeName + "' not defined");//$NON-NLS-2$//$NON-NLS-1$
+    }
+
+    /**
+     * Logs a very common registry error when a required child is missing.
+     */
+    protected static void logMissingElement(IConfigurationElement element,
+            String elementName) {
+        logError(element,
+                "Required sub element '" + elementName + "' not defined");//$NON-NLS-2$//$NON-NLS-1$
+    }
+
+    /**
+     * Logs a registry error when the configuration element is unknown.
+     */
+    protected static void logUnknownElement(IConfigurationElement element) {
+        logError(element, "Unknown extension tag found: " + element.getName());//$NON-NLS-1$
+    }
+
+    /**
+     * Apply a reproducable order to the list of extensions
+     * provided, such that the order will not change as
+     * extensions are added or removed.
+     * @param extensions the extensions to order
+     * @return ordered extensions
+     */
+    public static IExtension[] orderExtensions(IExtension[] extensions) {
+		return new ExtensionsSort().sort(extensions);
+    }
+
+    /**
+     * Implement this method to read element's attributes.
+     * If children should also be read, then implementor
+     * is responsible for calling <code>readElementChildren</code>.
+     * Implementor is also responsible for logging missing
+     * attributes.
+     *
+     * @return true if element was recognized, false if not.
+     */
+    protected abstract boolean readElement(IConfigurationElement element);
+
+    /**
+     * Read the element's children. This is called by
+     * the subclass' readElement method when it wants
+     * to read the children of the element.
+     */
+    protected void readElementChildren(IConfigurationElement element) {
+        readElements(element.getChildren());
+    }
+
+    /**
+     * Read each element one at a time by calling the
+     * subclass implementation of <code>readElement</code>.
+     *
+     * Logs an error if the element was not recognized.
+     */
+    protected void readElements(IConfigurationElement[] elements) {
+        for (int i = 0; i < elements.length; i++) {
+            if (!readElement(elements[i])) {
+				logUnknownElement(elements[i]);
+			}
+        }
+    }
+
+    /**
+     * Read one extension by looping through its
+     * configuration elements.
+     */
+    protected void readExtension(IExtension extension) {
+        readElements(extension.getConfigurationElements());
+    }
+
+    /**
+     *	Start the registry reading process using the
+     * supplied plugin ID and extension point.
+     *
+     * @param registry the registry to read from
+     * @param pluginId the plugin id of the extenion point
+     * @param extensionPoint the extension point id
+     */
+    public void readRegistry(IExtensionRegistry registry, String pluginId,
+            String extensionPoint) {
+        IExtensionPoint point = registry.getExtensionPoint(pluginId,
+                extensionPoint);
+        if (point == null) {
+			return;
+		}
+        IExtension[] extensions = point.getExtensions();
+        extensions = orderExtensions(extensions);
+        for (IExtension extension : extensions) {
+			readExtension(extension);
+		}
+    }
+
+    /**
+     * Utility for extracting the description child of an element.
+     *
+     * @param configElement the element
+     * @return the description
+     * @since 3.1
+     */
+    public static String getDescription(IConfigurationElement configElement) {
+		IConfigurationElement[] children = configElement.getChildren(IWorkbenchRegistryConstants.TAG_DESCRIPTION);
+	    if (children.length >= 1) {
+	        return children[0].getValue();
+	    }
+	    return "";//$NON-NLS-1$
+    }
+
+    /**
+	 * Utility for extracting the value of a class attribute or a nested class
+	 * element that follows the pattern set forth by
+	 * {@link org.eclipse.core.runtime.IExecutableExtension}.
+	 *
+	 * @param configElement
+	 *            the element
+	 * @param classAttributeName
+	 *            the name of the class attribute to check
+	 * @return the value of the attribute or nested class element
+	 * @since 3.1
+	 */
+    public static String getClassValue(IConfigurationElement configElement, String classAttributeName) {
+    	String className = configElement.getAttribute(classAttributeName);
+    	if (className != null) {
+			return className;
+		}
+		IConfigurationElement [] candidateChildren = configElement.getChildren(classAttributeName);
+		if (candidateChildren.length == 0) {
+			return null;
+		}
+
+		return candidateChildren[0].getAttribute(IWorkbenchRegistryConstants.ATT_CLASS);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/ShowViewHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/ShowViewHandler.java
new file mode 100644
index 0000000..eaf0b97
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/ShowViewHandler.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.registry;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+/**
+ * Command handler to show a particular view.
+ *
+ * @since 3.0
+ */
+public final class ShowViewHandler extends AbstractHandler {
+
+	/**
+	 * The identifier of the view this handler should open. This value should
+	 * never be <code>null</code>.
+	 */
+	private final String viewId;
+
+	/**
+	 * Constructs a new instance of <code>ShowViewHandler</code>.
+	 *
+	 * @param viewId
+	 *            The identifier of the view this handler should open; must not
+	 *            be <code>null</code>.
+	 */
+	public ShowViewHandler(final String viewId) {
+		this.viewId = viewId;
+	}
+
+	@Override
+	public final Object execute(final ExecutionEvent event)
+			throws ExecutionException {
+		final IWorkbenchWindow activeWorkbenchWindow = HandlerUtil
+				.getActiveWorkbenchWindowChecked(event);
+
+		final IWorkbenchPage activePage = activeWorkbenchWindow.getActivePage();
+		if (activePage == null) {
+			return null;
+		}
+
+		try {
+			activePage.showView(viewId);
+		} catch (PartInitException e) {
+			IStatus status = StatusUtil
+					.newStatus(e.getStatus(), e.getMessage());
+			StatusManager.getManager().handle(status, StatusManager.SHOW);
+		}
+
+		return null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/StickyViewDescriptor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/StickyViewDescriptor.java
new file mode 100644
index 0000000..0bef501
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/StickyViewDescriptor.java
@@ -0,0 +1,129 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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
+ *     Jan-Hendrik Diederich, Bredex GmbH - bug 201052
+ *******************************************************************************/
+package org.eclipse.ui.internal.registry;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.ui.IPageLayout;
+import org.eclipse.ui.IPluginContribution;
+import org.eclipse.ui.views.IStickyViewDescriptor;
+
+/**
+ * @since 3.0
+ */
+public class StickyViewDescriptor implements IStickyViewDescriptor,
+	IPluginContribution {
+
+    private IConfigurationElement configurationElement;
+
+	private String id;
+
+	/**
+	 * Folder constant for right sticky views.
+	 */
+	public static final String STICKY_FOLDER_RIGHT = "stickyFolderRight"; //$NON-NLS-1$
+
+	/**
+	 * Folder constant for left sticky views.
+	 */
+	public static final String STICKY_FOLDER_LEFT = "stickyFolderLeft"; //$NON-NLS-1$
+
+	/**
+	 * Folder constant for top sticky views.
+	 */
+	public static final String STICKY_FOLDER_TOP = "stickyFolderTop"; //$NON-NLS-1$
+
+	/**
+	 * Folder constant for bottom sticky views.
+	 */
+	public static final String STICKY_FOLDER_BOTTOM = "stickyFolderBottom"; //$NON-NLS-1$
+
+    /**
+     * @param element
+     * @throws CoreException
+     */
+    public StickyViewDescriptor(IConfigurationElement element)
+            throws CoreException {
+    	this.configurationElement = element;
+    	id = configurationElement.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+        if (id == null) {
+			throw new CoreException(new Status(IStatus.ERROR, element
+                    .getNamespace(), 0,
+                    "Invalid extension (missing id) ", null));//$NON-NLS-1$
+		}
+    }
+
+	/**
+     * Return the configuration element.
+     *
+	 * @return the configuration element
+	 */
+	public IConfigurationElement getConfigurationElement() {
+		return configurationElement;
+	}
+
+    @Override
+	public int getLocation() {
+    	int direction = IPageLayout.RIGHT;
+
+    	String location = configurationElement.getAttribute(IWorkbenchRegistryConstants.ATT_LOCATION);
+        if (location != null) {
+            if (location.equalsIgnoreCase("left")) { //$NON-NLS-1$
+				direction = IPageLayout.LEFT;
+			} else if (location.equalsIgnoreCase("top")) { //$NON-NLS-1$
+				direction = IPageLayout.TOP;
+			} else if (location.equalsIgnoreCase("bottom")) { //$NON-NLS-1$
+				direction = IPageLayout.BOTTOM;
+            //no else for right - it is the default value;
+			}
+        }
+        return direction;
+    }
+
+    @Override
+	public String getId() {
+        return id;
+    }
+
+    @Override
+	public String getLocalId() {
+    	return id;
+    }
+
+    @Override
+	public String getPluginId() {
+    	return configurationElement.getContributor().getName();
+    }
+
+
+    @Override
+	public boolean isCloseable() {
+    	boolean closeable = true;
+    	String closeableString = configurationElement.getAttribute(IWorkbenchRegistryConstants.ATT_CLOSEABLE);
+        if (closeableString != null) {
+            closeable = !closeableString.equals("false"); //$NON-NLS-1$
+        }
+        return closeable;
+    }
+
+    @Override
+	public boolean isMoveable() {
+    	boolean moveable = true;
+    	String moveableString = configurationElement.getAttribute(IWorkbenchRegistryConstants.ATT_MOVEABLE);
+        if (moveableString != null) {
+            moveable = !moveableString.equals("false"); //$NON-NLS-1$
+        }
+        return moveable;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/UIExtensionTracker.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/UIExtensionTracker.java
new file mode 100644
index 0000000..d24367f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/UIExtensionTracker.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2014 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.ui.internal.registry;
+
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.dynamichelpers.ExtensionTracker;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+
+/**
+ * @since 3.1
+ */
+public class UIExtensionTracker extends ExtensionTracker {
+    private Display display;
+
+    // SOMETHING HAS NOT BEEN DONE IN THE REGISTTRY CHANGED CODE
+    // if (!PlatformUI.isWorkbenchRunning())
+    // return;
+    // int numDeltas = 0;
+    // Display display = PlatformUI.getWorkbench().getDisplay();
+    // if (display == null || display.isDisposed())
+    // return;
+    // It seems that the tracker should be closed.
+
+    /**
+	 * @param display
+	 */
+	public UIExtensionTracker(Display display) {
+		this.display = display;
+	}
+
+	@Override
+	protected void applyRemove(final IExtensionChangeHandler handler, final IExtension removedExtension, final Object[] objects) {
+		if (display.isDisposed())
+			return;
+
+		display.asyncExec(() -> {
+            try {
+                handler.removeExtension(removedExtension, objects);
+            } catch (Exception e) {
+                WorkbenchPlugin.log(getClass(), "doRemove", e); //$NON-NLS-1$
+            }
+        });
+    }
+
+    @Override
+	protected void applyAdd(final IExtensionChangeHandler handler, final IExtension addedExtension) {
+		if (display.isDisposed())
+			return;
+
+		display.asyncExec(() -> {
+			try {
+				handler.addExtension(UIExtensionTracker.this, addedExtension);
+			} catch (Exception e) {
+				WorkbenchPlugin.log(getClass(), "doAdd", e); //$NON-NLS-1$
+            }
+        });
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/ViewCategory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/ViewCategory.java
new file mode 100644
index 0000000..a6b988b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/ViewCategory.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ ******************************************************************************/
+
+package org.eclipse.ui.internal.registry;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.ui.activities.WorkbenchActivityHelper;
+import org.eclipse.ui.views.IViewCategory;
+import org.eclipse.ui.views.IViewDescriptor;
+
+public class ViewCategory implements IViewCategory {
+
+	private String id;
+	private String label;
+	private IPath path;
+	private List<IViewDescriptor> descriptors = new ArrayList<>();
+
+	public ViewCategory(String id, String label) {
+		this.id = id;
+		this.label = label;
+		this.path = new Path(id);
+	}
+
+	void addDescriptor(IViewDescriptor descriptor) {
+		descriptors.add(descriptor);
+	}
+
+	@Override
+	public IViewDescriptor[] getViews() {
+		Collection<?> allowedViews = WorkbenchActivityHelper.restrictCollection(descriptors,
+				new ArrayList<>());
+		return allowedViews.toArray(new IViewDescriptor[allowedViews.size()]);
+	}
+
+	@Override
+	public String getId() {
+		return id;
+	}
+
+	@Override
+	public String getLabel() {
+		return label;
+	}
+
+	@Override
+	public IPath getPath() {
+		return path;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/ViewDescriptor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/ViewDescriptor.java
new file mode 100644
index 0000000..db472bd
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/ViewDescriptor.java
@@ -0,0 +1,144 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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
+ *     Markus Alexander Kuppe, Versant Corporation - bug #215797
+ *     Friederike Schertel <friederike@schertel.org> - Bug 478336
+ *******************************************************************************/
+package org.eclipse.ui.internal.registry;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.e4.ui.model.LocalizationHelper;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.descriptor.basic.MPartDescriptor;
+import org.eclipse.e4.ui.workbench.IResourceUtilities;
+import org.eclipse.e4.ui.workbench.swt.util.ISWTResourceUtilities;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.IPluginContribution;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.views.IViewDescriptor;
+
+public class ViewDescriptor implements IViewDescriptor, IPluginContribution {
+
+	private MApplication application;
+	private MPartDescriptor descriptor;
+	private IConfigurationElement element;
+	private String[] categoryPath;
+	private ImageDescriptor imageDescriptor;
+
+	public ViewDescriptor(MApplication application, MPartDescriptor descriptor,
+			IConfigurationElement element) {
+		this.application = application;
+		this.descriptor = descriptor;
+		this.element = element;
+
+		String category = descriptor.getCategory();
+		if (category != null) {
+			categoryPath = category.split("/"); //$NON-NLS-1$
+		}
+	}
+
+	@Override
+	public IViewPart createView() throws CoreException {
+		if (element == null) {
+			throw new CoreException(new Status(IStatus.ERROR, WorkbenchPlugin.PI_WORKBENCH,
+					"Unable to create an e4 view of id " + descriptor.getElementId())); //$NON-NLS-1$
+		}
+		return (IViewPart) element.createExecutableExtension("class"); //$NON-NLS-1$
+	}
+
+	@Override
+	public String[] getCategoryPath() {
+		return categoryPath;
+	}
+
+	@Override
+	public String getDescription() {
+		return element == null ? "" : RegistryReader.getDescription(element); //$NON-NLS-1$
+	}
+
+	@Override
+	public String getId() {
+		return descriptor.getElementId();
+	}
+
+	@Override
+	public ImageDescriptor getImageDescriptor() {
+		if (imageDescriptor == null) {
+			String iconURI = descriptor.getIconURI();
+			if (iconURI == null) {
+				// If the icon attribute was omitted, use the default one
+				IWorkbench workbench = (IWorkbench) application.getContext().get(
+						IWorkbench.class.getName());
+				imageDescriptor = workbench.getSharedImages().getImageDescriptor(
+						ISharedImages.IMG_DEF_VIEW);
+			} else {
+				ISWTResourceUtilities utility = (ISWTResourceUtilities) application.getContext()
+						.get(IResourceUtilities.class.getName());
+				imageDescriptor = utility.imageDescriptorFromURI(URI.createURI(iconURI));
+			}
+		}
+		return imageDescriptor;
+	}
+
+	@Override
+	public String getLabel() {
+		return LocalizationHelper.getLocalized(descriptor.getLabel(), descriptor,
+				application.getContext());
+	}
+
+	@Override
+	public float getFastViewWidthRatio() {
+		return 0;
+	}
+
+	@Override
+	public boolean getAllowMultiple() {
+		return descriptor.isAllowMultiple();
+	}
+
+	@Override
+	public boolean isRestorable() {
+		if (element == null) {
+			return false;
+		}
+
+		String string = element.getAttribute(IWorkbenchRegistryConstants.ATT_RESTORABLE);
+		return string == null ? true : Boolean.parseBoolean(string);
+	}
+
+	@Override
+	public <T> T getAdapter(Class<T> adapter) {
+		if (adapter != null && adapter.equals(IConfigurationElement.class)) {
+			return adapter.cast(getConfigurationElement());
+		}
+		return null;
+	}
+
+	public IConfigurationElement getConfigurationElement() {
+		return element;
+	}
+
+	@Override
+	public String getLocalId() {
+		return getId();
+	}
+
+	@Override
+	public String getPluginId() {
+		return getConfigurationElement().getNamespaceIdentifier();
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/ViewParameterValues.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/ViewParameterValues.java
new file mode 100644
index 0000000..5be70bd
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/ViewParameterValues.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.registry;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.commands.IParameterValues;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.views.IViewDescriptor;
+
+/**
+ * Provides the parameter values for the show view command.
+ *
+ * @since 3.1
+ */
+public final class ViewParameterValues implements IParameterValues {
+
+	@Override
+	public final Map getParameterValues() {
+		final Map values = new HashMap();
+
+		final IViewDescriptor[] views = PlatformUI.getWorkbench()
+				.getViewRegistry().getViews();
+		for (final IViewDescriptor view : views) {
+			values.put(view.getLabel(), view.getId());
+		}
+
+		return values;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/ViewRegistry.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/ViewRegistry.java
new file mode 100644
index 0000000..8dedc61
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/ViewRegistry.java
@@ -0,0 +1,253 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Jan-Hendrik Diederich, Bredex GmbH - bug 201052
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 430616, 441267, 441282, 445609, 441280, 472654
+ *     Simon Scholz <scholzsimon@vogella.com> - Bug 473845
+ *******************************************************************************/
+package org.eclipse.ui.internal.registry;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.e4.core.services.log.Logger;
+import org.eclipse.e4.ui.model.application.MApplication;
+import org.eclipse.e4.ui.model.application.descriptor.basic.MPartDescriptor;
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.activities.WorkbenchActivityHelper;
+import org.eclipse.ui.internal.IWorkbenchConstants;
+import org.eclipse.ui.internal.e4.compatibility.CompatibilityPart;
+import org.eclipse.ui.internal.menus.MenuHelper;
+import org.eclipse.ui.part.ViewPart;
+import org.eclipse.ui.views.IStickyViewDescriptor;
+import org.eclipse.ui.views.IViewCategory;
+import org.eclipse.ui.views.IViewDescriptor;
+import org.eclipse.ui.views.IViewRegistry;
+import org.osgi.framework.Bundle;
+
+public class ViewRegistry implements IViewRegistry {
+
+	public static final String VIEW_TAG = "View"; //$NON-NLS-1$
+
+	/**
+	 * This constant is used as key for persisting the original class for a
+	 * legacy {@link ViewPart} in the persisted state of a
+	 * {@link MPartDescriptor}.
+	 */
+	public static final String ORIGINAL_COMPATIBILITY_VIEW_CLASS = "originalCompatibilityViewClass"; //$NON-NLS-1$
+
+	/**
+	 * This constant is used as key for persisting the original bundle for a
+	 * legacy {@link ViewPart} in the persisted state of a
+	 * {@link MPartDescriptor}.
+	 */
+	public static final String ORIGINAL_COMPATIBILITY_VIEW_BUNDLE = "originalCompatibilityViewBundle"; //$NON-NLS-1$
+
+	@Inject
+	private MApplication application;
+
+	@Inject
+	private EModelService modelService;
+
+	@Inject
+	private IExtensionRegistry extensionRegistry;
+
+	@Inject
+	private IWorkbench workbench;
+
+	@Inject
+	Logger logger;
+
+	private Map<String, IViewDescriptor> descriptors = new HashMap<>();
+
+	private List<IStickyViewDescriptor> stickyDescriptors = new ArrayList<>();
+
+	private HashMap<String, ViewCategory> categories = new HashMap<>();
+
+	private Category miscCategory = new Category();
+
+	@PostConstruct
+	void postConstruct() {
+		IExtensionPoint point = extensionRegistry.getExtensionPoint("org.eclipse.ui.views"); //$NON-NLS-1$
+		for (IExtension extension : point.getExtensions()) {
+			// find the category first
+			for (IConfigurationElement element : extension.getConfigurationElements()) {
+				if (element.getName().equals(IWorkbenchRegistryConstants.TAG_CATEGORY)) {
+					ViewCategory category = new ViewCategory(
+							element.getAttribute(IWorkbenchRegistryConstants.ATT_ID),
+							element.getAttribute(IWorkbenchRegistryConstants.ATT_NAME));
+					categories.put(category.getId(), category);
+				} else if (element.getName().equals(IWorkbenchRegistryConstants.TAG_STICKYVIEW)) {
+					try {
+						stickyDescriptors.add(new StickyViewDescriptor(element));
+					} catch (CoreException e) {
+						// log an error since its not safe to open a dialog here
+						logger.error("Unable to create sticky view descriptor.", e.getStatus()); //$NON-NLS-1$
+					}
+				}
+			}
+		}
+		if (!categories.containsKey(miscCategory.getId())) {
+			categories.put(miscCategory.getId(), new ViewCategory(miscCategory.getId(),
+					miscCategory.getLabel()));
+		}
+
+		for (IExtension extension : point.getExtensions()) {
+			for (IConfigurationElement element : extension.getConfigurationElements()) {
+				if (element.getName().equals(IWorkbenchRegistryConstants.TAG_VIEW)) {
+					createDescriptor(element, false);
+				}
+				if (element.getName().equals(IWorkbenchRegistryConstants.TAG_E4VIEW)) {
+					createDescriptor(element, true);
+				}
+			}
+		}
+	}
+
+	private void createDescriptor(IConfigurationElement element, boolean e4View) {
+		String id = element.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+		MPartDescriptor descriptor = null;
+		List<MPartDescriptor> currentDescriptors = application.getDescriptors();
+		for (MPartDescriptor desc : currentDescriptors) {
+			// do we have a matching descriptor?
+			if (desc.getElementId().equals(id)) {
+				descriptor = desc;
+				break;
+			}
+		}
+		if (descriptor == null) { // create a new descriptor
+			descriptor = modelService.createModelElement(MPartDescriptor.class);
+			descriptor.setElementId(id);
+			application.getDescriptors().add(descriptor);
+		}
+		// ==> Update descriptor
+		descriptor.setLabel(element.getAttribute(IWorkbenchRegistryConstants.ATT_NAME));
+
+		List<String> tags = descriptor.getTags();
+		tags.add(VIEW_TAG);
+
+		descriptor.setCloseable(true);
+		descriptor.setAllowMultiple(Boolean.parseBoolean(element
+				.getAttribute(IWorkbenchRegistryConstants.ATT_ALLOW_MULTIPLE)));
+
+		// make view description available as tooltip
+		String viewDescription = RegistryReader.getDescription(element);
+		descriptor.setTooltip(viewDescription);
+
+		// Is this an E4 part or a legacy IViewPart ?
+		String clsSpec = element.getAttribute(IWorkbenchConstants.TAG_CLASS);
+		String implementationURI = CompatibilityPart.COMPATIBILITY_VIEW_URI;
+		if (e4View) {
+			implementationURI = "bundleclass://" + element.getContributor().getName() + "/" + clsSpec; //$NON-NLS-1$//$NON-NLS-2$
+		} else {
+			IExtension declaringExtension = element.getDeclaringExtension();
+			String name = declaringExtension.getContributor().getName();
+
+			Bundle bundle = Platform.getBundle(name);
+			// the indexOf operation removes potential additional information
+			// from the qualified classname
+			int colonIndex = clsSpec.indexOf(':');
+			String viewClass = colonIndex == -1 ? clsSpec : clsSpec.substring(0, colonIndex);
+			descriptor.getPersistedState().put(ORIGINAL_COMPATIBILITY_VIEW_CLASS, viewClass);
+			descriptor.getPersistedState().put(ORIGINAL_COMPATIBILITY_VIEW_BUNDLE, bundle.getSymbolicName());
+
+			boolean useDependencyInjection = Boolean
+					.parseBoolean(element.getAttribute(IWorkbenchConstants.TAG_USE_DEPENDENCY_INJECTION));
+			if (useDependencyInjection) {
+				descriptor.getTags().add(IWorkbenchConstants.TAG_USE_DEPENDENCY_INJECTION);
+			}
+		}
+		descriptor.setContributionURI(implementationURI);
+
+		String iconURI = MenuHelper.getIconURI(element, IWorkbenchRegistryConstants.ATT_ICON);
+		if (iconURI == null) {
+			descriptor.setIconURI(MenuHelper.getImageUrl(workbench.getSharedImages()
+					.getImageDescriptor(ISharedImages.IMG_DEF_VIEW)));
+		} else {
+			descriptor.setIconURI(iconURI);
+		}
+
+		String categoryId = element.getAttribute(IWorkbenchRegistryConstants.ATT_CATEGORY);
+		ViewCategory category = findCategory(categoryId);
+		if (category == null) {
+			category = findCategory(miscCategory.getId());
+		}
+		if (category != null) {
+			tags.add("categoryTag:" + category.getLabel()); //$NON-NLS-1$
+			descriptor.setCategory(category.getLabel());
+		}
+		// ==> End of update descriptor
+
+		ViewDescriptor viewDescriptor = new ViewDescriptor(application, descriptor, element);
+		descriptors.put(descriptor.getElementId(), viewDescriptor);
+		if (category != null) {
+			category.addDescriptor(viewDescriptor);
+		}
+	}
+
+	@Override
+	public IViewDescriptor find(String id) {
+		IViewDescriptor candidate = descriptors.get(id);
+		if (WorkbenchActivityHelper.restrictUseOf(candidate)) {
+			return null;
+		}
+		return candidate;
+	}
+
+	@Override
+	public IViewCategory[] getCategories() {
+		return categories.values().toArray(new IViewCategory[categories.size()]);
+	}
+
+	@Override
+	public IViewDescriptor[] getViews() {
+		Collection<?> allowedViews = WorkbenchActivityHelper.restrictCollection(
+				descriptors.values(), new ArrayList<>());
+		return allowedViews.toArray(new IViewDescriptor[allowedViews.size()]);
+	}
+
+	@Override
+	public IStickyViewDescriptor[] getStickyViews() {
+		Collection<?> allowedViews = WorkbenchActivityHelper.restrictCollection(stickyDescriptors,
+				new ArrayList<>());
+		return allowedViews.toArray(new IStickyViewDescriptor[allowedViews.size()]);
+	}
+
+	/**
+	 * Returns the {@link ViewCategory} for the given id or <code>null</code> if
+	 * one cannot be found or the id is <code>null</code>
+	 *
+	 * @param id
+	 *            the {@link ViewCategory} id
+	 * @return the {@link ViewCategory} with the given id or <code>null</code>
+	 */
+	public ViewCategory findCategory(String id) {
+		if (id == null) {
+			return categories.get(miscCategory.getId());
+		}
+		return categories.get(id);
+	}
+
+	public Category getMiscCategory() {
+		return miscCategory;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/WizardParameterValues.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/WizardParameterValues.java
new file mode 100644
index 0000000..a81928d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/WizardParameterValues.java
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.registry;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.eclipse.core.commands.IParameterValues;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.wizards.IWizardCategory;
+import org.eclipse.ui.wizards.IWizardDescriptor;
+import org.eclipse.ui.wizards.IWizardRegistry;
+
+/**
+ * Provides the parameter values for a show wizard command.
+ * <p>
+ * This class is only intended to be extended by the three inner classes (<code>Export</code>,
+ * <code>Import</code> and <code>New</code>) defined here.
+ * </p>
+ *
+ * @since 3.2
+ */
+public abstract class WizardParameterValues implements IParameterValues {
+
+	/**
+	 * Provides the parameter values for export wizards.
+	 */
+	public static final class Export extends WizardParameterValues {
+		@Override
+		protected IWizardRegistry getWizardRegistry() {
+			return PlatformUI.getWorkbench().getExportWizardRegistry();
+		}
+	}
+
+	/**
+	 * Provides the parameter values for import wizards.
+	 */
+	public static final class Import extends WizardParameterValues {
+		@Override
+		protected IWizardRegistry getWizardRegistry() {
+			return PlatformUI.getWorkbench().getImportWizardRegistry();
+		}
+	}
+
+	/**
+	 * Provides the parameter values for new wizards.
+	 */
+	public static final class New extends WizardParameterValues {
+		@Override
+		protected IWizardRegistry getWizardRegistry() {
+			return PlatformUI.getWorkbench().getNewWizardRegistry();
+		}
+	}
+
+	private void addParameterValues(Map values, IWizardCategory wizardCategory) {
+
+		for (final IWizardDescriptor wizardDescriptor : wizardCategory.getWizards()) {
+
+
+			// Note: using description instead of label for the name
+			// to reduce possibilities of key collision in the map
+			// final String name = wizardDescriptor.getDescription();
+
+			// by request
+			String name = wizardDescriptor.getLabel();
+			final String id = wizardDescriptor.getId();
+			final String value = (String) values.get(name);
+			if (value!=null && !value.equals(id)) {
+				name = name + " (" + id + ")"; //$NON-NLS-1$//$NON-NLS-2$
+			}
+			values.put(name, id);
+		}
+
+		for (final IWizardCategory childCategory : wizardCategory.getCategories()) {
+			addParameterValues(values, childCategory);
+		}
+	}
+
+	@Override
+	public Map getParameterValues() {
+		final Map values = new HashMap();
+
+		final IWizardRegistry wizardRegistry = getWizardRegistry();
+		addParameterValues(values, wizardRegistry.getRootCategory());
+
+		return values;
+	}
+
+	/**
+	 * Returns the wizard registry for the concrete
+	 * <code>WizardParameterValues</code> implementation class.
+	 *
+	 * @return The wizard registry for the concrete
+	 *         <code>WizardParameterValues</code> implementation class.
+	 */
+	protected abstract IWizardRegistry getWizardRegistry();
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/WizardsRegistryReader.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/WizardsRegistryReader.java
new file mode 100644
index 0000000..67d591e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/WizardsRegistryReader.java
@@ -0,0 +1,551 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Jan-Hendrik Diederich, Bredex GmbH - bug 201052
+ *******************************************************************************/
+package org.eclipse.ui.internal.registry;
+
+import com.ibm.icu.text.Collator;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.StringTokenizer;
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.ui.activities.WorkbenchActivityHelper;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.dialogs.WizardCollectionElement;
+import org.eclipse.ui.internal.dialogs.WorkbenchWizardElement;
+
+/**
+ *  Instances access the registry that is provided at creation time
+ *  in order to determine the contained Wizards
+ */
+public class WizardsRegistryReader extends RegistryReader {
+
+	private String pluginPoint;
+
+    private WizardCollectionElement wizardElements = null;
+
+    private ArrayList deferWizards = null;
+
+    private ArrayList deferCategories = null;
+
+    private Set deferPrimary;
+
+    // constants
+    /**
+     * Examples wizard category id
+     */
+    public final static String FULL_EXAMPLES_WIZARD_CATEGORY = "org.eclipse.ui.Examples";//$NON-NLS-1$
+    /**
+     * Other wizard category id
+     */
+    final public static String UNCATEGORIZED_WIZARD_CATEGORY = "org.eclipse.ui.Other";//$NON-NLS-1$
+    /**
+     * General wizard category id
+     */
+    final public static String GENERAL_WIZARD_CATEGORY = "org.eclipse.ui.Basic";	//$NON-NLS-1$
+
+    final private static String UNCATEGORIZED_WIZARD_CATEGORY_LABEL = WorkbenchMessages.get().NewWizardsRegistryReader_otherCategory;
+
+    private final static String CATEGORY_SEPARATOR = "/";//$NON-NLS-1$
+
+    private WorkbenchWizardElement[] primaryWizards = new WorkbenchWizardElement[0];
+
+    private class CategoryNode {
+        private Category category;
+
+        private String path;
+
+        CategoryNode(Category cat) {
+            category = cat;
+            path = ""; //$NON-NLS-1$
+            String[] categoryPath = category.getParentPath();
+            if (categoryPath != null) {
+                for (String parentPath : categoryPath) {
+                    path += parentPath + '/';
+                }
+            }
+            path += cat.getId();
+        }
+
+        String getPath() {
+            return path;
+        }
+
+        Category getCategory() {
+            return category;
+        }
+    }
+
+    private static final Comparator comparer = new Comparator() {
+        private Collator collator = Collator.getInstance();
+
+        @Override
+		public int compare(Object arg0, Object arg1) {
+            String s1 = ((CategoryNode) arg0).getPath();
+            String s2 = ((CategoryNode) arg1).getPath();
+            return collator.compare(s1, s2);
+        }
+    };
+
+	private boolean readAll = true;
+
+	private String plugin;
+
+    /**
+     *Create an instance of this class.
+     *
+     * @param pluginId the plugin id
+     * @param pluginPointId java.lang.String
+     */
+    public WizardsRegistryReader(String pluginId, String pluginPointId) {
+        pluginPoint = pluginPointId;
+        plugin = pluginId;
+    }
+
+	/*
+	 * <p> This implementation uses a defering strategy. For more info see
+	 * <code>readWizards</code>. </p>
+	 */
+    protected void addNewElementToResult(WorkbenchWizardElement element,
+            IConfigurationElement config) {
+        // TODO: can we remove the config parameter?
+        deferWizard(element);
+    }
+
+    /**
+     *
+     * @param parent
+     * @param element
+     * @since 3.1
+     */
+    private WizardCollectionElement createCollectionElement(WizardCollectionElement parent, IConfigurationElement element) {
+        WizardCollectionElement newElement = new WizardCollectionElement(
+				element, parent);
+
+        parent.add(newElement);
+        return newElement;
+	}
+    /**
+     *	Create and answer a new WizardCollectionElement, configured as a
+     *	child of <code>parent</code>
+     *
+     *	@return org.eclipse.ui.internal.model.WizardCollectionElement
+     *	@param parent org.eclipse.ui.internal.model.WizardCollectionElement
+     *  @param id the id of the new collection
+     *  @param pluginId the originating plugin id of the collection, if any. <code>null</code> otherwise.
+     *	@param label java.lang.String
+     */
+    protected WizardCollectionElement createCollectionElement(
+            WizardCollectionElement parent, String id, String pluginId,
+            String label) {
+        WizardCollectionElement newElement = new WizardCollectionElement(id,
+                pluginId, label, parent);
+
+        parent.add(newElement);
+        return newElement;
+    }
+
+    /**
+     * Creates empty element collection. Overrider to fill
+     * initial elements, if needed.
+     */
+    protected void createEmptyWizardCollection() {
+        wizardElements = new WizardCollectionElement("root", null, "root", null);//$NON-NLS-2$//$NON-NLS-1$
+    }
+
+    /**
+     * Set the initial wizard set for supplemental reading via dynamic plugin loading.
+     *
+     * @param wizards the wizards
+     * @since 3.1
+     */
+    public void setInitialCollection(WizardCollectionElement wizards) {
+    	wizardElements = wizards;
+    	readAll = false;
+    }
+
+    /**
+     * Stores a category element for deferred addition.
+     */
+    private void deferCategory(IConfigurationElement config) {
+        // Create category.
+        Category category = null;
+        try {
+            category = new Category(config);
+        } catch (CoreException e) {
+            WorkbenchPlugin.log("Cannot create category: ", e.getStatus());//$NON-NLS-1$
+            return;
+        }
+
+        // Defer for later processing.
+        if (deferCategories == null) {
+			deferCategories = new ArrayList(20);
+		}
+        deferCategories.add(category);
+    }
+
+
+    /**
+     * Stores a wizard element for deferred addition.
+     */
+    private void deferWizard(WorkbenchWizardElement element) {
+        if (deferWizards == null) {
+			deferWizards = new ArrayList(50);
+		}
+        deferWizards.add(element);
+    }
+
+    /**
+     * Finishes the addition of categories.  The categories are sorted and
+     * added in a root to depth traversal.
+     */
+    private void finishCategories() {
+        // If no categories just return.
+        if (deferCategories == null) {
+			return;
+		}
+
+        // Sort categories by flattened name.
+        CategoryNode[] flatArray = new CategoryNode[deferCategories.size()];
+        for (int i = 0; i < deferCategories.size(); i++) {
+            flatArray[i] = new CategoryNode((Category) deferCategories.get(i));
+        }
+        Collections.sort(Arrays.asList(flatArray), comparer);
+
+        // Add each category.
+        for (CategoryNode categoryNode : flatArray) {
+            Category cat = categoryNode.getCategory();
+            finishCategory(cat);
+        }
+
+        // Cleanup.
+        deferCategories = null;
+    }
+
+    /**
+     * Save new category definition.
+     */
+    private void finishCategory(Category category) {
+        String[] categoryPath = category.getParentPath();
+        WizardCollectionElement parent = wizardElements; // ie.- root
+
+        // Traverse down into parent category.
+        if (categoryPath != null) {
+            for (String parentPath : categoryPath) {
+                WizardCollectionElement tempElement = getChildWithID(parent,
+                        parentPath);
+                if (tempElement == null) {
+                    // The parent category is invalid.  By returning here the
+                    // category will be dropped and any wizard within the category
+                    // will be added to the "Other" category.
+                    return;
+                }
+                parent = tempElement;
+            }
+        }
+
+        // If another category already exists with the same id ignore this one.
+        Object test = getChildWithID(parent, category.getId());
+        if (test != null) {
+			return;
+		}
+
+        if (parent != null) {
+			createCollectionElement(parent, Adapters.adapt(category, IConfigurationElement.class));
+		}
+    }
+
+
+	/**
+     * Finishes the recognition of primary wizards.
+     */
+    private void finishPrimary() {
+        if (deferPrimary != null) {
+            ArrayList primary = new ArrayList();
+            for (Iterator i = deferPrimary.iterator(); i.hasNext();) {
+                String id = (String) i.next();
+                WorkbenchWizardElement element = wizardElements == null ? null : wizardElements.findWizard(id, true);
+                if (element != null) {
+                    primary.add(element);
+                }
+            }
+
+            primaryWizards = (WorkbenchWizardElement[]) primary
+                    .toArray(new WorkbenchWizardElement[primary.size()]);
+
+            deferPrimary = null;
+        }
+    }
+
+
+    /**
+     *	Insert the passed wizard element into the wizard collection appropriately
+     *	based upon its defining extension's CATEGORY tag value
+     *
+     *	@param element WorkbenchWizardElement
+     *	@param config configuration element
+     */
+    private void finishWizard(WorkbenchWizardElement element,
+            IConfigurationElement config) {
+        StringTokenizer familyTokenizer = new StringTokenizer(
+                getCategoryStringFor(config), CATEGORY_SEPARATOR);
+
+        // use the period-separated sections of the current Wizard's category
+        // to traverse through the NamedSolution "tree" that was previously created
+        WizardCollectionElement currentCollectionElement = wizardElements; // ie.- root
+        boolean moveToOther = false;
+
+        while (familyTokenizer.hasMoreElements()) {
+            WizardCollectionElement tempCollectionElement = getChildWithID(
+                    currentCollectionElement, familyTokenizer.nextToken());
+
+            if (tempCollectionElement == null) { // can't find the path; bump it to uncategorized
+                moveToOther = true;
+                break;
+            }
+            currentCollectionElement = tempCollectionElement;
+        }
+
+        if (moveToOther) {
+			moveElementToUncategorizedCategory(wizardElements, element);
+		} else {
+            currentCollectionElement.add(element);
+            element.setParent(currentCollectionElement);
+        }
+    }
+
+    /**
+     * Finishes the addition of wizards.  The wizards are processed and categorized.
+     */
+    private void finishWizards() {
+        if (deferWizards != null) {
+            Iterator iter = deferWizards.iterator();
+            while (iter.hasNext()) {
+                WorkbenchWizardElement wizard = (WorkbenchWizardElement) iter
+                        .next();
+                IConfigurationElement config = wizard.getConfigurationElement();
+                finishWizard(wizard, config);
+            }
+            deferWizards = null;
+        }
+    }
+
+    /**
+     *	Return the appropriate category (tree location) for this Wizard.
+     *	If a category is not specified then return a default one.
+     */
+    protected String getCategoryStringFor(IConfigurationElement config) {
+        String result = config.getAttribute(IWorkbenchRegistryConstants.TAG_CATEGORY);
+        if (result == null) {
+			result = UNCATEGORIZED_WIZARD_CATEGORY;
+		}
+
+        return result;
+    }
+
+    /**
+     *	Go through the children of  the passed parent and answer the child
+     *	with the passed name.  If no such child is found then return null.
+     *
+     *	@return org.eclipse.ui.internal.model.WizardCollectionElement
+     *	@param parent org.eclipse.ui.internal.model.WizardCollectionElement
+     *	@param id java.lang.String
+     */
+    protected WizardCollectionElement getChildWithID(
+            WizardCollectionElement parent, String id) {
+		for (Object child : parent.getChildren(null)) {
+			WizardCollectionElement currentChild = (WizardCollectionElement) child;
+            if (currentChild.getId().equals(id)) {
+				return currentChild;
+			}
+        }
+        return null;
+    }
+
+    /**
+     *	Moves given element to "Other" category, previously creating one if missing.
+     */
+    protected void moveElementToUncategorizedCategory(
+            WizardCollectionElement root, WorkbenchWizardElement element) {
+        WizardCollectionElement otherCategory = getChildWithID(root,
+                UNCATEGORIZED_WIZARD_CATEGORY);
+
+        if (otherCategory == null) {
+			otherCategory = createCollectionElement(root,
+                    UNCATEGORIZED_WIZARD_CATEGORY, null,
+                    UNCATEGORIZED_WIZARD_CATEGORY_LABEL);
+		}
+
+        otherCategory.add(element);
+        element.setParent(otherCategory);
+    }
+
+    /**
+     * Removes the empty categories from a wizard collection.
+     */
+    private void pruneEmptyCategories(WizardCollectionElement parent) {
+        Object[] children = parent.getChildren(null);
+        for (Object element : children) {
+            WizardCollectionElement child = (WizardCollectionElement) element;
+            pruneEmptyCategories(child);
+            boolean shouldPrune = child.getId().equals(FULL_EXAMPLES_WIZARD_CATEGORY);
+            if (child.isEmpty() && shouldPrune) {
+				parent.remove(child);
+			}
+        }
+    }
+
+    /**
+     * Implement this method to read element attributes.
+     */
+    @Override
+	public boolean readElement(IConfigurationElement element) {
+        if (element.getName().equals(IWorkbenchRegistryConstants.TAG_CATEGORY)) {
+            deferCategory(element);
+            return true;
+        } else if (element.getName().equals(IWorkbenchRegistryConstants.TAG_PRIMARYWIZARD)) {
+            if (deferPrimary == null) {
+				deferPrimary = new HashSet();
+			}
+            deferPrimary.add(element.getAttribute(IWorkbenchRegistryConstants.ATT_ID));
+
+            return true;
+        } else {
+            if (!element.getName().equals(IWorkbenchRegistryConstants.TAG_WIZARD)) {
+				return false;
+			}
+            WorkbenchWizardElement wizard = createWizardElement(element);
+            if (wizard != null) {
+				addNewElementToResult(wizard, element);
+			}
+            return true;
+        }
+    }
+
+    /**
+     * Reads the wizards in a registry.
+     * <p>
+     * This implementation uses a defering strategy.  All of the elements
+     * (categories, wizards) are read.  The categories are created as the read occurs.
+     * The wizards are just stored for later addition after the read completes.
+     * This ensures that wizard categorization is performed after all categories
+     * have been read.
+     * </p>
+     */
+    protected void readWizards() {
+    	if (readAll) {
+    	       if (!areWizardsRead()) {
+                createEmptyWizardCollection();
+                IExtensionRegistry registry = Platform.getExtensionRegistry();
+                readRegistry(registry, plugin, pluginPoint);
+            }
+    	}
+        finishCategories();
+        finishWizards();
+        finishPrimary();
+        if (wizardElements != null) {
+            pruneEmptyCategories(wizardElements);
+        }
+    }
+
+    /**
+     * Returns the list of wizards that are considered 'primary'.
+     *
+     * The return value for this method is cached since computing its value
+     * requires non-trivial work.
+     *
+     * @return the primary wizards
+     */
+    public WorkbenchWizardElement [] getPrimaryWizards() {
+        if (!areWizardsRead()) {
+            readWizards();
+        }
+        return (WorkbenchWizardElement[]) WorkbenchActivityHelper.restrictArray(primaryWizards);
+    }
+
+
+    /**
+     * Returns whether the wizards have been read already
+     */
+    protected boolean areWizardsRead() {
+        return wizardElements != null && readAll;
+    }
+
+    /**
+     * Returns a list of wizards, project and not.
+     *
+     * The return value for this method is cached since computing its value
+     * requires non-trivial work.
+     *
+     * @return the wizard collection
+     */
+    public WizardCollectionElement getWizardElements() {
+        if (!areWizardsRead()) {
+            readWizards();
+        }
+        return wizardElements;
+    }
+
+    protected Object[] getWizardCollectionElements() {
+        if (!areWizardsRead()) {
+            readWizards();
+        }
+        return wizardElements.getChildren();
+    }
+
+    /**
+     * Returns a new WorkbenchWizardElement configured according to the parameters
+     * contained in the passed Registry.
+     *
+     * May answer null if there was not enough information in the Extension to create
+     * an adequate wizard
+     */
+    protected WorkbenchWizardElement createWizardElement(
+            IConfigurationElement element) {
+        // WizardElements must have a name attribute
+        if (element.getAttribute(IWorkbenchRegistryConstants.ATT_NAME) == null) {
+            logMissingAttribute(element, IWorkbenchRegistryConstants.ATT_NAME);
+            return null;
+        }
+
+        if (getClassValue(element, IWorkbenchRegistryConstants.ATT_CLASS) == null) {
+            logMissingAttribute(element, IWorkbenchRegistryConstants.ATT_CLASS);
+            return null;
+        }
+        return new WorkbenchWizardElement(element);
+    }
+
+    /**
+     * Returns the first wizard with a given id.
+     *
+     * @param id wizard id to search for
+     * @return WorkbenchWizardElement matching the given id, if found; null otherwise
+     */
+    public WorkbenchWizardElement findWizard(String id) {
+		for (Object wizard : getWizardCollectionElements()) {
+            WizardCollectionElement collection = (WizardCollectionElement) wizard;
+            WorkbenchWizardElement element = collection.findWizard(id, true);
+            if (element != null && !WorkbenchActivityHelper.restrictUseOf(element)) {
+				return element;
+			}
+        }
+        return null;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/WorkingSetDescriptor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/WorkingSetDescriptor.java
new file mode 100644
index 0000000..6629c43
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/WorkingSetDescriptor.java
@@ -0,0 +1,319 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.registry;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.IPluginContribution;
+import org.eclipse.ui.IWorkingSetElementAdapter;
+import org.eclipse.ui.IWorkingSetUpdater;
+import org.eclipse.ui.dialogs.IWorkingSetPage;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+/**
+ * A working set descriptor stores the plugin registry data for
+ * a working set page extension.
+ *
+ * @since 2.0
+ */
+public class WorkingSetDescriptor implements IPluginContribution {
+    private String id;
+
+    private String name;
+
+    private String icon;
+
+    private String pageClassName;
+
+    private String updaterClassName;
+
+    private IConfigurationElement configElement;
+
+    private String[] classTypes;
+
+	private String[] adapterTypes;
+
+    private static final String ATT_ID = "id"; //$NON-NLS-1$
+
+    private static final String ATT_NAME = "name"; //$NON-NLS-1$
+
+    private static final String ATT_ICON = "icon"; //$NON-NLS-1$
+
+    private static final String ATT_PAGE_CLASS = "pageClass"; //$NON-NLS-1$
+
+    private static final String ATT_UPDATER_CLASS = "updaterClass";  //$NON-NLS-1$
+
+    private static final String ATT_ELEMENT_ADAPTER_CLASS = "elementAdapterClass";  //$NON-NLS-1$
+
+    private static final String TAG_APPLICABLE_TYPE = "applicableType"; //$NON-NLS-1$
+
+    /**
+     * Creates a descriptor from a configuration element.
+     *
+     * @param configElement configuration element to create a descriptor from
+     */
+    public WorkingSetDescriptor(IConfigurationElement configElement)
+            throws CoreException {
+        super();
+        this.configElement = configElement;
+        id = configElement.getAttribute(ATT_ID);
+        name = configElement.getAttribute(ATT_NAME);
+        icon = configElement.getAttribute(ATT_ICON);
+        pageClassName = configElement.getAttribute(ATT_PAGE_CLASS);
+        updaterClassName = configElement.getAttribute(ATT_UPDATER_CLASS);
+
+        if (name == null) {
+            throw new CoreException(new Status(IStatus.ERROR,
+                    WorkbenchPlugin.PI_WORKBENCH, 0,
+                    "Invalid extension (missing class name): " + id, //$NON-NLS-1$
+                    null));
+        }
+
+        IConfigurationElement[] containsChildren = configElement
+				.getChildren(TAG_APPLICABLE_TYPE);
+		if (containsChildren.length > 0) {
+			List byClassList = new ArrayList(containsChildren.length);
+			List byAdapterList = new ArrayList(containsChildren.length);
+			for (IConfigurationElement child : containsChildren) {
+				String className = child
+						.getAttribute(IWorkbenchRegistryConstants.ATT_CLASS);
+				if (className != null)
+					byClassList.add(className);
+				if ("true".equals(child.getAttribute(IWorkbenchRegistryConstants.ATT_ADAPTABLE)))  //$NON-NLS-1$
+					byAdapterList.add(className);
+			}
+			if (!byClassList.isEmpty()) {
+				classTypes = (String[]) byClassList.toArray(new String[byClassList
+						.size()]);
+				Arrays.sort(classTypes);
+			}
+
+			if (!byAdapterList.isEmpty()) {
+				adapterTypes = (String[]) byAdapterList.toArray(new String[byAdapterList
+						.size()]);
+				Arrays.sort(adapterTypes);
+			}
+		}
+    }
+
+    /**
+     * Returns the name space that declares this working set.
+     *
+     * @return the name space declaring this working set
+     */
+    public String getDeclaringNamespace() {
+    	return configElement.getNamespace();
+    }
+
+    /**
+	 * Return the namespace that contains the class referenced by the
+	 * updaterClass. May be the bundle that declared this extension or another
+	 * bundle that contains the referenced class.
+	 *
+	 * @return the namespace
+	 * @since 3.3
+	 */
+	public String getUpdaterNamespace() {
+		return WorkbenchPlugin.getBundleForExecutableExtension(configElement,
+				ATT_UPDATER_CLASS).getSymbolicName();
+	}
+
+    /**
+	 * Return the namespace that contains the class referenced by the
+	 * elementAdapterClass. May be the bundle that declared this extension or
+	 * another bundle that contains the referenced class.
+	 *
+	 * @return the namespace
+	 * @since 3.3
+	 */
+	public String getElementAdapterNamespace() {
+		return WorkbenchPlugin.getBundleForExecutableExtension(configElement,
+				ATT_UPDATER_CLASS).getSymbolicName();
+	}
+
+    /**
+	 * Creates a working set page from this extension descriptor.
+	 *
+	 * @return a working set page created from this extension descriptor.
+	 */
+    public IWorkingSetPage createWorkingSetPage() {
+        Object page = null;
+
+        if (pageClassName != null) {
+            try {
+                page = WorkbenchPlugin.createExtension(configElement,
+                        ATT_PAGE_CLASS);
+            } catch (CoreException exception) {
+                WorkbenchPlugin.log("Unable to create working set page: " + //$NON-NLS-1$
+                        pageClassName, exception.getStatus());
+            }
+        }
+        return (IWorkingSetPage) page;
+    }
+
+    /**
+     * Returns the page's icon
+     *
+     * @return the page's icon
+     */
+    public ImageDescriptor getIcon() {
+        if (icon == null) {
+			return null;
+		}
+
+        IExtension extension = configElement.getDeclaringExtension();
+        String extendingPluginId = extension.getNamespace();
+        return AbstractUIPlugin.imageDescriptorFromPlugin(extendingPluginId,
+                icon);
+    }
+
+    /**
+     * Returns the working set page id.
+     *
+     * @return the working set page id.
+     */
+    public String getId() {
+        return id;
+    }
+
+    /**
+     * Returns the working set page class name
+     *
+     * @return the working set page class name or <code>null</code> if
+     *  no page class name has been provided by the extension
+     */
+    public String getPageClassName() {
+        return pageClassName;
+    }
+
+    /**
+     * Returns the name of the working set element type the
+     * page works with.
+     *
+     * @return the working set element type name
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Returns the working set updater class name
+     *
+     * @return the working set updater class name or <code>null</code> if
+     *  no updater class name has been provided by the extension
+     */
+    public String getUpdaterClassName() {
+    	return updaterClassName;
+    }
+
+    /**
+	 * Creates a working set element adapter.
+	 *
+	 * @return the element adapter or <code>null</code> if no adapter has been
+	 *         declared
+	 */
+	public IWorkingSetElementAdapter createWorkingSetElementAdapter() {
+		if (!WorkbenchPlugin.hasExecutableExtension(configElement, ATT_ELEMENT_ADAPTER_CLASS))
+			return null;
+		IWorkingSetElementAdapter result = null;
+		try {
+			result = (IWorkingSetElementAdapter) WorkbenchPlugin
+					.createExtension(configElement, ATT_ELEMENT_ADAPTER_CLASS);
+		} catch (CoreException exception) {
+			WorkbenchPlugin.log("Unable to create working set element adapter: " + //$NON-NLS-1$
+					result, exception.getStatus());
+		}
+		return result;
+	}
+
+    /**
+	 * Creates a working set updater.
+	 *
+	 * @return the working set updater or <code>null</code> if no updater has
+	 *         been declared
+	 */
+    public IWorkingSetUpdater createWorkingSetUpdater() {
+    	if (updaterClassName == null) {
+			return null;
+		}
+    	IWorkingSetUpdater result = null;
+        try {
+            result = (IWorkingSetUpdater)WorkbenchPlugin.createExtension(configElement, ATT_UPDATER_CLASS);
+        } catch (CoreException exception) {
+            WorkbenchPlugin.log("Unable to create working set updater: " + //$NON-NLS-1$
+            	updaterClassName, exception.getStatus());
+        }
+        return result;
+    }
+
+    public boolean isUpdaterClassLoaded() {
+    	return WorkbenchPlugin.isBundleLoadedForExecutableExtension(configElement, ATT_UPDATER_CLASS);
+    }
+
+    public boolean isElementAdapterClassLoaded() {
+    	return WorkbenchPlugin.isBundleLoadedForExecutableExtension(configElement, ATT_ELEMENT_ADAPTER_CLASS);
+    }
+
+    /**
+     * Returns whether working sets based on this descriptor are editable.
+     *
+     * @return <code>true</code> if working sets based on this descriptor are editable; otherwise
+     *  <code>false</code>
+     *
+     * @since 3.1
+     */
+    public boolean isEditable() {
+        return getPageClassName() != null;
+    }
+
+	@Override
+	public String getLocalId() {
+		return getId();
+	}
+
+	@Override
+	public String getPluginId() {
+		return getDeclaringNamespace();
+	}
+
+	/**
+	 * Return the config element for this descriptor.
+	 *
+	 * @return the config element
+	 * @since 3.3
+	 */
+	public IConfigurationElement getConfigurationElement() {
+		return configElement;
+	}
+
+	/**
+	 * Return the description for this working set type.
+	 *
+	 * @return the description for this type. May be an empty string.
+	 * @since 3.4
+	 */
+	public String getDescription() {
+		String description = configElement
+				.getAttribute(IWorkbenchRegistryConstants.ATT_DESCRIPTION);
+		if (description == null)
+			description = ""; //$NON-NLS-1$
+		return description;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/WorkingSetRegistry.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/WorkingSetRegistry.java
new file mode 100644
index 0000000..5558333
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/WorkingSetRegistry.java
@@ -0,0 +1,226 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.registry;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.dynamichelpers.ExtensionTracker;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.dialogs.IWorkingSetPage;
+
+/**
+ * Stores working set descriptors for working set extensions.
+ */
+public class WorkingSetRegistry implements IExtensionChangeHandler {
+    // used in Workbench plugin.xml for default workingSet extension
+    // @issue this is an IDE specific working set page!
+    private static final String DEFAULT_PAGE_ID = "org.eclipse.ui.resourceWorkingSetPage"; //$NON-NLS-1$
+
+    private HashMap/*<String, WorkingSetDescriptor>*/ workingSetDescriptors = new HashMap();
+
+    /**
+	 *
+	 */
+	public WorkingSetRegistry() {
+		IExtensionTracker tracker = PlatformUI.getWorkbench()
+				.getExtensionTracker();
+		tracker.registerHandler(this, ExtensionTracker
+				.createExtensionPointFilter(getExtensionPointFilter()));
+
+	}
+
+	/**
+	 *
+	 * @return
+	 * @since 3.3
+	 */
+	private IExtensionPoint getExtensionPointFilter() {
+        // RAP [bm]: namespace
+        return Platform.getExtensionRegistry().getExtensionPoint(
+                PlatformUI.PLUGIN_EXTENSION_NAME_SPACE,
+                IWorkbenchRegistryConstants.PL_WORKINGSETS);
+	}
+
+    /**
+     * Adds a working set descriptor.
+     *
+     * @param descriptor working set descriptor to add. Must not
+     * 	exist in the registry yet.
+     */
+    public void addWorkingSetDescriptor(WorkingSetDescriptor descriptor) {
+		Assert.isTrue(!workingSetDescriptors.containsValue(descriptor),
+				"working set descriptor already registered"); //$NON-NLS-1$
+		IExtensionTracker tracker = PlatformUI.getWorkbench()
+				.getExtensionTracker();
+		tracker.registerObject(descriptor.getConfigurationElement()
+				.getDeclaringExtension(), descriptor,
+				IExtensionTracker.REF_WEAK);
+		workingSetDescriptors.put(descriptor.getId(), descriptor);
+	}
+
+    /**
+	 * Returns the default, resource based, working set page
+	 *
+	 * @return the default working set page.
+	 */
+    public IWorkingSetPage getDefaultWorkingSetPage() {
+        // @issue this will return the IDE resource working set page... not good for generic workbench
+        WorkingSetDescriptor descriptor = (WorkingSetDescriptor) workingSetDescriptors
+                .get(DEFAULT_PAGE_ID);
+
+        if (descriptor != null) {
+            return descriptor.createWorkingSetPage();
+        }
+        return null;
+    }
+
+    /**
+     * Returns the working set descriptor with the given id.
+     *
+     * @param pageId working set page id
+     * @return the working set descriptor with the given id.
+     */
+    public WorkingSetDescriptor getWorkingSetDescriptor(String pageId) {
+        return (WorkingSetDescriptor) workingSetDescriptors.get(pageId);
+    }
+
+    /**
+     * Returns an array of all working set descriptors.
+     *
+     * @return an array of all working set descriptors.
+     */
+    public WorkingSetDescriptor[] getWorkingSetDescriptors() {
+        return (WorkingSetDescriptor[]) workingSetDescriptors.values().toArray(
+                new WorkingSetDescriptor[workingSetDescriptors.size()]);
+    }
+
+    /**
+     * Returns an array of all working set descriptors having
+     * a page class attribute
+     *
+     * @return an array of all working set descriptors having a
+     * page class attribute
+     */
+    public WorkingSetDescriptor[] getNewPageWorkingSetDescriptors() {
+    	Collection descriptors= workingSetDescriptors.values();
+        List result= new ArrayList(descriptors.size());
+        for (Iterator iter= descriptors.iterator(); iter.hasNext();) {
+			WorkingSetDescriptor descriptor= (WorkingSetDescriptor)iter.next();
+			if (descriptor.getPageClassName() != null) {
+				result.add(descriptor);
+			}
+		}
+        return (WorkingSetDescriptor[])result.toArray(new WorkingSetDescriptor[result.size()]);
+    }
+
+    /**
+     * Returns <code>true</code> if there is a working set descriptor with
+     * a page class attribute. Otherwise <code>false</code> is returned.
+     *
+     * @return whether a descriptor with a page class attribute exists
+     */
+    public boolean hasNewPageWorkingSetDescriptor() {
+    	Collection descriptors= workingSetDescriptors.values();
+        for (Iterator iter= descriptors.iterator(); iter.hasNext();) {
+			WorkingSetDescriptor descriptor= (WorkingSetDescriptor)iter.next();
+			if (descriptor.getPageClassName() != null) {
+				return true;
+			}
+		}
+    	return false;
+    }
+
+    public WorkingSetDescriptor[] getUpdaterDescriptorsForNamespace(
+			String namespace) {
+    	if (namespace == null) // fix for Bug 84225
+    		return new WorkingSetDescriptor[0];
+		Collection descriptors = workingSetDescriptors.values();
+		List result = new ArrayList();
+		for (Iterator iter = descriptors.iterator(); iter.hasNext();) {
+			WorkingSetDescriptor descriptor = (WorkingSetDescriptor) iter
+					.next();
+			if (namespace.equals(descriptor.getUpdaterNamespace())) {
+				result.add(descriptor);
+			}
+		}
+		return (WorkingSetDescriptor[]) result
+				.toArray(new WorkingSetDescriptor[result.size()]);
+	}
+
+    public WorkingSetDescriptor[] getElementAdapterDescriptorsForNamespace(
+			String namespace) {
+    	if (namespace == null) // fix for Bug 84225
+    		return new WorkingSetDescriptor[0];
+		Collection descriptors = workingSetDescriptors.values();
+		List result = new ArrayList();
+		for (Iterator iter = descriptors.iterator(); iter.hasNext();) {
+			WorkingSetDescriptor descriptor = (WorkingSetDescriptor) iter
+					.next();
+			if (namespace.equals(descriptor.getDeclaringNamespace())) {
+				result.add(descriptor);
+			}
+		}
+		return (WorkingSetDescriptor[]) result
+				.toArray(new WorkingSetDescriptor[result.size()]);
+	}
+
+    /**
+     * Returns the working set page with the given id.
+     *
+     * @param pageId working set page id
+     * @return the working set page with the given id.
+     */
+    public IWorkingSetPage getWorkingSetPage(String pageId) {
+        WorkingSetDescriptor descriptor = (WorkingSetDescriptor) workingSetDescriptors
+                .get(pageId);
+
+        if (descriptor == null) {
+            return null;
+        }
+        return descriptor.createWorkingSetPage();
+    }
+
+    /**
+     * Loads the working set registry.
+     */
+    public void load() {
+        WorkingSetRegistryReader reader = new WorkingSetRegistryReader();
+        reader.readWorkingSets(Platform.getExtensionRegistry(), this);
+    }
+
+	@Override
+	public void addExtension(IExtensionTracker tracker, IExtension extension) {
+		WorkingSetRegistryReader reader = new WorkingSetRegistryReader(this);
+		for (IConfigurationElement element : extension.getConfigurationElements()) {
+			reader.readElement(element);
+		}
+	}
+
+	@Override
+	public void removeExtension(IExtension extension, Object[] objects) {
+		for (Object object : objects) {
+            if (object instanceof WorkingSetDescriptor) {
+                WorkingSetDescriptor desc = (WorkingSetDescriptor) object;
+                workingSetDescriptors.remove(desc.getId());
+            }
+        }
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/WorkingSetRegistryReader.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/WorkingSetRegistryReader.java
new file mode 100644
index 0000000..af7ad11
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/registry/WorkingSetRegistryReader.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.registry;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+
+/**
+ * A strategy to read working set extensions from the registry.
+ */
+public class WorkingSetRegistryReader extends RegistryReader {
+
+
+    private WorkingSetRegistry registry;
+
+    /**
+     * Create a new instance of this reader.
+     */
+    public WorkingSetRegistryReader() {
+        super();
+    }
+
+    /**
+     * Create a new instance of this reader.
+     *
+     * @param registry the registry to populate
+     */
+    public WorkingSetRegistryReader(WorkingSetRegistry registry) {
+        super();
+        this.registry = registry;
+    }
+
+    /**
+     * Overrides method in RegistryReader.
+     *
+     * @see RegistryReader#readElement(IConfigurationElement)
+     */
+    @Override
+	public boolean readElement(IConfigurationElement element) {
+        if (element.getName().equals(IWorkbenchRegistryConstants.TAG_WORKING_SET)) {
+            try {
+                WorkingSetDescriptor desc = new WorkingSetDescriptor(element);
+                registry.addWorkingSetDescriptor(desc);
+            } catch (CoreException e) {
+                // log an error since its not safe to open a dialog here
+                WorkbenchPlugin
+                        .log(
+                                "Unable to create working set descriptor.", e.getStatus());//$NON-NLS-1$
+            }
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Reads the working set extensions within a registry.
+     *
+     * @param in the plugin registry to read from
+     * @param out the working set registry to store read entries in.
+     */
+    public void readWorkingSets(IExtensionRegistry in, WorkingSetRegistry out) {
+        // RAP [bm]: namespace
+        readRegistry(in, PlatformUI.PLUGIN_EXTENSION_NAME_SPACE,
+                IWorkbenchRegistryConstants.PL_WORKINGSETS);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/ActionSetSourceProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/ActionSetSourceProvider.java
new file mode 100644
index 0000000..9dba4b1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/ActionSetSourceProvider.java
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.services;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.ui.AbstractSourceProvider;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.internal.ActionSetsEvent;
+import org.eclipse.ui.internal.menus.IActionSetsListener;
+import org.eclipse.ui.internal.registry.IActionSetDescriptor;
+import org.eclipse.ui.internal.util.Util;
+
+/**
+ * <p>
+ * A listener to changes in the action sets.
+ * </p>
+ * <p>
+ * This class is only intended for internal use within
+ * <code>org.eclipse.ui.workbench</code>.
+ * </p>
+ *
+ * @since 3.2
+ */
+public final class ActionSetSourceProvider extends AbstractSourceProvider
+		implements IActionSetsListener {
+
+	/**
+	 * The names of the sources supported by this source provider.
+	 */
+	private static final String[] PROVIDED_SOURCE_NAMES = new String[] { ISources.ACTIVE_ACTION_SETS_NAME };
+
+	/**
+	 * The action sets last seen as active by this source provider. This value
+	 * may be <code>null</code>.
+	 */
+	private IActionSetDescriptor[] activeActionSets;
+
+	public ActionSetSourceProvider() {
+		super();
+	}
+
+	@Override
+	public final void actionSetsChanged(final ActionSetsEvent event) {
+		final IActionSetDescriptor[] newActionSets = event.getNewActionSets();
+		if (!Util.equals(newActionSets, activeActionSets)) {
+			if (DEBUG) {
+				final StringBuffer message = new StringBuffer();
+				message.append("Action sets changed to ["); //$NON-NLS-1$
+				if (newActionSets != null) {
+					for (int i = 0; i < newActionSets.length; i++) {
+						message.append(newActionSets[i].getLabel());
+						if (i < newActionSets.length - 1) {
+							message.append(", "); //$NON-NLS-1$
+						}
+					}
+				}
+				message.append(']');
+				logDebuggingInfo(message.toString());
+			}
+
+			activeActionSets = newActionSets;
+			fireSourceChanged(ISources.ACTIVE_ACTION_SETS,
+					ISources.ACTIVE_ACTION_SETS_NAME, activeActionSets);
+
+		}
+	}
+
+	@Override
+	public final void dispose() {
+		activeActionSets = null;
+	}
+
+	@Override
+	public final Map getCurrentState() {
+		final Map currentState = new HashMap();
+		currentState.put(ISources.ACTIVE_ACTION_SETS_NAME, activeActionSets);
+		return currentState;
+	}
+
+	@Override
+	public final String[] getProvidedSourceNames() {
+		return PROVIDED_SOURCE_NAMES;
+	}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/EvaluationReference.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/EvaluationReference.java
new file mode 100644
index 0000000..5c34961
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/EvaluationReference.java
@@ -0,0 +1,132 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal.services;
+
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.e4.core.commands.ExpressionContext;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.contexts.RunAndTrack;
+import org.eclipse.e4.ui.internal.workbench.Activator;
+import org.eclipse.e4.ui.internal.workbench.Policy;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.ui.services.IEvaluationReference;
+
+/**
+ * @since 3.3
+ *
+ */
+public class EvaluationReference extends RunAndTrack implements IEvaluationReference {
+	final IEclipseContext context;
+	final Expression expression;
+	final IPropertyChangeListener listener;
+	final String property;
+	final int sourcePriority;
+	boolean cache;
+	boolean participating = true;
+	boolean postingChanges = true;
+	boolean hasRun = false;
+
+	public EvaluationReference(IEclipseContext context, Expression expression,
+			IPropertyChangeListener listener, String property) {
+		this.context = context;
+		this.expression = expression;
+		this.listener = listener;
+		this.property = property;
+		this.sourcePriority = SourcePriorityNameMapping.computeSourcePriority(expression);
+	}
+
+	@Override
+	public void clearResult() {
+	}
+
+	@Override
+	public Expression getExpression() {
+		return expression;
+	}
+
+	@Override
+	public int getSourcePriority() {
+		return sourcePriority;
+	}
+
+	@Override
+	public boolean evaluate(IEvaluationContext context) {
+		if (expression == null) {
+			cache = true;
+		} else {
+			try {
+				cache = expression.evaluate(context) != EvaluationResult.FALSE;
+			} catch (CoreException e) {
+			    Activator.trace(Policy.DEBUG_CMDS, "Failed to calculate active", e); //$NON-NLS-1$
+			}
+		}
+		return cache;
+	}
+
+	@Override
+	public void setResult(boolean result) {
+		cache = result;
+	}
+
+	@Override
+	public boolean changed(IEclipseContext context) {
+		if (!participating) {
+			return false;
+		}
+
+		evaluate();
+		return participating;
+	}
+
+	public void evaluate() {
+		boolean value = cache;
+		evaluate(new ExpressionContext(context));
+		if (!postingChanges) {
+			return;
+		}
+		if (!hasRun) {
+			getListener().propertyChange(
+					new PropertyChangeEvent(this, getProperty(), null, Boolean.valueOf(cache)));
+		} else if (!participating) {
+			getListener().propertyChange(
+					new PropertyChangeEvent(this, getProperty(), Boolean.valueOf(value), null));
+		}
+		if (value != cache) {
+			getListener().propertyChange(
+					new PropertyChangeEvent(this, getProperty(), Boolean.valueOf(value), Boolean
+							.valueOf(cache)));
+		}
+		hasRun = true;
+	}
+
+	@Override
+	public IPropertyChangeListener getListener() {
+		return listener;
+	}
+
+	@Override
+	public String getProperty() {
+		return property;
+	}
+
+	public void setPostingChanges(boolean b) {
+		postingChanges = b;
+	}
+
+	public boolean isPostingChanges() {
+		return postingChanges;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/EvaluationResultCache.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/EvaluationResultCache.java
new file mode 100644
index 0000000..cee4c8e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/EvaluationResultCache.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.services;
+
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.ui.ISources;
+
+/**
+ * <p>
+ * A token representing the activation or contribution of some expression-based
+ * element. This caches the evaluation result so that it is only re-computed as
+ * necessary.
+ * </p>
+ *
+ * @since 3.2
+ */
+public abstract class EvaluationResultCache implements IEvaluationResultCache {
+
+	/**
+	 * The previous computed evaluation result. If no evaluation result is
+	 * available, then this value is <code>null</code>.
+	 */
+	private EvaluationResult evaluationResult = null;
+
+	/**
+	 * The expression to evaluate. This value may be <code>null</code>, in
+	 * which case the evaluation result is always <code>true</code>.
+	 */
+	private final Expression expression;
+
+	/**
+	 * The priority that has been given to this expression.
+	 */
+	private final int sourcePriority;
+
+	/**
+	 * Constructs a new instance of <code>EvaluationResultCache</code>.
+	 *
+	 * @param expression
+	 *            The expression that must evaluate to <code>true</code>
+	 *            before this handler is active. This value may be
+	 *            <code>null</code> if it is always active.
+	 * @see ISources
+	 */
+	protected EvaluationResultCache(final Expression expression) {
+		this.expression = expression;
+		this.sourcePriority = SourcePriorityNameMapping
+				.computeSourcePriority(expression);
+	}
+
+	@Override
+	public final void clearResult() {
+		evaluationResult = null;
+	}
+
+	@Override
+	public final boolean evaluate(final IEvaluationContext context) {
+		if (expression == null) {
+			return true;
+		}
+
+		if (evaluationResult == null) {
+			try {
+				evaluationResult = expression.evaluate(context);
+			} catch (final CoreException e) {
+				/*
+				 * Swallow the exception. It simply means the variable is not
+				 * valid it some (most frequently, that the value is null). This
+				 * kind of information is not really useful to us, so we can
+				 * just treat it as null.
+				 */
+				evaluationResult = EvaluationResult.FALSE;
+				return false;
+			}
+		}
+
+		// return true if  the result is FALSE or NOT_LOADED
+		return evaluationResult != EvaluationResult.FALSE;
+	}
+
+	@Override
+	public final Expression getExpression() {
+		return expression;
+	}
+
+	@Override
+	public final int getSourcePriority() {
+		return sourcePriority;
+	}
+
+	@Override
+	public final void setResult(final boolean result) {
+		if (result) {
+			evaluationResult = EvaluationResult.TRUE;
+		} else {
+			evaluationResult = EvaluationResult.FALSE;
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/EvaluationResultCacheComparator.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/EvaluationResultCacheComparator.java
new file mode 100644
index 0000000..36a2000
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/EvaluationResultCacheComparator.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.services;
+
+import java.util.Comparator;
+
+import org.eclipse.ui.internal.util.Util;
+
+/**
+ * <p>
+ * Compares two evaluation result caches ({@link IEvaluationResultCache}). The
+ * cache with the lowest source priority is considered "greater". In the event
+ * of a tie, other characteristics are checked.
+ * </p>
+ * <p>
+ * This class is only intended for use within the
+ * <code>org.eclipse.ui.workbench</code> plug-in.
+ * </p>
+ *
+ * @since 3.2
+ *
+ */
+public final class EvaluationResultCacheComparator implements Comparator {
+
+	@Override
+	public final int compare(final Object object1, final Object object2) {
+		if (Util.equals(object2, object1)) {
+			return 0;
+		}
+
+		final IEvaluationResultCache cache1 = (IEvaluationResultCache) object1;
+		final IEvaluationResultCache cache2 = (IEvaluationResultCache) object2;
+		int comparison;
+
+		/*
+		 * Note: all of the comparisons are flipped intentionally. This allows
+		 * those items with greater values to appear earlier when using an
+		 * iterator.
+		 */
+		// if objects went to the trouble to implement Comparable
+		// we should use it ... this algorithm can accept a natural ordering
+		// that's not compatible with equals.
+		if (object1 instanceof Comparable && object2 instanceof Comparable) {
+			comparison = Util.compare((Comparable) object2,
+					(Comparable) object1);
+			if (comparison != 0) {
+				return comparison;
+			}
+		}
+
+		return Util.compareIdentity(cache2, cache1);
+	}
+}
+
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/EvaluationService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/EvaluationService.java
new file mode 100644
index 0000000..2c4aa4a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/EvaluationService.java
@@ -0,0 +1,348 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2016 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.services;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Map.Entry;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.ExpressionInfo;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.e4.core.commands.ExpressionContext;
+import org.eclipse.e4.core.contexts.ContextFunction;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.contexts.RunAndTrack;
+import org.eclipse.e4.core.services.events.IEventBroker;
+import org.eclipse.e4.ui.services.IServiceConstants;
+import org.eclipse.e4.ui.workbench.UIEvents;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.ISourceProvider;
+import org.eclipse.ui.ISourceProviderListener;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.services.IEvaluationReference;
+import org.eclipse.ui.services.IEvaluationService;
+
+/**
+ * @since 3.3
+ *
+ */
+public final class EvaluationService implements IEvaluationService {
+	public static final String DEFAULT_VAR = "org.eclipse.ui.internal.services.EvaluationService.default_var"; //$NON-NLS-1$
+	private static final String RE_EVAL = "org.eclipse.ui.internal.services.EvaluationService.evaluate"; //$NON-NLS-1$
+	private boolean evaluate = false;
+	private ExpressionContext legacyContext;
+	private IEclipseContext context;
+	private IEclipseContext ratContext;
+	private int notifying = 0;
+
+	private ListenerList<IPropertyChangeListener> serviceListeners = new ListenerList<>(ListenerList.IDENTITY);
+	ArrayList<ISourceProvider> sourceProviders = new ArrayList<>();
+	LinkedList<EvaluationReference> refs = new LinkedList<>();
+	private ISourceProviderListener contextUpdater;
+
+	private HashSet<String> ratVariables = new HashSet<>();
+	private RunAndTrack ratUpdater = new RunAndTrack() {
+		@Override
+		public boolean changed(IEclipseContext context) {
+			context.get(RE_EVAL);
+			String[] vars = ratVariables.toArray(new String[ratVariables.size()]);
+			for (String var : vars) {
+				Object value = context.getActive(var);
+				if (value == null) {
+					ratContext.remove(var);
+				} else {
+					ratContext.set(var, value);
+				}
+			}
+			// This ties tool item enablement to variable changes that can
+			// effect the enablement.
+			getEventBroker().send(UIEvents.REQUEST_ENABLEMENT_UPDATE_TOPIC, UIEvents.ALL_ELEMENT_ID);
+			return true;
+		}
+	};
+
+	private HashSet<String> variableFilter = new HashSet<>();
+	private IEventBroker eventBroker;
+
+	public EvaluationService(IEclipseContext c) {
+		context = c;
+		ratContext = context.getParent().createChild(getClass().getName());
+		legacyContext = new ExpressionContext(context);
+		ExpressionContext.defaultVariableConverter = new ContextFunction() {
+			@Override
+			public Object compute(IEclipseContext context, String contextKey) {
+				Object defaultVariable = context.getLocal(DEFAULT_VAR);
+				if (defaultVariable != null
+						&& defaultVariable != IEvaluationContext.UNDEFINED_VARIABLE) {
+					return defaultVariable;
+				}
+				defaultVariable = context.getActive(IServiceConstants.ACTIVE_SELECTION);
+				if (defaultVariable instanceof IStructuredSelection) {
+					final IStructuredSelection selection = (IStructuredSelection) defaultVariable;
+					return selection.toList();
+				} else if ((defaultVariable instanceof ISelection)
+						&& (!((ISelection) defaultVariable).isEmpty())) {
+					return Collections.singleton(defaultVariable);
+				}
+				return null;
+			}
+		};
+		contextUpdater = new ISourceProviderListener() {
+
+			@Override
+			public void sourceChanged(int sourcePriority, String sourceName, Object sourceValue) {
+				changeVariable(sourceName, sourceValue);
+			}
+
+			@Override
+			public void sourceChanged(int sourcePriority, Map sourceValuesByName) {
+				Iterator i = sourceValuesByName.entrySet().iterator();
+				while (i.hasNext()) {
+					final Map.Entry entry = (Entry) i.next();
+					changeVariable((String) entry.getKey(), entry.getValue());
+				}
+			}
+		};
+		variableFilter.addAll(Arrays.asList(new String[] { ISources.ACTIVE_WORKBENCH_WINDOW_NAME,
+				ISources.ACTIVE_WORKBENCH_WINDOW_SHELL_NAME, ISources.ACTIVE_EDITOR_ID_NAME,
+				ISources.ACTIVE_EDITOR_INPUT_NAME, ISources.SHOW_IN_INPUT,
+				ISources.SHOW_IN_SELECTION, ISources.ACTIVE_PART_NAME,
+				ISources.ACTIVE_PART_ID_NAME, ISources.ACTIVE_SITE_NAME,
+				ISources.ACTIVE_CONTEXT_NAME, ISources.ACTIVE_CURRENT_SELECTION_NAME }));
+		context.runAndTrack(ratUpdater);
+	}
+
+	private void contextEvaluate() {
+		evaluate = !evaluate;
+		context.set(RE_EVAL, Boolean.valueOf(evaluate));
+	}
+
+	protected final void changeVariable(final String name, final Object value) {
+		if (name == null || variableFilter.contains(name)) {
+			return;
+		}
+		if (value == null) {
+			legacyContext.removeVariable(name);
+		} else {
+			legacyContext.addVariable(name, value);
+		}
+	}
+	@Override
+	public void addSourceProvider(ISourceProvider provider) {
+		sourceProviders.add(provider);
+		provider.addSourceProviderListener(contextUpdater);
+		final Map currentState = provider.getCurrentState();
+		final Iterator variableItr = currentState.entrySet().iterator();
+		while (variableItr.hasNext()) {
+			final Map.Entry entry = (Map.Entry) variableItr.next();
+			final String variableName = (String) entry.getKey();
+			final Object variableValue = entry.getValue();
+
+			/*
+			 * Bug 84056. If we update the active workbench window, then we risk
+			 * falling back to that shell when the active shell has registered
+			 * as "none".
+			 */
+			if ((variableName != null)
+					&& (!ISources.ACTIVE_WORKBENCH_WINDOW_SHELL_NAME.equals(variableName))) {
+				changeVariable(variableName, variableValue);
+			}
+		}
+		contextEvaluate();
+	}
+
+	@Override
+	public void removeSourceProvider(ISourceProvider provider) {
+		provider.removeSourceProviderListener(contextUpdater);
+		sourceProviders.remove(provider);
+
+		final Map currentState = provider.getCurrentState();
+		final Iterator variableItr = currentState.entrySet().iterator();
+		while (variableItr.hasNext()) {
+			final Map.Entry entry = (Map.Entry) variableItr.next();
+			final String variableName = (String) entry.getKey();
+			changeVariable(variableName, null);
+		}
+		contextEvaluate();
+	}
+
+	@Override
+	public void dispose() {
+		for (EvaluationReference ref : refs) {
+			invalidate(ref, false);
+		}
+		refs.clear();
+		serviceListeners.clear();
+	}
+
+	@Override
+	public void addServiceListener(IPropertyChangeListener listener) {
+		serviceListeners.add(listener);
+	}
+
+	@Override
+	public void removeServiceListener(IPropertyChangeListener listener) {
+		serviceListeners.remove(listener);
+	}
+
+	@Override
+	public IEvaluationReference addEvaluationListener(Expression expression,
+			IPropertyChangeListener listener, String property) {
+		EvaluationReference ref = new EvaluationReference(ratContext, expression, listener,
+				property);
+		addEvaluationReference(ref);
+		return ref;
+	}
+
+	@Override
+	public void addEvaluationReference(IEvaluationReference ref) {
+		EvaluationReference eref = (EvaluationReference) ref;
+		refs.add(eref);
+		boolean changed = false;
+		if (eref.getExpression() != null) {
+			ExpressionInfo info = new ExpressionInfo();
+			eref.getExpression().collectExpressionInfo(info);
+			for (String varName : info.getAccessedVariableNames()) {
+				if (ratVariables.add(varName)) {
+					changed = true;
+				}
+			}
+
+			if (info.hasDefaultVariableAccess()
+					&& ratVariables.add(IServiceConstants.ACTIVE_SELECTION)) {
+				changed = true;
+			}
+		}
+		if (changed) {
+			contextEvaluate();
+		}
+		eref.participating = true;
+		ratContext.runAndTrack(eref);
+	}
+
+	private void invalidate(IEvaluationReference ref, boolean remove) {
+		if (remove) {
+			refs.remove(ref);
+		}
+		EvaluationReference eref = (EvaluationReference) ref;
+		eref.participating = false;
+		eref.evaluate();
+		eref.hasRun = false;
+		contextEvaluate();
+	}
+
+	@Override
+	public void removeEvaluationListener(IEvaluationReference ref) {
+		invalidate(ref, true);
+	}
+
+	@Override
+	public IEvaluationContext getCurrentState() {
+		return legacyContext;
+	}
+
+	@Override
+	public void requestEvaluation(String propertyName) {
+		// Trigger evaluation of properties via context
+		String pokeVar = propertyName + ".evaluationServiceLink"; //$NON-NLS-1$
+		context.remove(pokeVar);
+		context.set(pokeVar, "link"); //$NON-NLS-1$
+
+		String[] sourceNames = new String[] { propertyName };
+		startSourceChange(sourceNames);
+		for (EvaluationReference ref : refs) {
+			Expression expr = ref.getExpression();
+			if (expr != null) {
+				boolean evaluated = false;
+				ExpressionInfo info = expr.computeExpressionInfo();
+				String[] names = info.getAccessedPropertyNames();
+				for (String name : names) {
+					if (propertyName.equals(name)) {
+						evaluated = true;
+						ref.evaluate();
+						break;
+					}
+				}
+				if (!evaluated) {
+					names = info.getAccessedVariableNames();
+					for (String name : names) {
+						if (propertyName.equals(name)) {
+							evaluated = true;
+							ref.evaluate();
+							break;
+						}
+					}
+				}
+			}
+		}
+		endSourceChange(sourceNames);
+		eventBroker.send(UIEvents.REQUEST_ENABLEMENT_UPDATE_TOPIC, UIEvents.ALL_ELEMENT_ID);
+	}
+
+	/**
+	 * @param sourceNames
+	 */
+	private void startSourceChange(final String[] sourceNames) {
+		notifying++;
+		if (notifying == 1) {
+			fireServiceChange(IEvaluationService.PROP_NOTIFYING, Boolean.FALSE, Boolean.TRUE);
+		}
+	}
+
+	/**
+	 * @param sourceNames
+	 */
+	private void endSourceChange(final String[] sourceNames) {
+		if (notifying == 1) {
+			fireServiceChange(IEvaluationService.PROP_NOTIFYING, Boolean.TRUE, Boolean.FALSE);
+		}
+		notifying--;
+	}
+
+	private void fireServiceChange(final String property, final Object oldValue,
+			final Object newValue) {
+		for (final IPropertyChangeListener listener : serviceListeners) {
+			SafeRunner.run(new ISafeRunnable() {
+				@Override
+				public void handleException(Throwable exception) {
+					WorkbenchPlugin.log(exception);
+				}
+
+				@Override
+				public void run() throws Exception {
+					listener.propertyChange(new PropertyChangeEvent(EvaluationService.this,
+							property, oldValue, newValue));
+				}
+			});
+		}
+	}
+
+	IEventBroker getEventBroker() {
+		if (eventBroker == null) {
+			eventBroker = context.get(IEventBroker.class);
+		}
+		return eventBroker;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/EvaluationServiceFactory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/EvaluationServiceFactory.java
new file mode 100644
index 0000000..cc1a596
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/EvaluationServiceFactory.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2015 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.ui.internal.services;
+
+import org.eclipse.ui.services.AbstractServiceFactory;
+import org.eclipse.ui.services.IEvaluationService;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * @since 3.4
+ *
+ */
+public class EvaluationServiceFactory extends AbstractServiceFactory {
+
+	@Override
+	public Object create(Class serviceInterface, IServiceLocator parentLocator,
+			IServiceLocator locator) {
+		if (!IEvaluationService.class.equals(serviceInterface)) {
+			return null;
+		}
+		Object parent = parentLocator.getService(serviceInterface);
+		if (parent == null) {
+			return null;
+		}
+		return new SlaveEvaluationService((IEvaluationService)parent);
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/ExpressionAuthority.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/ExpressionAuthority.java
new file mode 100644
index 0000000..c8601c6
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/ExpressionAuthority.java
@@ -0,0 +1,360 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.services;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.eclipse.core.expressions.EvaluationContext;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.ISourceProvider;
+import org.eclipse.ui.ISourceProviderListener;
+import org.eclipse.ui.ISources;
+
+/**
+ * <p>
+ * Provides common functionality for evaluating expressions and listening to
+ * {@link ISourceProvider} (i.e., the common event framework for commands).
+ * </p>
+ * <p>
+ * This class is not intended for use outside of the
+ * <code>org.eclipse.ui.workbench</code> plug-in.
+ * </p>
+ *
+ * @since 3.2
+ * @see ISourceProvider
+ * @see ISources
+ * @see Expression
+ * @see IEvaluationContext
+ */
+public abstract class ExpressionAuthority implements ISourceProviderListener {
+
+	/**
+	 * The evaluation context instance to use when evaluating expression. This
+	 * context is shared, and so all calls into <code>sourceChanged</code>
+	 * must happen on the event thread.
+	 */
+	private final IEvaluationContext context;
+
+	/**
+	 * The current state of this authority. This is a child of the
+	 * {@link #context} that has been given the selection as the default
+	 * variable. This value is cleared to <code>null</code> whenever the
+	 * selection changes.
+	 */
+	private IEvaluationContext currentState = null;
+
+	/**
+	 * The collection of source providers used by this authority. This
+	 * collection is consulted whenever a contribution is made. This collection
+	 * only contains instances of <code>ISourceProvider</code>.
+	 */
+	private final Collection providers = new ArrayList();
+
+	/**
+	 * Constructs a new instance of <code>ExpressionAuthority</code>.
+	 */
+	protected ExpressionAuthority() {
+		context = new EvaluationContext(null, this);
+		context.setAllowPluginActivation(true);
+		context.addVariable("org.eclipse.core.runtime.Platform", Platform.class); //$NON-NLS-1$
+		// this is not as useful as it appears
+		// context.addVariable("java.lang.System", System.class); //$NON-NLS-1$
+	}
+
+	/**
+	 * Adds a source provider to a list of providers to check when updating.
+	 * This also attaches this authority as a listener to the provider.
+	 *
+	 * @param provider
+	 *            The provider to add; must not be <code>null</code>.
+	 */
+	public final void addSourceProvider(final ISourceProvider provider) {
+		provider.addSourceProviderListener(this);
+		providers.add(provider);
+
+		// Update the current state.
+		final Map currentState = provider.getCurrentState();
+		final Iterator variableItr = currentState.entrySet().iterator();
+		while (variableItr.hasNext()) {
+			final Map.Entry entry = (Map.Entry) variableItr.next();
+			final String variableName = (String) entry.getKey();
+			final Object variableValue = entry.getValue();
+
+			/*
+			 * Bug 84056. If we update the active workbench window, then we risk
+			 * falling back to that shell when the active shell has registered
+			 * as "none".
+			 */
+			if ((variableName != null)
+					&& (!ISources.ACTIVE_WORKBENCH_WINDOW_SHELL_NAME
+							.equals(variableName))) {
+				changeVariable(variableName, variableValue);
+			}
+		}
+		sourceChanged(0, currentState);
+	}
+
+	/**
+	 * Removes all of the source provider listeners. Subclasses may extend, but
+	 * must not override.
+	 */
+	public void dispose() {
+		final Iterator providerItr = providers.iterator();
+		while (providerItr.hasNext()) {
+			final ISourceProvider provider = (ISourceProvider) providerItr
+					.next();
+			provider.removeSourceProviderListener(this);
+		}
+
+		providers.clear();
+	}
+
+	/**
+	 * Returns whether at least one of the <code>IEvaluationResultCache</code>
+	 * instances in <code>collection</code> evaluates to <code>true</code>.
+	 *
+	 * @param collection
+	 *            The evaluation result caches to check; must not be
+	 *            <code>null</code>, but may be empty.
+	 * @return <code>true</code> if there is at least one expression that
+	 *         evaluates to <code>true</code>; <code>false</code>
+	 *         otherwise.
+	 */
+	protected final boolean evaluate(final Collection collection) {
+		final Iterator iterator = collection.iterator();
+		while (iterator.hasNext()) {
+			final IEvaluationResultCache cache = (IEvaluationResultCache) iterator
+					.next();
+			if (evaluate(cache)) {
+				return true;
+			}
+		}
+
+		return false;
+	}
+
+	/**
+	 * Returns whether the <code>IEvaluationResultCache</code> evaluates to
+	 * <code>true</code>.
+	 *
+	 * @param expression
+	 *            The evaluation result cache to check; must not be
+	 *            <code>null</code>.
+	 * @return <code>true</code> if the expression evaluates to
+	 *         <code>true</code>; <code>false</code> otherwise.
+	 */
+	protected final boolean evaluate(final IEvaluationResultCache expression) {
+		final IEvaluationContext contextWithDefaultVariable = getCurrentState();
+		return expression.evaluate(contextWithDefaultVariable);
+	}
+
+	/**
+	 * Creates a new evaluation context based on the current evaluation context
+	 * (i.e., the current state), and places the current selection as the
+	 * default variable.
+	 *
+	 * @return An evaluation context that can be used for evaluating
+	 *         expressions; never <code>null</code>.
+	 */
+	public final IEvaluationContext getCurrentState() {
+		if (currentState == null) {
+			final Object defaultVariable = context
+					.getVariable(ISources.ACTIVE_CURRENT_SELECTION_NAME);
+			final IEvaluationContext contextWithDefaultVariable;
+			if (defaultVariable instanceof IStructuredSelection) {
+				final IStructuredSelection selection = (IStructuredSelection) defaultVariable;
+				contextWithDefaultVariable = new EvaluationContext(context,
+						selection.toList());
+			} else if ((defaultVariable instanceof ISelection)
+					&& (!((ISelection) defaultVariable).isEmpty())) {
+				contextWithDefaultVariable = new EvaluationContext(context,
+						Collections.singleton(defaultVariable));
+			} else {
+				contextWithDefaultVariable = new EvaluationContext(context,
+						Collections.EMPTY_LIST);
+			}
+			currentState = contextWithDefaultVariable;
+		}
+
+		return currentState;
+	}
+
+	/**
+	 * Returns the variable of the given name.
+	 *
+	 * @param name
+	 *            The name of the variable to get; must not be <code>null</code>.
+	 * @return The variable of the given name; <code>null</code> if none.
+	 */
+	protected final Object getVariable(final String name) {
+		return context.getVariable(name);
+	}
+
+	/**
+	 * Removes this source provider from the list, and detaches this authority
+	 * as a listener.
+	 *
+	 * @param provider
+	 *            The provider to remove; must not be <code>null</code>.
+	 */
+	public final void removeSourceProvider(final ISourceProvider provider) {
+		provider.removeSourceProviderListener(this);
+		providers.remove(provider);
+
+		final Map currentState = provider.getCurrentState();
+		final Iterator variableItr = currentState.entrySet().iterator();
+		while (variableItr.hasNext()) {
+			final Map.Entry entry = (Map.Entry) variableItr.next();
+			final String variableName = (String) entry.getKey();
+			changeVariable(variableName, null);
+		}
+	}
+
+	/**
+	 * Changes the variable of the given name. If the <code>value</code> is
+	 * <code>null</code>, then the variable is removed.
+	 *
+	 * @param name
+	 *            The name of the variable to change; must not be
+	 *            <code>null</code>.
+	 * @param value
+	 *            The new value; the variable should be removed if this is
+	 *            <code>null</code>.
+	 */
+	protected final void changeVariable(final String name, final Object value) {
+		if (value == null) {
+			context.removeVariable(name);
+		} else {
+			context.addVariable(name, value);
+		}
+	}
+
+	/**
+	 * Carries out the actual source change notification. It assumed that by the
+	 * time this method is called, <code>getEvaluationContext()</code> is
+	 * up-to-date with the current state of the application.
+	 *
+	 * @param sourcePriority
+	 *            A bit mask of all the source priorities that have changed.
+	 */
+	protected abstract void sourceChanged(final int sourcePriority);
+
+	/**
+	 * Similar to sourceChanged(int) this notifies the subclass about the
+	 * change, but using the array of source names that changed instead of the
+	 * priority ... int based.
+	 * <p>
+	 * Clients may override this method.
+	 * </p>
+	 *
+	 * @param sourceNames
+	 *            The array of names that changed.
+	 * @since 3.3
+	 */
+	protected void sourceChanged(final String[] sourceNames) {
+		// this is a no-op, since we're late in the game
+	}
+
+	@Override
+	public final void sourceChanged(final int sourcePriority,
+			final Map sourceValuesByName) {
+		// If the selection has changed, invalidate the current state.
+		if (sourceValuesByName
+				.containsKey(ISources.ACTIVE_CURRENT_SELECTION_NAME)) {
+			currentState = null;
+		}
+
+		final Iterator entryItr = sourceValuesByName.entrySet().iterator();
+		while (entryItr.hasNext()) {
+			final Map.Entry entry = (Map.Entry) entryItr.next();
+			final String sourceName = (String) entry.getKey();
+			final Object sourceValue = entry.getValue();
+			updateEvaluationContext(sourceName, sourceValue);
+		}
+		sourceChanged(sourcePriority, (String[]) sourceValuesByName.keySet()
+				.toArray(new String[0]));
+	}
+
+	@Override
+	public final void sourceChanged(final int sourcePriority,
+			final String sourceName, final Object sourceValue) {
+		// If the selection has changed, invalidate the current state.
+		if (ISources.ACTIVE_CURRENT_SELECTION_NAME.equals(sourceName)) {
+			currentState = null;
+		}
+
+		updateEvaluationContext(sourceName, sourceValue);
+		sourceChanged(sourcePriority, new String[] { sourceName });
+	}
+
+	/**
+	 * @param sourcePriority
+	 * @param strings
+	 */
+	private void sourceChanged(int sourcePriority, String[] sourceNames) {
+		sourceChanged(sourcePriority);
+		sourceChanged(sourceNames);
+	}
+
+	/**
+	 * Updates the evaluation context with the current state from all of the
+	 * source providers.
+	 */
+	protected final void updateCurrentState() {
+		final Iterator providerItr = providers.iterator();
+		while (providerItr.hasNext()) {
+			final ISourceProvider provider = (ISourceProvider) providerItr
+					.next();
+			final Map currentState = provider.getCurrentState();
+			final Iterator variableItr = currentState.entrySet().iterator();
+			while (variableItr.hasNext()) {
+				final Map.Entry entry = (Map.Entry) variableItr.next();
+				final String variableName = (String) entry.getKey();
+				final Object variableValue = entry.getValue();
+				/*
+				 * Bug 84056. If we update the active workbench window, then we
+				 * risk falling back to that shell when the active shell has
+				 * registered as "none".
+				 */
+				if ((variableName != null)
+						&& (!ISources.ACTIVE_WORKBENCH_WINDOW_SHELL_NAME
+								.equals(variableName))) {
+					changeVariable(variableName, variableValue);
+				}
+			}
+		}
+	}
+
+	/**
+	 * Updates this authority's evaluation context.
+	 *
+	 * @param name
+	 *            The name of the variable to update; must not be
+	 *            <code>null</code>.
+	 * @param value
+	 *            The new value of the variable. If this value is
+	 *            <code>null</code>, then the variable is removed.
+	 */
+	protected void updateEvaluationContext(final String name, final Object value) {
+		if (name != null) {
+			changeVariable(name, value);
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/IEvaluationResultCache.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/IEvaluationResultCache.java
new file mode 100644
index 0000000..37809f8
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/IEvaluationResultCache.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.services;
+
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.ui.ISources;
+
+/**
+ * <p>
+ * A cache of the result of an expression. This also provides the source
+ * priority for the expression.
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented or extended by clients.
+ * </p>
+ *
+ * @since 3.2
+ * @see org.eclipse.ui.ISources
+ * @see org.eclipse.ui.ISourceProvider
+ */
+public interface IEvaluationResultCache {
+
+	/**
+	 * Clears the cached computation of the <code>evaluate</code> method, if
+	 * any. This method is only intended for internal use. It provides a
+	 * mechanism by which <code>ISourceProvider</code> events can invalidate
+	 * state on a <code>IEvaluationResultCache</code> instance.
+	 */
+	public void clearResult();
+
+	/**
+	 * Returns the expression controlling the activation or visibility of this
+	 * item.
+	 *
+	 * @return The expression associated with this item; may be
+	 *         <code>null</code>.
+	 */
+	public Expression getExpression();
+
+	/**
+	 * Returns the priority that has been given to this expression.
+	 *
+	 * @return The priority.
+	 * @see ISources
+	 */
+	public int getSourcePriority();
+
+	/**
+	 * Evaluates the expression -- given the current state of the workbench.
+	 * This method should cache its computation. The cache will be cleared by a
+	 * call to <code>clearResult</code>.
+	 *
+	 * @param context
+	 *            The context in which this state should be evaluated; must not
+	 *            be <code>null</code>.
+	 * @return <code>true</code> if the expression currently evaluates to
+	 *         <code>true</code>; <code>false</code> otherwise.
+	 */
+	public boolean evaluate(IEvaluationContext context);
+
+	/**
+	 * Forces the cached result to be a particular value. This will <b>not</b>
+	 * notify any users of the cache that it has changed.
+	 *
+	 * @param result
+	 *            The cached result to use.
+	 * @since 3.3
+	 */
+	public void setResult(boolean result);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/INestable.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/INestable.java
new file mode 100644
index 0000000..5aba46e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/INestable.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.services;
+
+/**
+ * </p>
+ * A service which can appear on a component which is wholly contained with
+ * another component. The component on which it appears can be active or
+ * inactive -- depending on the state of the application. For example, a
+ * workbench part is a component which appears within a workbench window. This
+ * workbench part can either be active or inactive, depending on what the user
+ * is doing.
+ * </p>
+ * <p>
+ * Services implement this interface, and are then notified by the component
+ * when the activation changes. It is the responsibility of the component to
+ * notify such services when the activation changes.
+ * </p>
+ * <p>
+ * This class is not intended for use outside of the
+ * <code>org.eclipse.ui.workbench</code> plug-in.
+ * </p>
+ * <p>
+ * <strong>PROVISIONAL</strong>. This class or interface has been added as part
+ * of a work in progress. There is a guarantee neither that this API will work
+ * nor that it will remain the same. Please do not use this API without
+ * consulting with the Platform/UI team.
+ * </p>
+ * <p>
+ * This class should eventually move to <code>org.eclipse.ui.services</code>.
+ * </p>
+ *
+ * @since 3.2
+ */
+public interface INestable {
+
+	/**
+	 * Notifies this service that the component within which it exists has
+	 * become active. The service should modify its state as appropriate.
+	 *
+	 */
+	public void activate();
+
+	/**
+	 * Notifies this service that the component within which it exists has
+	 * become inactive. The service should modify its state as appropriate.
+	 */
+	public void deactivate();
+}
+
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/IServiceLocatorCreator.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/IServiceLocatorCreator.java
new file mode 100644
index 0000000..e426dcd
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/IServiceLocatorCreator.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal.services;
+
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.ui.services.AbstractServiceFactory;
+import org.eclipse.ui.services.IDisposable;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * When creating components this service can be used to create the appropriate
+ * service locator for the new component. For use with the component framework.
+ * <p>
+ * <b>Note:</b> Must not be implemented or extended by clients.
+ * <p>
+ * <p>
+ * <strong>PROVISIONAL</strong>. This class or interface has been added as part
+ * of a work in progress. There is a guarantee neither that this API will work
+ * nor that it will remain the same. Please do not use this API without
+ * consulting with the Platform/UI team.  This might disappear in 3.4 M5.
+ * </p>
+ *
+ *
+ * @since 3.4
+ */
+public interface IServiceLocatorCreator {
+	/**
+	 * Creates a service locator that can be used for hosting a new service
+	 * context. It will have the appropriate child services created as needed,
+	 * and can be used with the Dependency Injection framework to reuse
+	 * components (by simply providing your own implementation for certain
+	 * services).
+	 *
+	 * @param parent
+	 *            the parent locator
+	 * @param factory
+	 *            a factory that can lazily provide services if requested. This
+	 *            may be <code>null</code>
+	 * @param owner
+	 *            an object whose {@link IDisposable#dispose()} method will be
+	 *            called on the UI thread if the created service locator needs
+	 *            to be disposed (typically, because a plug-in contributing
+	 *            services to the service locator via an
+	 *            {@link AbstractServiceFactory} is no longer available). The
+	 *            owner can be any object that implements {@link IDisposable}.
+	 *            The recommended implementation of the owner's dispose method
+	 *            is to do whatever is necessary to stop using the created
+	 *            service locator, and then to call
+	 *            {@link IDisposable#dispose()} on the service locator.
+	 * @return the created service locator. The returned service locator will be
+	 *         an instance of {@link IDisposable}.
+	 */
+	public IServiceLocator createServiceLocator(IServiceLocator parent,
+			AbstractServiceFactory factory, IDisposable owner);
+
+	public IServiceLocator createServiceLocator(IServiceLocator parent,
+			AbstractServiceFactory factory, IDisposable owner, IEclipseContext context);
+
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/IWorkbenchLocationService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/IWorkbenchLocationService.java
new file mode 100644
index 0000000..681bdda
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/IWorkbenchLocationService.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2015 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.ui.internal.services;
+
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.part.IPageSite;
+import org.eclipse.ui.part.MultiPageEditorSite;
+import org.eclipse.ui.part.PageBookView;
+import org.eclipse.ui.services.IServiceScopes;
+
+/**
+ * Query where you are in the workbench hierarchy.
+ *
+ * @since 3.4
+ */
+public interface IWorkbenchLocationService {
+	/**
+	 * Get the service scope.
+	 *
+	 * @return the service scope. May return <code>null</code>.
+	 * @see IServiceScopes#PARTSITE_SCOPE
+	 */
+	public String getServiceScope();
+
+	/**
+	 * A more numeric representation of the service level.
+	 *
+	 * @return the level - 0==workbench, 1==workbench window or dialog, etc
+	 */
+	public int getServiceLevel();
+
+	/**
+	 * @return the workbench. May return <code>null</code>.
+	 */
+	public IWorkbench getWorkbench();
+
+	/**
+	 * @return the workbench window in this service locator hierarchy. May
+	 * 	return <code>null</code>.
+	 */
+	public IWorkbenchWindow getWorkbenchWindow();
+
+	/**
+	 * @return the part site in this service locator hierarchy. May return
+	 * 	<code>null</code>.
+	 */
+	public IWorkbenchPartSite getPartSite();
+
+	/**
+	 * @return the inner editor site for a multi-page editor in this service
+	 * 	locator hierarchy. May return <code>null</code>.
+	 * @see MultiPageEditorSite
+	 */
+	public IEditorSite getMultiPageEditorSite();
+
+	/**
+	 * @return the inner page site for a page based view in this service locator
+	 * 	hierarchy. May return <code>null</code>.
+	 * @see PageBookView
+	 */
+	public IPageSite getPageSite();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/MenuSourceProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/MenuSourceProvider.java
new file mode 100644
index 0000000..c06fa94
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/MenuSourceProvider.java
@@ -0,0 +1,139 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.services;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.ui.AbstractSourceProvider;
+import org.eclipse.ui.ISources;
+
+/**
+ * <p>
+ * A listener to changes in the showing menus. This is used to activate handlers
+ * just for the span of a menu being shown. This is needed for full support for
+ * legacy action-based extension points.
+ * </p>
+ * <p>
+ * This class is only intended for internal use within
+ * <code>org.eclipse.ui.workbench</code>.
+ * </p>
+ *
+ * @since 3.2
+ */
+public final class MenuSourceProvider extends AbstractSourceProvider {
+
+	/**
+	 * The names of the sources supported by this source provider.
+	 */
+	private static final String[] PROVIDED_SOURCE_NAMES = new String[] {
+			ISources.ACTIVE_MENU_NAME, ISources.ACTIVE_MENU_SELECTION_NAME,
+			ISources.ACTIVE_MENU_EDITOR_INPUT_NAME };
+
+	/**
+	 * The menu ids that are currently showing, as known by this source
+	 * provider. This value may be <code>null</code>.
+	 */
+	private Set menuIds = new HashSet();
+
+	/**
+	 * Adds all of the given menu identifiers as being shown.
+	 *
+	 * @param menuIds
+	 *            The ids of the menu that is now showing; must not be
+	 *            <code>null</code>.
+	 */
+	public final void addShowingMenus(final Set menuIds,
+			final ISelection localSelection, final ISelection localEditorInput) {
+		this.menuIds.addAll(menuIds);
+		if (DEBUG) {
+			logDebuggingInfo("Menu ids changed to " + this.menuIds); //$NON-NLS-1$
+		}
+		Map m = new HashMap();
+		m.put(ISources.ACTIVE_MENU_NAME, this.menuIds);
+		if (selection != localSelection) {
+			selection = localSelection;
+			m.put(ISources.ACTIVE_MENU_SELECTION_NAME,
+					selection == null ? IEvaluationContext.UNDEFINED_VARIABLE
+							: selection);
+		}
+		if (input != localEditorInput) {
+			input = localEditorInput;
+			m.put(ISources.ACTIVE_MENU_EDITOR_INPUT_NAME,
+					input == null ? IEvaluationContext.UNDEFINED_VARIABLE
+							: input);
+		}
+
+		fireSourceChanged(ISources.ACTIVE_MENU, m);
+	}
+
+	@Override
+	public final void dispose() {
+		menuIds.clear();
+		selection = null;
+		input = null;
+	}
+
+	@Override
+	public final Map getCurrentState() {
+		final Map state = new HashMap();
+		state.put(ISources.ACTIVE_MENU_NAME, menuIds);
+		state.put(ISources.ACTIVE_MENU_SELECTION_NAME,
+				selection == null ? IEvaluationContext.UNDEFINED_VARIABLE
+						: selection);
+		state.put(ISources.ACTIVE_MENU_EDITOR_INPUT_NAME,
+				input == null ? IEvaluationContext.UNDEFINED_VARIABLE : input);
+		return state;
+	}
+
+	@Override
+	public final String[] getProvidedSourceNames() {
+		return PROVIDED_SOURCE_NAMES;
+	}
+
+	/**
+	 * Removes all of the given menu identifiers as being shown.
+	 *
+	 * @param menuIds
+	 *            The ids of the menu that is no longer shown; must not be
+	 *            <code>null</code>.
+	 */
+	public final void removeShowingMenus(final Set menuIds,
+			final ISelection localSelection, final ISelection localEditorInput) {
+		this.menuIds.removeAll(menuIds);
+		if (DEBUG) {
+			logDebuggingInfo("Menu ids changed to " + this.menuIds); //$NON-NLS-1$
+		}
+		Map m = new HashMap();
+		m.put(ISources.ACTIVE_MENU_NAME, this.menuIds);
+		if (selection != localSelection) {
+			selection = localSelection;
+			m.put(ISources.ACTIVE_MENU_SELECTION_NAME,
+					selection == null ? IEvaluationContext.UNDEFINED_VARIABLE
+							: selection);
+		}
+		if (input != localEditorInput) {
+			input = localEditorInput;
+			m.put(ISources.ACTIVE_MENU_EDITOR_INPUT_NAME,
+					input == null ? IEvaluationContext.UNDEFINED_VARIABLE
+							: input);
+		}
+		fireSourceChanged(ISources.ACTIVE_MENU, m);
+	}
+
+	private ISelection selection = null;
+	private ISelection input = null;
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/PreferencePersistence.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/PreferencePersistence.java
new file mode 100644
index 0000000..08e7eb9
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/PreferencePersistence.java
@@ -0,0 +1,438 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.services;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.IParameter;
+import org.eclipse.core.commands.Parameterization;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.util.Util;
+
+/**
+ * <p>
+ * A manager for items parsed from the preference store. This attaches a
+ * listener to the registry after the first read, and monitors the preference
+ * for changes from that point on. When {@link #dispose()} is called, the
+ * listener is detached.
+ * </p>
+ * <p>
+ * This class is only intended for internal use within the
+ * <code>org.eclipse.ui.workbench</code> plug-in.
+ * </p>
+ *
+ * @since 3.2
+ */
+public abstract class PreferencePersistence extends RegistryPersistence {
+
+	/**
+	 * Inserts the given element into the indexed two-dimensional array in the
+	 * array at the index. The array is grown as necessary.
+	 *
+	 * @param elementToAdd
+	 *            The element to add to the indexed array; may be
+	 *            <code>null</code>
+	 * @param indexedArray
+	 *            The two-dimensional array that is indexed by element type;
+	 *            must not be <code>null</code>.
+	 * @param index
+	 *            The index at which the element should be added; must be a
+	 *            valid index.
+	 * @param currentCount
+	 *            The current number of items in the array at the index.
+	 */
+	protected static final void addElementToIndexedArray(
+			final IMemento elementToAdd, final IMemento[][] indexedArray,
+			final int index, final int currentCount) {
+		final IMemento[] elements;
+		if (currentCount == 0) {
+			elements = new IMemento[1];
+			indexedArray[index] = elements;
+		} else {
+			if (currentCount >= indexedArray[index].length) {
+				final IMemento[] copy = new IMemento[indexedArray[index].length * 2];
+				System.arraycopy(indexedArray[index], 0, copy, 0, currentCount);
+				elements = copy;
+				indexedArray[index] = elements;
+			} else {
+				elements = indexedArray[index];
+			}
+		}
+		elements[currentCount] = elementToAdd;
+	}
+
+	/**
+	 * Adds a warning to be logged at some later point in time.
+	 *
+	 * @param warningsToLog
+	 *            The collection of warnings to be logged; must not be
+	 *            <code>null</code>.
+	 * @param message
+	 *            The mesaage to log; must not be <code>null</code>.
+	 */
+	protected static final void addWarning(final List warningsToLog,
+			final String message) {
+		addWarning(warningsToLog, message, null, null, null);
+	}
+
+	/**
+	 * Adds a warning to be logged at some later point in time. This logs the
+	 * identifier of the item.
+	 *
+	 * @param warningsToLog
+	 *            The collection of warnings to be logged; must not be
+	 *            <code>null</code>.
+	 * @param message
+	 *            The mesaage to log; must not be <code>null</code>.
+	 * @param id
+	 *            The identifier of the item for which a warning is being
+	 *            logged; may be <code>null</code>.
+	 */
+	protected static final void addWarning(final List warningsToLog,
+			final String message, final String id) {
+		addWarning(warningsToLog, message, id, null, null);
+	}
+
+	/**
+	 * Adds a warning to be logged at some later point in time. This logs the
+	 * identifier of the item, as well as an extra attribute.
+	 *
+	 * @param warningsToLog
+	 *            The collection of warnings to be logged; must not be
+	 *            <code>null</code>.
+	 * @param message
+	 *            The mesaage to log; must not be <code>null</code>.
+	 * @param id
+	 *            The identifier of the item for which a warning is being
+	 *            logged; may be <code>null</code>.
+	 * @param extraAttributeName
+	 *            The name of extra attribute to be logged; may be
+	 *            <code>null</code>.
+	 * @param extraAttributeValue
+	 *            The value of the extra attribute to be logged; may be
+	 *            <code>null</code>.
+	 */
+	protected static final void addWarning(final List warningsToLog,
+			final String message, final String id,
+			final String extraAttributeName, final String extraAttributeValue) {
+		String statusMessage = message;
+		if (id != null) {
+			statusMessage = statusMessage + ": id='" + id + '\''; //$NON-NLS-1$
+		}
+		if (extraAttributeName != null) {
+			if (id != null) {
+				statusMessage = statusMessage + ',';
+			} else {
+				statusMessage = statusMessage + ':';
+			}
+			statusMessage = statusMessage + ' ' + extraAttributeName + "='" //$NON-NLS-1$
+					+ extraAttributeValue + '\'';
+		}
+
+		final IStatus status = new Status(IStatus.WARNING,
+				WorkbenchPlugin.PI_WORKBENCH, 0, statusMessage, null);
+		warningsToLog.add(status);
+	}
+
+	/**
+	 * Reads a boolean attribute from a memnto.
+	 *
+	 * @param memento
+	 *            The memento from which to read the attribute; must not be
+	 *            <code>null</code>.
+	 * @param attribute
+	 *            The attribute to read; must not be <code>null</code>.
+	 * @param defaultValue
+	 *            The default boolean value.
+	 * @return The attribute's value; may be <code>null</code> if none.
+	 */
+	protected static final boolean readBoolean(final IMemento memento,
+			final String attribute, final boolean defaultValue) {
+		final String value = memento.getString(attribute);
+		if (value == null) {
+			return defaultValue;
+		}
+
+		if (defaultValue) {
+			return !value.equalsIgnoreCase("false"); //$NON-NLS-1$
+		}
+
+		return !value.equalsIgnoreCase("true"); //$NON-NLS-1$
+	}
+
+	/**
+	 * Reads an optional attribute from a memento. This converts zero-length
+	 * strings into <code>null</code>.
+	 *
+	 * @param memento
+	 *            The memento from which to read the attribute; must not be
+	 *            <code>null</code>.
+	 * @param attribute
+	 *            The attribute to read; must not be <code>null</code>.
+	 * @return The attribute's value; may be <code>null</code> if none.
+	 */
+	protected static final String readOptional(final IMemento memento,
+			final String attribute) {
+		String value = memento.getString(attribute);
+		if ((value != null) && (value.length() == 0)) {
+			value = null;
+		}
+
+		return value;
+	}
+
+	/**
+	 * Reads the parameterized command from a parent memento. This is used to
+	 * read the parameter sub-elements from a key element, as well as the
+	 * command id. Each parameter is guaranteed to be valid. If invalid
+	 * parameters are found, then a warning status will be appended to the
+	 * <code>warningsToLog</code> list. The command id is required, or a
+	 * warning will be logged.
+	 *
+	 * @param memento
+	 *            The memento from which the parameters should be read; must not
+	 *            be <code>null</code>.
+	 * @param commandService
+	 *            The service providing commands for the workbench; must not be
+	 *            <code>null</code>.
+	 * @param warningsToLog
+	 *            The list of warnings found during parsing. Warnings found will
+	 *            parsing the parameters will be appended to this list. This
+	 *            value must not be <code>null</code>.
+	 * @param message
+	 *            The message to print if the command identifier is not present;
+	 *            must not be <code>null</code>.
+	 * @return The array of parameters found for this configuration element;
+	 *         <code>null</code> if none can be found.
+	 */
+	protected static final ParameterizedCommand readParameterizedCommand(
+			final IMemento memento, final ICommandService commandService,
+			final List warningsToLog, final String message, final String id) {
+		final String commandId = readRequired(memento, ATT_COMMAND_ID,
+				warningsToLog, message, id);
+		if (commandId == null) {
+			return null;
+		}
+
+		final Command command = commandService.getCommand(commandId);
+		final ParameterizedCommand parameterizedCommand = readParameters(
+				memento, warningsToLog, command);
+
+		return parameterizedCommand;
+	}
+
+	/**
+	 * Reads the parameters from a parent memento. This is used to read the
+	 * parameter sub-elements from a key element. Each parameter is guaranteed
+	 * to be valid. If invalid parameters are found, then a warning status will
+	 * be appended to the <code>warningsToLog</code> list.
+	 *
+	 * @param memento
+	 *            The memento from which the parameters should be read; must not
+	 *            be <code>null</code>.
+	 * @param warningsToLog
+	 *            The list of warnings found during parsing. Warnings found will
+	 *            parsing the parameters will be appended to this list. This
+	 *            value must not be <code>null</code>.
+	 * @param command
+	 *            The command around which the parameterization should be
+	 *            created; must not be <code>null</code>.
+	 * @return The array of parameters found for this memento; <code>null</code>
+	 *         if none can be found.
+	 */
+	protected static final ParameterizedCommand readParameters(
+			final IMemento memento, final List warningsToLog,
+			final Command command) {
+		final IMemento[] parameterMementos = memento
+				.getChildren(TAG_PARAMETER);
+		if ((parameterMementos == null) || (parameterMementos.length == 0)) {
+			return new ParameterizedCommand(command, null);
+		}
+
+		final Collection parameters = new ArrayList();
+		for (final IMemento parameterMemento : parameterMementos) {
+			// Read out the id.
+			final String id = parameterMemento.getString(ATT_ID);
+			if ((id == null) || (id.length() == 0)) {
+				// The name should never be null. This is invalid.
+				addWarning(warningsToLog, "Parameters need a name"); //$NON-NLS-1$
+				continue;
+			}
+
+			// Find the parameter on the command.
+			IParameter parameter = null;
+			try {
+				final IParameter[] commandParameters = command.getParameters();
+				if (parameters != null) {
+					for (final IParameter currentParameter : commandParameters) {
+						if (Util.equals(currentParameter.getId(), id)) {
+							parameter = currentParameter;
+							break;
+						}
+					}
+
+				}
+			} catch (final NotDefinedException e) {
+				// This should not happen.
+			}
+			if (parameter == null) {
+				// The name should never be null. This is invalid.
+				addWarning(warningsToLog,
+						"Could not find a matching parameter", id); //$NON-NLS-1$
+				continue;
+			}
+
+			// Read out the value.
+			final String value = parameterMemento.getString(ATT_VALUE);
+			if ((value == null) || (value.length() == 0)) {
+				// The name should never be null. This is invalid.
+				addWarning(warningsToLog, "Parameters need a value", id); //$NON-NLS-1$
+				continue;
+			}
+
+			parameters.add(new Parameterization(parameter, value));
+		}
+
+		if (parameters.isEmpty()) {
+			return new ParameterizedCommand(command, null);
+		}
+
+		return new ParameterizedCommand(command,
+				(Parameterization[]) parameters
+						.toArray(new Parameterization[parameters.size()]));
+	}
+
+	/**
+	 * Reads a required attribute from the memento.
+	 *
+	 * @param memento
+	 *            The memento from which to read; must not be <code>null</code>.
+	 * @param attribute
+	 *            The attribute to read; must not be <code>null</code>.
+	 * @param warningsToLog
+	 *            The list of warnings; must not be <code>null</code>.
+	 * @param message
+	 *            The warning message to use if the attribute is missing; must
+	 *            not be <code>null</code>.
+	 * @return The required attribute; may be <code>null</code> if missing.
+	 */
+	protected static final String readRequired(final IMemento memento,
+			final String attribute, final List warningsToLog,
+			final String message) {
+		return readRequired(memento, attribute, warningsToLog, message, null);
+	}
+
+	/**
+	 * Reads a required attribute from the memento. This logs the identifier of
+	 * the item if this required element cannot be found.
+	 *
+	 * @param memento
+	 *            The memento from which to read; must not be <code>null</code>.
+	 * @param attribute
+	 *            The attribute to read; must not be <code>null</code>.
+	 * @param warningsToLog
+	 *            The list of warnings; must not be <code>null</code>.
+	 * @param message
+	 *            The warning message to use if the attribute is missing; must
+	 *            not be <code>null</code>.
+	 * @param id
+	 *            The identifier of the element for which this is a required
+	 *            attribute; may be <code>null</code>.
+	 * @return The required attribute; may be <code>null</code> if missing.
+	 */
+	protected static final String readRequired(final IMemento memento,
+			final String attribute, final List warningsToLog,
+			final String message, final String id) {
+		final String value = memento.getString(attribute);
+		if ((value == null) || (value.length() == 0)) {
+			addWarning(warningsToLog, message, id);
+			return null;
+		}
+
+		return value;
+	}
+
+	/**
+	 * Whether the preference and registry change listeners have been attached
+	 * yet.
+	 */
+	protected boolean preferenceListenerAttached = false;
+
+	/**
+	 * The registry change listener for this class.
+	 */
+	private final IPropertyChangeListener preferenceChangeListener;
+
+	/**
+	 * Detaches the preference change listener from the registry.
+	 */
+	@Override
+	public final void dispose() {
+		super.dispose();
+
+		final IPreferenceStore store = WorkbenchPlugin.getDefault()
+				.getPreferenceStore();
+		store.removePropertyChangeListener(preferenceChangeListener);
+	}
+
+	/**
+	 * Checks whether the preference change could affect this persistence class.
+	 *
+	 * @param event
+	 *            The event indicating the preference change; must not be
+	 *            <code>null</code>.
+	 * @return <code>true</code> if the persistence instance is affected by
+	 *         this change; <code>false</code> otherwise.
+	 */
+	protected abstract boolean isChangeImportant(final PropertyChangeEvent event);
+
+	/**
+	 * Reads the various elements from the registry. Subclasses should extend,
+	 * but must not override.
+	 */
+	@Override
+	protected void read() {
+		super.read();
+
+		if (!preferenceListenerAttached) {
+			final IPreferenceStore store = WorkbenchPlugin.getDefault()
+					.getPreferenceStore();
+			store.addPropertyChangeListener(preferenceChangeListener);
+		}
+	}
+
+	/**
+	 * Constructs a new instance of {@link PreferencePersistence}. A preference
+	 * change listener is created.
+	 */
+	protected PreferencePersistence() {
+		super();
+
+		preferenceChangeListener = event -> {
+			if (isChangeImportant(event)) {
+				read();
+			}
+		};
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/RegistryPersistence.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/RegistryPersistence.java
new file mode 100644
index 0000000..4e66fea
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/RegistryPersistence.java
@@ -0,0 +1,631 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.services;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.IParameter;
+import org.eclipse.core.commands.Parameterization;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.core.expressions.ElementHandler;
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.ExpressionConverter;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.IRegistryChangeEvent;
+import org.eclipse.core.runtime.IRegistryChangeListener;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.util.Util;
+import org.eclipse.ui.services.IDisposable;
+
+/**
+ * <p>
+ * A manager for items parsed from the registry. This attaches a listener to the
+ * registry after the first read, and monitors the registry for changes from
+ * that point on. When {@link #dispose()} is called, the listener is detached.
+ * </p>
+ * <p>
+ * This class is only intended for internal use within the
+ * <code>org.eclipse.ui.workbench</code> plug-in.
+ * </p>
+ *
+ * @since 3.2
+ */
+public abstract class RegistryPersistence implements IDisposable,
+		IWorkbenchRegistryConstants {
+
+	/**
+	 * The expression to return when there is an error. Never <code>null</code>.
+	 */
+	protected static final Expression ERROR_EXPRESSION = new Expression() {
+		@Override
+		public final EvaluationResult evaluate(final IEvaluationContext context) {
+			return null;
+		}
+	};
+
+	/**
+	 * Inserts the given element into the indexed two-dimensional array in the
+	 * array at the index. The array is grown as necessary.
+	 *
+	 * @param elementToAdd
+	 *            The element to add to the indexed array; may be
+	 *            <code>null</code>
+	 * @param indexedArray
+	 *            The two-dimensional array that is indexed by element type;
+	 *            must not be <code>null</code>.
+	 * @param index
+	 *            The index at which the element should be added; must be a
+	 *            valid index.
+	 * @param currentCount
+	 *            The current number of items in the array at the index.
+	 */
+	protected static final void addElementToIndexedArray(
+			final IConfigurationElement elementToAdd,
+			final IConfigurationElement[][] indexedArray, final int index,
+			final int currentCount) {
+		final IConfigurationElement[] elements;
+		if (currentCount == 0) {
+			elements = new IConfigurationElement[1];
+			indexedArray[index] = elements;
+		} else {
+			if (currentCount >= indexedArray[index].length) {
+				final IConfigurationElement[] copy = new IConfigurationElement[indexedArray[index].length * 2];
+				System.arraycopy(indexedArray[index], 0, copy, 0, currentCount);
+				elements = copy;
+				indexedArray[index] = elements;
+			} else {
+				elements = indexedArray[index];
+			}
+		}
+		elements[currentCount] = elementToAdd;
+	}
+
+	/**
+	 * Adds a warning to be logged at some later point in time.
+	 *
+	 * @param warningsToLog
+	 *            The collection of warnings to be logged; must not be
+	 *            <code>null</code>.
+	 * @param message
+	 *            The mesaage to log; must not be <code>null</code>.
+	 * @param element
+	 *            The element from which the warning originates; may be
+	 *            <code>null</code>.
+	 */
+	protected static final void addWarning(final List warningsToLog,
+			final String message, final IConfigurationElement element) {
+		addWarning(warningsToLog, message, element, null, null, null);
+	}
+
+	/**
+	 * Adds a warning to be logged at some later point in time. This logs the
+	 * identifier of the item.
+	 *
+	 * @param warningsToLog
+	 *            The collection of warnings to be logged; must not be
+	 *            <code>null</code>.
+	 * @param message
+	 *            The mesaage to log; must not be <code>null</code>.
+	 * @param element
+	 *            The element from which the warning originates; may be
+	 *            <code>null</code>.
+	 * @param id
+	 *            The identifier of the item for which a warning is being
+	 *            logged; may be <code>null</code>.
+	 */
+	protected static final void addWarning(final List warningsToLog,
+			final String message, final IConfigurationElement element,
+			final String id) {
+		addWarning(warningsToLog, message, element, id, null, null);
+	}
+
+	/**
+	 * Adds a warning to be logged at some later point in time. This logs the
+	 * identifier of the item, as well as an extra attribute.
+	 *
+	 * @param warningsToLog
+	 *            The collection of warnings to be logged; must not be
+	 *            <code>null</code>.
+	 * @param message
+	 *            The mesaage to log; must not be <code>null</code>.
+	 * @param element
+	 *            The element from which the warning originates; may be
+	 *            <code>null</code>.
+	 * @param id
+	 *            The identifier of the item for which a warning is being
+	 *            logged; may be <code>null</code>.
+	 * @param extraAttributeName
+	 *            The name of extra attribute to be logged; may be
+	 *            <code>null</code>.
+	 * @param extraAttributeValue
+	 *            The value of the extra attribute to be logged; may be
+	 *            <code>null</code>.
+	 */
+	protected static final void addWarning(final List warningsToLog,
+			final String message, final IConfigurationElement element,
+			final String id, final String extraAttributeName,
+			final String extraAttributeValue) {
+		String statusMessage = message;
+		if (element != null) {
+			statusMessage = statusMessage
+					+ ": plug-in='" + element.getNamespace() + '\''; //$NON-NLS-1$
+		}
+		if (id != null) {
+			if (element != null) {
+				statusMessage = statusMessage + ',';
+			} else {
+				statusMessage = statusMessage + ':';
+			}
+			statusMessage = statusMessage + " id='" + id + '\''; //$NON-NLS-1$
+		}
+		if (extraAttributeName != null) {
+			if ((element != null) || (id != null)) {
+				statusMessage = statusMessage + ',';
+			} else {
+				statusMessage = statusMessage + ':';
+			}
+			statusMessage = statusMessage + ' ' + extraAttributeName + "='" //$NON-NLS-1$
+					+ extraAttributeValue + '\'';
+		}
+
+		final IStatus status = new Status(IStatus.WARNING,
+				WorkbenchPlugin.PI_WORKBENCH, 0, statusMessage, null);
+		warningsToLog.add(status);
+	}
+
+	/**
+	 * Checks that the class attribute or element exists for this element. This
+	 * is used for executable extensions that are being read in.
+	 *
+	 * @param configurationElement
+	 *            The configuration element which should contain a class
+	 *            attribute or a class child element; must not be
+	 *            <code>null</code>.
+	 * @param warningsToLog
+	 *            The list of warnings to be logged; never <code>null</code>.
+	 * @param message
+	 *            The message to log if something goes wrong; may be
+	 *            <code>null</code>.
+	 * @param id
+	 *            The identifier of the handle object; may be <code>null</code>.
+	 * @return <code>true</code> if the class attribute or element exists;
+	 *         <code>false</code> otherwise.
+	 */
+	protected static final boolean checkClass(
+			final IConfigurationElement configurationElement,
+			final List warningsToLog, final String message, final String id) {
+		// Check to see if we have a handler class.
+		if ((configurationElement.getAttribute(ATT_CLASS) == null)
+				&& (configurationElement.getChildren(TAG_CLASS).length == 0)) {
+			addWarning(warningsToLog, message, configurationElement, id);
+			return false;
+		}
+
+		return true;
+	}
+
+	/**
+	 * Checks to see whether the configuration element represents a pulldown
+	 * action. This involves reading the <code>style</code> and
+	 * <code>pulldown</code> attributes.
+	 *
+	 * @param element
+	 *            The element to check; must not be <code>null</code>.
+	 * @return <code>true</code> if the element is a pulldown action;
+	 *         <code>false</code> otherwise.
+	 */
+	protected static final boolean isPulldown(
+			final IConfigurationElement element) {
+		final String style = readOptional(element, ATT_STYLE);
+		final boolean pulldown = readBoolean(element, ATT_PULLDOWN, false);
+		return (pulldown || STYLE_PULLDOWN.equals(style));
+	}
+
+	/**
+	 * Logs any warnings in <code>warningsToLog</code>.
+	 *
+	 * @param warningsToLog
+	 *            The warnings to log; may be <code>null</code>.
+	 * @param message
+	 *            The message to include in the log entry; must not be
+	 *            <code>null</code>.
+	 */
+	protected static final void logWarnings(final List warningsToLog,
+			final String message) {
+		// If there were any warnings, then log them now.
+		if ((warningsToLog != null) && (!warningsToLog.isEmpty())) {
+			final IStatus status = new MultiStatus(
+					WorkbenchPlugin.PI_WORKBENCH, 0, (IStatus[]) warningsToLog
+							.toArray(new IStatus[warningsToLog.size()]),
+					message, null);
+			WorkbenchPlugin.log(status);
+		}
+	}
+
+	/**
+	 * Reads a boolean attribute from an element.
+	 *
+	 * @param configurationElement
+	 *            The configuration element from which to read the attribute;
+	 *            must not be <code>null</code>.
+	 * @param attribute
+	 *            The attribute to read; must not be <code>null</code>.
+	 * @param defaultValue
+	 *            The default boolean value.
+	 * @return The attribute's value; may be <code>null</code> if none.
+	 */
+	protected static final boolean readBoolean(
+			final IConfigurationElement configurationElement,
+			final String attribute, final boolean defaultValue) {
+		final String value = configurationElement.getAttribute(attribute);
+		if (value == null) {
+			return defaultValue;
+		}
+
+		if (defaultValue) {
+			return !value.equalsIgnoreCase("false"); //$NON-NLS-1$
+		}
+
+		return value.equalsIgnoreCase("true"); //$NON-NLS-1$
+	}
+
+	/**
+	 * Reads an optional attribute from an element. This converts zero-length
+	 * strings into <code>null</code>.
+	 *
+	 * @param configurationElement
+	 *            The configuration element from which to read the attribute;
+	 *            must not be <code>null</code>.
+	 * @param attribute
+	 *            The attribute to read; must not be <code>null</code>.
+	 * @return The attribute's value; may be <code>null</code> if none.
+	 */
+	protected static final String readOptional(
+			final IConfigurationElement configurationElement,
+			final String attribute) {
+		String value = configurationElement.getAttribute(attribute);
+		if ((value != null) && (value.length() == 0)) {
+			value = null;
+		}
+
+		return value;
+	}
+
+	/**
+	 * Reads the parameterized command from a parent configuration element. This
+	 * is used to read the parameter sub-elements from a key element, as well as
+	 * the command id. Each parameter is guaranteed to be valid. If invalid
+	 * parameters are found, then a warning status will be appended to the
+	 * <code>warningsToLog</code> list. The command id is required, or a
+	 * warning will be logged.
+	 *
+	 * @param configurationElement
+	 *            The configuration element from which the parameters should be
+	 *            read; must not be <code>null</code>.
+	 * @param commandService
+	 *            The service providing commands for the workbench; must not be
+	 *            <code>null</code>.
+	 * @param warningsToLog
+	 *            The list of warnings found during parsing. Warnings found will
+	 *            parsing the parameters will be appended to this list. This
+	 *            value must not be <code>null</code>.
+	 * @param message
+	 *            The message to print if the command identifier is not present;
+	 *            must not be <code>null</code>.
+	 * @return The array of parameters found for this configuration element;
+	 *         <code>null</code> if none can be found.
+	 */
+	protected static final ParameterizedCommand readParameterizedCommand(
+			final IConfigurationElement configurationElement,
+			final ICommandService commandService, final List warningsToLog,
+			final String message, final String id) {
+		final String commandId = readRequired(configurationElement,
+				ATT_COMMAND_ID, warningsToLog, message, id);
+		if (commandId == null) {
+			return null;
+		}
+
+		final Command command = commandService.getCommand(commandId);
+		final ParameterizedCommand parameterizedCommand = readParameters(
+				configurationElement, warningsToLog, command);
+
+		return parameterizedCommand;
+	}
+
+	/**
+	 * Reads the parameters from a parent configuration element. This is used to
+	 * read the parameter sub-elements from a key element. Each parameter is
+	 * guaranteed to be valid. If invalid parameters are found, then a warning
+	 * status will be appended to the <code>warningsToLog</code> list.
+	 *
+	 * @param configurationElement
+	 *            The configuration element from which the parameters should be
+	 *            read; must not be <code>null</code>.
+	 * @param warningsToLog
+	 *            The list of warnings found during parsing. Warnings found will
+	 *            parsing the parameters will be appended to this list. This
+	 *            value must not be <code>null</code>.
+	 * @param command
+	 *            The command around which the parameterization should be
+	 *            created; must not be <code>null</code>.
+	 * @return The array of parameters found for this configuration element;
+	 *         <code>null</code> if none can be found.
+	 */
+	protected static final ParameterizedCommand readParameters(
+			final IConfigurationElement configurationElement,
+			final List warningsToLog, final Command command) {
+		final IConfigurationElement[] parameterElements = configurationElement
+				.getChildren(TAG_PARAMETER);
+		if ((parameterElements == null) || (parameterElements.length == 0)) {
+			return new ParameterizedCommand(command, null);
+		}
+
+		final Collection parameters = new ArrayList();
+		for (final IConfigurationElement parameterElement : parameterElements) {
+			// Read out the id.
+			final String id = parameterElement.getAttribute(ATT_ID);
+			if ((id == null) || (id.length() == 0)) {
+				// The name should never be null. This is invalid.
+				addWarning(warningsToLog, "Parameters need a name", //$NON-NLS-1$
+						configurationElement);
+				continue;
+			}
+
+			// Find the parameter on the command.
+			IParameter parameter = null;
+			try {
+				final IParameter[] commandParameters = command.getParameters();
+				if (parameters != null) {
+					for (final IParameter currentParameter : commandParameters) {
+						if (Util.equals(currentParameter.getId(), id)) {
+							parameter = currentParameter;
+							break;
+						}
+					}
+
+				}
+			} catch (final NotDefinedException e) {
+				// This should not happen.
+			}
+			if (parameter == null) {
+				// The name should never be null. This is invalid.
+				addWarning(warningsToLog,
+						"Could not find a matching parameter", //$NON-NLS-1$
+						configurationElement, id);
+				continue;
+			}
+
+			// Read out the value.
+			final String value = parameterElement.getAttribute(ATT_VALUE);
+			if ((value == null) || (value.length() == 0)) {
+				// The name should never be null. This is invalid.
+				addWarning(warningsToLog, "Parameters need a value", //$NON-NLS-1$
+						configurationElement, id);
+				continue;
+			}
+
+			parameters.add(new Parameterization(parameter, value));
+		}
+
+		if (parameters.isEmpty()) {
+			return new ParameterizedCommand(command, null);
+		}
+
+		return new ParameterizedCommand(command,
+				(Parameterization[]) parameters
+						.toArray(new Parameterization[parameters.size()]));
+	}
+
+	/**
+	 * Reads a required attribute from the configuration element.
+	 *
+	 * @param configurationElement
+	 *            The configuration element from which to read; must not be
+	 *            <code>null</code>.
+	 * @param attribute
+	 *            The attribute to read; must not be <code>null</code>.
+	 * @param warningsToLog
+	 *            The list of warnings; must not be <code>null</code>.
+	 * @param message
+	 *            The warning message to use if the attribute is missing; must
+	 *            not be <code>null</code>.
+	 * @return The required attribute; may be <code>null</code> if missing.
+	 */
+	protected static final String readRequired(
+			final IConfigurationElement configurationElement,
+			final String attribute, final List warningsToLog,
+			final String message) {
+		return readRequired(configurationElement, attribute, warningsToLog,
+				message, null);
+	}
+
+	/**
+	 * Reads a required attribute from the configuration element. This logs the
+	 * identifier of the item if this required element cannot be found.
+	 *
+	 * @param configurationElement
+	 *            The configuration element from which to read; must not be
+	 *            <code>null</code>.
+	 * @param attribute
+	 *            The attribute to read; must not be <code>null</code>.
+	 * @param warningsToLog
+	 *            The list of warnings; must not be <code>null</code>.
+	 * @param message
+	 *            The warning message to use if the attribute is missing; must
+	 *            not be <code>null</code>.
+	 * @param id
+	 *            The identifier of the element for which this is a required
+	 *            attribute; may be <code>null</code>.
+	 * @return The required attribute; may be <code>null</code> if missing.
+	 */
+	protected static final String readRequired(
+			final IConfigurationElement configurationElement,
+			final String attribute, final List warningsToLog,
+			final String message, final String id) {
+		final String value = configurationElement.getAttribute(attribute);
+		if ((value == null) || (value.length() == 0)) {
+			addWarning(warningsToLog, message, configurationElement, id);
+			return null;
+		}
+
+		return value;
+	}
+
+	/**
+	 * Reads a <code>when</code> child element from the given configuration
+	 * element. Warnings will be appended to <code>warningsToLog</code>.
+	 *
+	 * @param parentElement
+	 *            The configuration element which might have a <code>when</code>
+	 *            element as a child; never <code>null</code>.
+	 * @param whenElementName
+	 *            The name of the when element to find; never <code>null</code>.
+	 * @param id
+	 *            The identifier of the menu element whose <code>when</code>
+	 *            expression is being read; never <code>null</code>.
+	 * @param warningsToLog
+	 *            The list of warnings while parsing the extension point; never
+	 *            <code>null</code>.
+	 * @return The <code>when</code> expression for the
+	 *         <code>configurationElement</code>, if any; otherwise,
+	 *         <code>null</code>.
+	 */
+	protected static final Expression readWhenElement(
+			final IConfigurationElement parentElement,
+			final String whenElementName, final String id,
+			final List warningsToLog) {
+		// Check to see if we have an when expression.
+		final IConfigurationElement[] whenElements = parentElement
+				.getChildren(whenElementName);
+		Expression whenExpression = null;
+		if (whenElements.length > 0) {
+			// Check if we have too many when elements.
+			if (whenElements.length > 1) {
+				// There should only be one when element
+				addWarning(warningsToLog,
+						"There should only be one when element", parentElement, //$NON-NLS-1$
+						id, "whenElementName", //$NON-NLS-1$
+						whenElementName);
+				return ERROR_EXPRESSION;
+			}
+
+			final IConfigurationElement whenElement = whenElements[0];
+			final IConfigurationElement[] expressionElements = whenElement
+					.getChildren();
+			if (expressionElements.length > 0) {
+				// Check if we have too many expression elements
+				if (expressionElements.length > 1) {
+					// There should only be one expression element
+					addWarning(
+							warningsToLog,
+							"There should only be one expression element", parentElement, //$NON-NLS-1$
+							id, "whenElementName", //$NON-NLS-1$
+							whenElementName);
+					return ERROR_EXPRESSION;
+				}
+
+				// Convert the activeWhen element into an expression.
+				final ElementHandler elementHandler = ElementHandler
+						.getDefault();
+				final ExpressionConverter converter = ExpressionConverter
+						.getDefault();
+				final IConfigurationElement expressionElement = expressionElements[0];
+				try {
+					whenExpression = elementHandler.create(converter,
+							expressionElement);
+				} catch (final CoreException e) {
+					// There when expression could not be created.
+					addWarning(
+							warningsToLog,
+							"Problem creating when element", //$NON-NLS-1$
+							parentElement, id,
+							"whenElementName", whenElementName); //$NON-NLS-1$
+					return ERROR_EXPRESSION;
+				}
+			}
+		}
+
+		return whenExpression;
+	}
+
+	/**
+	 * The registry change listener for this class.
+	 */
+	private final IRegistryChangeListener registryChangeListener;
+
+	/**
+	 * Whether the preference and registry change listeners have been attached
+	 * yet.
+	 */
+	protected boolean registryListenerAttached = false;
+
+	/**
+	 * Constructs a new instance of {@link RegistryPersistence}. A registry
+	 * change listener is created.
+	 */
+	protected RegistryPersistence() {
+		registryChangeListener = event -> {
+			if (isChangeImportant(event)) {
+				Display.getDefault().asyncExec(() -> read());
+			}
+		};
+	}
+
+	/**
+	 * Detaches the registry change listener from the registry.
+	 */
+	@Override
+	public void dispose() {
+		final IExtensionRegistry registry = Platform.getExtensionRegistry();
+		registry.removeRegistryChangeListener(registryChangeListener);
+		registryListenerAttached = false;
+	}
+
+	/**
+	 * Checks whether the registry change could affect this persistence class.
+	 *
+	 * @param event
+	 *            The event indicating the registry change; must not be
+	 *            <code>null</code>.
+	 * @return <code>true</code> if the persistence instance is affected by
+	 *         this change; <code>false</code> otherwise.
+	 */
+	protected abstract boolean isChangeImportant(
+			final IRegistryChangeEvent event);
+
+	/**
+	 * Reads the various elements from the registry. Subclasses should extend,
+	 * but must not override.
+	 */
+	protected void read() {
+		if (!registryListenerAttached) {
+			final IExtensionRegistry registry = Platform.getExtensionRegistry();
+			registry.addRegistryChangeListener(registryChangeListener);
+			registryListenerAttached = true;
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/ServiceLocator.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/ServiceLocator.java
new file mode 100644
index 0000000..0de12ce
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/ServiceLocator.java
@@ -0,0 +1,327 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2016 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
+ *     Andrey Loskutov <loskutov@gmx.de> - Bug 436225
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ *     Fabio Zadrozny <fabiofz at gmail dot com> - Bug 459833
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.services;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.services.AbstractServiceFactory;
+import org.eclipse.ui.services.IDisposable;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * @since 3.2
+ *
+ */
+public final class ServiceLocator implements IDisposable, INestable,
+		IServiceLocator {
+	boolean activated = false;
+
+	private static class ParentLocator implements IServiceLocator {
+		private IServiceLocator locator;
+		private Class<?> key;
+
+		public ParentLocator(IServiceLocator parent, Class<?> serviceInterface) {
+			locator = parent;
+			key = serviceInterface;
+		}
+
+		@SuppressWarnings("unchecked")
+		@Override
+		public <T> T getService(Class<T> api) {
+			if (key.equals(api)) {
+				return (T) locator.getService(key);
+			}
+			return null;
+		}
+
+		@Override
+		public boolean hasService(Class<?> api) {
+			if (key.equals(api)) {
+				return true;
+			}
+			return false;
+		}
+	}
+
+	private final AbstractServiceFactory factory;
+
+	/**
+	 * The parent for this service locator. If a service can't be found in this
+	 * locator, then the parent is asked. This value may be <code>null</code> if
+	 * there is no parent.
+	 */
+	private final IServiceLocator parent;
+
+	private volatile boolean disposed;
+
+	private IDisposable owner;
+
+	private volatile IEclipseContext e4Context;
+
+	private final Map<Class<?>, Object> services = new ConcurrentHashMap<>();
+
+	/**
+	 * Constructs a service locator with no parent.
+	 */
+	public ServiceLocator() {
+		this(null, null, null);
+	}
+
+	/**
+	 * Constructs a service locator with the given parent.
+	 *
+	 * @param parent
+	 *            The parent for this service locator; this value may be
+	 *            <code>null</code>.
+	 * @param factory
+	 *            a local factory that can provide services at this level
+	 * @param owner
+	 */
+	public ServiceLocator(final IServiceLocator parent,
+			AbstractServiceFactory factory, IDisposable owner) {
+		this.parent = parent;
+		this.factory = factory;
+		this.owner = owner;
+	}
+
+	@Override
+	public final void activate() {
+		activated = true;
+
+		for (Object service : services.values()) {
+			if (!(service instanceof INestable)) {
+				continue;
+			}
+			SafeRunner.run(new ISafeRunnable() {
+				@Override
+				public void run() throws Exception {
+					((INestable) service).activate();
+				}
+
+				@Override
+				public void handleException(Throwable ex) {
+					WorkbenchPlugin.log(StatusUtil.newStatus(IStatus.ERROR, "Error while activating: " + service, ex)); //$NON-NLS-1$
+				}
+			});
+		}
+	}
+
+	@Override
+	public final void deactivate() {
+		activated = false;
+
+		for (Object service : services.values()) {
+			if (!(service instanceof INestable)) {
+				continue;
+			}
+			SafeRunner.run(new ISafeRunnable() {
+				@Override
+				public void run() throws Exception {
+					((INestable) service).deactivate();
+				}
+
+				@Override
+				public void handleException(Throwable ex) {
+					WorkbenchPlugin
+							.log(StatusUtil.newStatus(IStatus.ERROR, "Error while deactivating: " + service, ex)); //$NON-NLS-1$
+				}
+			});
+		}
+	}
+
+	@Override
+	public final void dispose() {
+		disposeServices();
+		if (services.size() > 0) {
+			// If someone registered during shutdown, dispose of it too.
+			// See: Bug 459833 - ConcurrentModificationException in
+			// ServiceLocator.dispose
+			disposeServices();
+		}
+		// Check if there was some other leftover and warn about it.
+		if (services.size() > 0) {
+			WorkbenchPlugin.log(StatusUtil.newStatus(IStatus.WARNING,
+					String.format(
+							"Services: %s register themselves while disposing (skipping dispose of such services).", //$NON-NLS-1$
+							services),
+					null));
+		}
+		services.clear();
+		disposed = true;
+		e4Context = null;
+		owner = null;
+	}
+
+	private void disposeServices() {
+		Iterator<Entry<Class<?>, Object>> iterator = services.entrySet().iterator();
+		while (iterator.hasNext()) {
+			Entry<Class<?>, Object> entry = iterator.next();
+			if (entry.getValue() instanceof IDisposable) {
+				IDisposable iDisposable = (IDisposable) entry.getValue();
+				SafeRunner.run(new ISafeRunnable() {
+					@Override
+					public void run() throws Exception {
+						iDisposable.dispose();
+					}
+
+					@Override
+					public void handleException(Throwable ex) {
+						WorkbenchPlugin
+								.log(StatusUtil.newStatus(IStatus.ERROR,
+										"Error while disposing: " + iDisposable.getClass().getName(), ex)); //$NON-NLS-1$
+					}
+				});
+			}
+			iterator.remove();
+		}
+	}
+
+	@SuppressWarnings("unchecked")
+	@Override
+	public final <T> T getService(final Class<T> key) {
+		IEclipseContext context = e4Context;
+		if (context == null) {
+			return null;
+		}
+		if (IEclipseContext.class.equals(key)) {
+			return (T) context;
+		}
+
+		Object service = context.get(key.getName());
+		if (service == null) {
+			// this scenario can happen when we dispose the service locator
+			// after the window has been removed, in that case the window's
+			// context has been destroyed so we should check our own local cache
+			// of services first before checking the registry
+			service = services.get(key);
+		} else if (service == context.getLocal(key.getName())) {
+			// store this service retrieved from the context in the map only if
+			// it is a local service for this context, as otherwise we do not
+			// want to dispose it when this service locator gets disposed
+			registerService(key, service, false);
+		}
+
+		if (service == null) {
+			// nothing cached, check registry then parent
+			IServiceLocator factoryParent = WorkbenchServiceRegistry.GLOBAL_PARENT;
+			if (parent != null) {
+				factoryParent = new ParentLocator(parent, key);
+			}
+			if (factory != null) {
+				service = factory.create(key, factoryParent, this);
+			}
+			if (service == null) {
+				service = WorkbenchServiceRegistry.getRegistry().getService(key, factoryParent,
+						this);
+			}
+			if (service == null) {
+				service = factoryParent.getService(key);
+			} else {
+				registerService(key, service, true);
+			}
+		}
+		return (T) service;
+	}
+
+	@Override
+	public final boolean hasService(final Class<?> key) {
+		IEclipseContext context = e4Context;
+		if (context == null) {
+			return false;
+		}
+		return context.containsKey(key.getName());
+	}
+
+	/**
+	 * Registers a service with this locator. If there is an existing service
+	 * matching the same <code>api</code> and it implements {@link IDisposable},
+	 * it will be disposed.
+	 *
+	 * @param api
+	 *            This is the interface that the service implements. Must not be
+	 *            <code>null</code>.
+	 * @param service
+	 *            The service to register. This must be some implementation of
+	 *            <code>api</code>. This value must not be <code>null</code>.
+	 */
+	public final void registerService(final Class api, final Object service) {
+		registerService(api, service, true);
+	}
+
+	private void registerService(Class<?> api, Object service, boolean saveInContext) {
+		if (api == null) {
+			throw new NullPointerException("The service key cannot be null"); //$NON-NLS-1$
+		}
+
+		if (!api.isInstance(service)) {
+			throw new IllegalArgumentException(
+					"The service does not implement the given interface"); //$NON-NLS-1$
+		}
+		if (isDisposed()) {
+			IllegalStateException ex = new IllegalStateException("An attempt was made to register service " + service //$NON-NLS-1$
+					+ " with implementation class " + api + " on a disposed service locator"); //$NON-NLS-1$//$NON-NLS-2$
+			WorkbenchPlugin.log(StatusUtil.newStatus(IStatus.ERROR, ex.getMessage(), ex));
+			return;
+		}
+
+		if (service instanceof INestable && activated) {
+			((INestable) service).activate();
+		}
+
+		services.put(api, service);
+
+		if (saveInContext) {
+			IEclipseContext context = e4Context;
+			if (context == null) {
+				return;
+			}
+			context.set(api.getName(), service);
+		}
+	}
+
+	/**
+	 * @return
+	 */
+	public boolean isDisposed() {
+		return disposed;
+	}
+
+	/**
+	 * Some services that were contributed to this locator are no longer
+	 * available (because the plug-in containing the AbstractServiceFactory is
+	 * no longer available). Notify the owner of the locator about this.
+	 */
+	public void unregisterServices(String[] serviceNames) {
+		if (owner != null) {
+			owner.dispose();
+		}
+	}
+
+	public void setContext(IEclipseContext context) {
+		e4Context = context;
+	}
+
+	public IEclipseContext getContext() {
+		return e4Context;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/ServiceLocatorCreator.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/ServiceLocatorCreator.java
new file mode 100644
index 0000000..32df162
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/ServiceLocatorCreator.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.services;
+
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.ui.services.AbstractServiceFactory;
+import org.eclipse.ui.services.IDisposable;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * A simple service locator creator.
+ *
+ * @since 3.4
+ */
+public class ServiceLocatorCreator implements IServiceLocatorCreator {
+
+	@Override
+	public IServiceLocator createServiceLocator(IServiceLocator parent,
+			AbstractServiceFactory factory, IDisposable owner) {
+		ServiceLocator serviceLocator = new ServiceLocator(parent, factory, owner);
+		//System.err.println("parentLocator: " + parent); //$NON-NLS-1$
+		if (parent != null) {
+			IEclipseContext ctx = parent.getService(IEclipseContext.class);
+			if (ctx != null) {
+				serviceLocator.setContext(ctx.createChild());
+			}
+		}
+		return serviceLocator;
+	}
+
+	@Override
+	public IServiceLocator createServiceLocator(IServiceLocator parent,
+			AbstractServiceFactory factory, IDisposable owner, IEclipseContext context) {
+		ServiceLocator serviceLocator = new ServiceLocator(parent, factory, owner);
+		serviceLocator.setContext(context);
+		return serviceLocator;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/SlaveEvaluationService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/SlaveEvaluationService.java
new file mode 100644
index 0000000..0736e71
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/SlaveEvaluationService.java
@@ -0,0 +1,151 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2015 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.ui.internal.services;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.ui.ISourceProvider;
+import org.eclipse.ui.services.IEvaluationReference;
+import org.eclipse.ui.services.IEvaluationService;
+
+/**
+ * @since 3.4
+ *
+ */
+public class SlaveEvaluationService implements IEvaluationService {
+
+	private IEvaluationService parentService;
+
+	private Collection sourceProviders = new ArrayList();
+
+	private Collection serviceListeners = new ArrayList();
+
+	private Collection evaluationReferences = new ArrayList();
+
+	/**
+	 * @param parent
+	 */
+	public SlaveEvaluationService(IEvaluationService parent) {
+		parentService = parent;
+	}
+
+	/**
+	 * @see org.eclipse.ui.services.IEvaluationService#addEvaluationListener(org.eclipse.core.expressions.Expression,
+	 *      org.eclipse.jface.util.IPropertyChangeListener, java.lang.String)
+	 */
+	@Override
+	public IEvaluationReference addEvaluationListener(Expression expression,
+			IPropertyChangeListener listener, String property) {
+		IEvaluationReference ref = parentService.addEvaluationListener(
+				expression, listener, property);
+		if (!evaluationReferences.contains(ref)) {
+			evaluationReferences.add(ref);
+		}
+		return ref;
+	}
+
+	@Override
+	public void addEvaluationReference(IEvaluationReference ref) {
+		if (!evaluationReferences.contains(ref)) {
+			evaluationReferences.add(ref);
+		}
+		parentService.addEvaluationReference(ref);
+	}
+
+	/**
+	 * @see org.eclipse.ui.services.IEvaluationService#addServiceListener(org.eclipse.jface.util.IPropertyChangeListener)
+	 */
+	@Override
+	public void addServiceListener(IPropertyChangeListener listener) {
+		if (!serviceListeners.contains(listener)) {
+			serviceListeners.add(listener);
+		}
+		parentService.addServiceListener(listener);
+	}
+
+	/**
+	 * @see org.eclipse.ui.services.IServiceWithSources#addSourceProvider(org.eclipse.ui.ISourceProvider)
+	 */
+	@Override
+	public void addSourceProvider(ISourceProvider provider) {
+		if (!sourceProviders.contains(provider)) {
+			sourceProviders.add(provider);
+		}
+		parentService.addSourceProvider(provider);
+	}
+
+	/**
+	 * @see org.eclipse.ui.services.IEvaluationService#getCurrentState()
+	 */
+	@Override
+	public IEvaluationContext getCurrentState() {
+		return parentService.getCurrentState();
+	}
+
+	/**
+	 * @see org.eclipse.ui.services.IEvaluationService#removeEvaluationListener(org.eclipse.ui.services.IEvaluationReference)
+	 */
+	@Override
+	public void removeEvaluationListener(IEvaluationReference ref) {
+		evaluationReferences.remove(ref);
+		parentService.removeEvaluationListener(ref);
+	}
+
+	/**
+	 * @see org.eclipse.ui.services.IEvaluationService#removeServiceListener(org.eclipse.jface.util.IPropertyChangeListener)
+	 */
+	@Override
+	public void removeServiceListener(IPropertyChangeListener listener) {
+		serviceListeners.remove(listener);
+		parentService.removeServiceListener(listener);
+	}
+
+	/**
+	 * @see org.eclipse.ui.services.IServiceWithSources#removeSourceProvider(org.eclipse.ui.ISourceProvider)
+	 */
+	@Override
+	public void removeSourceProvider(ISourceProvider provider) {
+		sourceProviders.remove(provider);
+		parentService.removeSourceProvider(provider);
+	}
+
+	@Override
+	public void dispose() {
+		if (!evaluationReferences.isEmpty()) {
+			for (Object evaluationListener : evaluationReferences.toArray()) {
+				parentService.removeEvaluationListener((IEvaluationReference) evaluationListener);
+			}
+		}
+		if (!serviceListeners.isEmpty()) {
+			for (Object serviceListener : serviceListeners.toArray()) {
+				parentService.removeServiceListener((IPropertyChangeListener) serviceListener);
+			}
+			serviceListeners.clear();
+		}
+		// Remove any "resource", like listeners, that were associated
+		// with this service.
+		if (!sourceProviders.isEmpty()) {
+			for (Object sourceProvider : sourceProviders.toArray()) {
+				parentService.removeSourceProvider((ISourceProvider) sourceProvider);
+			}
+			sourceProviders.clear();
+		}
+	}
+
+	@Override
+	public void requestEvaluation(String propertyName) {
+		parentService.requestEvaluation(propertyName);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/SourcePriorityNameMapping.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/SourcePriorityNameMapping.java
new file mode 100644
index 0000000..17296ea
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/SourcePriorityNameMapping.java
@@ -0,0 +1,183 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.services;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.ExpressionInfo;
+import org.eclipse.ui.ISources;
+
+/**
+ * <p>
+ * A static class linking the names of variables in an IEvaluationContext to the
+ * priority they should be given when doing conflict resolution.
+ * </p>
+ * <p>
+ * In the future, it will possible to define a new variable (i.e., piece of
+ * application state) that you want to use inside of the
+ * <code>org.eclipse.ui.contexts</code>, <code>org.eclipse.ui.handlers</code>
+ * or <code>org.eclipse.ui.menus</code> extension points. As it stands right
+ * now, it is not possible to run code soon enough for the
+ * <code>IHandlerService</code>, <code>IMenuService</code> or
+ * <code>IContextService</code> to become aware of the new variables. This
+ * will likely be fixed with a new extension point.
+ * </p>
+ * <p>
+ * TODO Move to "org.eclipse.ui" and resolve the above issue.
+ * </p>
+ *
+ * @since 3.2
+ * @see org.eclipse.ui.ISources
+ * @see org.eclipse.ui.contexts.IContextService
+ * @see org.eclipse.ui.handlers.IHandlerService
+ * @see org.eclipse.ui.menus.IMenuService
+ */
+public final class SourcePriorityNameMapping implements ISources {
+
+	/**
+	 * The variable name to use when boosting priority on an activation.
+	 */
+	public static final String LEGACY_LEGACY_NAME = "LEGACY"; //$NON-NLS-1$
+
+	/**
+	 * The value returned if there is source priority for the given name
+	 *
+	 * @see SourcePriorityNameMapping#getMapping(String)
+	 */
+	public static final int NO_SOURCE_PRIORITY = 0;
+
+	/**
+	 * The map of source priorities indexed by name. This value is never
+	 * <code>null</code>.
+	 */
+	private static final Map sourcePrioritiesByName = new HashMap();
+
+	static {
+		addMapping(ACTIVE_ACTION_SETS_NAME, ACTIVE_ACTION_SETS);
+		addMapping(ACTIVE_CONTEXT_NAME, ACTIVE_CONTEXT);
+		addMapping(ACTIVE_CURRENT_SELECTION_NAME, ACTIVE_CURRENT_SELECTION);
+		addMapping(ACTIVE_EDITOR_NAME, ACTIVE_EDITOR);
+		addMapping(ACTIVE_EDITOR_INPUT_NAME, ACTIVE_EDITOR);
+		addMapping(ACTIVE_EDITOR_ID_NAME, ACTIVE_EDITOR_ID);
+		addMapping(ACTIVE_MENU_NAME, ACTIVE_MENU);
+		addMapping(ACTIVE_MENU_SELECTION_NAME, ACTIVE_MENU);
+		addMapping(ACTIVE_MENU_EDITOR_INPUT_NAME, ACTIVE_MENU);
+		addMapping(ACTIVE_FOCUS_CONTROL_ID_NAME, ACTIVE_MENU);
+		addMapping(ACTIVE_FOCUS_CONTROL_NAME, ACTIVE_MENU);
+		addMapping(ACTIVE_PART_NAME, ACTIVE_PART);
+		addMapping(ACTIVE_PART_ID_NAME, ACTIVE_PART_ID);
+		addMapping(ACTIVE_SHELL_NAME, ACTIVE_SHELL);
+		addMapping(ACTIVE_SITE_NAME, ACTIVE_SITE);
+		addMapping(ACTIVE_WORKBENCH_WINDOW_NAME, ACTIVE_WORKBENCH_WINDOW);
+		addMapping(ACTIVE_WORKBENCH_WINDOW_SHELL_NAME,
+				ACTIVE_WORKBENCH_WINDOW_SHELL);
+		addMapping(ACTIVE_WORKBENCH_WINDOW_IS_COOLBAR_VISIBLE_NAME,
+				ACTIVE_WORKBENCH_WINDOW_SUBORDINATE);
+		addMapping(ACTIVE_WORKBENCH_WINDOW_ACTIVE_PERSPECTIVE_NAME,
+				ACTIVE_WORKBENCH_WINDOW_SUBORDINATE);
+		addMapping(ACTIVE_WORKBENCH_WINDOW_IS_PERSPECTIVEBAR_VISIBLE_NAME,
+				ACTIVE_WORKBENCH_WINDOW_SUBORDINATE);
+		addMapping(LEGACY_LEGACY_NAME, LEGACY_LEGACY);
+		addMapping("workbench", WORKBENCH); //$NON-NLS-1$
+	}
+
+	/**
+	 * Adds a mapping between a source name and a source priority. This method
+	 * also cleans up any existing mappings using the same name or priority.
+	 * There is a one-to-one relationship between name and priority.
+	 *
+	 * @param sourceName
+	 *            The name of the variable as it would appear in an XML
+	 *            expression; must not be <code>null</code>.
+	 * @param sourcePriority
+	 *            The priority of the source with respect to other sources. A
+	 *            higher value means that expressions including this priority
+	 *            will win ties more often. It is recommended that this value is
+	 *            simply a single bit shifted to a particular place.
+	 * @see ISources
+	 */
+	public static final void addMapping(final String sourceName,
+			final int sourcePriority) {
+		if (sourceName == null) {
+			throw new NullPointerException("The source name cannot be null."); //$NON-NLS-1$
+		}
+
+		if (!sourcePrioritiesByName.containsKey(sourceName)) {
+			final Integer priority = Integer.valueOf(sourcePriority);
+
+			sourcePrioritiesByName.put(sourceName, priority);
+		}
+	}
+
+	/**
+	 * Computes the source priority for the given expression. The source
+	 * priority is a bit mask of all of the variables references by the
+	 * expression. The default variable is considered to be
+	 * {@link ISources#ACTIVE_CURRENT_SELECTION}. The source priority is used
+	 * to minimize recomputations of the expression, and it can also be used for
+	 * conflict resolution.
+	 *
+	 * @param expression
+	 *            The expression for which the source priority should be
+	 *            computed; may be <code>null</code>.
+	 * @return The bit mask of all the sources required for this expression;
+	 *         <code>0</code> if none.
+	 */
+	public static final int computeSourcePriority(final Expression expression) {
+		int sourcePriority = ISources.WORKBENCH;
+
+		if (expression == null) {
+			return sourcePriority;
+		}
+
+		final ExpressionInfo info = expression.computeExpressionInfo();
+
+		// Add the default variable, if any.
+		if (info.hasDefaultVariableAccess()) {
+			sourcePriority |= ISources.ACTIVE_CURRENT_SELECTION;
+		}
+
+		// Add all of the reference variables.
+		final String[] sourceNames = info.getAccessedVariableNames();
+		for (final String sourceName : sourceNames) {
+			sourcePriority |= getMapping(sourceName);
+		}
+
+		return sourcePriority;
+	}
+
+	/**
+	 * Gets the priority for the source with the given name.
+	 *
+	 * @param sourceName
+	 *            The name of the variable as it would appear in an XML
+	 *            expression; should not be <code>null</code>.
+	 * @return The source priority that matches, if any;
+	 *         <code>NO_SOURCE_PRIORITY</code> if none is found.
+	 */
+	public static final int getMapping(final String sourceName) {
+		final Object object = sourcePrioritiesByName.get(sourceName);
+		if (object instanceof Integer) {
+			return ((Integer) object).intValue();
+		}
+
+		return NO_SOURCE_PRIORITY;
+	}
+
+	/**
+	 * This class should not be instantiated.
+	 */
+	private SourcePriorityNameMapping() {
+		// This class should not be instantiated.
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/SourceProviderService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/SourceProviderService.java
new file mode 100644
index 0000000..0ce8fbe
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/SourceProviderService.java
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.internal.services;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import org.eclipse.ui.AbstractSourceProvider;
+import org.eclipse.ui.ISourceProvider;
+import org.eclipse.ui.services.IDisposable;
+import org.eclipse.ui.services.IServiceLocator;
+import org.eclipse.ui.services.ISourceProviderService;
+
+/**
+ * <p>
+ * A service holding all of the registered source providers.
+ * </p>
+ * <p>
+ * This class is not intended for use outside of the
+ * <code>org.eclipse.ui.workbench</code> plug-in.
+ * </p>
+ *
+ * @since 3.2
+ */
+public final class SourceProviderService implements ISourceProviderService,
+		IDisposable {
+
+	/**
+	 * The source providers registered with this service. This value is never
+	 * <code>null</code>. This is a map of the source name ({@link String})
+	 * to the source provider ({@link ISourceProvider}).
+	 */
+	private final Map sourceProvidersByName = new HashMap();
+
+	/**
+	 * All of the source providers registered with this service. This value is
+	 * never <code>null</code>.
+	 */
+	private final Set sourceProviders = new HashSet();
+
+	private IServiceLocator locator;
+
+	public SourceProviderService(final IServiceLocator locator) {
+		this.locator = locator;
+	}
+
+	@Override
+	public final void dispose() {
+		final Iterator sourceProviderItr = sourceProviders.iterator();
+		while (sourceProviderItr.hasNext()) {
+			final ISourceProvider sourceProvider = (ISourceProvider) sourceProviderItr
+					.next();
+			sourceProvider.dispose();
+		}
+		sourceProviders.clear();
+		sourceProvidersByName.clear();
+	}
+
+	@Override
+	public final ISourceProvider getSourceProvider(final String sourceName) {
+		return (ISourceProvider) sourceProvidersByName.get(sourceName);
+	}
+
+	@Override
+	public final ISourceProvider[] getSourceProviders() {
+		return (ISourceProvider[]) sourceProviders
+				.toArray(new ISourceProvider[sourceProviders.size()]);
+	}
+
+	public final void registerProvider(final ISourceProvider sourceProvider) {
+		if (sourceProvider == null) {
+			throw new NullPointerException("The source provider cannot be null"); //$NON-NLS-1$
+		}
+
+		for (final String sourceName : sourceProvider.getProvidedSourceNames()) {
+			sourceProvidersByName.put(sourceName, sourceProvider);
+		}
+		sourceProviders.add(sourceProvider);
+	}
+
+	public final void unregisterProvider(ISourceProvider sourceProvider) {
+		if (sourceProvider == null) {
+			throw new NullPointerException("The source provider cannot be null"); //$NON-NLS-1$
+		}
+
+		for (String sourceName : sourceProvider.getProvidedSourceNames()) {
+			sourceProvidersByName.remove(sourceName);
+		}
+		sourceProviders.remove(sourceProvider);
+	}
+
+	public final void readRegistry() {
+		for (AbstractSourceProvider sourceProvider : WorkbenchServiceRegistry.getRegistry().getSourceProviders()) {
+			sourceProvider.initialize(locator);
+			registerProvider(sourceProvider);
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/WorkbenchLocationService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/WorkbenchLocationService.java
new file mode 100644
index 0000000..9de9bde
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/WorkbenchLocationService.java
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2015 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.ui.internal.services;
+
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.part.IPageSite;
+import org.eclipse.ui.services.IDisposable;
+
+/**
+ * @since 3.4
+ *
+ */
+public class WorkbenchLocationService implements IWorkbenchLocationService,
+		IDisposable {
+
+	private IEditorSite mpepSite;
+	private IPageSite pageSite;
+	private IWorkbenchPartSite partSite;
+	private String serviceScope;
+	private IWorkbench workbench;
+	private IWorkbenchWindow window;
+	private int level;
+
+	public WorkbenchLocationService(String serviceScope, IWorkbench workbench,
+			IWorkbenchWindow window, IWorkbenchPartSite partSite,
+			IEditorSite mpepSite, IPageSite pageSite, int level) {
+		this.mpepSite = mpepSite;
+		this.pageSite = pageSite;
+		this.partSite = partSite;
+		this.serviceScope = serviceScope;
+		this.window = window;
+		this.workbench = workbench;
+		this.level = level;
+	}
+
+	@Override
+	public IEditorSite getMultiPageEditorSite() {
+		return mpepSite;
+	}
+
+	@Override
+	public IPageSite getPageSite() {
+		return pageSite;
+	}
+
+	@Override
+	public IWorkbenchPartSite getPartSite() {
+		return partSite;
+	}
+
+	@Override
+	public String getServiceScope() {
+		return serviceScope;
+	}
+
+	@Override
+	public IWorkbench getWorkbench() {
+		return workbench;
+	}
+
+	@Override
+	public IWorkbenchWindow getWorkbenchWindow() {
+		return window;
+	}
+
+	@Override
+	public void dispose() {
+		mpepSite = null;
+		pageSite = null;
+		partSite = null;
+		serviceScope = null;
+		workbench = null;
+		window = null;
+	}
+
+	@Override
+	public int getServiceLevel() {
+		return level;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/WorkbenchServiceRegistry.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/WorkbenchServiceRegistry.java
new file mode 100644
index 0000000..0abd1da
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/WorkbenchServiceRegistry.java
@@ -0,0 +1,263 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.ui.internal.services;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.dynamichelpers.ExtensionTracker;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
+import org.eclipse.ui.AbstractSourceProvider;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.services.AbstractServiceFactory;
+import org.eclipse.ui.services.IServiceLocator;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+/**
+ * This class will create a service from the matching factory. If the factory
+ * doesn't exist, it will try and load it from the registry.
+ *
+ * @since 3.4
+ */
+public class WorkbenchServiceRegistry implements IExtensionChangeHandler {
+	/**
+	 *
+	 */
+	private static final String WORKBENCH_LEVEL = "workbench"; //$NON-NLS-1$
+
+	private static final String EXT_ID_SERVICES = "org.eclipse.ui.services"; //$NON-NLS-1$
+
+	private static WorkbenchServiceRegistry registry = null;
+
+	public static WorkbenchServiceRegistry getRegistry() {
+		if (registry == null) {
+			registry = new WorkbenchServiceRegistry();
+		}
+		return registry;
+	}
+
+	private WorkbenchServiceRegistry() {
+		PlatformUI.getWorkbench().getExtensionTracker().registerHandler(
+				this,
+				ExtensionTracker
+						.createExtensionPointFilter(getExtensionPoint()));
+	}
+
+	/**
+	 * Used as the global service locator's parent.
+	 */
+	public static final IServiceLocator GLOBAL_PARENT = new IServiceLocator() {
+		@Override
+		public <T> T getService(Class<T> api) {
+			return null;
+		}
+
+		@Override
+		public boolean hasService(Class<?> api) {
+			return false;
+		}
+	};
+
+	private Map factories = new HashMap();
+
+	static class ServiceFactoryHandle {
+		AbstractServiceFactory factory;
+		WeakHashMap serviceLocators = new WeakHashMap();
+		String[] serviceNames;
+		ServiceFactoryHandle(AbstractServiceFactory factory) {
+			this.factory = factory;
+		}
+	}
+
+	public Object getService(Class key, IServiceLocator parentLocator,
+			ServiceLocator locator) {
+		ServiceFactoryHandle handle = (ServiceFactoryHandle) factories.get(key.getName());
+		if (handle == null) {
+			handle = loadFromRegistry(key);
+		}
+		if (handle != null) {
+			Object result = handle.factory.create(key, parentLocator, locator);
+			if (result != null) {
+				handle.serviceLocators.put(locator, new Object());
+				return result;
+			}
+		}
+		return null;
+	}
+
+	private ServiceFactoryHandle loadFromRegistry(Class key) {
+		ServiceFactoryHandle result = null;
+		IConfigurationElement[] serviceFactories = getExtensionPoint()
+				.getConfigurationElements();
+		try {
+			final String requestedName = key.getName();
+			boolean done = false;
+			for (int i = 0; i < serviceFactories.length && !done; i++) {
+				final IConfigurationElement[] serviceNameElements = serviceFactories[i]
+						.getChildren(IWorkbenchRegistryConstants.TAG_SERVICE);
+				for (int j = 0; j < serviceNameElements.length && !done; j++) {
+					String serviceName = serviceNameElements[j]
+							.getAttribute(IWorkbenchRegistryConstants.ATTR_SERVICE_CLASS);
+					if (requestedName.equals(serviceName)) {
+						done = true;
+					}
+				}
+				if (done) {
+					final AbstractServiceFactory f = (AbstractServiceFactory) serviceFactories[i]
+							.createExecutableExtension(IWorkbenchRegistryConstants.ATTR_FACTORY_CLASS);
+					ServiceFactoryHandle handle = new ServiceFactoryHandle(f);
+			    	PlatformUI.getWorkbench().getExtensionTracker().registerObject(
+			    			serviceFactories[i].getDeclaringExtension(),
+							handle, IExtensionTracker.REF_WEAK);
+
+			    	List serviceNames = new ArrayList();
+					for (IConfigurationElement configElement : serviceNameElements) {
+						String serviceName = configElement.getAttribute(IWorkbenchRegistryConstants.ATTR_SERVICE_CLASS);
+						if (factories.containsKey(serviceName)) {
+							WorkbenchPlugin.log("Factory already exists for " //$NON-NLS-1$
+									+ serviceName);
+						} else {
+							factories.put(serviceName, handle);
+							serviceNames.add(serviceName);
+						}
+					}
+					handle.serviceNames = (String[]) serviceNames.toArray(new String[serviceNames
+							.size()]);
+					result = handle;
+				}
+			}
+		} catch (CoreException e) {
+			StatusManager.getManager().handle(e.getStatus());
+		}
+		return result;
+	}
+
+	private IExtensionPoint getExtensionPoint() {
+		IExtensionRegistry reg = Platform.getExtensionRegistry();
+		IExtensionPoint ep = reg.getExtensionPoint(EXT_ID_SERVICES);
+		return ep;
+	}
+
+	public AbstractSourceProvider[] getSourceProviders() {
+		ArrayList providers = new ArrayList();
+		IExtensionPoint ep = getExtensionPoint();
+		for (IConfigurationElement configElement : ep.getConfigurationElements()) {
+			if (configElement.getName().equals(
+					IWorkbenchRegistryConstants.TAG_SOURCE_PROVIDER)) {
+				try {
+					Object sourceProvider = configElement
+							.createExecutableExtension(IWorkbenchRegistryConstants.ATTR_PROVIDER);
+					if (!(sourceProvider instanceof AbstractSourceProvider)) {
+						String attributeName = configElement.getAttribute(IWorkbenchRegistryConstants.ATTR_PROVIDER);
+						final String message = "Source Provider '" + //$NON-NLS-1$
+								attributeName
+								+ "' should extend AbstractSourceProvider"; //$NON-NLS-1$
+						final IStatus status = new Status(IStatus.ERROR, WorkbenchPlugin.PI_WORKBENCH, message);
+						WorkbenchPlugin.log(status);
+						continue;
+					}
+					providers.add(sourceProvider);
+					processVariables(configElement.getChildren(IWorkbenchRegistryConstants.TAG_VARIABLE));
+				} catch (CoreException e) {
+					StatusManager.getManager().handle(e.getStatus());
+				}
+			}
+		}
+		return (AbstractSourceProvider[]) providers
+				.toArray(new AbstractSourceProvider[providers.size()]);
+	}
+
+	private static final String[] supportedLevels = { ISources.ACTIVE_CONTEXT_NAME,
+			ISources.ACTIVE_SHELL_NAME,
+			ISources.ACTIVE_WORKBENCH_WINDOW_NAME,
+			ISources.ACTIVE_EDITOR_ID_NAME,
+			ISources.ACTIVE_PART_ID_NAME,
+			ISources.ACTIVE_SITE_NAME
+	};
+
+	private void processVariables(IConfigurationElement[] children) {
+		for (IConfigurationElement configElement : children) {
+			String name = configElement.getAttribute(IWorkbenchRegistryConstants.ATT_NAME);
+			if (name == null || name.length() == 0) {
+				continue;
+			}
+			String level = configElement.getAttribute(IWorkbenchRegistryConstants.ATT_PRIORITY_LEVEL);
+			if (level == null || level.length() == 0) {
+				level = WORKBENCH_LEVEL;
+			} else {
+				boolean found = false;
+				for (int j = 0; j < supportedLevels.length && !found; j++) {
+					if (supportedLevels[j].equals(level)) {
+						found = true;
+					}
+				}
+				if (!found) {
+					level = WORKBENCH_LEVEL;
+				}
+			}
+			int existingPriority = SourcePriorityNameMapping.getMapping(level);
+			int newPriority = existingPriority << 1;
+			SourcePriorityNameMapping.addMapping(name, newPriority);
+		}
+	}
+
+	@Override
+	public void addExtension(IExtensionTracker tracker, IExtension extension) {
+		// we don't need to react to adds because we are not caching the extensions we find -
+		// next time a service is requested, we will look at all extensions again in
+		// loadFromRegistry
+	}
+
+	@Override
+	public void removeExtension(IExtension extension, Object[] objects) {
+		for (Object object : objects) {
+			if (object instanceof ServiceFactoryHandle) {
+				ServiceFactoryHandle handle = (ServiceFactoryHandle) object;
+				Set locatorSet = handle.serviceLocators.keySet();
+				ServiceLocator[] locators = (ServiceLocator[]) locatorSet.toArray(new ServiceLocator[locatorSet.size()]);
+				Arrays.sort(locators, (loc1, loc2) -> {
+					int l1 = loc1.getService(IWorkbenchLocationService.class).getServiceLevel();
+					int l2 = loc2.getService(IWorkbenchLocationService.class).getServiceLevel();
+					return l1 < l2 ? -1 : (l1 > l2 ? 1 : 0);
+				});
+				for (ServiceLocator locator : locators) {
+					ServiceLocator serviceLocator = locator;
+					if (!serviceLocator.isDisposed()) {
+						serviceLocator.unregisterServices(handle.serviceNames);
+					}
+				}
+				handle.factory = null;
+				for (String serviceName : handle.serviceNames) {
+					if (factories.get(serviceName) == handle) {
+						factories.remove(serviceName);
+					}
+				}
+			}
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/WorkbenchSourceProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/WorkbenchSourceProvider.java
new file mode 100644
index 0000000..953592b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/services/WorkbenchSourceProvider.java
@@ -0,0 +1,958 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ ******************************************************************************/
+
+package org.eclipse.ui.internal.services;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.AbstractSourceProvider;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.INullSelectionListener;
+import org.eclipse.ui.IPartListener;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.IPerspectiveListener;
+import org.eclipse.ui.IPropertyListener;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.IWindowListener;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.contexts.IContextService;
+import org.eclipse.ui.internal.WorkbenchWindow;
+import org.eclipse.ui.internal.util.Util;
+import org.eclipse.ui.part.IShowInSource;
+import org.eclipse.ui.part.ShowInContext;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * @since 3.5
+ * @author Prakash G.R.
+ */
+public class WorkbenchSourceProvider extends AbstractSourceProvider implements
+		INullSelectionListener {
+
+	private static final String STATUS_LINE_VIS = ISources.ACTIVE_WORKBENCH_WINDOW_NAME
+			+ ".isStatusLineVisible"; //$NON-NLS-1$
+
+	/**
+	 * The names of the sources supported by this source provider.
+	 */
+	private static final String[] PROVIDED_SOURCE_NAMES = new String[] {
+			ISources.ACTIVE_CURRENT_SELECTION_NAME,
+			ISources.ACTIVE_EDITOR_ID_NAME, ISources.ACTIVE_EDITOR_NAME,
+			ISources.ACTIVE_PART_ID_NAME, ISources.ACTIVE_PART_NAME,
+			ISources.ACTIVE_SITE_NAME, ISources.SHOW_IN_SELECTION,
+			ISources.SHOW_IN_INPUT, ISources.ACTIVE_SHELL_NAME,
+			ISources.ACTIVE_WORKBENCH_WINDOW_NAME,
+			ISources.ACTIVE_WORKBENCH_WINDOW_SHELL_NAME,
+			ISources.ACTIVE_WORKBENCH_WINDOW_IS_COOLBAR_VISIBLE_NAME,
+			ISources.ACTIVE_WORKBENCH_WINDOW_IS_PERSPECTIVEBAR_VISIBLE_NAME,
+			ISources.ACTIVE_WORKBENCH_WINDOW_ACTIVE_PERSPECTIVE_NAME,
+			STATUS_LINE_VIS };
+
+	private IWorkbench workbench;
+	private IWorkbenchWindow lastWindow;
+//	private IServiceLocator locator;
+
+	@Override
+	public void initialize(IServiceLocator locator) {
+//		this.locator = locator;
+		super.initialize(locator);
+		IWorkbenchLocationService wls = locator
+				.getService(IWorkbenchLocationService.class);
+		workbench = wls.getWorkbench();
+		workbench.addWindowListener(windowListener);
+		lastWindow = workbench.getActiveWorkbenchWindow();
+		display = workbench.getDisplay();
+		display.addFilter(SWT.Activate, listener);
+	}
+
+	@Override
+	public void dispose() {
+		if (lastWindow != null)
+			lastWindow.getSelectionService().removeSelectionListener(this);
+		workbench.removeWindowListener(windowListener);
+		display.removeFilter(SWT.Activate, listener);
+		hookListener(lastActiveWorkbenchWindow, null);
+		lastActiveWorkbenchWindow = null;
+		lastActiveWorkbenchWindowShell = null;
+		lastActiveShell = null;
+		lastWindow = null;
+	}
+
+	@Override
+	public String[] getProvidedSourceNames() {
+		return PROVIDED_SOURCE_NAMES;
+	}
+
+	@Override
+	public Map getCurrentState() {
+
+		final Map currentState = new HashMap();
+
+		updateActiveShell(currentState);
+		updateActivePart(currentState);
+		updateSelection(currentState);
+
+		return currentState;
+	}
+
+	// Selection SourceProvider
+
+	ISelection selection;
+
+	private int updateSelection(final Map currentState) {
+		int sources = 0;
+		currentState.put(ISources.ACTIVE_CURRENT_SELECTION_NAME,
+				IEvaluationContext.UNDEFINED_VARIABLE);
+		Object object = currentState.get(ISources.ACTIVE_PART_NAME);
+		if (object instanceof IWorkbenchPart) {
+			IWorkbenchPart part = (IWorkbenchPart) object;
+			if (part.getSite() != null
+					&& part.getSite().getSelectionProvider() != null) {
+				sources = ISources.ACTIVE_CURRENT_SELECTION;
+				ISelection currentSelection = part.getSite()
+						.getSelectionProvider()
+						.getSelection();
+				currentState.put(ISources.ACTIVE_CURRENT_SELECTION_NAME,
+						currentSelection);
+			}
+		}
+		return sources;
+	}
+
+	@Override
+	public final void selectionChanged(final IWorkbenchPart part,
+			final ISelection newSelection) {
+
+		if (Util.equals(selection, newSelection))
+			return; // we have already handled the change
+
+		selection = newSelection;
+
+		if (DEBUG) {
+			logDebuggingInfo("Selection changed to " + selection); //$NON-NLS-1$
+		}
+
+		fireSourceChanged(ISources.ACTIVE_CURRENT_SELECTION,
+				ISources.ACTIVE_CURRENT_SELECTION_NAME, selection);
+	}
+
+	private final void updateWindows(IWorkbenchWindow newWindow) {
+		if (lastWindow == newWindow) {
+			return;
+		}
+
+		ISelection selection = null;
+		if (lastWindow != null) {
+			lastWindow.getSelectionService().removeSelectionListener(this);
+		}
+		if (newWindow != null) {
+			newWindow.getSelectionService().addSelectionListener(this);
+			selection = newWindow.getSelectionService().getSelection();
+		}
+		selectionChanged(null, selection);
+		lastWindow = newWindow;
+	}
+
+	// Active Part SourceProvider
+
+	/**
+	 * The last active editor part seen as active by this provider. This value
+	 * may be <code>null</code> if there is no currently active editor.
+	 */
+	private IEditorPart lastActiveEditor = null;
+
+	/**
+	 * The last active editor id seen as active by this provider. This value may
+	 * be <code>null</code> if there is no currently active editor.
+	 */
+	private String lastActiveEditorId = null;
+
+	/**
+	 * The last active part seen as active by this provider. This value may be
+	 * <code>null</code> if there is no currently active part.
+	 */
+	private IWorkbenchPart lastActivePart = null;
+
+	/**
+	 * The last active part id seen as active by this provider. This value may
+	 * be <code>null</code> if there is no currently active part.
+	 */
+	private String lastActivePartId = null;
+
+	/**
+	 * The last active part site seen by this provider. This value may be
+	 * <code>null</code> if there is no currently active site.
+	 */
+	private IWorkbenchPartSite lastActivePartSite = null;
+
+	private Object lastShowInInput = null;
+	private ISelection lastShowInSelection = null;
+
+	private final IPartListener partListener = new IPartListener() {
+
+		@Override
+		public final void partActivated(final IWorkbenchPart part) {
+			checkActivePart();
+		}
+
+		@Override
+		public final void partBroughtToTop(final IWorkbenchPart part) {
+			checkActivePart();
+		}
+
+		@Override
+		public final void partClosed(final IWorkbenchPart part) {
+			checkActivePart();
+		}
+
+		@Override
+		public final void partDeactivated(final IWorkbenchPart part) {
+			checkActivePart();
+		}
+
+		@Override
+		public final void partOpened(final IWorkbenchPart part) {
+			checkActivePart();
+		}
+
+	};
+
+	private final IWindowListener windowListener = new IWindowListener() {
+
+		@Override
+		public final void windowActivated(final IWorkbenchWindow window) {
+			checkActivePart();
+		}
+
+		@Override
+		public final void windowClosed(final IWorkbenchWindow window) {
+			if (window != null) {
+				window.getPartService().removePartListener(partListener);
+			}
+			checkActivePart();
+		}
+
+		@Override
+		public final void windowDeactivated(final IWorkbenchWindow window) {
+			checkActivePart();
+		}
+
+		@Override
+		public final void windowOpened(final IWorkbenchWindow window) {
+			if (window != null) {
+				window.getPartService().addPartListener(partListener);
+			}
+		}
+
+	};
+
+	private IEditorInput lastEditorInput;
+
+	public void handleCheck(Shell s) {
+		if (s != lastActiveShell) {
+			lastActiveShell = s;
+			checkActivePart();
+			IWorkbenchWindow window = null;
+			if (s.getData() instanceof WorkbenchWindow) {
+				window = (IWorkbenchWindow) s.getData();
+			}
+			updateWindows(window);
+
+		}
+	}
+
+	public final void checkActivePart() {
+		checkActivePart(false);
+	}
+
+	public final void checkActivePart(boolean updateShowInSelection) {
+		Map currentState = new HashMap();
+		updateActivePart(currentState, updateShowInSelection);
+
+		int sources = 0;
+
+		// Figure out what was changed.
+		final Object newActivePart = currentState
+				.get(ISources.ACTIVE_PART_NAME);
+		if (!Util.equals(newActivePart, lastActivePart)) {
+			sources |= ISources.ACTIVE_PART;
+			if (newActivePart != IEvaluationContext.UNDEFINED_VARIABLE) {
+				lastActivePart = (IWorkbenchPart) newActivePart;
+			} else {
+				lastActivePart = null;
+			}
+		}
+		final Object newActivePartId = currentState
+				.get(ISources.ACTIVE_PART_ID_NAME);
+		if (!Util.equals(newActivePartId, lastActivePartId)) {
+			sources |= ISources.ACTIVE_PART_ID;
+			if (newActivePartId != IEvaluationContext.UNDEFINED_VARIABLE) {
+				lastActivePartId = (String) newActivePartId;
+			} else {
+				lastActivePartId = null;
+			}
+		}
+		final Object newActivePartSite = currentState
+				.get(ISources.ACTIVE_SITE_NAME);
+		if (!Util.equals(newActivePartSite, lastActivePartSite)) {
+			sources |= ISources.ACTIVE_SITE;
+			if (newActivePartSite != IEvaluationContext.UNDEFINED_VARIABLE) {
+				lastActivePartSite = (IWorkbenchPartSite) newActivePartSite;
+			} else {
+				lastActivePartSite = null;
+			}
+		}
+		final Object newShowInInput = currentState.get(ISources.SHOW_IN_INPUT);
+		if (!Util.equals(newShowInInput, lastShowInInput)) {
+			sources |= ISources.ACTIVE_SITE;
+			lastShowInInput = newShowInInput;
+		}
+		if (updateShowInSelection) {
+			final Object newShowInSelection = currentState
+					.get(ISources.SHOW_IN_SELECTION);
+			if (!Util.equals(newShowInSelection, lastShowInSelection)) {
+				sources |= ISources.ACTIVE_SITE;
+				if (newShowInSelection != IEvaluationContext.UNDEFINED_VARIABLE) {
+					lastShowInSelection = (ISelection) newShowInSelection;
+				} else {
+					lastShowInSelection = null;
+				}
+			}
+		}
+		Object newActiveEditor = currentState.get(ISources.ACTIVE_EDITOR_NAME);
+		if (!Util.equals(newActiveEditor, lastActiveEditor)) {
+			sources |= ISources.ACTIVE_EDITOR;
+			newActiveEditor = (newActiveEditor == IEvaluationContext.UNDEFINED_VARIABLE ? null
+					: newActiveEditor);
+			hookListener(lastActiveEditor, (IEditorPart) newActiveEditor);
+			lastActiveEditor = (IEditorPart) newActiveEditor;
+		}
+		Object newEditorInput = currentState.get(ISources.ACTIVE_EDITOR_INPUT_NAME);
+		if (!Util.equals(newEditorInput, lastEditorInput)) {
+			sources |= ISources.ACTIVE_EDITOR;
+			if (newEditorInput != IEvaluationContext.UNDEFINED_VARIABLE) {
+				lastEditorInput = (IEditorInput) newEditorInput;
+			} else {
+				lastEditorInput = null;
+			}
+		}
+		final Object newActiveEditorId = currentState
+				.get(ISources.ACTIVE_EDITOR_ID_NAME);
+		if (!Util.equals(newActiveEditorId, lastActiveEditorId)) {
+			sources |= ISources.ACTIVE_EDITOR_ID;
+			if (newActiveEditorId != IEvaluationContext.UNDEFINED_VARIABLE) {
+				lastActiveEditorId = (String) newActiveEditorId;
+			} else {
+				lastActiveEditorId = null;
+			}
+		}
+
+		// Fire the event, if something has changed.
+		if (sources != 0) {
+			if (DEBUG) {
+				if ((sources & ISources.ACTIVE_PART) != 0) {
+					logDebuggingInfo("Active part changed to " //$NON-NLS-1$
+							+ lastActivePart);
+				}
+				if ((sources & ISources.ACTIVE_PART_ID) != 0) {
+					logDebuggingInfo("Active part id changed to " //$NON-NLS-1$
+							+ lastActivePartId);
+				}
+				if ((sources & ISources.ACTIVE_SITE) != 0) {
+					logDebuggingInfo("Active site changed to " //$NON-NLS-1$
+							+ lastActivePartSite);
+				}
+				if ((sources & ISources.ACTIVE_EDITOR) != 0) {
+					logDebuggingInfo("Active editor changed to " //$NON-NLS-1$
+							+ lastActiveEditor);
+				}
+				if ((sources & ISources.ACTIVE_EDITOR_ID) != 0) {
+					logDebuggingInfo("Active editor id changed to " //$NON-NLS-1$
+							+ lastActiveEditorId);
+				}
+			}
+			sources |= updateSelection(currentState);
+			fireSourceChanged(sources, currentState);
+		}
+	}
+
+	private IShowInSource getShowInSource(IWorkbenchPart sourcePart) {
+		return Adapters.adapt(sourcePart, IShowInSource.class);
+	}
+
+	private ShowInContext getContext(IWorkbenchPart sourcePart) {
+		IShowInSource source = getShowInSource(sourcePart);
+		if (source != null) {
+			ShowInContext context = source.getShowInContext();
+			if (context != null) {
+				return context;
+			}
+		} else if (sourcePart instanceof IEditorPart) {
+			Object input = ((IEditorPart) sourcePart).getEditorInput();
+			ISelectionProvider sp = sourcePart.getSite().getSelectionProvider();
+			ISelection sel = sp == null ? null : sp.getSelection();
+			return new ShowInContext(input, sel);
+		}
+		return null;
+	}
+
+	private IWorkbenchWindow getActiveWindow() {
+		final Shell newActiveShell = workbench.getDisplay().getActiveShell();
+		final IContextService contextService = workbench
+				.getService(IContextService.class);
+		if (contextService != null) {
+			final int shellType = contextService.getShellType(newActiveShell);
+			if (shellType != IContextService.TYPE_DIALOG) {
+				return workbench.getActiveWorkbenchWindow();
+			}
+		}
+		return null;
+	}
+
+	private void updateActivePart(Map currentState) {
+		updateActivePart(currentState, false);
+	}
+
+	private void updateActivePart(Map currentState, boolean updateShowInSelection) {
+		currentState.put(ISources.ACTIVE_SITE_NAME,
+				IEvaluationContext.UNDEFINED_VARIABLE);
+		currentState.put(ISources.ACTIVE_PART_NAME,
+				IEvaluationContext.UNDEFINED_VARIABLE);
+		currentState.put(ISources.ACTIVE_PART_ID_NAME,
+				IEvaluationContext.UNDEFINED_VARIABLE);
+		currentState.put(ISources.ACTIVE_EDITOR_NAME,
+				IEvaluationContext.UNDEFINED_VARIABLE);
+		currentState.put(ISources.ACTIVE_EDITOR_ID_NAME,
+				IEvaluationContext.UNDEFINED_VARIABLE);
+		currentState.put(ISources.SHOW_IN_INPUT,
+				IEvaluationContext.UNDEFINED_VARIABLE);
+		currentState.put(ISources.SHOW_IN_SELECTION,
+				IEvaluationContext.UNDEFINED_VARIABLE);
+
+		final IWorkbenchWindow activeWorkbenchWindow = getActiveWindow();
+		if (activeWorkbenchWindow != null) {
+			final IWorkbenchPage activeWorkbenchPage = activeWorkbenchWindow
+					.getActivePage();
+			if (activeWorkbenchPage != null) {
+				// Check the active workbench part.
+				final IWorkbenchPart newActivePart = activeWorkbenchPage
+						.getActivePart();
+				currentState.put(ISources.ACTIVE_PART_NAME, newActivePart);
+				if (newActivePart != null) {
+					final IWorkbenchPartSite activeWorkbenchPartSite = newActivePart
+							.getSite();
+					currentState.put(ISources.ACTIVE_SITE_NAME,
+							activeWorkbenchPartSite);
+					if (activeWorkbenchPartSite != null) {
+						final String newActivePartId = activeWorkbenchPartSite
+								.getId();
+						currentState.put(ISources.ACTIVE_PART_ID_NAME,
+								newActivePartId);
+					}
+					ShowInContext context = getContext(newActivePart);
+					if (context != null) {
+						Object input = context.getInput();
+						if (input != null) {
+							currentState.put(ISources.SHOW_IN_INPUT, input);
+						}
+						if (updateShowInSelection) {
+							ISelection selection = context.getSelection();
+							if (selection != null) {
+								currentState.put(ISources.SHOW_IN_SELECTION,
+										selection);
+							}
+						}
+					}
+				}
+
+				// Check the active editor part.
+				final IEditorPart newActiveEditor = activeWorkbenchPage
+						.getActiveEditor();
+				currentState.put(ISources.ACTIVE_EDITOR_NAME, newActiveEditor);
+				if (newActiveEditor != null) {
+					currentState.put(ISources.ACTIVE_EDITOR_INPUT_NAME,
+							newActiveEditor.getEditorInput());
+					final IEditorSite activeEditorSite = newActiveEditor
+							.getEditorSite();
+					if (activeEditorSite != null) {
+						final String newActiveEditorId = activeEditorSite
+								.getId();
+						currentState.put(ISources.ACTIVE_EDITOR_ID_NAME,
+								newActiveEditorId);
+					}
+				}
+			}
+		}
+
+	}
+
+	// Active Part SourceProvider
+
+	/**
+	 * The display on which this provider is working.
+	 */
+	private Display display;
+
+	/**
+	 * The last shell seen as active by this provider. This value may be
+	 * <code>null</code> if the last call to
+	 * <code>Display.getActiveShell()</code> returned <code>null</code>.
+	 */
+	private Shell lastActiveShell = null;
+
+	/**
+	 * The last workbench window shell seen as active by this provider. This
+	 * value may be <code>null</code> if the last call to
+	 * <code>workbench.getActiveWorkbenchWindow()</code> returned
+	 * <code>null</code>.
+	 */
+	private Shell lastActiveWorkbenchWindowShell = null;
+
+	/**
+	 * The last workbench window seen as active by this provider. This value may
+	 * be null if the last call to
+	 * <code>workbench.getActiveWorkbenchWindow()</code> returned
+	 * <code>null</code>.
+	 *
+	 * @since 3.3
+	 */
+	private WorkbenchWindow lastActiveWorkbenchWindow = null;
+
+	/**
+	 * The result of the last visibility check on the coolbar of the last active
+	 * workbench window.
+	 *
+	 * @since 3.3
+	 */
+	private Boolean lastCoolbarVisibility = Boolean.FALSE;
+
+	/**
+	 * The result of the last visibility check on the perspective bar of the
+	 * last active workbench window.
+	 *
+	 * @since 3.3
+	 */
+	private Boolean lastPerspectiveBarVisibility = Boolean.FALSE;
+
+	/**
+	 * The result of the last visibility check on the status line for the last
+	 * workbench window.
+	 *
+	 * @since 3.4
+	 */
+	private Boolean lastStatusLineVisibility = Boolean.FALSE;
+
+	/**
+	 * The last perspective id that was provided by this source.
+	 *
+	 * @since 3.4
+	 */
+	private String lastPerspectiveId = null;
+
+	/**
+	 * The listener to individual window properties.
+	 *
+	 * @since 3.3
+	 */
+	private final IPropertyChangeListener propertyListener = event -> {
+		if (WorkbenchWindow.PROP_COOLBAR_VISIBLE
+				.equals(event.getProperty())) {
+			Object newValue1 = event.getNewValue();
+			if (newValue1 == null || !(newValue1 instanceof Boolean))
+				return;
+			if (!lastCoolbarVisibility.equals(newValue1)) {
+				fireSourceChanged(
+						ISources.ACTIVE_WORKBENCH_WINDOW_SUBORDINATE,
+						ISources.ACTIVE_WORKBENCH_WINDOW_IS_COOLBAR_VISIBLE_NAME,
+						newValue1);
+				lastCoolbarVisibility = (Boolean) newValue1;
+			}
+		} else if (WorkbenchWindow.PROP_PERSPECTIVEBAR_VISIBLE.equals(event
+				.getProperty())) {
+			Object newValue2 = event.getNewValue();
+			if (newValue2 == null || !(newValue2 instanceof Boolean))
+				return;
+			if (!lastPerspectiveBarVisibility.equals(newValue2)) {
+				fireSourceChanged(
+						ISources.ACTIVE_WORKBENCH_WINDOW_SUBORDINATE,
+						ISources.ACTIVE_WORKBENCH_WINDOW_IS_PERSPECTIVEBAR_VISIBLE_NAME,
+						newValue2);
+				lastPerspectiveBarVisibility = (Boolean) newValue2;
+			}
+		} else if (WorkbenchWindow.PROP_STATUS_LINE_VISIBLE.equals(event
+				.getProperty())) {
+			Object newValue3 = event.getNewValue();
+			if (newValue3 == null || !(newValue3 instanceof Boolean))
+				return;
+			if (!lastStatusLineVisibility.equals(newValue3)) {
+				fireSourceChanged(
+						ISources.ACTIVE_WORKBENCH_WINDOW_SUBORDINATE,
+						ISources.ACTIVE_WORKBENCH_WINDOW_NAME
+								+ ".isStatusLineVisible", newValue3); //$NON-NLS-1$
+				lastStatusLineVisibility = (Boolean) newValue3;
+			}
+		}
+	};
+
+	IPerspectiveListener perspectiveListener = new IPerspectiveListener() {
+		@Override
+		public void perspectiveActivated(IWorkbenchPage page,
+				IPerspectiveDescriptor perspective) {
+			String id = perspective == null ? null : perspective.getId();
+			if (Util.equals(lastPerspectiveId, id)) {
+				return;
+			}
+
+			HashMap currentState = new HashMap();
+			int sources = updateSelection(currentState);
+			sources |= ISources.ACTIVE_WORKBENCH_WINDOW_SUBORDINATE;
+			currentState.put(
+					ISources.ACTIVE_WORKBENCH_WINDOW_ACTIVE_PERSPECTIVE_NAME,
+					id);
+			fireSourceChanged(sources, currentState);
+			lastPerspectiveId = id;
+		}
+
+		@Override
+		public void perspectiveChanged(IWorkbenchPage page,
+				IPerspectiveDescriptor perspective, String changeId) {
+		}
+	};
+
+	private IPropertyListener editorListener = (source, propId) -> {
+		if (propId == IEditorPart.PROP_INPUT) {
+			handleInputChanged((IEditorPart) source);
+		}
+	};
+
+
+	/**
+	 * The listener to shell activations on the display.
+	 */
+	private final Listener listener = event -> {
+		if (!(event.widget instanceof Shell)) {
+			if (DEBUG) {
+				logDebuggingInfo("WSP: passOnEvent: " + event.widget); //$NON-NLS-1$
+			}
+			return;
+		}
+		if (DEBUG) {
+			logDebuggingInfo("\tWSP:lastActiveShell: " + lastActiveShell); //$NON-NLS-1$
+			logDebuggingInfo("\tWSP:lastActiveWorkbenchWindowShell" + lastActiveWorkbenchWindowShell); //$NON-NLS-1$
+		}
+
+		final Map currentState = getCurrentState();
+		final Shell newActiveShell = (Shell) currentState
+				.get(ISources.ACTIVE_SHELL_NAME);
+		final WorkbenchWindow newActiveWorkbenchWindow = (WorkbenchWindow) currentState
+				.get(ISources.ACTIVE_WORKBENCH_WINDOW_NAME);
+		final Shell newActiveWorkbenchWindowShell = (Shell) currentState
+				.get(ISources.ACTIVE_WORKBENCH_WINDOW_SHELL_NAME);
+
+		// dont update the coolbar/perspective bar visibility unless we're
+		// processing a workbench window change
+		final Boolean newCoolbarVisibility = newActiveWorkbenchWindow == null ? lastCoolbarVisibility
+				: (newActiveWorkbenchWindow.getCoolBarVisible() ? Boolean.TRUE
+						: Boolean.FALSE);
+		final Boolean newPerspectiveBarVisibility = newActiveWorkbenchWindow == null ? lastPerspectiveBarVisibility
+				: (newActiveWorkbenchWindow.getPerspectiveBarVisible() ? Boolean.TRUE
+						: Boolean.FALSE);
+		final Boolean newStatusLineVis = newActiveWorkbenchWindow == null ? lastStatusLineVisibility
+				: (newActiveWorkbenchWindow.getStatusLineVisible() ? Boolean.TRUE
+						: Boolean.FALSE);
+
+		String perspectiveId = lastPerspectiveId;
+		if (newActiveWorkbenchWindow != null) {
+			IWorkbenchPage activePage = newActiveWorkbenchWindow
+					.getActivePage();
+			if (activePage != null) {
+				IPerspectiveDescriptor perspective = activePage
+						.getPerspective();
+				if (perspective != null) {
+					perspectiveId = perspective.getId();
+				}
+			}
+		}
+
+		// Figure out which variables have changed.
+		final boolean shellChanged = newActiveShell != lastActiveShell;
+		final boolean windowChanged = newActiveWorkbenchWindowShell != lastActiveWorkbenchWindowShell;
+		final boolean coolbarChanged = newCoolbarVisibility != lastCoolbarVisibility;
+		final boolean statusLineChanged = newStatusLineVis != lastStatusLineVisibility;
+
+		final boolean perspectiveBarChanged = newPerspectiveBarVisibility != lastPerspectiveBarVisibility;
+		final boolean perspectiveIdChanged = !Util.equals(
+				lastPerspectiveId, perspectiveId);
+		// Fire an event for those sources that have changed.
+		if (shellChanged && windowChanged) {
+			final Map sourceValuesByName1 = new HashMap(5);
+			sourceValuesByName1.put(ISources.ACTIVE_SHELL_NAME,
+					newActiveShell);
+			sourceValuesByName1.put(ISources.ACTIVE_WORKBENCH_WINDOW_NAME,
+					newActiveWorkbenchWindow);
+			sourceValuesByName1.put(
+					ISources.ACTIVE_WORKBENCH_WINDOW_SHELL_NAME,
+					newActiveWorkbenchWindowShell);
+			int sourceFlags1 = ISources.ACTIVE_SHELL
+					| ISources.ACTIVE_WORKBENCH_WINDOW;
+
+			if (coolbarChanged) {
+				sourceValuesByName1
+						.put(
+								ISources.ACTIVE_WORKBENCH_WINDOW_IS_COOLBAR_VISIBLE_NAME,
+								newCoolbarVisibility);
+				sourceFlags1 |= ISources.ACTIVE_WORKBENCH_WINDOW_SUBORDINATE;
+			}
+			if (statusLineChanged) {
+				sourceValuesByName1.put(STATUS_LINE_VIS, newStatusLineVis);
+				sourceFlags1 |= ISources.ACTIVE_WORKBENCH_WINDOW_SUBORDINATE;
+			}
+			if (perspectiveBarChanged) {
+				sourceValuesByName1
+						.put(
+								ISources.ACTIVE_WORKBENCH_WINDOW_IS_PERSPECTIVEBAR_VISIBLE_NAME,
+								newPerspectiveBarVisibility);
+				sourceFlags1 |= ISources.ACTIVE_WORKBENCH_WINDOW_SUBORDINATE;
+			}
+			if (perspectiveIdChanged) {
+				sourceValuesByName1
+						.put(
+								ISources.ACTIVE_WORKBENCH_WINDOW_ACTIVE_PERSPECTIVE_NAME,
+								perspectiveId);
+				sourceFlags1 |= ISources.ACTIVE_WORKBENCH_WINDOW_SUBORDINATE;
+			}
+
+			if (DEBUG) {
+				logDebuggingInfo("Active shell changed to " //$NON-NLS-1$
+						+ newActiveShell);
+				logDebuggingInfo("Active workbench window changed to " //$NON-NLS-1$
+						+ newActiveWorkbenchWindow);
+				logDebuggingInfo("Active workbench window shell changed to " //$NON-NLS-1$
+						+ newActiveWorkbenchWindowShell);
+				logDebuggingInfo("Active workbench window coolbar visibility " //$NON-NLS-1$
+						+ newCoolbarVisibility);
+				logDebuggingInfo("Active workbench window perspective bar visibility " //$NON-NLS-1$
+						+ newPerspectiveBarVisibility);
+				logDebuggingInfo("Active workbench window status line visibility " //$NON-NLS-1$
+						+ newStatusLineVis);
+			}
+
+			fireSourceChanged(sourceFlags1, sourceValuesByName1);
+			hookListener(lastActiveWorkbenchWindow,
+					newActiveWorkbenchWindow);
+
+		} else if (shellChanged) {
+			if (DEBUG) {
+				logDebuggingInfo("Active shell changed to " //$NON-NLS-1$
+						+ newActiveShell);
+			}
+			fireSourceChanged(ISources.ACTIVE_SHELL,
+					ISources.ACTIVE_SHELL_NAME, newActiveShell);
+		} else if (windowChanged) {
+			final Map sourceValuesByName2 = new HashMap(4);
+			sourceValuesByName2.put(ISources.ACTIVE_WORKBENCH_WINDOW_NAME,
+					newActiveWorkbenchWindow);
+			sourceValuesByName2.put(
+					ISources.ACTIVE_WORKBENCH_WINDOW_SHELL_NAME,
+					newActiveWorkbenchWindowShell);
+
+			int sourceFlags2 = ISources.ACTIVE_SHELL
+					| ISources.ACTIVE_WORKBENCH_WINDOW;
+
+			if (coolbarChanged) {
+				sourceValuesByName2
+						.put(
+								ISources.ACTIVE_WORKBENCH_WINDOW_IS_COOLBAR_VISIBLE_NAME,
+								newCoolbarVisibility);
+				sourceFlags2 |= ISources.ACTIVE_WORKBENCH_WINDOW_SUBORDINATE;
+			}
+			if (statusLineChanged) {
+				sourceValuesByName2.put(STATUS_LINE_VIS, newStatusLineVis);
+				sourceFlags2 |= ISources.ACTIVE_WORKBENCH_WINDOW_SUBORDINATE;
+			}
+			if (perspectiveBarChanged) {
+				sourceValuesByName2
+						.put(
+								ISources.ACTIVE_WORKBENCH_WINDOW_IS_PERSPECTIVEBAR_VISIBLE_NAME,
+								newPerspectiveBarVisibility);
+				sourceFlags2 |= ISources.ACTIVE_WORKBENCH_WINDOW_SUBORDINATE;
+			}
+			if (perspectiveIdChanged) {
+				sourceValuesByName2
+						.put(
+								ISources.ACTIVE_WORKBENCH_WINDOW_ACTIVE_PERSPECTIVE_NAME,
+								perspectiveId);
+				sourceFlags2 |= ISources.ACTIVE_WORKBENCH_WINDOW_SUBORDINATE;
+			}
+
+			if (DEBUG) {
+				logDebuggingInfo("Active workbench window changed to " //$NON-NLS-1$
+						+ newActiveWorkbenchWindow);
+				logDebuggingInfo("Active workbench window shell changed to " //$NON-NLS-1$
+						+ newActiveWorkbenchWindowShell);
+				logDebuggingInfo("Active workbench window coolbar visibility " //$NON-NLS-1$
+						+ newCoolbarVisibility);
+				logDebuggingInfo("Active workbench window perspective bar visibility " //$NON-NLS-1$
+						+ newPerspectiveBarVisibility);
+				logDebuggingInfo("Active workbench window status line visibility " //$NON-NLS-1$
+						+ newStatusLineVis);
+			}
+
+			fireSourceChanged(sourceFlags2, sourceValuesByName2);
+			hookListener(lastActiveWorkbenchWindow,
+					newActiveWorkbenchWindow);
+		}
+
+		if (shellChanged || windowChanged) {
+			checkOtherSources((Shell) event.widget);
+		}
+
+		// Update the member variables.
+		lastActiveShell = newActiveShell;
+		lastActiveWorkbenchWindowShell = newActiveWorkbenchWindowShell;
+		lastActiveWorkbenchWindow = newActiveWorkbenchWindow;
+		lastCoolbarVisibility = newCoolbarVisibility;
+		lastStatusLineVisibility = newStatusLineVis;
+		lastPerspectiveBarVisibility = newPerspectiveBarVisibility;
+		lastPerspectiveId = perspectiveId;
+	};
+
+
+	protected void checkOtherSources(Shell s) {
+		handleCheck(s);
+	}
+
+	protected void handleInputChanged(IEditorPart editor) {
+		IEditorInput newInput = editor.getEditorInput();
+		if (!Util.equals(newInput, lastEditorInput)) {
+			fireSourceChanged(ISources.ACTIVE_EDITOR,
+					ISources.ACTIVE_EDITOR_INPUT_NAME,
+					newInput == null ? IEvaluationContext.UNDEFINED_VARIABLE
+							: newInput);
+			lastEditorInput = newInput;
+		}
+	}
+
+	private void hookListener(WorkbenchWindow lastActiveWorkbenchWindow,
+			WorkbenchWindow newActiveWorkbenchWindow) {
+		if (lastActiveWorkbenchWindow != null) {
+			lastActiveWorkbenchWindow
+					.removePropertyChangeListener(propertyListener);
+			lastActiveWorkbenchWindow
+					.removePerspectiveListener(perspectiveListener);
+		}
+
+		if (newActiveWorkbenchWindow != null) {
+			newActiveWorkbenchWindow
+					.addPropertyChangeListener(propertyListener);
+			newActiveWorkbenchWindow
+					.addPerspectiveListener(perspectiveListener);
+		}
+	}
+
+	private void hookListener(IEditorPart lastActiveEditor,
+			IEditorPart newActiveEditor) {
+		if (lastActiveEditor!=null) {
+			lastActiveEditor.removePropertyListener(editorListener);
+		}
+		if (newActiveEditor!=null) {
+			newActiveEditor.addPropertyListener(editorListener);
+		}
+	}
+
+	private void updateActiveShell(Map currentState) {
+
+		final Shell newActiveShell = display.getActiveShell();
+		currentState.put(ISources.ACTIVE_SHELL_NAME, newActiveShell);
+
+		/*
+		 * We will fallback to the workbench window, but only if a dialog is not
+		 * open.
+		 */
+		final IContextService contextService = workbench
+				.getService(IContextService.class);
+		if (contextService == null) {
+			return;
+		}
+
+		final int shellType = contextService.getShellType(newActiveShell);
+		if (shellType == IContextService.TYPE_DIALOG)
+			return;
+
+		final WorkbenchWindow newActiveWorkbenchWindow = (WorkbenchWindow) workbench
+				.getActiveWorkbenchWindow();
+		final Shell newActiveWorkbenchWindowShell;
+		if (newActiveWorkbenchWindow == null) {
+			newActiveWorkbenchWindowShell = null;
+		} else {
+			newActiveWorkbenchWindowShell = newActiveWorkbenchWindow.getShell();
+		}
+		currentState.put(ISources.ACTIVE_WORKBENCH_WINDOW_NAME,
+				newActiveWorkbenchWindow);
+		currentState.put(ISources.ACTIVE_WORKBENCH_WINDOW_SHELL_NAME,
+				newActiveWorkbenchWindowShell);
+
+		final Boolean newCoolbarVisibility = newActiveWorkbenchWindow == null ? lastCoolbarVisibility
+				: (newActiveWorkbenchWindow.getCoolBarVisible() ? Boolean.TRUE
+						: Boolean.FALSE);
+		final Boolean newPerspectiveBarVisibility = newActiveWorkbenchWindow == null ? lastPerspectiveBarVisibility
+				: (newActiveWorkbenchWindow.getPerspectiveBarVisible() ? Boolean.TRUE
+						: Boolean.FALSE);
+		final Boolean newStatusLineVis = newActiveWorkbenchWindow == null ? lastStatusLineVisibility
+				: (newActiveWorkbenchWindow.getStatusLineVisible() ? Boolean.TRUE
+						: Boolean.FALSE);
+
+		String perspectiveId = lastPerspectiveId;
+		if (newActiveWorkbenchWindow != null) {
+			IWorkbenchPage activePage = newActiveWorkbenchWindow
+					.getActivePage();
+			if (activePage != null) {
+				IPerspectiveDescriptor perspective = activePage
+						.getPerspective();
+				if (perspective != null) {
+					perspectiveId = perspective.getId();
+				}
+			}
+		}
+
+		currentState.put(
+				ISources.ACTIVE_WORKBENCH_WINDOW_IS_COOLBAR_VISIBLE_NAME,
+				newCoolbarVisibility);
+
+		currentState
+				.put(
+						ISources.ACTIVE_WORKBENCH_WINDOW_IS_PERSPECTIVEBAR_VISIBLE_NAME,
+						newPerspectiveBarVisibility);
+		currentState.put(STATUS_LINE_VIS, newStatusLineVis);
+
+		currentState.put(
+				ISources.ACTIVE_WORKBENCH_WINDOW_ACTIVE_PERSPECTIVE_NAME,
+				perspectiveId);
+
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/splash/EclipseSplashHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/splash/EclipseSplashHandler.java
new file mode 100644
index 0000000..166c5ee
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/splash/EclipseSplashHandler.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2014 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 430848
+ *******************************************************************************/
+package org.eclipse.ui.internal.splash;
+
+import org.eclipse.core.runtime.IProduct;
+import org.eclipse.core.runtime.Platform;
+//import org.eclipse.e4.ui.css.swt.CSSSWTConstants;
+import org.eclipse.jface.resource.StringConverter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.branding.IProductConstants;
+import org.eclipse.ui.internal.util.PrefUtil;
+import org.eclipse.ui.splash.BasicSplashHandler;
+
+/**
+ * Parses the well known product constants and constructs a splash handler
+ * accordingly.
+ */
+public class EclipseSplashHandler extends BasicSplashHandler {
+
+	// CSS id can be used to style the label for the build ID
+	private static final String CSS_ID_SPLASH_BUILD_ID = "org-eclipse-ui-buildid-text"; //$NON-NLS-1$
+
+	/**
+	 * Initializes the splash screen.
+	 * <p>
+	 * <strong>WARNING:</strong> Do not change the default values as existing
+	 * products might rely on them.
+	 * </p>
+	 *
+	 * @param splash
+	 *            the shell that contains the splash screen
+	 */
+	@Override
+	public void init(Shell splash) {
+		super.init(splash);
+		String progressRectString = null;
+		String messageRectString = null;
+		String foregroundColorString = null;
+		IProduct product = Platform.getProduct();
+		if (product != null) {
+			progressRectString = product
+					.getProperty(IProductConstants.STARTUP_PROGRESS_RECT);
+			messageRectString = product
+					.getProperty(IProductConstants.STARTUP_MESSAGE_RECT);
+			foregroundColorString = product
+					.getProperty(IProductConstants.STARTUP_FOREGROUND_COLOR);
+		}
+		Rectangle progressRect = StringConverter.asRectangle(
+				progressRectString, new Rectangle(10, 10, 300, 15));
+		setProgressRect(progressRect);
+
+		Rectangle messageRect = StringConverter.asRectangle(messageRectString,
+				new Rectangle(10, 35, 300, 15));
+		setMessageRect(messageRect);
+
+		int foregroundColorInteger;
+		try {
+			foregroundColorInteger = Integer
+					.parseInt(foregroundColorString, 16);
+		} catch (Exception ex) {
+			foregroundColorInteger = 0xD2D7FF; // off white
+		}
+
+		setForeground(new RGB((foregroundColorInteger & 0xFF0000) >> 16,
+				(foregroundColorInteger & 0xFF00) >> 8,
+				foregroundColorInteger & 0xFF));
+		// the following code will be removed for release time
+		if (PrefUtil.getInternalPreferenceStore().getBoolean(
+				"SHOW_BUILDID_ON_STARTUP")) { //$NON-NLS-1$
+			final String buildId = System.getProperty(
+					"eclipse.buildId", "Unknown Build"); //$NON-NLS-1$ //$NON-NLS-2$
+			// find the specified location.  Not currently API
+			// hardcoded to be sensible with our current splash Graphic
+
+			String buildIdLocString = product.getProperty("buildIdLocation"); //$NON-NLS-1$
+			String buildIdSize = product.getProperty("buildIdSize"); //$NON-NLS-1$
+			if (buildIdLocString != null) {
+				if (buildIdSize != null) {
+					buildIdLocString += "," + buildIdSize; //$NON-NLS-1$
+				} else {
+					buildIdLocString += ",100,40"; //$NON-NLS-1$
+				}
+			}
+			Rectangle buildIdRectangle = StringConverter.asRectangle(buildIdLocString,
+					new Rectangle(322, 190, 100, 40));
+
+			Label idLabel = new Label(getContent(), SWT.RIGHT);
+			idLabel.setForeground(getForeground());
+			idLabel.setBounds(buildIdRectangle);
+			idLabel.setText(buildId);
+			// RAP
+//			idLabel.setData(CSSSWTConstants.CSS_ID_KEY, CSS_ID_SPLASH_BUILD_ID);
+		}
+		else {
+			getContent(); // ensure creation of the progress
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/splash/SplashHandlerFactory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/splash/SplashHandlerFactory.java
new file mode 100644
index 0000000..40aea16
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/splash/SplashHandlerFactory.java
@@ -0,0 +1,147 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal.splash;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IProduct;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.jface.util.SafeRunnable;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.splash.AbstractSplashHandler;
+
+/**
+ * Simple non-caching access to the splashHandler extension point.
+ *
+ * @since 3.3
+ */
+public final class SplashHandlerFactory {
+
+	/**
+	 * Find the splash handler for the given product or <code>null</code> if
+	 * it cannot be found.
+	 *
+	 * @param product
+	 *            the product
+	 * @return the splash or <code>null</code>
+	 */
+	public static AbstractSplashHandler findSplashHandlerFor(IProduct product) {
+		if (product == null)
+			return null;
+
+		IExtensionPoint point = Platform.getExtensionRegistry()
+				.getExtensionPoint(PlatformUI.PLUGIN_ID,
+						IWorkbenchRegistryConstants.PL_SPLASH_HANDLERS);
+
+		if (point == null)
+			return null;
+
+		IExtension[] extensions = point.getExtensions();
+		Map idToSplash = new HashMap(); // String->ConfigurationElement
+		String[] targetId = new String[1];
+		for (IExtension extension : extensions) {
+			IConfigurationElement[] children = extension.getConfigurationElements();
+			for (IConfigurationElement element : children) {
+				AbstractSplashHandler handler = processElement(element, idToSplash, targetId, product);
+				if (handler != null)
+					return handler;
+
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Process a given element.
+	 *
+	 * @param configurationElement
+	 *            the element to process
+	 * @param idToSplash
+	 *            the map of current splash elements
+	 * @param targetId
+	 *            the target id if known
+	 * @param product
+	 *            the product to search for
+	 * @return a splash matching the target id from this element or
+	 *         <code>null</code>
+	 */
+	private static AbstractSplashHandler processElement(
+			IConfigurationElement configurationElement, Map idToSplash,
+			String[] targetId, IProduct product) {
+		String type = configurationElement.getName();
+		if (IWorkbenchRegistryConstants.TAG_SPLASH_HANDLER.equals(type)) {
+			String id = configurationElement
+					.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+			if (id == null)
+				return null;
+
+			// we know the target and this element is it
+			if (targetId[0] != null && id.equals(targetId[0])) {
+				return create(configurationElement);
+			}
+			// store for later examination
+			idToSplash.put(id, configurationElement);
+
+		} else if (IWorkbenchRegistryConstants.TAG_SPLASH_HANDLER_PRODUCT_BINDING
+				.equals(type)) {
+			String productId = configurationElement
+					.getAttribute(IWorkbenchRegistryConstants.ATT_PRODUCTID);
+			if (product.getId().equals(productId) && targetId[0] == null) { // we
+				// found the target ID
+				targetId[0] = configurationElement
+						.getAttribute(IWorkbenchRegistryConstants.ATT_SPLASH_ID);
+				// check all currently located splashes
+				IConfigurationElement splashElement = (IConfigurationElement) idToSplash
+						.get(targetId[0]);
+				if (splashElement != null)
+					return create(splashElement);
+			}
+		}
+
+		return null;
+	}
+
+	/**
+	 * Create the splash implementation.
+	 *
+	 * @param splashElement
+	 *            the element to create from
+	 * @return the element or <code>null</code> if it couldn't be created
+	 */
+	private static AbstractSplashHandler create(
+			final IConfigurationElement splashElement) {
+		final AbstractSplashHandler[] handler = new AbstractSplashHandler[1];
+		SafeRunner.run(new SafeRunnable() {
+
+			@Override
+			public void run() throws Exception {
+				handler[0] = (AbstractSplashHandler) WorkbenchPlugin
+						.createExtension(splashElement,
+								IWorkbenchRegistryConstants.ATT_CLASS);
+			}
+
+			@Override
+			public void handleException(Throwable e) {
+				WorkbenchPlugin
+						.log("Problem creating splash implementation", e); //$NON-NLS-1$
+			}
+		});
+
+		return handler[0];
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/DefaultDetailsArea.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/DefaultDetailsArea.java
new file mode 100644
index 0000000..fd26811
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/DefaultDetailsArea.java
@@ -0,0 +1,361 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ ******************************************************************************/
+
+package org.eclipse.ui.internal.statushandlers;
+
+import java.util.Collection;
+import java.util.Date;
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.dnd.DND;
+import org.eclipse.swt.dnd.DragSource;
+import org.eclipse.swt.dnd.DragSourceEvent;
+import org.eclipse.swt.dnd.DragSourceListener;
+import org.eclipse.swt.dnd.TextTransfer;
+import org.eclipse.swt.dnd.Transfer;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.progress.ProgressMessages;
+import org.eclipse.ui.keys.IBindingService;
+import org.eclipse.ui.statushandlers.AbstractStatusAreaProvider;
+import org.eclipse.ui.statushandlers.IStatusAdapterConstants;
+import org.eclipse.ui.statushandlers.StatusAdapter;
+
+import com.ibm.icu.text.DateFormat;
+
+/**
+ * The default details area displaying a tree of statuses.
+ */
+public class DefaultDetailsArea extends AbstractStatusAreaProvider {
+
+	private static final int MINIMUM_HEIGHT = 100;
+
+	/*
+	 * All statuses should be displayed.
+	 */
+	private int mask;
+
+	/*
+	 * New child entry in the list will be shifted by a number of pixels
+	 */
+	private static final int NESTING_INDENT = 15;
+
+	// RAP [bm] StyledText
+	private Text text;
+//	private StyledText text;
+
+	private boolean handleOkStatuses;
+
+	private Map dialogState;
+
+	private MenuItem copyAction;
+
+	/**
+	 * @param dialogState
+	 */
+	public DefaultDetailsArea(Map dialogState) {
+		this.dialogState = dialogState;
+		handleOkStatuses = ((Boolean) dialogState
+				.get(IStatusDialogConstants.HANDLE_OK_STATUSES)).booleanValue();
+		mask = ((Integer) dialogState.get(IStatusDialogConstants.MASK))
+				.intValue();
+	}
+
+	@Override
+	public Control createSupportArea(Composite parent,
+			StatusAdapter statusAdapter) {
+		Composite area = createArea(parent);
+		setStatusAdapter(statusAdapter);
+		return area;
+	}
+
+	protected Composite createArea(Composite parent) {
+		parent = new Composite(parent, SWT.NONE);
+		parent.setLayout(new GridLayout());
+		parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+		// RAP [bm] StylyedText
+				text = new Text(parent, SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI
+						| SWT.BORDER | SWT.READ_ONLY | SWT.WRAP);
+//				text = new StyledText(parent, SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI
+//						| SWT.BORDER | SWT.READ_ONLY | SWT.WRAP);
+				text.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_WHITE));
+				GridData gd = new GridData(GridData.FILL_BOTH);
+		gd.grabExcessHorizontalSpace = true;
+		gd.grabExcessVerticalSpace = true;
+		gd.widthHint = 250;
+		gd.minimumHeight = MINIMUM_HEIGHT;
+		text.setLayoutData(gd);
+		// There is no support for triggering commands in the dialogs. I am
+		// trying to emulate the workbench behavior as exactly as possible.
+		IBindingService binding = PlatformUI.getWorkbench()
+				.getService(IBindingService.class);
+		// find bindings for copy action
+		// RAP [bm] KeyListener
+//      final TriggerSequence ts[] = binding
+//              .getActiveBindingsFor(ActionFactory.COPY.getCommandId());
+//      text.addKeyListener(new KeyListener() {
+//
+//          ArrayList keyList = new ArrayList();
+//
+//          public void keyPressed(KeyEvent e) {
+//              // get the character. reverse the ctrl modifier if necessary
+//              char character = e.character;
+//              boolean ctrlDown = (e.stateMask & SWT.CTRL) != 0;
+//              if (ctrlDown && e.character != e.keyCode && e.character < 0x20
+//                      && (e.keyCode & SWT.KEYCODE_BIT) == 0) {
+//                  character += 0x40;
+//              }
+//              // do not process modifier keys
+//              if ((e.keyCode & (~SWT.MODIFIER_MASK)) == 0) {
+//                  return;
+//              }
+//              // if there is a character, use it. if no character available,
+//              // try with key code
+//              KeyStroke ks = KeyStroke.getInstance(e.stateMask,
+//                      character != 0 ? character : e.keyCode);
+//              keyList.add(ks);
+//              KeySequence sequence = KeySequence.getInstance(keyList);
+//              boolean partialMatch = false;
+//              for (int i = 0; i < ts.length; i++) {
+//                  if (ts[i].equals(sequence)) {
+//                      copyToClipboard();
+//                      keyList.clear();
+//                      break;
+//                  }
+//                  if (ts[i].startsWith(sequence, false)) {
+//                      partialMatch = true;
+//                  }
+//                  for (int j = 0; j < ts[i].getTriggers().length; j++) {
+//                      if (ts[i].getTriggers()[j].equals(ks)) {
+//                          partialMatch = true;
+//                      }
+//                  }
+//              }
+//              if (!partialMatch) {
+//                  keyList.clear();
+//              }
+//          }
+//
+//          public void keyReleased(KeyEvent e) {
+//              // no op
+//          }
+//      });
+		text.addSelectionListener(new SelectionListener() {
+
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				if (text.getSelectionText().length() == 0) {
+					if (copyAction != null && !copyAction.isDisposed()) {
+						copyAction.setEnabled(false);
+					}
+				} else {
+					if (copyAction != null && !copyAction.isDisposed()) {
+						copyAction.setEnabled(true);
+					}
+				}
+			}
+
+			@Override
+			public void widgetDefaultSelected(SelectionEvent e) {
+				widgetSelected(e);
+			}
+
+		});
+		createDNDSource();
+		createCopyAction(parent);
+		Dialog.applyDialogFont(parent);
+		return parent;
+	}
+
+	private void setStatusAdapter(StatusAdapter adapter) {
+		populateList(text, adapter.getStatus(), 0, new int[] { 0 });
+		if (!isMulti()) {
+			Long timestamp = (Long) adapter
+					.getProperty(IStatusAdapterConstants.TIMESTAMP_PROPERTY);
+
+			if (timestamp != null) {
+				String date = DateFormat.getDateTimeInstance(DateFormat.LONG,
+						DateFormat.LONG)
+						.format(new Date(timestamp.longValue()));
+				text.append(NLS.bind(ProgressMessages.get().JobInfo_Error,
+						(new Object[] { "", date }))); //$NON-NLS-1$
+			}
+		}
+		int delimiterLength = getLineSeparator().length();
+		// RAP [bm] StyledText#replaceTextRange
+//		text.replaceTextRange(text.getText().length() - delimiterLength,
+//				delimiterLength, ""); //$NON-NLS-1$
+		String newText = text.getText();
+		newText = newText.substring(0, newText.length() - delimiterLength);
+		text.setText(newText);
+		adjustHeight(text);
+	}
+
+	// RAP [bm] StyledText
+//	private void adjustHeight(StyledText text) {
+	private void adjustHeight(Text text) {
+		// RAP [bm] Text#getLineCount
+//		int lineCount = text.getLineCount();
+		int lineCount = 2;
+		int lineHeight = text.getLineHeight();
+		int startPos = text.getLocation().y;
+		Composite c = text.getParent();
+		while (c != null) {
+			startPos += c.getLocation().y;
+			c = c.getParent();
+		}
+		// the text is not positioned yet, we assume that it will appear
+		// on the bottom of the dialog
+		startPos += text.getShell().getBounds().height;
+		int screenHeight = text.getShell().getMonitor().getBounds().height;
+		int availableScreenForText = screenHeight - startPos;
+		if (availableScreenForText <= MINIMUM_HEIGHT) {
+			// should not happen. But in that case nothing can improve user
+			// experience.
+			return;
+		}
+		int desiredHeight = lineCount * lineHeight;
+		if (desiredHeight > availableScreenForText * 0.75) {
+			((GridData) text.getLayoutData()).heightHint = (int) (availableScreenForText * 0.75);
+		}
+	}
+
+	/**
+	 * Creates DND source for the list
+	 */
+	private void createDNDSource() {
+		DragSource ds = new DragSource(text, DND.DROP_COPY);
+		ds.setTransfer(new Transfer[] { TextTransfer.getInstance() });
+		ds.addDragListener(new DragSourceListener() {
+			@Override
+			public void dragFinished(DragSourceEvent event) {
+			}
+
+			@Override
+			public void dragSetData(DragSourceEvent event) {
+				if (TextTransfer.getInstance().isSupportedType(event.dataType)) {
+					event.data = text.getSelectionText();
+				}
+			}
+
+			@Override
+			public void dragStart(DragSourceEvent event) {
+			}
+		});
+	}
+
+	private void createCopyAction(final Composite parent) {
+        // RAP [bm]: Clipboard
+//      Menu menu = new Menu(parent.getShell(), SWT.POP_UP);
+//      MenuItem copyAction = new MenuItem(menu, SWT.PUSH);
+//      copyAction.setText(JFaceResources.getString("copy")); //$NON-NLS-1$
+//      copyAction.addSelectionListener(new SelectionAdapter() {
+//
+//          /*
+//           * (non-Javadoc)
+//           * 
+//           * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
+//           */
+//          public void widgetSelected(SelectionEvent e) {
+//              clipboard = new Clipboard(parent.getDisplay());
+//              clipboard.setContents(new Object[] { prepareCopyString() },
+//                      new Transfer[] { TextTransfer.getInstance() });
+//              super.widgetSelected(e);
+//          }
+//
+//      });
+//      list.setMenu(menu);
+        // RAPEND: [bm] 
+	}
+
+	// RAP [bm] StyledText
+//	private void populateList(StyledText text, IStatus status, int nesting,
+	private void populateList(Text text, IStatus status, int nesting,
+			int[] lineNumber) {
+		if (!status.matches(mask) && !(handleOkStatuses && status.isOK())) {
+			return;
+		}
+		appendNewLine(text, status.getMessage(), nesting, lineNumber[0]++);
+
+		// Look for a nested core exception
+		Throwable t = status.getException();
+		if (t instanceof CoreException) {
+			CoreException ce = (CoreException) t;
+			populateList(text, ce.getStatus(), nesting + 1, lineNumber);
+		} else if (t != null) {
+			// Include low-level exception message
+			String message = t.getLocalizedMessage();
+			if (message == null) {
+				message = t.toString();
+			}
+			appendNewLine(text, message, nesting, lineNumber[0]++);
+		}
+
+		for (IStatus child : status.getChildren()) {
+			populateList(text, child, nesting + 1, lineNumber);
+		}
+	}
+
+	private String getLineSeparator() {
+		return System.getProperty("line.separator"); //$NON-NLS-1$
+	}
+
+	// RAP [bm] StyledText
+//	private void appendNewLine(StyledText text, String line, int indentLevel,
+	private void appendNewLine(Text text, String line, int indentLevel,
+			int lineNumber) {
+		text.append(line + getLineSeparator());
+		int pixelIndent = indentLevel * NESTING_INDENT;
+		if (lineNumber != 0) {
+			pixelIndent += NESTING_INDENT / 2;
+		}
+		// RAP [bm] StyledText
+//		text.setLineIndent(lineNumber, 1, pixelIndent);
+//		text.setLineWrapIndent(lineNumber, 1, indentLevel * NESTING_INDENT);
+	}
+
+	// RAP [bm] Clipboard
+	private void copyToClipboard() {
+//		Clipboard clipboard = null;
+//		try {
+//			clipboard = new Clipboard(text.getDisplay());
+//			clipboard.setContents(new Object[] { text.getSelectionText() },
+//					new Transfer[] { TextTransfer.getInstance() });
+//		} finally {
+//			if (clipboard != null) {
+//				clipboard.dispose();
+//			}
+//		}
+	}
+
+	/**
+	 * This method checks if status dialog holds more than one status.
+	 *
+	 * @return true if the dialog has one more than one status.
+	 */
+	private boolean isMulti() {
+		return ((Collection) dialogState
+				.get(IStatusDialogConstants.STATUS_ADAPTERS)).size() != 1;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/DetailsAreaManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/DetailsAreaManager.java
new file mode 100644
index 0000000..8a4e7eb
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/DetailsAreaManager.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2015 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.ui.internal.statushandlers;
+
+import java.util.Map;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.statushandlers.AbstractStatusAreaProvider;
+import org.eclipse.ui.statushandlers.StatusAdapter;
+
+
+/**
+ * This class is responsible for managing details area.
+ */
+public class DetailsAreaManager {
+
+	private Map dialogState;
+	private Control control = null;
+
+	/**
+	 * @param dialogState
+	 */
+	public DetailsAreaManager(Map dialogState) {
+		this.dialogState = dialogState;
+	}
+
+	/**
+	 * Closes the details area
+	 */
+	public void close() {
+		if (control != null && !control.isDisposed()) {
+			control.dispose();
+		}
+	}
+
+	/**
+	 * This method is responsible for creating details area on the specified
+	 * Composite and displaying specified StatusAdapter
+	 *
+	 * @param parent
+	 *            A composite on which should be the details area created.
+	 * @param statusAdapter
+	 *            StatusAdapter for which should be the details area
+	 *            created.
+	 */
+	public void createDetailsArea(Composite parent,
+			StatusAdapter statusAdapter) {
+		Composite container = new Composite(parent, SWT.NONE);
+		container.setLayout(GridLayoutFactory.fillDefaults().create());
+		container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+		getProvider().createSupportArea(container, statusAdapter);
+		control = container;
+	}
+
+	/**
+	 * Returns current detail area provider.
+	 *
+	 * @return current detail area provider.
+	 */
+	public AbstractStatusAreaProvider getProvider() {
+		AbstractStatusAreaProvider provider = (AbstractStatusAreaProvider) dialogState
+				.get(IStatusDialogConstants.CUSTOM_DETAILS_PROVIDER);
+		if (provider == null) {
+			provider = new DefaultDetailsArea(dialogState);
+		}
+		return provider;
+	}
+
+	/**
+	 * This method allows to check if the details area is open (physically
+	 * constructed).
+	 *
+	 * @return true if the area is open, false otherwise
+	 */
+	public boolean isOpen() {
+		if (control == null || control.isDisposed()) {
+			return false;
+		}
+		return true;
+	}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/IStatusDialogConstants.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/IStatusDialogConstants.java
new file mode 100644
index 0000000..b6ced5f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/IStatusDialogConstants.java
@@ -0,0 +1,179 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2015 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.ui.internal.statushandlers;
+
+import java.util.Collection;
+import java.util.Map;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.viewers.ILabelDecorator;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.statushandlers.AbstractStatusAreaProvider;
+import org.eclipse.ui.statushandlers.StatusAdapter;
+import org.eclipse.ui.statushandlers.WorkbenchStatusDialogManager;
+
+/**
+ * This class contains constant necessary to read/write the
+ * {@link WorkbenchStatusDialogManager} properties. Some properties may be
+ * promoted to the API. Some of those properties are used to configure the
+ * dialog, while others are used to describe the state of the dialgo.
+ *
+ */
+public interface IStatusDialogConstants {
+
+	/**
+	 * This property can be only read. It will return the current dialog
+	 * {@link Shell}. It may be null.
+	 */
+	public static final Object SHELL = Shell.class;
+
+	/**
+	 * This property indicates if the support area should be opened when the
+	 * dialog appears. The value must be of {@link Boolean} type.
+	 * {@link Boolean#TRUE} means that the support area will be opened, while
+	 * {@link Boolean#FALSE} means that it will be in the closed state.
+	 */
+	public static final Object SHOW_SUPPORT = new Object();
+
+	/**
+	 * This property indicates if the dialog should display a link to the Error
+	 * Log if the Error Log view is available. The value must be of
+	 * {@link Boolean} type. {@link Boolean#TRUE} means that the link will be
+	 * present if the Error Log is available, {@link Boolean#FALSE} means that
+	 * it will never be displayed.
+	 */
+	public static final Object ERRORLOG_LINK = new Object();
+
+	/**
+	 * This property indicates if the dialog should threat {@link Status}es with
+	 * severity {@link IStatus#OK} as all other statuses. The value must be of
+	 * {@link Boolean} type. A {@link Boolean#TRUE} means that those
+	 * {@link Status}es will be handled as all others, while
+	 * {@link Boolean#FALSE} means that they will be silently ignored.
+	 */
+	public static final Object HANDLE_OK_STATUSES = new Object();
+
+	/**
+	 * This property indicates how the dialog should be named. The default value
+	 * comes from jface resources. It may be {@link String} or <code>null</code>
+	 * .
+	 */
+	public static final Object TITLE = new Object();
+
+	/**
+	 * This property indicates which status severities should be handled. The
+	 * value must be of {@link Integer} type.
+	 */
+	public static final Object MASK = new Object();
+
+	/**
+	 * This flag indicates if the details area was opened before switching the
+	 * modality or not. It must be of {@link Boolean} type.
+	 */
+	public static final Object DETAILS_OPENED = new Object();
+
+	/**
+	 * This flag indicates if the support area was opened before switching the
+	 * modality or not. It must be of {@link Boolean} type.
+	 */
+	public static final Object TRAY_OPENED = new Object();
+
+	/**
+	 * This flag controls if the support area is opened automatically when the
+	 * dialog is opened. It must be of {@link Boolean} type or <code>null</code>
+	 * .
+	 */
+	public static final Object ENABLE_DEFAULT_SUPPORT_AREA = new Object();
+
+	/**
+	 * This flag controls if there should be a control allowing for support
+	 * opening. It must be of {@link Boolean} type or <code>null</code>.
+	 */
+	public static final Object HIDE_SUPPORT_BUTTON = new Object();
+
+	/**
+	 * This property holds custom support provider which will be used do display
+	 * support area for currently selected {@link StatusAdapter}. It must be of
+	 * {@link AbstractStatusAreaProvider} or <code>null</code>.
+	 */
+	public static final Object CUSTOM_SUPPORT_PROVIDER = new Object();
+
+	/**
+	 * This property holds custom details provider which will be used do display
+	 * details for currently selected {@link StatusAdapter}. It must be of
+	 * {@link AbstractStatusAreaProvider} or <code>null</code>.
+	 */
+	public static final Object CUSTOM_DETAILS_PROVIDER = new Object();
+
+	/**
+	 * Currently selected status adapter. It must be of {@link StatusAdapter}
+	 * type.
+	 */
+	public static final Object CURRENT_STATUS_ADAPTER = new Object();
+
+	/**
+	 * This property allows for retrieving the list of {@link StatusAdapter}
+	 * currently kept by the dialog. The corresponding object must be of
+	 * {@link Collection} type.
+	 */
+	public static final Object STATUS_ADAPTERS = new Object();
+
+	/**
+	 * Stores "modal" flags describing {@link StatusAdapter}. It is a
+	 * {@link Map} of {@link StatusAdapter}s and {@link Boolean}s.
+	 */
+	public static final Object STATUS_MODALS = new Object();
+
+	/**
+	 * This fields holds the information about dialog position and size when
+	 * switching the modality.
+	 */
+	public static final Object SHELL_BOUNDS = new Object();
+
+	/**
+	 * This property stores internal {@link LabelProviderWrapper} which is
+	 * responsible for providing all the text and images. This property should
+	 * be never changed.
+	 */
+	public static final Object LABEL_PROVIDER = new Object();
+
+	/**
+	 * This property stores custom label provider. LABEL_PROVIDER uses
+	 * CUSTOM_LABEL_PROVIDER or default label provider to deliver images and
+	 * text to the dialog. Since the custom label provider is not able to
+	 * deliver all necessary images, this field should not be used. It is kept
+	 * only for backward compatibility.
+	 */
+	public static final Object CUSTOM_LABEL_PROVIDER = new Object();
+
+	/**
+	 * If it is necessary to modify each message, this property may be used. It
+	 * should be of {@link ILabelDecorator} type. This decorator will be invoked
+	 * for each text that will be later passed to the dialog.
+	 */
+	public static final Object DECORATOR = new Object();
+
+	/**
+	 * This flag indicates if the dialog is during modality switch state. It
+	 * must be of {@link Boolean} type.
+	 */
+	public static final Object MODALITY_SWITCH = new Object();
+
+	/**
+	 * This flag controls animations. It is for testing purposes only. If it set
+	 * to false, animations will not be created. Animation means shell
+	 * closing/opening animation.
+	 */
+	public static final Object ANIMATION = new Object();
+
+	public static final Object MANAGER_IMPL = WorkbenchStatusDialogManagerImpl.class;
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/InternalDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/InternalDialog.java
new file mode 100644
index 0000000..0e5e442
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/InternalDialog.java
@@ -0,0 +1,1059 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2016 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
+ *     Patrik Suzzi <psuzzi@gmail.com> - Bug 473973
+ *     Friederike Schertel <friederike@schertel.org> - Bug 478336
+ ******************************************************************************/
+package org.eclipse.ui.internal.statushandlers;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.DialogTray;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.dialogs.MessageDialogWithToggle;
+import org.eclipse.jface.dialogs.TrayDialog;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.viewers.IContentProvider;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Link;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.internal.Workbench;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.progress.ProgressManagerUtil;
+import org.eclipse.ui.internal.progress.ProgressMessages;
+import org.eclipse.ui.progress.IProgressConstants;
+import org.eclipse.ui.statushandlers.StatusAdapter;
+import org.eclipse.ui.statushandlers.StatusManager;
+import org.eclipse.ui.views.IViewDescriptor;
+
+
+/**
+ * Parent window actually does not use its Shell to build dialog on. The
+ * window passes the shell to the InternalDialog, and it can do switching
+ * modality and recreate the window silently.
+ *
+ * @since 3.4
+ */
+public class InternalDialog extends TrayDialog {
+
+	/**
+	 * The id of the goto action button
+	 */
+	static final int GOTO_ACTION_ID = IDialogConstants.CLIENT_ID + 1;
+
+	static final String LOG_VIEW_ID = "org.eclipse.pde.runtime.LogView"; //$NON-NLS-1$
+
+	/**
+	 * Preference used to indicate whether the user should be prompted to
+	 * confirm the execution of the job's goto action
+	 */
+	static final String PREF_SKIP_GOTO_ACTION_PROMPT = "pref_skip_goto_action_prompt"; //$NON-NLS-1$
+
+	/**
+	 * This composite holds all components of the dialog.
+	 */
+	private Composite dialogArea;
+	/**
+	 * This composite is initially scrolled to the 0 x 0 size. When more
+	 * than one status arrives, listArea is resized and a list is created on
+	 * it to present statuses to the user.
+	 */
+	private Composite listArea;
+	/**
+	 * On this composite are presented additional elements for displaying
+	 * single status. Currently it is the second label that displays the
+	 * second most important message to the user.
+	 */
+	private Composite singleStatusDisplayArea;
+	/**
+	 * This label is used to display the second most important message to
+	 * the user. It is placed on singleStatusDisplayArea.
+	 */
+	private Label singleStatusLabel;
+	/**
+	 * A list from which the user selects statuses. The list is placed on
+	 * listArea.
+	 */
+	private TableViewer statusListViewer;
+	/**
+	 * Composite on the left bottom corner. Allows for opening support tray
+	 * & Error Log.
+	 */
+	private Composite linkComposite;
+	/**
+	 * This item is used to launch support tray
+	 */
+	private Link launchTrayLink;
+	/**
+	 * This fields contains indicator if link to ErrorLog view should be
+	 * present.
+	 */
+	private Link showErrorLogLink;
+	/**
+	 * Main dialog image holder.
+	 */
+	private Label titleImageLabel;
+	/**
+	 * Message in the header.
+	 */
+	private Label mainMessageLabel;
+	/**
+	 * Header area.
+	 */
+	private Composite titleArea;
+
+	/**
+	 * In this support tray status support providers are displayed.
+	 */
+	private SupportTray supportTray;
+
+	private DetailsAreaManager detailsManager;
+
+	private Map dialogState;
+
+	/**
+	 * @param dialogState
+	 * @param modal
+	 */
+	public InternalDialog(final Map dialogState, boolean modal) {
+		super(ProgressManagerUtil.getDefaultParent());
+		this.dialogState = dialogState;
+		supportTray = new SupportTray(dialogState, event -> {
+			dialogState.put(IStatusDialogConstants.TRAY_OPENED,
+					Boolean.FALSE);
+			// close the tray
+			closeTray();
+			// set focus back to shell
+			getShell().setFocus();
+		});
+		detailsManager = new DetailsAreaManager(dialogState);
+		setShellStyle(SWT.RESIZE | SWT.MAX | SWT.MIN | getShellStyle());
+		setBlockOnOpen(false);
+
+		if (!modal) {
+			setShellStyle(~SWT.APPLICATION_MODAL & getShellStyle());
+		}
+	}
+
+	@Override
+	protected void buttonPressed(int id) {
+		if (id == GOTO_ACTION_ID) {
+			IAction gotoAction = getGotoAction();
+			if (gotoAction != null) {
+				if (isPromptToClose()) {
+					okPressed(); // close the dialog
+					gotoAction.run(); // run the goto action
+				}
+			}
+		}
+		if (id == IDialogConstants.DETAILS_ID) {
+			// was the details button pressed?
+			dialogState.put(IStatusDialogConstants.DETAILS_OPENED, Boolean.valueOf(
+					toggleDetailsArea()));
+		} else {
+			super.buttonPressed(id);
+		}
+	}
+
+	@Override
+	final protected void configureShell(Shell shell) {
+		super.configureShell(shell);
+		shell.setText(getString(IStatusDialogConstants.TITLE));
+	}
+
+	/**
+	 * Status dialog button should be aligned SWT.END.
+	 */
+	@Override
+	protected void setButtonLayoutData(Button button) {
+		GridData data = new GridData(SWT.END, SWT.CENTER, false, false);
+		int widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
+		Point minSize = button.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
+		data.widthHint = Math.max(widthHint, minSize.x);
+		button.setLayoutData(data);
+	}
+
+	@Override
+	protected Control createDialogArea(Composite parent) {
+		createTitleArea(parent);
+		createListArea(parent);
+		dialogArea = parent;
+		Dialog.applyDialogFont(dialogArea);
+		return parent;
+	}
+
+	@Override
+	protected boolean isResizable() {
+		return true;
+	}
+
+	/**
+	 * Creates title area.
+	 *
+	 * @param parent
+	 *            A composite on which the title area should be created.
+	 */
+	private void createTitleArea(Composite parent) {
+		titleArea = new Composite(parent, SWT.NONE);
+		titleArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
+				false));
+
+		GridLayout layout = new GridLayout();
+		layout.numColumns = 2;
+		layout.horizontalSpacing = 10;
+		layout.marginLeft = 10;
+		layout.marginTop = 10;
+		layout.marginBottom = 0;
+		titleArea.setLayout(layout);
+
+		titleImageLabel = new Label(titleArea, SWT.NONE);
+		titleImageLabel.setImage(getLabelProviderWrapper()
+				.getImage(getCurrentStatusAdapter()));
+		GridData layoutData = new GridData();
+		layoutData.verticalSpan = 2;
+		layoutData.verticalAlignment = SWT.TOP;
+		titleImageLabel.setLayoutData(layoutData);
+
+		GridData messageData = new GridData(SWT.FILL, SWT.FILL, true, true);
+		messageData.widthHint = convertWidthInCharsToPixels(50);
+		mainMessageLabel = new Label(titleArea, SWT.WRAP);
+		mainMessageLabel.setLayoutData(messageData);
+		// main message set up early, to address bug 222391
+		mainMessageLabel.setText(getLabelProviderWrapper()
+				.getMainMessage(getCurrentStatusAdapter()));
+		if (!isMulti()) {
+			singleStatusDisplayArea = createSingleStatusDisplayArea(titleArea);
+		}
+	}
+
+	/**
+	 * Create an area which allows the user to view the status if only one
+	 * is created or to select one of reported statuses when there are many.
+	 *
+	 * @param parent
+	 *            the parent composite on which all components should be
+	 *            placed.
+	 */
+	private void createListArea(Composite parent) {
+		listArea = new Composite(parent, SWT.NONE);
+		GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true);
+		layoutData.heightHint = 0;
+		layoutData.widthHint = 0;
+		listArea.setLayoutData(layoutData);
+		GridLayout layout = new GridLayout();
+		listArea.setLayout(layout);
+		if (isMulti()) {
+			fillListArea(listArea);
+		}
+	}
+
+	/**
+	 * This function checks if the dialog is modal.
+	 *
+	 * @return true if the dialog is modal, false otherwise
+	 *
+	 */
+	public boolean isModal() {
+		return ((getShellStyle() & SWT.APPLICATION_MODAL) == SWT.APPLICATION_MODAL);
+	}
+
+	/**
+	 * @return Returns the supportTray.
+	 */
+	public SupportTray getSupportTray() {
+		return supportTray;
+	}
+
+	/**
+	 * @param supportTray
+	 *            The supportTray to set.
+	 */
+	public void setSupportTray(SupportTray supportTray) {
+		this.supportTray = supportTray;
+	}
+
+	@Override
+	public int open() {
+		boolean modalitySwitch = getBooleanValue(IStatusDialogConstants.MODALITY_SWITCH);
+		int result = super.open();
+		if (modalitySwitch) {
+			if (getBooleanValue(IStatusDialogConstants.DETAILS_OPENED)) {
+				showDetailsArea();
+			}
+			if (getBooleanValue(IStatusDialogConstants.TRAY_OPENED)) {
+				openTray();
+			}
+		} else {
+			if (getBooleanValue(IStatusDialogConstants.ANIMATION)) {
+				Rectangle shellPosition = getShell().getBounds();
+				ProgressManagerUtil.animateUp(shellPosition);
+			}
+		}
+		return result;
+	}
+
+	@Override
+	public void closeTray() throws IllegalStateException {
+		if (getTray() != null) {
+			super.closeTray();
+		}
+		//preserve state during modality switch
+		if (!getBooleanValue(IStatusDialogConstants.MODALITY_SWITCH)) {
+			dialogState.put(IStatusDialogConstants.TRAY_OPENED, Boolean.FALSE);
+		}
+		if (launchTrayLink != null && !launchTrayLink.isDisposed()) {
+			launchTrayLink.setEnabled(providesSupport()
+					&& !getBooleanValue(IStatusDialogConstants.TRAY_OPENED));
+		}
+	}
+
+	/**
+	 * Method which should be invoked when new errors become available for
+	 * display.
+	 */
+	void refresh() {
+		if (dialogArea == null || dialogArea.isDisposed()) {
+			return;
+		}
+		updateTitleArea();
+		updateListArea();
+		updateEnablements();
+		// adjust width if necessary
+		Point currentSize = getShell().getSize();
+		Point desiredSize = getShell()
+				.computeSize(SWT.DEFAULT, SWT.DEFAULT);
+		if (currentSize.x < desiredSize.x) {
+			getShell().setSize(desiredSize.x, currentSize.y);
+		} else {
+			getShell().layout();
+		}
+	}
+
+	void refreshDialogSize() {
+		if (dialogArea == null || dialogArea.isDisposed()) {
+			return;
+		}
+		Point newSize = getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT);
+		getShell().setSize(newSize);
+	}
+
+	/**
+	 * Show the details portion of the dialog if it is not already visible.
+	 * This method will only work when it is invoked after the control of
+	 * the dialog has been set. In other words, after the
+	 * <code>createContents</code> method has been invoked and has returned
+	 * the control for the content area of the dialog. Invoking the method
+	 * before the content area has been set or after the dialog has been
+	 * disposed will have no effect.
+	 */
+	private void showDetailsArea() {
+		if (dialogArea != null && !dialogArea.isDisposed()) {
+			if (detailsManager.isOpen()) {
+				detailsManager.close();
+				detailsManager.createDetailsArea(dialogArea,
+						getCurrentStatusAdapter());
+				dialogState.put(IStatusDialogConstants.DETAILS_OPENED,
+						Boolean.TRUE);
+			} else {
+				toggleDetailsArea();
+				dialogState.put(IStatusDialogConstants.DETAILS_OPENED,
+						Boolean.TRUE);
+			}
+			dialogArea.layout();
+		}
+	}
+
+	/**
+	 * Toggles the unfolding of the details area. This is triggered by the
+	 * user pressing the details button.
+	 *
+	 */
+	private boolean toggleDetailsArea() {
+		boolean opened = false;
+		Point windowSize = getShell().getSize();
+		if (detailsManager.isOpen()) {
+			detailsManager.close();
+			getButton(IDialogConstants.DETAILS_ID).setText(
+					IDialogConstants.get().SHOW_DETAILS_LABEL);
+			opened = false;
+		} else {
+			detailsManager.createDetailsArea(dialogArea,
+					getCurrentStatusAdapter());
+			getButton(IDialogConstants.DETAILS_ID).setText(
+					IDialogConstants.get().HIDE_DETAILS_LABEL);
+			opened = true;
+		}
+
+		GridData listAreaGridData = (GridData) listArea.getLayoutData();
+		// if there is only one status to display,
+		// make sure that the list area is as small as possible
+		if (!isMulti()) {
+			listAreaGridData.heightHint = 0;
+		}
+		// allow listArea to grab space depending if details
+		// are opened or not
+		if (opened) {
+			listAreaGridData.grabExcessVerticalSpace = false;
+		} else {
+			listAreaGridData.grabExcessVerticalSpace = true;
+		}
+		listArea.setLayoutData(listAreaGridData);
+
+		Point newSize = getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT);
+		int diffY = newSize.y - windowSize.y;
+		// increase the dialog height if details were opened and such
+		// increase is necessary
+		// decrease the dialog height if details were closed and empty space
+		// appeared
+		if ((opened && diffY > 0) || (!opened && diffY < 0)) {
+			getShell().setSize(
+					new Point(windowSize.x, windowSize.y + (diffY)));
+		}
+		dialogArea.layout();
+		return opened;
+	}
+
+	/**
+	 * This method should initialize the dialog bounds.
+	 */
+	@Override
+	protected void initializeBounds() {
+		super.initializeBounds();
+		refreshDialogSize();
+		boolean modalitySwitch = getBooleanValue(IStatusDialogConstants.MODALITY_SWITCH);
+		if (modalitySwitch) {
+			getShell().setBounds(getShellBounds());
+		}
+	}
+
+	@Override
+	public Point getInitialLocation(Point initialSize) {
+		return super.getInitialLocation(initialSize);
+	}
+
+	/**
+	 * The selection in the multiple job list has changed. Update widget
+	 * enablements, repopulate the list and show details.
+	 */
+	private void handleSelectionChange() {
+		StatusAdapter newSelection = getSingleSelection();
+		if (newSelection != null) {
+			dialogState.put(IStatusDialogConstants.CURRENT_STATUS_ADAPTER,
+					newSelection);
+			showDetailsArea();
+			refresh();
+		}
+	}
+
+	/**
+	 * This method creates display area for {@link StatusAdapter}s when more
+	 * is available.
+	 *
+	 * @param parent
+	 *            A parent composite on which all components should be
+	 *            placed.
+	 */
+	private void fillListArea(Composite parent) {
+		// it is necessary to make list parent composite taller
+		GridData listAreaGD = (GridData) parent.getLayoutData();
+		listAreaGD.grabExcessHorizontalSpace = true;
+		if (!detailsManager.isOpen()) {
+			listAreaGD.grabExcessVerticalSpace = true;
+		}
+		listAreaGD.heightHint = SWT.DEFAULT;
+
+		// create list viewer
+		statusListViewer = new TableViewer(parent, SWT.SINGLE
+				| SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
+		statusListViewer.setComparator(getLabelProviderWrapper());
+		Control control = statusListViewer.getControl();
+		GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
+		data.heightHint = convertHeightInCharsToPixels(5);
+		control.setLayoutData(data);
+		initContentProvider();
+		initLabelProvider();
+		statusListViewer.addPostSelectionChangedListener(event -> {
+			handleSelectionChange();
+			if ((getTray() == null) && getBooleanValue(IStatusDialogConstants.TRAY_OPENED)
+					&& providesSupport()) {
+				silentTrayOpen();
+				return;
+			}
+			if ((getTray() != null) && !providesSupport()) {
+				silentTrayClose();
+				return;
+			}
+			supportTray.selectionChanged(event);
+		});
+		Dialog.applyDialogFont(parent);
+	}
+
+	/**
+	 * closes the tray without changing any flag
+	 */
+	private void silentTrayClose() {
+		super.closeTray();
+	}
+
+	/** opens the tray without changing any flag */
+	private void silentTrayOpen() {
+		if (getTray() == null)
+			super.openTray(supportTray);
+	}
+	/**
+	 * This methods switches StatusAdapters presentation depending if there
+	 * is one status or more.
+	 */
+	private void updateListArea() {
+		// take care about list area if there is more than one status
+		if (isMulti()) {
+			if (singleStatusDisplayArea != null) {
+				singleStatusDisplayArea.dispose();
+			}
+			if (statusListViewer == null
+					|| statusListViewer.getControl().isDisposed()) {
+				fillListArea(listArea);
+				listArea.layout();
+				listArea.getParent().layout();
+				getShell().setSize(
+						getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT));
+			}
+			refreshStatusListArea();
+		}
+	}
+
+	/**
+	 * Updated title area. Adjust title, title message and title image
+	 * according to selected {@link StatusAdapter}.
+	 */
+	private void updateTitleArea() {
+		Image image = getLabelProviderWrapper().getImage(
+				getCurrentStatusAdapter());
+		titleImageLabel.setImage(image);
+		if (getCurrentStatusAdapter() != null) {
+			mainMessageLabel.setText(getLabelProviderWrapper()
+					.getMainMessage(getCurrentStatusAdapter()));
+		}
+		if (singleStatusDisplayArea != null) {
+			if (isMulti()) {
+				singleStatusDisplayArea.dispose();
+			} else {
+				refreshSingleStatusArea();
+			}
+		}
+		titleArea.layout();
+	}
+
+	/**
+	 * This method creates button bar that is available on the bottom of the
+	 * dialog.
+	 */
+	@Override
+	protected Control createButtonBar(Composite parent) {
+		Composite composite = new Composite(parent, SWT.NONE);
+		GridLayout layout = new GridLayout();
+		layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
+		layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
+		composite.setLayout(layout);
+		composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
+				false));
+
+		linkComposite = createLinkComposite(composite);
+
+		// Add the buttons to the button bar.
+		createButtonsForButtonBar(composite);
+
+		composite.layout();
+		return composite;
+	}
+
+	/**
+	 * This method creates buttons that are placed on button bar.
+	 */
+	@Override
+	protected void createButtonsForButtonBar(Composite parent) {
+		IAction gotoAction = getGotoAction();
+		String text = null;
+		if (gotoAction != null) {
+			text = gotoAction.getText();
+		}
+		Button button = createButton(parent, GOTO_ACTION_ID,
+				text == null ? "" : text, //$NON-NLS-1$
+				false);
+		if (text == null)
+			hideButton(button, true);
+
+		createButton(parent, IDialogConstants.OK_ID,
+				IDialogConstants.get().OK_LABEL, true);
+
+		createButton(parent, IDialogConstants.DETAILS_ID,
+				IDialogConstants.get().SHOW_DETAILS_LABEL, false);
+	}
+
+	/**
+	 * This method creates additional display area for {@link StatusAdapter}
+	 * when only one is available.
+	 *
+	 * It creates one label on a composite currently for secondary message.
+	 *
+	 * @param parent
+	 *            A parent composite on which all components should be
+	 *            placed.
+	 * @return composite the composite on which are all components for
+	 *         displaying status when only one is available.
+	 */
+	private Composite createSingleStatusDisplayArea(Composite parent) {
+		// secondary message is displayed on separate composite with no
+		// margins
+		Composite singleStatusParent = new Composite(parent, SWT.NONE);
+		GridLayout gridLayout = new GridLayout();
+		gridLayout.marginWidth = 0;
+		singleStatusParent.setLayout(gridLayout);
+		GridData gd = new GridData(SWT.FILL, SWT.FILL, true, false);
+		singleStatusParent.setLayoutData(gd);
+
+		// label that wraps
+		singleStatusLabel = new Label(singleStatusParent, SWT.WRAP);
+		GridData labelLayoutData = new GridData(SWT.FILL, SWT.FILL, true,
+				true);
+		labelLayoutData.widthHint = convertWidthInCharsToPixels(50);
+		singleStatusLabel.setLayoutData(labelLayoutData);
+		// main message set up early, to address bug 222391
+		singleStatusLabel.setText(getLabelProviderWrapper()
+				.getColumnText(getCurrentStatusAdapter(), 0));
+
+		singleStatusLabel.addMouseListener(new MouseListener() {
+			@Override
+			public void mouseDoubleClick(MouseEvent e) {
+			}
+
+			@Override
+			public void mouseDown(MouseEvent e) {
+				showDetailsArea();
+			}
+
+			@Override
+			public void mouseUp(MouseEvent e) {
+			}
+		});
+		return singleStatusParent;
+	}
+
+	/**
+	 * This method closes the dialog.
+	 */
+	@Override
+	public boolean close() {
+		boolean modalitySwitch = getBooleanValue(IStatusDialogConstants.MODALITY_SWITCH);
+		if (detailsManager.isOpen()) {
+			dialogState.put(IStatusDialogConstants.DETAILS_OPENED, Boolean.TRUE);
+			toggleDetailsArea();
+		}
+		if (getBooleanValue(IStatusDialogConstants.TRAY_OPENED)) {
+			closeTray();
+			if (modalitySwitch) {
+				dialogState.put(IStatusDialogConstants.DETAILS_OPENED, Boolean.TRUE);
+			}
+		}
+		dialogState.put(IStatusDialogConstants.SHELL_BOUNDS, getShell().getBounds());
+		statusListViewer = null;
+		boolean result = super.close();
+		if (!modalitySwitch && getBooleanValue(IStatusDialogConstants.ANIMATION)) {
+			ProgressManagerUtil.animateDown(getShellBounds());
+		}
+		return result;
+	}
+
+	/**
+	 * Hide the button if hide is <code>true</code>.
+	 *
+	 * @param button
+	 * @param hide
+	 */
+	private void hideButton(Button button, boolean hide) {
+		((GridData) button.getLayoutData()).exclude = hide;
+		button.setVisible(!hide);
+		button.setEnabled(!hide);
+	}
+
+	/**
+	 * Update the button enablements
+	 */
+	private void updateEnablements() {
+		Button details = getButton(IDialogConstants.DETAILS_ID);
+		if (details != null) {
+			details.setEnabled(true);
+		}
+		Button gotoButton = getButton(GOTO_ACTION_ID);
+		if (gotoButton != null) {
+			IAction gotoAction = getGotoAction();
+			boolean hasValidGotoAction = (gotoAction != null)
+					&& (gotoAction.getText() != null);
+			if (hasValidGotoAction) {
+				hideButton(gotoButton, false);
+				gotoButton.setText(gotoAction.getText());
+
+				((GridData) gotoButton.getLayoutData()).widthHint = gotoButton
+						.computeSize(SWT.DEFAULT, SWT.DEFAULT).x;
+				gotoButton.getParent().layout();
+			} else
+				hideButton(gotoButton, true);
+		}
+		// and tray enablement button
+		if (providesSupport() && !getBooleanValue(IStatusDialogConstants.HIDE_SUPPORT_BUTTON)) {
+			if (launchTrayLink == null || launchTrayLink.isDisposed()) {
+				launchTrayLink = createGetSupportLink();
+			}
+			launchTrayLink
+					.setEnabled(!getBooleanValue(IStatusDialogConstants.TRAY_OPENED));
+		} else {
+			if (launchTrayLink != null && !launchTrayLink.isDisposed()) {
+				launchTrayLink.dispose();
+				launchTrayLink = null;
+			}
+		}
+		IViewDescriptor descriptor = shouldDisplayLinkToErrorLog();
+		if (descriptor != null) {
+			if (showErrorLogLink == null || showErrorLogLink.isDisposed()) {
+				showErrorLogLink = createShowErrorLogLink();
+			}
+		} else {
+			if (showErrorLogLink != null && !showErrorLogLink.isDisposed()) {
+				showErrorLogLink.dispose();
+			}
+		}
+		linkComposite.getParent().layout();
+	}
+
+	private IViewDescriptor shouldDisplayLinkToErrorLog() {
+		/* no support for error log */
+		if (!getBooleanValue(IStatusDialogConstants.ERRORLOG_LINK)) {
+			return null;
+		}
+		/* check handling hint and display link if it is expected */
+		boolean shouldDisplay = false;
+		Iterator it = ((Collection) dialogState
+				.get(IStatusDialogConstants.STATUS_ADAPTERS)).iterator();
+		while (it.hasNext()) {
+			StatusAdapter adapter = (StatusAdapter) it.next();
+			Integer hint = (Integer) adapter.getProperty(WorkbenchStatusDialogManagerImpl.HINT);
+			if (hint != null
+					&& ((hint.intValue() & StatusManager.LOG) != 0)) {
+				shouldDisplay |= true;
+				break;
+			}
+		}
+		if (!shouldDisplay) {
+			return null;
+		}
+		/* view description */
+		return Workbench.getInstance().getViewRegistry().find(LOG_VIEW_ID);
+	}
+
+	/**
+	 * Opens the dialog tray (support area at the right side of the dialog)
+	 */
+	@Override
+	public void openTray(DialogTray tray) throws IllegalStateException,
+			UnsupportedOperationException {
+		if (launchTrayLink != null && !launchTrayLink.isDisposed()) {
+			launchTrayLink.setEnabled(false);
+		}
+		if (providesSupport()) {
+			super.openTray(tray);
+		}
+		dialogState.put(IStatusDialogConstants.TRAY_OPENED, Boolean.TRUE);
+	}
+
+	/**
+	 * Refreshes the single status area. Is called only when there is one
+	 * and only one error.
+	 */
+	private void refreshSingleStatusArea() {
+		String description = getLabelProviderWrapper()
+				.getColumnText(getCurrentStatusAdapter(), 0);
+		if (description.equals(singleStatusLabel.getText()))
+			singleStatusLabel.setText(" "); //$NON-NLS-1$
+		singleStatusLabel.setText(description);
+		singleStatusDisplayArea.layout();
+		getShell().setText(getString(IStatusDialogConstants.TITLE));
+	}
+
+	/**
+	 * Refresh the contents of the viewer.
+	 */
+	private void refreshStatusListArea() {
+		if (statusListViewer != null
+				&& !statusListViewer.getControl().isDisposed()) {
+			statusListViewer.refresh();
+			if (statusListViewer.getTable().getItemCount() > 1) {
+				getShell()
+						.setText(
+								WorkbenchMessages.get().WorkbenchStatusDialog_MultipleProblemsHaveOccured);
+			} else {
+				getShell().setText(
+						getString(IStatusDialogConstants.TITLE));
+			}
+		}
+	}
+
+	/**
+	 * Sets the content provider for the viewer.
+	 */
+	private void initContentProvider() {
+		IContentProvider provider = new IStructuredContentProvider() {
+			@Override
+			public void dispose() {
+				// Nothing of interest here
+			}
+
+			@Override
+			public Object[] getElements(Object inputElement) {
+				return ((Collection) dialogState
+						.get(IStatusDialogConstants.STATUS_ADAPTERS)).toArray();
+			}
+
+			@Override
+			public void inputChanged(Viewer viewer, Object oldInput,
+					Object newInput) {
+				if (newInput != null) {
+					refreshStatusListArea();
+				}
+			}
+		};
+		statusListViewer.setContentProvider(provider);
+		statusListViewer.setInput(this);
+		statusListViewer.setSelection(new StructuredSelection(
+				getCurrentStatusAdapter()));
+	}
+
+	/**
+	 * Creates a new control that provides access to support providers.
+	 * <p>
+	 * The <code>WorkbenchStatusDialog</code> implementation of this method
+	 * creates the control, registers it for selection events including
+	 * selection, Note that the parent's layout is assumed to be a
+	 * <code>GridLayout</code> and the number of columns in this layout is
+	 * incremented. Subclasses may override.
+	 * </p>
+	 *
+	 * @param parent
+	 *            A parent composite on which all components should be
+	 *            placed.
+	 * @return the report control
+	 */
+	private Composite createLinkComposite(Composite parent) {
+		Composite linkArea = new Composite(parent, SWT.NONE) {
+
+			// the composite should be as small as possible when there is no
+			// additional controls on it
+			@Override
+			public Point computeSize(int wHint, int hHint, boolean changed) {
+				Point newSize = super.computeSize(wHint, hHint, changed);
+				if (getChildren().length == 0) {
+					newSize.x = 0;
+					newSize.y = 0;
+				}
+				return newSize;
+			}
+
+		};
+		GridLayout layout = new GridLayout();
+		layout.marginHeight = 0;
+		layout.marginWidth = 0;
+		layout.verticalSpacing = 0;
+		linkArea.setLayout(layout);
+
+		((GridLayout) parent.getLayout()).numColumns++;
+
+		GridData layoutData = new GridData(SWT.BEGINNING, SWT.CENTER, true,
+				false);
+		linkArea.setLayoutData(layoutData);
+		return linkArea;
+	}
+
+	/**
+	 * Creates a button with a report image. This is only used if there is
+	 * an image available.
+	 */
+	private Link createGetSupportLink() {
+		// no support
+		if (!providesSupport() || getBooleanValue(IStatusDialogConstants.HIDE_SUPPORT_BUTTON)) {
+			return null;
+		}
+
+		Link link = new Link(linkComposite, SWT.NONE);
+		link
+				.setText(WorkbenchMessages.get().WorkbenchStatusDialog_SupportHyperlink);
+		link
+				.setToolTipText(WorkbenchMessages.get().WorkbenchStatusDialog_SupportTooltip);
+		link.addSelectionListener(new SelectionAdapter()
+        {
+            /** {@inheritDoc} */
+            @Override
+            public void widgetSelected(SelectionEvent e)
+            {
+                openTray();
+            }
+        });
+		Dialog.applyDialogFont(link);
+		return link;
+	}
+
+	private Link createShowErrorLogLink() {
+		Link link = new Link(linkComposite, SWT.NONE);
+		link.addSelectionListener(new SelectionAdapter()
+        {
+            /** {@inheritDoc} */
+            @Override
+            public void widgetSelected(SelectionEvent e)
+            {
+    			try {
+    				Workbench.getInstance().getActiveWorkbenchWindow().getActivePage().showView(LOG_VIEW_ID);
+    			} catch (CoreException ce) {
+    				StatusManager.getManager().handle(ce, WorkbenchPlugin.PI_WORKBENCH);
+    			}
+            }
+		});
+		link.setText(WorkbenchMessages.get().ErrorLogUtil_ShowErrorLogHyperlink);
+		link
+				.setToolTipText(WorkbenchMessages.get().ErrorLogUtil_ShowErrorLogTooltip);
+		Dialog.applyDialogFont(link);
+		return link;
+	}
+
+	/**
+	 * Sets initial label provider.
+	 */
+	private void initLabelProvider() {
+		statusListViewer.setLabelProvider(getLabelProviderWrapper());
+	}
+
+	/**
+	 * Returns {@link IAction} associated with selected StatusAdapter.
+	 *
+	 * @return {@link IAction} that is set as {@link StatusAdapter} property
+	 *         with Job.class key.
+	 */
+	private IAction getGotoAction() {
+		Object property = null;
+
+		Job job = Adapters.adapt(getCurrentStatusAdapter(), Job.class);
+		if (job != null) {
+			property = job.getProperty(IProgressConstants.ACTION_PROPERTY);
+		}
+
+		if (property instanceof IAction) {
+			return (IAction) property;
+		}
+		return null;
+	}
+
+	/**
+	 * Get the single selection. Return null if the selection is not just
+	 * one element.
+	 *
+	 * @return StatusAdapter or <code>null</code>.
+	 */
+	private StatusAdapter getSingleSelection() {
+		IStructuredSelection selection = statusListViewer.getStructuredSelection();
+		if (selection.size() == 1) {
+			return (StatusAdapter) selection.getFirstElement();
+		}
+		return null;
+	}
+
+	/*
+	 * Prompt to inform the user that the dialog will close and the errors
+	 * cleared.
+	 */
+	private boolean isPromptToClose() {
+		IPreferenceStore store = WorkbenchPlugin.getDefault()
+				.getPreferenceStore();
+		if (!store.contains(PREF_SKIP_GOTO_ACTION_PROMPT)
+				|| !store.getString(PREF_SKIP_GOTO_ACTION_PROMPT).equals(
+						MessageDialogWithToggle.ALWAYS)) {
+			MessageDialogWithToggle dialog = MessageDialogWithToggle.open(
+					MessageDialog.CONFIRM, getShell(),
+					ProgressMessages.get().JobErrorDialog_CloseDialogTitle,
+					ProgressMessages.get().JobErrorDialog_CloseDialogMessage,
+					ProgressMessages.get().JobErrorDialog_DoNotShowAgainMessage,
+					false, store, PREF_SKIP_GOTO_ACTION_PROMPT, SWT.SHEET);
+			return dialog.getReturnCode() == Window.OK;
+		}
+		return true;
+	}
+
+	public void openTray() {
+		openTray(supportTray);
+	}
+
+	public boolean providesSupport() {
+		return supportTray.providesSupport(getCurrentStatusAdapter()) != null;
+	}
+
+	private String getString(Object key) {
+		return (String) dialogState.get(key);
+	}
+
+	private StatusAdapter getCurrentStatusAdapter() {
+		return (StatusAdapter) dialogState
+				.get(IStatusDialogConstants.CURRENT_STATUS_ADAPTER);
+	}
+
+	private boolean getBooleanValue(Object key) {
+		Boolean b = (Boolean) dialogState.get(key);
+		if (b == null) {
+			return false;
+		}
+		return b.booleanValue();
+	}
+
+	private Rectangle getShellBounds() {
+		return (Rectangle) dialogState.get(IStatusDialogConstants.SHELL_BOUNDS);
+	}
+
+	private LabelProviderWrapper getLabelProviderWrapper() {
+		return (LabelProviderWrapper) dialogState
+				.get(IStatusDialogConstants.LABEL_PROVIDER);
+	}
+
+	private boolean isMulti() {
+		return ((Collection) dialogState
+				.get(IStatusDialogConstants.STATUS_ADAPTERS)).size() > 1;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/LabelProviderWrapper.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/LabelProviderWrapper.java
new file mode 100644
index 0000000..d015da3
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/LabelProviderWrapper.java
@@ -0,0 +1,476 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2015 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.ui.internal.statushandlers;
+
+import java.net.URL;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Map;
+
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.jface.resource.ResourceManager;
+import org.eclipse.jface.viewers.ILabelDecorator;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.progress.ProgressManager;
+import org.eclipse.ui.internal.progress.ProgressMessages;
+import org.eclipse.ui.progress.IProgressConstants;
+import org.eclipse.ui.statushandlers.IStatusAdapterConstants;
+import org.eclipse.ui.statushandlers.StatusAdapter;
+
+import com.ibm.icu.text.DateFormat;
+
+
+/**
+ * This is an utility class which is responsible for text and icon decorators in
+ * the StatusDialog.
+ *
+ * @since 3.6
+ */
+public class LabelProviderWrapper extends ViewerComparator implements
+		ITableLabelProvider {
+	/**
+	 * The default status label provider.
+	 */
+	private class DefaultLabelProvider implements ITableLabelProvider {
+		ResourceManager manager = new LocalResourceManager(JFaceResources
+				.getResources());
+
+		@Override
+		public void addListener(ILabelProviderListener listener) {
+			// Do nothing
+		}
+
+		@Override
+		public void dispose() {
+			manager.dispose();
+		}
+
+		@Override
+		public Image getColumnImage(Object element, int columnIndex) {
+			Image result = null;
+			if (element != null) {
+				StatusAdapter statusAdapter = ((StatusAdapter) element);
+				Job job = Adapters.adapt(statusAdapter, Job.class);
+				if (job != null) {
+					result = getIcon(job);
+				}
+			}
+			// if somehow disposed image was received (should not happen)
+			if (result != null && result.isDisposed()) {
+				result = null;
+			}
+			return result;
+		}
+
+		@Override
+		public String getColumnText(Object element, int columnIndex) {
+			StatusAdapter statusAdapter = (StatusAdapter) element;
+			String text = WorkbenchMessages.get().WorkbenchStatusDialog_ProblemOccurred;
+			if (!isMulti()) {
+				Job job = Adapters.adapt(statusAdapter, Job.class);
+				if (job != null) {
+					text = getPrimaryMessage(statusAdapter);
+				} else {
+					text = getSecondaryMessage(statusAdapter);
+				}
+			} else {
+				Job job = Adapters.adapt(statusAdapter, Job.class);
+				if (job != null) {
+					text = job.getName();
+				} else {
+					text = getPrimaryMessage(statusAdapter);
+				}
+			}
+			Long timestamp = (Long) statusAdapter
+					.getProperty(IStatusAdapterConstants.TIMESTAMP_PROPERTY);
+
+			if (timestamp != null && isMulti()) {
+				String date = DateFormat.getDateTimeInstance(DateFormat.LONG,
+						DateFormat.LONG)
+						.format(new Date(timestamp.longValue()));
+				return NLS.bind(ProgressMessages.get().JobInfo_Error, (new Object[] {
+						text, date }));
+			}
+			return text;
+		}
+
+		/*
+		 * Get the icon for the job.
+		 */
+		private Image getIcon(Job job) {
+			if (job != null) {
+				Object property = job
+						.getProperty(IProgressConstants.ICON_PROPERTY);
+
+				// Create an image from the job's icon property or family
+				if (property instanceof ImageDescriptor) {
+					return manager.createImage((ImageDescriptor) property);
+				} else if (property instanceof URL) {
+					return manager.createImage(ImageDescriptor
+							.createFromURL((URL) property));
+				} else {
+					// Let the progress manager handle the resource management
+					return ProgressManager.getInstance().getIconFor(job);
+				}
+			}
+			return null;
+		}
+
+		@Override
+		public boolean isLabelProperty(Object element, String property) {
+			return false;
+		}
+
+		@Override
+		public void removeListener(ILabelProviderListener listener) {
+			// Do nothing
+		}
+	}
+
+	private ITableLabelProvider labelProvider;
+
+	/**
+	 * This field stores the decorator which can override various texts produced
+	 * by this class.
+	 */
+	private ILabelDecorator messageDecorator;
+
+	private Map dialogState;
+
+	/**
+	 * @param dialogState
+	 */
+	public LabelProviderWrapper(Map dialogState) {
+		this.dialogState = dialogState;
+	}
+
+	@Override
+	public Image getColumnImage(Object element, int columnIndex) {
+		return labelProvider.getColumnImage(element, columnIndex);
+	}
+
+	@Override
+	public String getColumnText(Object element, int columnIndex) {
+		return getLabelProvider().getColumnText(element, columnIndex);
+	}
+
+	@Override
+	public void addListener(ILabelProviderListener listener) {
+		getLabelProvider().addListener(listener);
+	}
+
+	/**
+	 * This method disposes the label provider if and only if the dialog is not
+	 * changing its state.
+	 *
+	 * @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose()
+	 */
+	@Override
+	public void dispose() {
+		boolean modalitySwitch = ((Boolean) dialogState.get(IStatusDialogConstants.MODALITY_SWITCH))
+				.booleanValue();
+		if (!modalitySwitch) {
+			getLabelProvider().dispose();
+		}
+	}
+
+	@Override
+	public boolean isLabelProperty(Object element, String property) {
+		return getLabelProvider().isLabelProperty(element, property);
+	}
+
+	@Override
+	public void removeListener(ILabelProviderListener listener) {
+		getLabelProvider().removeListener(listener);
+	}
+
+	/**
+	 * Gets {@link Image} associated with current {@link StatusAdapter}
+	 * severity.
+	 *
+	 * @param statusAdapter
+	 *
+	 * @return {@link Image} associated with current {@link StatusAdapter}
+	 *         severity.
+	 */
+	public Image getImage(StatusAdapter statusAdapter) {
+		if (statusAdapter != null) {
+			int severity = statusAdapter.getStatus().getSeverity();
+			switch (severity) {
+			case IStatus.OK:
+			case IStatus.INFO:
+			case IStatus.CANCEL:
+				return getSWTImage(SWT.ICON_INFORMATION);
+			case IStatus.WARNING:
+				return getSWTImage(SWT.ICON_WARNING);
+			default: /* IStatus.ERROR */
+				return getSWTImage(SWT.ICON_ERROR);
+			}
+		}
+		// should not never happen but if we do not know what is going on, then
+		// return error image.
+		return getSWTImage(SWT.ICON_ERROR);
+	}
+
+	/**
+	 * Get an <code>Image</code> from the provide SWT image constant.
+	 *
+	 * @param imageID
+	 *            the SWT image constant
+	 * @return image the image
+	 */
+	public Image getSWTImage(final int imageID) {
+		return Display.getCurrent().getSystemImage(imageID);
+	}
+
+	/**
+	 * This method computes the dialog main message.
+	 *
+	 * If there is only one reported status adapter, main message should be:
+	 * <ul>
+	 * <li>information about job that reported an error.</li>
+	 * <li>primary message, if the statusAdapter was not reported by job</li>
+	 * </ul>
+	 *
+	 * If there is more reported statusAdapters, main message should be:
+	 * <ul>
+	 * <li>primary message for job reported statusAdapters</li>
+	 * <li>secondary message for statuses not reported by jobs</li>
+	 * </ul>
+	 *
+	 * If nothing can be found, some general information should be displayed.
+	 *
+	 * @param statusAdapter
+	 *            A status adapter which is used as the base for computation.
+	 * @return main message of the dialog.
+	 *
+	 * @see #getPrimaryMessage(StatusAdapter)
+	 * @see #getSecondaryMessage(StatusAdapter)
+	 */
+	public String getMainMessage(StatusAdapter statusAdapter) {
+		if (!isMulti()) {
+			Job job = Adapters.adapt(statusAdapter, Job.class);
+			// job
+			if (job != null) {
+				return NLS
+						.bind(
+								WorkbenchMessages.get().WorkbenchStatusDialog_ProblemOccurredInJob,
+								job.getName());
+			}
+			// we are not handling job
+			return getPrimaryMessage(statusAdapter);
+		}
+		// we have a list. primary message or job name or on the list name (both
+		// with timestamp if available).
+		// we display secondary message or status
+		if (isMulti()) {
+			Job job = Adapters.adapt(statusAdapter, Job.class);
+			// job
+			if (job != null) {
+				return getPrimaryMessage(statusAdapter);
+			}
+
+			// plain status
+			return getSecondaryMessage(statusAdapter);
+		}
+		return WorkbenchMessages.get().WorkbenchStatusDialog_ProblemOccurred;
+	}
+
+	/**
+	 * Retrieves primary message from passed statusAdapter. Primary message
+	 * should be (from the most important):
+	 * <ul>
+	 * <li>statusAdapter title</li>
+	 * <li>IStatus message</li>
+	 * <li>pointing to child statuses if IStatus has them.</li>
+	 * <li>exception message</li>
+	 * <li>exception class</li>
+	 * <li>general message informing about error (no details at all)</li>
+	 * </ul>
+	 *
+	 * @param statusAdapter
+	 *            an status adapter to retrieve primary message from
+	 * @return String containing primary message
+	 *
+	 * @see #getMainMessage(StatusAdapter)
+	 * @see #getSecondaryMessage(StatusAdapter)
+	 */
+	public String getPrimaryMessage(StatusAdapter statusAdapter) {
+		// if there was nonempty title set, display the title
+		Object property = statusAdapter
+				.getProperty(IStatusAdapterConstants.TITLE_PROPERTY);
+		if (property instanceof String) {
+			String header = (String) property;
+			if (header.trim().length() > 0) {
+				return decorate(header, statusAdapter);
+			}
+		}
+		// if there was message set in the status
+		IStatus status = statusAdapter.getStatus();
+		if (status.getMessage() != null
+				&& status.getMessage().trim().length() > 0) {
+			return decorate(status.getMessage(), statusAdapter);
+		}
+
+		// if status has children
+		if (status.getChildren().length > 0) {
+			return WorkbenchMessages.get().WorkbenchStatusDialog_StatusWithChildren;
+		}
+
+		// check the exception
+		Throwable t = status.getException();
+		if (t != null) {
+			if (t.getMessage() != null && t.getMessage().trim().length() > 0) {
+				return decorate(t.getMessage(), statusAdapter);
+			}
+			return t.getClass().getName();
+		}
+		return WorkbenchMessages.get().WorkbenchStatusDialog_ProblemOccurred;
+	}
+
+	/**
+	 * Retrieves secondary message from the passed statusAdapter. Secondary
+	 * message is one level lower than primary. Secondary message should be
+	 * (from the most important):
+	 * <ul>
+	 * <li>IStatus message</li>
+	 * <li>pointing to child statuses if IStatus has them.</li>
+	 * <li>exception message</li>
+	 * <li>exception class</li>
+	 * </ul>
+	 * Secondary message should not be the same as primary one. If no secondary
+	 * message can be extracted, details should be pointed.
+	 *
+	 * @param statusAdapter
+	 *            an status adapter to retrieve secondary message from
+	 * @return String containing secondary message
+	 *
+	 * @see #getMainMessage(StatusAdapter)
+	 * @see #getPrimaryMessage(StatusAdapter)
+	 */
+	public String getSecondaryMessage(StatusAdapter statusAdapter) {
+		String primary = getPrimaryMessage(statusAdapter);
+		// we can skip the title, it is always displayed as primary message
+
+		// if there was message set in the status
+		IStatus status = statusAdapter.getStatus();
+		String message = status.getMessage();
+		String decoratedMessage = message == null ? null : decorate(message,
+				statusAdapter);
+		if (message != null && message.trim().length() > 0
+				&& !primary.equals(decoratedMessage)) {
+			/* we have not displayed it yet */
+			return decoratedMessage;
+		}
+		// if status has children
+		if (status.getChildren().length > 0
+				&& !primary.equals(decoratedMessage)) {
+			return WorkbenchMessages.get().WorkbenchStatusDialog_StatusWithChildren;
+		}
+
+		// check the exception
+		Throwable t = status.getException();
+		if (t != null) {
+			if (t.getMessage() != null) {
+				String decoratedThrowable = decorate(t.getMessage(),
+						statusAdapter);
+				if (t.getMessage().trim().length() > 0
+						&& !primary.equals(decoratedThrowable)) {
+					return decoratedThrowable;
+				}
+			}
+			String throwableName = t.getClass().getName();
+			if (!primary.equals(throwableName)) {
+				return throwableName;
+			}
+		}
+		return WorkbenchMessages.get().WorkbenchStatusDialog_SeeDetails;
+	}
+
+	private String decorate(String string, StatusAdapter adapter) {
+		messageDecorator = (ILabelDecorator) dialogState
+				.get(IStatusDialogConstants.DECORATOR);
+		if (messageDecorator != null) {
+			string = messageDecorator.decorateText(string, adapter);
+		}
+		return string;
+	}
+
+	private int compare(StatusAdapter s1, StatusAdapter s2) {
+		Long timestamp1 = ((Long) s1
+				.getProperty(IStatusAdapterConstants.TIMESTAMP_PROPERTY));
+		Long timestamp2 = ((Long) s2
+				.getProperty(IStatusAdapterConstants.TIMESTAMP_PROPERTY));
+		if (timestamp1 == null || timestamp2 == null
+				|| (timestamp1.equals(timestamp2))) {
+			String text1 = getColumnText(s1, 0);
+			String text2 = getColumnText(s2, 0);
+			return text1.compareTo(text2);
+		}
+
+		if (timestamp1.longValue() < timestamp2.longValue()) {
+			return -1;
+		}
+		if (timestamp1.longValue() > timestamp2.longValue()) {
+			return 1;
+		}
+		// should be never called
+		return 0;
+	}
+
+	@Override
+	public int compare(Viewer testViewer, Object o1, Object o2) {
+		if (o1 instanceof StatusAdapter && o2 instanceof StatusAdapter) {
+			return compare((StatusAdapter) o1, (StatusAdapter) o2);
+		}
+		// should not happen
+		if (o1.hashCode() < o2.hashCode()) {
+			return -1;
+		}
+		if (o2.hashCode() > o2.hashCode()) {
+			return 1;
+		}
+		return 0;
+	}
+
+	private boolean isMulti() {
+		return ((Collection) dialogState
+				.get(IStatusDialogConstants.STATUS_ADAPTERS)).size() > 1;
+	}
+
+	/**
+	 * @return Returns the labelProvider.
+	 */
+	public ITableLabelProvider getLabelProvider() {
+		ITableLabelProvider temp = (ITableLabelProvider) dialogState
+				.get(IStatusDialogConstants.CUSTOM_LABEL_PROVIDER);
+		if (temp != null) {
+			labelProvider = temp;
+		}
+		if (labelProvider == null) {
+			labelProvider = new DefaultLabelProvider();
+		}
+		return labelProvider;
+	}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/StackTraceSupportArea.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/StackTraceSupportArea.java
new file mode 100644
index 0000000..1b59a71
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/StackTraceSupportArea.java
@@ -0,0 +1,173 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2015 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.ui.internal.statushandlers;
+
+import org.eclipse.jface.util.Policy;
+import org.eclipse.swt.SWT;
+//import org.eclipse.swt.dnd.Clipboard;
+import org.eclipse.swt.dnd.DND;
+import org.eclipse.swt.dnd.DragSource;
+import org.eclipse.swt.dnd.DragSourceEvent;
+import org.eclipse.swt.dnd.DragSourceListener;
+import org.eclipse.swt.dnd.TextTransfer;
+import org.eclipse.swt.dnd.Transfer;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.List;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.statushandlers.AbstractStatusAreaProvider;
+import org.eclipse.ui.statushandlers.StatusAdapter;
+import org.eclipse.ui.statushandlers.WorkbenchErrorHandler;
+import org.eclipse.ui.statushandlers.WorkbenchStatusDialogManager;
+
+/**
+ * This class is responsible for displaying stack trace retrieved from IStatus.
+ * It has similar functionality as details area in {@link WorkbenchStatusDialogManager}.
+ * This class will be visible only if it is enabled in
+ * {@link WorkbenchStatusDialogManager} and no support provider is passed by
+ * {@link Policy}
+ *
+ * @see Policy#setErrorSupportProvider
+ * @see Policy#getErrorSupportProvider()
+ * @see WorkbenchStatusDialogManager#enableDefaultSupportArea
+ * @see WorkbenchErrorHandler
+ * @since 3.4
+ */
+public class StackTraceSupportArea extends AbstractStatusAreaProvider {
+
+	/*
+	 * Displays statuses.
+	 */
+	private List list;
+
+	@Override
+	public Control createSupportArea(final Composite parent,
+			StatusAdapter statusAdapter) {
+
+		Label label = new Label(parent, SWT.NONE);
+		label.setText(WorkbenchMessages.get().StackTraceSupportArea_Title);
+
+		list = new List(parent, SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI);
+		GridData gd = new GridData(GridData.FILL_BOTH);
+		gd.grabExcessHorizontalSpace = true;
+		gd.grabExcessVerticalSpace = true;
+		gd.widthHint = 250;
+		list.setLayoutData(gd);
+		list.addSelectionListener(new SelectionAdapter() {
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				list.selectAll();
+				super.widgetSelected(e);
+			}
+		});
+		list.removeAll();
+		populateList(statusAdapter.getStatus().getException());
+		createDNDSource();
+		createCopyAction(parent);
+		return parent;
+	}
+
+	/**
+	 * Creates DND source for the list
+	 */
+	private void createDNDSource() {
+		DragSource ds = new DragSource(list, DND.DROP_COPY);
+		ds.setTransfer(new Transfer[] { TextTransfer.getInstance() });
+		ds.addDragListener(new DragSourceListener() {
+			@Override
+			public void dragFinished(DragSourceEvent event) {
+
+			}
+
+			@Override
+			public void dragSetData(DragSourceEvent event) {
+				if (TextTransfer.getInstance().isSupportedType(event.dataType)) {
+					event.data = prepareCopyString();
+				}
+			}
+
+			@Override
+			public void dragStart(DragSourceEvent event) {
+				list.selectAll();
+			}
+		});
+	}
+
+	private void createCopyAction(final Composite parent) {
+	    // RAP
+//		Menu menu = new Menu(parent.getShell(), SWT.POP_UP);
+//		MenuItem copyAction = new MenuItem(menu, SWT.PUSH);
+//		copyAction.setText("&Copy"); //$NON-NLS-1$
+//		copyAction.addSelectionListener(new SelectionAdapter() {
+//			@Override
+//			public void widgetSelected(SelectionEvent e) {
+//				Clipboard clipboard = null;
+//				try {
+//					clipboard = new Clipboard(parent.getDisplay());
+//					clipboard.setContents(new Object[] { prepareCopyString() },
+//							new Transfer[] { TextTransfer.getInstance() });
+//				} finally {
+//					if (clipboard != null) {
+//						clipboard.dispose();
+//					}
+//				}
+//				super.widgetSelected(e);
+//			}
+//		});
+//		list.setMenu(menu);
+	}
+
+	private String prepareCopyString() {
+		if (list == null || list.isDisposed()) {
+			return ""; //$NON-NLS-1$
+		}
+		StringBuffer sb = new StringBuffer();
+		String newLine = System.getProperty("line.separator"); //$NON-NLS-1$
+		for (int i = 0; i < list.getItemCount(); i++) {
+			sb.append(list.getItem(i));
+			sb.append(newLine);
+		}
+		return sb.toString();
+	}
+
+	private void populateList(Throwable t) {
+		if (t == null) {
+			list.add(WorkbenchMessages.get().StackTraceSupportArea_NoStackTrace);
+			return;
+		}
+		list.add(t.toString());
+		for (StackTraceElement stackTraceElement : t.getStackTrace()) {
+			list.add(stackTraceElement.toString());
+		}
+		if (t.getCause() != null) {
+			list.add(WorkbenchMessages.get().StackTraceSupportArea_CausedBy);
+			populateList(t.getCause());
+		}
+	}
+
+	/**
+	 * @return Returns the list.
+	 */
+	public List getList() {
+		return list;
+	}
+
+	@Override
+	public boolean validFor(StatusAdapter statusAdapter) {
+		return statusAdapter.getStatus().getException() != null;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/StatusHandlerDescriptor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/StatusHandlerDescriptor.java
new file mode 100644
index 0000000..60f2250
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/StatusHandlerDescriptor.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal.statushandlers;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.ui.IPluginContribution;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.statushandlers.AbstractStatusHandler;
+
+/**
+ * The status handler descriptor.
+ *
+ * @since 3.3
+ */
+public class StatusHandlerDescriptor implements IPluginContribution {
+
+	private AbstractStatusHandler cachedInstance;
+
+	private final static String PREFIX = "prefix"; //$NON-NLS-1$
+
+	private IConfigurationElement configElement;
+
+	private String id;
+
+	private String pluginId;
+
+	private String prefix;
+
+	/**
+	 * @param configElement
+	 */
+	public StatusHandlerDescriptor(IConfigurationElement configElement) {
+		super();
+		this.configElement = configElement;
+		id = configElement.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+		pluginId = configElement.getContributor().getName();
+	}
+
+	/**
+	 * Gets an instance of the status handler defined in the descriptor.
+	 *
+	 * @return the status handler
+	 * @throws CoreException
+	 *             thrown if there is a problem creating the handler
+	 */
+	public synchronized AbstractStatusHandler getStatusHandler()
+			throws CoreException {
+		if (cachedInstance == null) {
+			AbstractStatusHandler statusHandler = (AbstractStatusHandler) configElement
+					.createExecutableExtension(IWorkbenchRegistryConstants.ATT_CLASS);
+			statusHandler.setId(configElement
+					.getAttribute(IWorkbenchRegistryConstants.ATT_ID));
+
+			IConfigurationElement parameters[] = configElement
+					.getChildren(IWorkbenchRegistryConstants.TAG_PARAMETER);
+
+			Map params = new HashMap();
+
+			for (IConfigurationElement configElement : parameters) {
+				params.put(configElement.getAttribute(IWorkbenchRegistryConstants.ATT_NAME),
+						configElement.getAttribute(IWorkbenchRegistryConstants.ATT_VALUE));
+			}
+
+			statusHandler.setParams(params);
+			cachedInstance = statusHandler;
+		}
+		return cachedInstance;
+	}
+
+	/**
+	 * Gets prefix parameter for the status handler defined in the descriptor.
+	 *
+	 * @return prefix parameter
+	 */
+	public String getPrefix() {
+		IConfigurationElement parameters[] = configElement.getChildren(IWorkbenchRegistryConstants.TAG_PARAMETER);
+
+		for (IConfigurationElement configElement : parameters) {
+			if (configElement.getAttribute(IWorkbenchRegistryConstants.ATT_NAME).equals(PREFIX)) {
+				prefix = configElement.getAttribute(IWorkbenchRegistryConstants.ATT_VALUE);
+			}
+		}
+		return prefix;
+	}
+
+	/**
+	 * Returns the id of the status handler.
+	 *
+	 * @return the id
+	 */
+	public String getId() {
+		return id;
+	}
+
+	@Override
+	public String getLocalId() {
+		return id;
+	}
+
+	@Override
+	public String getPluginId() {
+		return pluginId;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/StatusHandlerDescriptorsMap.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/StatusHandlerDescriptorsMap.java
new file mode 100644
index 0000000..081b44f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/StatusHandlerDescriptorsMap.java
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal.statushandlers;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Helper class supporting the prefix based status handling policy.
+ *
+ * @since 3.3
+ */
+class StatusHandlerDescriptorsMap {
+
+	private final String ASTERISK = "*"; //$NON-NLS-1$
+
+	private HashMap map;
+
+	/**
+	 * Creates a new instance of the class
+	 */
+	public StatusHandlerDescriptorsMap() {
+		map = new HashMap();
+	}
+
+	/**
+	 * Adds a new handler descriptor to the prefix tree
+	 *
+	 * @param handlerDescriptor
+	 *            the handler descriptor to add
+	 */
+	public void addHandlerDescriptor(StatusHandlerDescriptor handlerDescriptor) {
+		add(this.map, handlerDescriptor.getPrefix(), handlerDescriptor);
+	}
+
+	/*
+	 * Recursively searches the tree for the best place for the handler
+	 * descriptor
+	 */
+	private void add(Map map, String prefix,
+			StatusHandlerDescriptor handlerDescriptor) {
+		if (prefix == null) {
+			if (map.get(ASTERISK) == null) {
+				map.put(ASTERISK, new ArrayList());
+			}
+
+			((List) map.get(ASTERISK)).add(handlerDescriptor);
+		} else {
+			int delimIndex = prefix.indexOf("."); //$NON-NLS-1$
+
+			String pre = null;
+			String post = null;
+
+			if (delimIndex != -1) {
+				pre = prefix.substring(0, delimIndex);
+
+				if (delimIndex < prefix.length() - 1) {
+					post = prefix.substring(delimIndex + 1);
+				}
+			} else {
+				pre = prefix;
+			}
+
+			if (map.get(pre) == null) {
+				map.put(pre, new HashMap());
+			}
+
+			add((Map) map.get(pre), post, handlerDescriptor);
+		}
+	}
+
+	public void clear() {
+		map.clear();
+	}
+
+	/**
+	 * Returns status handler descriptors whose prefixes are the most specific
+	 * for given pluginId.
+	 *
+	 * @param pluginId
+	 * @return handler descriptors list
+	 */
+	public List getHandlerDescriptors(String pluginId) {
+		return get(pluginId, this.map);
+	}
+
+	/*
+	 * Recursively searches the prefix tree for the most specific handler
+	 * descriptor for the given pluginId.
+	 */
+	private List get(String pluginId, Map map) {
+		if (pluginId == null) {
+			return getAsteriskList(map);
+		}
+
+		int delimIndex = pluginId.indexOf("."); //$NON-NLS-1$
+
+		String pre = null;
+		String post = null;
+
+		if (delimIndex != -1) {
+			pre = pluginId.substring(0, delimIndex);
+
+			if (delimIndex < pluginId.length() - 1) {
+				post = pluginId.substring(delimIndex + 1);
+			}
+		} else {
+			pre = pluginId;
+		}
+
+		if (map.get(pre) == null) {
+			return getAsteriskList(map);
+		}
+
+		return get(post, (Map) map.get(pre));
+	}
+
+	private List getAsteriskList(Map map) {
+		Object list = map.get(ASTERISK);
+		if (list != null) {
+			return (List) list;
+		}
+
+		return null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/StatusHandlerProductBindingDescriptor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/StatusHandlerProductBindingDescriptor.java
new file mode 100644
index 0000000..0d529e2
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/StatusHandlerProductBindingDescriptor.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal.statushandlers;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.ui.IPluginContribution;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+
+/**
+ * The status handler product binding descriptor.
+ *
+ * @since 3.3
+ */
+class StatusHandlerProductBindingDescriptor implements
+		IPluginContribution {
+
+	/**
+	 * Handler id attribute. Value <code>handlerId</code>.
+	 */
+	private static String ATT_HANDLER_ID = "handlerId"; //$NON-NLS-1$
+
+	private String id;
+
+	private String pluginId;
+
+	private String productId;
+
+	private String handlerId;
+
+	/**
+	 * @param configElement
+	 */
+	public StatusHandlerProductBindingDescriptor(
+			IConfigurationElement configElement) {
+		super();
+		id = configElement.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+		pluginId = configElement.getContributor().getName();
+		productId = configElement.getAttribute(IWorkbenchRegistryConstants.ATT_PRODUCTID);
+		handlerId = configElement.getAttribute(ATT_HANDLER_ID);
+	}
+
+	@Override
+	public String getLocalId() {
+		return id;
+	}
+
+	@Override
+	public String getPluginId() {
+		return pluginId;
+	}
+
+	/**
+	 * @return Returns the productId.
+	 */
+	public String getProductId() {
+		return productId;
+	}
+
+	/**
+	 * @return Returns the handlerId.
+	 */
+	public String getHandlerId() {
+		return handlerId;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/StatusHandlerRegistry.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/StatusHandlerRegistry.java
new file mode 100644
index 0000000..ac80ff7
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/StatusHandlerRegistry.java
@@ -0,0 +1,250 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal.statushandlers;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.dynamichelpers.ExtensionTracker;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+
+/**
+ * The registry of status handlers extensions.
+ *
+ * @since 3.3
+ *
+ */
+public class StatusHandlerRegistry implements IExtensionChangeHandler {
+
+	private static final String STATUSHANDLERS_POINT_NAME = "statusHandlers"; //$NON-NLS-1$
+
+	private static final String TAG_STATUSHANDLER = "statusHandler"; //$NON-NLS-1$
+
+	private static final String TAG_STATUSHANDLER_PRODUCTBINDING = "statusHandlerProductBinding"; //$NON-NLS-1$
+
+	private static final String STATUSHANDLER_ARG = "-statushandler"; //$NON-NLS-1$
+
+	private ArrayList statusHandlerDescriptors = new ArrayList();
+
+	private ArrayList productBindingDescriptors = new ArrayList();
+
+	private StatusHandlerDescriptorsMap statusHandlerDescriptorsMap;
+
+	private StatusHandlerDescriptor defaultHandlerDescriptor;
+
+	private static StatusHandlerRegistry instance;
+
+	/**
+	 * Creates an instance of the class.
+	 */
+	private StatusHandlerRegistry() {
+		IExtensionTracker tracker = PlatformUI.getWorkbench()
+				.getExtensionTracker();
+		// RAP [bm]: namespace
+//      IExtensionPoint handlersPoint = Platform.getExtensionRegistry()
+//              .getExtensionPoint(WorkbenchPlugin.PI_WORKBENCH,
+//                      STATUSHANDLERS_POINT_NAME);
+        IExtensionPoint handlersPoint = Platform.getExtensionRegistry()
+        .getExtensionPoint(PlatformUI.PLUGIN_EXTENSION_NAME_SPACE,
+                STATUSHANDLERS_POINT_NAME);
+        // RAPEND: [bm] 
+		IExtension[] extensions = handlersPoint.getExtensions();
+
+		statusHandlerDescriptorsMap = new StatusHandlerDescriptorsMap();
+
+		// initial population
+		for (IExtension extension : extensions) {
+			addExtension(tracker, extension);
+		}
+
+		tracker.registerHandler(this, ExtensionTracker
+				.createExtensionPointFilter(handlersPoint));
+
+		// registers on products ext. point to, needed
+		// for changing the default handler if product is changed
+		IExtensionPoint productsPoint = Platform.getExtensionRegistry()
+				.getExtensionPoint(Platform.PI_RUNTIME, Platform.PT_PRODUCT);
+
+		tracker.registerHandler(this, ExtensionTracker
+				.createExtensionPointFilter(productsPoint));
+	}
+
+	/**
+	 * Returns StatusHandlerRegistry singleton instance.
+	 *
+	 * @return StatusHandlerRegistry instance
+	 */
+	public static StatusHandlerRegistry getDefault() {
+		if (instance == null) {
+			instance = new StatusHandlerRegistry();
+		}
+		return instance;
+	}
+
+	@Override
+	public void addExtension(IExtensionTracker tracker, IExtension extension) {
+		IConfigurationElement[] configElements = extension.getConfigurationElements();
+		for (IConfigurationElement configElement : configElements) {
+			if (configElement.getName().equals(TAG_STATUSHANDLER)) {
+				StatusHandlerDescriptor descriptor = new StatusHandlerDescriptor(configElement);
+				tracker.registerObject(extension, descriptor, IExtensionTracker.REF_STRONG);
+				statusHandlerDescriptors.add(descriptor);
+			} else if (configElement.getName().equals(
+					TAG_STATUSHANDLER_PRODUCTBINDING)) {
+				StatusHandlerProductBindingDescriptor descriptor = new StatusHandlerProductBindingDescriptor(
+						configElement);
+				tracker.registerObject(extension, descriptor, IExtensionTracker.REF_STRONG);
+				productBindingDescriptors.add(descriptor);
+			}
+		}
+		buildHandlersStructure();
+	}
+
+	@Override
+	public void removeExtension(IExtension extension, Object[] objects) {
+		for (Object object : objects) {
+			if (object instanceof StatusHandlerDescriptor) {
+				statusHandlerDescriptors.remove(object);
+			} else if (object instanceof StatusHandlerProductBindingDescriptor) {
+				productBindingDescriptors.remove(object);
+			}
+		}
+		buildHandlersStructure();
+	}
+
+	/**
+	 * Returns the default product handler descriptor, or null if the product is
+	 * not defined or there is no product binding
+	 *
+	 * @return the default handler
+	 */
+	public StatusHandlerDescriptor getDefaultHandlerDescriptor() {
+		return defaultHandlerDescriptor;
+	}
+
+	/**
+	 * Returns a list of handler descriptors which should be used for statuses
+	 * with given plugin id.
+	 *
+	 * @param pluginId
+	 * @return list of handler descriptors
+	 */
+	public List getHandlerDescriptors(String pluginId) {
+		return statusHandlerDescriptorsMap.getHandlerDescriptors(pluginId);
+	}
+
+	/**
+	 * Returns status handler descriptor for given id.
+	 *
+	 * @param statusHandlerId
+	 *            the id to get for
+	 * @return the status handler descriptor
+	 */
+	public StatusHandlerDescriptor getHandlerDescriptor(String statusHandlerId) {
+		StatusHandlerDescriptor descriptor = null;
+		for (Iterator it = statusHandlerDescriptors.iterator(); it.hasNext();) {
+			descriptor = (StatusHandlerDescriptor) it.next();
+			if (descriptor.getId().equals(statusHandlerId)) {
+				return descriptor;
+			}
+		}
+
+		if (defaultHandlerDescriptor != null
+				&& defaultHandlerDescriptor.getId().equals(statusHandlerId)) {
+			return defaultHandlerDescriptor;
+		}
+
+		return null;
+	}
+
+	/**
+	 * Disposes the registry.
+	 */
+	public void dispose() {
+		PlatformUI.getWorkbench().getExtensionTracker().unregisterHandler(this);
+	}
+
+	/**
+	 * It is possible since Eclipse 3.5 to configure custom status handling
+	 * using the -statushandler parameter.
+	 *
+	 * @return the id of the statushandler
+	 * @since 3.5
+	 */
+	private String resolveUserStatusHandlerId(){
+		String[] parameters = Platform.getCommandLineArgs();
+
+		for(int i = 0; i < parameters.length - 1; i++){
+			if(STATUSHANDLER_ARG.equals(parameters[i])){
+				return parameters[i + 1];
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Sets the default product handler descriptor if product exists and binding
+	 * is defined and creates handler descriptors tree due to the prefix policy.
+	 */
+	private void buildHandlersStructure() {
+		statusHandlerDescriptorsMap.clear();
+		defaultHandlerDescriptor = null;
+
+		String productId = Platform.getProduct() != null ? Platform
+				.getProduct().getId() : null;
+
+		List allHandlers = new ArrayList();
+
+		String defaultHandlerId = resolveUserStatusHandlerId();
+
+		if (defaultHandlerId == null) {
+			// we look for product related statushandler if it was not passed as
+			// an argument to Eclipse
+			for (Iterator it = productBindingDescriptors.iterator(); it
+					.hasNext();) {
+				StatusHandlerProductBindingDescriptor descriptor = ((StatusHandlerProductBindingDescriptor) it
+						.next());
+
+				if (descriptor.getProductId().equals(productId)) {
+					defaultHandlerId = descriptor.getHandlerId();
+				}
+			}
+		}
+
+		for (Iterator it = statusHandlerDescriptors.iterator(); it.hasNext();) {
+			StatusHandlerDescriptor descriptor = ((StatusHandlerDescriptor) it
+					.next());
+
+			allHandlers.add(descriptor);
+		}
+
+		StatusHandlerDescriptor handlerDescriptor = null;
+
+		for (Iterator it = allHandlers.iterator(); it.hasNext();) {
+			handlerDescriptor = (StatusHandlerDescriptor) it.next();
+
+			if (handlerDescriptor.getId().equals(defaultHandlerId)) {
+				defaultHandlerDescriptor = handlerDescriptor;
+			} else {
+				statusHandlerDescriptorsMap
+						.addHandlerDescriptor(handlerDescriptor);
+			}
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/SupportTray.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/SupportTray.java
new file mode 100644
index 0000000..6416cc3
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/SupportTray.java
@@ -0,0 +1,363 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2015 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
+ *     Krzysztof Daniel <krzysztof.daniel@gmail.com> - Bug 355030
+ ******************************************************************************/
+package org.eclipse.ui.internal.statushandlers;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+
+import org.eclipse.jface.action.ContributionItem;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.ToolBarManager;
+import org.eclipse.jface.dialogs.DialogTray;
+import org.eclipse.jface.dialogs.ErrorSupportProvider;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.util.Policy;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.PaletteData;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+import org.eclipse.ui.statushandlers.AbstractStatusAreaProvider;
+import org.eclipse.ui.statushandlers.StatusAdapter;
+
+
+/**
+ * This class is responsible for displaying the support area on the right
+ * side of the status dialog.
+ */
+public class SupportTray extends DialogTray implements
+		ISelectionChangedListener {
+
+	private Map dialogState;
+
+
+	/**
+	 * @param dialogState
+	 * @param listener
+	 */
+	public SupportTray(Map dialogState, Listener listener) {
+		this.closeListener = listener;
+		this.dialogState = dialogState;
+		this.hideSupportButtons = getBooleanValue(IStatusDialogConstants.HIDE_SUPPORT_BUTTON);
+		this.lastSelectedStatus = getCurrentStatusAdapter();
+	}
+
+	private IContributionItem closeAction;
+	private Listener closeListener;
+	private boolean hideSupportButtons;
+	private Image normal;
+	private Image hover;
+
+	/**
+	 * This composite occupies the whole space that is available to the support
+	 * tray. It has hardcoded layout behavior to protect the dialog.
+	 */
+	private Composite supportArea;
+	private Composite supportAreaContent;
+
+	private StatusAdapter lastSelectedStatus;
+
+	@Override
+	protected Control createContents(Composite parent) {
+		Composite container = new Composite(parent, SWT.NONE);
+
+		// nothing to display. Should never happen, cause button is disabled
+		// when nothing to display.
+
+		if (providesSupport(getCurrentStatusAdapter()) == null
+				&& getBooleanValue(IStatusDialogConstants.TRAY_OPENED)) {
+
+		}
+
+		GridLayout layout = new GridLayout();
+		layout.marginWidth = layout.marginHeight = 0;
+		layout.verticalSpacing = 0;
+		container.setLayout(layout);
+		GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true);
+		container.setLayoutData(layoutData);
+
+		container.addListener(SWT.Dispose, event -> destroyImages());
+
+		if (!hideSupportButtons) {
+			ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT);
+			toolBarManager.createControl(container);
+			GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_END);
+			gd.grabExcessHorizontalSpace = true;
+			toolBarManager.getControl().setLayoutData(gd);
+			Label separator = new Label(container, SWT.SEPARATOR
+					| SWT.HORIZONTAL);
+			gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
+			gd.heightHint = 1;
+			separator.setLayoutData(gd);
+
+			createActions();
+			toolBarManager.add(closeAction);
+
+			toolBarManager.update(true);
+		}
+
+		supportArea = new Composite(container, SWT.NONE);
+		layout = new GridLayout();
+		layout.marginWidth = layout.marginHeight = 0;
+		layout.verticalSpacing = 0;
+		supportArea.setLayout(layout);
+		GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL
+				| GridData.VERTICAL_ALIGN_FILL);
+		gd.horizontalSpan = 1;
+		gd.grabExcessHorizontalSpace = true;
+		gd.grabExcessVerticalSpace = true;
+		supportArea.setLayoutData(gd);
+
+		if (lastSelectedStatus != null)
+			createSupportArea(supportArea, lastSelectedStatus);
+
+		Point shellSize = supportArea.getShell().getSize();
+		Point desiredSize = supportArea.getShell().computeSize(SWT.DEFAULT,
+				SWT.DEFAULT);
+
+		if(desiredSize.y > shellSize.y){
+			supportArea.getShell().setSize(shellSize.x,
+					Math.min(desiredSize.y, 500));
+		}
+
+		return container;
+	}
+
+	/**
+	 * Creates any custom needed by the tray, such as the close button.
+	 */
+	private void createImages() {
+		Display display = Display.getCurrent();
+		int[] shape = new int[] { 3, 3, 5, 3, 7, 5, 8, 5, 10, 3, 12, 3, 12,
+				5, 10, 7, 10, 8, 12, 10, 12, 12, 10, 12, 8, 10, 7, 10, 5,
+				12, 3, 12, 3, 10, 5, 8, 5, 7, 3, 5 };
+
+		/*
+		 * Use magenta as transparency color since it is used infrequently.
+		 */
+		Color border = display.getSystemColor(SWT.COLOR_WIDGET_DARK_SHADOW);
+		Color background = display
+				.getSystemColor(SWT.COLOR_LIST_BACKGROUND);
+		Color backgroundHot = new Color(display, new RGB(252, 160, 160));
+		Color transparent = display.getSystemColor(SWT.COLOR_MAGENTA);
+
+		PaletteData palette = new PaletteData(new RGB[] {
+				transparent.getRGB(), border.getRGB(), background.getRGB(),
+				backgroundHot.getRGB() });
+		ImageData data = new ImageData(16, 16, 8, palette);
+		data.transparentPixel = 0;
+
+		// RAP [bm] owner drawn image replaced by static
+//		normal = new Image(display, data);
+//		normal.setBackground(transparent);
+//		GC gc = new GC(normal);
+//		gc.setBackground(background);
+//		gc.fillPolygon(shape);
+//		gc.setForeground(border);
+//		gc.drawPolygon(shape);
+//		gc.dispose();
+		normal = loadImage( display, "org/eclipse/ui/internal/statushandlers/close.gif" );
+		
+//		hover = new Image(display, data);
+//		hover.setBackground(transparent);
+//		gc = new GC(hover);
+//		gc.setBackground(backgroundHot);
+//		gc.fillPolygon(shape);
+//		gc.setForeground(border);
+//		gc.drawPolygon(shape);
+//		gc.dispose();
+		hover = loadImage( display, "org/eclipse/ui/internal/statushandlers/close_hover.gif" );
+		
+		backgroundHot.dispose();
+	}
+	
+	// RAP [if]
+		private static Image loadImage( Display display, String name ) {
+	      Image result = null;
+		  InputStream stream = SupportTray.class.getClassLoader().getResourceAsStream( name );
+		  if( stream != null ) {
+		    try {
+		      result = new Image( display, stream );
+		    } finally {
+		      try {
+		        stream.close();
+		      } catch( IOException unexpected ) {
+		        throw new RuntimeException( "Failed to close image input stream", unexpected );
+		      }
+		    }
+		  }
+		  return result;
+		}
+	// RAPEND
+
+	/**
+	 * Creates any actions needed by the tray.
+	 */
+	private void createActions() {
+		createImages();
+		closeAction = new ContributionItem() {
+			@Override
+			public void fill(ToolBar parent, int index) {
+				final ToolItem item = new ToolItem(parent, SWT.PUSH);
+				item.setImage(normal);
+				item.setHotImage(hover);
+				item.setToolTipText(JFaceResources.getString("close")); //$NON-NLS-1$
+				item.addListener(SWT.Selection, closeListener);
+			}
+		};
+	}
+
+	private void destroyImages() {
+		if (normal != null) normal.dispose();
+		if (hover != null) hover.dispose();
+	}
+
+	/**
+	 * Create the area for extra error support information.
+	 *
+	 * @param parent
+	 *            A composite on which should be the support area created.
+	 * @param statusAdapter
+	 *            StatusAdapter for which should be the support area
+	 *            created.
+	 */
+	private void createSupportArea(Composite parent,
+			StatusAdapter statusAdapter) {
+
+		ErrorSupportProvider provider = getSupportProvider();
+
+		// default support area was disabled
+		if (provider == null)
+			return;
+
+		if (supportAreaContent != null)
+			supportAreaContent.dispose();
+
+		supportAreaContent = new Composite(parent, SWT.FILL);
+
+		GridData supportData = new GridData(SWT.FILL, SWT.FILL, true, true);
+		supportAreaContent.setLayoutData(supportData);
+		if (supportAreaContent.getLayout() == null) {
+			GridLayout layout = new GridLayout();
+			layout.marginWidth = 0;
+			layout.marginHeight = 0;
+			supportAreaContent.setLayout(layout); // Give it a default
+			// layout
+		}
+
+		if (provider instanceof AbstractStatusAreaProvider) {
+			((AbstractStatusAreaProvider) provider).createSupportArea(
+					supportAreaContent, statusAdapter);
+		} else {
+			provider.createSupportArea(supportAreaContent, statusAdapter
+					.getStatus());
+		}
+	}
+
+	public ErrorSupportProvider getSupportProvider() {
+		ErrorSupportProvider provider = Policy.getErrorSupportProvider();
+
+		Object userSupportProvider = dialogState
+				.get(IStatusDialogConstants.CUSTOM_SUPPORT_PROVIDER);
+		if (userSupportProvider instanceof AbstractStatusAreaProvider) {
+			provider = (ErrorSupportProvider) userSupportProvider;
+		}
+
+
+		if (getBooleanValue(IStatusDialogConstants.ENABLE_DEFAULT_SUPPORT_AREA) && provider == null) {
+			provider = new StackTraceSupportArea();
+		}
+		return provider;
+	}
+
+	private StatusAdapter getStatusAdapterFromEvent(
+			SelectionChangedEvent event) {
+
+		ISelection selection = event.getSelection();
+
+		if (selection instanceof StructuredSelection) {
+			StructuredSelection structuredSelection = (StructuredSelection) selection;
+			Object element = structuredSelection.getFirstElement();
+			if (element instanceof StatusAdapter) {
+				return (StatusAdapter) element;
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Checks if the support dialog has any support areas.
+	 *
+	 * @param adapter
+	 *            - a parameter for which we area checking the status adapter
+	 * @return true if support dialog has any support areas to display, false
+	 *         otherwise
+	 */
+	public ErrorSupportProvider providesSupport(StatusAdapter adapter) {
+		ErrorSupportProvider provider = getSupportProvider();
+		if (provider instanceof AbstractStatusAreaProvider) {
+			AbstractStatusAreaProvider areaProvider = (AbstractStatusAreaProvider) provider;
+			if (areaProvider.validFor(adapter)) {
+				return areaProvider;
+			}
+			return null;
+		}
+		return provider;
+	}
+
+	@Override
+	public void selectionChanged(SelectionChangedEvent event) {
+		lastSelectedStatus = getStatusAdapterFromEvent(event);
+		if (supportArea != null && !supportArea.isDisposed()) {
+			if (lastSelectedStatus != null) {
+				createSupportArea(supportArea, lastSelectedStatus);
+				supportArea.layout(true);
+			}
+		}
+	}
+
+	/**
+	 * @return Returns the supportArea.
+	 */
+	public Composite getSupportArea() {
+		return supportArea;
+	}
+
+	private boolean getBooleanValue(Object key) {
+		Boolean b = (Boolean) dialogState.get(key);
+		if (b == null) {
+			return false;
+		}
+		return b.booleanValue();
+	}
+
+	private StatusAdapter getCurrentStatusAdapter() {
+		return (StatusAdapter) dialogState
+				.get(IStatusDialogConstants.CURRENT_STATUS_ADAPTER);
+	}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/WorkbenchStatusDialogManagerImpl.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/WorkbenchStatusDialogManagerImpl.java
new file mode 100644
index 0000000..d53f099
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/WorkbenchStatusDialogManagerImpl.java
@@ -0,0 +1,539 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2015 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.ui.internal.statushandlers;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.QualifiedName;
+import org.eclipse.jface.dialogs.ErrorDialog;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.viewers.ILabelDecorator;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.progress.IProgressConstants;
+import org.eclipse.ui.statushandlers.IStatusAdapterConstants;
+import org.eclipse.ui.statushandlers.StatusAdapter;
+import org.eclipse.ui.statushandlers.StatusManager;
+import org.eclipse.ui.statushandlers.StatusManager.INotificationTypes;
+
+/**
+ * <p>
+ * This class is the actual dialog manager. Status dialog is a very bad thing to
+ * manage, because it can switch its modality. As you know this is not possible,
+ * so dialog is closed and then reopened. This approach makes impossible to keep
+ * dialog data inside dialog class, because the dialog will be disposed.
+ * </p>
+ * <p>
+ * To overcome this issue, a {@link Map} dialogState is introduced, which holds
+ * the actual state (and configuration) of the dialog. This map is passed to all
+ * dialog subcomponents.
+ * </p>
+ * <p>
+ * Dialog state variables are defined in {@link IStatusDialogConstants}.
+ * </p>
+ *
+ * @since 3.6
+ * @noextend This class is not intended to be subclassed by clients.
+ * @noinstantiate This class is not intended to be instantiated by clients.
+ */
+public class WorkbenchStatusDialogManagerImpl {
+
+	static final QualifiedName HINT = new QualifiedName(
+			IStatusAdapterConstants.PROPERTY_PREFIX, "hint"); //$NON-NLS-1$
+
+	private final class StatusDialogDisposeListener implements DisposeListener {
+
+		@Override
+		public void widgetDisposed(org.eclipse.swt.events.DisposeEvent e) {
+			cleanUp();
+		}
+	}
+
+	private DisposeListener disposeListener = new StatusDialogDisposeListener();
+
+	/**
+	 * This field stores the real dialog that appears to the user.
+	 */
+	private InternalDialog dialog;
+
+	/**
+	 * This variable holds the real state of the dialog.
+	 */
+	private Map dialogState = new HashMap();
+
+	/**
+	 * Returns whether the given StatusAdapter object should be displayed.
+	 *
+	 * @param statusAdapter
+	 *            a status object
+	 * @return <code>true</code> if the given status should be displayed, and
+	 *         <code>false</code> otherwise
+	 * @see org.eclipse.core.runtime.IStatus#matches(int)
+	 */
+	public boolean shouldAccept(StatusAdapter statusAdapter) {
+		IStatus status = statusAdapter.getStatus();
+		IStatus[] children = status.getChildren();
+		int mask = ((Integer) dialogState.get(IStatusDialogConstants.MASK))
+				.intValue();
+		boolean handleOKStatuses = ((Boolean) dialogState
+				.get(IStatusDialogConstants.HANDLE_OK_STATUSES)).booleanValue();
+		if (children == null || children.length == 0) {
+			return status.matches(mask) || (handleOKStatuses && status.isOK());
+		}
+		for (IStatus child : children) {
+			if (child.matches(mask)) {
+				return true;
+			}
+		}
+		if (handleOKStatuses && status.isOK()) {
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Creates workbench status dialog.
+	 *
+	 * @param displayMask
+	 *            the mask used to filter the handled <code>StatusAdapter</code>
+	 *            objects, the mask is a logical sum of status severities
+	 * @param dialogTitle
+	 *            the title of the dialog. If null, than default will be used.
+	 */
+	public WorkbenchStatusDialogManagerImpl(int displayMask, String dialogTitle) {
+
+		Assert
+				.isNotNull(Display.getCurrent(),
+						"WorkbenchStatusDialogManager must be instantiated in UI thread"); //$NON-NLS-1$
+
+		dialogState = initDialogState(dialogState, displayMask, dialogTitle);
+	}
+
+	/**
+	 * This method creates the initial state of the dialog.
+	 *
+	 * @param dialogState
+	 *            - the map to fill in.
+	 * @param displayMask
+	 *            - the mask suggesting which statuses should be displayed
+	 * @param dialogTitle
+	 *            - the dialog title.
+	 * @return populated dialogState
+	 */
+	public Map initDialogState(Map dialogState, int displayMask, String dialogTitle) {
+		dialogState.put(IStatusDialogConstants.MASK, Integer.valueOf(displayMask));
+		dialogState.put(IStatusDialogConstants.TITLE,
+				dialogTitle == null ? JFaceResources
+						.getString("Problem_Occurred") : //$NON-NLS-1$
+						dialogTitle);
+		dialogState.put(IStatusDialogConstants.HANDLE_OK_STATUSES,
+				Boolean.FALSE);
+
+		dialogState.put(IStatusDialogConstants.SHOW_SUPPORT, Boolean.FALSE);
+		dialogState.put(IStatusDialogConstants.ENABLE_DEFAULT_SUPPORT_AREA,
+				Boolean.FALSE);
+		dialogState.put(IStatusDialogConstants.DETAILS_OPENED, Boolean.FALSE);
+		dialogState.put(IStatusDialogConstants.TRAY_OPENED, Boolean.FALSE);
+		dialogState.put(IStatusDialogConstants.HIDE_SUPPORT_BUTTON,
+				Boolean.FALSE);
+		dialogState.put(IStatusDialogConstants.STATUS_ADAPTERS, Collections
+				.synchronizedSet(new HashSet()));
+		dialogState.put(IStatusDialogConstants.STATUS_MODALS, new HashMap());
+		dialogState.put(IStatusDialogConstants.LABEL_PROVIDER, new LabelProviderWrapper(
+				dialogState));
+		dialogState.put(IStatusDialogConstants.MODALITY_SWITCH, Boolean.FALSE);
+		dialogState.put(IStatusDialogConstants.ANIMATION, Boolean.TRUE);
+		return dialogState;
+	}
+
+	/**
+	 * <p>
+	 * Adds a new {@link StatusAdapter} to the status adapters list in the
+	 * dialog.
+	 * </p>
+	 * <p>
+	 * If the dialog is already visible, the status adapter will be shown
+	 * immediately. Otherwise, the dialog with the added status adapter will
+	 * show up, if all conditions below are false.
+	 * <ul>
+	 * <li>the status adapter has
+	 * {@link IProgressConstants#NO_IMMEDIATE_ERROR_PROMPT_PROPERTY} set to true</li>
+	 * </ul>
+	 * </p>
+	 * <p>
+	 * All not shown status adapters will be displayed as soon as the dialog
+	 * shows up.
+	 * </p>
+	 *
+	 * @param modal
+	 *            <code>true</code> if the dialog should be modal,
+	 *            <code>false</code> otherwise
+	 * @param statusAdapter
+	 *            the status adapter
+	 */
+	public void addStatusAdapter(final StatusAdapter statusAdapter,
+			final boolean modal) {
+		if (ErrorDialog.AUTOMATED_MODE == true) {
+			return;
+		}
+		try {
+			doAddStatusAdapter(statusAdapter, modal);
+		} catch (Exception e) {
+			// if dialog is open, dispose it (and all child controls)
+			if (!isDialogClosed()) {
+				dialog.getShell().dispose();
+			}
+			// reset the state
+			cleanUp();
+			// log original problem
+			// TODO: check if is it possible to discover duplicates
+			WorkbenchPlugin.log(statusAdapter.getStatus());
+			// log the problem with status handling
+			WorkbenchPlugin.log(e);
+		}
+	}
+
+	private boolean isDialogClosed() {
+		return dialog == null || dialog.getShell() == null
+				|| dialog.getShell().isDisposed();
+	}
+
+	private void cleanUp() {
+		dialog = null;
+		getErrors().clear();
+		getModals().clear();
+		dialogState.put(IStatusDialogConstants.DETAILS_OPENED, Boolean.FALSE);
+		dialogState.put(IStatusDialogConstants.TRAY_OPENED, Boolean.FALSE);
+		dialogState.put(IStatusDialogConstants.MODALITY_SWITCH, Boolean.FALSE);
+		dialogState.remove(IStatusDialogConstants.CURRENT_STATUS_ADAPTER);
+	}
+
+	private void doAddStatusAdapter(final StatusAdapter statusAdapter,
+			final boolean modal) {
+
+		if (!PlatformUI.isWorkbenchRunning()) {
+			// we are shutting down, so just log
+			WorkbenchPlugin.log(statusAdapter.getStatus());
+			return;
+		}
+
+		// if statusAdapter does not match the mask, ignore it
+		if (!shouldAccept(statusAdapter)) {
+			return;
+		}
+
+		// Add the error in the UI thread to ensure thread safety in the
+		// dialog
+		if (isDialogClosed()) {
+
+			getErrors().add(statusAdapter);
+			getModals().put(statusAdapter, Boolean.valueOf(modal));
+			// Delay prompting if the status adapter property is set
+			if (shouldPrompt(statusAdapter)) {
+				// notify all interested parties that status adapters will be
+				// handled
+				StatusManager.getManager().fireNotification(
+						INotificationTypes.HANDLED,
+						(StatusAdapter[]) getErrors()
+								.toArray(new StatusAdapter[] {}));
+
+				if (dialog == null) {
+					setSelectedStatusAdapter(statusAdapter);
+					dialog = new InternalDialog(dialogState, shouldBeModal());
+					dialog.create();
+					dialog.getShell().addDisposeListener(disposeListener);
+					boolean showSupport = ((Boolean) dialogState
+							.get(IStatusDialogConstants.SHOW_SUPPORT))
+							.booleanValue();
+					if (showSupport) {
+						dialog.openTray();
+						dialog.getShell().setLocation(
+								dialog.getInitialLocation(dialog.getShell().getSize()));
+					}
+					dialog.open();
+				}
+				dialog.refresh();
+				dialog.refreshDialogSize();
+			}
+
+		} else {
+			StatusManager.getManager().fireNotification(
+					INotificationTypes.HANDLED,
+					new StatusAdapter[] { statusAdapter });
+			if (statusAdapter
+					.getProperty(IProgressConstants.NO_IMMEDIATE_ERROR_PROMPT_PROPERTY) != null) {
+				statusAdapter.setProperty(
+						IProgressConstants.NO_IMMEDIATE_ERROR_PROMPT_PROPERTY,
+						Boolean.FALSE);
+			}
+			openStatusDialog(modal, statusAdapter);
+		}
+	}
+
+	/**
+	 * Gets a collection of status adapters that were passed to the dialog.
+	 *
+	 * @return collection of {@link StatusAdapter} objects
+	 */
+	public Collection getStatusAdapters() {
+		return Collections.unmodifiableCollection(getErrors());
+	}
+
+	/**
+	 * Opens status dialog with particular statusAdapter selected.
+	 *
+	 * @param modal
+	 *            decides if window is modal or not.
+	 * @param statusAdapter
+	 *            status adapter to be selected.
+	 */
+	private void openStatusDialog(final boolean modal,
+			final StatusAdapter statusAdapter) {
+		getErrors().add(statusAdapter);
+		getModals().put(statusAdapter, Boolean.valueOf(modal));
+		boolean shouldBeModal = shouldBeModal();
+		if (shouldBeModal ^ dialog.isModal()) {
+			dialog.getShell().removeDisposeListener(disposeListener);
+			dialogState.put(IStatusDialogConstants.MODALITY_SWITCH, Boolean.TRUE);
+			dialog.close();
+			dialog = new InternalDialog(dialogState, modal);
+			dialog.open();
+			dialog.getShell().addDisposeListener(disposeListener);
+			dialogState.put(IStatusDialogConstants.MODALITY_SWITCH, Boolean.FALSE);
+		}
+		dialog.refresh();
+	}
+
+	/**
+	 * Sets current status adapter.
+	 *
+	 * @param statusAdapter
+	 *            The statusAdapter to set.
+	 */
+	public void setSelectedStatusAdapter(StatusAdapter statusAdapter) {
+		dialogState.put(IStatusDialogConstants.CURRENT_STATUS_ADAPTER,
+				statusAdapter);
+	}
+
+	/**
+	 * Sets new label provider for the status list. This label provider is used
+	 * also to display the second message on the dialog if only one status is
+	 * available.
+	 *
+	 * <p>
+	 * This method is no longer recommended to use as it is impossible to
+	 * achieve consistent behavior after changing only one label provider.
+	 * </p>
+	 *
+	 * @deprecated As of 3.5 {@link #setMessageDecorator} is recommended.
+	 *
+	 * @param labelProvider
+	 *            a label provider to be used when displaying status adapters.
+	 */
+	@Deprecated
+	public void setStatusListLabelProvider(ITableLabelProvider labelProvider) {
+		Assert.isLegal(labelProvider != null, "Label Provider cannot be null"); //$NON-NLS-1$
+		dialogState.put(IStatusDialogConstants.CUSTOM_LABEL_PROVIDER,
+				labelProvider);
+	}
+
+	/**
+	 * Decides if dialog should be modal. Dialog will be modal if any of the
+	 * statuses contained by StatusAdapters had been reported with
+	 * {@link StatusManager#BLOCK} flag.
+	 *
+	 * @return true if any StatusHandler should be displayed in modal window
+	 */
+	public boolean shouldBeModal() {
+		Map<?, ?> modals = (Map<?, ?>) dialogState
+				.get(IStatusDialogConstants.STATUS_MODALS);
+		for (Object value : modals.values()) {
+			if (value instanceof Boolean) {
+				Boolean b = (Boolean) value;
+				if (b.booleanValue()) {
+					return true;
+				}
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Checks if the user should be prompted immediately about
+	 * {@link StatusAdapter}
+	 *
+	 * @param statusAdapter
+	 *            to be checked.
+	 * @return true if the statusAdapter should be prompted, false otherwise.
+	 */
+	public boolean shouldPrompt(final StatusAdapter statusAdapter) {
+		Object noPromptProperty = statusAdapter
+				.getProperty(IProgressConstants.NO_IMMEDIATE_ERROR_PROMPT_PROPERTY);
+
+		boolean prompt = true;
+		if (noPromptProperty instanceof Boolean) {
+			prompt = !((Boolean) noPromptProperty).booleanValue();
+		}
+		return prompt;
+	}
+
+	/**
+	 * Gets the shell of the managed dialog.
+	 *
+	 * @return Shell or null
+	 *
+	 */
+	public Shell getShell() {
+		if (this.dialog == null)
+			return null;
+		return this.dialog.getShell();
+	}
+
+	/**
+	 * <p>
+	 * This methods sets up the decorator, which is used to modify displayed
+	 * strings extracted from StatusAdapter. The decorator should be used to
+	 * remove technical codes from the dialog, f.e. following message
+	 * "<i>ERR2008 Invalid password</i>" can be translated into
+	 * "<i>Invalid password</i>".
+	 * </p>
+	 * <p>
+	 * The decorator will be applied only to messages extracted from
+	 * StatusAdapter (predefined messages like
+	 * "This status has children statuses. See 'Details' for more information."
+	 * are not affected.
+	 * </p>
+	 * <p>
+	 * This method should not be used together with
+	 * {@link #setStatusListLabelProvider(ITableLabelProvider)}.
+	 * </p>
+	 *
+	 * @param decorator
+	 *            - the decorator to be set. Only
+	 *            {@link ILabelDecorator#decorateText(String, Object)} method
+	 *            will be used. This method should return <code>null</code> if
+	 *            and only if the first argument is null. StatusAdapter is
+	 *            passed as second parameter. Other methods should have default
+	 *            behavior as they may be used in future versions of the dialog.
+	 * @since 3.5
+	 */
+	public void setMessageDecorator(ILabelDecorator decorator){
+		dialogState.put(IStatusDialogConstants.DECORATOR, decorator);
+	}
+
+
+	/**
+	 * This method sets various properties on the manager.
+	 *
+	 * @param key
+	 *            a key of the property to be set.
+	 * @param value
+	 *            a value of the property to be set. The value must be of type
+	 *            specified by the property key. <code>null</code> should never
+	 *            be passed unless the property key javadoc allows for that.
+	 * @since 3.5
+	 */
+	public void setProperty(Object key, Object value) {
+		dialogState.put(key, value);
+	}
+
+	/**
+	 * This method gets various dialog properties.
+	 *
+	 * @param key
+	 *            a key of the property to be get.
+	 * @return a value of the property. The value will be of type specified by
+	 *         the property key. <code>null</code> can be returned.
+	 * @since 3.5
+	 */
+	public Object getProperty(Object key){
+		if(key == IStatusDialogConstants.SHELL){
+			return getShell();
+		}
+		if (key == IStatusDialogConstants.MANAGER_IMPL) {
+			return this;
+		}
+		return dialogState.get(key);
+	}
+
+	/**
+	 * This method makes the dialog to be similar to the JFace ErrorDialog. The
+	 * dialog handles {@link StatusAdapter}s wrapping {@link IStatus} with
+	 * severity {@link IStatus#OK}, does not display the link to the error log,
+	 * does not display the link to the support area but always opens it.
+	 *
+	 * @see ErrorDialog
+	 * @since 3.6
+	 */
+	public void enableErrorDialogCompatibility(){
+		setProperty(IStatusDialogConstants.ERRORLOG_LINK, Boolean.FALSE);
+		setProperty(IStatusDialogConstants.HANDLE_OK_STATUSES, Boolean.TRUE);
+		setProperty(IStatusDialogConstants.SHOW_SUPPORT, Boolean.TRUE);
+		setProperty(IStatusDialogConstants.HIDE_SUPPORT_BUTTON, Boolean.TRUE);
+	}
+
+	/**
+	 * This method is public for testing purposes only.
+	 *
+	 * @return Returns the dialog.
+	 */
+	public InternalDialog getDialog() {
+		return dialog;
+	}
+
+	/**
+	 * This method is public for testing purposes only.
+	 *
+	 * @param dialog
+	 *            The dialog to set.
+	 */
+	public void setDialog(InternalDialog dialog) {
+		this.dialog = dialog;
+	}
+
+	/**
+	 * This method is public for testing purposes only.
+	 *
+	 * @return dialog state.
+	 */
+	public Map getDialogState() {
+		return dialogState;
+	}
+
+	/**
+	 * Utility method to access StatusAdapters
+	 *
+	 * @return Collection of StatusAdapters
+	 */
+	private Collection getErrors() {
+		return (Collection) dialogState
+				.get(IStatusDialogConstants.STATUS_ADAPTERS);
+	}
+
+	/**
+	 * Utility method to access StatusAdapter modal flag.
+	 *
+	 * @return Collection of StatusAdapter modal flag.
+	 */
+	private Map getModals() {
+		return (Map) dialogState
+				.get(IStatusDialogConstants.STATUS_MODALS);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/package.html b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/package.html
new file mode 100644
index 0000000..d720e2b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/statushandlers/package.html
@@ -0,0 +1,16 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <meta name="Author" content="IBM">
+   <meta name="GENERATOR" content="Mozilla/4.5 [en] (Win98; I) [Netscape]">
+   <title>Package-level Javadoc</title>
+</head>
+<body>
+To be written.
+<h2>
+Package Specification</h2>
+<p>
+This package provides classes that can be used to ...</p>
+</body>
+</html>
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/testing/ContributionInfoMessages.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/testing/ContributionInfoMessages.java
new file mode 100644
index 0000000..557e136
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/testing/ContributionInfoMessages.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2015 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.ui.internal.testing;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * @since 3.6
+ *
+ */
+public class ContributionInfoMessages extends NLS {
+	private static final String BUNDLE_NAME = "org.eclipse.ui.internal.testing.messages";//$NON-NLS-1$
+
+
+	public static String ContributionInfo_Editor;
+	public static String ContributionInfo_View;
+	public static String ContributionInfo_ActionSet;
+	public static String ContributionInfo_Category;
+	public static String ContributionInfo_ColorDefinition;
+	public static String ContributionInfo_Wizard;
+	public static String ContributionInfo_Perspective;
+	public static String ContributionInfo_Page;
+	public static String ContributionInfo_EarlyStartupPlugin;
+	public static String ContributionInfo_Unknown;
+	public static String ContributionInfo_Job;
+	public static String ContributionInfo_TableItem;
+	public static String ContributionInfo_TreeItem;
+	public static String ContributionInfo_Window;
+	public static String ContributionInfo_LabelDecoration;
+	public static String ContributionInfo_ViewContent;
+
+	public static String ContributionInfo_ContributedBy;
+
+	static {
+		// load message values from bundle file
+		NLS.initializeMessages(BUNDLE_NAME, ContributionInfoMessages.class);
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/testing/PluginContributionAdapterFactory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/testing/PluginContributionAdapterFactory.java
new file mode 100644
index 0000000..a53695a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/testing/PluginContributionAdapterFactory.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2016 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.ui.internal.testing;
+
+import org.eclipse.core.runtime.IAdapterFactory;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.ui.IPluginContribution;
+import org.eclipse.ui.internal.decorators.DecoratorDefinition;
+import org.eclipse.ui.internal.dialogs.WizardCollectionElement;
+import org.eclipse.ui.internal.dialogs.WorkbenchWizardElement;
+import org.eclipse.ui.internal.preferences.WorkbenchPreferenceExpressionNode;
+import org.eclipse.ui.internal.progress.JobInfo;
+import org.eclipse.ui.internal.registry.ActionSetDescriptor;
+import org.eclipse.ui.internal.registry.Category;
+import org.eclipse.ui.internal.registry.EditorDescriptor;
+import org.eclipse.ui.internal.registry.PerspectiveDescriptor;
+import org.eclipse.ui.internal.registry.ViewDescriptor;
+import org.eclipse.ui.internal.themes.ColorDefinition;
+import org.eclipse.ui.internal.themes.ThemeElementCategory;
+import org.eclipse.ui.testing.ContributionInfo;
+import org.eclipse.ui.views.IViewCategory;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.FrameworkUtil;
+
+/**
+ * @since 3.6
+ *
+ */
+public class PluginContributionAdapterFactory implements IAdapterFactory {
+
+	@Override
+	public <T> T getAdapter(Object adaptableObject, Class<T> adapterType) {
+		if (adapterType != ContributionInfo.class) {
+			return null;
+		}
+		if (adaptableObject instanceof IPluginContribution) {
+			IPluginContribution contribution = (IPluginContribution) adaptableObject;
+
+			String elementType;
+
+			if (contribution instanceof EditorDescriptor) {
+				elementType = ContributionInfoMessages.ContributionInfo_Editor;
+			} else if (contribution instanceof ViewDescriptor) {
+				elementType = ContributionInfoMessages.ContributionInfo_View;
+			} else if (contribution instanceof ActionSetDescriptor) {
+				elementType = ContributionInfoMessages.ContributionInfo_ActionSet;
+			} else if (contribution instanceof Category) {
+				elementType = ContributionInfoMessages.ContributionInfo_Category;
+			} else if (contribution instanceof IViewCategory) {
+				elementType = ContributionInfoMessages.ContributionInfo_Category;
+			} else if (contribution instanceof ThemeElementCategory) {
+				elementType = ContributionInfoMessages.ContributionInfo_Category;
+			} else if (contribution instanceof WizardCollectionElement) {
+				elementType = ContributionInfoMessages.ContributionInfo_Category;
+			} else if (contribution instanceof ColorDefinition) {
+				elementType = ContributionInfoMessages.ContributionInfo_ColorDefinition;
+			} else if (contribution instanceof WorkbenchWizardElement) {
+				elementType = ContributionInfoMessages.ContributionInfo_Wizard;
+			} else if (contribution instanceof PerspectiveDescriptor) {
+				elementType = ContributionInfoMessages.ContributionInfo_Perspective;
+			} else if (contribution instanceof WorkbenchPreferenceExpressionNode) {
+				elementType = ContributionInfoMessages.ContributionInfo_Page;
+			} else if (contribution instanceof DecoratorDefinition) {
+				elementType = ContributionInfoMessages.ContributionInfo_LabelDecoration;
+			} else {
+				elementType = ContributionInfoMessages.ContributionInfo_Unknown;
+			}
+
+			return adapterType.cast(new ContributionInfo(contribution.getPluginId(), elementType, null));
+		}
+		if (adaptableObject instanceof JobInfo) {
+			JobInfo jobInfo = (JobInfo) adaptableObject;
+			Job job = jobInfo.getJob();
+			if (job != null) {
+				Bundle bundle = FrameworkUtil.getBundle(job.getClass());
+				if (bundle != null) {
+					return adapterType.cast(new ContributionInfo(bundle.getSymbolicName(),
+							ContributionInfoMessages.ContributionInfo_Job, null));
+				}
+			}
+		}
+		return null;
+	}
+
+	@Override
+	public Class<?>[] getAdapterList() {
+		return new Class[] { ContributionInfo.class };
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/testing/WorkbenchPartTestable.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/testing/WorkbenchPartTestable.java
new file mode 100644
index 0000000..e046101
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/testing/WorkbenchPartTestable.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.testing;
+
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.internal.PartSite;
+import org.eclipse.ui.testing.IWorkbenchPartTestable;
+
+/**
+ * Implementation of {@link IWorkbenchPartTestable}.
+ *
+ * @since 3.3
+ */
+public class WorkbenchPartTestable implements IWorkbenchPartTestable {
+
+	private Composite composite;
+
+	/**
+	 * Create a new instance of this class based on the provided part.
+	 *
+	 * @param partSite the part to test
+	 */
+	public WorkbenchPartTestable(PartSite partSite) {
+		Composite paneComposite = (Composite) partSite.getModel().getWidget();
+		Control [] paneChildren = paneComposite.getChildren();
+		this.composite = ((Composite) paneChildren[0]);
+	}
+
+	@Override
+	public Composite getControl() {
+		return composite;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/testing/WorkbenchTestable.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/testing/WorkbenchTestable.java
new file mode 100644
index 0000000..9b64116
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/testing/WorkbenchTestable.java
@@ -0,0 +1,131 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.internal.testing;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.dialogs.ErrorDialog;
+import org.eclipse.jface.util.SafeRunnable;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.Workbench;
+import org.eclipse.ui.testing.TestableObject;
+
+/**
+ * The Workbench's testable object facade to a test harness.
+ *
+ * @since 3.0
+ */
+public class WorkbenchTestable extends TestableObject {
+
+    private Display display;
+
+    private IWorkbench workbench;
+
+    private boolean oldAutomatedMode;
+
+    private boolean oldIgnoreErrors;
+
+    /**
+     * Constructs a new workbench testable object.
+     */
+    public WorkbenchTestable() {
+        // do nothing
+    }
+
+    /**
+     * Initializes the workbench testable with the display and workbench,
+     * and notifies all listeners that the tests can be run.
+     *
+     * @param display the display
+     * @param workbench the workbench
+     */
+    public void init(Display display, IWorkbench workbench) {
+        Assert.isNotNull(display);
+        Assert.isNotNull(workbench);
+        this.display = display;
+        this.workbench = workbench;
+        if (getTestHarness() != null) {
+        	// don't use a job, since tests often wait for all jobs to complete before proceeding
+            Runnable runnable = () -> {
+				// disable workbench auto-save during tests
+				if ("true".equalsIgnoreCase(System.getProperty(PlatformUI.PLUGIN_ID + ".testsDisableWorkbenchAutoSave"))) { //$NON-NLS-1$ //$NON-NLS-2$
+					if (WorkbenchTestable.this.workbench instanceof Workbench) {
+						((Workbench) WorkbenchTestable.this.workbench).setEnableAutoSave(false);
+					}
+					Job.getJobManager().cancel(Workbench.WORKBENCH_AUTO_SAVE_JOB);
+				}
+				// Some tests (notably the startup performance tests) do not want to wait for early startup.
+				// Allow this to be disabled by specifying the system property: org.eclipse.ui.testsWaitForEarlyStartup=false
+				// For details, see bug 94129 [Workbench] Performance test regression caused by workbench harness change
+				if (!"false".equalsIgnoreCase(System.getProperty(PlatformUI.PLUGIN_ID + ".testsWaitForEarlyStartup"))) {  //$NON-NLS-1$ //$NON-NLS-2$
+					waitForEarlyStartup();
+				}
+			    getTestHarness().runTests();
+			};
+            new Thread(runnable, "WorkbenchTestable").start(); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Waits for the early startup job to complete.
+     */
+    private void waitForEarlyStartup() {
+		try {
+			Job.getJobManager().join(Workbench.EARLY_STARTUP_FAMILY, null);
+		} catch (OperationCanceledException e) {
+			// ignore
+		} catch (InterruptedException e) {
+			// ignore
+		}
+    }
+
+    /**
+     * The <code>WorkbenchTestable</code> implementation of this
+     * <code>TestableObject</code> method ensures that the workbench
+     * has been set.
+     */
+    @Override
+	public void testingStarting() {
+        Assert.isNotNull(workbench);
+        oldAutomatedMode = ErrorDialog.AUTOMATED_MODE;
+        ErrorDialog.AUTOMATED_MODE = true;
+        oldIgnoreErrors = SafeRunnable.getIgnoreErrors();
+        SafeRunnable.setIgnoreErrors(true);
+    }
+
+    /**
+     * The <code>WorkbenchTestable</code> implementation of this
+     * <code>TestableObject</code> method flushes the event queue,
+     * runs the test in a <code>syncExec</code>, then flushes the
+     * event queue again.
+     */
+    @Override
+	public void runTest(Runnable testRunnable) {
+        Assert.isNotNull(workbench);
+        display.syncExec(testRunnable);
+    }
+
+    /**
+     * The <code>WorkbenchTestable</code> implementation of this
+     * <code>TestableObject</code> method flushes the event queue,
+     * then closes the workbench.
+     */
+    @Override
+	public void testingFinished() {
+        // force events to be processed, and ensure the close is done in the UI thread
+        display.syncExec(() -> Assert.isTrue(workbench.close()));
+        ErrorDialog.AUTOMATED_MODE = oldAutomatedMode;
+        SafeRunnable.setIgnoreErrors(oldIgnoreErrors);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/testing/messages.properties b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/testing/messages.properties
new file mode 100644
index 0000000..5c040ca
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/testing/messages.properties
@@ -0,0 +1,29 @@
+###############################################################################
+# Copyright (c) 2010, 2013 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
+###############################################################################
+
+ContributionInfo_Unknown=unknown contribution
+ContributionInfo_Editor=editor
+ContributionInfo_View=view
+ContributionInfo_ActionSet=command group
+ContributionInfo_Category=category
+ContributionInfo_ColorDefinition=color definition
+ContributionInfo_Wizard=wizard
+ContributionInfo_Perspective=perspective
+ContributionInfo_Page=page
+ContributionInfo_EarlyStartupPlugin=early startup plug-in
+ContributionInfo_Job=job
+ContributionInfo_TableItem=table item
+ContributionInfo_TreeItem=tree item
+ContributionInfo_Window=window
+ContributionInfo_LabelDecoration=label decoration
+ContributionInfo_ViewContent=view content
+
+ContributionInfo_ContributedBy=This {0} has been contributed by: {1} 
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/CascadingColorRegistry.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/CascadingColorRegistry.java
new file mode 100644
index 0000000..efcdec1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/CascadingColorRegistry.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.themes;
+
+import java.util.HashSet;
+import java.util.Set;
+import org.eclipse.jface.resource.ColorRegistry;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * @since 3.0
+ */
+public class CascadingColorRegistry extends ColorRegistry {
+
+    private ColorRegistry parent;
+
+    private IPropertyChangeListener listener = event -> {
+		// check to see if we have an override for the given key. If so,
+		// then a change in our parent registry shouldn't cause a change in
+		// us. Without this check we will propagate a new value
+		// (event.getNewValue()) to our listeners despite the fact that this
+		// value is NOT our current value.
+		if (!hasOverrideFor(event.getProperty()))
+			fireMappingChanged(event.getProperty(), event.getOldValue(),
+					event.getNewValue());
+	};
+
+    /**
+     * Create a new instance of this class.
+     *
+     * @param parent the parent registry
+     */
+    public CascadingColorRegistry(ColorRegistry parent) {
+    	super(Display.getCurrent(), false);
+        this.parent = parent;
+        parent.addListener(listener);
+    }
+
+    @Override
+	public Color get(String symbolicName) {
+        if (super.hasValueFor(symbolicName)) {
+			return super.get(symbolicName);
+		}
+
+        return parent.get(symbolicName);
+    }
+
+    @Override
+	public Set getKeySet() {
+        Set keyUnion = new HashSet(super.getKeySet());
+        keyUnion.addAll(parent.getKeySet());
+        return keyUnion;
+    }
+
+    @Override
+	public RGB getRGB(String symbolicName) {
+        if (super.hasValueFor(symbolicName)) {
+			return super.getRGB(symbolicName);
+		}
+
+        return parent.getRGB(symbolicName);
+    }
+
+    @Override
+	public boolean hasValueFor(String colorKey) {
+        return super.hasValueFor(colorKey) || parent.hasValueFor(colorKey);
+    }
+
+    /**
+     * Returns whether this cascading registry has an override for the provided
+     * color key.
+     *
+     * @param colorKey the provided color key
+     * @return hether this cascading registry has an override
+     */
+    public boolean hasOverrideFor(String colorKey) {
+        return super.hasValueFor(colorKey);
+    }
+
+    /**
+     * Disposes of all allocated resources.
+     */
+    public void dispose() {
+        parent.removeListener(listener);
+        PlatformUI.getWorkbench().getDisplay().asyncExec(displayRunnable);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/CascadingFontRegistry.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/CascadingFontRegistry.java
new file mode 100644
index 0000000..4f1006e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/CascadingFontRegistry.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.themes;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.jface.resource.FontRegistry;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * @since 3.0
+ */
+public class CascadingFontRegistry extends FontRegistry {
+
+    private FontRegistry parent;
+
+    private IPropertyChangeListener listener = event -> {
+		// check to see if we have an override for the given key. If so,
+		// then a change in our parent registry shouldn't cause a change in
+		// us. Without this check we will propagate a new value
+		// (event.getNewValue()) to our listeners despite the fact that this
+		// value is NOT our current value.
+		if (!hasOverrideFor(event.getProperty()))
+	    fireMappingChanged(event.getProperty(), event.getOldValue(), event
+	            .getNewValue());
+
+	};
+
+    /**
+     * Create a new instance of this class.
+     *
+     * @param parent the parent registry
+     */
+    public CascadingFontRegistry(FontRegistry parent) {
+    	super(Display.getCurrent(), false);
+        this.parent = parent;
+        parent.addListener(listener);
+    }
+
+    @Override
+	public Font get(String symbolicName) {
+        if (super.hasValueFor(symbolicName)) {
+			return super.get(symbolicName);
+		}
+        return parent.get(symbolicName);
+    }
+
+    @Override
+	public Set getKeySet() {
+        Set keyUnion = new HashSet(super.getKeySet());
+        keyUnion.addAll(parent.getKeySet());
+        return keyUnion;
+    }
+
+    @Override
+	public FontData[] getFontData(String symbolicName) {
+        if (super.hasValueFor(symbolicName)) {
+			return super.getFontData(symbolicName);
+		}
+        return parent.getFontData(symbolicName);
+    }
+
+    @Override
+	public boolean hasValueFor(String colorKey) {
+        return super.hasValueFor(colorKey) || parent.hasValueFor(colorKey);
+    }
+
+    /**
+     * Returns whether this cascading registry has an override for the provided
+     * color key.
+     *
+     * @param fontKey the provided color key
+     * @return hether this cascading registry has an override
+     */
+    public boolean hasOverrideFor(String fontKey) {
+        return super.hasValueFor(fontKey);
+    }
+
+    /**
+     * Disposes of all allocated resources.
+     */
+    public void dispose() {
+        parent.removeListener(listener);
+        PlatformUI.getWorkbench().getDisplay().asyncExec(displayRunnable);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/CascadingMap.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/CascadingMap.java
new file mode 100644
index 0000000..c4dd938
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/CascadingMap.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.themes;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @since 3.0
+ */
+public class CascadingMap {
+
+    private Map base, override;
+
+    /**
+     * @param base the base (default) map
+     * @param override the override map
+     */
+    public CascadingMap(Map base, Map override) {
+        this.base = base;
+        this.override = override;
+    }
+
+    /**
+     * Return the union of the parent and child key sets.
+     *
+     * @return the union.  This set is read only.
+     */
+    public Set keySet() {
+        Set keySet = new HashSet(base.keySet());
+        keySet.addAll(override.keySet());
+        return Collections.unmodifiableSet(keySet);
+    }
+
+    /**
+     * Get the value.  Preference will be given to entries in the override map.
+     *
+     * @param key the key
+     * @return the value
+     */
+    public Object get(Object key) {
+        if (override.containsKey(key)) {
+			return override.get(key);
+		}
+        return base.get(key);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/CascadingTheme.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/CascadingTheme.java
new file mode 100644
index 0000000..b5c4cc5
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/CascadingTheme.java
@@ -0,0 +1,114 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.themes;
+
+import java.util.Set;
+import org.eclipse.core.commands.common.EventManager;
+import org.eclipse.jface.resource.ColorRegistry;
+import org.eclipse.jface.resource.FontRegistry;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.ui.themes.ITheme;
+
+/**
+ * @since 3.0
+ */
+public class CascadingTheme extends EventManager implements ITheme {
+
+    private CascadingFontRegistry fontRegistry;
+
+    private CascadingColorRegistry colorRegistry;
+
+    private ITheme currentTheme;
+
+    private IPropertyChangeListener listener = event -> fire(event);
+
+    /**
+     * @param colorRegistry
+     * @param fontRegistry
+     */
+    public CascadingTheme(ITheme currentTheme,
+            CascadingColorRegistry colorRegistry,
+            CascadingFontRegistry fontRegistry) {
+        this.currentTheme = currentTheme;
+        this.colorRegistry = colorRegistry;
+        this.fontRegistry = fontRegistry;
+
+        fontRegistry.addListener(listener);
+        colorRegistry.addListener(listener);
+    }
+
+    /**
+     * @param event
+     */
+    protected void fire(PropertyChangeEvent event) {
+		for (Object listener : getListeners()) {
+			((IPropertyChangeListener) listener).propertyChange(event);
+        }
+    }
+
+    @Override
+	public void addPropertyChangeListener(IPropertyChangeListener listener) {
+        addListenerObject(listener);
+    }
+
+    @Override
+	public void removePropertyChangeListener(IPropertyChangeListener listener) {
+        removeListenerObject(listener);
+    }
+
+    @Override
+	public String getId() {
+        return currentTheme.getId();
+    }
+
+    @Override
+	public String getLabel() {
+        return currentTheme.getLabel();
+    }
+
+    @Override
+	public ColorRegistry getColorRegistry() {
+        return colorRegistry;
+    }
+
+    @Override
+	public FontRegistry getFontRegistry() {
+        return fontRegistry;
+    }
+
+    @Override
+	public void dispose() {
+        colorRegistry.removeListener(listener);
+        fontRegistry.removeListener(listener);
+    }
+
+    @Override
+	public String getString(String key) {
+        return currentTheme.getString(key);
+    }
+
+    @Override
+	public int getInt(String key) {
+        return currentTheme.getInt(key);
+    }
+
+    @Override
+	public boolean getBoolean(String key) {
+        return currentTheme.getBoolean(key);
+    }
+
+    @Override
+	public Set keySet() {
+        return currentTheme.keySet();
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/ColorDefinition.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/ColorDefinition.java
new file mode 100644
index 0000000..0e4b5f7
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/ColorDefinition.java
@@ -0,0 +1,159 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.internal.themes;
+
+import org.eclipse.core.runtime.IStatus;
+//import org.eclipse.e4.ui.internal.css.swt.definition.IColorDefinitionOverridable;
+import org.eclipse.jface.resource.DataFormatException;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.ui.IPluginContribution;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.statushandlers.StatusManager;
+import org.eclipse.ui.themes.ColorUtil;
+
+/**
+ * A <code>ColorDefiniton </code> is the representation of the extensions
+ * defined by the <code>org.eclipse.ui.colorDefinitions</code> extension point.
+ *
+ *  @since 3.0
+ */
+public class ColorDefinition extends ThemeElementDefinition implements IPluginContribution,
+		IHierarchalThemeElementDefinition, ICategorizedThemeElementDefinition, IEditable
+//		,IColorDefinitionOverridable 
+		{
+	/**
+	 * Default color value - black - for colors that cannot be parsed.
+	 */
+    private static final RGB DEFAULT_COLOR_VALUE = new RGB(0,0,0);
+
+	private String defaultsTo;
+
+    private String pluginId;
+
+    private String rawValue;
+
+    boolean isEditable;
+
+    private RGB parsedValue;
+
+    /**
+     * Create a new instance of the receiver.
+     *
+     * @param label the label for this definition
+     * @param id the identifier for this definition
+     * @param defaultsTo the id of a definition that this definition will
+     * 		default to.
+     * @param value the default value of this definition, either in the form
+     * rrr,ggg,bbb or the name of an SWT color constant.
+     * @param description the description for this definition.
+     * @param pluginId the identifier of the plugin that contributed this
+     * 		definition.
+     */
+    public ColorDefinition(String label, String id, String defaultsTo,
+            String value, String categoryId, boolean isEditable,
+            String description, String pluginId) {
+		super(id, label, description, categoryId);
+        this.defaultsTo = defaultsTo;
+        this.rawValue = value;
+        this.isEditable = isEditable;
+        this.pluginId = pluginId;
+    }
+
+    /**
+     * Create a new instance of the receiver.
+     *
+     * @param original the original definition.  This will be used to populate
+     * all fields except defaultsTo and value.  defaultsTo will always be
+     * <code>null</code>.
+     * @param value the RGB value
+     */
+    public ColorDefinition(ColorDefinition original, RGB value) {
+		super(original.getId(), original.getName(), original.getDescription(), original
+				.getCategoryId());
+        this.isEditable = original.isEditable();
+        this.pluginId = original.getPluginId();
+        this.parsedValue = value;
+    }
+
+    /**
+     * @return the defaultsTo value, or <code>null</code> if none was supplied.
+     */
+    @Override
+	public String getDefaultsTo() {
+        return defaultsTo;
+    }
+
+    @Override
+	public String getLocalId() {
+        return getId();
+    }
+
+    @Override
+	public String getPluginId() {
+        return pluginId;
+    }
+
+    /**
+     * @return the value. Any SWT constants  supplied to the constructor will be
+     * evaluated and converted into their RGB value.
+     */
+//    @Override
+	public RGB getValue() {
+        if (parsedValue == null) {
+			try {
+				parsedValue = ColorUtil.getColorValue(rawValue);
+			} catch (DataFormatException e) {
+				parsedValue = DEFAULT_COLOR_VALUE;
+				IStatus status = StatusUtil.newStatus(IStatus.WARNING,
+						"Could not parse value for theme color " + getId(), e); //$NON-NLS-1$
+				StatusManager.getManager().handle(status, StatusManager.LOG);
+			}
+		}
+        return parsedValue;
+    }
+
+	@Override
+	public void resetToDefaultValue() {
+		parsedValue = null;
+		super.resetToDefaultValue();
+	}
+
+    @Override
+	public String toString() {
+        return getId();
+    }
+
+    @Override
+	public boolean isEditable() {
+        return isEditable;
+    }
+
+    @Override
+	public boolean equals(Object obj) {
+        if (obj instanceof ColorDefinition) {
+            return getId().equals(((ColorDefinition)obj).getId());
+        }
+        return false;
+    }
+
+    @Override
+	public int hashCode() {
+		return getId().hashCode();
+    }
+
+//	@Override
+	public void setValue(RGB data) {
+		if (data != null) {
+			parsedValue = data;
+			appendState(State.OVERRIDDEN);
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/ColorsAndFontsPreferencePage.properties b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/ColorsAndFontsPreferencePage.properties
new file mode 100644
index 0000000..c882264
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/ColorsAndFontsPreferencePage.properties
@@ -0,0 +1,34 @@
+###############################################################################
+# Copyright (c) 2003, 2014, 2015 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
+#     Robert Roth <robert.roth.off@gmail.com> - Bug 274005
+###############################################################################
+
+openChange=&Edit...
+reset=&Reset
+editDefault=Ed&it Default...
+goToDefault=&Go to Default
+expandAll=E&xpand All
+value=&Value
+colorsAndFonts=Colors and &Fonts (? = any character, * = any string):
+description=Descriptio&n:
+preview=Previe&w:
+noPreviewAvailable=No preview available.
+errorCreatingPreview=There was an error creating this preview.  Please see your log for details.
+errorCreatePreviewLog=Error creating preview.
+errorDisposePreviewLog=Error disposing preview.
+defaultFormat_default={0} (set to default: {1})
+defaultFormat_override={0} (overrides default: {1})
+editParent=&Go to parent
+boldFont=Bold
+italicFont=Italic
+fontTextSample=The quick brown fox jumps over the lazy dog.
+fontColorSample=Sample text
+fontColorString=RGB({0}, {1}, {2})
+definitionNotAvailInTheme={0} (not available in the current theme)
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/FontDefinition.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/FontDefinition.java
new file mode 100644
index 0000000..6e3c93a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/FontDefinition.java
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.themes;
+
+//import org.eclipse.e4.ui.internal.css.swt.definition.IFontDefinitionOverridable;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.resource.StringConverter;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * The FontDefiniton is the representation of the fontDefinition
+ * from the plugin.xml of a type.
+ */
+public class FontDefinition extends ThemeElementDefinition implements
+		IHierarchalThemeElementDefinition, ICategorizedThemeElementDefinition, IEditable
+//		,
+//		IFontDefinitionOverridable 
+		{
+
+	private String defaultsTo;
+
+    private String value;
+
+	private String defaultValue;
+
+    private boolean isEditable;
+
+    private FontData[] parsedValue;
+
+    /**
+     * Create a new instance of the receiver.
+     *
+     * @param fontName The name display
+     * ed in the preference page.
+     * @param uniqueId The id used to refer to this definition.
+     * @param defaultsId The id of the font this defaults to.
+     * @param fontDescription The description of the font in the preference page.
+     */
+    public FontDefinition(String fontName, String uniqueId, String defaultsId,
+            String value, String categoryId, boolean isEditable,
+            String fontDescription) {
+		super(uniqueId, fontName, fontDescription, categoryId);
+        this.defaultsTo = defaultsId;
+        this.value = value;
+        this.isEditable = isEditable;
+    }
+
+    /**
+     * Create a new instance of the receiver.
+     *
+     * @param originalFont the original definition.  This will be used to populate
+     * all fields except defaultsTo and value.  defaultsTo will always be
+     * <code>null</code>.
+     * @param datas the FontData[] value
+     */
+    public FontDefinition(FontDefinition originalFont, FontData[] datas) {
+		super(originalFont.getId(), originalFont.getName(), originalFont.getDescription(),
+				originalFont.getCategoryId());
+        this.isEditable = originalFont.isEditable();
+        this.parsedValue = datas;
+    }
+
+    /**
+     * Returns the defaultsTo. This is the id of the text font
+     * that this font defualts to.
+     * @return String or <pre>null</pre>.
+     */
+    @Override
+	public String getDefaultsTo() {
+        return defaultsTo;
+    }
+
+    /**
+     * Returns the value.
+     *
+     * @return FontData []
+     */
+//    @Override
+	public FontData[] getValue() {
+        if (value == null) {
+			return null;
+		}
+        if (parsedValue == null) {
+            parsedValue = JFaceResources.getFontRegistry().filterData(
+                    StringConverter.asFontDataArray(value),
+                    PlatformUI.getWorkbench().getDisplay());
+        }
+
+        return parsedValue;
+    }
+
+	@Override
+	public void resetToDefaultValue() {
+		value = defaultValue;
+		parsedValue = null;
+		super.resetToDefaultValue();
+	}
+
+    @Override
+	public boolean isEditable() {
+        return isEditable;
+    }
+
+    @Override
+	public boolean equals(Object obj) {
+        if (obj instanceof FontDefinition) {
+            return getId().equals(((FontDefinition)obj).getId());
+        }
+        return false;
+    }
+
+    @Override
+	public int hashCode() {
+		return getId().hashCode();
+	}
+
+//	@Override
+	public void setValue(FontData[] data) {
+		if (data != null && data.length > 0) {
+			if (defaultValue == null) {
+				defaultValue = value;
+			}
+			value = data[0].getName();
+			parsedValue = data;
+			appendState(State.OVERRIDDEN);
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/ICategorizedThemeElementDefinition.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/ICategorizedThemeElementDefinition.java
new file mode 100644
index 0000000..e69f05d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/ICategorizedThemeElementDefinition.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.themes;
+
+/**
+ * A theme element that may belong to a category.
+ *
+ * @since 3.0
+ */
+public interface ICategorizedThemeElementDefinition extends
+        IThemeElementDefinition {
+
+    /**
+     * Returns the category of this element.
+     *
+     * @return the category of this element, or <code>null</code> if it does not belong to one.
+     */
+    String getCategoryId();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/IEditable.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/IEditable.java
new file mode 100644
index 0000000..22b1e62
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/IEditable.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.themes;
+
+/**
+ * Theme elements which may potentially be editted by the user should implement
+ * this interface.
+ *
+ * @since 3.0
+ */
+public interface IEditable {
+
+    /**
+     * Returns whether this object is editable.
+     *
+     * @return whether this object is editable.
+     */
+    public boolean isEditable();
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/IHierarchalThemeElementDefinition.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/IHierarchalThemeElementDefinition.java
new file mode 100644
index 0000000..34eb8ca
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/IHierarchalThemeElementDefinition.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.themes;
+
+/**
+ * A theme element whose value may default to that of another theme element.
+ *
+ * @since 3.0
+ */
+public interface IHierarchalThemeElementDefinition extends
+        IThemeElementDefinition {
+
+    /**
+     * Return the id of the element this element defaults to.
+     *
+     * @return the id of the element this element defaults to, or
+     * <code>null</code> if it does not default to another element.
+     */
+    String getDefaultsTo();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/IThemeDescriptor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/IThemeDescriptor.java
new file mode 100644
index 0000000..5f25805
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/IThemeDescriptor.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.themes;
+
+import java.util.Map;
+
+/**
+ * Interface for the Theme descriptors
+ *
+ * @since 3.0
+ */
+public interface IThemeDescriptor extends IThemeElementDefinition {
+    public static final String TAB_BORDER_STYLE = "TAB_BORDER_STYLE"; //$NON-NLS-1$
+
+    /**
+     * Returns the color overrides for this theme.
+     * @return ColorDefinition []
+     */
+    public ColorDefinition[] getColors();
+
+    /**
+     * Returns the font overrides for this theme.
+     * @return GradientDefinition []
+     */
+    public FontDefinition[] getFonts();
+
+    /**
+     * Returns the data map for this theme.
+     *
+     * @return the data map.  This will be read only.
+     */
+    public Map getData();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/IThemeElementDefinition.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/IThemeElementDefinition.java
new file mode 100644
index 0000000..97243f7
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/IThemeElementDefinition.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.themes;
+
+/**
+ * A basic element (color, font) of a theme must implement this
+ * interface.
+ *
+ * @since 3.0
+ */
+public interface IThemeElementDefinition {
+
+    /**
+     * Returns the name for this element.
+     *
+     * @return the name for this element
+     */
+    public String getName();
+
+    /**
+     * Returns the id for this element.
+     *
+     * @return the id for this element.  This will never be <code>null</code>.
+     */
+    public String getId();
+
+    /**
+     * Returns the description for this element.
+     *
+     * @return the description for this element.  This may be <code>null</code>.
+     */
+    public String getDescription();
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/IThemeRegistry.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/IThemeRegistry.java
new file mode 100644
index 0000000..814b9c4
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/IThemeRegistry.java
@@ -0,0 +1,210 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.themes;
+
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Registry of color, font, gradient, category and theme descriptors.
+ *
+ * @since 3.0
+ */
+public interface IThemeRegistry {
+
+    /**
+     * A comparator that will sort IHierarchalThemeElementDefinition elements
+     * by defaultsTo depth.
+     *
+     * @since 3.0
+     */
+    public static class HierarchyComparator implements Comparator {
+
+        private IHierarchalThemeElementDefinition[] definitions;
+
+        /**
+         * Create a new comparator.
+         *
+         * @param definitions the elements to be sorted by depth, in ID order.
+         */
+        public HierarchyComparator(
+                IHierarchalThemeElementDefinition[] definitions) {
+            this.definitions = definitions;
+        }
+
+        @Override
+		public int compare(Object arg0, Object arg1) {
+            String def0 = arg0 == null ? null
+                    : ((IHierarchalThemeElementDefinition) arg0)
+                            .getDefaultsTo();
+            String def1 = arg1 == null ? null
+                    : ((IHierarchalThemeElementDefinition) arg1)
+                            .getDefaultsTo();
+
+            if (def0 == null && def1 == null) {
+				return 0;
+			}
+
+            if (def0 == null) {
+				return -1;
+			}
+
+            if (def1 == null) {
+				return 1;
+			}
+
+            return compare(getDefaultsTo(def0), getDefaultsTo(def1));
+        }
+
+        /**
+         * @param id the identifier to search for.
+         * @return the <code>IHierarchalThemeElementDefinition</code> that
+         * matches the id.
+         */
+        private IHierarchalThemeElementDefinition getDefaultsTo(String id) {
+            int idx = Arrays.binarySearch(definitions, id, ID_COMPARATOR);
+            if (idx >= 0) {
+				return definitions[idx];
+			}
+            return null;
+        }
+    }
+
+    /**
+     * A comparator that will sort <code>IThemeElementDefinition</code> elements
+     * by id depth.  You may use this on both <code>String</code> and
+     * <code>IThemeElementDefinition</code> objects in order to perform
+     * searching.
+     *
+     * @since 3.0
+     */
+    public static final Comparator ID_COMPARATOR = new Comparator() {
+
+        @Override
+		public int compare(Object arg0, Object arg1) {
+            String str0 = getCompareString(arg0);
+            String str1 = getCompareString(arg1);
+            return str0.compareTo(str1);
+        }
+
+        /**
+         * @param object
+         * @return <code>String</code> representation of the object.
+         */
+        private String getCompareString(Object object) {
+            if (object instanceof String) {
+				return (String) object;
+			} else if (object instanceof IThemeElementDefinition) {
+				return ((IThemeElementDefinition) object).getId();
+			}
+            return ""; //$NON-NLS-1$
+        }
+    };
+
+    /**
+     * Returns the category matching the provided id.
+     *
+     * @param id the id to search for
+     * @return the element matching the provided id, or <code>null</code> if
+     * not found
+     */
+    public ThemeElementCategory findCategory(String id);
+
+    /**
+     * Returns the color matching the provided id.
+     *
+     * @param id the id to search for
+     * @return the element matching the provided id, or <code>null</code> if
+     * not found
+     */
+    public ColorDefinition findColor(String id);
+
+    /**
+     * Returns the font matching the provided id.
+     *
+     * @param id the id to search for
+     * @return the element matching the provided id, or <code>null</code> if
+     * not found
+     */
+    public FontDefinition findFont(String id);
+
+    /**
+     *  Returns the theme matching the provided id.
+     *
+     * @param id the id to search for
+     * @return the element matching the provided id, or <code>null</code> if
+     * not found
+     */
+    public IThemeDescriptor findTheme(String id);
+
+    /**
+     * Returns a list of categories defined in the registry.
+     *
+     * @return the categories in this registry
+     */
+    public ThemeElementCategory[] getCategories();
+
+    /**
+     * Returns a list of colors defined in the registry.
+     *
+     * @return the colors in this registry
+     */
+    public ColorDefinition[] getColors();
+
+    /**
+     * Returns a list of colors defined for the given theme.  This is the
+     * set of base colours overlayed with any theme specific overrides.
+     *
+     * @param themeId the theme id
+     * @return the colors in this theme
+     */
+    public ColorDefinition[] getColorsFor(String themeId);
+
+    /**
+     * Returns a list of fonts defined for the given theme.  This is the
+     * set of base fonts overlayed with any theme specific overrides.
+     *
+     * @param themeId the theme id
+     * @return the fonts in this theme
+     */
+    public FontDefinition[] getFontsFor(String themeId);
+
+    /**
+     * Returns a list of fonts defined in the registry.
+     *
+     * @return the fonts in this registry
+     */
+    public FontDefinition[] getFonts();
+
+    /**
+     * Returns a list of themes defined in the registry.
+     *
+     * @return the themes in this registry
+     */
+    public IThemeDescriptor[] getThemes();
+
+    /**
+     * Return the data map.
+     *
+     * @return the data map
+     */
+    public Map getData();
+
+    /**
+     * Return the set of category presentation bindings.
+     *
+     * @param category the category to test
+     * @return the set of bindings or <code>null</code> if this category has no bindings
+     */
+    public Set getPresentationsBindingsFor(ThemeElementCategory category);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/LightColorFactory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/LightColorFactory.java
new file mode 100644
index 0000000..de04e18
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/LightColorFactory.java
@@ -0,0 +1,165 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal.themes;
+
+import java.util.Hashtable;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExecutableExtension;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.themes.ColorUtil;
+import org.eclipse.ui.themes.IColorFactory;
+
+/**
+ * LightColorFactory returns tab begin and end colours based on taking
+ * a system color as input, analyzing it, and lightening it appropriately.
+ *
+ * @since 3.3
+ *
+ */
+public class LightColorFactory implements IColorFactory,
+		IExecutableExtension {
+
+	protected static final RGB white = ColorUtil.getColorValue("COLOR_WHITE"); //$NON-NLS-1$
+	protected static final RGB black = ColorUtil.getColorValue("COLOR_BLACK"); //$NON-NLS-1$
+
+	String baseColorName;
+	String definitionId;
+
+	/**
+	 * Return the highlight start (top of tab) color as an RGB
+	 * @return the highlight start RGB
+	 */
+
+	public static RGB createHighlightStartColor(RGB tabStartColor) {
+		return ColorUtil.blend(white, tabStartColor);
+	}
+
+	/**
+	 * This executable extension requires parameters to be explicitly declared
+	 * via the second method described in the <code>IExecutableExtension</code>
+	 * documentation. The following parameters are parsed:
+	 * <code>base</code>, describes the base color to produce all other colours from.
+	 * This value may either be an RGB triple or an SWT constant.
+	 * <code>definitionId</code>, describes the id of color we are looking for, one of
+	 * "org.eclipse.ui.workbench.ACTIVE_TAB_BG_START"
+	 * "org.eclipse.ui.workbench.ACTIVE_TAB_BG_END"
+	 * @see org.eclipse.core.runtime.IExecutableExtension#setInitializationData(org.eclipse.core.runtime.IConfigurationElement,
+	 *      java.lang.String, java.lang.Object)
+	 */
+	@Override
+	public void setInitializationData(IConfigurationElement config,
+			String propertyName, Object data) {
+
+		if (data instanceof Hashtable) {
+			Hashtable table = (Hashtable) data;
+			baseColorName = (String) table.get("base"); //$NON-NLS-1$
+			definitionId = (String) table.get("definitionId"); //$NON-NLS-1$
+		}
+	}
+
+	/*
+	 * Return the number of RGB values in test that are
+	 * equal to or between lower and upper.
+	 */
+	protected int valuesInRange(RGB test, int lower, int upper) {
+		int hits = 0;
+		if(test.red >= lower && test.red <= upper) hits++;
+		if(test.blue >= lower && test.blue <= upper) hits++;
+		if(test.green >= lower && test.green <= upper) hits++;
+
+		return hits;
+	}
+
+	/*
+	 * Return the RGB value for the bottom tab color
+	 * based on a blend of white and sample color
+	 */
+	private RGB getLightenedColor(RGB sample) {
+		//Group 1
+		if(valuesInRange(sample, 180, 255) >= 2)
+			return sample;
+
+		//Group 2
+		if(valuesInRange(sample, 100, 179) >= 2)
+			return ColorUtil.blend(white, sample, 40);
+
+		//Group 3
+		if(valuesInRange(sample, 0, 99) >= 2)
+			return ColorUtil.blend(white, sample, 60);
+
+		//Group 4
+		return ColorUtil.blend(white, sample, 30);
+	}
+
+	/*
+	 * Return the Start (top of tab) color as an RGB
+	 */
+	private RGB getActiveFocusStartColor() {
+		if (Display.getCurrent().getDepth() < 15)
+				return getActiveFocusEndColor();
+
+		RGB startColor = ColorUtil.blend(white, getActiveFocusEndColor(), 75);
+		return startColor;
+	}
+
+	/*
+	 * Return the End (top of tab) color as an RGB
+	 */
+	private RGB getActiveFocusEndColor() {
+		if (Display.getCurrent().getDepth() < 15)
+			return ColorUtil.getColorValue(baseColorName);
+
+		return getLightenedColor(
+				ColorUtil.getColorValue(baseColorName));
+	}
+
+	/*
+	 * Return the active focus tab text color as an RGB
+	 */
+	private RGB getActiveFocusTextColor() {
+		if (Display.getCurrent().getDepth() < 15)
+			return ColorUtil.getColorValue(baseColorName);  //typically TITLE_FOREGROUND
+
+		return ColorUtil.getColorValue("COLOR_BLACK"); //$NON-NLS-1$
+	}
+	/*
+	 * Return the RGB value for the top tab color.
+	 */
+	private RGB getActiveNofocusStartColor() {
+		RGB base = ColorUtil.getColorValue(baseColorName);
+		if (Display.getCurrent().getDepth() < 15)
+			return base;
+
+		return ColorUtil.blend(white, base, 40);
+	}
+
+	@Override
+	public RGB createColor() {
+		//should have base, otherwise error in the xml
+		if (baseColorName == null || definitionId == null)
+			return white;
+
+		if (definitionId.equals("org.eclipse.ui.workbench.ACTIVE_TAB_BG_START")) //$NON-NLS-1$
+			return getActiveFocusStartColor();
+		if (definitionId.equals("org.eclipse.ui.workbench.ACTIVE_TAB_BG_END")) //$NON-NLS-1$
+			return getActiveFocusEndColor();
+		if (definitionId.equals("org.eclipse.ui.workbench.ACTIVE_TAB_TEXT_COLOR")) //$NON-NLS-1$
+			return getActiveFocusTextColor();
+		if (definitionId.equals("org.eclipse.ui.workbench.ACTIVE_NOFOCUS_TAB_BG_START")) //$NON-NLS-1$
+			return getActiveNofocusStartColor();
+
+		//should be one of start or end, otherwise error in the xml
+		return white;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/RGBBrightnessColorFactory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/RGBBrightnessColorFactory.java
new file mode 100644
index 0000000..dedfa3a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/RGBBrightnessColorFactory.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2013, 2015 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.ui.internal.themes;
+
+import java.util.Hashtable;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExecutableExtension;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.ui.themes.ColorUtil;
+import org.eclipse.ui.themes.IColorFactory;
+
+/**
+ * @since 3.105
+ *
+ */
+public class RGBBrightnessColorFactory implements IColorFactory, IExecutableExtension {
+
+	String color, scaleFactor;
+
+	@Override
+	public RGB createColor() {
+		RGB rgb = ColorUtil.getColorValue(color);
+		float scale = Float.parseFloat(scaleFactor);
+		float[] hsb = rgb.getHSB();
+		float b = hsb[2] * scale;
+		if (b < 0)
+			b = 0;
+		if (b > 1)
+			b = 1;
+		return new RGB(hsb[0], hsb[1], b);
+	}
+
+	/**
+	 * This executable extension requires parameters to be explicitly declared
+	 * via the second method described in the <code>IExecutableExtension</code>
+	 * documentation. This class expects that there will be two parameters,
+	 * <code>color</code> that describe the color to be blended (this values may
+	 * either be RGB triples or SWT constants) and <code>scaleFactor</code>
+	 * which is the brightness scale factor with 1.0 having the same brightness
+	 * as the original color.
+	 *
+	 * @see org.eclipse.core.runtime.IExecutableExtension#setInitializationData(org.eclipse.core.runtime.IConfigurationElement,
+	 *      java.lang.String, java.lang.Object)
+	 */
+	@Override
+	public void setInitializationData(IConfigurationElement config, String propertyName, Object data)
+			throws CoreException {
+		if (data instanceof Hashtable) {
+			Hashtable table = (Hashtable) data;
+			color = (String) table.get("color"); //$NON-NLS-1$
+			scaleFactor = (String) table.get("scaleFactor"); //$NON-NLS-1$
+		}
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/RGBContrastFactory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/RGBContrastFactory.java
new file mode 100644
index 0000000..28c3b3f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/RGBContrastFactory.java
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.themes;
+
+import java.util.Hashtable;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExecutableExtension;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.ui.themes.ColorUtil;
+import org.eclipse.ui.themes.IColorFactory;
+
+/**
+ * A <code>IColorFactory</code> that may be used to select a colour with
+ * a higher contrast.  The colors to blend are specified as per method
+ * number two in  {@link org.eclipse.core.runtime.IExecutableExtension}.
+ * <p>
+ * Example usage:
+ * <br/>
+ * <code>
+ * &lt;colorDefinition
+ *     label="Red/Blue Contrast"
+ *     id="example.redblueblend"&gt;
+ *     &lt;colorFactory
+ * 				plugin="org.eclipse.ui"
+ * 				class="org.eclipse.ui.internal.themes.RGBContrastFactory"&gt;
+ *      	&lt;parameter name="foreground" value="0,0,0" /&gt;
+ *  		&lt;parameter name="background1" value="COLOR_RED" /&gt;
+ *          &lt;parameter name="background2" value="COLOR_BLUE" /&gt;
+ *     &lt;/colorFactory&gt;
+ * &lt;/colorDefinition&gt;
+ * </code>
+ * </p>
+ *
+ * <p>
+ * This will select whichever of Red or Blue has a higher contrst with black.
+ * The color values may be specified as RGB triples or as SWT constants.
+ * </p>
+ *
+ * @see org.eclipse.swt.SWT
+ * @since 3.0
+ */
+public class RGBContrastFactory implements IColorFactory, IExecutableExtension {
+    private String fg, bg1, bg2;
+
+    /**
+     * Returns the intensity of an RGB component using the
+     * sRGB gamma function.
+     *
+     * @param val Value to convert.
+     * @return Light intensity of the component.
+     */
+    double voltage_to_intensity_srgb(double val) {
+        /* Handle invalid values before doing a gamma transform. */
+        if (val < 0.0) {
+			return 0.0;
+		}
+        if (val > 1.0) {
+			return 1.0;
+		}
+
+        if (val <= 0.04045) {
+            return val / 12.92;
+        }
+        return Math.pow((val + 0.055) / 1.055, 2.4);
+    }
+
+    /**
+     * Returns a measure of the lightness in the perceptual colourspace
+     * IPT.
+     *
+     * @param color The colour in sRGB
+     * @return Lightness in IPT space.
+     */
+    double lightness(RGB color) {
+        double r = voltage_to_intensity_srgb(color.red / 255.0);
+        double g = voltage_to_intensity_srgb(color.green / 255.0);
+        double b = voltage_to_intensity_srgb(color.blue / 255.0);
+        double l = (0.3139 * r) + (0.6395 * g) + (0.0466 * b);
+        double m = (0.1516 * r) + (0.7482 * g) + (0.1000 * b);
+        double s = (0.0177 * r) + (0.1095 * g) + (0.8729 * b);
+        double lp, mp, sp;
+
+        if (l < 0.0) {
+			lp = -Math.pow(-l, 0.43);
+		} else {
+			lp = Math.pow(l, 0.43);
+		}
+        if (m < 0.0) {
+			mp = -Math.pow(-m, 0.43);
+		} else {
+			mp = Math.pow(m, 0.43);
+		}
+        if (s < 0.0) {
+			sp = -Math.pow(-s, 0.43);
+		} else {
+			sp = Math.pow(s, 0.43);
+		}
+
+        return (0.4000 * lp) + (0.4000 * mp) + (0.2000 * sp);
+    }
+
+    @Override
+	public RGB createColor() {
+        /**
+         * Determine which pair has a higher contrast by selecting
+         * the colour with the furthest distance in lightness.
+         */
+        RGB cfg, cbg1, cbg2;
+
+        if (fg != null) {
+            cfg = ColorUtil.getColorValue(fg);
+        } else {
+            cfg = new RGB(255, 255, 255);
+        }
+        if (bg1 != null) {
+            cbg1 = ColorUtil.getColorValue(bg1);
+        } else {
+            cbg1 = new RGB(0, 0, 0);
+        }
+        if (bg2 != null) {
+            cbg2 = ColorUtil.getColorValue(bg2);
+        } else {
+            cbg2 = new RGB(0, 0, 0);
+        }
+
+        double lfg = lightness(cfg);
+        double lbg1 = lightness(cbg1);
+        double lbg2 = lightness(cbg2);
+
+        if (Math.abs(lbg1 - lfg) > Math.abs(lbg2 - lfg)) {
+            return cbg1;
+        } else {
+            return cbg2;
+        }
+    }
+
+    /**
+     * This executable extension requires parameters to be explicitly declared
+     * via the second method described in the <code>IExecutableExtension</code>
+     * documentation.  This class expects that there will be three parameters,
+     * <code>foreground</code>, <code>background1</code> and
+     * <code>background2</code>, that describe the two colors to be blended.
+     * These values may either be RGB triples or SWT constants.
+     *
+     * @see org.eclipse.core.runtime.IExecutableExtension#setInitializationData(org.eclipse.core.runtime.IConfigurationElement, java.lang.String, java.lang.Object)
+     */
+    @Override
+	public void setInitializationData(IConfigurationElement config,
+            String propertyName, Object data) throws CoreException {
+        if (data instanceof Hashtable) {
+            Hashtable table = (Hashtable) data;
+            fg = (String) table.get("foreground"); //$NON-NLS-1$
+            bg1 = (String) table.get("background1"); //$NON-NLS-1$
+            bg2 = (String) table.get("background2"); //$NON-NLS-1$
+        }
+
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/RGBInfoColorFactory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/RGBInfoColorFactory.java
new file mode 100644
index 0000000..9e6ba9c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/RGBInfoColorFactory.java
@@ -0,0 +1,62 @@
+package org.eclipse.ui.internal.themes;
+
+import java.util.Hashtable;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExecutableExtension;
+import org.eclipse.jface.util.Util;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.ui.themes.ColorUtil;
+import org.eclipse.ui.themes.IColorFactory;
+
+/**
+ * Used in org.eclipse.ui.themes extension point of the org.eclipse.ui plug-in
+ * for the color definition org.eclipse.ui.workbench.HOVER_BACKGROUND and
+ * org.eclipse.ui.workbench.HOVER_FOREGROUND
+ */
+public class RGBInfoColorFactory implements IColorFactory, IExecutableExtension {
+	String color;
+
+	@Override
+	public RGB createColor() {
+		RGB rgb = new RGB(0, 0, 0); // IColorFactory must return a valid color
+
+		if (color == null) {
+			return rgb;
+		}
+		/**
+		 * Starting with ~Gnome 3.06, COLOR_INFO_BACKGROUND and
+		 * COLOR_INFO_FOREGROUND are inverted, often producing hoverboxes with
+		 * black background with white text on an otherwise white background and
+		 * black text. However, on Windows/Cocoa COLOR_INFO_* looks ok. Solution
+		 * is to generate a different color based on platform.
+		 */
+		if (Util.isGtk()) {
+			switch (color) {
+			case "foreground": //$NON-NLS-1$
+				rgb = ColorUtil.getColorValue("COLOR_LIST_FOREGROUND"); //$NON-NLS-1$
+				break;
+			case "background": //$NON-NLS-1$
+				rgb = ColorUtil.getColorValue("COLOR_LIST_BACKGROUND"); //$NON-NLS-1$
+				break;
+			}
+		} else {
+			switch (color) {
+			case "foreground": //$NON-NLS-1$
+				rgb = ColorUtil.getColorValue("COLOR_INFO_FOREGROUND"); //$NON-NLS-1$
+				break;
+			case "background": //$NON-NLS-1$
+				rgb = ColorUtil.getColorValue("COLOR_INFO_BACKGROUND");  //$NON-NLS-1$
+				break;
+			}
+		}
+		return rgb;
+	}
+
+	@Override
+	public void setInitializationData(IConfigurationElement config, String propertyName, Object data) {
+		if (data instanceof Hashtable<?, ?>) {
+			Hashtable<?, ?> map = (Hashtable<?, ?>) data;
+			color = (String) map.get("color"); //$NON-NLS-1$
+		}
+	}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/RGBVisibleContrastColorFactory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/RGBVisibleContrastColorFactory.java
new file mode 100644
index 0000000..60184ca
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/RGBVisibleContrastColorFactory.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.themes;
+
+import java.util.Hashtable;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExecutableExtension;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.ui.themes.ColorUtil;
+import org.eclipse.ui.themes.IColorFactory;
+
+/**
+ * A <code>IColorFactory</code> that may be used to select a color with a higher
+ * contrast. The input colors are specified as per method number two in
+ * {@link org.eclipse.core.runtime.IExecutableExtension}.
+ * <p>
+ * Example usage:
+ *
+ * <pre>
+ * &lt;colorDefinition
+ *     label="Declaration view background"
+ *     id="org.eclipse.jdt.ui.DeclarationView.backgroundColor"&gt;
+ *     &lt;colorFactory
+ *             plugin="org.eclipse.ui"
+ *             class="org.eclipse.ui.internal.themes.RGBContrastFactory"&gt;
+ *         &lt;parameter name="foreground" value="0,0,0" /&gt;
+ *         &lt;parameter name="background" value="COLOR_INFO_BACKGROUND" /&gt;
+ *         &lt;parameter name="alternativeBackground" value="COLOR_LIST_BACKGROUND" /&gt;
+ *     &lt;/colorFactory&gt;
+ * &lt;/colorDefinition&gt;
+ * </pre>
+ *
+ * <p>
+ * Returns <em>background</em> if <em>foreground</em> is visibly distinct from
+ * <em>background</em>. Otherwise, returns <em>alternativeBackground</em> if
+ * that color has more difference in brightness to the foreground. If both
+ * colors are bad, returns <em>background</em>. The color values may be
+ * specified as RGB triples or as SWT constants.
+ *
+ * @see org.eclipse.swt.SWT
+ * @since 3.107.100
+ */
+// This class is used by org.eclipse.jdt.ui/plugin.xml to fix
+// https://bugs.eclipse.org/477487
+public class RGBVisibleContrastColorFactory implements IColorFactory, IExecutableExtension {
+	private String fg, bg, altBg;
+
+	@Override
+	public RGB createColor() {
+		RGB cfg, cbg, cbgAlt;
+
+		if (fg != null) {
+			cfg = ColorUtil.getColorValue(fg);
+		} else {
+			cfg = new RGB(0, 0, 0);
+		}
+		if (bg != null) {
+			cbg = ColorUtil.getColorValue(bg);
+		} else {
+			cbg = new RGB(255, 255, 255);
+		}
+		if (altBg != null) {
+			cbgAlt = ColorUtil.getColorValue(altBg);
+		} else {
+			cbgAlt = new RGB(255, 255, 255);
+		}
+
+		float bfg = cfg.getHSB()[2];
+		float bbg = cbg.getHSB()[2];
+		float bbgAlt = cbgAlt.getHSB()[2];
+
+		if (Math.abs(bbg - bfg) < 0.5f && Math.abs(bbgAlt - bfg) > Math.abs(bbg - bfg)) {
+			return cbgAlt;
+		}
+		return cbg;
+	}
+
+	/**
+	 * This executable extension requires parameters to be explicitly declared
+	 * via the second method described in the <code>IExecutableExtension</code>
+	 * documentation. This class expects that there will be three parameters,
+	 * <code>foreground</code>, <code>background</code> and
+	 * <code>alternativeBackground</code>. These values may either be RGB
+	 * triples or SWT constants.
+	 */
+	@Override
+	public void setInitializationData(IConfigurationElement config, String propertyName, Object data)
+			throws CoreException {
+		if (data instanceof Hashtable) {
+			@SuppressWarnings("unchecked")
+			Hashtable<String, String> table = (Hashtable<String, String>) data;
+			fg = table.get("foreground"); //$NON-NLS-1$
+			bg = table.get("background"); //$NON-NLS-1$
+			altBg = table.get("alternativeBackground"); //$NON-NLS-1$
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/Theme.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/Theme.java
new file mode 100644
index 0000000..ea49cc9
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/Theme.java
@@ -0,0 +1,303 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.themes;
+
+import java.util.ResourceBundle;
+import java.util.Set;
+
+import org.eclipse.core.commands.common.EventManager;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.PreferenceConverter;
+import org.eclipse.jface.resource.ColorRegistry;
+import org.eclipse.jface.resource.DataFormatException;
+import org.eclipse.jface.resource.FontRegistry;
+import org.eclipse.jface.resource.StringConverter;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferenceConstants;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.util.PrefUtil;
+import org.eclipse.ui.internal.util.Util;
+import org.eclipse.ui.themes.ITheme;
+import org.eclipse.ui.themes.IThemeManager;
+
+/**
+ * @since 3.0
+ */
+public class Theme extends EventManager implements ITheme {
+
+    /**
+     * The translation bundle in which to look up internationalized text.
+     */
+    private final static ResourceBundle RESOURCE_BUNDLE = ResourceBundle
+            .getBundle(Theme.class.getName());
+
+    private CascadingColorRegistry themeColorRegistry;
+
+    private CascadingFontRegistry themeFontRegistry;
+
+    private IThemeDescriptor descriptor;
+
+    private IPropertyChangeListener themeListener;
+
+    private CascadingMap dataMap;
+
+    private ThemeRegistry themeRegistry;
+
+    private IPropertyChangeListener propertyListener;
+
+    /**
+     * @param descriptor
+     */
+    public Theme(IThemeDescriptor descriptor) {
+        themeRegistry = ((ThemeRegistry) WorkbenchPlugin.getDefault()
+                .getThemeRegistry());
+        this.descriptor = descriptor;
+        IWorkbench workbench = PlatformUI.getWorkbench();
+        if (descriptor != null) {
+        	ITheme defaultTheme = workbench.getThemeManager().getTheme(
+                    IThemeManager.DEFAULT_THEME);
+
+            ColorDefinition[] colorDefinitions = this.descriptor.getColors();
+            themeColorRegistry = new CascadingColorRegistry(defaultTheme
+                    .getColorRegistry());
+            if (colorDefinitions.length > 0) {
+//                ThemeElementHelper.populateRegistry(this, colorDefinitions,
+//                		PrefUtil.getInternalPreferenceStore());
+            }
+
+            FontDefinition[] fontDefinitions = this.descriptor.getFonts();
+            themeFontRegistry = new CascadingFontRegistry(defaultTheme
+                    .getFontRegistry());
+            if (fontDefinitions.length > 0) {
+//                ThemeElementHelper.populateRegistry(this, fontDefinitions,
+//                		PrefUtil.getInternalPreferenceStore());
+            }
+
+            dataMap = new CascadingMap(((ThemeRegistry) WorkbenchPlugin
+                    .getDefault().getThemeRegistry()).getData(), descriptor
+                    .getData());
+        }
+
+        getColorRegistry().addListener(getCascadeListener());
+        getFontRegistry().addListener(getCascadeListener());
+        PrefUtil.getInternalPreferenceStore().addPropertyChangeListener(
+                getPropertyListener());
+    }
+
+    /**
+     * Listener that is responsible for responding to preference changes.
+     *
+     * @return the property change listener
+     */
+    private IPropertyChangeListener getPropertyListener() {
+        if (propertyListener == null) {
+            propertyListener = new IPropertyChangeListener() {
+
+                @Override
+				public void propertyChange(PropertyChangeEvent event) {
+                    String[] split = ThemeElementHelper.splitPropertyName(
+                            Theme.this, event.getProperty());
+                    String key = split[1];
+                    String theme = split[0];
+                    if (key.equals(IWorkbenchPreferenceConstants.CURRENT_THEME_ID)) {
+						return;
+					}
+                    try {
+                    	String thisTheme = getId();
+
+                        if (Util.equals(thisTheme, theme)) {
+							if (getFontRegistry().hasValueFor(key)) {
+								FontData[] data = event.getNewValue() instanceof String
+										? PreferenceConverter.basicGetFontData((String) event.getNewValue())
+										: (FontData[]) event.getNewValue();
+
+								getFontRegistry().put(key, data);
+								processDefaultsTo(key, data);
+								return;
+							}
+							else if (getColorRegistry().hasValueFor(key)) {
+								RGB rgb = event.getNewValue() instanceof String
+										? StringConverter.asRGB((String) event.getNewValue())
+										: (RGB) event.getNewValue();
+
+								getColorRegistry().put(key, rgb);
+								processDefaultsTo(key, rgb);
+								return;
+							}
+						}
+                    } catch (DataFormatException e) {
+                        //no-op
+                    }
+                }
+
+                /**
+                 * Process all fonts that default to the given ID.
+                 *
+                 * @param key the font ID
+                 * @param fd the new FontData for defaulted fonts
+                 */
+                private void processDefaultsTo(String key, FontData[] fd) {
+					FontDefinition[] defs = WorkbenchPlugin.getDefault().getThemeRegistry().getFontsFor(getId());
+                    for (FontDefinition fontDefinition : defs) {
+                        String defaultsTo = fontDefinition.getDefaultsTo();
+                        if (defaultsTo != null && defaultsTo.equals(key)) {
+							IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore();
+                            if (store.isDefault(ThemeElementHelper
+									.createPreferenceKey(Theme.this, fontDefinition.getId()))) {
+                                getFontRegistry().put(fontDefinition.getId(), fd);
+                                processDefaultsTo(fontDefinition.getId(), fd);
+                            }
+                        }
+                    }
+                }
+
+                /**
+                 * Process all colors that default to the given ID.
+                 *
+                 * @param key the color ID
+                 * @param rgb the new RGB value for defaulted colors
+                 */
+                private void processDefaultsTo(String key, RGB rgb) {
+					ColorDefinition[] defs = WorkbenchPlugin.getDefault().getThemeRegistry().getColorsFor(getId());
+                    for (ColorDefinition colorDefinition : defs) {
+                        String defaultsTo = colorDefinition.getDefaultsTo();
+                        if (defaultsTo != null && defaultsTo.equals(key)) {
+							IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore();
+							if (store.isDefault(
+									ThemeElementHelper.createPreferenceKey(Theme.this, colorDefinition.getId()))) {
+                                getColorRegistry().put(colorDefinition.getId(), rgb);
+                                processDefaultsTo(colorDefinition.getId(), rgb);
+                            }
+                        }
+                    }
+                }
+            };
+        }
+        return propertyListener;
+    }
+
+    /**
+     * Listener that is responsible for rebroadcasting events fired from the base font/color registry
+     */
+    private IPropertyChangeListener getCascadeListener() {
+        if (themeListener == null) {
+            themeListener = event -> firePropertyChange(event);
+        }
+        return themeListener;
+    }
+
+    @Override
+	public ColorRegistry getColorRegistry() {
+      if (themeColorRegistry != null) {
+        return themeColorRegistry;
+  }
+
+  return WorkbenchThemeManager.getInstance()
+          .getDefaultThemeColorRegistry();
+	}
+
+    @Override
+	public FontRegistry getFontRegistry() {
+      if (themeFontRegistry != null) {
+        return themeFontRegistry;
+  }
+
+  return WorkbenchThemeManager.getInstance()
+          .getDefaultThemeFontRegistry();
+}
+
+    @Override
+	public void dispose() {
+        if (themeColorRegistry != null) {
+            themeColorRegistry.removeListener(themeListener);
+            themeColorRegistry.dispose();
+        }
+        if (themeFontRegistry != null) {
+            themeFontRegistry.removeListener(themeListener);
+            themeFontRegistry.dispose();
+        }
+        PrefUtil.getInternalPreferenceStore()
+                .removePropertyChangeListener(getPropertyListener());
+    }
+
+    @Override
+	public String getId() {
+        return descriptor == null ? IThemeManager.DEFAULT_THEME : descriptor
+                .getId();
+    }
+
+    @Override
+	public void addPropertyChangeListener(IPropertyChangeListener listener) {
+        addListenerObject(listener);
+    }
+
+    @Override
+	public void removePropertyChangeListener(IPropertyChangeListener listener) {
+        removeListenerObject(listener);
+    }
+
+    private void firePropertyChange(PropertyChangeEvent event) {
+		for (Object listener : getListeners()) {
+			((IPropertyChangeListener) listener).propertyChange(event);
+		}
+    }
+
+    @Override
+	public String getLabel() {
+        return descriptor == null ? RESOURCE_BUNDLE
+                .getString("DefaultTheme.label") : descriptor.getName(); //$NON-NLS-1$
+    }
+
+    @Override
+	public String getString(String key) {
+        if (dataMap != null) {
+			return (String) dataMap.get(key);
+		}
+        return (String) themeRegistry.getData().get(key);
+    }
+
+    @Override
+	public Set keySet() {
+        if (dataMap != null) {
+			return dataMap.keySet();
+		}
+
+        return themeRegistry.getData().keySet();
+    }
+
+    @Override
+	public int getInt(String key) {
+        String string = getString(key);
+        if (string == null) {
+			return 0;
+		}
+        try {
+            return Integer.parseInt(string);
+        } catch (NumberFormatException e) {
+            return 0;
+        }
+    }
+
+    @Override
+	public boolean getBoolean(String key) {
+        String string = getString(key);
+        if (string == null) {
+			return false;
+		}
+
+        return Boolean.valueOf(getString(key)).booleanValue();
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/Theme.properties b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/Theme.properties
new file mode 100644
index 0000000..81c1369
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/Theme.properties
@@ -0,0 +1,15 @@
+###############################################################################
+# Copyright (c) 2004, 2014 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
+###############################################################################
+DefaultTheme.label=Default
+Overridden.by.css.label={0} (overridden by CSS)
+Overridden.by.css.and.modified.by.user.label={0} (overridden by CSS and modified by user)
+Added.by.css.label={0} (the definition has been added by CSS)
+Added.by.css.and.modified.by.user.label={0} (the definition has been added by CSS and modified by user)
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/ThemeDescriptor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/ThemeDescriptor.java
new file mode 100644
index 0000000..dfaf1c7
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/ThemeDescriptor.java
@@ -0,0 +1,149 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.themes;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+
+/**
+ * Concrete implementation of a theme descriptor.
+ *
+ * @since 3.0
+ */
+public class ThemeDescriptor implements IThemeDescriptor {
+
+    /* Theme */
+    public static final String ATT_ID = "id";//$NON-NLS-1$
+
+    private static final String ATT_NAME = "name";//$NON-NLS-1$
+
+    private Collection colors = new HashSet();
+
+    private String description;
+
+    private Collection fonts = new HashSet();
+
+    private String id;
+
+    private String name;
+
+    private Map dataMap = new HashMap();
+
+    /**
+     * Create a new ThemeDescriptor
+     * @param id
+     */
+    public ThemeDescriptor(String id) {
+        this.id = id;
+    }
+
+    /**
+     * Add a color override to this descriptor.
+     *
+     * @param definition the definition to add
+     */
+    void add(ColorDefinition definition) {
+    	if (colors.contains(definition)) {
+    		colors.remove(definition);
+		}
+        colors.add(definition);
+    }
+
+    /**
+     * Add a font override to this descriptor.
+     *
+     * @param definition the definition to add
+     */
+    void add(FontDefinition definition) {
+        if (fonts.contains(definition)) {
+			return;
+		}
+        fonts.add(definition);
+    }
+
+    /**
+     * Add a data object to this descriptor.
+     *
+     * @param key the key
+     * @param data the data
+     */
+    void setData(String key, Object data) {
+        if (dataMap.containsKey(key)) {
+			return;
+		}
+
+        dataMap.put(key, data);
+    }
+
+    @Override
+	public ColorDefinition[] getColors() {
+        ColorDefinition[] defs = (ColorDefinition[]) colors
+                .toArray(new ColorDefinition[colors.size()]);
+        Arrays.sort(defs, IThemeRegistry.ID_COMPARATOR);
+        return defs;
+    }
+
+    @Override
+	public String getDescription() {
+        return description;
+    }
+
+    @Override
+	public FontDefinition[] getFonts() {
+        FontDefinition[] defs = (FontDefinition[]) fonts
+                .toArray(new FontDefinition[fonts.size()]);
+        Arrays.sort(defs, IThemeRegistry.ID_COMPARATOR);
+        return defs;
+    }
+
+    @Override
+	public String getId() {
+        return id;
+    }
+
+    @Override
+	public String getName() {
+    	if (name == null)
+    		return getId();
+        return name;
+    }
+
+    /*
+     * load the name if it is not already set.
+     */
+    void extractName(IConfigurationElement configElement) {
+        if (name == null) {
+			name = configElement.getAttribute(ATT_NAME);
+		}
+    }
+
+    /**
+     * Set the description.
+     *
+     * @param description the description
+     */
+    void setDescription(String description) {
+        if (this.description == null) {
+			this.description = description;
+		}
+    }
+
+    @Override
+	public Map getData() {
+        return Collections.unmodifiableMap(dataMap);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/ThemeElementCategory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/ThemeElementCategory.java
new file mode 100644
index 0000000..07548ec
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/ThemeElementCategory.java
@@ -0,0 +1,126 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.themes;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.ui.IPluginContribution;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.themes.IThemePreview;
+
+/**
+ * @since 3.0
+ */
+public class ThemeElementCategory implements IPluginContribution,
+        IThemeElementDefinition {
+
+    private String description;
+
+    private IConfigurationElement element;
+
+    private String id;
+
+    private String parentId;
+
+    private String label;
+
+    private String pluginId;
+
+    /**
+     *
+     * @param label
+     * @param id
+     * @param parentId
+     * @param description
+     * @param pluginId
+     * @param element
+     */
+    public ThemeElementCategory(String label, String id, String parentId,
+            String description, String pluginId, IConfigurationElement element) {
+
+        this.label = label;
+        this.id = id;
+        this.parentId = parentId;
+        this.description = description;
+        this.pluginId = pluginId;
+        this.element = element;
+    }
+
+    /**
+     * @return Returns the <code>IColorExample</code> for this category.  If one
+     * is not available, <code>null</code> is returned.
+     * @throws CoreException thrown if there is a problem instantiating the preview
+     */
+    public IThemePreview createPreview() throws CoreException {
+        String classString = element.getAttribute(IWorkbenchRegistryConstants.ATT_CLASS);
+        if (classString == null || "".equals(classString)) { //$NON-NLS-1$
+			return null;
+		}
+        return (IThemePreview) WorkbenchPlugin.createExtension(element,
+                IWorkbenchRegistryConstants.ATT_CLASS);
+    }
+
+    /**
+     * @return Returns the description.
+     */
+    @Override
+	public String getDescription() {
+        return description;
+    }
+
+    /**
+     * @return Returns the element.
+     */
+    public IConfigurationElement getElement() {
+        return element;
+    }
+
+    @Override
+	public String getId() {
+        return id;
+    }
+
+    @Override
+	public String getName() {
+        return label;
+    }
+
+    @Override
+	public String getLocalId() {
+        return id;
+    }
+
+    @Override
+	public String getPluginId() {
+        return pluginId;
+    }
+
+    /**
+     * @return Returns the parentId.  May be <code>null</code>.
+     */
+    public String getParentId() {
+        return parentId;
+    }
+
+    @Override
+	public boolean equals(Object obj) {
+        if (obj instanceof ThemeElementCategory) {
+            return getId().equals(((ThemeElementCategory)obj).getId());
+        }
+        return false;
+    }
+
+    @Override
+	public int hashCode() {
+        return id.hashCode();
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/ThemeElementDefinition.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/ThemeElementDefinition.java
new file mode 100644
index 0000000..7098d6a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/ThemeElementDefinition.java
@@ -0,0 +1,165 @@
+/*******************************************************************************
+ * Copyright (c) 2013, 2016 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
+ *     Patrik Suzzi <psuzzi@gmail.com> - Bug 489250
+ ******************************************************************************/
+
+package org.eclipse.ui.internal.themes;
+
+import com.ibm.icu.text.MessageFormat;
+import java.util.ResourceBundle;
+
+/**
+ * @since 3.5
+ *
+ */
+public class ThemeElementDefinition {
+	private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle.getBundle(Theme.class
+			.getName());
+
+	public static interface State {
+		int UNKNOWN = 0;
+
+		int OVERRIDDEN = 1;
+
+		int ADDED_BY_CSS = 2;
+
+		int MODIFIED_BY_USER = 4;
+	}
+
+	private String id;
+
+	private String label;
+
+	private String description;
+
+	private String formattedDescription;
+
+	private String categoryId;
+
+	private int state = State.UNKNOWN;
+
+	private int stateDuringFormattingMessage;
+
+	public ThemeElementDefinition(String id, String label, String description, String categoryId) {
+		this.id = id;
+		this.label = label;
+		this.description = description;
+		this.categoryId = categoryId;
+	}
+
+	/**
+	 * @return the id of this definition. Should not be <code>null</code>.
+	 */
+	public String getId() {
+		return id;
+	}
+
+	/**
+	 * Returns the label.
+	 *
+	 * @return String
+	 */
+	public String getName() {
+		return label;
+	}
+
+	public void setName(String label) {
+		this.label = label;
+		appendState(State.OVERRIDDEN);
+	}
+
+	/**
+	 * Returns the description.
+	 *
+	 * @return String or
+	 *
+	 *         <pre>
+	 * null
+	 * </pre>
+	 *
+	 *         .
+	 */
+	public String getDescription() {
+		if (formattedDescription == null || stateDuringFormattingMessage != state) {
+			formattedDescription = formatDescription();
+			stateDuringFormattingMessage = state;
+		}
+		return formattedDescription;
+	}
+
+	private String formatDescription() {
+		String description = this.description != null && this.description.trim().length() != 0 ? this.description
+				: label;
+		if (isAddedByCss() && isModifiedByUser()) {
+			return MessageFormat.format(RESOURCE_BUNDLE.getString("Added.by.css.and.modified.by.user.label"), //$NON-NLS-1$
+					description).trim();
+		}
+		if (isAddedByCss()) {
+			return MessageFormat.format(RESOURCE_BUNDLE.getString("Added.by.css.label"), //$NON-NLS-1$
+					description).trim();
+		}
+		if (isOverridden() && isModifiedByUser()) {
+			return MessageFormat.format(RESOURCE_BUNDLE.getString("Overridden.by.css.and.modified.by.user.label"), //$NON-NLS-1$
+					description).trim();
+		}
+		if (isOverridden()) {
+			return MessageFormat.format(RESOURCE_BUNDLE.getString("Overridden.by.css.label"), //$NON-NLS-1$
+					description).trim();
+		}
+		return description;
+	}
+
+	public void setDescription(String description) {
+		this.description = description;
+		formattedDescription = null;
+		appendState(State.OVERRIDDEN);
+	}
+
+	/**
+	 * Returns the categoryId.
+	 *
+	 * @return String
+	 */
+	public String getCategoryId() {
+		return categoryId;
+	}
+
+	public void setCategoryId(String categoryId) {
+		this.categoryId = categoryId;
+		appendState(State.OVERRIDDEN);
+	}
+
+	public int getState() {
+		return state;
+	}
+
+	public void appendState(int state) {
+		this.state |= state;
+	}
+
+	public void removeState(int state) {
+		this.state &= ~state;
+	}
+	public boolean isOverridden() {
+		return (state & State.OVERRIDDEN) != 0;
+	}
+
+	public boolean isAddedByCss() {
+		return (state & State.ADDED_BY_CSS) != 0;
+	}
+
+	public boolean isModifiedByUser() {
+		return (state & State.MODIFIED_BY_USER) != 0;
+	}
+
+	public void resetToDefaultValue() {
+		state = State.UNKNOWN;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/ThemeElementHelper.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/ThemeElementHelper.java
new file mode 100644
index 0000000..13b13b5
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/ThemeElementHelper.java
@@ -0,0 +1,352 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.themes;
+
+import java.util.Arrays;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.PreferenceConverter;
+import org.eclipse.jface.resource.ColorRegistry;
+import org.eclipse.jface.resource.FontRegistry;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.themes.ITheme;
+import org.eclipse.ui.themes.IThemeManager;
+
+/**
+ * @since 3.0
+ */
+public final class ThemeElementHelper {
+
+    public static void populateRegistry(ITheme theme,
+            FontDefinition[] definitions, IPreferenceStore store) {
+        // sort the definitions by dependant ordering so that we process
+        // ancestors before children.
+        FontDefinition[] copyOfDefinitions = null;
+
+        // the colors to set a default value for, but not a registry value
+        FontDefinition[] defaults = null;
+        if (!theme.getId().equals(IThemeManager.DEFAULT_THEME)) {
+            definitions = addDefaulted(definitions);
+            //compute the defaults only if we're setting preferences at this time
+            if (store != null) {
+				defaults = getDefaults(definitions);
+			}
+        }
+
+        copyOfDefinitions = new FontDefinition[definitions.length];
+        System.arraycopy(definitions, 0, copyOfDefinitions, 0,
+                definitions.length);
+        Arrays.sort(copyOfDefinitions, new IThemeRegistry.HierarchyComparator(
+                definitions));
+
+        for (FontDefinition definition : copyOfDefinitions) {
+            installFont(definition, theme, store, true);
+        }
+
+        if (defaults != null) {
+            for (FontDefinition fontDef : defaults) {
+                installFont(fontDef, theme, store, false);
+            }
+        }
+    }
+
+    /**
+     * @param definitions
+     * @return
+     */
+    private static FontDefinition[] addDefaulted(FontDefinition[] definitions) {
+        IThemeRegistry registry = WorkbenchPlugin.getDefault()
+                .getThemeRegistry();
+        FontDefinition[] allDefs = registry.getFonts();
+
+        SortedSet set = addDefaulted(definitions, allDefs);
+        return (FontDefinition[]) set.toArray(new FontDefinition[set.size()]);
+    }
+
+    /**
+     * Installs the given font in the preference store and optionally the font
+     * registry.
+     *
+     * @param definition
+     *            the font definition
+     * @param registry
+     *            the font registry
+     * @param store
+     *            the preference store from which to set and obtain font data
+     * @param setInRegistry
+     * 			  whether the color should be put into the registry as well as
+     *            having its default preference set
+     */
+    private static void installFont(FontDefinition definition, ITheme theme,
+            IPreferenceStore store, boolean setInRegistry) {
+        FontRegistry registry = theme.getFontRegistry();
+
+        String id = definition.getId();
+        String key = createPreferenceKey(theme, id);
+        FontData[] prefFont = store != null ? PreferenceConverter
+                .getFontDataArray(store, key) : null;
+        FontData[] defaultFont = null;
+        if (definition.getValue() != null) {
+			defaultFont = definition.getValue();
+        }
+        else if (definition.getDefaultsTo() != null)
+        {
+            defaultFont = registry.filterData(registry.getFontData(definition.getDefaultsTo()), PlatformUI
+                    .getWorkbench().getDisplay());
+        }
+        else
+        {
+            // values pushed in from jface property files.  Very ugly.
+            // RAP [rh] work around missing FontRegistry#bestDataArray()
+            // defaultFont =
+            // registry.bestDataArray(JFaceResources.getFontRegistry().getFontData(id),
+            // Workbench.getInstance().getDisplay());
+            defaultFont = JFaceResources.getFontRegistry().getFontData(id);
+        }
+
+        if (setInRegistry) {
+            if (prefFont == null
+                    || prefFont == PreferenceConverter.FONTDATA_ARRAY_DEFAULT_DEFAULT) {
+                prefFont = defaultFont;
+            }
+
+            if (prefFont != null) {
+                registry.put(id, prefFont);
+            }
+        }
+
+        if (defaultFont != null && store != null) {
+            PreferenceConverter.setDefault(store, key, defaultFont);
+        }
+    }
+
+    public static void populateRegistry(ITheme theme,
+            ColorDefinition[] definitions, IPreferenceStore store) {
+        // sort the definitions by dependant ordering so that we process
+        // ancestors before children.
+
+        ColorDefinition[] copyOfDefinitions = null;
+
+        // the colors to set a default value for, but not a registry value
+        ColorDefinition[] defaults = null;
+        if (!theme.getId().equals(IThemeManager.DEFAULT_THEME)) {
+            definitions = addDefaulted(definitions);
+            //compute defaults only if we're setting preferences
+            if (store != null) {
+				defaults = getDefaults(definitions);
+			}
+        }
+
+        copyOfDefinitions = new ColorDefinition[definitions.length];
+        System.arraycopy(definitions, 0, copyOfDefinitions, 0,
+                definitions.length);
+        Arrays.sort(copyOfDefinitions, new IThemeRegistry.HierarchyComparator(
+                definitions));
+
+        for (ColorDefinition definition : copyOfDefinitions) {
+            installColor(definition, theme, store, true);
+        }
+
+        if (defaults != null) {
+			for (ColorDefinition colorDef : defaults) {
+				installColor(colorDef, theme, store, false);
+            }
+        }
+    }
+
+    /**
+     * Return the definitions that should have their default preference value
+     * set but nothing else.
+     *
+     * @param definitions the definitions that will be fully handled
+     * @return the remaining definitions that should be defaulted
+     */
+    private static ColorDefinition[] getDefaults(ColorDefinition[] definitions) {
+        IThemeRegistry registry = WorkbenchPlugin.getDefault()
+                .getThemeRegistry();
+        ColorDefinition[] allDefs = registry.getColors();
+
+        SortedSet set = new TreeSet(IThemeRegistry.ID_COMPARATOR);
+        set.addAll(Arrays.asList(allDefs));
+        set.removeAll(Arrays.asList(definitions));
+        return (ColorDefinition[]) set.toArray(new ColorDefinition[set.size()]);
+    }
+
+    /**
+     * Return the definitions that should have their default preference value
+     * set but nothing else.
+     *
+     * @param definitions the definitions that will be fully handled
+     * @return the remaining definitions that should be defaulted
+     */
+    private static FontDefinition[] getDefaults(FontDefinition[] definitions) {
+        IThemeRegistry registry = WorkbenchPlugin.getDefault()
+                .getThemeRegistry();
+        FontDefinition[] allDefs = registry.getFonts();
+
+        SortedSet set = new TreeSet(IThemeRegistry.ID_COMPARATOR);
+        set.addAll(Arrays.asList(allDefs));
+        set.removeAll(Arrays.asList(definitions));
+        return (FontDefinition[]) set.toArray(new FontDefinition[set.size()]);
+    }
+
+    /**
+     * @param definitions
+     * @return
+     */
+    private static ColorDefinition[] addDefaulted(ColorDefinition[] definitions) {
+        IThemeRegistry registry = WorkbenchPlugin.getDefault()
+                .getThemeRegistry();
+        ColorDefinition[] allDefs = registry.getColors();
+
+        SortedSet set = addDefaulted(definitions, allDefs);
+        return (ColorDefinition[]) set.toArray(new ColorDefinition[set.size()]);
+    }
+
+    /**
+     * @param definitions
+     * @param allDefs
+     * @return
+     */
+    private static SortedSet addDefaulted(
+            IHierarchalThemeElementDefinition[] definitions,
+            IHierarchalThemeElementDefinition[] allDefs) {
+        SortedSet set = new TreeSet(IThemeRegistry.ID_COMPARATOR);
+        set.addAll(Arrays.asList(definitions));
+
+        IHierarchalThemeElementDefinition copy [] = new IHierarchalThemeElementDefinition[allDefs.length];
+		System.arraycopy(allDefs, 0, copy, 0, allDefs.length);
+
+        Arrays.sort(allDefs, new IThemeRegistry.HierarchyComparator(copy));
+        for (IHierarchalThemeElementDefinition def : allDefs) {
+            if (def.getDefaultsTo() != null) {
+                if (set.contains(def.getDefaultsTo())) {
+					set.add(def);
+				}
+            }
+        }
+        return set;
+    }
+
+    /**
+     * Installs the given color in the preference store and optionally the color
+     * registry.
+     *
+     * @param definition
+     *            the color definition
+     * @param theme
+     *            the theme defining the color
+     * @param store
+     *            the preference store from which to set and obtain color data
+     * @param setInRegistry
+     * 			  whether the color should be put into the registry
+     */
+
+    private static void installColor(ColorDefinition definition, ITheme theme,
+            IPreferenceStore store, boolean setInRegistry) {
+
+        //TODO: store shouldn't be null, should assert instead of checking null all over
+
+    	ColorRegistry registry = theme.getColorRegistry();
+
+        String id = definition.getId();
+        String key = createPreferenceKey(theme, id);
+        RGB prefColor = store != null
+        	? PreferenceConverter.getColor(store, key)
+        	: null;
+		RGB defaultColor;
+		if (definition.getValue() != null) {
+			defaultColor = definition.getValue();
+		} else if (definition.getDefaultsTo() != null) {
+			String defaultsToKey = createPreferenceKey(theme, definition.getDefaultsTo());
+			defaultColor = PreferenceConverter.getDefaultColor(store, defaultsToKey);
+		} else {
+			defaultColor = null;
+		}
+
+        if (defaultColor == null) {
+			// default is null, likely because we have a bad definition - the
+			// defaultsTo color doesn't exist. We still need a sensible default,
+			// however.
+			defaultColor = PreferenceConverter.COLOR_DEFAULT_DEFAULT;
+		}
+
+		if (prefColor == null || prefColor == PreferenceConverter.COLOR_DEFAULT_DEFAULT) {
+			if (definition.getValue() != null) {
+				prefColor = definition.getValue();
+			} else if (definition.getDefaultsTo() != null) {
+				prefColor = registry.getRGB(definition.getDefaultsTo());
+			}
+		}
+
+		if (prefColor == null) {
+			prefColor = defaultColor;
+		}
+
+        if (setInRegistry) {
+        	registry.put(id, prefColor);
+        }
+
+        if (store != null) {
+            PreferenceConverter.setDefault(store, key, defaultColor);
+        }
+    }
+
+    /**
+     * @param theme
+     * @param id
+     * @return
+     */
+    public static String createPreferenceKey(ITheme theme, String id) {
+        String themeId = theme.getId();
+        if (themeId.equals(IThemeManager.DEFAULT_THEME)) {
+			return id;
+		}
+
+        return themeId + '.' + id;
+    }
+
+    /**
+     * @param theme
+     * @param property
+     * @return
+     */
+    public static String[] splitPropertyName(Theme theme, String property) {
+    	IThemeDescriptor[] descriptors = WorkbenchPlugin.getDefault()
+				.getThemeRegistry().getThemes();
+		for (IThemeDescriptor themeDescriptor : descriptors) {
+			String id = themeDescriptor.getId();
+			if (property.startsWith(id + '.')) { // the property starts with
+													// a known theme ID -
+													// extract and return it and
+													// the remaining property
+				return new String[] { property.substring(0, id.length()),
+						property.substring(id.length() + 1) };
+			}
+		}
+
+		// default is simply return the default theme ID and the raw property
+		return new String[] { IThemeManager.DEFAULT_THEME, property };
+    }
+
+    /**
+	 * Not intended to be instantiated.
+	 */
+    private ThemeElementHelper() {
+        // no-op
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/ThemeRegistry.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/ThemeRegistry.java
new file mode 100644
index 0000000..1817656
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/ThemeRegistry.java
@@ -0,0 +1,305 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 440136
+ *******************************************************************************/
+package org.eclipse.ui.internal.themes;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.eclipse.ui.themes.IThemeManager;
+
+/**
+ * The central manager for Theme descriptors.
+ *
+ * @since 3.0
+ */
+public class ThemeRegistry implements IThemeRegistry {
+
+    private List themes;
+
+    private List colors;
+
+    private List fonts;
+
+    private List categories;
+
+    private Map dataMap;
+
+    /**
+     * Map from String (categoryId) -> Set (presentationIds)
+     */
+    private Map categoryBindingMap;
+
+    /**
+     * Create a new ThemeRegistry.
+     */
+    public ThemeRegistry() {
+        themes = new ArrayList();
+        colors = new ArrayList();
+        fonts = new ArrayList();
+        categories = new ArrayList();
+        dataMap = new HashMap();
+        categoryBindingMap = new HashMap();
+    }
+
+    /**
+     * Add a descriptor to the registry.
+     */
+    void add(IThemeDescriptor desc) {
+        if (findTheme(desc.getId()) != null) {
+			return;
+		}
+        themes.add(desc);
+    }
+
+    /**
+     * Add a descriptor to the registry.
+     */
+    void add(ColorDefinition desc) {
+    	addOrReplaceDescriptor(colors, desc);
+    }
+
+    @Override
+	public ThemeElementCategory findCategory(String id) {
+        return (ThemeElementCategory) findDescriptor(getCategories(), id);
+    }
+
+    @Override
+	public ColorDefinition findColor(String id) {
+        return (ColorDefinition) findDescriptor(getColors(), id);
+    }
+
+    @Override
+	public IThemeDescriptor findTheme(String id) {
+        return (IThemeDescriptor) findDescriptor(getThemes(), id);
+    }
+
+    /**
+     * @param descriptors
+     * @param id
+     * @return
+     */
+    private IThemeElementDefinition findDescriptor(
+            IThemeElementDefinition[] descriptors, String id) {
+        int idx = Arrays.binarySearch(descriptors, id, ID_COMPARATOR);
+        if (idx < 0) {
+			return null;
+		}
+        return descriptors[idx];
+    }
+
+    /*
+     * Add newElement to descriptors.
+     * If one with the same id already exists, replace it.
+     * Return the existing element in the case of replacing, null in the case of adding.
+     */
+    private IThemeElementDefinition addOrReplaceDescriptor(
+            List descriptors, IThemeElementDefinition newElement) {
+    	String id = newElement.getId();
+    	for (int i = 0; i < descriptors.size(); i++) {
+    		IThemeElementDefinition existingElement = (IThemeElementDefinition) descriptors.get(i);
+    		if(existingElement.getId().equals(id)) {
+    			descriptors.remove(i);
+    			descriptors.add(newElement);
+    			return existingElement;
+    		}
+		}
+    	descriptors.add(newElement);
+        return null;
+    }
+
+    @Override
+	public IThemeDescriptor[] getThemes() {
+        int nSize = themes.size();
+        IThemeDescriptor[] retArray = new IThemeDescriptor[nSize];
+        themes.toArray(retArray);
+        Arrays.sort(retArray, ID_COMPARATOR);
+        return retArray;
+    }
+
+    @Override
+	public ColorDefinition[] getColors() {
+        int nSize = colors.size();
+        ColorDefinition[] retArray = new ColorDefinition[nSize];
+        colors.toArray(retArray);
+        Arrays.sort(retArray, ID_COMPARATOR);
+        return retArray;
+    }
+
+    @Override
+	public ColorDefinition[] getColorsFor(String themeId) {
+        ColorDefinition[] defs = getColors();
+        if (themeId.equals(IThemeManager.DEFAULT_THEME)) {
+			return defs;
+		}
+
+        IThemeDescriptor desc = findTheme(themeId);
+        ColorDefinition[] overrides = desc.getColors();
+        return (ColorDefinition[]) overlay(defs, overrides);
+    }
+
+    @Override
+	public FontDefinition[] getFontsFor(String themeId) {
+        FontDefinition[] defs = getFonts();
+        if (themeId.equals(IThemeManager.DEFAULT_THEME)) {
+			return defs;
+		}
+
+        IThemeDescriptor desc = findTheme(themeId);
+        FontDefinition[] overrides = desc.getFonts();
+        return (FontDefinition[]) overlay(defs, overrides);
+    }
+
+    /**
+     * Overlay the overrides onto the base definitions.
+     *
+     * @param defs the base definitions
+     * @param overrides the overrides
+     * @return the overlayed elements
+     */
+    private IThemeElementDefinition[] overlay(IThemeElementDefinition[] defs,
+            IThemeElementDefinition[] overrides) {
+        for (IThemeElementDefinition override : overrides) {
+			int idx = Arrays.binarySearch(defs, override, IThemeRegistry.ID_COMPARATOR);
+            if (idx >= 0) {
+                // RAP
+//                defs[idx] = overlay(defs[idx], overrides[i]);
+          }
+      }
+      return defs;
+  }
+
+    // RAP
+//    /**
+//     * Overlay the override onto the base definition.
+//     *
+//     * @param defs the base definition
+//     * @param overrides the override
+//     * @return the overlayed element
+//     */
+//    private IThemeElementDefinition overlay(IThemeElementDefinition original,
+//            IThemeElementDefinition overlay) {
+//        if (original instanceof ColorDefinition) {
+//            ColorDefinition originalColor = (ColorDefinition) original;
+//            ColorDefinition overlayColor = (ColorDefinition) overlay;
+//            return new ColorDefinition(originalColor, overlayColor.getValue());
+//        } else if (original instanceof FontDefinition) {
+//            FontDefinition originalFont = (FontDefinition) original;
+//            FontDefinition overlayFont = (FontDefinition) overlay;
+//            return new FontDefinition(originalFont, overlayFont.getValue());
+//        }
+//        return null;
+//    }
+
+    /**
+     * @param definition
+     */
+    void add(FontDefinition definition) {
+        if (findFont(definition.getId()) != null) {
+			return;
+		}
+        fonts.add(definition);
+    }
+
+    @Override
+	public FontDefinition[] getFonts() {
+        int nSize = fonts.size();
+        FontDefinition[] retArray = new FontDefinition[nSize];
+        fonts.toArray(retArray);
+        Arrays.sort(retArray, ID_COMPARATOR);
+        return retArray;
+    }
+
+    @Override
+	public FontDefinition findFont(String id) {
+        return (FontDefinition) findDescriptor(getFonts(), id);
+    }
+
+    /**
+     * @param definition
+     */
+    void add(ThemeElementCategory definition) {
+        if (findCategory(definition.getId()) != null) {
+			return;
+		}
+        categories.add(definition);
+    }
+
+    @Override
+	public ThemeElementCategory[] getCategories() {
+        int nSize = categories.size();
+        ThemeElementCategory[] retArray = new ThemeElementCategory[nSize];
+        categories.toArray(retArray);
+        Arrays.sort(retArray, ID_COMPARATOR);
+        return retArray;
+    }
+
+    /**
+     * @param name
+     * @param value
+     */
+    void setData(String name, String value) {
+        if (dataMap.containsKey(name)) {
+			return;
+		}
+
+        dataMap.put(name, value);
+    }
+
+    @Override
+	public Map getData() {
+        return Collections.unmodifiableMap(dataMap);
+    }
+
+    /**
+     * Add the data from another map to this data
+     *
+     * @param otherData the other data to add
+     */
+    public void addData(Map<?, ?> otherData) {
+		for (Entry<?, ?> entry : otherData.entrySet()) {
+			Object key = entry.getKey();
+            if (dataMap.containsKey(key)) {
+				continue;
+			}
+			dataMap.put(key, entry.getValue());
+        }
+    }
+    
+    /**
+     * Add a category presentation binding.  The given category will only be 
+     * availible if the given presentation is active.
+     * 
+     * @param categoryId the category id
+     * @param presentationId the presentation id
+     */
+    public void addCategoryPresentationBinding(String categoryId,
+            String presentationId) {
+        Set presentations = (Set) categoryBindingMap.get(categoryId);
+        if (presentations == null) {
+            presentations = new HashSet();
+            categoryBindingMap.put(categoryId, presentations);
+        }
+        presentations.add(presentationId);
+    }
+
+    @Override
+	public Set getPresentationsBindingsFor(ThemeElementCategory category) {
+        return (Set) categoryBindingMap.get(category.getId());
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/ThemeRegistryReader.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/ThemeRegistryReader.java
new file mode 100644
index 0000000..89e3cbc
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/ThemeRegistryReader.java
@@ -0,0 +1,470 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.themes;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.ResourceBundle;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.resource.StringConverter;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.registry.RegistryReader;
+import org.eclipse.ui.themes.IColorFactory;
+
+/**
+ * Registry reader for themes.
+ *
+ * @since 3.0
+ */
+public class ThemeRegistryReader extends RegistryReader {
+
+    /**
+     * The translation bundle in which to look up internationalized text.
+     */
+    private final static ResourceBundle RESOURCE_BUNDLE = ResourceBundle
+            .getBundle(ThemeRegistryReader.class.getName());
+
+    private Collection categoryDefinitions = new HashSet();
+
+    private Collection colorDefinitions = new HashSet();
+
+    private Collection fontDefinitions = new HashSet();
+
+    private ThemeDescriptor themeDescriptor = null;
+
+    private ThemeRegistry themeRegistry;
+
+    private Map dataMap = new HashMap();
+
+    /**
+     * ThemeRegistryReader constructor comment.
+     */
+    public ThemeRegistryReader() {
+        super();
+    }
+
+    /**
+     * Returns the category definitions.
+     *
+     * @return the category definitions
+     */
+    public Collection getCategoryDefinitions() {
+        return categoryDefinitions;
+    }
+
+    /**
+     * Returns the color definitions.
+     *
+     * @return the color definitions
+     */
+    public Collection getColorDefinitions() {
+        return colorDefinitions;
+    }
+
+    /**
+     * Returns the data map.
+     *
+     * @return the data map
+     */
+    public Map getData() {
+        return dataMap;
+    }
+
+    /**
+     * Returns the font definitions.
+     *
+     * @return the font definitions
+     */
+    public Collection getFontDefinitions() {
+        return fontDefinitions;
+    }
+
+    /**
+     * Read a category.
+     *
+     * @param element the element to read
+     * @return the new category
+     */
+    private ThemeElementCategory readCategory(IConfigurationElement element) {
+        String name = element.getAttribute(IWorkbenchRegistryConstants.ATT_LABEL);
+
+        String id = element.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+        String parentId = element.getAttribute(IWorkbenchRegistryConstants.ATT_PARENT_ID);
+
+        String description = null;
+
+        IConfigurationElement[] descriptions = element
+                .getChildren(IWorkbenchRegistryConstants.TAG_DESCRIPTION);
+
+        if (descriptions.length > 0) {
+			description = descriptions[0].getValue();
+		}
+
+        return new ThemeElementCategory(name, id, parentId, description,
+                element.getNamespace(), element);
+    }
+
+    /**
+     * Read a color.
+     *
+     * @param element the element to read
+     * @return the new color
+     */
+    private ColorDefinition readColor(IConfigurationElement element) {
+        String name = element.getAttribute(IWorkbenchRegistryConstants.ATT_LABEL);
+
+        String id = element.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+
+        String defaultMapping = element.getAttribute(IWorkbenchRegistryConstants.ATT_DEFAULTS_TO);
+
+        String value = getPlatformSpecificColorValue(element
+                .getChildren(IWorkbenchRegistryConstants.TAG_COLORVALUE));
+
+        if (value == null) {
+            value = getColorValue(element);
+        }
+
+        if ((value == null && defaultMapping == null)
+                || (value != null && defaultMapping != null)) {
+            logError(element, RESOURCE_BUNDLE.getString("Colors.badDefault")); //$NON-NLS-1$
+            return null;
+        }
+
+        String categoryId = element.getAttribute(IWorkbenchRegistryConstants.ATT_CATEGORY_ID);
+
+        String description = null;
+        boolean isEditable = true;
+        String isEditableString = element.getAttribute(IWorkbenchRegistryConstants.ATT_IS_EDITABLE);
+        if (isEditableString != null) {
+            isEditable = Boolean.valueOf(isEditableString).booleanValue();
+        }
+
+        IConfigurationElement[] descriptions = element
+                .getChildren(IWorkbenchRegistryConstants.TAG_DESCRIPTION);
+
+        if (descriptions.length > 0) {
+			description = descriptions[0].getValue();
+		}
+
+        return new ColorDefinition(name, id, defaultMapping, value, categoryId,
+                isEditable, description, element.getDeclaringExtension()
+                        .getNamespace());
+    }
+
+    /**
+     * Gets the color value, either via the value attribute or from a color
+     * factory.
+     *
+     * @param element the element to check
+     * @return the color string
+     */
+    private String getColorValue(IConfigurationElement element) {
+        if (element == null) {
+			return null;
+		}
+
+        String value = element.getAttribute(IWorkbenchRegistryConstants.ATT_VALUE);
+        if (value == null) {
+            value = checkColorFactory(element);
+        }
+        return value;
+    }
+
+    /**
+     * Check for platform specific color values.  This will return the
+     * "best match" for the current platform.
+     *
+     * @param elements the elements to check
+     * @return the platform specific color, if any
+     */
+    private String getPlatformSpecificColorValue(
+            IConfigurationElement[] elements) {
+        return getColorValue(getBestPlatformMatch(elements));
+    }
+
+    /**
+     * Get the element that has os/ws attributes that best match the current
+     * platform.
+     *
+     * @param elements the elements to check
+     * @return the best match, if any
+     */
+    private IConfigurationElement getBestPlatformMatch(
+            IConfigurationElement[] elements) {
+        IConfigurationElement match = null;
+
+        String osname = Platform.getOS();
+        String wsname = Platform.getWS();
+
+        for (IConfigurationElement element : elements) {
+            String elementOs = element.getAttribute(IWorkbenchRegistryConstants.ATT_OS);
+            String elementWs = element.getAttribute(IWorkbenchRegistryConstants.ATT_WS);
+
+            if (osname.equalsIgnoreCase(elementOs)) {
+                if (wsname.equalsIgnoreCase(elementWs)) {
+                    // best possible match.  Return
+                    return element;
+                }
+                match = element;
+            } else if (wsname.equalsIgnoreCase(elementWs)) {
+                match = element;
+            }
+        }
+
+        return match;
+    }
+
+    @Override
+	public boolean readElement(IConfigurationElement element) {
+        String elementName = element.getName();
+        if (themeDescriptor == null && elementName.equals(IWorkbenchRegistryConstants.TAG_COLORDEFINITION)) {
+            ColorDefinition definition = readColor(element);
+            if (definition != null) {
+                if (!colorDefinitions.contains(definition)) {
+	                colorDefinitions.add(definition);
+	                themeRegistry.add(definition);
+                }
+            }
+            return true;
+        } else if (themeDescriptor != null
+                && elementName.equals(IWorkbenchRegistryConstants.TAG_COLOROVERRIDE)) {
+            ColorDefinition definition = readColor(element);
+            if (definition != null) {
+                themeDescriptor.add(definition);
+            }
+            return true;
+        } else if (themeDescriptor == null
+                && elementName.equals(IWorkbenchRegistryConstants.TAG_FONTDEFINITION)) {
+            FontDefinition definition = readFont(element);
+            if (definition != null) {
+                if (!fontDefinitions.contains(definition)) {
+	                fontDefinitions.add(definition);
+	                themeRegistry.add(definition);
+                }
+            }
+            return true;
+        } else if (themeDescriptor != null
+                && elementName.equals(IWorkbenchRegistryConstants.TAG_FONTOVERRIDE)) {
+            FontDefinition definition = readFont(element);
+            if (definition != null) {
+                themeDescriptor.add(definition);
+            }
+            return true;
+        } else if (themeDescriptor == null
+                && elementName.equals(IWorkbenchRegistryConstants.TAG_CATEGORYDEFINITION)) {
+            ThemeElementCategory definition = readCategory(element);
+            if (definition != null) {
+                if (!categoryDefinitions.contains(definition)) {
+	                categoryDefinitions.add(definition);
+	                themeRegistry.add(definition);
+                }
+            }
+            return true;
+        } else if (element.getName().equals(IWorkbenchRegistryConstants.TAG_THEME)) {
+            if (themeDescriptor != null) {
+				logError(element, RESOURCE_BUNDLE
+                        .getString("Themes.badNesting")); //$NON-NLS-1$
+			} else {
+                themeDescriptor = readTheme(element);
+                if (themeDescriptor != null) {
+                    readElementChildren(element);
+                    themeDescriptor = null;
+                }
+                return true;
+            }
+        } else if (themeDescriptor != null
+                && elementName.equals(IWorkbenchRegistryConstants.TAG_DESCRIPTION)) {
+            themeDescriptor.setDescription(element.getValue());
+            return true;
+        } else if (elementName.equals(IWorkbenchRegistryConstants.TAG_DATA)) {
+            String name = element.getAttribute(IWorkbenchRegistryConstants.ATT_NAME);
+            String value = element.getAttribute(IWorkbenchRegistryConstants.ATT_VALUE);
+            if (name == null || value == null) {
+                logError(element, RESOURCE_BUNDLE.getString("Data.badData")); //$NON-NLS-1$
+            } else {
+                if (themeDescriptor != null) {
+                    themeDescriptor.setData(name, value);
+                } else {
+                    themeRegistry.setData(name, value);
+                    if (!dataMap.containsKey(name)) {
+						dataMap.put(name, value);
+					}
+                }
+            }
+            return true;
+        } else if (elementName.equals(IWorkbenchRegistryConstants.TAG_CATEGORYPRESENTATIONBINDING)) {
+            String categoryId = element.getAttribute(IWorkbenchRegistryConstants.ATT_CATEGORY_ID);
+            String presentationId = element.getAttribute(IWorkbenchRegistryConstants.ATT_PRESENTATIONID);
+            themeRegistry.addCategoryPresentationBinding(categoryId,
+                    presentationId);
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Read a font.
+     *
+     * @param element the element to read
+     * @return the new font
+     */
+    private FontDefinition readFont(IConfigurationElement element) {
+        String name = element.getAttribute(IWorkbenchRegistryConstants.ATT_LABEL);
+
+        String id = element.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
+
+        String defaultMapping = element.getAttribute(IWorkbenchRegistryConstants.ATT_DEFAULTS_TO);
+
+        String value = getPlatformSpecificFontValue(element
+                .getChildren(IWorkbenchRegistryConstants.TAG_FONTVALUE));
+        if (value == null) {
+            value = element.getAttribute(IWorkbenchRegistryConstants.ATT_VALUE);
+        }
+
+        if (value != null && defaultMapping != null) {
+            logError(element, RESOURCE_BUNDLE.getString("Fonts.badDefault")); //$NON-NLS-1$
+            return null;
+        }
+
+        String categoryId = element.getAttribute(IWorkbenchRegistryConstants.ATT_CATEGORY_ID);
+
+        boolean isEditable = true;
+        String isEditableString = element.getAttribute(IWorkbenchRegistryConstants.ATT_IS_EDITABLE);
+        if (isEditableString != null) {
+            isEditable = Boolean.valueOf(isEditableString).booleanValue();
+        }
+
+        String description = null;
+
+        IConfigurationElement[] descriptions = element
+                .getChildren(IWorkbenchRegistryConstants.TAG_DESCRIPTION);
+
+        if (descriptions.length > 0) {
+			description = descriptions[0].getValue();
+		}
+
+        return new FontDefinition(name, id, defaultMapping, value, categoryId,
+                isEditable, description);
+    }
+
+    /**
+     * Check for platform specific font values.  This will return the
+     * "best match" for the current platform.
+     *
+     * @param elements the elements to check
+     * @return the platform specific font, if any
+     */
+    private String getPlatformSpecificFontValue(IConfigurationElement[] elements) {
+        return getFontValue(getBestPlatformMatch(elements));
+    }
+
+    /**
+     * Gets the font valu from the value attribute.
+     *
+     * @param element the element to check
+     * @return the font string
+     */
+    private String getFontValue(IConfigurationElement element) {
+        if (element == null) {
+			return null;
+		}
+
+        return element.getAttribute(IWorkbenchRegistryConstants.ATT_VALUE);
+    }
+
+    /**
+     * Attempt to load the color value from the colorFactory attribute.
+     *
+     * @param element the element to load from
+     * @return the value, or null if it could not be obtained
+     */
+    private String checkColorFactory(IConfigurationElement element) {
+        String value = null;
+        if (element.getAttribute(IWorkbenchRegistryConstants.ATT_COLORFACTORY) != null
+                || element.getChildren(IWorkbenchRegistryConstants.ATT_COLORFACTORY).length > 0) {
+            try {
+                IColorFactory factory = (IColorFactory) element
+                        .createExecutableExtension(IWorkbenchRegistryConstants.ATT_COLORFACTORY);
+                value = StringConverter.asString(factory.createColor());
+            } catch (Exception e) {
+                WorkbenchPlugin.log(RESOURCE_BUNDLE
+                        .getString("Colors.badFactory"), //$NON-NLS-1$
+                        WorkbenchPlugin.getStatus(e));
+            }
+        }
+        return value;
+    }
+
+    /**
+     * Read a theme.
+     *
+     * @param element the element to read
+     * @return the new theme
+     */
+    protected ThemeDescriptor readTheme(IConfigurationElement element) {
+        ThemeDescriptor desc = null;
+
+        String id = element.getAttribute(ThemeDescriptor.ATT_ID);
+        if (id == null) {
+			return null;
+		}
+        //see if the theme has already been created in another extension
+        desc = (ThemeDescriptor) themeRegistry.findTheme(id);
+        //if not, create it
+        if (desc == null) {
+            desc = new ThemeDescriptor(id);
+            themeRegistry.add(desc);
+        }
+        //set the name as applicable
+        desc.extractName(element);
+
+        return desc;
+    }
+
+    /**
+     * Read the theme extensions within a registry.
+     *
+     * @param in the registry to read
+     * @param out the registry to write to
+     */
+    public void readThemes(IExtensionRegistry in, ThemeRegistry out) {
+        // this does not seem to really ever be throwing an the exception
+        setRegistry(out);
+        // RAP [bm]: 
+//        readRegistry(in, PlatformUI.PLUGIN_ID, IWorkbenchRegistryConstants.PL_THEMES);
+//
+//        // support for old font definitions
+//        readRegistry(in, PlatformUI.PLUGIN_ID,
+//                IWorkbenchRegistryConstants.PL_FONT_DEFINITIONS);
+        readRegistry(in, PlatformUI.PLUGIN_EXTENSION_NAME_SPACE, IWorkbenchRegistryConstants.PL_THEMES);
+
+        // support for old font definitions
+        readRegistry(in, PlatformUI.PLUGIN_EXTENSION_NAME_SPACE,
+                IWorkbenchRegistryConstants.PL_FONT_DEFINITIONS);
+        // RAPEND: [bm]
+    }
+
+    /**
+     * Set the output registry.
+     *
+     * @param out the output registry
+     */
+    public void setRegistry(ThemeRegistry out) {
+        themeRegistry = out;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/ThemeRegistryReader.properties b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/ThemeRegistryReader.properties
new file mode 100644
index 0000000..70f5236
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/ThemeRegistryReader.properties
@@ -0,0 +1,18 @@
+###############################################################################
+# Copyright (c) 2004, 2013 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
+###############################################################################
+
+Colors.badFactory=Could not create color factory.
+Colors.badDefault=Only one of value or defaultMapping may be set.
+Fonts.badDefault=Only one or neither of value or defaultMapping may be set.
+Gradients.badPercentage=Percentage must be a positive integer.
+Gradients.badGradientValue=Value must be present.
+Themes.badNesting=Cannot have nested themes.
+Data.badData=Name and value must be present for data elements.
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/WorkbenchPreview.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/WorkbenchPreview.java
new file mode 100644
index 0000000..1dad916
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/WorkbenchPreview.java
@@ -0,0 +1,163 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.themes;
+
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CLabel;
+import org.eclipse.swt.custom.CTabFolder;
+import org.eclipse.swt.custom.CTabItem;
+import org.eclipse.swt.custom.ViewForm;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.IWorkbenchPreferenceConstants;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
+import org.eclipse.ui.internal.IWorkbenchThemeConstants;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.themes.ITheme;
+import org.eclipse.ui.themes.IThemePreview;
+
+/**
+ * @since 3.0
+ */
+public class WorkbenchPreview implements IThemePreview {
+
+	  // don't reset this dynamically, so just keep the information static.
+	// see bug:
+	//   75422 [Presentations] Switching presentation to R21 switches immediately, but only partially
+    private static int tabPos = PlatformUI.getPreferenceStore().getInt(IWorkbenchPreferenceConstants.VIEW_TAB_POSITION);
+
+    private boolean disposed = false;
+
+    private CTabFolder folder;
+
+    private ITheme theme;
+
+    private ToolBar toolBar;
+
+    private CLabel viewMessage;
+
+    private ViewForm viewForm;
+
+    private IPropertyChangeListener fontAndColorListener = event -> {
+	    if (!disposed) {
+	        setColorsAndFonts();
+	        //viewMessage.setSize(viewMessage.computeSize(SWT.DEFAULT, SWT.DEFAULT, true));
+	        viewForm.layout(true);
+	    }
+	};
+
+    @Override
+	public void createControl(Composite parent, ITheme currentTheme) {
+        this.theme = currentTheme;
+        folder = new CTabFolder(parent, SWT.BORDER);
+        folder.setUnselectedCloseVisible(false);
+        folder.setEnabled(false);
+        folder.setMaximizeVisible(true);
+        folder.setMinimizeVisible(true);
+
+        viewForm = new ViewForm(folder, SWT.NONE);
+        viewForm.marginHeight = 0;
+        viewForm.marginWidth = 0;
+        viewForm.verticalSpacing = 0;
+        viewForm.setBorderVisible(false);
+        toolBar = new ToolBar(viewForm, SWT.FLAT | SWT.WRAP);
+        ToolItem toolItem = new ToolItem(toolBar, SWT.PUSH);
+
+        Image hoverImage = WorkbenchImages
+                .getImage(IWorkbenchGraphicConstants.IMG_LCL_VIEW_MENU);
+        toolItem.setImage(hoverImage);
+
+        viewForm.setTopRight(toolBar);
+
+        viewMessage = new CLabel(viewForm, SWT.NONE);
+        viewMessage.setText("Etu?"); //$NON-NLS-1$
+        viewForm.setTopLeft(viewMessage);
+
+        CTabItem item = new CTabItem(folder, SWT.CLOSE);
+        item.setText("Lorem"); //$NON-NLS-1$
+        Label text = new Label(viewForm, SWT.NONE);
+        viewForm.setContent(text);
+        text.setText("Lorem ipsum dolor sit amet"); //$NON-NLS-1$
+        item = new CTabItem(folder, SWT.CLOSE);
+        item.setText("Ipsum"); //$NON-NLS-1$
+        item.setControl(viewForm);
+        item.setImage(WorkbenchImages.getImage(ISharedImages.IMG_TOOL_COPY));
+
+        folder.setSelection(item);
+
+        item = new CTabItem(folder, SWT.CLOSE);
+        item.setText("Dolor"); //$NON-NLS-1$
+        item = new CTabItem(folder, SWT.CLOSE);
+        item.setText("Sit"); //$NON-NLS-1$
+
+        currentTheme.addPropertyChangeListener(fontAndColorListener);
+        setColorsAndFonts();
+        setTabPosition();
+        setTabStyle();
+    }
+
+    /**
+     * Set the tab style from preferences.
+     */
+    protected void setTabStyle() {
+        boolean traditionalTab = PlatformUI.getPreferenceStore()
+                .getBoolean(IWorkbenchPreferenceConstants.SHOW_TRADITIONAL_STYLE_TABS);
+        // RAP
+//        folder.setSimple(traditionalTab);
+    }
+
+    /**
+     * Set the tab location from preferences.
+     */
+    protected void setTabPosition() {
+        tabPos = PlatformUI.getPreferenceStore().getInt(IWorkbenchPreferenceConstants.VIEW_TAB_POSITION);
+        folder.setTabPosition(tabPos);
+    }
+
+    /**
+     * Set the folder colors and fonts
+     */
+    private void setColorsAndFonts() {
+        folder.setSelectionForeground(theme.getColorRegistry().get(
+                IWorkbenchThemeConstants.ACTIVE_TAB_TEXT_COLOR));
+        folder.setForeground(theme.getColorRegistry().get(
+                IWorkbenchThemeConstants.INACTIVE_TAB_TEXT_COLOR));
+
+        Color[] colors = new Color[2];
+        colors[0] = theme.getColorRegistry().get(
+                IWorkbenchThemeConstants.INACTIVE_TAB_BG_START);
+        colors[1] = theme.getColorRegistry().get(
+                IWorkbenchThemeConstants.INACTIVE_TAB_BG_END);
+        colors[0] = theme.getColorRegistry().get(
+                IWorkbenchThemeConstants.ACTIVE_TAB_BG_START);
+        colors[1] = theme.getColorRegistry().get(
+                IWorkbenchThemeConstants.ACTIVE_TAB_BG_END);
+        folder.setSelectionBackground(colors, new int[] { theme
+                .getInt(IWorkbenchThemeConstants.ACTIVE_TAB_PERCENT) }, theme
+                .getBoolean(IWorkbenchThemeConstants.ACTIVE_TAB_VERTICAL));
+
+        folder.setFont(theme.getFontRegistry().get(
+                IWorkbenchThemeConstants.TAB_TEXT_FONT));
+    }
+
+    @Override
+	public void dispose() {
+        disposed = true;
+        theme.removePropertyChangeListener(fontAndColorListener);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/WorkbenchThemeManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/WorkbenchThemeManager.java
new file mode 100644
index 0000000..a27891e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/themes/WorkbenchThemeManager.java
@@ -0,0 +1,349 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2016 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.ui.internal.themes;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.eclipse.core.commands.common.EventManager;
+import org.eclipse.jface.resource.ColorRegistry;
+import org.eclipse.jface.resource.FontRegistry;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.rap.rwt.SingletonUtil;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.ui.IWorkbenchPreferenceConstants;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.internal.util.PrefUtil;
+import org.eclipse.ui.statushandlers.StatusManager;
+import org.eclipse.ui.themes.ITheme;
+import org.eclipse.ui.themes.IThemeManager;
+
+/**
+ * Theme manager for the Workbench.
+ *
+ * @since 3.0
+ */
+public class WorkbenchThemeManager extends EventManager implements IThemeManager {
+
+	private static final String SYSTEM_DEFAULT_THEME = "org.eclipse.ui.ide.systemDefault";//$NON-NLS-1$
+
+	// RAP [bm]:
+//  private static WorkbenchThemeManager instance;
+    private boolean initialized;
+
+	/**
+	 * Returns the singelton instance of the WorkbenchThemeManager
+	 *
+	 * @return singleton instance
+	 */
+ // RAP [rst]: use session scope
+//  public static synchronized WorkbenchThemeManager getInstance() {
+//      if (instance == null) {
+//          instance = new WorkbenchThemeManager();
+//          instance.getCurrentTheme(); // initialize the current theme
+//      }
+//      return instance;
+//  }
+    public static WorkbenchThemeManager getInstance() {
+        WorkbenchThemeManager result
+          = SingletonUtil.getSessionInstance( WorkbenchThemeManager.class );
+        synchronized( result ) {
+            if( !result.initialized ) {
+                result.initialized = true;
+                result.getCurrentTheme();
+            }
+        }
+        return result;
+    }
+
+	private ITheme currentTheme;
+
+	private IPropertyChangeListener currentThemeListener = event -> {
+		firePropertyChange(event);
+		if (event.getSource() instanceof FontRegistry) {
+			JFaceResources.getFontRegistry().put(event.getProperty(),
+					(FontData[]) event.getNewValue());
+		} else if (event.getSource() instanceof ColorRegistry) {
+			JFaceResources.getColorRegistry().put(event.getProperty(),
+					(RGB) event.getNewValue());
+		}
+	};
+
+	private ColorRegistry defaultThemeColorRegistry;
+
+	private FontRegistry defaultThemeFontRegistry;
+
+	private IThemeRegistry themeRegistry;
+
+	private Map themes = new HashMap(7);
+
+	/*
+     * Initialize the WorkbenchThemeManager.
+     * Determine the default theme according to the following rules:
+     *   1) If we're in HC mode then default to system default
+     *   2) Otherwise, if preference already set (e.g. via plugin_customization.ini), then observe that value
+     *   3) Otherwise, use our default
+     * Call dispose when we close.
+     */	
+	private WorkbenchThemeManager() {	
+		defaultThemeColorRegistry = new ColorRegistry(PlatformUI.getWorkbench()
+				.getDisplay());
+
+		defaultThemeFontRegistry = new FontRegistry(PlatformUI.getWorkbench()
+				.getDisplay());
+
+		// copy the font values from preferences.
+		FontRegistry jfaceFonts = JFaceResources.getFontRegistry();
+		for (Object fontRegistryKey : jfaceFonts.getKeySet()) {
+			String key = (String) fontRegistryKey;
+			defaultThemeFontRegistry.put(key, jfaceFonts.getFontData(key));
+		}
+
+		//Theme might be set via plugin_configuration.ini
+		String themeId = PrefUtil.getAPIPreferenceStore().getDefaultString(IWorkbenchPreferenceConstants.CURRENT_THEME_ID);
+
+		//If not set, use default
+		if (themeId.length() == 0)
+			themeId = IThemeManager.DEFAULT_THEME;
+
+        // Check if we are in high contrast mode. If so then set the theme to
+        // the system default
+        if (PlatformUI.getWorkbench().getDisplay() != null) {
+            // Determine the high contrast setting before
+            // any access to preferences
+            final boolean[] highContrast = new boolean[] { false };
+            // RAP [bm]: Display#getHighContrast
+            // RAP [bm]: SWT.Settings
+//          PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {
+//
+//              /*
+//               * (non-Javadoc)
+//               *
+//               * @see java.lang.Runnable#run()
+//               */
+//              public void run() {
+//                  highContrast[0] = Display.getCurrent().getHighContrast();
+//
+//                  Display.getCurrent().addListener(SWT.Settings, new Listener() {
+//                      public void handleEvent(Event event) {
+//                          updateThemes();
+//                      }
+//                  });
+//
+//              }
+//          });
+            // RAPEND: [bm]
+
+		// If in HC, *always* use the system default.
+		// This ignores any default theme set via plugin_customization.ini
+		if (highContrast[0])
+			themeId = SYSTEM_DEFAULT_THEME;
+        }
+		PrefUtil.getAPIPreferenceStore().setDefault(
+				IWorkbenchPreferenceConstants.CURRENT_THEME_ID, themeId);
+	}		
+
+	/*
+	 * Update existing theme contents, descriptors, and registries.
+	 * Reread the themes and recompute the registries.
+	 */
+    // RAP [bm]: never used
+//	private void updateThemes() {
+//		//reread the themes since their descriptors have changed in value
+//        ThemeRegistryReader reader = new ThemeRegistryReader();
+//        reader.readThemes(Platform.getExtensionRegistry(),(ThemeRegistry) getThemeRegistry());
+//
+//        //DEFAULT_THEME is not in getThemes() list so must be handled special
+//        ThemeElementHelper.populateRegistry(getTheme(IThemeManager.DEFAULT_THEME), getThemeRegistry().getColors(), PrefUtil.getInternalPreferenceStore());
+//
+//        IThemeDescriptor[] themeDescriptors = getThemeRegistry().getThemes();
+//
+//       	for (IThemeDescriptor themeDescriptor : themeDescriptors) {
+//        	ITheme theme = (ITheme) themes.get(themeDescriptor);
+//    		//If theme is in our themes table then its already been populated
+//    		if (theme != null) {
+//                ColorDefinition[] colorDefinitions = themeDescriptor.getColors();
+//
+//               if (colorDefinitions.length > 0) {
+//                	ThemeElementHelper.populateRegistry(theme, colorDefinitions,PrefUtil.getInternalPreferenceStore());
+//                }
+//    		}
+//		}
+//	}
+	// RAPEND: [bm]
+	@Override
+	public void addPropertyChangeListener(IPropertyChangeListener listener) {
+		addListenerObject(listener);
+	}
+
+	/**
+	 * Disposes all ThemeEntries.
+	 */
+	public void dispose() {
+		for (Iterator i = themes.values().iterator(); i.hasNext();) {
+			ITheme theme = (ITheme) i.next();
+			theme.removePropertyChangeListener(currentThemeListener);
+			theme.dispose();
+		}
+		themes.clear();
+	}
+
+	private boolean doSetCurrentTheme(String id) {
+		ITheme oldTheme = currentTheme;
+		ITheme newTheme = getTheme(id);
+		if (oldTheme != newTheme && newTheme != null) {
+			currentTheme = newTheme;
+			return true;
+		}
+
+		return false;
+	}
+
+	protected void firePropertyChange(PropertyChangeEvent event) {
+		for (Object listener : getListeners()) {
+			((IPropertyChangeListener) listener).propertyChange(event);
+		}
+	}
+
+	protected void firePropertyChange(String changeId, ITheme oldTheme,
+			ITheme newTheme) {
+
+		PropertyChangeEvent event = new PropertyChangeEvent(this, changeId,
+				oldTheme, newTheme);
+		firePropertyChange(event);
+	}
+
+	@Override
+	public ITheme getCurrentTheme() {
+		if (currentTheme == null) {
+			String themeId = PrefUtil.getAPIPreferenceStore().getString(
+					IWorkbenchPreferenceConstants.CURRENT_THEME_ID);
+
+			if (themeId == null) // missing preference
+				setCurrentTheme(IThemeManager.DEFAULT_THEME);
+			else {
+				setCurrentTheme(themeId);
+				if (currentTheme == null) { // still null - the preference
+											// didn't resolve to a proper theme
+					setCurrentTheme(IThemeManager.DEFAULT_THEME);
+					StatusManager
+							.getManager()
+							.handle(
+									StatusUtil
+											.newStatus(
+													PlatformUI.PLUGIN_ID,
+													"Could not restore current theme: " + themeId, null)); //$NON-NLS-1$
+				}
+			}
+		}
+		return currentTheme;
+	}
+
+	/**
+	 * Return the default color registry.
+	 *
+	 * @return the default color registry
+	 */
+	public ColorRegistry getDefaultThemeColorRegistry() {
+		return defaultThemeColorRegistry;
+	}
+
+	/**
+	 * Return the default font registry.
+	 *
+	 * @return the default font registry
+	 */
+	public FontRegistry getDefaultThemeFontRegistry() {
+		return defaultThemeFontRegistry;
+	}
+
+	private ITheme getTheme(IThemeDescriptor td) {
+		ITheme theme = (ITheme) themes.get(td);
+		if (theme == null) {
+			theme = new Theme(td);
+			themes.put(td, theme);
+		}
+		return theme;
+	}
+
+	@Override
+	public ITheme getTheme(String id) {
+		if (id.equals(IThemeManager.DEFAULT_THEME)) {
+			return getTheme((IThemeDescriptor) null);
+		}
+
+		IThemeDescriptor td = getThemeRegistry().findTheme(id);
+		if (td == null) {
+			return null;
+		}
+		return getTheme(td);
+	}
+
+	/**
+	 * Answer the IThemeRegistry for the Workbench
+	 */
+	private IThemeRegistry getThemeRegistry() {
+		if (themeRegistry == null) {
+			themeRegistry = WorkbenchPlugin.getDefault().getThemeRegistry();
+		}
+		return themeRegistry;
+	}
+
+	@Override
+	public void removePropertyChangeListener(IPropertyChangeListener listener) {
+		removeListenerObject(listener);
+	}
+
+	@Override
+	public void setCurrentTheme(String id) {
+		ITheme oldTheme = currentTheme;
+		if (WorkbenchThemeManager.getInstance().doSetCurrentTheme(id)) {
+			firePropertyChange(CHANGE_CURRENT_THEME, oldTheme,
+					getCurrentTheme());
+			if (oldTheme != null) {
+				oldTheme.removePropertyChangeListener(currentThemeListener);
+			}
+			currentTheme.addPropertyChangeListener(currentThemeListener);
+
+			// update the preference if required.
+			if (!PrefUtil.getAPIPreferenceStore().getString(
+					IWorkbenchPreferenceConstants.CURRENT_THEME_ID).equals(id)) {
+				PrefUtil.getAPIPreferenceStore().setValue(
+						IWorkbenchPreferenceConstants.CURRENT_THEME_ID, id);
+				PrefUtil.saveAPIPrefs();
+			}
+
+			// update the jface registries
+			{
+				ColorRegistry jfaceColors = JFaceResources.getColorRegistry();
+				ColorRegistry themeColors = currentTheme.getColorRegistry();
+				for (Object themeColorKey : themeColors.getKeySet()) {
+					String key = (String) themeColorKey;
+					jfaceColors.put(key, themeColors.getRGB(key));
+				}
+			}
+			{
+				FontRegistry jfaceFonts = JFaceResources.getFontRegistry();
+				FontRegistry themeFonts = currentTheme.getFontRegistry();
+				for (Object themeFontKey : themeFonts.getKeySet()) {
+					String key = (String) themeFontKey;
+					jfaceFonts.put(key, themeFonts.getFontData(key));
+				}
+			}
+		}
+    }
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/tweaklets/AllowGrabFocus.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/tweaklets/AllowGrabFocus.java
new file mode 100644
index 0000000..64413b2
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/tweaklets/AllowGrabFocus.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal.tweaklets;
+
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IWorkbenchPart;
+
+/**
+ * @since 3.3
+ *
+ */
+public class AllowGrabFocus extends GrabFocus {
+
+	@Override
+	public boolean grabFocusAllowed(IWorkbenchPart part) {
+		return true;
+	}
+
+	@Override
+	public void init(Display display) {
+	}
+
+	@Override
+	public void dispose() {
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/tweaklets/Animations.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/tweaklets/Animations.java
new file mode 100644
index 0000000..984a291
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/tweaklets/Animations.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal.tweaklets;
+
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.internal.RectangleAnimationFeedbackBase;
+import org.eclipse.ui.internal.tweaklets.Tweaklets.TweakKey;
+
+/**
+ * Animation tweaklet base class. Create (and register) a tweaklet
+ * extension derived from this class to provide alternate animation
+ * behavior. Currently only affects animations produced by the new
+ * min / max behavior.
+ *
+ * @since 3.3
+ *
+ */
+public abstract class Animations {
+	public static TweakKey KEY = new Tweaklets.TweakKey(Animations.class);
+
+	static {
+		Tweaklets.setDefault(Animations.KEY, new LegacyAnimations());
+	}
+
+	/** Default c'tor */
+	public Animations() {}
+
+	/**
+	 * Create and return the animation feedback you want to use.
+	 *
+	 * @param shell The shell that the animation will be in
+	 * @return The feedback renderer to use.
+	 */
+	public abstract RectangleAnimationFeedbackBase createFeedback(Shell shell);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/tweaklets/DummyPrefPageEnhancer.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/tweaklets/DummyPrefPageEnhancer.java
new file mode 100644
index 0000000..5e8624c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/tweaklets/DummyPrefPageEnhancer.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2015 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.ui.internal.tweaklets;
+
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * @since 3.8
+ *
+ */
+public class DummyPrefPageEnhancer extends PreferencePageEnhancer {
+
+	@Override
+	public void createContents(Composite parent) {
+	}
+
+	@Override
+	public void setSelection(Object selection) {
+
+	}
+
+	@Override
+	public void performOK() {
+
+	}
+
+	@Override
+	public void performCancel() {
+
+	}
+
+	@Override
+	public void performDefaults() {
+
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/tweaklets/DummyTitlePathUpdater.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/tweaklets/DummyTitlePathUpdater.java
new file mode 100644
index 0000000..96b3c70
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/tweaklets/DummyTitlePathUpdater.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2015 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.ui.internal.tweaklets;
+
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * @since 3.7
+ *
+ */
+public class DummyTitlePathUpdater extends TitlePathUpdater {
+
+	@Override
+	public void updateTitlePath(Shell window, String path) {
+		// do nothing
+	}
+
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/tweaklets/GrabFocus.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/tweaklets/GrabFocus.java
new file mode 100644
index 0000000..1ee62a4
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/tweaklets/GrabFocus.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal.tweaklets;
+
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.internal.tweaklets.Tweaklets.TweakKey;
+
+/**
+ * The tweaklet provider can prevent the workbench page from grabbing focus.
+ *
+ * @since 3.3
+ */
+public abstract class GrabFocus {
+	public static TweakKey KEY = new Tweaklets.TweakKey(GrabFocus.class);
+
+	static {
+		Tweaklets.setDefault(GrabFocus.KEY, new AllowGrabFocus());
+	}
+
+	public abstract boolean grabFocusAllowed(IWorkbenchPart part);
+
+	public abstract void init(Display display);
+
+	public abstract void dispose();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/tweaklets/InterceptContributions.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/tweaklets/InterceptContributions.java
new file mode 100644
index 0000000..188418b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/tweaklets/InterceptContributions.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal.tweaklets;
+
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.internal.tweaklets.Tweaklets.TweakKey;
+
+/**
+ * @since 3.4
+ *
+ */
+public abstract class InterceptContributions {
+	public static TweakKey KEY = new Tweaklets.TweakKey(
+			InterceptContributions.class);
+
+	static {
+		Tweaklets.setDefault(InterceptContributions.KEY,
+				new InterceptContributions() {
+					@Override
+					public IViewPart tweakView(Object viewContribution) {
+						return (IViewPart) viewContribution;
+					}
+					@Override
+					public IEditorPart tweakEditor(Object editorContribution) {
+						return (IEditorPart) editorContribution;
+					}
+				});
+	}
+
+	/** Default constructor */
+	public InterceptContributions() {
+	}
+
+	/**
+	 * Tweak the given view contribution.
+	 *
+	 * @param viewContribution
+	 *            The contributed instance
+	 * @return The view part to use
+	 */
+	public abstract IViewPart tweakView(Object viewContribution);
+
+	/**
+	 * Tweak the given editor contribution.
+	 *
+	 * @param editorContribution
+	 *            The contributed instance
+	 * @return The editor part to use
+	 */
+	public abstract IEditorPart tweakEditor(Object editorContribution);
+
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/tweaklets/LegacyAnimations.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/tweaklets/LegacyAnimations.java
new file mode 100644
index 0000000..14b0f3a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/tweaklets/LegacyAnimations.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal.tweaklets;
+
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.internal.LegacyAnimationFeedback;
+import org.eclipse.ui.internal.RectangleAnimationFeedbackBase;
+
+/**
+ * Return the default (legacy) animation.
+ *
+ * @since 3.3
+ *
+ */
+public class LegacyAnimations extends Animations {
+	/** Default c'tor */
+	public LegacyAnimations() {}
+
+	@Override
+	public RectangleAnimationFeedbackBase createFeedback(Shell shell) {
+		return new LegacyAnimationFeedback(shell, null, null);
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/tweaklets/PreferencePageEnhancer.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/tweaklets/PreferencePageEnhancer.java
new file mode 100644
index 0000000..455af3e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/tweaklets/PreferencePageEnhancer.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2015 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.ui.internal.tweaklets;
+
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.internal.tweaklets.Tweaklets.TweakKey;
+
+/**
+ * @since 3.8
+ *
+ */
+public abstract class PreferencePageEnhancer {
+	public static TweakKey KEY = new Tweaklets.TweakKey(PreferencePageEnhancer.class);
+
+	static {
+		Tweaklets.setDefault(PreferencePageEnhancer.KEY, new DummyPrefPageEnhancer());
+	}
+
+	public abstract void createContents(Composite parent);
+
+	public abstract void setSelection(Object selection);
+
+	public abstract void performOK();
+
+	public abstract void performCancel();
+
+	public abstract void performDefaults();
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/tweaklets/TabBehaviour.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/tweaklets/TabBehaviour.java
new file mode 100644
index 0000000..287062a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/tweaklets/TabBehaviour.java
@@ -0,0 +1,132 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal.tweaklets;
+
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorReference;
+import org.eclipse.ui.internal.IPreferenceConstants;
+import org.eclipse.ui.internal.WorkbenchPage;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.registry.EditorDescriptor;
+import org.eclipse.ui.internal.tweaklets.Tweaklets.TweakKey;
+
+/**
+ * @since 3.3
+ *
+ */
+public abstract class TabBehaviour {
+
+	public static TweakKey KEY = new Tweaklets.TweakKey(TabBehaviour.class);
+
+	static {
+		Tweaklets.setDefault(TabBehaviour.KEY, new TabBehaviourMRU());
+	}
+
+	/**
+	 *
+	 * @return
+	 */
+	public abstract boolean alwaysShowPinAction();
+
+	/**
+	 *
+	 * @param page
+	 * @return
+	 */
+	public abstract IEditorReference findReusableEditor(WorkbenchPage page);
+
+	public abstract IEditorReference reuseInternalEditor(WorkbenchPage page,
+ Object manager,
+			Object editorPresentation,
+			EditorDescriptor desc, IEditorInput input,
+			IEditorReference reusableEditorRef);
+
+	/**
+	 * Does nothing by default. Can be overridden by subclasses.
+	 *
+	 * @param editorReuseGroup
+	 * @param showMultipleEditorTabs
+	 */
+	public void setPreferenceVisibility(Composite editorReuseGroup,
+			Button showMultipleEditorTabs) {
+	}
+
+	/**
+	 * @return
+	 */
+	public boolean autoPinOnDirty() {
+		return false;
+	}
+
+	/**
+	 * @return
+	 */
+	public boolean isPerTabHistoryEnabled() {
+		return false;
+	}
+
+	/**
+	 * @param originalMatchFlags
+	 * @return
+	 */
+	public int getReuseEditorMatchFlags(int originalMatchFlags) {
+		return originalMatchFlags;
+	}
+
+	/**
+	 * @return
+	 */
+	public int getEditorReuseThreshold() {
+		IPreferenceStore store = WorkbenchPlugin.getDefault()
+				.getPreferenceStore();
+		return store.getInt(IPreferenceConstants.REUSE_EDITORS);
+	}
+
+	/**
+	 * @return
+	 */
+	public boolean enableMRUTabVisibility() {
+		return true;
+	}
+
+	public boolean sortEditorListAlphabetically() {
+		return true;
+	}
+
+	public Color createVisibleEditorsColor(Display display, RGB originalForegroundColor, RGB originalBackgroundColor) {
+		return new Color(display, originalForegroundColor);
+	}
+
+	public Font createVisibleEditorsFont(Display display, Font originalFont) {
+		FontData fontData[] = originalFont.getFontData();
+		return new Font(display, fontData);
+	}
+
+	public Font createInvisibleEditorsFont(Display display, Font originalFont) {
+        FontData fontData[] = originalFont.getFontData();
+        // Adding the bold attribute
+        for (FontData element : fontData) {
+			element.setStyle(element.getStyle() | SWT.BOLD);
+		}
+        return new Font(display, fontData);
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/tweaklets/TabBehaviourMRU.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/tweaklets/TabBehaviourMRU.java
new file mode 100644
index 0000000..01db412
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/tweaklets/TabBehaviourMRU.java
@@ -0,0 +1,114 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2016 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ *     Patrik Suzzi <psuzzi@gmail.com> - Bug 490700
+ ******************************************************************************/
+
+package org.eclipse.ui.internal.tweaklets;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorReference;
+import org.eclipse.ui.internal.IPreferenceConstants;
+import org.eclipse.ui.internal.WorkbenchPage;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.e4.compatibility.E4Util;
+import org.eclipse.ui.internal.registry.EditorDescriptor;
+
+/**
+ * @since 3.3
+ *
+ */
+public class TabBehaviourMRU extends TabBehaviour {
+
+	@Override
+	public boolean alwaysShowPinAction() {
+		return false;
+	}
+
+	@Override
+	public IEditorReference findReusableEditor(WorkbenchPage page) {
+		boolean reuse = WorkbenchPlugin.getDefault().getPreferenceStore()
+				.getBoolean(IPreferenceConstants.REUSE_EDITORS_BOOLEAN);
+		if (!reuse) {
+			return null;
+		}
+
+		IEditorReference editors[] = page.getSortedEditors();
+		int length = editors.length;
+		if (length < page.getEditorReuseThreshold()) {
+			return null;
+		} else if (length > page.getEditorReuseThreshold()) {
+			List<IEditorReference> refs = new ArrayList<>();
+			List<IEditorReference> keep = new ArrayList<>(Arrays.asList(editors));
+			int extra = length - page.getEditorReuseThreshold();
+			// look for extra editors that should be closed
+			for (IEditorReference editor : editors) {
+				if (extra == 0) {
+					break;
+				}
+
+				if (editor.isPinned() || editor.isDirty()) {
+					continue;
+				}
+
+				refs.add(editor);
+				extra--;
+			}
+
+			for (IEditorReference ref : refs) {
+				page.closeEditor(ref, false);
+				keep.remove(ref);
+			}
+
+			editors = keep.toArray(new IEditorReference[keep.size()]);
+		}
+
+		IEditorReference dirtyEditor = null;
+
+		// find an editor to reuse, go in reverse due to activation order
+		for (int i = editors.length - 1; i > -1; i--) {
+			IEditorReference editor = editors[i];
+			if (editor.isPinned()) {
+				// skip pinned editors
+				continue;
+			}
+			if (editor.isDirty()) {
+				// record dirty editors
+				if (dirtyEditor == null) {
+					dirtyEditor = editor;
+				}
+				continue;
+			}
+			// an editor is neither pinned nor dirty, use this one
+			return editor;
+		}
+		// can't find anything, return null
+		if (dirtyEditor == null) {
+			return null;
+		}
+
+		return null;
+
+	}
+
+	@Override
+	public IEditorReference reuseInternalEditor(WorkbenchPage page,
+ Object manager,
+			Object editorPresentation,
+			EditorDescriptor desc, IEditorInput input,
+			IEditorReference reusableEditorRef) {
+		E4Util.unsupported("reuseInternalEditor: we reuse nothing"); //$NON-NLS-1$
+		return reusableEditorRef;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/tweaklets/TitlePathUpdater.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/tweaklets/TitlePathUpdater.java
new file mode 100644
index 0000000..f9f9ae4
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/tweaklets/TitlePathUpdater.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2015 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.ui.internal.tweaklets;
+
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.internal.tweaklets.Tweaklets.TweakKey;
+
+/**
+ *
+ * Tweaklet to update the Shell when the active editor is changed
+ *
+ * @since 3.7
+ *
+ */
+public abstract class TitlePathUpdater {
+
+	public static TweakKey KEY = new Tweaklets.TweakKey(TitlePathUpdater.class);
+
+	static {
+		Tweaklets.setDefault(KEY, new DummyTitlePathUpdater());
+	}
+
+	public abstract void updateTitlePath(Shell window, String path);
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/tweaklets/Tweaklets.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/tweaklets/Tweaklets.java
new file mode 100644
index 0000000..aa23d4f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/tweaklets/Tweaklets.java
@@ -0,0 +1,120 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.internal.tweaklets;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+/**
+ * @since 3.3
+ *
+ */
+public class Tweaklets {
+
+	public static class TweakKey {
+		Class tweakClass;
+
+		/**
+		 * @param tweakClass
+		 */
+		public TweakKey(Class tweakClass) {
+			this.tweakClass = tweakClass;
+		}
+
+		@Override
+		public int hashCode() {
+			final int prime = 31;
+			int result = 1;
+			result = prime * result
+					+ ((tweakClass == null) ? 0 : tweakClass.hashCode());
+			return result;
+		}
+
+		@Override
+		public boolean equals(Object obj) {
+			if (this == obj)
+				return true;
+			if (obj == null)
+				return false;
+			if (getClass() != obj.getClass())
+				return false;
+			final TweakKey other = (TweakKey) obj;
+			if (tweakClass == null) {
+				if (other.tweakClass != null)
+					return false;
+			} else if (!tweakClass.equals(other.tweakClass))
+				return false;
+			return true;
+		}
+	}
+
+	private static Map defaults = new HashMap();
+	private static Map tweaklets = new HashMap();
+
+	public static void setDefault(TweakKey definition, Object implementation) {
+		defaults.put(definition, implementation);
+	}
+
+	public static Object get(TweakKey definition) {
+		Object result = tweaklets.get(definition);
+		if (result == null) {
+			result = createTweaklet(definition);
+			if (result == null) {
+				result = getDefault(definition);
+			}
+			Assert.isNotNull(result);
+			tweaklets.put(definition, result);
+		}
+		return result;
+	}
+
+	/**
+	 * @param definition
+	 * @return
+	 */
+	private static Object getDefault(TweakKey definition) {
+		return defaults.get(definition);
+	}
+
+	/**
+	 * @param definition
+	 * @return
+	 */
+	private static Object createTweaklet(TweakKey definition) {
+		IConfigurationElement[] elements = Platform
+				.getExtensionRegistry()
+				.getConfigurationElementsFor("org.eclipse.rap.ui.internalTweaklets"); //$NON-NLS-1$
+		for (IConfigurationElement element : elements) {
+			if (definition.tweakClass.getName().equals(
+					element.getAttribute("definition"))) { //$NON-NLS-1$
+				try {
+					Object tweaklet = element.createExecutableExtension("implementation"); //$NON-NLS-1$
+					tweaklets.put(definition, tweaklet);
+					return tweaklet;
+				} catch (CoreException e) {
+					StatusManager.getManager().handle(
+							StatusUtil.newStatus(IStatus.ERROR, "Error with extension " + element, e), //$NON-NLS-1$
+							StatusManager.LOG);
+				}
+			}
+		}
+		return null;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/util/BundleUtility.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/util/BundleUtility.java
new file mode 100644
index 0000000..72a3b76
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/util/BundleUtility.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2014 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
+ *     Aurelien Pupier <aurelien.pupier@bonitasoft.com> - Bug 450701
+ *******************************************************************************/
+package org.eclipse.ui.internal.util;
+
+import java.net.URL;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.osgi.framework.Bundle;
+
+/**
+ * A set of static methods that provide an nicer interface to common platform
+ * operations related to bundle management.
+ */
+public class BundleUtility {
+	public static boolean isActive(Bundle bundle) {
+		if (bundle == null) {
+			return false;
+		}
+		return bundle.getState() == Bundle.ACTIVE;
+	}
+
+    public static boolean isActivated(Bundle bundle) {
+		if (bundle != null && (bundle.getState() & Bundle.STARTING) != 0)
+    		return WorkbenchPlugin.getDefault().isStarting(bundle);
+        return bundle != null && (bundle.getState() & (Bundle.ACTIVE | Bundle.STOPPING)) != 0;
+    }
+
+    // TODO: needs a better name
+    public static boolean isReady(Bundle bundle) {
+    	return bundle != null && isReady(bundle.getState());
+    }
+
+    public static boolean isReady(int bundleState) {
+    	return (bundleState & (Bundle.RESOLVED | Bundle.STARTING | Bundle.ACTIVE | Bundle.STOPPING)) != 0;
+	}
+
+    public static boolean isActive(String bundleId) {
+		return isActive(Platform.getBundle(bundleId));
+	}
+
+    public static boolean isActivated(String bundleId) {
+        return isActivated(Platform.getBundle(bundleId));
+    }
+
+    public static boolean isReady(String bundleId) {
+        return isReady(Platform.getBundle(bundleId));
+    }
+
+    public static URL find(Bundle bundle, String path) {
+        if (bundle == null) {
+			return null;
+		}
+        return Platform.find(bundle, new Path(path));
+    }
+
+    public static URL find(String bundleId, String path) {
+        return find(Platform.getBundle(bundleId), path);
+    }
+
+    public static void log(String bundleId, Throwable exception) {
+        Bundle bundle = Platform.getBundle(bundleId);
+        if (bundle == null) {
+			return;
+		}
+        IStatus status = new Status(IStatus.ERROR, bundleId, IStatus.ERROR,
+                exception.getMessage() == null ? "" : exception.getMessage(), //$NON-NLS-1$
+                exception);
+        Platform.getLog(bundle).log(status);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/util/ConfigurationElementMemento.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/util/ConfigurationElementMemento.java
new file mode 100644
index 0000000..9bd5873
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/util/ConfigurationElementMemento.java
@@ -0,0 +1,175 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.util;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.ui.IMemento;
+
+public final class ConfigurationElementMemento implements IMemento {
+
+    private IConfigurationElement configurationElement;
+
+    public ConfigurationElementMemento(
+            IConfigurationElement configurationElement) {
+        if (configurationElement == null) {
+			throw new NullPointerException();
+		}
+
+        this.configurationElement = configurationElement;
+    }
+
+    @Override
+	public IMemento createChild(String type) {
+        return null;
+    }
+
+    @Override
+	public IMemento createChild(String type, String id) {
+        return null;
+    }
+
+    @Override
+	public IMemento getChild(String type) {
+        IConfigurationElement[] configurationElements = configurationElement
+                .getChildren(type);
+
+        if (configurationElements != null && configurationElements.length >= 1) {
+			return new ConfigurationElementMemento(configurationElements[0]);
+		}
+
+        return null;
+    }
+
+	@Override
+	public IMemento[] getChildren() {
+		IConfigurationElement[] configurationElements = configurationElement.getChildren();
+
+		return getMementoArray(configurationElements);
+	}
+
+    @Override
+	public IMemento[] getChildren(String type) {
+        IConfigurationElement[] configurationElements = configurationElement
+                .getChildren(type);
+
+        return getMementoArray(configurationElements);
+    }
+
+	private IMemento[] getMementoArray(IConfigurationElement[] configurationElements) {
+		if (configurationElements != null && configurationElements.length > 0) {
+            IMemento mementos[] = new ConfigurationElementMemento[configurationElements.length];
+
+            for (int i = 0; i < configurationElements.length; i++) {
+				mementos[i] = new ConfigurationElementMemento(
+                        configurationElements[i]);
+			}
+
+            return mementos;
+        }
+
+        return new IMemento[0];
+	}
+
+    @Override
+	public Float getFloat(String key) {
+        String string = configurationElement.getAttribute(key);
+
+        if (string != null) {
+			try {
+                return new Float(string);
+            } catch (NumberFormatException eNumberFormat) {
+            }
+		}
+
+        return null;
+    }
+
+    @Override
+	public String getType() {
+        return configurationElement.getName();
+    }
+
+    @Override
+	public String getID() {
+        return configurationElement.getAttribute(TAG_ID);
+    }
+
+    @Override
+	public Integer getInteger(String key) {
+        String string = configurationElement.getAttribute(key);
+
+        if (string != null) {
+			try {
+				return Integer.valueOf(string);
+            } catch (NumberFormatException eNumberFormat) {
+            }
+		}
+
+        return null;
+    }
+
+    @Override
+	public String getString(String key) {
+        return configurationElement.getAttribute(key);
+    }
+
+    @Override
+	public Boolean getBoolean(String key) {
+        String string = configurationElement.getAttribute(key);
+        if (string==null) {
+        	return null;
+        }
+        return Boolean.valueOf(string);
+    }
+
+    @Override
+	public String getTextData() {
+        return configurationElement.getValue();
+    }
+
+    @Override
+	public String[] getAttributeKeys() {
+    	return configurationElement.getAttributeNames();
+    }
+
+    @Override
+	public void putFloat(String key, float value) {
+    }
+
+    @Override
+	public void putInteger(String key, int value) {
+    }
+
+    @Override
+	public void putMemento(IMemento memento) {
+    }
+
+    @Override
+	public void putString(String key, String value) {
+    }
+
+    @Override
+	public void putBoolean(String key, boolean value) {
+    }
+
+    @Override
+	public void putTextData(String data) {
+    }
+
+    public String getContributorName() {
+    	return configurationElement.getContributor().getName();
+    }
+
+    public String getExtensionID() {
+    	return configurationElement.getDeclaringExtension().getUniqueIdentifier();
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/util/Descriptors.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/util/Descriptors.java
new file mode 100644
index 0000000..1d8f017
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/util/Descriptors.java
@@ -0,0 +1,295 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.util;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.jface.resource.ColorDescriptor;
+import org.eclipse.jface.resource.DeviceResourceDescriptor;
+import org.eclipse.jface.resource.DeviceResourceException;
+import org.eclipse.jface.resource.FontDescriptor;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.resource.ResourceManager;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Item;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.ToolItem;
+import org.eclipse.swt.widgets.Widget;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+
+/**
+ * Contains a bunch of helper methods that allow JFace resource descriptors to be passed
+ * directly to SWT widgets without worrying about resource allocation. This class is internal,
+ * but it should be moved into JFace if the pattern is found generally useful. The current
+ * implementation uses a lot of reflection to save repeated code, but this could all be inlined
+ * (without reflection) if performance turns out to be a problem.
+ *
+ * <p>
+ * For example, an Image might be passed to a TableItem as follows:
+ * <p>
+ *
+ * <code>
+ *      ImageDescriptor someDescriptor = ...;
+ *      TableItem someTableItem = ...;
+ *      ResourceManager manager = JFaceResources.getResources();
+ *
+ *      Image actualImage = manager.createImage(someDescriptor);
+ *      someTableItem.setImage(actualImage);
+ *
+ *      // do something with the table item
+ *
+ *      someTableItem.dispose();
+ *      manager.destroyImage(someDescriptor);
+ * </code>
+ *
+ * <p>
+ * It is much more convenient to do the following:
+ * </p>
+ *
+ * <code>
+ *      ImageDescriptor someDescriptor = ...;
+ *      TableItem someTableItem = ...;
+ *
+ *      Descriptors.setImage(someTableItem, someDescriptor);
+ *
+ *      // do something with the table item
+ *
+ *      someTableItem.dispose();
+ * </code>
+ *
+ * <p>
+ * This class tries to behave as if the table item itself had a set method that took a descriptor.
+ * Resource allocation and deallocation happens for free. All the methods are leakproof. That is,
+ * if any images, colors, etc. need to be allocated and passed to the SWT widget, they will be
+ * deallocated automatically when the widget goes away (the implementation hooks a dispose listener
+ * on the widget which cleans up as soon as the widget is disposed).
+ * </p>
+ *
+ * @since 3.1
+ */
+public final class Descriptors {
+    private static final String DISPOSE_LIST = "Descriptors.disposeList"; //$NON-NLS-1$
+
+    private Descriptors() {
+    }
+
+    private static final class ResourceMethod {
+        ResourceMethod(Method m, String id) {
+            method = m;
+            this.id = id;
+        }
+
+        Method method;
+        DeviceResourceDescriptor oldDescriptor;
+        String id;
+
+        public void invoke(Widget toCall, DeviceResourceDescriptor newDescriptor) {
+            if (newDescriptor == oldDescriptor) {
+                return;
+            }
+
+            ResourceManager mgr = JFaceResources.getResources(toCall.getDisplay());
+
+            Object newResource;
+            try {
+                newResource = newDescriptor == null? null : mgr.create(newDescriptor);
+            } catch (DeviceResourceException e1) {
+                WorkbenchPlugin.log(e1);
+                return;
+            }
+
+            try {
+                method.invoke(toCall, new Object[] {newResource});
+            } catch (IllegalArgumentException e) {
+                throw e;
+            } catch (IllegalAccessException e) {
+                WorkbenchPlugin.log(e);
+                return;
+            } catch (InvocationTargetException e) {
+                if (e.getTargetException() instanceof RuntimeException) {
+                    throw (RuntimeException)e.getTargetException();
+                }
+                WorkbenchPlugin.log(e);
+                return;
+            }
+
+            // Deallocate the old image
+            if (oldDescriptor != null) {
+                // Dispose the image
+                mgr.destroy(oldDescriptor);
+            }
+
+            // Remember the new image for next time
+
+            oldDescriptor = newDescriptor;
+        }
+
+        public void dispose() {
+            // Deallocate the old image
+            if (oldDescriptor != null) {
+                ResourceManager mgr = JFaceResources.getResources();
+                // Dispose the image
+                mgr.destroy(oldDescriptor);
+                oldDescriptor = null;
+            }
+
+        }
+    }
+
+    private static DisposeListener disposeListener = e -> doDispose(e.widget);
+
+    // Item //////////////////////////////////////////////////////////////////////////////////
+
+    /**
+     * Sets the image on the given ToolItem. The image will be automatically allocated and
+     * disposed as needed.
+     *
+     * @since 3.1
+     *
+     * @param item
+     * @param descriptor
+     */
+    public static void setImage(Item item, ImageDescriptor descriptor) {
+        callMethod(item, "setImage", descriptor, Image.class); //$NON-NLS-1$
+    }
+
+    // ToolItem //////////////////////////////////////////////////////////////////////////////
+
+    public static void setHotImage(ToolItem item, ImageDescriptor descriptor) {
+        callMethod(item, "setHotImage", descriptor, Image.class); //$NON-NLS-1$
+    }
+
+    public static void setDisabledImage(ToolItem item, ImageDescriptor descriptor) {
+        callMethod(item, "setDisabledImage", descriptor, Image.class); //$NON-NLS-1$
+    }
+
+    // TableItem //////////////////////////////////////////////////////////////////////////////
+
+    public static void setFont(TableItem item, FontDescriptor descriptor) {
+        callMethod(item, "setFont", descriptor, Font.class); //$NON-NLS-1$
+    }
+
+    public static void setBackground(TableItem item, ColorDescriptor descriptor) {
+        callMethod(item, "setBackground", descriptor, Color.class); //$NON-NLS-1$
+    }
+
+    public static void setForeground(TableItem item, ColorDescriptor descriptor) {
+        callMethod(item, "setForeground", descriptor, Color.class); //$NON-NLS-1$
+    }
+
+    // Control ///////////////////////////////////////////////////////////////////////////////
+
+    public static void setBackground(Control control, ColorDescriptor descriptor) {
+        callMethod(control, "setBackground", descriptor, Color.class); //$NON-NLS-1$
+    }
+
+    public static void setForeground(Control control, ColorDescriptor descriptor) {
+        callMethod(control, "setForeground", descriptor, Color.class); //$NON-NLS-1$
+    }
+
+    // Button ///////////////////////////////////////////////////////////////////////////////
+
+    public static void setImage(Button button, ImageDescriptor descriptor) {
+        callMethod(button, "setImage", descriptor, Image.class); //$NON-NLS-1$
+    }
+
+    public static void setImage(Label label, ImageDescriptor descriptor) {
+        callMethod(label, "setImage", descriptor, Image.class); //$NON-NLS-1$
+    }
+
+    private static ResourceMethod getResourceMethod(Widget toCall, String methodName, Class resourceType) throws NoSuchMethodException {
+        Object oldData = toCall.getData(DISPOSE_LIST);
+
+        if (oldData instanceof List) {
+            // Check for existing data
+            for (Iterator iter = ((List)oldData).iterator(); iter.hasNext();) {
+                ResourceMethod method = (ResourceMethod) iter.next();
+
+                if (method.id == methodName) {
+                    return method;
+                }
+            }
+        } if (oldData instanceof ResourceMethod) {
+            if (((ResourceMethod)oldData).id == methodName) {
+                return ((ResourceMethod)oldData);
+            }
+
+            List newList = new ArrayList();
+            newList.add(oldData);
+            oldData = newList;
+            toCall.setData(DISPOSE_LIST, oldData);
+        }
+
+        // At this point, the DISPOSE_LIST data is either null or points to an ArrayList
+
+        Class clazz = toCall.getClass();
+
+        Method method;
+        try {
+            method = clazz.getMethod(methodName, new Class[] {resourceType});
+        } catch (SecurityException e) {
+            throw e;
+        }
+
+        ResourceMethod result = new ResourceMethod(method, methodName);
+
+        if (oldData == null) {
+            toCall.setData(DISPOSE_LIST, result);
+            toCall.addDisposeListener(disposeListener);
+        } else {
+            ((List)oldData).add(result);
+        }
+
+        return result;
+    }
+
+    private static void callMethod(Widget toCall, String methodName, DeviceResourceDescriptor descriptor, Class resourceType) {
+        ResourceMethod method;
+        try {
+            method = getResourceMethod(toCall, methodName, resourceType);
+        } catch (NoSuchMethodException e) {
+            WorkbenchPlugin.log(e);
+            return;
+        }
+
+        method.invoke(toCall, descriptor);
+    }
+
+    private static void doDispose(Widget widget) {
+        Object oldData = widget.getData(DISPOSE_LIST);
+
+        if (oldData instanceof ArrayList) {
+            ArrayList list = ((ArrayList)oldData);
+            ResourceMethod[] data = (ResourceMethod[]) list.toArray(new ResourceMethod[list.size()]);
+
+            // Clear out the images
+            for (ResourceMethod method : data) {
+                method.dispose();
+            }
+        }
+
+        if (oldData instanceof ResourceMethod) {
+            ((ResourceMethod)oldData).dispose();
+        }
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/util/ImageSupport.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/util/ImageSupport.java
new file mode 100644
index 0000000..f94f7fe
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/util/ImageSupport.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2006 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.ui.internal.util;
+
+import java.net.URL;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.PlatformUI;
+
+public final class ImageSupport {
+
+    public static ImageDescriptor getImageDescriptor(String path) {
+        URL url = BundleUtility.find(PlatformUI.PLUGIN_ID, path);
+        return ImageDescriptor.createFromURL(url);
+    }
+
+    private ImageSupport() {
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/util/PrefUtil.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/util/PrefUtil.java
new file mode 100644
index 0000000..90de596
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/util/PrefUtil.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.util;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.osgi.service.prefs.BackingStoreException;
+
+
+/**
+ * Internal utility class to help with getting/setting preferences.
+ * <p>
+ * API preferences are defined in {@link org.eclipse.ui.IWorkbenchPreferenceConstants}
+ * and are obtained from the <code>org.eclipse.ui</code> plug-in's preference store.
+ * </p>
+ * <p>
+ * Internal preferences are defined in {@link org.eclipse.ui.internal.IPreferenceConstants}
+ * and are obtained from the <code>org.eclipse.ui.workbench</code> plug-in's preference store.
+ * </p>
+ *
+ * @since 3.0
+ */
+public class PrefUtil {
+
+    private PrefUtil() {
+        // prevents instantiation
+    }
+
+    /**
+     * Callback interface to obtain and save the UI preference store.
+     */
+    public static interface ICallback {
+        IPreferenceStore getPreferenceStore();
+
+        void savePreferences();
+    }
+
+    private static ICallback uiCallback;
+
+    private static IPreferenceStore uiPreferenceStore;
+
+    /**
+	 * Sets the callback used to obtain and save the UI preference store.
+	 *
+	 * @param callback
+	 *            the callback
+	 */
+    public static final void setUICallback(ICallback callback) {
+        Assert.isTrue(uiCallback == null);
+        uiCallback = callback;
+    }
+
+    /**
+     * Returns the API preference store.
+     *
+     * @return the API preference store
+     */
+    public static IPreferenceStore getAPIPreferenceStore() {
+        if (uiPreferenceStore == null) {
+            Assert.isNotNull(uiCallback);
+            uiPreferenceStore = uiCallback.getPreferenceStore();
+        }
+        return uiPreferenceStore;
+    }
+
+    /**
+     * Returns the internal preference store.
+     *
+     * @return the internal preference store
+     */
+    public static IPreferenceStore getInternalPreferenceStore() {
+        return WorkbenchPlugin.getDefault().getPreferenceStore();
+    }
+
+    /**
+     * Saves both the API and internal preference stores.
+     */
+    public static void savePrefs() {
+        saveAPIPrefs();
+        saveInternalPrefs();
+    }
+
+    /**
+     * Saves the API preference store, if needed.
+     */
+    public static void saveAPIPrefs() {
+        Assert.isNotNull(uiCallback);
+        uiCallback.savePreferences();
+    }
+
+    /**
+     * Saves the internal preference store, if needed.
+     */
+    public static void saveInternalPrefs() {
+		try {
+			InstanceScope.INSTANCE.getNode(WorkbenchPlugin.PI_WORKBENCH).flush();
+		} catch (BackingStoreException e) {
+			WorkbenchPlugin.log(e);
+		}
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/util/Util.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/util/Util.java
new file mode 100644
index 0000000..4cb92b2
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/util/Util.java
@@ -0,0 +1,872 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.SortedSet;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.PlatformObject;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.util.Assert;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+
+public final class Util {
+
+    public final static SortedMap EMPTY_SORTED_MAP = Collections
+            .unmodifiableSortedMap(new TreeMap());
+
+    public final static SortedSet EMPTY_SORTED_SET = Collections
+            .unmodifiableSortedSet(new TreeSet());
+
+    public final static String ZERO_LENGTH_STRING = ""; //$NON-NLS-1$
+
+    public final static String[] EMPTY_STRING_ARRAY = new String[0];
+
+    /**
+     * Ensures that a string is not null. Converts null strings into empty
+     * strings, and leaves any other string unmodified. Use this to help
+     * wrap calls to methods that return null instead of the empty string.
+     * Can also help protect against implementation errors in methods that
+     * are not supposed to return null.
+     *
+     * @param input input string (may be null)
+     * @return input if not null, or the empty string if input is null
+     */
+    public static String safeString(String input) {
+        if (input != null) {
+            return input;
+        }
+
+        return ZERO_LENGTH_STRING;
+    }
+    
+    /**
+     * If it is possible to adapt the given object to the given type, this
+     * returns the adapter. Performs the following checks:
+     * 
+     * <ol>
+     * <li>Returns <code>sourceObject</code> if it is an instance of the
+     * adapter type.</li>
+     * <li>If sourceObject implements IAdaptable, it is queried for adapters.</li>
+     * <li>If sourceObject is not an instance of PlatformObject (which would have
+     * already done so), the adapter manager is queried for adapters</li>
+     * </ol>
+     * 
+     * Otherwise returns null.
+     * 
+     * @param sourceObject
+     *            object to adapt, or null
+     * @param adapterType
+     *            type to adapt to
+     * @return a representation of sourceObject that is assignable to the
+     *         adapter type, or null if no such representation exists
+     */
+    public static Object getAdapter(Object sourceObject, Class adapterType) {
+        Assert.isNotNull(adapterType);
+        if (sourceObject == null) {
+            return null;
+        }
+        if (adapterType.isInstance(sourceObject)) {
+            return sourceObject;
+        }
+
+        if (sourceObject instanceof IAdaptable) {
+            IAdaptable adaptable = (IAdaptable) sourceObject;
+
+            Object result = adaptable.getAdapter(adapterType);
+            if (result != null) {
+                // Sanity-check
+                Assert.isTrue(adapterType.isInstance(result));
+                return result;
+            }
+        } 
+        
+        if (!(sourceObject instanceof PlatformObject)) {
+            Object result = Platform.getAdapterManager().getAdapter(sourceObject, adapterType);
+            if (result != null) {
+                return result;
+            }
+        }
+
+        return null;
+    }
+
+    public static void assertInstance(Object object, Class c) {
+        assertInstance(object, c, false);
+    }
+
+    public static void assertInstance(Object object, Class c, boolean allowNull) {
+        if (object == null && allowNull) {
+			return;
+		}
+
+        if (object == null || c == null) {
+			throw new NullPointerException();
+		} else if (!c.isInstance(object)) {
+			throw new IllegalArgumentException();
+		}
+    }
+
+    public static int compare(boolean left, boolean right) {
+        return left == false ? (right == true ? -1 : 0) : 1;
+    }
+
+    public static int compare(Comparable left, Comparable right) {
+        if (left == null && right == null) {
+			return 0;
+		} else if (left == null) {
+			return -1;
+		} else if (right == null) {
+			return 1;
+		} else {
+			return left.compareTo(right);
+		}
+    }
+
+    public static int compare(Comparable[] left, Comparable[] right) {
+        if (left == null && right == null) {
+			return 0;
+		} else if (left == null) {
+			return -1;
+		} else if (right == null) {
+			return 1;
+		} else {
+            int l = left.length;
+            int r = right.length;
+
+            if (l != r) {
+				return l - r;
+			} else {
+                for (int i = 0; i < l; i++) {
+                    int compareTo = compare(left[i], right[i]);
+
+                    if (compareTo != 0) {
+						return compareTo;
+					}
+                }
+
+                return 0;
+            }
+        }
+    }
+
+    public static int compare(int left, int right) {
+        return left - right;
+    }
+
+    public static int compare(List left, List right) {
+        if (left == null && right == null) {
+			return 0;
+		} else if (left == null) {
+			return -1;
+		} else if (right == null) {
+			return 1;
+		} else {
+            int l = left.size();
+            int r = right.size();
+
+            if (l != r) {
+				return l - r;
+			} else {
+                for (int i = 0; i < l; i++) {
+                    int compareTo = compare((Comparable) left.get(i),
+                            (Comparable) right.get(i));
+
+                    if (compareTo != 0) {
+						return compareTo;
+					}
+                }
+
+                return 0;
+            }
+        }
+    }
+
+    public static int compare(Object left, Object right) {
+        if (left == null && right == null) {
+			return 0;
+		} else if (left == null) {
+			return -1;
+		} else if (right == null) {
+			return 1;
+		} else if (left == right) {
+			return 0;
+		} else {
+			return compare(System.identityHashCode(left), System
+                    .identityHashCode(right));
+		}
+    }
+
+    /**
+     * An optimized comparison that uses identity hash codes to perform the
+     * comparison between non- <code>null</code> objects.
+     *
+     * @param left
+     *            The left-hand side of the comparison; may be <code>null</code>.
+     * @param right
+     *            The right-hand side of the comparison; may be
+     *            <code>null</code>.
+     * @return <code>0</code> if they are the same, <code>-1</code> if left
+     *         is <code>null</code>;<code>1</code> if right is
+     *         <code>null</code>. Otherwise, the left identity hash code
+     *         minus the right identity hash code.
+     */
+    public static final int compareIdentity(Object left, Object right) {
+        if (left == null && right == null) {
+			return 0;
+		} else if (left == null) {
+			return -1;
+		} else if (right == null) {
+			return 1;
+		} else {
+			return System.identityHashCode(left)
+                    - System.identityHashCode(right);
+		}
+    }
+
+	public static void diff(Map<?, ?> left, Map<?, ?> right, Set leftOnly, Set different,
+            Set rightOnly) {
+        if (left == null || right == null || leftOnly == null
+                || different == null || rightOnly == null) {
+			throw new NullPointerException();
+		}
+
+		for (Entry<?, ?> leftEntry : left.entrySet()) {
+			Object key = leftEntry.getKey();
+
+            if (!right.containsKey(key)) {
+				leftOnly.add(key);
+			} else if (!Util.equals(leftEntry.getValue(), right.get(key))) {
+				different.add(key);
+			}
+        }
+
+		for (Object rightKey : right.keySet()) {
+			if (!left.containsKey(rightKey)) {
+				rightOnly.add(rightKey);
+			}
+        }
+    }
+
+    public static void diff(Set left, Set right, Set leftOnly, Set rightOnly) {
+        if (left == null || right == null || leftOnly == null
+                || rightOnly == null) {
+			throw new NullPointerException();
+		}
+
+        Iterator iterator = left.iterator();
+
+        while (iterator.hasNext()) {
+            Object object = iterator.next();
+
+            if (!right.contains(object)) {
+				leftOnly.add(object);
+			}
+        }
+
+        iterator = right.iterator();
+
+        while (iterator.hasNext()) {
+            Object object = iterator.next();
+
+            if (!left.contains(object)) {
+				rightOnly.add(object);
+			}
+        }
+    }
+
+    public static boolean endsWith(List left, List right, boolean equals) {
+        if (left == null || right == null) {
+			return false;
+		} else {
+            int l = left.size();
+            int r = right.size();
+
+            if (r > l || !equals && r == l) {
+				return false;
+			}
+
+            for (int i = 0; i < r; i++) {
+				if (!equals(left.get(l - i - 1), right.get(r - i - 1))) {
+					return false;
+				}
+			}
+
+            return true;
+        }
+    }
+
+    public static boolean endsWith(Object[] left, Object[] right, boolean equals) {
+        if (left == null || right == null) {
+			return false;
+		} else {
+            int l = left.length;
+            int r = right.length;
+
+            if (r > l || !equals && r == l) {
+				return false;
+			}
+
+            for (int i = 0; i < r; i++) {
+				if (!equals(left[l - i - 1], right[r - i - 1])) {
+					return false;
+				}
+			}
+
+            return true;
+        }
+    }
+
+    public static boolean equals(boolean left, boolean right) {
+        return left == right;
+    }
+
+    public static boolean equals(int left, int right) {
+        return left == right;
+    }
+
+    public static boolean equals(Object left, Object right) {
+        return left == null ? right == null : ((right != null) && left
+                .equals(right));
+    }
+
+	/**
+	 * Tests whether two arrays of objects are equal to each other. The arrays
+	 * must not be <code>null</code>, but their elements may be
+	 * <code>null</code>.
+	 *
+	 * @param leftArray
+	 *            The left array to compare; may be <code>null</code>, and
+	 *            may be empty and may contain <code>null</code> elements.
+	 * @param rightArray
+	 *            The right array to compare; may be <code>null</code>, and
+	 *            may be empty and may contain <code>null</code> elements.
+	 * @return <code>true</code> if the arrays are equal length and the
+	 *         elements at the same position are equal; <code>false</code>
+	 *         otherwise.
+	 */
+	public static final boolean equals(final Object[] leftArray,
+			final Object[] rightArray) {
+		if (leftArray == rightArray) {
+			return true;
+		}
+
+		if (leftArray == null) {
+			return (rightArray == null);
+		} else if (rightArray == null) {
+			return false;
+		}
+
+		if (leftArray.length != rightArray.length) {
+			return false;
+		}
+
+		for (int i = 0; i < leftArray.length; i++) {
+			final Object left = leftArray[i];
+			final Object right = rightArray[i];
+			final boolean equal = (left == null) ? (right == null) : (left
+					.equals(right));
+			if (!equal) {
+				return false;
+			}
+		}
+
+		return true;
+	}
+
+    public static int hashCode(boolean b) {
+        return b ? Boolean.TRUE.hashCode() : Boolean.FALSE.hashCode();
+    }
+
+    public static int hashCode(int i) {
+        return i;
+    }
+
+    public static int hashCode(Object object) {
+        return object != null ? object.hashCode() : 0;
+    }
+
+    public static Collection safeCopy(Collection collection, Class c) {
+        return safeCopy(collection, c, false);
+    }
+
+    public static Collection safeCopy(Collection collection, Class c,
+            boolean allowNullElements) {
+        if (collection == null || c == null) {
+			throw new NullPointerException();
+		}
+
+        collection = Collections.unmodifiableCollection(new ArrayList(
+                collection));
+        Iterator iterator = collection.iterator();
+
+        while (iterator.hasNext()) {
+			assertInstance(iterator.next(), c, allowNullElements);
+		}
+
+        return collection;
+    }
+
+    public static List safeCopy(List list, Class c) {
+        return safeCopy(list, c, false);
+    }
+
+    public static List safeCopy(List list, Class c, boolean allowNullElements) {
+        if (list == null || c == null) {
+			throw new NullPointerException();
+		}
+
+        list = Collections.unmodifiableList(new ArrayList(list));
+        Iterator iterator = list.iterator();
+
+        while (iterator.hasNext()) {
+			assertInstance(iterator.next(), c, allowNullElements);
+		}
+
+        return list;
+    }
+
+    public static Map safeCopy(Map map, Class keyClass, Class valueClass) {
+        return safeCopy(map, keyClass, valueClass, false, false);
+    }
+
+    public static Map safeCopy(Map map, Class keyClass, Class valueClass,
+            boolean allowNullKeys, boolean allowNullValues) {
+        if (map == null || keyClass == null || valueClass == null) {
+			throw new NullPointerException();
+		}
+
+        map = Collections.unmodifiableMap(new HashMap(map));
+        Iterator iterator = map.entrySet().iterator();
+
+        while (iterator.hasNext()) {
+            Map.Entry entry = (Map.Entry) iterator.next();
+            assertInstance(entry.getKey(), keyClass, allowNullKeys);
+            assertInstance(entry.getValue(), valueClass, allowNullValues);
+        }
+
+        return map;
+    }
+
+    public static Set safeCopy(Set set, Class c) {
+        return safeCopy(set, c, false);
+    }
+
+    public static Set safeCopy(Set set, Class c, boolean allowNullElements) {
+        if (set == null || c == null) {
+			throw new NullPointerException();
+		}
+
+        set = Collections.unmodifiableSet(new HashSet(set));
+        Iterator iterator = set.iterator();
+
+        while (iterator.hasNext()) {
+			assertInstance(iterator.next(), c, allowNullElements);
+		}
+
+        return set;
+    }
+
+    public static SortedMap safeCopy(SortedMap sortedMap, Class keyClass,
+            Class valueClass) {
+        return safeCopy(sortedMap, keyClass, valueClass, false, false);
+    }
+
+    public static SortedMap safeCopy(SortedMap sortedMap, Class keyClass,
+            Class valueClass, boolean allowNullKeys, boolean allowNullValues) {
+        if (sortedMap == null || keyClass == null || valueClass == null) {
+			throw new NullPointerException();
+		}
+
+        sortedMap = Collections.unmodifiableSortedMap(new TreeMap(sortedMap));
+        Iterator iterator = sortedMap.entrySet().iterator();
+
+        while (iterator.hasNext()) {
+            Map.Entry entry = (Map.Entry) iterator.next();
+            assertInstance(entry.getKey(), keyClass, allowNullKeys);
+            assertInstance(entry.getValue(), valueClass, allowNullValues);
+        }
+
+        return sortedMap;
+    }
+
+    public static SortedSet safeCopy(SortedSet sortedSet, Class c) {
+        return safeCopy(sortedSet, c, false);
+    }
+
+    public static SortedSet safeCopy(SortedSet sortedSet, Class c,
+            boolean allowNullElements) {
+        if (sortedSet == null || c == null) {
+			throw new NullPointerException();
+		}
+
+        sortedSet = Collections.unmodifiableSortedSet(new TreeSet(sortedSet));
+        Iterator iterator = sortedSet.iterator();
+
+        while (iterator.hasNext()) {
+			assertInstance(iterator.next(), c, allowNullElements);
+		}
+
+        return sortedSet;
+    }
+
+    public static boolean startsWith(List left, List right, boolean equals) {
+        if (left == null || right == null) {
+			return false;
+		} else {
+            int l = left.size();
+            int r = right.size();
+
+            if (r > l || !equals && r == l) {
+				return false;
+			}
+
+            for (int i = 0; i < r; i++) {
+				if (!equals(left.get(i), right.get(i))) {
+					return false;
+				}
+			}
+
+            return true;
+        }
+    }
+
+    public static boolean startsWith(Object[] left, Object[] right,
+            boolean equals) {
+        if (left == null || right == null) {
+			return false;
+		} else {
+            int l = left.length;
+            int r = right.length;
+
+            if (r > l || !equals && r == l) {
+				return false;
+			}
+
+            for (int i = 0; i < r; i++) {
+				if (!equals(left[i], right[i])) {
+					return false;
+				}
+			}
+
+            return true;
+        }
+    }
+
+    public static String translateString(ResourceBundle resourceBundle,
+            String key) {
+        return Util.translateString(resourceBundle, key, key, true, true);
+    }
+
+    public static String translateString(ResourceBundle resourceBundle,
+            String key, String string, boolean signal, boolean trim) {
+        if (resourceBundle != null && key != null) {
+			try {
+                final String translatedString = resourceBundle.getString(key);
+
+                if (translatedString != null) {
+					return trim ? translatedString.trim() : translatedString;
+				}
+            } catch (MissingResourceException eMissingResource) {
+                if (signal) {
+					WorkbenchPlugin.log(eMissingResource);
+				}
+            }
+		}
+
+        return trim ? string.trim() : string;
+    }
+
+    public static void arrayCopyWithRemoval(Object [] src, Object [] dst, int idxToRemove) {
+    	if (src == null || dst == null || src.length - 1 != dst.length || idxToRemove < 0 || idxToRemove >= src.length) {
+			throw new IllegalArgumentException();
+		}
+
+    	if (idxToRemove == 0) {
+    		System.arraycopy(src, 1, dst, 0, src.length - 1);
+    	}
+    	else if (idxToRemove == src.length - 1) {
+    		System.arraycopy(src, 0, dst, 0, src.length - 1);
+    	}
+    	else {
+    		System.arraycopy(src, 0, dst, 0, idxToRemove);
+    		System.arraycopy(src, idxToRemove + 1, dst, idxToRemove, src.length - idxToRemove - 1);
+    	}
+    }
+
+    /**
+     * Appends array2 to the end of array1 and returns the result
+     *
+     * @param array1
+     * @param array2
+     * @return
+     * @since 3.1
+     */
+    public static Object[] appendArray(Object[] array1, Object[] array2) {
+        Object[] result = new Object[array1.length + array2.length];
+        System.arraycopy(array1, 0, result, 0, array1.length);
+        System.arraycopy(array2, 0, result, array1.length, array2.length);
+        return result;
+    }
+
+    private Util() {
+    }
+
+	/**
+	 * Returns an interned representation of the given string
+	 * @param string The string to intern
+	 * @return The interned string
+	 */
+	public static String intern(String string) {
+		return string == null ? null : string.intern();
+	}
+
+	/**
+	 * Two {@link String}s presented in a list form.
+	 * This method can be used to form a longer list by providing a list for
+	 * <code>item1</code> and an item to append to the list for
+	 * <code>item2</code>.
+	 *
+	 * @param item1	a string
+	 * @param item2	a string
+	 * @return	a string which presents <code>item1</code> and
+	 * 	<code>item2</code> in a list form.
+	 */
+	public static String createList(String item1, String item2) {
+		return NLS.bind(WorkbenchMessages.get().Util_List, item1, item2);
+	}
+
+	/**
+	 * Creates a {@link String} representing the elements in <code>items</code>
+	 * as a list. This method uses the {@link Object#toString()} method on the
+	 * objects to create them as a String.
+	 * @param items	the List to make into a String
+	 * @return	a string which presents <code>items</code> in String form.
+	 */
+	public static String createList(List items) {
+		String list = null;
+		for (Iterator i = items.iterator(); i.hasNext();) {
+			Object object = i.next();
+			final String string = object == null ? WorkbenchMessages.get().Util_listNull : object.toString();
+			if(list == null) {
+				list = string;
+			} else {
+				list = createList(list, string);
+			}
+		}
+		return safeString(list);
+	}
+
+	/**
+	 * Creates a {@link String} representing the elements in <code>items</code>
+	 * as a list. This method uses the {@link Object#toString()} method on the
+	 * objects to create them as a String.
+	 * @param items	the array to make into a String
+	 * @return	a string which presents <code>items</code> in String form.
+	 */
+	public static String createList(Object[] items) {
+		String list = null;
+		for (Object item : items) {
+			if(list == null) {
+				list = item.toString();
+			} else {
+				list = createList(list, item.toString());
+			}
+		}
+		return safeString(list);
+	}
+
+	/**
+	 * Return the window for the given shell or the currently active window if
+	 * one could not be determined.
+	 *
+	 * @param shellToCheck
+	 *            the shell to search on
+	 * @return the window for the given shell or the currently active window if
+	 *         one could not be determined
+	 * @since 3.2
+	 */
+	public static IWorkbenchWindow getWorkbenchWindowForShell(Shell shellToCheck) {
+		IWorkbenchWindow workbenchWindow = null;
+		while (workbenchWindow == null && shellToCheck != null) {
+			if (shellToCheck.getData() instanceof IWorkbenchWindow) {
+				workbenchWindow = (IWorkbenchWindow) shellToCheck.getData();
+			} else {
+				shellToCheck = (Shell) shellToCheck.getParent();
+			}
+		}
+
+		if (workbenchWindow == null) {
+			workbenchWindow = PlatformUI.getWorkbench()
+					.getActiveWorkbenchWindow();
+		}
+
+		return workbenchWindow;
+	}
+
+	/**
+	 * Return an appropriate shell to parent dialogs on. This will be one of the
+	 * workbench windows (the active one) should any exist. Otherwise
+	 * <code>null</code> is returned.
+	 *
+	 * @return the shell to parent on or <code>null</code> if there is no
+	 *         appropriate shell
+	 * @since 3.3
+	 */
+	public static Shell getShellToParentOn() {
+		IWorkbench workbench = PlatformUI.getWorkbench();
+		IWorkbenchWindow activeWindow = workbench.getActiveWorkbenchWindow();
+		IWorkbenchWindow windowToParentOn = activeWindow == null ? (workbench
+				.getWorkbenchWindowCount() > 0 ? workbench
+				.getWorkbenchWindows()[0] : null) : activeWindow;
+		return windowToParentOn == null ? null : windowToParentOn.getShell();
+	}
+
+	/**
+	 * A String#split(*) replacement that splits on the provided char. No Regex
+	 * involved.
+	 *
+	 * @param src
+	 *            The string to be split
+	 * @param delim
+	 *            The character to split on
+	 * @return An array containing the split. Might be empty, but will not be
+	 *         <code>null</code>.
+	 */
+	public static String[] split(String src, char delim) {
+		if (src == null) {
+			return EMPTY_STRING_ARRAY;
+		}
+
+		if (src.length()==0) {
+			return new String[] { ZERO_LENGTH_STRING };
+		}
+
+		ArrayList result = new ArrayList();
+		int idx = src.indexOf(delim);
+		int lastIdx = 0;
+		while (idx != -1) {
+			result.add(src.substring(lastIdx, idx));
+			lastIdx = idx + 1;
+			if (lastIdx == src.length()) {
+				idx = -1;
+			} else {
+				idx = src.indexOf(delim, lastIdx);
+			}
+		}
+		if (lastIdx < src.length()) {
+			result.add(src.substring(lastIdx));
+		}
+		String[] resultArray = (String[]) result.toArray(new String[result.size()]);
+		boolean allEmpty = true;
+		for (int i = 0; i < resultArray.length && allEmpty; i++) {
+			if (resultArray[i].length()>0) {
+				allEmpty = false;
+			}
+		}
+		if (allEmpty) {
+			return EMPTY_STRING_ARRAY;
+		}
+		return resultArray;
+	}
+
+	/**
+	 * Foundation replacement for String.replaceAll(*).
+	 *
+	 * @param src the starting string.
+	 * @param find the string to find.
+	 * @param replacement the string to replace.
+	 * @return The new string.
+	 * @since 3.3
+	 */
+	public static String replaceAll(String src, String find, String replacement) {
+		return org.eclipse.jface.util.Util.replaceAll(src, find, replacement);
+	}
+
+	/**
+	 * Attempt to load the executable extension from the element/attName. If
+	 * the load fails or the resulting object is not castable to the
+	 * provided classSpec (if any) an error is logged and a null is returned.
+	 *
+	 * @param element The {@link IConfigurationElement} containing the
+	 * executable extension's specification
+	 * @param attName The attribute name of the executable extension
+	 * @param classSpec An optional <code>Class</code> defining the type
+	 * that the loaded Object must be castable to. This is optional to support
+	 * code where the client has a choice of mutually non-castable types to
+	 * choose from.
+	 *
+	 * @return The loaded object which is guaranteed to be
+	 * castable to the given classSpec or null if a failure occurred
+	 */
+	public static Object safeLoadExecutableExtension(IConfigurationElement element,
+			String attName, Class classSpec) {
+		Object loadedEE = null;
+
+		// Load the handler.
+		try {
+			loadedEE = element.createExecutableExtension(attName);
+		} catch (final CoreException e) {
+			// TODO: give more info (eg plugin id)....
+			// Gather formatting info
+			final String classDef = element.getAttribute(attName);
+
+			final String message = "Class load Failure: '" + classDef + "'";  //$NON-NLS-1$//$NON-NLS-2$
+			IStatus status = new Status(IStatus.ERROR,
+					WorkbenchPlugin.PI_WORKBENCH, 0, message, e);
+			WorkbenchPlugin.log(message, status);
+		}
+
+		// Check the loaded object's type
+		if (classSpec != null && loadedEE != null && !classSpec.isInstance(loadedEE)) {
+			// ooops, the loaded class is not castable to the given type
+			final String message = "Loaded class is of incorrect type: expected(" + //$NON-NLS-1$
+				classSpec.getName() + ") got (" + loadedEE.getClass().getName() + ")"; //$NON-NLS-1$ //$NON-NLS-2$
+
+			IllegalArgumentException e = new IllegalArgumentException(message);
+			final IStatus status = new Status(IStatus.ERROR,
+					WorkbenchPlugin.PI_WORKBENCH, 0, message, e);
+			WorkbenchPlugin.log(message, status);
+
+			// This 'failed'
+			loadedEE = null;
+		}
+
+		return loadedEE;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/AbstractExtensionWizardRegistry.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/AbstractExtensionWizardRegistry.java
new file mode 100644
index 0000000..c452541
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/AbstractExtensionWizardRegistry.java
@@ -0,0 +1,191 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.wizards;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.dynamichelpers.ExtensionTracker;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler;
+import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.dialogs.WizardCollectionElement;
+import org.eclipse.ui.internal.dialogs.WorkbenchWizardElement;
+import org.eclipse.ui.internal.registry.WizardsRegistryReader;
+import org.eclipse.ui.internal.util.Util;
+import org.eclipse.ui.wizards.IWizardDescriptor;
+
+/**
+ * Abstract baseclass for wizard registries that listen to extension changes.
+ *
+ * @since 3.1
+ */
+public abstract class AbstractExtensionWizardRegistry extends
+		AbstractWizardRegistry implements IExtensionChangeHandler{
+
+	/**
+	 * Create a new instance of this class.
+	 */
+	public AbstractExtensionWizardRegistry() {
+		super();
+	}
+
+	@Override
+	public void addExtension(IExtensionTracker tracker, IExtension extension) {
+		WizardsRegistryReader reader = new WizardsRegistryReader(getPlugin(),
+				getExtensionPoint());
+		reader.setInitialCollection(getWizardElements());
+		IConfigurationElement[] configurationElements = extension
+				.getConfigurationElements();
+		for (IConfigurationElement configurationElement : configurationElements) {
+			reader.readElement(configurationElement);
+		}
+		// no need to reset the wizard elements - getWizardElements will parse
+		// the
+		// results of the registry reading
+		setWizardElements(reader.getWizardElements());
+		// reregister all object handles - it'd be better to process the deltas
+		// in this case
+		registerWizards(getWizardElements());
+
+		// handle the primary wizards
+		WorkbenchWizardElement[] additionalPrimary = reader.getPrimaryWizards();
+		if (additionalPrimary.length == 0) {
+			return;
+		}
+		IWizardDescriptor[] localPrimaryWizards = getPrimaryWizards();
+		WorkbenchWizardElement[] newPrimary = new WorkbenchWizardElement[additionalPrimary.length
+				+ localPrimaryWizards.length];
+		System.arraycopy(localPrimaryWizards, 0, newPrimary, 0,
+				localPrimaryWizards.length);
+		System.arraycopy(additionalPrimary, 0, newPrimary,
+				localPrimaryWizards.length, additionalPrimary.length);
+		setPrimaryWizards(newPrimary);
+	}
+
+	@Override
+	public void dispose() {
+		super.dispose();
+		PlatformUI.getWorkbench().getExtensionTracker()
+				.unregisterHandler(this);
+	}
+
+	@Override
+	protected void doInitialize() {
+
+		PlatformUI.getWorkbench().getExtensionTracker().registerHandler(this, ExtensionTracker.createExtensionPointFilter(getExtensionPointFilter()));
+
+		WizardsRegistryReader reader = new WizardsRegistryReader(getPlugin(),
+				getExtensionPoint());
+		setWizardElements(reader.getWizardElements());
+		setPrimaryWizards(reader.getPrimaryWizards());
+		registerWizards(getWizardElements());
+	}
+
+	/**
+	 * Return the extension point id that should be used for extension registry
+	 * queries.
+	 *
+	 * @return the extension point id
+	 */
+	protected abstract String getExtensionPoint();
+
+	private IExtensionPoint getExtensionPointFilter() {
+		return Platform.getExtensionRegistry().getExtensionPoint(getPlugin(),
+				getExtensionPoint());
+	}
+
+	/**
+	 * Return the plugin id that should be used for extension registry queries.
+	 *
+	 * @return the plugin id
+	 */
+	protected abstract String getPlugin();
+
+	/**
+	 * Register the object with the workbench tracker.
+	 *
+	 * @param extension
+	 *            the originating extension
+	 * @param object
+	 *            the object to track
+	 */
+	private void register(IExtension extension, Object object) {
+		PlatformUI.getWorkbench().getExtensionTracker().registerObject(
+				extension, object, IExtensionTracker.REF_WEAK);
+	}
+
+	/**
+	 * Register all wizards in the given collection with the extension tracker.
+	 *
+	 * @param collection
+	 *            the collection to register
+	 */
+	private void registerWizards(WizardCollectionElement collection) {
+		registerWizards(collection.getWorkbenchWizardElements());
+
+		for (WizardCollectionElement wizardCollectionElement : collection.getCollectionElements()) {
+			IConfigurationElement configurationElement = wizardCollectionElement.getConfigurationElement();
+			if (configurationElement != null) {
+				register(configurationElement.getDeclaringExtension(),
+						wizardCollectionElement);
+			}
+			registerWizards(wizardCollectionElement);
+		}
+	}
+
+	/**
+	 * Register all wizards in the given array.
+	 *
+	 * @param wizards
+	 *            the wizards to register
+	 */
+	private void registerWizards(WorkbenchWizardElement[] wizards) {
+		for (WorkbenchWizardElement wizard : wizards) {
+			register(wizard.getConfigurationElement()
+					.getDeclaringExtension(), wizard);
+		}
+	}
+
+	@Override
+	public void removeExtension(IExtension extension, Object[] objects) {
+		if (!extension.getExtensionPointUniqueIdentifier().equals(
+				getExtensionPointFilter().getUniqueIdentifier())) {
+			return;
+		}
+		for (Object object : objects) {
+			if (object instanceof WizardCollectionElement) {
+				// TODO: should we move child wizards to the "other" node?
+				WizardCollectionElement collection = (WizardCollectionElement) object;
+				collection.getParentCollection().remove(collection);
+			} else if (object instanceof WorkbenchWizardElement) {
+				WorkbenchWizardElement wizard = (WorkbenchWizardElement) object;
+				WizardCollectionElement parent = wizard.getCollectionElement();
+				if (parent != null) {
+					parent.remove(wizard);
+				}
+				IWizardDescriptor[] primaryWizards = getPrimaryWizards();
+				for (int j = 0; j < primaryWizards.length; j++) {
+					if (primaryWizards[j] == wizard) {
+						WorkbenchWizardElement[] newPrimary = new WorkbenchWizardElement[primaryWizards.length - 1];
+						Util
+								.arrayCopyWithRemoval(primaryWizards,
+										newPrimary, j);
+						primaryWizards = newPrimary;
+						break;
+					}
+				}
+				setPrimaryWizards((WorkbenchWizardElement[]) primaryWizards);
+			}
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/AbstractWizardRegistry.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/AbstractWizardRegistry.java
new file mode 100644
index 0000000..0769f38
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/AbstractWizardRegistry.java
@@ -0,0 +1,128 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.wizards;
+
+import org.eclipse.ui.internal.dialogs.WizardCollectionElement;
+import org.eclipse.ui.internal.dialogs.WorkbenchWizardElement;
+import org.eclipse.ui.wizards.IWizardCategory;
+import org.eclipse.ui.wizards.IWizardDescriptor;
+import org.eclipse.ui.wizards.IWizardRegistry;
+
+/**
+ * Abstract base class for various workbench wizards.
+ *
+ * @since 3.1
+ */
+public abstract class AbstractWizardRegistry implements IWizardRegistry {
+
+	private boolean initialized = false;
+
+	private WorkbenchWizardElement[] primaryWizards;
+
+	private WizardCollectionElement wizardElements;
+
+	/**
+	 * Create a new instance of this class.
+	 */
+	public AbstractWizardRegistry() {
+		super();
+	}
+
+	/**
+	 * Dispose of this registry.
+	 */
+	public void dispose() {
+		primaryWizards = null;
+		wizardElements = null;
+		initialized = false;
+	}
+
+	/**
+	 * Perform initialization of this registry. Should never be called by
+	 * implementations.
+	 */
+	protected abstract void doInitialize();
+
+	@Override
+	public IWizardCategory findCategory(String id) {
+		initialize();
+		return wizardElements.findCategory(id);
+	}
+
+	@Override
+	public IWizardDescriptor findWizard(String id) {
+		initialize();
+		return wizardElements.findWizard(id, true);
+	}
+
+	@Override
+	public IWizardDescriptor[] getPrimaryWizards() {
+		initialize();
+		return primaryWizards;
+	}
+
+	@Override
+	public IWizardCategory getRootCategory() {
+		initialize();
+		return wizardElements;
+	}
+
+	/**
+	 * Return the wizard elements.
+	 *
+	 * @return the wizard elements
+	 */
+	protected WizardCollectionElement getWizardElements() {
+		initialize();
+		return wizardElements;
+	}
+
+	/**
+	 * Read the contents of the registry if necessary.
+	 */
+	protected final synchronized void initialize() {
+		if (isInitialized()) {
+			return;
+		}
+
+		initialized = true;
+		doInitialize();
+	}
+
+	/**
+	 * Return whether the registry has been read.
+	 *
+	 * @return whether the registry has been read
+	 */
+	private boolean isInitialized() {
+		return initialized;
+	}
+
+	/**
+	 * Set the primary wizards.
+	 *
+	 * @param primaryWizards
+	 *            the primary wizards
+	 */
+	protected void setPrimaryWizards(WorkbenchWizardElement[] primaryWizards) {
+		this.primaryWizards = primaryWizards;
+	}
+
+	/**
+	 * Set the wizard elements.
+	 *
+	 * @param wizardElements
+	 *            the wizard elements
+	 */
+	protected void setWizardElements(WizardCollectionElement wizardElements) {
+		this.wizardElements = wizardElements;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/ExportWizardRegistry.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/ExportWizardRegistry.java
new file mode 100644
index 0000000..af630f1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/ExportWizardRegistry.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.wizards;
+
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+
+/**
+ * Registry that contains wizards contributed via the <code>exportWizards</code>
+ * extension point.
+ *
+ * @since 3.1
+ */
+public class ExportWizardRegistry extends AbstractExtensionWizardRegistry {
+
+	private static ExportWizardRegistry singleton;
+
+	/**
+	 * Return the singleton instance of this class.
+	 *
+	 * @return the singleton instance of this class
+	 */
+	public static synchronized ExportWizardRegistry getInstance() {
+		if (singleton == null) {
+			singleton = new ExportWizardRegistry();
+		}
+		return singleton;
+	}
+
+	/**
+	 *
+	 */
+	public ExportWizardRegistry() {
+		super();
+	}
+
+	@Override
+	protected String getExtensionPoint() {
+		return IWorkbenchRegistryConstants.PL_EXPORT;
+	}
+
+	@Override
+	protected String getPlugin() {
+        // RAP [bm]: 
+//      return PlatformUI.PLUGIN_ID;
+        return PlatformUI.PLUGIN_EXTENSION_NAME_SPACE;
+        // RAPEND: [bm] 
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/ImportWizardRegistry.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/ImportWizardRegistry.java
new file mode 100644
index 0000000..36baaec
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/ImportWizardRegistry.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.wizards;
+
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+
+/**
+ * Registry that contains wizards contributed via the <code>importWizards</code>
+ * extension point.
+ *
+ * @since 3.1
+ */
+public class ImportWizardRegistry extends AbstractExtensionWizardRegistry {
+
+	private static ImportWizardRegistry singleton;
+
+	/**
+	 * Return the singleton instance of this class.
+	 *
+	 * @return the singleton instance of this class
+	 */
+	public static synchronized ImportWizardRegistry getInstance() {
+		if (singleton == null) {
+			singleton = new ImportWizardRegistry();
+		}
+		return singleton;
+	}
+
+
+	/**
+	 *
+	 */
+	public ImportWizardRegistry() {
+		super();
+	}
+
+	@Override
+	protected String getExtensionPoint() {
+		return IWorkbenchRegistryConstants.PL_IMPORT;
+	}
+
+	@Override
+	protected String getPlugin() {
+        // RAP [bm]: namespace
+//      return PlatformUI.PLUGIN_ID;
+        return PlatformUI.PLUGIN_EXTENSION_NAME_SPACE;
+        // RAPEND: [bm]
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/NewWizardRegistry.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/NewWizardRegistry.java
new file mode 100644
index 0000000..da0fe54
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/NewWizardRegistry.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.internal.wizards;
+
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+
+/**
+ * Registry that contains wizards contributed via the <code>newWizards</code>
+ * extension point.
+ *
+ * @since 3.1
+ */
+public final class NewWizardRegistry extends AbstractExtensionWizardRegistry {
+
+	private static NewWizardRegistry singleton;
+
+	/**
+	 * Return the singleton instance of this class.
+	 *
+	 * @return the singleton instance of this class
+	 */
+	public static synchronized NewWizardRegistry getInstance() {
+		if (singleton == null) {
+			singleton = new NewWizardRegistry();
+		}
+		return singleton;
+	}
+
+	/**
+	 * Private constructor.
+	 */
+	private NewWizardRegistry() {
+		super();
+	}
+
+	@Override
+	protected String getExtensionPoint() {
+		return IWorkbenchRegistryConstants.PL_NEW;
+	}
+
+	@Override
+	protected String getPlugin() {
+        // RAP [bm]: namespace
+//      return PlatformUI.PLUGIN_ID;
+        return PlatformUI.PLUGIN_EXTENSION_NAME_SPACE;
+        // RAPEND: [bm]
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/preferences/PreferencesContentProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/preferences/PreferencesContentProvider.java
new file mode 100644
index 0000000..8f51144
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/preferences/PreferencesContentProvider.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2015 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.ui.internal.wizards.preferences;
+
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.ui.internal.preferences.PreferenceTransferElement;
+
+/**
+ *
+ * @since 3.6
+ * @author Prakash G.R.
+ */
+public class PreferencesContentProvider implements ITreeContentProvider {
+
+	@Override
+	public Object[] getChildren(Object parentElement) {
+		return null;
+	}
+
+	@Override
+	public Object getParent(Object element) {
+		return null;
+	}
+
+	@Override
+	public boolean hasChildren(Object element) {
+		return false;
+	}
+
+	@Override
+	public Object[] getElements(Object inputElement) {
+		if (inputElement instanceof PreferenceTransferElement[])
+			return (PreferenceTransferElement[]) inputElement;
+		return new PreferenceTransferElement[0];
+	}
+
+	@Override
+	public void dispose() {
+
+	}
+
+	@Override
+	public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+
+	}
+
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/preferences/PreferencesExportWizard.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/preferences/PreferencesExportWizard.java
new file mode 100644
index 0000000..5d7d8ad
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/preferences/PreferencesExportWizard.java
@@ -0,0 +1,102 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.wizards.preferences;
+
+import org.eclipse.e4.core.services.events.IEventBroker;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.ui.IExportWizard;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+
+/**
+ * Standard workbench wizard for exporting preferences from the workspace
+ * to the local file system.
+ * <p>
+ * This class may be instantiated and used without further configuration;
+ * this class is not intended to be subclassed.
+ * </p>
+ * <p>
+ * Example:
+ * <pre>
+ * IWizard wizard = new PreferencesExportWizard();
+ * wizard.init(workbench, selection);
+ * WizardDialog dialog = new WizardDialog(shell, wizard);
+ * dialog.open();
+ * </pre>
+ * During the call to <code>open</code>, the wizard dialog is presented to the
+ * user. When the user hits Finish, the user-selected workspace preferences
+ * are exported to the user-specified location in the local file system,
+ * the dialog closes, and the call to <code>open</code> returns.
+ * </p>
+ *
+ * @since 3.1
+ *
+ */
+public class PreferencesExportWizard extends Wizard implements IExportWizard {
+
+	private static final String EVENT_TOPIC_BASE = "org/eclipse/ui/internal/wizards/preferences/export/"; //$NON-NLS-1$
+
+	public static final String EVENT_EXPORT_BEGIN = EVENT_TOPIC_BASE + "begin"; //$NON-NLS-1$
+
+	public static final String EVENT_EXPORT_END = EVENT_TOPIC_BASE + "end"; //$NON-NLS-1$
+
+    private WizardPreferencesExportPage1 mainPage;
+
+	private IEventBroker eventBroker;
+
+    /**
+     * Creates a wizard for exporting workspace preferences to the local file system.
+     */
+    public PreferencesExportWizard() {
+        IDialogSettings workbenchSettings = WorkbenchPlugin.getDefault().getDialogSettings();
+        IDialogSettings section = workbenchSettings
+                .getSection("PreferencesExportWizard");//$NON-NLS-1$
+        if (section == null) {
+			section = workbenchSettings.addNewSection("PreferencesExportWizard");//$NON-NLS-1$
+		}
+        setDialogSettings(section);
+    }
+
+    @Override
+	public void addPages() {
+        super.addPages();
+        mainPage = new WizardPreferencesExportPage1();
+        addPage(mainPage);
+    }
+
+    @Override
+	public void init(IWorkbench workbench, IStructuredSelection currentSelection) {
+		eventBroker = workbench.getService(IEventBroker.class);
+        setWindowTitle(PreferencesMessages.PreferencesExportWizard_export);
+        setDefaultPageImageDescriptor(WorkbenchImages
+                .getImageDescriptor(IWorkbenchGraphicConstants.IMG_WIZBAN_EXPORT_PREF_WIZ));
+        setNeedsProgressMonitor(true);
+    }
+
+    @Override
+	public boolean performFinish() {
+		sendEvent(EVENT_EXPORT_BEGIN);
+		boolean success = mainPage.finish();
+		sendEvent(EVENT_EXPORT_END);
+		return success;
+    }
+
+	private void sendEvent(String topic) {
+		if (eventBroker != null) {
+			eventBroker.send(topic, null);
+		}
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/preferences/PreferencesImportWizard.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/preferences/PreferencesImportWizard.java
new file mode 100644
index 0000000..cfc0aaa
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/preferences/PreferencesImportWizard.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.internal.wizards.preferences;
+
+import org.eclipse.e4.core.services.events.IEventBroker;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.ui.IImportWizard;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+
+
+/**
+ * Standard workbench wizard for importing resources from the local file system
+ * into the workspace.
+ * <p>
+ * This class may be instantiated and used without further configuration;
+ * this class is not intended to be subclassed.
+ * </p>
+ * <p>
+ * Example:
+ * <pre>
+ * IWizard wizard = new PreferencesImportWizard();
+ * wizard.init(workbench, selection);
+ * WizardDialog dialog = new WizardDialog(shell, wizard);
+ * dialog.open();
+ * </pre>
+ * During the call to <code>open</code>, the wizard dialog is presented to the
+ * user. When the user hits Finish, the user-selected files are imported
+ * into the workspace, the dialog closes, and the call to <code>open</code>
+ * returns.
+ * </p>
+ *
+ * @since 3.1
+ *
+ */
+public class PreferencesImportWizard extends Wizard implements IImportWizard {
+
+	public static final String EVENT_IMPORT_END = "org/eclipse/ui/internal/wizards/preferences/import/end"; //$NON-NLS-1$
+
+    private WizardPreferencesImportPage1 mainPage;
+
+	private IEventBroker eventBroker;
+
+    /**
+     * Creates a wizard for importing resources into the workspace from
+     * the file system.
+     */
+    public PreferencesImportWizard() {
+        IDialogSettings workbenchSettings = WorkbenchPlugin.getDefault().getDialogSettings();
+        IDialogSettings section = workbenchSettings
+                .getSection("PreferencesImportWizard");//$NON-NLS-1$
+        if (section == null) {
+			section = workbenchSettings.addNewSection("PreferencesImportWizard");//$NON-NLS-1$
+		}
+        setDialogSettings(section);
+    }
+
+    @Override
+	public void addPages() {
+        super.addPages();
+        mainPage = new WizardPreferencesImportPage1();
+        addPage(mainPage);
+    }
+
+    @Override
+	public void init(IWorkbench workbench, IStructuredSelection currentSelection) {
+		eventBroker = workbench.getService(IEventBroker.class);
+        setWindowTitle(PreferencesMessages.PreferencesImportWizard_import);
+        setDefaultPageImageDescriptor(WorkbenchImages
+                .getImageDescriptor(IWorkbenchGraphicConstants.IMG_WIZBAN_IMPORT_PREF_WIZ));
+        setNeedsProgressMonitor(true);
+    }
+
+    @Override
+	public boolean performFinish() {
+		boolean success = mainPage.finish();
+		sendEvent(EVENT_IMPORT_END);
+		return success;
+    }
+
+	private void sendEvent(String topic) {
+		if (eventBroker != null) {
+			eventBroker.send(topic, null);
+		}
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/preferences/PreferencesMessages.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/preferences/PreferencesMessages.java
new file mode 100644
index 0000000..f5aaf24
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/preferences/PreferencesMessages.java
@@ -0,0 +1,66 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2015 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 - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.ui.internal.wizards.preferences;
+
+import org.eclipse.osgi.util.NLS;
+
+
+/**
+ * NLS messages class for preferences messages.
+
+ * @since 3.1
+ *
+ */
+public class PreferencesMessages extends NLS {
+	private static final String BUNDLE_NAME = "org.eclipse.ui.internal.wizards.preferences.messages";//$NON-NLS-1$
+
+	public static String WizardPreferences_description;
+	public static String WizardPreferencesPage_noOptionsSelected;
+	public static String WizardPreferences_noSpecificPreferenceDescription;
+
+	public static String PreferencesExportWizard_export;
+	public static String WizardPreferencesExportPage1_exportTitle;
+	public static String WizardPreferencesExportPage1_exportDescription;
+	public static String WizardPreferencesExportPage1_preferences;
+	public static String WizardPreferencesExportPage1_noPrefFile;
+	public static String WizardPreferencesExportPage1_overwrite;
+	public static String WizardPreferencesExportPage1_title;
+	public static String WizardPreferencesExportPage1_all;
+	public static String WizardPreferencesExportPage1_choose;
+	public static String WizardPreferencesExportPage1_file;
+
+	public static String PreferencesExport_error;
+	public static String PreferencesExport_browse;
+	public static String PreferencesExport_createTargetDirectory;
+	public static String PreferencesExport_directoryCreationError;
+	public static String ExportFile_overwriteExisting;
+
+	public static String PreferencesImportWizard_import;
+	public static String WizardPreferencesImportPage1_importTitle;
+	public static String WizardPreferencesImportPage1_importDescription;
+	public static String WizardPreferencesImportPage1_all;
+	public static String WizardPreferencesImportPage1_choose;
+	public static String WizardPreferencesImportPage1_file;
+	public static String WizardPreferencesImportPage1_title;
+	public static String WizardPreferencesImportPage1_invalidPrefFile;
+
+	public static String SelectionDialog_selectLabel;
+	public static String SelectionDialog_deselectLabel;
+
+
+	public static String WizardDataTransfer_existsQuestion;
+	public static String WizardDataTransfer_overwriteNameAndPathQuestion;
+	public static String Question;
+
+	static {
+		// load message values from bundle file
+		NLS.initializeMessages(BUNDLE_NAME, PreferencesMessages.class);
+	}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/preferences/WizardPreferencesExportPage1.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/preferences/WizardPreferencesExportPage1.java
new file mode 100644
index 0000000..081c381
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/preferences/WizardPreferencesExportPage1.java
@@ -0,0 +1,215 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.wizards.preferences;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.IPreferenceFilter;
+import org.eclipse.core.runtime.preferences.IPreferencesService;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.preferences.PreferenceTransferElement;
+
+/**
+ * Page 1 of the base preference export Wizard
+ *
+ * @since 3.1
+ */
+public class WizardPreferencesExportPage1 extends WizardPreferencesPage  {
+
+	// constants
+	private static final String PREFERENCESEXPORTPAGE1 = "preferencesExportPage1"; // //$NON-NLS-1$
+
+	/**
+	 * Create an instance of this class
+	 */
+	protected WizardPreferencesExportPage1(String name) {
+		super(name);
+		setTitle(PreferencesMessages.WizardPreferencesExportPage1_exportTitle);
+		setDescription(PreferencesMessages.WizardPreferencesExportPage1_exportDescription);
+	}
+
+	/**
+	 * Create an instance of this class
+	 */
+	public WizardPreferencesExportPage1() {
+		this(PREFERENCESEXPORTPAGE1);
+	}
+
+	protected String getOutputSuffix() {
+    	return ".epf"; //$NON-NLS-1$
+    }
+
+	/**
+	 * Answer the contents of self's destination specification widget
+	 *
+	 * @return java.lang.String
+	 */
+	@Override
+	protected String getDestinationValue() {
+		String idealSuffix = getOutputSuffix();
+        String destinationText = super.getDestinationValue();
+
+        // only append a suffix if the destination doesn't already have a . in
+        // its last path segment.
+        // Also prevent the user from selecting a directory.  Allowing this will
+        // create a ".epf" file in the directory
+        if (destinationText.length() != 0
+                && !destinationText.endsWith(File.separator)) {
+            int dotIndex = destinationText.lastIndexOf('.');
+            if (dotIndex != -1) {
+				// the last path separator index
+                int pathSepIndex = destinationText.lastIndexOf(File.separator);
+                if (pathSepIndex != -1 && dotIndex < pathSepIndex) {
+                    destinationText += idealSuffix;
+                }
+            } else {
+                destinationText += idealSuffix;
+            }
+        }
+
+        return destinationText;
+    }
+
+
+	@Override
+	protected String getAllButtonText() {
+		return PreferencesMessages.WizardPreferencesExportPage1_all;
+	}
+
+	@Override
+	protected String getChooseButtonText() {
+		return PreferencesMessages.WizardPreferencesExportPage1_choose;
+	}
+
+	/**
+	 * @param composite
+	 */
+	@Override
+	protected void createTransferArea(Composite composite) {
+		createTransfersList(composite);
+		createDestinationGroup(composite);
+		createOptionsGroup(composite);
+	}
+
+	/**
+	 * Answer the string to display in self as the destination type
+	 *
+	 * @return java.lang.String
+	 */
+	@Override
+	protected String getDestinationLabel() {
+		return PreferencesMessages.WizardPreferencesExportPage1_file;
+	}
+
+	/*
+	 * return the PreferenceTransgerElements specified
+	 */
+	@Override
+	protected PreferenceTransferElement[] getTransfers() {
+		PreferenceTransferElement[] elements = super.getTransfers();
+		PreferenceTransferElement[] returnElements = new PreferenceTransferElement[elements.length];
+		IPreferenceFilter[] filters = new IPreferenceFilter[1];
+		IPreferenceFilter[] matches;
+		IPreferencesService service = Platform.getPreferencesService();
+		int count = 0;
+		try {
+			for (PreferenceTransferElement element : elements) {
+				filters[0] = element.getFilter();
+				matches = service.matches((IEclipsePreferences) service.getRootNode().node("instance"), filters); //$NON-NLS-1$
+				if (matches.length > 0) {
+					returnElements[count++] = element;
+				}
+			}
+			elements = new PreferenceTransferElement[count];
+			System.arraycopy(returnElements, 0, elements, 0, count);
+		} catch (CoreException e) {
+			WorkbenchPlugin.log(e.getMessage(), e);
+			return new PreferenceTransferElement[0];
+		}
+		return elements;
+	}
+
+	/**
+	 * @param transfers
+	 * @return <code>true</code> if the transfer was successful, and
+	 *         <code>false</code> otherwise
+	 */
+	@Override
+	protected boolean transfer(IPreferenceFilter[] transfers) {
+		File exportFile = new File(getDestinationValue());
+		if (!ensureTargetIsValid(exportFile)) {
+			return false;
+		}
+		FileOutputStream fos = null;
+		try {
+			if (transfers.length > 0) {
+				try {
+					fos = new FileOutputStream(exportFile);
+				} catch (FileNotFoundException e) {
+					reportException(e);
+					return false;
+				}
+				IPreferencesService service = Platform.getPreferencesService();
+				try {
+					service.exportPreferences(service.getRootNode(), transfers, fos);
+				} catch (CoreException e) {
+					reportException(e);
+					return false;
+				}
+			}
+		} finally {
+			if (fos != null) {
+				try {
+					fos.close();
+				} catch (IOException e) {
+					reportException(e);
+					return false;
+				}
+			}
+		}
+		return true;
+	}
+
+	@Override
+	protected String getFileDialogTitle() {
+		return PreferencesMessages.WizardPreferencesExportPage1_title;
+	}
+
+	@Override
+	protected int getFileDialogStyle() {
+		return SWT.SAVE | SWT.SHEET;
+	}
+
+	@Override
+	protected String getInvalidDestinationMessage() {
+		return PreferencesMessages.WizardPreferencesExportPage1_noPrefFile;
+	}
+
+	@Override
+	protected boolean shouldSaveTransferAll() {
+		return true;
+	}
+
+	private void reportException(Exception e) {
+		Shell shell = getControl().getShell();
+		WorkbenchPlugin.log(e.getMessage(), e);
+		MessageDialog.open(MessageDialog.ERROR, shell, "", e.getLocalizedMessage(), SWT.SHEET); //$NON-NLS-1$
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/preferences/WizardPreferencesImportPage1.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/preferences/WizardPreferencesImportPage1.java
new file mode 100644
index 0000000..51e3f4d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/preferences/WizardPreferencesImportPage1.java
@@ -0,0 +1,241 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.internal.wizards.preferences;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.preferences.IExportedPreferences;
+import org.eclipse.core.runtime.preferences.IPreferenceFilter;
+import org.eclipse.core.runtime.preferences.IPreferencesService;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.preferences.PreferenceTransferElement;
+
+/**
+ * Page 1 of the base preference import Wizard
+ *
+ *
+ * @since 3.1
+ */
+public class WizardPreferencesImportPage1 extends WizardPreferencesPage {
+
+    /**
+     * Create a new instance of the receiver with name pageName.
+     * @param pageName
+     */
+    protected WizardPreferencesImportPage1(String pageName) {
+        super(pageName);
+        setTitle(PreferencesMessages.WizardPreferencesImportPage1_importTitle);
+        setDescription(PreferencesMessages.WizardPreferencesImportPage1_importDescription);
+    }
+
+    /**
+     * Create an instance of this class
+     */
+    public WizardPreferencesImportPage1() {
+        this("preferencesImportPage1");//$NON-NLS-1$
+    }
+
+    @Override
+	protected String getAllButtonText() {
+        return PreferencesMessages.WizardPreferencesImportPage1_all;
+    }
+
+    @Override
+	protected String getChooseButtonText() {
+        return PreferencesMessages.WizardPreferencesImportPage1_choose;
+    }
+
+
+    @Override
+	protected PreferenceTransferElement[] getTransfers() {
+        if (validFromFile()) {
+            FileInputStream fis;
+
+            try {
+                fis = new FileInputStream(getDestinationValue());
+            } catch (FileNotFoundException e) {
+                WorkbenchPlugin.log(e.getMessage(), e);
+                return new PreferenceTransferElement[0];
+            }
+            IPreferencesService service = Platform.getPreferencesService();
+            try {
+                IExportedPreferences prefs;
+                prefs = service.readPreferences(fis);
+                PreferenceTransferElement[] transfers = super.getTransfers();
+                IPreferenceFilter[] filters = new IPreferenceFilter[transfers.length];
+                for (int i = 0; i < transfers.length; i++) {
+                    PreferenceTransferElement transfer = transfers[i];
+                    filters[i] = transfer.getFilter();
+                }
+                IPreferenceFilter[] matches = service.matches(prefs, filters);
+                PreferenceTransferElement[] returnTransfers = new PreferenceTransferElement[matches.length];
+                int index = 0;
+                for (IPreferenceFilter filter : matches) {
+                    for (PreferenceTransferElement element : transfers) {
+                        if (element.getFilter().equals(filter)) {
+							returnTransfers[index++] = element;
+						}
+                    }
+                }
+
+                PreferenceTransferElement[] destTransfers = new PreferenceTransferElement[index];
+                System.arraycopy(returnTransfers, 0, destTransfers, 0, index);
+                return destTransfers;
+            } catch (CoreException e) {
+            	//Do not log core exceptions, they indicate the chosen file is not valid
+                //WorkbenchPlugin.log(e.getMessage(), e);
+            } finally {
+                try {
+                    fis.close();
+                } catch (IOException e) {
+                    WorkbenchPlugin.log(e.getMessage(), e);
+                }
+            }
+        }
+
+        return new PreferenceTransferElement[0];
+    }
+
+    /**
+     * Return whether or not the file is valid.
+     * @return <code>true</code> of the file is an existing
+     * file and not a directory
+     */
+    private boolean validFromFile() {
+        File fromFile = new File(getDestinationValue());
+        return fromFile.exists() && !fromFile.isDirectory();
+    }
+
+    @Override
+	protected void setPreferenceTransfers() {
+    	super.setPreferenceTransfers();
+
+		if (validFromFile()
+				&& (transfersTree.getViewer().getTree().getItemCount() == 0)) {
+			descText
+					.setText(PreferencesMessages.WizardPreferences_noSpecificPreferenceDescription);
+		} else {
+			descText.setText(""); //$NON-NLS-1$
+		}
+	}
+
+    @Override
+	protected void createTransferArea(Composite composite) {
+        createDestinationGroup(composite);
+        createTransfersList(composite);
+    }
+
+    /**
+     * Answer the string to display in self as the destination type
+     *
+     * @return java.lang.String
+     */
+    @Override
+	protected String getDestinationLabel() {
+        return PreferencesMessages.WizardPreferencesImportPage1_file;
+    }
+
+    /**
+     * @param filters
+     * @return <code>true</code> if the transfer was succesful, and
+     *         <code>false</code> otherwise
+     */
+    @Override
+	protected boolean transfer(IPreferenceFilter[] filters) {
+        File importFile = new File(getDestinationValue());
+        FileInputStream fis = null;
+        try {
+            if (filters.length > 0) {
+                try {
+                    fis = new FileInputStream(importFile);
+                } catch (FileNotFoundException e) {
+                    WorkbenchPlugin.log(e.getMessage(), e);
+					MessageDialog.open(MessageDialog.ERROR, getControl().getShell(), "", //$NON-NLS-1$
+							e.getLocalizedMessage(),
+							SWT.SHEET);
+                    return false;
+                }
+                IPreferencesService service = Platform.getPreferencesService();
+                try {
+                    IExportedPreferences prefs = service.readPreferences(fis);
+
+                    service.applyPreferences(prefs, filters);
+                } catch (CoreException e) {
+                    WorkbenchPlugin.log(e.getMessage(), e);
+					MessageDialog.open(MessageDialog.ERROR, getControl()
+							.getShell(), "", e.getLocalizedMessage(), //$NON-NLS-1$
+							SWT.SHEET);
+                    return false;
+                }
+            }
+        } finally {
+            if (fis != null) {
+				try {
+                    fis.close();
+                } catch (IOException e) {
+                	WorkbenchPlugin.log(e.getMessage(), e);
+					MessageDialog.open(MessageDialog.ERROR, getControl()
+							.getShell(), "", e.getLocalizedMessage(), //$NON-NLS-1$
+							SWT.SHEET);
+                }
+			}
+        }
+        return true;
+    }
+
+    /**
+     * Handle events and enablements for widgets in this page
+     *
+     * @param e
+     *            Event
+     */
+    @Override
+	public void handleEvent(Event e) {
+        if (e.widget == destinationNameField) {
+			setPreferenceTransfers();
+		}
+
+        super.handleEvent(e);
+    }
+
+    @Override
+	protected String getFileDialogTitle(){
+		return PreferencesMessages.WizardPreferencesImportPage1_title;
+	}
+
+	@Override
+	protected int getFileDialogStyle() {
+		return SWT.OPEN | SWT.SHEET;
+	}
+
+	@Override
+	protected boolean validDestination() {
+		return super.validDestination() && validFromFile();
+	}
+
+	@Override
+	protected String getInvalidDestinationMessage() {
+		return PreferencesMessages.WizardPreferencesImportPage1_invalidPrefFile;
+	}
+
+	@Override
+	protected boolean shouldSaveTransferAll() {
+		return false;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/preferences/WizardPreferencesPage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/preferences/WizardPreferencesPage.java
new file mode 100644
index 0000000..6a1bbfb
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/preferences/WizardPreferencesPage.java
@@ -0,0 +1,995 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2016 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
+ *     Patrik Suzzi <psuzzi@gmail.com> - Bug 490700
+ *******************************************************************************/
+package org.eclipse.ui.internal.wizards.preferences;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.preferences.ConfigurationScope;
+import org.eclipse.core.runtime.preferences.IPreferenceFilter;
+import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.CheckboxTreeViewer;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.rap.rwt.widgets.FileUpload;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.Widget;
+import org.eclipse.ui.dialogs.FilteredTree;
+import org.eclipse.ui.dialogs.IOverwriteQuery;
+import org.eclipse.ui.dialogs.PatternFilter;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.preferences.PreferenceTransferElement;
+import org.eclipse.ui.internal.preferences.PreferenceTransferManager;
+import org.eclipse.ui.model.WorkbenchLabelProvider;
+
+/**
+ * Base class for preference export/import pages.
+ *
+ * @since 3.1
+ */
+public abstract class WizardPreferencesPage extends WizardPage implements
+		Listener, IOverwriteQuery {
+
+	// widgets
+	protected Combo destinationNameField;
+
+	private Button destinationBrowseButton;
+
+	private Button overwriteExistingFilesCheckbox;
+
+	protected FilteredTree transfersTree;
+
+	protected Text descText;
+
+	private Composite buttonComposite;
+
+	private Button transferAllButton;
+
+	private Group group;
+
+	private CheckboxTreeViewer viewer;
+
+	private Button selectAllButton;
+
+	private Button deselectAllButton;
+
+	// dialog store id constants
+	private static final String STORE_DESTINATION_NAMES_ID = "WizardPreferencesExportPage1.STORE_DESTINATION_NAMES_ID";//$NON-NLS-1$
+
+	private static final String STORE_OVERWRITE_EXISTING_FILES_ID = "WizardPreferencesExportPage1.STORE_OVERWRITE_EXISTING_FILES_ID";//$NON-NLS-1$
+
+	private static final String TRANSFER_ALL_PREFERENCES_ID = "WizardPreferencesExportPage1.EXPORT_ALL_PREFERENCES_ID"; //$NON-NLS-1$
+
+	private static final String TRANSFER_PREFERENCES_NAMES_ID = "WizardPreferencesExportPage1.TRANSFER_PREFERENCES_NAMES_ID"; //$NON-NLS-1$
+
+	private PreferenceTransferElement[] transfers;
+
+	private String currentMessage;
+
+	private static final String STORE_DESTINATION_ID = null;
+
+	protected static final int COMBO_HISTORY_LENGTH = 5;
+
+
+	/**
+	 * @param pageName
+	 */
+	protected WizardPreferencesPage(String pageName) {
+		super(pageName);
+	}
+
+	/**
+	 * Creates a new button with the given id.
+	 * <p>
+	 * The <code>Dialog</code> implementation of this framework method creates
+	 * a standard push button, registers for selection events including button
+	 * presses and registers default buttons with its shell. The button id is
+	 * stored as the buttons client data. Note that the parent's layout is
+	 * assumed to be a GridLayout and the number of columns in this layout is
+	 * incremented. Subclasses may override.
+	 * </p>
+	 *
+	 * @param parent
+	 *            the parent composite
+	 * @param id
+	 *            the id of the button (see <code>IDialogConstants.*_ID</code>
+	 *            constants for standard dialog button ids)
+	 * @param label
+	 *            the label from the button
+	 * @param defaultButton
+	 *            <code>true</code> if the button is to be the default button,
+	 *            and <code>false</code> otherwise
+	 */
+	protected Button createButton(Composite parent, int id, String label,
+			boolean defaultButton) {
+		// increment the number of columns in the button bar
+		((GridLayout) parent.getLayout()).numColumns++;
+
+		Button button = new Button(parent, SWT.PUSH);
+		button.setFont(parent.getFont());
+
+		setButtonLayoutData(button);
+
+		button.setData(Integer.valueOf(id));
+		button.setText(label);
+
+		if (defaultButton) {
+			Shell shell = parent.getShell();
+			if (shell != null) {
+				shell.setDefaultButton(button);
+			}
+			button.setFocus();
+		}
+		return button;
+	}
+
+	/**
+	 * Add the passed value to self's destination widget's history
+	 *
+	 * @param value
+	 *            java.lang.String
+	 */
+	protected void addDestinationItem(String value) {
+		destinationNameField.add(value);
+	}
+
+	@Override
+	public void createControl(Composite parent) {
+		initializeDialogUnits(parent);
+		Composite composite = new Composite(parent, SWT.NULL);
+		composite.setLayout(new GridLayout());
+		composite.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_FILL
+				| GridData.HORIZONTAL_ALIGN_FILL));
+
+
+		createTransferArea(composite);
+		setPreferenceTransfers();
+
+		restoreWidgetValues();
+		// updateWidgetEnablements();
+
+		// can not finish initially, but don't want to start with an error
+		// message either
+		if (!(validDestination() && validateOptionsGroup() && validateSourceGroup())) {
+			setPageComplete(false);
+		}
+
+		setControl(composite);
+
+		giveFocusToDestination();
+		Dialog.applyDialogFont(composite);
+	}
+
+	/**
+	 * @param composite
+	 */
+	protected abstract void createTransferArea(Composite composite);
+
+	/**
+	 * Validate the destination group.
+	 * @return <code>true</code> if the group is valid. If
+	 * not set the error message and return <code>false</code>.
+	 */
+	protected boolean validateDestinationGroup() {
+		if (!validDestination()) {
+			currentMessage = getInvalidDestinationMessage();
+			return false;
+		}
+
+		return true;
+	}
+
+	/**
+	 * Return the message that indicates an invalid destination.
+	 * @return String
+	 */
+	abstract protected String getInvalidDestinationMessage();
+
+	private String getNoOptionsMessage() {
+		return PreferencesMessages.WizardPreferencesPage_noOptionsSelected;
+	}
+
+	protected boolean validDestination() {
+		File file = new File(getDestinationValue());
+		return !(file.getPath().length() <= 0 || file.isDirectory());
+	}
+
+	protected void setPreferenceTransfers() {
+		PreferenceTransferElement[] transfers = getTransfers();
+		viewer.setInput(transfers);
+	}
+
+	/*
+	 * return the PreferenceTransgerElements specified
+	 */
+	protected PreferenceTransferElement[] getTransfers() {
+		if (transfers == null) {
+			transfers = PreferenceTransferManager.getPreferenceTransfers();
+		}
+		return transfers;
+	}
+
+	/**
+	 * @param composite
+	 */
+	protected void createTransfersList(Composite composite) {
+
+		transferAllButton = new Button(composite, SWT.CHECK);
+		transferAllButton.setText(getAllButtonText());
+
+		group = new Group(composite, SWT.NONE);
+		GridData groupData = new GridData(GridData.FILL_BOTH);
+		groupData.horizontalSpan = 2;
+//		groupData.horizontalIndent = LayoutConstants.getIndent();
+		Object compositeLayout = composite.getLayout();
+		if (compositeLayout instanceof GridLayout) {
+			groupData.horizontalIndent -= ((GridLayout) compositeLayout).marginWidth;
+			groupData.horizontalIndent -= ((GridLayout) compositeLayout).marginLeft;
+		}
+		group.setLayoutData(groupData);
+
+		GridLayout layout = new GridLayout();
+		group.setLayout(layout);
+
+		transfersTree = createFilteredTree(group);
+
+		transfersTree.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+		viewer = (CheckboxTreeViewer) transfersTree.getViewer();
+		viewer.setContentProvider(new PreferencesContentProvider());
+		viewer.setLabelProvider(new WorkbenchLabelProvider());
+
+		Label description = new Label(group, SWT.NONE);
+		description.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+		description.setText(PreferencesMessages.WizardPreferences_description);
+
+		descText = new Text(group, SWT.V_SCROLL | SWT.READ_ONLY
+				| SWT.BORDER | SWT.WRAP);
+		GridData descriptionData = new GridData(GridData.FILL_BOTH);
+		descriptionData.heightHint = convertHeightInCharsToPixels(3);
+		descText.setLayoutData(descriptionData);
+
+		transferAllButton.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+    			if (transferAllButton.getSelection()) {
+    				viewer.setAllChecked(false);
+    			}
+    			updateEnablement();
+    			updatePageCompletion();
+            }
+		});
+
+		viewer.addSelectionChangedListener(event -> updateDescription());
+
+		viewer.addCheckStateListener(event -> {
+			transferAllButton.setSelection(false);
+			updateEnablement();
+			updatePageCompletion();
+		});
+
+		addSelectionButtons(group);
+
+	}
+
+	protected void updateDescription() {
+		IStructuredSelection selection = viewer.getStructuredSelection();
+		String desc = ""; //$NON-NLS-1$
+		if (!selection.isEmpty()) {
+			Object element = selection.getFirstElement();
+			if ((element instanceof PreferenceTransferElement)) {
+				desc = ((PreferenceTransferElement) element).getDescription();
+			}
+		}
+		descText.setText(desc);
+	}
+
+	private FilteredTree createFilteredTree(Group group) {
+		int style = SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER;
+		FilteredTree transfersTree = new FilteredTree(group, style,
+				new PatternFilter(), true) {
+			@Override
+			protected TreeViewer doCreateTreeViewer(Composite parent, int style) {
+				return new CheckboxTreeViewer(parent, style);
+			}
+		};
+		return transfersTree;
+	}
+
+	protected abstract String getChooseButtonText();
+
+	protected abstract String getAllButtonText();
+
+	/**
+	 * Add the selection and deselection buttons to the composite.
+	 *
+	 * @param composite
+	 *            org.eclipse.swt.widgets.Composite
+	 */
+	private void addSelectionButtons(Composite composite) {
+		Font parentFont = composite.getFont();
+		buttonComposite = new Composite(composite, SWT.NONE);
+		GridLayout layout = new GridLayout();
+		layout.numColumns = 2;
+		buttonComposite.setLayout(layout);
+		GridData data = new GridData(GridData.GRAB_HORIZONTAL);
+		data.grabExcessHorizontalSpace = true;
+		buttonComposite.setLayoutData(data);
+		buttonComposite.setFont(parentFont);
+
+		selectAllButton = new Button(buttonComposite, SWT.PUSH);
+		selectAllButton.setText(PreferencesMessages.SelectionDialog_selectLabel);
+		selectAllButton.setData(Integer.valueOf(IDialogConstants.SELECT_ALL_ID));
+		setButtonLayoutData(selectAllButton);
+
+		SelectionListener listener = new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+    			viewer.setAllChecked(true);
+    			updatePageCompletion();
+            }
+		};
+		selectAllButton.addSelectionListener(listener);
+		selectAllButton.setFont(parentFont);
+
+		deselectAllButton = new Button(buttonComposite, SWT.PUSH);
+		deselectAllButton.setText(PreferencesMessages.SelectionDialog_deselectLabel);
+		deselectAllButton.setData(Integer.valueOf(IDialogConstants.DESELECT_ALL_ID));
+		setButtonLayoutData(deselectAllButton);
+
+		listener = new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+    			viewer.setAllChecked(false);
+    			updatePageCompletion();
+            }
+		};
+		deselectAllButton.addSelectionListener(listener);
+		deselectAllButton.setFont(parentFont);
+	}
+
+	/**
+	 * @param bool
+	 */
+	protected void setAllChecked(boolean bool) {
+		transferAllButton.setSelection(false);
+	}
+
+	/**
+	 * Create the export destination specification widgets
+	 *
+	 * @param parent
+	 *            org.eclipse.swt.widgets.Composite
+	 */
+	protected void createDestinationGroup(Composite parent) {
+		// destination specification group
+		Composite destinationSelectionGroup = new Composite(parent, SWT.NONE);
+		GridLayout layout = new GridLayout();
+		layout.numColumns = 3;
+		destinationSelectionGroup.setLayout(layout);
+		destinationSelectionGroup.setLayoutData(new GridData(
+				GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_FILL));
+
+		Label dest = new Label(destinationSelectionGroup, SWT.NONE);
+		dest.setText(getDestinationLabel());
+
+		// destination name entry field
+		destinationNameField = new Combo(destinationSelectionGroup, SWT.SINGLE
+				| SWT.BORDER);
+		destinationNameField.addListener(SWT.Modify, this);
+		destinationNameField.addListener(SWT.Selection, this);
+		GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL
+				| GridData.GRAB_HORIZONTAL);
+		destinationNameField.setLayoutData(data);
+
+		// destination browse button
+		destinationBrowseButton = new Button(destinationSelectionGroup,
+				SWT.PUSH);
+		destinationBrowseButton
+				.setText(PreferencesMessages.PreferencesExport_browse);
+		setButtonLayoutData(destinationBrowseButton);
+		destinationBrowseButton.addListener(SWT.Selection, this);
+
+		new Label(parent, SWT.NONE); // vertical spacer
+	}
+
+	/**
+	 * Create the export options specification widgets.
+	 *
+	 * @param parent
+	 *            org.eclipse.swt.widgets.Composite
+	 */
+	protected void createOptionsGroup(Composite parent) {
+		// options group
+
+		Composite optionsGroup = new Composite(parent, SWT.NONE);
+		GridLayout layout = new GridLayout();
+		layout.marginHeight = 0;
+		optionsGroup.setLayout(layout);
+		optionsGroup.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL
+				| GridData.GRAB_HORIZONTAL));
+
+		// overwrite... checkbox
+		overwriteExistingFilesCheckbox = new Button(optionsGroup, SWT.CHECK
+				| SWT.LEFT);
+		overwriteExistingFilesCheckbox
+				.setText(PreferencesMessages.ExportFile_overwriteExisting);
+
+	}
+
+	/**
+	 * Attempts to ensure that the specified directory exists on the local file
+	 * system. Answers a boolean indicating success.
+	 *
+	 * @return boolean
+	 * @param directory
+	 *            java.io.File
+	 */
+	protected boolean ensureDirectoryExists(File directory) {
+		if (!directory.exists()) {
+			if (!queryYesNoQuestion(PreferencesMessages.PreferencesExport_createTargetDirectory)) {
+				return false;
+			}
+
+			if (!directory.mkdirs()) {
+				MessageDialog
+						.open(
+								MessageDialog.ERROR,
+								getContainer().getShell(),
+								PreferencesMessages.PreferencesExport_error,
+								PreferencesMessages.PreferencesExport_directoryCreationError,
+								SWT.SHEET);
+				return false;
+			}
+		}
+		return true;
+	}
+
+	/**
+	 * Displays a Yes/No question to the user with the specified message and
+	 * returns the user's response.
+	 *
+	 * @param message
+	 *            the question to ask
+	 * @return <code>true</code> for Yes, and <code>false</code> for No
+	 */
+	protected boolean queryYesNoQuestion(String message) {
+		MessageDialog dialog = new MessageDialog(getContainer().getShell(),
+				PreferencesMessages.Question, (Image) null, message,
+				MessageDialog.NONE, new String[] { IDialogConstants.get().YES_LABEL,
+				                                   IDialogConstants.get().NO_LABEL }, 0) {
+			@Override
+			protected int getShellStyle() {
+				return super.getShellStyle() | SWT.SHEET;
+			}
+		};
+		// ensure yes is the default
+
+		return dialog.open() == 0;
+	}
+
+	/**
+	 * If the target for export does not exist then attempt to create it. Answer
+	 * a boolean indicating whether the target exists (ie.- if it either
+	 * pre-existed or this method was able to create it)
+	 *
+	 * @return boolean
+	 */
+	protected boolean ensureTargetIsValid(File file) {
+		if (file.exists()) {
+			if (!getOverwriteExisting()) {
+				String msg = NLS
+						.bind(
+								PreferencesMessages.WizardPreferencesExportPage1_overwrite,
+								file.getAbsolutePath());
+				if (!queryYesNoQuestion(msg)) {
+					return false;
+				}
+			}
+			file.delete();
+		} else if (!file.isDirectory()) {
+			File parent = file.getParentFile();
+			if (parent != null) {
+				file.getParentFile().mkdirs();
+			}
+		}
+		return true;
+	}
+
+	protected void saveWidgetValues() {
+
+		IDialogSettings settings = getDialogSettings();
+		if (settings != null) {
+			String[] directoryNames = settings
+					.getArray(STORE_DESTINATION_NAMES_ID);
+			if (directoryNames == null) {
+				directoryNames = new String[0];
+			}
+
+			directoryNames = addToHistory(directoryNames, getDestinationValue());
+			settings.put(STORE_DESTINATION_NAMES_ID, directoryNames);
+			String current = getDestinationValue();
+			if (current != null && !current.equals("")) { //$NON-NLS-1$
+				settings.put(STORE_DESTINATION_ID, current);
+			}
+			// options
+			if (overwriteExistingFilesCheckbox != null) {
+				settings.put(STORE_OVERWRITE_EXISTING_FILES_ID,
+						overwriteExistingFilesCheckbox.getSelection());
+			}
+
+			if (shouldSaveTransferAll()) {
+
+				boolean transferAll = getTransferAll();
+				settings.put(TRANSFER_ALL_PREFERENCES_ID, transferAll);
+				if (!transferAll) {
+					Object[] elements = viewer.getCheckedElements();
+					String[] preferenceIds = new String[elements.length];
+					for (int i = 0; i < elements.length; i++) {
+						PreferenceTransferElement element = (PreferenceTransferElement) elements[i];
+						preferenceIds[i] = element.getID();
+					}
+					settings.put(TRANSFER_PREFERENCES_NAMES_ID, preferenceIds);
+				}
+			}
+
+		}
+	}
+
+	/**
+	 * The Finish button was pressed. Try to do the required work now and answer
+	 * a boolean indicating success. If false is returned then the wizard will
+	 * not close.
+	 *
+	 * @return boolean
+	 */
+	public boolean finish() {
+		// about to invoke the operation so save our state
+		saveWidgetValues();
+
+		IPreferenceFilter[] transfers = null;
+
+		if (getTransferAll()) {
+			// export all
+			transfers = new IPreferenceFilter[1];
+
+			// For export all create a preference filter that can export
+			// all nodes of the Instance and Configuration scopes
+			transfers[0] = new IPreferenceFilter() {
+
+				@Override
+				public String[] getScopes() {
+					return new String[] { InstanceScope.SCOPE,
+							ConfigurationScope.SCOPE };
+				}
+
+				@Override
+				public Map getMapping(String scope) {
+					return null;
+				}
+			};
+		} else {
+			transfers = getFilters();
+		}
+
+		boolean success = transfer(transfers);
+		// if it was a successful tranfer then store the name of the file to use
+		// it on the next export
+		if (success) {
+			saveWidgetValues();
+		}
+		return success;
+	}
+
+	/**
+	 * @return the preference transfer filters
+	 */
+	protected IPreferenceFilter[] getFilters() {
+		IPreferenceFilter[] filters = null;
+		PreferenceTransferElement[] transferElements;
+		transferElements = getPreferenceTransferElements();
+		if (transferElements != null) {
+			filters = new IPreferenceFilter[transferElements.length];
+			for (int j = 0; j < transferElements.length; j++) {
+				PreferenceTransferElement element = transferElements[j];
+				try {
+					filters[j] = element.getFilter();
+				} catch (CoreException e) {
+					WorkbenchPlugin.log(e.getMessage(), e);
+				}
+			}
+		} else {
+			filters = new IPreferenceFilter[0];
+		}
+
+		return filters;
+	}
+
+	/**
+	 * @return the list of transfer elements
+	 */
+	protected PreferenceTransferElement[] getPreferenceTransferElements() {
+		Object[] checkedElements = viewer.getCheckedElements();
+		PreferenceTransferElement[] transferElements = new PreferenceTransferElement[checkedElements.length];
+		System.arraycopy(checkedElements, 0, transferElements, 0,
+				checkedElements.length);
+		return transferElements;
+	}
+
+	/**
+	 * @param transfers
+	 * @return boolean
+	 */
+	protected abstract boolean transfer(IPreferenceFilter[] transfers);
+
+	/**
+	 * Check whether the internal state of the page is complete and update the
+	 * dialog
+	 */
+	public void setPageComplete() {
+		boolean complete = true;
+
+		if (!determinePageCompletion()) {
+			complete = false;
+		}
+
+		super.setPageComplete(complete);
+	}
+
+	/**
+	 * Returns whether this page is complete. This determination is made based
+	 * upon the current contents of this page's controls. Subclasses wishing to
+	 * include their controls in this determination should override the hook
+	 * methods <code>validateSourceGroup</code> and/or
+	 * <code>validateOptionsGroup</code>.
+	 *
+	 * @return <code>true</code> if this page is complete, and
+	 *         <code>false</code> if incomplete
+	 * @see #validateSourceGroup
+	 * @see #validateOptionsGroup
+	 */
+	protected boolean determinePageCompletion() {
+
+		// validate groups in order of priority so error message is the most important one
+		boolean complete = validateSourceGroup() && validateDestinationGroup()
+				&& validateOptionsGroup();
+
+		// Avoid draw flicker by not clearing the error
+		// message unless all is valid.
+		if (complete) {
+			setErrorMessage(null);
+		} else {
+			setErrorMessage(currentMessage);
+		}
+
+		return complete;
+	}
+
+	/**
+	 * Returns whether this page's options group's controls currently all
+	 * contain valid values.
+	 * <p>
+	 * The <code>WizardPreferencesPage</code> implementation of this method
+	 * returns <code>true</code> if the button to transfer all preferences is
+	 * selected OR at least one of the individual items are checked. Subclasses
+	 * may reimplement this method.
+	 * </p>
+	 *
+	 * @return <code>true</code> indicating validity of all controls in the
+	 *         options group
+	 */
+	protected boolean validateOptionsGroup() {
+		boolean isValid = true;
+		if (!getTransferAll()) {
+			Object[] checkedElements = viewer.getCheckedElements();
+			if (checkedElements == null || checkedElements.length == 0) {
+				currentMessage = getNoOptionsMessage();
+				isValid = false;
+			}
+		}
+		return isValid;
+	}
+
+	/**
+	 * Returns whether this page's source specification controls currently all
+	 * contain valid values.
+	 * <p>
+	 * The <code>WizardDataTransferPage</code> implementation of this method
+	 * returns <code>true</code>. Subclasses may reimplement this hook
+	 * method.
+	 * </p>
+	 *
+	 * @return <code>true</code> indicating validity of all controls in the
+	 *         source specification group
+	 */
+	protected boolean validateSourceGroup() {
+		return true;
+	}
+
+	/**
+	 * Answer the string to display in self as the destination type
+	 *
+	 * @return java.lang.String
+	 */
+	protected abstract String getDestinationLabel();
+
+	/**
+	 * Answer the contents of self's destination specification widget
+	 *
+	 * @return java.lang.String
+	 */
+	protected String getDestinationValue() {
+		return destinationNameField.getText().trim();
+	}
+
+	/**
+	 * Set the current input focus to self's destination entry field
+	 */
+	protected void giveFocusToDestination() {
+		destinationNameField.setFocus();
+	}
+
+	/**
+	 * Open an appropriate destination browser so that the user can specify a
+	 * source to import from
+	 */
+	protected void handleDestinationBrowseButtonPressed() {
+	    FileUpload dialog = new FileUpload(getContainer().getShell(),
+				getFileDialogStyle());
+		dialog.setText(getFileDialogTitle());
+//		dialog.setFilterPath(getDestinationValue());
+//		dialog.setFilterExtensions(new String[] { "*.epf" ,"*.*"}); //$NON-NLS-1$ //$NON-NLS-2$
+		String selectedFileName = dialog.getFileName();
+
+		if (selectedFileName != null) {
+			setDestinationValue(selectedFileName);
+		}
+	}
+
+	protected abstract String getFileDialogTitle();
+
+	protected abstract int getFileDialogStyle();
+
+	/**
+	 * Handle all events and enablements for widgets in this page
+	 *
+	 * @param e
+	 *            Event
+	 */
+	@Override
+	public void handleEvent(Event e) {
+		Widget source = e.widget;
+
+		if (source == destinationBrowseButton) {
+			handleDestinationBrowseButtonPressed();
+		}
+
+		updatePageCompletion();
+	}
+
+	/**
+	 * Determine if the page is complete and update the page appropriately.
+	 */
+	protected void updatePageCompletion() {
+		boolean pageComplete = determinePageCompletion();
+		setPageComplete(pageComplete);
+		if (pageComplete) {
+			setMessage(null);
+		}
+	}
+
+	/**
+     * Adds an entry to a history, while taking care of duplicate history items
+     * and excessively long histories.  The assumption is made that all histories
+     * should be of length <code>WizardDataTransferPage.COMBO_HISTORY_LENGTH</code>.
+     *
+     * @param history the current history
+     * @param newEntry the entry to add to the history
+     */
+    protected String[] addToHistory(String[] history, String newEntry) {
+        java.util.ArrayList l = new java.util.ArrayList(Arrays.asList(history));
+        addToHistory(l, newEntry);
+        String[] r = new String[l.size()];
+        l.toArray(r);
+        return r;
+    }
+
+    /**
+     * Adds an entry to a history, while taking care of duplicate history items
+     * and excessively long histories.  The assumption is made that all histories
+     * should be of length <code>WizardDataTransferPage.COMBO_HISTORY_LENGTH</code>.
+     *
+     * @param history the current history
+     * @param newEntry the entry to add to the history
+     */
+    protected void addToHistory(List history, String newEntry) {
+        history.remove(newEntry);
+        history.add(0, newEntry);
+
+        // since only one new item was added, we can be over the limit
+        // by at most one item
+        if (history.size() > COMBO_HISTORY_LENGTH) {
+			history.remove(COMBO_HISTORY_LENGTH);
+		}
+    }
+
+	/**
+	 * Hook method for restoring widget values to the values that they held last
+	 * time this wizard was used to completion.
+	 */
+	protected void restoreWidgetValues() {
+
+		IDialogSettings settings = getDialogSettings();
+		if (shouldSaveTransferAll() && settings != null) {
+
+			boolean transferAll;
+			if (settings.get(TRANSFER_ALL_PREFERENCES_ID) == null)
+				transferAll = true;
+			else
+				transferAll = settings
+					.getBoolean(TRANSFER_ALL_PREFERENCES_ID);
+			transferAllButton.setSelection(transferAll);
+			if (!transferAll) {
+				String[] preferenceIds = settings
+						.getArray(TRANSFER_PREFERENCES_NAMES_ID);
+				if (preferenceIds != null) {
+					PreferenceTransferElement[] transfers = getTransfers();
+					for (PreferenceTransferElement transfer : transfers) {
+						for (String preferenceId : preferenceIds) {
+							if (transfer.getID().equals(preferenceId)) {
+								viewer.setChecked(transfer, true);
+								break;
+							}
+						}
+					}
+				}
+			}
+		} else {
+			transferAllButton.setSelection(true);
+		}
+		updateEnablement();
+
+		if (settings != null) {
+			String[] directoryNames = settings
+					.getArray(STORE_DESTINATION_NAMES_ID);
+			if (directoryNames != null) {
+				// destination
+				setDestinationValue(directoryNames[0]);
+				for (String directoryName : directoryNames) {
+					addDestinationItem(directoryName);
+				}
+
+				String current = settings.get(STORE_DESTINATION_ID);
+				if (current != null) {
+					setDestinationValue(current);
+				}
+				// options
+				if (overwriteExistingFilesCheckbox != null) {
+					overwriteExistingFilesCheckbox.setSelection(settings
+							.getBoolean(STORE_OVERWRITE_EXISTING_FILES_ID));
+				}
+			}
+		}
+	}
+
+	protected abstract boolean shouldSaveTransferAll();
+
+	private boolean getOverwriteExisting() {
+		return overwriteExistingFilesCheckbox.getSelection();
+	}
+
+	private boolean getTransferAll() {
+		return transferAllButton.getSelection();
+	}
+
+	/**
+	 * Set the contents of self's destination specification widget to the passed
+	 * value
+	 *
+	 * @param value
+	 *            java.lang.String
+	 */
+	protected void setDestinationValue(String value) {
+		destinationNameField.setText(value);
+	}
+
+	@Override
+	public void dispose() {
+		super.dispose();
+		transfers = null;
+	}
+
+	protected boolean allowNewContainerName() {
+		return true;
+	}
+
+	/**
+	 * The <code>WizardDataTransfer</code> implementation of this
+	 * <code>IOverwriteQuery</code> method asks the user whether the existing
+	 * resource at the given path should be overwritten.
+	 *
+	 * @param pathString
+	 * @return the user's reply: one of <code>"YES"</code>, <code>"NO"</code>,
+	 *         <code>"ALL"</code>, or <code>"CANCEL"</code>
+	 */
+	@Override
+	public String queryOverwrite(String pathString) {
+
+		Path path = new Path(pathString);
+
+		String messageString;
+		// Break the message up if there is a file name and a directory
+		// and there are at least 2 segments.
+		if (path.getFileExtension() == null || path.segmentCount() < 2) {
+			messageString = NLS.bind(
+					PreferencesMessages.WizardDataTransfer_existsQuestion,
+					pathString);
+		} else {
+			messageString = NLS
+					.bind(
+							PreferencesMessages.WizardDataTransfer_overwriteNameAndPathQuestion,
+							path.lastSegment(), path.removeLastSegments(1)
+									.toOSString());
+		}
+
+		final MessageDialog dialog = new MessageDialog(getContainer().getShell(), PreferencesMessages.Question, null,
+				messageString, MessageDialog.QUESTION, new String[] {
+				                                                     IDialogConstants.get().YES_LABEL,
+				                                                     IDialogConstants.get().YES_TO_ALL_LABEL,
+				                                                     IDialogConstants.get().NO_LABEL,
+				                                                     IDialogConstants.get().NO_TO_ALL_LABEL,
+				                                                     IDialogConstants.get().CANCEL_LABEL }, 0) {
+			@Override
+			protected int getShellStyle() {
+				return super.getShellStyle() | SWT.SHEET;
+			}
+		};
+		String[] response = new String[] { YES, ALL, NO, NO_ALL, CANCEL };
+		// run in syncExec because callback is from an operation,
+		// which is probably not running in the UI thread.
+		getControl().getDisplay().syncExec(() -> dialog.open());
+		return dialog.getReturnCode() < 0 ? CANCEL : response[dialog
+				.getReturnCode()];
+	}
+
+	private void updateEnablement() {
+		boolean transferAll = getTransferAll();
+		selectAllButton.setEnabled(!transferAll);
+		deselectAllButton.setEnabled(!transferAll);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/preferences/messages.properties b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/preferences/messages.properties
new file mode 100644
index 0000000..99ce96f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/internal/wizards/preferences/messages.properties
@@ -0,0 +1,50 @@
+###############################################################################
+# Copyright (c) 2005, 2013 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
+###############################################################################
+
+WizardPreferences_description=Descrip&tion:
+WizardPreferencesPage_noOptionsSelected=No specific preferences are selected.
+WizardPreferences_noSpecificPreferenceDescription=Empty list.\nNote: Not all preferences support individual import.
+PreferencesExportWizard_export=Export Preferences
+WizardPreferencesExportPage1_exportTitle=Export Preferences
+WizardPreferencesExportPage1_exportDescription=Export preferences to the local file system.
+
+WizardPreferencesExportPage1_preferences=Preferences
+WizardPreferencesExportPage1_noPrefFile=Preference file not set, or is not a normal file.
+WizardPreferencesExportPage1_overwrite=The file {0} already exists, do you want to overwrite it?
+WizardPreferencesExportPage1_title=Export to File
+WizardPreferencesExportPage1_all=Export &all
+WizardPreferencesExportPage1_choose=&Choose specific preferences to export
+WizardPreferencesExportPage1_file=To &preference file:
+
+PreferencesImportWizard_import=Import Preferences
+WizardPreferencesImportPage1_importTitle=Import Preferences
+WizardPreferencesImportPage1_importDescription=Import preferences from the local file system.
+WizardPreferencesImportPage1_all=Import &all
+WizardPreferencesImportPage1_choose=C&hoose specific preferences to import
+WizardPreferencesImportPage1_file=From &preference file:
+WizardPreferencesImportPage1_title=Import from File
+WizardPreferencesImportPage1_invalidPrefFile=Preference file does not exist or is a directory.
+
+PreferencesExport_error=Error
+PreferencesExport_browse=B&rowse...
+PreferencesExport_createTargetDirectory=Target directory does not exist.  Would you like to create it?
+PreferencesExport_directoryCreationError=Target directory could not be created.
+
+ExportFile_overwriteExisting=&Overwrite existing files without warning
+
+SelectionDialog_selectLabel = &Select All
+SelectionDialog_deselectLabel = &Deselect All
+
+WizardDataTransfer_existsQuestion = ''{0}'' already exists.  Would you like to overwrite it?
+WizardDataTransfer_overwriteNameAndPathQuestion = Overwrite ''{0}'' in folder ''{1}''?
+
+Question = Question
+
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/intro/IIntroManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/intro/IIntroManager.java
new file mode 100644
index 0000000..8180ac8
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/intro/IIntroManager.java
@@ -0,0 +1,123 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.intro;
+
+import org.eclipse.ui.IWorkbenchWindow;
+
+/**
+ * Manages the intro part that introduces the product to new users.
+ * The intro part is typically shown the first time a product is started up.
+ * <p>
+ * The initial behavior of the intro part is controlled by the application
+ * from via the {@link org.eclipse.ui.application.WorkbenchWindowAdvisor#openIntro()}
+ * method.
+ * </p>
+ * <p>
+ * See {@link org.eclipse.ui.intro.IIntroPart} for details on where intro parts
+ * come from.
+ * </p>
+ * <p>
+ * This interface is not intended to be extended or implemented by clients.
+ * </p>
+ *
+ * @see org.eclipse.ui.IWorkbench#getIntroManager()
+ * @since 3.0
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IIntroManager {
+
+    /**
+     * Closes the given intro part.
+     *
+     * @param part the intro part
+     * @return <code>true</code> if the intro part was closed, and
+     * <code>false</code> otherwise.  <code>false</code> is returned
+     * if part is <code>null</code> or it is not the intro part returned
+     * by {@link #getIntro()}.
+     */
+    public boolean closeIntro(IIntroPart part);
+
+    /**
+     * Returns the intro part. Returns <code>null</code> if there is no intro
+     * part, if it has been previously closed via {@link #closeIntro(IIntroPart)}
+     * or if there is an intro part but {@link #showIntro(IWorkbenchWindow, boolean)}
+     * has not yet been called to create it.
+     *
+     * @return the intro part, or <code>null</code> if none is available
+     */
+    public IIntroPart getIntro();
+
+    /**
+     * Return whether an intro is available. Note that this checks whether
+     * there is an applicable intro part that could be instantiated and shown
+     * to the user.
+     * Use {@link #getIntro()} to discover whether an intro part has already
+     * been created.
+     *
+     * @return <code>true</code> if there is an intro that could be shown, and
+     * <code>false</code> if there is no intro
+     */
+    public boolean hasIntro();
+
+    /**
+     * Return the standby state of the given intro part.
+     *
+     * @param part the intro part
+     * @return <code>true</code> if the part in its partially
+     * visible standy mode, and <code>false</code> if in its fully visible state.
+     * <code>false</code> is returned if part is <code>null</code> or it is not
+     * the intro part returned by {@link #getIntro()}.
+     */
+    boolean isIntroStandby(IIntroPart part);
+
+    /**
+     * Sets the standby state of the given intro part. Intro part usually should
+     * render themselves differently in the full and standby modes. In standby
+     * mode, the part should be partially visible to the user but otherwise
+     * allow them to work. In full mode, the part should be fully visible and
+     * be the center of the user's attention.
+     * <p>
+     * This method does nothing if the part is <code>null</code> or is not
+     * the intro part returned by {@link #getIntro()}.
+     * </p>
+     *
+     * @param part the intro part, or <code>null</code>
+     * @param standby <code>true</code> to put the part in its partially
+     * visible standy mode, and <code>false</code> to make it fully visible.
+     */
+    public void setIntroStandby(IIntroPart part, boolean standby);
+
+    /**
+     * Shows the intro part in the given workbench window. If the intro part has
+     * not been created yet, one will be created. If the intro part is currently
+     * being shown in some workbench window, that other window is made active.
+     *
+     * @param preferredWindow the preferred workbench window, or
+     * <code>null</code> to indicate the currently active workbench window
+     * @param standby <code>true</code> to put the intro part in its partially
+     * visible standy mode, and <code>false</code> to make it fully visible
+     * @return the newly-created or existing intro part, or <code>null</code>
+     * if no intro part is available or if <code>preferredWindow</code> is
+     * <code>null</code> and there is no currently active workbench window
+     */
+    public IIntroPart showIntro(IWorkbenchWindow preferredWindow,
+            boolean standby);
+
+    /**
+	 * Returns <code>true</code> if there is an intro content detector and it
+	 * reports that new intro content is available.
+	 *
+	 * @return <code>true</code> if new intro content is available
+	 *
+	 * @since 3.3
+	 */
+    public boolean isNewContentAvailable();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/intro/IIntroPart.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/intro/IIntroPart.java
new file mode 100644
index 0000000..c988385
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/intro/IIntroPart.java
@@ -0,0 +1,214 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.intro;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IPropertyListener;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PartInitException;
+
+/**
+ * The intro part is a visual component within the workbench responsible for
+ * introducing the product to new users. The intro part is typically shown the
+ * first time a product is started up.
+ * <p>
+ * The intro part implementation is contributed to the workbench via the
+ * <code>org.eclipse.ui.intro</code> extension point.  There can be several
+ * intro part implementations, and associations between intro part
+ * implementations and products. The workbench will only make use of the intro
+ * part implementation for the current product (as given by
+ * {@link org.eclipse.core.runtime.Platform#getProduct()}. There is at most one
+ * intro part instance in the entire workbench, and it resides in exactly one
+ * workbench window at a time.
+ * </p>
+ * <p>
+ * This interface in not intended to be directly implemented. Rather, clients
+ * providing a intro part implementation should subclass
+ * {@link org.eclipse.ui.part.IntroPart}.
+ * </p>
+ *
+ * @see org.eclipse.ui.intro.IIntroManager#showIntro(org.eclipse.ui.IWorkbenchWindow, boolean)
+ * @since 3.0
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IIntroPart extends IAdaptable {
+
+    /**
+	 * The property id for <code>getTitleImage</code> and
+	 * <code>getTitle</code>.
+	 *
+	 * @since 3.2 this property now covers changes to <code>getTitle</code> in
+	 *        addition to <code>getTitleImage</code>
+	 */
+	public static final int PROP_TITLE = IWorkbenchPart.PROP_TITLE;
+
+    /**
+	 * Returns the site for this intro part.
+	 *
+	 * @return the intro site
+	 */
+    IIntroSite getIntroSite();
+
+    /**
+     * Initializes this intro part with the given intro site. A memento is
+     * passed to the part which contains a snapshot of the part state from a
+     * previous session. Where possible, the part should try to recreate that
+     * state.
+     * <p>
+     * This method is automatically called by the workbench shortly after
+     * part construction.  It marks the start of the intro's lifecycle. Clients
+     * must not call this method.
+     * </p>
+     *
+     * @param site the intro site
+     * @param memento the intro part state or <code>null</code> if there is no previous
+     * saved state
+     * @exception PartInitException if this part was not initialized
+     * successfully
+     */
+    public void init(IIntroSite site, IMemento memento)
+            throws PartInitException;
+
+    /**
+     * Sets the standby state of this intro part. An intro part should render
+     * itself differently in the full and standby modes. In standby mode, the
+     * part should be partially visible to the user but otherwise allow them
+     * to work. In full mode, the part should be fully visible and be the center
+     * of the user's attention.
+     * <p>
+     * This method is automatically called by the workbench at appropriate
+     * times. Clients must not call this method directly (call
+     * {@link IIntroManager#setIntroStandby(IIntroPart, boolean)} instead.
+     * </p>
+     *
+     * @param standby <code>true</code> to put this part in its partially
+     * visible standy mode, and <code>false</code> to make it fully visible
+     */
+    public void standbyStateChanged(boolean standby);
+
+    /**
+     * Saves the object state within a memento.
+     * <p>
+     * This method is automatically called by the workbench at appropriate
+     * times. Clients must not call this method directly.
+     * </p>
+     *
+     * @param memento a memento to receive the object state
+     */
+    public void saveState(IMemento memento);
+
+    /**
+     * Adds a listener for changes to properties of this intro part.
+     * Has no effect if an identical listener is already registered.
+     * <p>
+     * The properties ids are as follows:
+     * <ul>
+     *   <li><code>IIntroPart.PROP_TITLE</code> </li>
+     * </ul>
+     * </p>
+     *
+     * @param listener a property listener
+     */
+    public void addPropertyListener(IPropertyListener listener);
+
+    /**
+     * Creates the SWT controls for this intro part.
+     * <p>
+     * Clients should not call this method (the workbench calls this method when
+     * it needs to, which may be never).
+     * </p>
+     * <p>
+     * For implementors this is a multi-step process:
+     * <ol>
+     *   <li>Create one or more controls within the parent.</li>
+     *   <li>Set the parent layout as needed.</li>
+     *   <li>Register any global actions with the <code>IActionService</code>.</li>
+     *   <li>Register any popup menus with the <code>IActionService</code>.</li>
+     *   <li>Register a selection provider with the <code>ISelectionService</code>
+     *     (optional). </li>
+     * </ol>
+     * </p>
+     *
+     * @param parent the parent control
+     */
+    public void createPartControl(Composite parent);
+
+    /**
+     * Disposes of this intro part.
+     * <p>
+     * This is the last method called on the <code>IIntroPart</code>.  At this
+     * point the part controls (if they were ever created) have been disposed as part
+     * of an SWT composite.  There is no guarantee that createPartControl() has been
+     * called, so the part controls may never have been created.
+     * </p>
+     * <p>
+     * Within this method a part may release any resources, fonts, images, etc.&nbsp;
+     * held by this part.  It is also very important to deregister all listeners
+     * from the workbench.
+     * </p>
+     * <p>
+     * Clients should not call this method (the workbench calls this method at
+     * appropriate times).
+     * </p>
+     */
+    public void dispose();
+
+    /**
+     * Returns the title image of this intro part.  If this value changes
+     * the part must fire a property listener event with
+     * {@link IIntroPart#PROP_TITLE}.
+     * <p>
+     * The title image is usually used to populate the title bar of this part's
+     * visual container. Since this image is managed by the part itself, callers
+     * must <b>not</b> dispose the returned image.
+     * </p>
+     *
+     * @return the title image
+     */
+    public Image getTitleImage();
+
+    /**
+     * Returns the title of this intro part. If this value changes
+     * the part must fire a property listener event with
+     * {@link IIntroPart#PROP_TITLE}.
+     * <p>
+     * The title is used to populate the title bar of this part's visual
+     * container.
+     * </p>
+     *
+     * @return the intro part title (not <code>null</code>)
+     * @since 3.2
+     */
+    public String getTitle();
+
+    /**
+	 * Removes the given property listener from this intro part. Has no effect
+	 * if an identical listener is not registered.
+	 *
+	 * @param listener
+	 *            a property listener
+	 */
+    public void removePropertyListener(IPropertyListener listener);
+
+    /**
+     * Asks this part to take focus within the workbench.
+     * <p>
+     * Clients should not call this method (the workbench calls this method at
+     * appropriate times).  To have the workbench activate a part, use
+     * {@link IIntroManager#showIntro(IWorkbenchWindow, boolean)}.
+     * </p>
+     */
+    public void setFocus();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/intro/IIntroSite.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/intro/IIntroSite.java
new file mode 100644
index 0000000..7443d9f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/intro/IIntroSite.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.intro;
+
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IKeyBindingService;
+import org.eclipse.ui.IWorkbenchSite;
+
+/**
+ * The primary interface between an intro part and the workbench.
+ * <p>
+ * The workbench exposes its implemention of intro part sites via this
+ * interface, which is not intended to be implemented or extended by clients.
+ * </p>
+ *
+ * @since 3.0
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IIntroSite extends IWorkbenchSite {
+
+    /**
+     * Returns the part registry extension id for this intro site's part.
+     * <p>
+     * The name comes from the <code>id</code> attribute in the configuration
+     * element.
+     * </p>
+     *
+     * @return the registry extension id
+     */
+    public String getId();
+
+    /**
+     * Returns the unique identifier of the plug-in that defines this intro
+     * site's part.
+     *
+     * @return the unique identifier of the declaring plug-in
+     * @see org.eclipse.core.runtime.IPluginDescriptor#getUniqueIdentifier()
+     */
+    public String getPluginId();
+
+    /**
+     * Returns the key binding service in use.
+     * <p>
+     * The part will access this service to register
+     * all of its actions, to set the active scope.
+     * </p>
+     *
+     * @return the key binding service in use
+     * @deprecated Use IServiceLocator#getService(*) to retrieve
+     * IContextService and IHandlerService instead.
+     */
+    @Deprecated
+	public IKeyBindingService getKeyBindingService();
+
+    /**
+     * Returns the action bars for this part site.
+     * The intro part has exclusive use of its site's action bars.
+     *
+     * @return the action bars
+     */
+    public IActionBars getActionBars();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/intro/IntroContentDetector.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/intro/IntroContentDetector.java
new file mode 100644
index 0000000..0480d2f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/intro/IntroContentDetector.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.intro;
+
+/**
+ * An intro content detector is used when starting the Workbench to determine if
+ * new intro content is available. Since calling this method is part of the
+ * Workbench start sequence, subclasses should be implemented with care as not
+ * to introduce noticeable delay at startup. If an intro content detector
+ * reports new available content, the view part showing the content will be
+ * opened again even if the user had closed it in a previous session. Because of
+ * this, the intro view part should draw the user's attention to the new content
+ * to avoid confusion about why the intro view part was opened again without the
+ * user requesting it.
+ *
+ * @since 3.3
+ *
+ */
+public abstract class IntroContentDetector {
+
+	/**
+	 * Returns <code>true</code> if new intro content is available.
+	 *
+	 * @return <code>true</code> if new intro content is available
+	 */
+	public abstract boolean isNewContentAvailable();
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/intro/package.html b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/intro/package.html
new file mode 100644
index 0000000..4ba8d59
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/intro/package.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <title>Package-level Javadoc</title>
+</head>
+<body>
+Application programming interfaces for interaction
+with and extension of the product introduction parts.
+<h2>Package Specification</h2>
+This package provides application programming interfaces for dealing with
+intro parts.  An intro part is a visual component within the workbench 
+responsible for introducing the product to new users. The intro part is 
+typically shown the first time a product is started up.
+</body>
+</html>
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/CharacterKey.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/CharacterKey.java
new file mode 100644
index 0000000..18a2c46
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/CharacterKey.java
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.keys;
+
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.eclipse.jface.bindings.keys.IKeyLookup;
+import org.eclipse.jface.bindings.keys.KeyLookupFactory;
+
+/**
+ * <p>
+ * Instances of <code>CharacterKey</code> represent keys on the keyboard which
+ * represent unicode characters.
+ * </p>
+ * <p>
+ * <code>CharacterKey</code> objects are immutable. Clients are not permitted
+ * to extend this class.
+ * </p>
+ *
+ * @deprecated Please use org.eclipse.jface.bindings.keys.KeyStroke and
+ *             org.eclipse.jface.bindings.keys.KeyLookupFactory
+ * @since 3.0
+ */
+@Deprecated
+public final class CharacterKey extends NaturalKey {
+
+	/**
+	 * An internal map used to lookup instances of <code>CharacterKey</code>
+	 * given the formal string representation of a character key.
+	 */
+	static SortedMap characterKeysByName = new TreeMap();
+
+	/**
+	 * The single static instance of <code>CharacterKey</code> which
+	 * represents the backspace key (U+0008).
+	 */
+	public final static CharacterKey BS;
+
+	/**
+	 * The single static instance of <code>CharacterKey</code> which
+	 * represents the carriage return (U+000D) key
+	 */
+	public final static CharacterKey CR;
+
+	/**
+	 * The single static instance of <code>CharacterKey</code> which
+	 * represents the delete (U+007F) key.
+	 */
+	public final static CharacterKey DEL;
+
+	/**
+	 * The single static instance of <code>CharacterKey</code> which
+	 * represents the escape (U+001B) key.
+	 */
+	public final static CharacterKey ESC;
+
+	/**
+	 * The single static instance of <code>CharacterKey</code> which
+	 * represents the form feed (U+000C) key.
+	 */
+	public final static CharacterKey FF;
+
+	/**
+	 * The single static instance of <code>CharacterKey</code> which
+	 * represents the line feed (U+000A) key.
+	 */
+	public final static CharacterKey LF;
+
+	/**
+	 * The single static instance of <code>CharacterKey</code> which
+	 * represents the null (U+0000) key.
+	 */
+	public final static CharacterKey NUL;
+
+	/**
+	 * The single static instance of <code>CharacterKey</code> which
+	 * represents the space (U+0020) key.
+	 */
+	public final static CharacterKey SPACE;
+
+	/**
+	 * The single static instance of <code>CharacterKey</code> which
+	 * represents the tab (U+0009) key.
+	 */
+	public final static CharacterKey TAB;
+
+	/**
+	 * The single static instance of <code>CharacterKey</code> which
+	 * represents the vertical tab (U+000B) key.
+	 */
+	public final static CharacterKey VT;
+
+	/**
+	 * Creates an instance of <code>CharacterKey</code> given a unicode
+	 * character. This method determines the correct name for the key based on
+	 * character. Typically, this name is a string of one-character in length
+	 * equal to the character that this instance represents.
+	 *
+	 * @param character
+	 *            the character that the resultant <code>CharacterKey</code>
+	 *            instance is to represent.
+	 * @return an instance of <code>CharacterKey</code> representing the
+	 *         character.
+	 */
+	public static final CharacterKey getInstance(final char character) {
+		return new CharacterKey(character);
+	}
+
+	static {
+		final IKeyLookup lookup = KeyLookupFactory.getDefault();
+		BS = new CharacterKey(lookup.formalKeyLookup(IKeyLookup.BS_NAME));
+		CR = new CharacterKey(lookup.formalKeyLookup(IKeyLookup.CR_NAME));
+		DEL = new CharacterKey(lookup.formalKeyLookup(IKeyLookup.DEL_NAME));
+		ESC = new CharacterKey(lookup.formalKeyLookup(IKeyLookup.ESC_NAME));
+		FF = new CharacterKey(lookup.formalKeyLookup(IKeyLookup.FF_NAME));
+		LF = new CharacterKey(lookup.formalKeyLookup(IKeyLookup.LF_NAME));
+		NUL = new CharacterKey(lookup.formalKeyLookup(IKeyLookup.NUL_NAME));
+		SPACE = new CharacterKey(lookup.formalKeyLookup(IKeyLookup.SPACE_NAME));
+		TAB = new CharacterKey(lookup.formalKeyLookup(IKeyLookup.TAB_NAME));
+		VT = new CharacterKey(lookup.formalKeyLookup(IKeyLookup.VT_NAME));
+
+		characterKeysByName.put(IKeyLookup.BS_NAME, CharacterKey.BS);
+		characterKeysByName.put(IKeyLookup.BACKSPACE_NAME, CharacterKey.BS);
+		characterKeysByName.put(IKeyLookup.CR_NAME, CharacterKey.CR);
+		characterKeysByName.put(IKeyLookup.ENTER_NAME, CharacterKey.CR);
+		characterKeysByName.put(IKeyLookup.RETURN_NAME, CharacterKey.CR);
+		characterKeysByName.put(IKeyLookup.DEL_NAME, CharacterKey.DEL);
+		characterKeysByName.put(IKeyLookup.DELETE_NAME, CharacterKey.DEL);
+		characterKeysByName.put(IKeyLookup.ESC_NAME, CharacterKey.ESC);
+		characterKeysByName.put(IKeyLookup.ESCAPE_NAME, CharacterKey.ESC);
+		characterKeysByName.put(IKeyLookup.FF_NAME, CharacterKey.FF);
+		characterKeysByName.put(IKeyLookup.LF_NAME, CharacterKey.LF);
+		characterKeysByName.put(IKeyLookup.NUL_NAME, CharacterKey.NUL);
+		characterKeysByName.put(IKeyLookup.SPACE_NAME, CharacterKey.SPACE);
+		characterKeysByName.put(IKeyLookup.TAB_NAME, CharacterKey.TAB);
+		characterKeysByName.put(IKeyLookup.VT_NAME, CharacterKey.VT);
+	}
+
+	/**
+	 * Constructs an instance of <code>CharacterKey</code> given a unicode
+	 * character and a name.
+	 *
+	 * @param key
+	 *            The key to be wrapped.
+	 */
+	private CharacterKey(final int key) {
+		super(key);
+	}
+
+	/**
+	 * Gets the character that this object represents.
+	 *
+	 * @return the character that this object represents.
+	 */
+	public final char getCharacter() {
+		return (char) key;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/IBindingService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/IBindingService.java
new file mode 100644
index 0000000..738f17f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/IBindingService.java
@@ -0,0 +1,382 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.keys;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Map;
+
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.jface.bindings.Binding;
+import org.eclipse.jface.bindings.IBindingManagerListener;
+import org.eclipse.jface.bindings.Scheme;
+import org.eclipse.jface.bindings.TriggerSequence;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.services.IDisposable;
+
+/**
+ * <p>
+ * Provides services related to the binding architecture (e.g., keyboard
+ * shortcuts) within the workbench. This service can be used to access the
+ * currently active bindings, as well as the current state of the binding
+ * architecture.
+ * </p>
+ * <p>
+ * This service can be acquired from your service locator:
+ * <pre>
+ * 	IBindingService service = (IBindingService) getSite().getService(IBindingService.class);
+ * </pre>
+ * <ul>
+ * <li>This service is available globally.</li>
+ * </ul>
+ * </p>
+ *
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noextend This interface is not intended to be extended by clients.
+ *
+ * @since 3.1
+ */
+public interface IBindingService extends IDisposable {
+
+	/**
+	 * The default default value for the active scheme id. This value can be
+	 * overridden using the "plugin_customization.ini" file. The
+	 * <code>BindingPersistence</code> code needs to know this value so it can
+	 * try to decide if someone overrode the default.
+	 */
+	public static final String DEFAULT_DEFAULT_ACTIVE_SCHEME_ID = "org.eclipse.ui.defaultAcceleratorConfiguration"; //$NON-NLS-1$
+
+	/**
+	 * <p>
+	 * Adds a listener to this binding service. The listener will be notified
+	 * when the set of defined schemes or bindings changes. This can be used to
+	 * track the global appearance and disappearance of bindings.
+	 * </p>
+	 * <p>
+	 * This method completes in amortized constant time (<code>O(1)</code>).
+	 * </p>
+	 *
+	 * @param listener
+	 *            The listener to attach; must not be <code>null</code>.
+	 *
+	 * @since 3.5
+	 */
+	public void addBindingManagerListener(IBindingManagerListener listener);
+
+	/**
+	 * <p>
+	 * Removes a listener from this binding service.
+	 * </p>
+	 * <p>
+	 * This method completes in amortized <code>O(1)</code>.
+	 * </p>
+	 *
+	 * @param listener
+	 *            The listener to be removed; must not be <code>null</code>.
+	 *
+	 * @since 3.5
+	 */
+	public void removeBindingManagerListener(IBindingManagerListener listener);
+
+	/**
+	 * Gets the active bindings for a given parameterized command.
+	 *
+	 * @param parameterizedCommand
+	 *            The fully-parameterized command for which the active bindings
+	 *            should be found; must not be <code>null</code>.
+	 * @return The array of all active bindings for the given command. This
+	 *         collection may be empty, but it is never <code>null</code>.
+	 */
+	public TriggerSequence[] getActiveBindingsFor(
+			ParameterizedCommand parameterizedCommand);
+
+	/**
+	 * Gets the active bindings for a given command identifier. It is assumed
+	 * that the command has no parameters.
+	 *
+	 * @param commandId
+	 *            The id of the command for which the active bindings should be
+	 *            found; must not be <code>null</code>.
+	 * @return The array of all active bindings for the given command. This
+	 *         collection may be empty, but it is never <code>null</code>.
+	 */
+	public TriggerSequence[] getActiveBindingsFor(String commandId);
+
+	/**
+	 * Returns the currently active scheme.
+	 *
+	 * @return The currently active scheme. This value may (in certain rare
+	 *         circumstances) be <code>null</code>.
+	 */
+	public Scheme getActiveScheme();
+
+	/**
+	 * Gets the best active binding for a command. The best binding is the one
+	 * that would be most appropriate to show in a menu. Bindings which belong
+	 * to a child scheme are given preference over those in a parent scheme.
+	 * Bindings which belong to a particular locale or platform are given
+	 * preference over those that do not. The rest of the calculation is based
+	 * most on various concepts of "length", as well as giving some modifier
+	 * keys preference (e.g., <code>Alt</code> is less likely to appear than
+	 * <code>Ctrl</code>).
+	 *
+	 * @param command
+	 *            The command for which the best active binding should be
+	 *            retrieved; must not be <code>null</code>.
+	 * @return The trigger sequence for the best binding; may be
+	 *         <code>null</code> if no bindings are active for the given
+	 *         command.
+	 * @since 3.4
+	 */
+	public TriggerSequence getBestActiveBindingFor(ParameterizedCommand command);
+
+	/**
+	 * Gets the best active binding for a command. The best binding is the one
+	 * that would be most appropriate to show in a menu. Bindings which belong
+	 * to a child scheme are given preference over those in a parent scheme.
+	 * Bindings which belong to a particular locale or platform are given
+	 * preference over those that do not. The rest of the calculaton is based
+	 * most on various concepts of "length", as well as giving some modifier
+	 * keys preference (e.g., <code>Alt</code> is less likely to appear than
+	 * <code>Ctrl</code>).
+	 *
+	 * @param commandId
+	 *            The identifier of the command for which the best active
+	 *            binding should be retrieved; must not be <code>null</code>.
+	 * @return The trigger sequence for the best binding; may be
+	 *         <code>null</code> if no bindings are active for the given
+	 *         command.
+	 * @since 3.2
+	 * @see #getBestActiveBindingFor(ParameterizedCommand)
+	 */
+	public TriggerSequence getBestActiveBindingFor(String commandId);
+
+	/**
+	 * Gets the formatted string representing the best active binding for a
+	 * command. The best binding is the one that would be most appropriate to
+	 * show in a menu. Bindings which belong to a child scheme are given
+	 * preference over those in a parent scheme. The rest of the calculaton is
+	 * based most on various concepts of "length", as well as giving some
+	 * modifier keys preference (e.g., <code>Alt</code> is less likely to
+	 * appear than <code>Ctrl</code>).
+	 *
+	 * @param commandId
+	 *            The identifier of the command for which the best active
+	 *            binding should be retrieved; must not be <code>null</code>.
+	 * @return The formatted string for the best binding; may be
+	 *         <code>null</code> if no bindings are active for the given
+	 *         command.
+	 * @since 3.2
+	 * @see #getBestActiveBindingFor(ParameterizedCommand)
+	 */
+	public String getBestActiveBindingFormattedFor(String commandId);
+
+	/**
+	 * Returns the current set of bindings.
+	 *
+	 * @return The current array of bindings (<code>Binding</code>).
+	 */
+	public Binding[] getBindings();
+
+	/**
+	 * Returns the current state of the key binding buffer. This will contain
+	 * all of the keys currently awaiting processing. If the system is currently
+	 * executing a command (as a result of a key press), then this will contain
+	 * the trigger sequence used to execute the command. If the key binding
+	 * architecture has seen part of multi-key binding, then this will contain
+	 * the part that it has seen. Otherwise, this will return nothing.
+	 *
+	 * @return The trigger sequence indicating the current state of the key
+	 *         binding buffer; never <code>null</code>, but may be empty if
+	 *         there is nothing in the buffer.
+	 * @since 3.2
+	 */
+	public TriggerSequence getBuffer();
+
+	/**
+	 * Returns the default scheme identifier for the currently running
+	 * application.
+	 *
+	 * @return The default scheme identifier (<code>String</code>); never
+	 *         <code>null</code>, but may be empty or point to an undefined
+	 *         scheme.
+	 */
+	public String getDefaultSchemeId();
+
+	/**
+	 * Returns the array of defined schemes in the workbench.
+	 *
+	 * @return The array of schemes (<code>Scheme</code>) that are defined;
+	 *         it may be <code>null</code>, and it may be empty.
+	 */
+	public Scheme[] getDefinedSchemes();
+
+	/**
+	 * Returns the currently active locale.
+	 *
+	 * @return The current locale.
+	 */
+	public String getLocale();
+
+	/**
+	 * Returns all of the possible bindings that start with the given trigger
+	 * (but are not equal to the given trigger).
+	 *
+	 * @param trigger
+	 *            The prefix to look for; must not be <code>null</code>.
+	 * @return A map of triggers (<code>TriggerSequence</code>) to bindings (<code>Binding</code>).
+	 *         This map may be empty, but it is never <code>null</code>.
+	 */
+	public Map getPartialMatches(TriggerSequence trigger);
+
+	/**
+	 * Returns the command identifier for the active binding matching this
+	 * trigger, if any.
+	 *
+	 * @param trigger
+	 *            The trigger to match; may be <code>null</code>.
+	 * @return The binding that matches, if any; <code>null</code> otherwise.
+	 */
+	public Binding getPerfectMatch(TriggerSequence trigger);
+
+	/**
+	 * Returns the currently active platform.
+	 *
+	 * @return The current platform.
+	 */
+	public String getPlatform();
+
+	/**
+	 * Retrieves the scheme with the given identifier. If no such scheme exists,
+	 * then an undefined scheme with the given id is created.
+	 *
+	 * @param schemeId
+	 *            The identifier to find; must not be <code>null</code>.
+	 * @return A scheme with the given identifier, either defined or undefined.
+	 */
+	public Scheme getScheme(String schemeId);
+
+	/**
+	 * Tests whether the global key binding architecture is currently active.
+	 *
+	 * @return <code>true</code> if the key bindings are active;
+	 *         <code>false</code> otherwise.
+	 */
+	public boolean isKeyFilterEnabled();
+
+	/**
+	 * Returns whether the given trigger sequence is a partial match for the
+	 * given sequence.
+	 *
+	 * @param trigger
+	 *            The sequence which should be the prefix for some binding;
+	 *            should not be <code>null</code>.
+	 * @return <code>true</code> if the trigger can be found in the active
+	 *         bindings; <code>false</code> otherwise.
+	 */
+	public boolean isPartialMatch(TriggerSequence trigger);
+
+	/**
+	 * Returns whether the given trigger sequence is a perfect match for the
+	 * given sequence.
+	 *
+	 * @param trigger
+	 *            The sequence which should match exactly; should not be
+	 *            <code>null</code>.
+	 * @return <code>true</code> if the trigger can be found in the active
+	 *         bindings; <code>false</code> otherwise.
+	 */
+	public boolean isPerfectMatch(TriggerSequence trigger);
+
+	/**
+	 * Opens the key assistant dialog positioned near the key binding entry in
+	 * the status bar.
+	 */
+	public void openKeyAssistDialog();
+
+	/**
+	 * <p>
+	 * Reads the binding information from the registry and the preferences. This
+	 * will overwrite any of the existing information in the binding service.
+	 * This method is intended to be called during start-up. When this method
+	 * completes, this binding service will reflect the current state of the
+	 * registry and preference store.
+	 * </p>
+	 *
+	 * @param commandService
+	 *            Ignored.
+	 */
+	public void readRegistryAndPreferences(ICommandService commandService);
+
+	/**
+	 * <p>
+	 * Writes the given active scheme and bindings to the preference store. Only
+	 * the bindings that are of the <code>Binding.USER</code> type will be
+	 * written; the others will be ignored. This should only be used by
+	 * applications trying to persist user preferences. If you are trying to
+	 * change the active scheme as an RCP application, then you should be using
+	 * the <code>plugin_customization.ini</code> file. If you are trying to
+	 * switch between groups of bindings dynamically, you should be using
+	 * contexts.
+	 * </p>
+	 * <p>
+	 * This method also updates the active scheme and bindings in the system to
+	 * match those written to the preference store.
+	 * </p>
+	 *
+	 * @param activeScheme
+	 *            The scheme which should be persisted; may be <code>null</code>.
+	 * @param bindings
+	 *            The bindings which should be persisted; may be
+	 *            <code>null</code>.
+	 * @throws IOException
+	 *             If something goes wrong while writing to the preference
+	 *             store.
+	 * @see org.eclipse.ui.IWorkbenchPreferenceConstants
+	 * @see org.eclipse.ui.contexts.IContextService
+	 */
+	public void savePreferences(Scheme activeScheme, Binding[] bindings)
+			throws IOException;
+
+	/**
+	 * <p>
+	 * Enables or disables the global key binding architecture. The architecture
+	 * should be enabled by default.
+	 * </p>
+	 * <p>
+	 * When enabled, keyboard shortcuts are active, and that key events can
+	 * trigger commands. This also means that widgets may not see all key events
+	 * (as they might be trapped as a keyboard shortcut).
+	 * </p>
+	 * <p>
+	 * When disabled, no key events will trapped as keyboard shortcuts, and that
+	 * no commands can be triggered by keyboard events. (Exception: it is
+	 * possible that someone listening for key events on a widget could trigger
+	 * a command.)
+	 * </p>
+	 *
+	 * @param enabled
+	 *            Whether the key filter should be enabled.
+	 */
+	public void setKeyFilterEnabled(boolean enabled);
+
+	/**
+	 * Provides the current conflicts in the keybindings for the given
+	 * TriggerSequence as a {@link Collection} of {@link Binding}
+	 *
+	 * @param sequence The sequence for which conflict info is required
+	 *
+	 * @return Collection of Bindings. If no conflicts,
+	 *         then returns a <code>null</code>
+	 * @since 3.5
+	 */
+	public Collection getConflictsFor(TriggerSequence sequence);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/IKeyFormatter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/IKeyFormatter.java
new file mode 100644
index 0000000..6186c6b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/IKeyFormatter.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.keys;
+
+/**
+ * Any formatter capable of taking key sequence or a key stroke and converting
+ * it into a string. These formatters are used to produce the strings that the
+ * user sees in the keys preference page and the menus, as well as the strings
+ * that are used for persistent storage.
+ *
+ * @deprecated Please use org.eclipse.jface.bindings.keys.IKeyFormatter
+ * @since 3.0
+ */
+@Deprecated
+public interface IKeyFormatter {
+
+    /**
+     * Formats an individual key into a human readable format. This uses an
+     * internationalization resource bundle to look up the key. This does not
+     * do any platform-specific formatting (e.g., Carbon's command character).
+     *
+     * @param key
+     *            The key to format; must not be <code>null</code>.
+     * @return The key formatted as a string; should not be <code>null</code>.
+     */
+    String format(Key key);
+
+    /**
+     * Format the given key sequence into a string. The manner of the
+     * conversion is dependent on the formatter. It is required that unequal
+     * key seqeunces return unequal strings.
+     *
+     * @param keySequence
+     *            The key sequence to convert; must not be <code>null</code>.
+     * @return A string representation of the key sequence; must not be <code>null</code>.
+     */
+    String format(KeySequence keySequence);
+
+    /**
+     * Format the given key strokes into a string. The manner of the conversion
+     * is dependent on the formatter. It is required that unequal key strokes
+     * return unequal strings.
+     *
+     * @param keyStroke
+     *            The key stroke to convert; must not be <Code>null</code>.
+     * @return A string representation of the key stroke; must not be <code>
+     *         null</code>
+     */
+    String format(KeyStroke keyStroke);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/Key.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/Key.java
new file mode 100644
index 0000000..097b3ef
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/Key.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.keys;
+
+import org.eclipse.jface.bindings.keys.IKeyLookup;
+import org.eclipse.jface.bindings.keys.KeyLookupFactory;
+import org.eclipse.ui.internal.util.Util;
+
+/**
+ * <p>
+ * <code>Key</code> is the abstract base class for all objects representing
+ * keys on the keyboard.
+ * </p>
+ * <p>
+ * All <code>Key</code> objects have a formal string representation, called
+ * the 'name' of the key, available via the <code>toString()</code> method.
+ * </p>
+ * <p>
+ * All <code>Key</code> objects, via the <code>format()</code> method,
+ * provide a version of their formal string representation translated by
+ * platform and locale, suitable for display to a user.
+ * </p>
+ * <p>
+ * <code>Key</code> objects are immutable. Clients are not permitted to extend
+ * this class.
+ * </p>
+ *
+ * @deprecated Please use org.eclipse.jface.bindings.keys.KeyStroke and
+ *             org.eclipse.jface.bindings.keys.KeyLookupFactory
+ * @since 3.0
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+@Deprecated
+public abstract class Key implements Comparable {
+
+	/**
+	 * The key from which this key was constructed. This value is defined by
+	 * <code>KeyLookupFactory.getDefault()</code>.
+	 */
+	protected final int key;
+
+	/**
+	 * Constructs an instance of <code>Key</code> given its formal string
+	 * representation.
+	 *
+	 * @param key
+	 *            the integer representation of this key, as defined by
+	 *            <code>KeyLookupFactory.getDefault()</code>.
+	 */
+	Key(final int key) {
+		this.key = key;
+	}
+
+	/**
+	 * @see java.lang.Comparable#compareTo(java.lang.Object)
+	 */
+	@Override
+	public final int compareTo(final Object object) {
+		return Util.compare(key, ((Key) object).key);
+	}
+
+	/**
+	 * @see java.lang.Object#equals(java.lang.Object)
+	 */
+	@Override
+	public final boolean equals(final Object object) {
+		if (!(object instanceof Key)) {
+			return false;
+		}
+
+		return key == ((Key) object).key;
+	}
+
+	/**
+	 * @see java.lang.Object#hashCode()
+	 */
+	@Override
+	public final int hashCode() {
+		return Util.hashCode(key);
+	}
+
+	/**
+	 * Returns the formal string representation for this key.
+	 *
+	 * @return The formal string representation for this key. Guaranteed not to
+	 *         be <code>null</code>.
+	 * @see java.lang.Object#toString()
+	 */
+	@Override
+	public final String toString() {
+		final IKeyLookup lookup = KeyLookupFactory.getDefault();
+		return lookup.formalNameLookup(key);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/KeyFormatterFactory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/KeyFormatterFactory.java
new file mode 100644
index 0000000..abae86d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/KeyFormatterFactory.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.keys;
+
+import org.eclipse.ui.internal.keys.CompactKeyFormatter;
+import org.eclipse.ui.internal.keys.EmacsKeyFormatter;
+import org.eclipse.ui.internal.keys.FormalKeyFormatter;
+
+/**
+ * A cache for formatters. It keeps a few instances of pre-defined instances of
+ * <code>IKeyFormatter</code> available for use. It also allows the default
+ * formatter to be changed.
+ *
+ * @deprecated Please use org.eclipse.jface.bindings.keys.KeyFormatterFactory
+ * @since 3.0
+ * @see org.eclipse.ui.keys.IKeyFormatter
+ */
+@Deprecated
+public final class KeyFormatterFactory {
+    private static final IKeyFormatter COMPACT_KEY_FORMATTER = new CompactKeyFormatter();
+
+    private static final IKeyFormatter FORMAL_KEY_FORMATTER = new FormalKeyFormatter();
+
+    private static final IKeyFormatter EMACS_KEY_FORMATTER = new EmacsKeyFormatter();
+
+    private static IKeyFormatter defaultKeyFormatter = FORMAL_KEY_FORMATTER;
+
+    /**
+     * Provides an instance of <code>CompactKeyFormatter</code>.
+     *
+     * @return The compact formatter; never <code>null</code>.
+     */
+    public static final IKeyFormatter getCompactKeyFormatter() {
+        return COMPACT_KEY_FORMATTER;
+    }
+
+    /**
+     * An accessor for the current default key formatter.
+     *
+     * @return The default formatter; never <code>null</code>.
+     */
+    public static IKeyFormatter getDefault() {
+        return defaultKeyFormatter;
+    }
+
+    /**
+     * Provides an instance of <code>EmacsKeyFormatter</code>.
+     *
+     * @return The Xemacs formatter; never <code>null</code>.
+     */
+    public static IKeyFormatter getEmacsKeyFormatter() {
+        return EMACS_KEY_FORMATTER;
+    }
+
+    /**
+     * Provides an instance of <code>FormalKeyFormatter</code>.
+     *
+     * @return The formal formatter; never <code>null</code>.
+     */
+    public static IKeyFormatter getFormalKeyFormatter() {
+        return FORMAL_KEY_FORMATTER;
+    }
+
+    /**
+     * Sets the default key formatter.
+     *
+     * @param defaultKeyFormatter
+     *            the default key formatter. Must not be <code>null</code>.
+     */
+    public static void setDefault(IKeyFormatter defaultKeyFormatter) {
+        if (defaultKeyFormatter == null) {
+			throw new NullPointerException();
+		}
+
+        KeyFormatterFactory.defaultKeyFormatter = defaultKeyFormatter;
+    }
+
+    private KeyFormatterFactory() {
+        // Not to be constructred.
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/KeySequence.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/KeySequence.java
new file mode 100644
index 0000000..b01dd94
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/KeySequence.java
@@ -0,0 +1,386 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.keys;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import org.eclipse.ui.internal.util.Util;
+
+/**
+ * <p>
+ * A <code>KeySequence</code> is defined as a list of zero or more
+ * <code>KeyStrokes</code>, with the stipulation that all
+ * <code>KeyStroke</code> objects must be complete, save for the last one,
+ * whose completeness is optional. A <code>KeySequence</code> is said to be
+ * complete if all of its <code>KeyStroke</code> objects are complete.
+ * </p>
+ * <p>
+ * All <code>KeySequence</code> objects have a formal string representation
+ * available via the <code>toString()</code> method. There are a number of
+ * methods to get instances of <code>KeySequence</code> objects, including one
+ * which can parse this formal string representation.
+ * </p>
+ * <p>
+ * All <code>KeySequence</code> objects, via the <code>format()</code>
+ * method, provide a version of their formal string representation translated by
+ * platform and locale, suitable for display to a user.
+ * </p>
+ * <p>
+ * <code>KeySequence</code> objects are immutable. Clients are not permitted
+ * to extend this class.
+ * </p>
+ *
+ * @deprecated Please use org.eclipse.jface.bindings.keys.KeySequence
+ * @since 3.0
+ */
+@Deprecated
+public final class KeySequence implements Comparable {
+
+    /**
+     * The delimiter between multiple key strokes in a single key sequence --
+     * expressed in the formal key stroke grammar. This is not to be displayed
+     * to the user. It is only intended as an internal representation.
+     */
+    public final static String KEY_STROKE_DELIMITER = "\u0020"; //$NON-NLS-1$
+
+    /**
+     * An empty key sequence instance for use by everyone.
+     */
+    private final static KeySequence EMPTY_KEY_SEQUENCE = new KeySequence(
+            Collections.EMPTY_LIST);
+
+    /**
+     * An internal constant used only in this object's hash code algorithm.
+     */
+    private final static int HASH_FACTOR = 89;
+
+    /**
+     * An internal constant used only in this object's hash code algorithm.
+     */
+    private final static int HASH_INITIAL = KeySequence.class.getName()
+            .hashCode();
+
+    /**
+     * The set of delimiters for <code>KeyStroke</code> objects allowed
+     * during parsing of the formal string representation.
+     */
+    public final static String KEY_STROKE_DELIMITERS = KEY_STROKE_DELIMITER
+            + "\b\r\u007F\u001B\f\n\0\t\u000B"; //$NON-NLS-1$
+
+    /**
+     * Gets an instance of <code>KeySequence</code>.
+     *
+     * @return a key sequence. This key sequence will have no key strokes.
+     *         Guaranteed not to be <code>null</code>.
+     */
+    public static KeySequence getInstance() {
+        return EMPTY_KEY_SEQUENCE;
+    }
+
+    /**
+     * Gets an instance of <code>KeySequence</code> given a key sequence and
+     * a key stroke.
+     *
+     * @param keySequence
+     *            a key sequence. Must not be <code>null</code>.
+     * @param keyStroke
+     *            a key stroke. Must not be <code>null</code>.
+     * @return a key sequence that is equal to the given key sequence with the
+     *         given key stroke appended to the end. Guaranteed not to be
+     *         <code>null</code>.
+     */
+    public static KeySequence getInstance(KeySequence keySequence,
+            KeyStroke keyStroke) {
+        if (keySequence == null || keyStroke == null) {
+			throw new NullPointerException();
+		}
+
+        List keyStrokes = new ArrayList(keySequence.getKeyStrokes());
+        keyStrokes.add(keyStroke);
+        return new KeySequence(keyStrokes);
+    }
+
+    /**
+     * Gets an instance of <code>KeySequence</code> given a single key
+     * stroke.
+     *
+     * @param keyStroke
+     *            a single key stroke. Must not be <code>null</code>.
+     * @return a key sequence. Guaranteed not to be <code>null</code>.
+     */
+    public static KeySequence getInstance(KeyStroke keyStroke) {
+        return new KeySequence(Collections.singletonList(keyStroke));
+    }
+
+    /**
+     * Gets an instance of <code>KeySequence</code> given an array of key
+     * strokes.
+     *
+     * @param keyStrokes
+     *            the array of key strokes. This array may be empty, but it
+     *            must not be <code>null</code>. This array must not contain
+     *            <code>null</code> elements.
+     * @return a key sequence. Guaranteed not to be <code>null</code>.
+     */
+    public static KeySequence getInstance(KeyStroke[] keyStrokes) {
+        return new KeySequence(Arrays.asList(keyStrokes));
+    }
+
+    /**
+     * Gets an instance of <code>KeySequence</code> given a list of key
+     * strokes.
+     *
+     * @param keyStrokes
+     *            the list of key strokes. This list may be empty, but it must
+     *            not be <code>null</code>. If this list is not empty, it
+     *            must only contain instances of <code>KeyStroke</code>.
+     * @return a key sequence. Guaranteed not to be <code>null</code>.
+     */
+    public static KeySequence getInstance(List keyStrokes) {
+        return new KeySequence(keyStrokes);
+    }
+
+	/**
+	 * Gets an instance of <code>KeySequence</code> given a new-style key
+	 * sequence.
+	 *
+	 * @param newKeySequence
+	 *            The new-style key sequence to convert into a legacy key
+	 *            sequence; must not be <code>null</code>.
+	 * @return a key sequence; never <code>null</code>.
+	 */
+	public static final KeySequence getInstance(
+			final org.eclipse.jface.bindings.keys.KeySequence newKeySequence) {
+		final org.eclipse.jface.bindings.keys.KeyStroke[] newKeyStrokes = newKeySequence
+				.getKeyStrokes();
+		final int newKeyStrokesCount = newKeyStrokes.length;
+		final List legacyKeyStrokes = new ArrayList(newKeyStrokesCount);
+
+		for (int i = 0; i < newKeyStrokesCount; i++) {
+			final org.eclipse.jface.bindings.keys.KeyStroke newKeyStroke = newKeyStrokes[i];
+			legacyKeyStrokes.add(SWTKeySupport
+					.convertAcceleratorToKeyStroke(newKeyStroke
+							.getModifierKeys()
+							| newKeyStroke.getNaturalKey()));
+		}
+
+		return new KeySequence(legacyKeyStrokes);
+	}
+
+    /**
+     * Gets an instance of <code>KeySequence</code> by parsing a given a
+     * formal string representation.
+     *
+     * @param string
+     *            the formal string representation to parse.
+     * @return a key sequence. Guaranteed not to be <code>null</code>.
+     * @throws ParseException
+     *             if the given formal string representation could not be
+     *             parsed to a valid key sequence.
+     */
+    public static KeySequence getInstance(String string) throws ParseException {
+        if (string == null) {
+			throw new NullPointerException();
+		}
+
+        List keyStrokes = new ArrayList();
+        StringTokenizer stringTokenizer = new StringTokenizer(string,
+                KEY_STROKE_DELIMITERS);
+
+        while (stringTokenizer.hasMoreTokens()) {
+			keyStrokes.add(KeyStroke.getInstance(stringTokenizer.nextToken()));
+		}
+
+        try {
+            return new KeySequence(keyStrokes);
+        } catch (Throwable t) {
+            throw new ParseException(
+                    "Could not construct key sequence with these key strokes: " //$NON-NLS-1$
+                            + keyStrokes);
+        }
+    }
+
+    /**
+     * The cached hash code for this object. Because <code>KeySequence</code>
+     * objects are immutable, their hash codes need only to be computed once.
+     * After the first call to <code>hashCode()</code>, the computed value
+     * is cached here for all subsequent calls.
+     */
+    private transient int hashCode;
+
+    /**
+     * A flag to determine if the <code>hashCode</code> field has already
+     * been computed.
+     */
+    private transient boolean hashCodeComputed;
+
+    /**
+     * The list of key strokes for this key sequence.
+     */
+    private List keyStrokes;
+
+    /**
+     * Constructs an instance of <code>KeySequence</code> given a list of key
+     * strokes.
+     *
+     * @param keyStrokes
+     *            the list of key strokes. This list may be empty, but it must
+     *            not be <code>null</code>. If this list is not empty, it
+     *            must only contain instances of <code>KeyStroke</code>.
+     */
+    private KeySequence(List keyStrokes) {
+        this.keyStrokes = Util.safeCopy(keyStrokes, KeyStroke.class);
+
+        for (int i = 0; i < this.keyStrokes.size() - 1; i++) {
+            KeyStroke keyStroke = (KeyStroke) this.keyStrokes.get(i);
+
+            if (!keyStroke.isComplete()) {
+				throw new IllegalArgumentException();
+			}
+        }
+    }
+
+    /**
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+	public int compareTo(Object object) {
+        KeySequence castedObject = (KeySequence) object;
+        int compareTo = Util.compare(keyStrokes, castedObject.keyStrokes);
+        return compareTo;
+    }
+
+    /**
+     * Returns whether or not this key sequence ends with the given key
+     * sequence.
+     *
+     * @param keySequence
+     *            a key sequence. Must not be <code>null</code>.
+     * @param equals
+     *            whether or not an identical key sequence should be considered
+     *            as a possible match.
+     * @return <code>true</code>, iff the given key sequence ends with this
+     *         key sequence.
+     */
+    public boolean endsWith(KeySequence keySequence, boolean equals) {
+        if (keySequence == null) {
+			throw new NullPointerException();
+		}
+
+        return Util.endsWith(keyStrokes, keySequence.keyStrokes, equals);
+    }
+
+    /**
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+	public boolean equals(Object object) {
+        if (!(object instanceof KeySequence)) {
+			return false;
+		}
+
+        return keyStrokes.equals(((KeySequence) object).keyStrokes);
+    }
+
+    /**
+     * Formats this key sequence into the current default look.
+     *
+     * @return A string representation for this key sequence using the default
+     *         look; never <code>null</code>.
+     */
+    public String format() {
+        return KeyFormatterFactory.getDefault().format(this);
+    }
+
+    /**
+     * Returns the list of key strokes for this key sequence.
+     *
+     * @return the list of key strokes keys. This list may be empty, but is
+     *         guaranteed not to be <code>null</code>. If this list is not
+     *         empty, it is guaranteed to only contain instances of <code>KeyStroke</code>.
+     */
+    public List getKeyStrokes() {
+        return keyStrokes;
+    }
+
+    /**
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+	public int hashCode() {
+        if (!hashCodeComputed) {
+            hashCode = HASH_INITIAL;
+            hashCode = hashCode * HASH_FACTOR + keyStrokes.hashCode();
+            hashCodeComputed = true;
+        }
+
+        return hashCode;
+    }
+
+    /**
+     * Returns whether or not this key sequence is complete. Key sequences are
+     * complete iff all of their key strokes are complete.
+     *
+     * @return <code>true</code>, iff the key sequence is complete.
+     */
+    public boolean isComplete() {
+        return keyStrokes.isEmpty()
+                || ((KeyStroke) keyStrokes.get(keyStrokes.size() - 1))
+                        .isComplete();
+    }
+
+    /**
+     * Returns whether or not this key sequence is empty. Key sequences are
+     * complete iff they have no key strokes.
+     *
+     * @return <code>true</code>, iff the key sequence is empty.
+     */
+    public boolean isEmpty() {
+        return keyStrokes.isEmpty();
+    }
+
+    /**
+     * Returns whether or not this key sequence starts with the given key
+     * sequence.
+     *
+     * @param keySequence
+     *            a key sequence. Must not be <code>null</code>.
+     * @param equals
+     *            whether or not an identical key sequence should be considered
+     *            as a possible match.
+     * @return <code>true</code>, iff the given key sequence starts with
+     *         this key sequence.
+     */
+    public boolean startsWith(KeySequence keySequence, boolean equals) {
+        if (keySequence == null) {
+			throw new NullPointerException();
+		}
+
+        return Util.startsWith(keyStrokes, keySequence.keyStrokes, equals);
+    }
+
+    /**
+     * Returns the formal string representation for this key sequence.
+     *
+     * @return The formal string representation for this key sequence.
+     *         Guaranteed not to be <code>null</code>.
+     * @see java.lang.Object#toString()
+     */
+    @Override
+	public String toString() {
+        return KeyFormatterFactory.getFormalKeyFormatter().format(this);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/KeyStroke.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/KeyStroke.java
new file mode 100644
index 0000000..230596b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/KeyStroke.java
@@ -0,0 +1,363 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.keys;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Locale;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.StringTokenizer;
+import java.util.TreeSet;
+import org.eclipse.ui.internal.util.Util;
+
+/**
+ * <p>
+ * A <code>KeyStroke</code> is defined as an optional set of modifier keys
+ * followed optionally by a natural key. A <code>KeyStroke</code> is said to
+ * be complete if it contains a natural key. A natural key is any Unicode
+ * character (e.g., "backspace", etc.), any character belonging to a natural
+ * language (e.g., "A", "1", "[", etc.), or any special control character
+ * specific to computers (e.g., "F10", "PageUp", etc.).
+ * </p>
+ * <p>
+ * All <code>KeyStroke</code> objects have a formal string representation
+ * available via the <code>toString()</code> method. There are a number of
+ * methods to get instances of <code>KeyStroke</code> objects, including one
+ * which can parse this formal string representation.
+ * </p>
+ * <p>
+ * All <code>KeyStroke</code> objects, via the <code>format()</code> method,
+ * provide a version of their formal string representation translated by
+ * platform and locale, suitable for display to a user.
+ * </p>
+ * <p>
+ * <code>KeyStroke</code> objects are immutable. Clients are not permitted to
+ * extend this class.
+ * </p>
+ *
+ * @deprecated Please use org.eclipse.jface.bindings.keys.KeyStroke
+ * @since 3.0
+ * @see org.eclipse.ui.keys.ModifierKey
+ * @see org.eclipse.ui.keys.NaturalKey
+ */
+@Deprecated
+public final class KeyStroke implements Comparable {
+
+    /**
+     * The delimiter between multiple keys in a single key strokes -- expressed
+     * in the formal key stroke grammar. This is not to be displayed to the
+     * user. It is only intended as an internal representation.
+     */
+    public final static String KEY_DELIMITER = "\u002B"; //$NON-NLS-1$
+
+    /**
+     * An internal constant used only in this object's hash code algorithm.
+     */
+    private final static int HASH_FACTOR = 89;
+
+    /**
+     * An internal constant used only in this object's hash code algorithm.
+     */
+    private final static int HASH_INITIAL = KeyStroke.class.getName()
+            .hashCode();
+
+    /**
+     * The set of delimiters for <code>Key</code> objects allowed during
+     * parsing of the formal string representation.
+     */
+    public final static String KEY_DELIMITERS = KEY_DELIMITER;
+
+    /**
+     * Gets an instance of <code>KeyStroke</code> given a single modifier key
+     * and a natural key.
+     *
+     * @param modifierKey
+     *            a modifier key. Must not be <code>null</code>.
+     * @param naturalKey
+     *            the natural key. May be <code>null</code>.
+     * @return a key stroke. Guaranteed not to be <code>null</code>.
+     */
+    public static KeyStroke getInstance(ModifierKey modifierKey,
+            NaturalKey naturalKey) {
+        if (modifierKey == null) {
+			throw new NullPointerException();
+		}
+
+        return new KeyStroke(
+                new TreeSet(Collections.singletonList(modifierKey)), naturalKey);
+    }
+
+    /**
+     * Gets an instance of <code>KeyStroke</code> given an array of modifier
+     * keys and a natural key.
+     *
+     * @param modifierKeys
+     *            the array of modifier keys. This array may be empty, but it
+     *            must not be <code>null</code>. If this array is not empty,
+     *            it must not contain <code>null</code> elements.
+     * @param naturalKey
+     *            the natural key. May be <code>null</code>.
+     * @return a key stroke. Guaranteed not to be <code>null</code>.
+     */
+    public static KeyStroke getInstance(ModifierKey[] modifierKeys,
+            NaturalKey naturalKey) {
+        Util.assertInstance(modifierKeys, ModifierKey.class);
+        return new KeyStroke(new TreeSet(Arrays.asList(modifierKeys)),
+                naturalKey);
+    }
+
+    /**
+     * Gets an instance of <code>KeyStroke</code> given a natural key.
+     *
+     * @param naturalKey
+     *            the natural key. May be <code>null</code>.
+     * @return a key stroke. This key stroke will have no modifier keys.
+     *         Guaranteed not to be <code>null</code>.
+     */
+    public static KeyStroke getInstance(NaturalKey naturalKey) {
+        return new KeyStroke(Util.EMPTY_SORTED_SET, naturalKey);
+    }
+
+    /**
+     * Gets an instance of <code>KeyStroke</code> given a set of modifier
+     * keys and a natural key.
+     *
+     * @param modifierKeys
+     *            the set of modifier keys. This set may be empty, but it must
+     *            not be <code>null</code>. If this set is not empty, it
+     *            must only contain instances of <code>ModifierKey</code>.
+     * @param naturalKey
+     *            the natural key. May be <code>null</code>.
+     * @return a key stroke. Guaranteed not to be <code>null</code>.
+     */
+    public static KeyStroke getInstance(SortedSet modifierKeys,
+            NaturalKey naturalKey) {
+        return new KeyStroke(modifierKeys, naturalKey);
+    }
+
+    /**
+     * Gets an instance of <code>KeyStroke</code> by parsing a given a formal
+     * string representation.
+     *
+     * @param string
+     *            the formal string representation to parse.
+     * @return a key stroke. Guaranteed not to be <code>null</code>.
+     * @throws ParseException
+     *             if the given formal string representation could not be
+     *             parsed to a valid key stroke.
+     */
+    public static KeyStroke getInstance(String string) throws ParseException {
+        if (string == null) {
+			throw new NullPointerException();
+		}
+
+        SortedSet modifierKeys = new TreeSet();
+        NaturalKey naturalKey = null;
+        StringTokenizer stringTokenizer = new StringTokenizer(string,
+                KEY_DELIMITERS, true);
+        int i = 0;
+
+        while (stringTokenizer.hasMoreTokens()) {
+            String token = stringTokenizer.nextToken();
+
+            if (i % 2 == 0) {
+                if (stringTokenizer.hasMoreTokens()) {
+					token = token.toUpperCase(Locale.ENGLISH);
+                    ModifierKey modifierKey = (ModifierKey) ModifierKey.modifierKeysByName
+                            .get(token);
+
+                    if (modifierKey == null || !modifierKeys.add(modifierKey)) {
+						throw new ParseException(
+                                "Cannot create key stroke with duplicate or non-existent modifier key: " //$NON-NLS-1$
+                                        + token);
+					}
+                } else if (token.length() == 1) {
+                    naturalKey = CharacterKey.getInstance(token.charAt(0));
+                    break;
+                } else {
+					token = token.toUpperCase(Locale.ENGLISH);
+                    naturalKey = (NaturalKey) CharacterKey.characterKeysByName
+                            .get(token);
+
+                    if (naturalKey == null) {
+						naturalKey = (NaturalKey) SpecialKey.specialKeysByName
+                                .get(token);
+					}
+
+                    if (naturalKey == null) {
+						throw new ParseException(
+                                "Cannot create key stroke with invalid natural key: " //$NON-NLS-1$
+                                        + token);
+					}
+                }
+            }
+
+            i++;
+        }
+
+        try {
+            return new KeyStroke(modifierKeys, naturalKey);
+        } catch (Throwable t) {
+            throw new ParseException("Cannot create key stroke with " //$NON-NLS-1$
+                    + modifierKeys + " and " + naturalKey); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * The cached hash code for this object. Because <code>KeyStroke</code>
+     * objects are immutable, their hash codes need only to be computed once.
+     * After the first call to <code>hashCode()</code>, the computed value
+     * is cached here for all subsequent calls.
+     */
+    private transient int hashCode;
+
+    /**
+     * A flag to determine if the <code>hashCode</code> field has already
+     * been computed.
+     */
+    private transient boolean hashCodeComputed;
+
+    /**
+     * The set of modifier keys for this key stroke.
+     */
+    private SortedSet modifierKeys;
+
+    /**
+     * The set of modifier keys for this key stroke in the form of an array.
+     * Used internally by <code>int compareTo(Object)</code>.
+     */
+    private transient ModifierKey[] modifierKeysAsArray;
+
+    /**
+     * The natural key for this key stroke.
+     */
+    private NaturalKey naturalKey;
+
+    /**
+     * Constructs an instance of <code>KeyStroke</code> given a set of
+     * modifier keys and a natural key.
+     *
+     * @param modifierKeys
+     *            the set of modifier keys. This set may be empty, but it must
+     *            not be <code>null</code>. If this set is not empty, it
+     *            must only contain instances of <code>ModifierKey</code>.
+     * @param naturalKey
+     *            the natural key. May be <code>null</code>.
+     */
+    private KeyStroke(SortedSet modifierKeys, NaturalKey naturalKey) {
+        this.modifierKeys = Util.safeCopy(modifierKeys, ModifierKey.class);
+        this.naturalKey = naturalKey;
+        this.modifierKeysAsArray = (ModifierKey[]) this.modifierKeys
+                .toArray(new ModifierKey[this.modifierKeys.size()]);
+    }
+
+    /**
+     * @see java.lang.Comparable#compareTo(java.lang.Object)
+     */
+    @Override
+	public int compareTo(Object object) {
+        KeyStroke castedObject = (KeyStroke) object;
+        int compareTo = Util.compare(modifierKeysAsArray,
+                castedObject.modifierKeysAsArray);
+
+        if (compareTo == 0) {
+			compareTo = Util.compare(naturalKey, castedObject.naturalKey);
+		}
+
+        return compareTo;
+    }
+
+    /**
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+	public boolean equals(Object object) {
+        if (!(object instanceof KeyStroke)) {
+			return false;
+		}
+
+        KeyStroke castedObject = (KeyStroke) object;
+
+        if (!modifierKeys.equals(castedObject.modifierKeys)) {
+			return false;
+		}
+        return Util.equals(naturalKey, castedObject.naturalKey);
+    }
+
+    /**
+     * Formats this key stroke into the current default look.
+     *
+     * @return A string representation for this key stroke using the default
+     *         look; never <code>null</code>.
+     */
+    public String format() {
+        return KeyFormatterFactory.getDefault().format(this);
+    }
+
+    /**
+     * Returns the set of modifier keys for this key stroke.
+     *
+     * @return the set of modifier keys. This set may be empty, but is
+     *         guaranteed not to be <code>null</code>. If this set is not
+     *         empty, it is guaranteed to only contain instances of <code>ModifierKey</code>.
+     */
+    public Set getModifierKeys() {
+        return Collections.unmodifiableSet(modifierKeys);
+    }
+
+    /**
+     * Returns the natural key for this key stroke.
+     *
+     * @return the natural key. May be <code>null</code>.
+     */
+    public NaturalKey getNaturalKey() {
+        return naturalKey;
+    }
+
+    /**
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+	public int hashCode() {
+        if (!hashCodeComputed) {
+            hashCode = HASH_INITIAL;
+            hashCode = hashCode * HASH_FACTOR + modifierKeys.hashCode();
+            hashCode = hashCode * HASH_FACTOR + Util.hashCode(naturalKey);
+            hashCodeComputed = true;
+        }
+
+        return hashCode;
+    }
+
+    /**
+     * Returns whether or not this key stroke is complete. Key strokes are
+     * complete iff they have a natural key which is not <code>null</code>.
+     *
+     * @return <code>true</code>, iff the key stroke is complete.
+     */
+    public boolean isComplete() {
+        return naturalKey != null;
+    }
+
+    /**
+     * Returns the formal string representation for this key stroke.
+     *
+     * @return The formal string representation for this key stroke. Guaranteed
+     *         not to be <code>null</code>.
+     * @see java.lang.Object#toString()
+     */
+    @Override
+	public String toString() {
+        return KeyFormatterFactory.getFormalKeyFormatter().format(this);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/ModifierKey.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/ModifierKey.java
new file mode 100644
index 0000000..1d18349
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/ModifierKey.java
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.keys;
+
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.eclipse.jface.bindings.keys.IKeyLookup;
+import org.eclipse.jface.bindings.keys.KeyLookupFactory;
+import org.eclipse.jface.util.Util;
+
+/**
+ * <p>
+ * Instances of <code>ModifierKey</code> represent the four keys on the
+ * keyboard recognized by convention as 'modifier keys', those keys typically
+ * pressed in combination with themselves and/or a
+ * {@link org.eclipse.ui.keys.NaturalKey}.
+ * </p>
+ * <p>
+ * <code>ModifierKey</code> objects are immutable. Clients are not permitted
+ * to extend this class.
+ * </p>
+ *
+ * @deprecated Please use org.eclipse.jface.bindings.keys.KeyStroke and
+ *             org.eclipse.jface.bindings.keys.KeyLookupFactory
+ * @since 3.0
+ * @see org.eclipse.ui.keys.NaturalKey
+ */
+@Deprecated
+public final class ModifierKey extends Key {
+
+	/**
+	 * An internal map used to lookup instances of <code>ModifierKey</code>
+	 * given the formal string representation of a modifier key.
+	 */
+	static SortedMap modifierKeysByName = new TreeMap();
+
+	/**
+	 * The single static instance of <code>ModifierKey</code> which represents
+	 * the 'Alt' key.
+	 */
+	public final static ModifierKey ALT;
+
+	/**
+	 * The single static instance of <code>ModifierKey</code> which represents
+	 * the 'Command' key.
+	 */
+	public final static ModifierKey COMMAND;
+
+	/**
+	 * The single static instance of <code>ModifierKey</code> which represents
+	 * the 'Ctrl' key.
+	 */
+	public final static ModifierKey CTRL;
+
+	/**
+	 * The name of the 'M1' key.
+	 */
+	private final static String M1_NAME = "M1"; //$NON-NLS-1$
+
+	/**
+	 * The name of the 'M2' key.
+	 */
+	private final static String M2_NAME = "M2"; //$NON-NLS-1$
+
+	/**
+	 * The name of the 'M3' key.
+	 */
+	private final static String M3_NAME = "M3"; //$NON-NLS-1$
+
+	/**
+	 * The name of the 'M4' key.
+	 */
+	private final static String M4_NAME = "M4"; //$NON-NLS-1$
+
+	/**
+	 * The single static instance of <code>ModifierKey</code> which represents
+	 * the 'Shift' key.
+	 */
+	public final static ModifierKey SHIFT;
+
+	static {
+		final IKeyLookup lookup = KeyLookupFactory.getDefault();
+		ALT = new ModifierKey(lookup.getAlt());
+		COMMAND = new ModifierKey(lookup.getCommand());
+		CTRL = new ModifierKey(lookup.getCtrl());
+		SHIFT = new ModifierKey(lookup.getShift());
+
+		modifierKeysByName.put(ModifierKey.ALT.toString(), ModifierKey.ALT);
+		modifierKeysByName.put(ModifierKey.COMMAND.toString(),
+				ModifierKey.COMMAND);
+		modifierKeysByName.put(ModifierKey.CTRL.toString(), ModifierKey.CTRL);
+		modifierKeysByName.put(ModifierKey.SHIFT.toString(), ModifierKey.SHIFT);
+		modifierKeysByName
+				.put(
+						M1_NAME,
+						Util.isMac() ? ModifierKey.COMMAND : ModifierKey.CTRL);
+		modifierKeysByName.put(M2_NAME, ModifierKey.SHIFT);
+		modifierKeysByName.put(M3_NAME, ModifierKey.ALT);
+		modifierKeysByName
+				.put(
+						M4_NAME,
+						Util.isMac() ? ModifierKey.CTRL : ModifierKey.COMMAND);
+	}
+
+	/**
+	 * Constructs an instance of <code>ModifierKey</code> given a name.
+	 *
+	 * @param key
+	 *            The key which this key wraps.
+	 */
+	private ModifierKey(final int key) {
+		super(key);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/NaturalKey.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/NaturalKey.java
new file mode 100644
index 0000000..542cc52
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/NaturalKey.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.keys;
+
+/**
+ * </p>
+ * Instances of <code>NaturalKey</code> represent all keys on the keyboard not
+ * known by convention as 'modifier keys'. These can either be keys that belong
+ * to a natural language of some kind(e.g., "A", "1"), any Unicode character
+ * (e.g., "backspace"), or they can be special controls keys used by computers
+ * (e.g., "F10", "PageUp").
+ * </p>
+ * <p>
+ * <code>NaturalKey</code> objects are immutable. Clients are not permitted to
+ * extend this class.
+ * </p>
+ *
+ * @deprecated Please use org.eclipse.jface.bindings.keys.KeyStroke and
+ *             org.eclipse.jface.bindings.keys.KeyLookupFactory
+ * @since 3.0
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+@Deprecated
+public abstract class NaturalKey extends Key {
+
+	/**
+	 * Constructs an instance of <code>NaturalKey</code> given a name.
+	 *
+	 * @param key
+	 *            The key to be wrapped.
+	 */
+	NaturalKey(final int key) {
+		super(key);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/ParseException.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/ParseException.java
new file mode 100644
index 0000000..5c17546
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/ParseException.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.keys;
+
+/**
+ * <p>
+ * An exception indicating problems while parsing formal string representations
+ * of either <code>KeyStroke</code> or <code>KeySequence</code> objects.
+ * </p>
+ * <p>
+ * <code>ParseException</code> objects are immutable. Clients are not
+ * permitted to extend this class.
+ * </p>
+ *
+ * @deprecated Please use org.eclipse.jface.bindings.keys.ParseException
+ * @since 3.0
+ */
+@Deprecated
+public final class ParseException extends Exception {
+
+    /**
+     * Generated serial version UID for this class.
+     * @since 3.1
+     */
+    private static final long serialVersionUID = 3257009864814376241L;
+
+    /**
+     * Constructs a <code>ParseException</code> with the specified detail
+     * message.
+     *
+     * @param s
+     *            the detail message.
+     */
+    public ParseException(final String s) {
+        super(s);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/SWTKeySupport.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/SWTKeySupport.java
new file mode 100644
index 0000000..12b965a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/SWTKeySupport.java
@@ -0,0 +1,462 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.keys;
+
+import java.util.Iterator;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.ui.internal.keys.NativeKeyFormatter;
+
+/**
+ * A utility class for converting SWT events into key strokes.
+ *
+ * @deprecated Please use {@link org.eclipse.jface.bindings.keys.SWTKeySupport}
+ * @since 3.0
+ */
+@Deprecated
+public final class SWTKeySupport {
+
+    /**
+     * Given an SWT accelerator value, provide the corresponding key stroke.
+     *
+     * @param accelerator
+     *            The accelerator to convert; should be a valid SWT accelerator
+     *            value.
+     * @return The equivalent key stroke; never <code>null</code>.
+     */
+    public static KeyStroke convertAcceleratorToKeyStroke(int accelerator) {
+        final SortedSet modifierKeys = new TreeSet();
+		NaturalKey naturalKey;
+
+        if ((accelerator & SWT.ALT) != 0) {
+			modifierKeys.add(ModifierKey.ALT);
+		}
+
+        if ((accelerator & SWT.COMMAND) != 0) {
+			modifierKeys.add(ModifierKey.COMMAND);
+		}
+
+        if ((accelerator & SWT.CTRL) != 0) {
+			modifierKeys.add(ModifierKey.CTRL);
+		}
+
+        if ((accelerator & SWT.SHIFT) != 0) {
+			modifierKeys.add(ModifierKey.SHIFT);
+		}
+
+        if (((accelerator & SWT.KEY_MASK) == 0) && (accelerator != 0)) {
+            // There were only accelerators
+            naturalKey = null;
+        } else {
+            // There were other keys.
+            accelerator &= SWT.KEY_MASK;
+
+            switch (accelerator) {
+            case SWT.ARROW_DOWN:
+                naturalKey = SpecialKey.ARROW_DOWN;
+                break;
+            case SWT.ARROW_LEFT:
+                naturalKey = SpecialKey.ARROW_LEFT;
+                break;
+            case SWT.ARROW_RIGHT:
+                naturalKey = SpecialKey.ARROW_RIGHT;
+                break;
+            case SWT.ARROW_UP:
+                naturalKey = SpecialKey.ARROW_UP;
+                break;
+            case SWT.BREAK:
+                naturalKey = SpecialKey.BREAK;
+                break;
+            case SWT.CAPS_LOCK:
+                naturalKey = SpecialKey.CAPS_LOCK;
+                break;
+            case SWT.END:
+                naturalKey = SpecialKey.END;
+                break;
+            case SWT.F1:
+                naturalKey = SpecialKey.F1;
+                break;
+            case SWT.F10:
+                naturalKey = SpecialKey.F10;
+                break;
+            case SWT.F11:
+                naturalKey = SpecialKey.F11;
+                break;
+            case SWT.F12:
+                naturalKey = SpecialKey.F12;
+                break;
+            case SWT.F2:
+                naturalKey = SpecialKey.F2;
+                break;
+            case SWT.F3:
+                naturalKey = SpecialKey.F3;
+                break;
+            case SWT.F4:
+                naturalKey = SpecialKey.F4;
+                break;
+            case SWT.F5:
+                naturalKey = SpecialKey.F5;
+                break;
+            case SWT.F6:
+                naturalKey = SpecialKey.F6;
+                break;
+            case SWT.F7:
+                naturalKey = SpecialKey.F7;
+                break;
+            case SWT.F8:
+                naturalKey = SpecialKey.F8;
+                break;
+            case SWT.F9:
+                naturalKey = SpecialKey.F9;
+                break;
+            case SWT.HOME:
+                naturalKey = SpecialKey.HOME;
+                break;
+            case SWT.INSERT:
+                naturalKey = SpecialKey.INSERT;
+                break;
+            case SWT.KEYPAD_0:
+                naturalKey = SpecialKey.NUMPAD_0;
+                break;
+            case SWT.KEYPAD_1:
+                naturalKey = SpecialKey.NUMPAD_1;
+                break;
+            case SWT.KEYPAD_2:
+                naturalKey = SpecialKey.NUMPAD_2;
+                break;
+            case SWT.KEYPAD_3:
+                naturalKey = SpecialKey.NUMPAD_3;
+                break;
+            case SWT.KEYPAD_4:
+                naturalKey = SpecialKey.NUMPAD_4;
+                break;
+            case SWT.KEYPAD_5:
+                naturalKey = SpecialKey.NUMPAD_5;
+                break;
+            case SWT.KEYPAD_6:
+                naturalKey = SpecialKey.NUMPAD_6;
+                break;
+            case SWT.KEYPAD_7:
+                naturalKey = SpecialKey.NUMPAD_7;
+                break;
+            case SWT.KEYPAD_8:
+                naturalKey = SpecialKey.NUMPAD_8;
+                break;
+            case SWT.KEYPAD_9:
+                naturalKey = SpecialKey.NUMPAD_9;
+                break;
+            case SWT.KEYPAD_ADD:
+                naturalKey = SpecialKey.NUMPAD_ADD;
+                break;
+            case SWT.KEYPAD_CR:
+                naturalKey = SpecialKey.NUMPAD_ENTER;
+                break;
+            case SWT.KEYPAD_DECIMAL:
+                naturalKey = SpecialKey.NUMPAD_DECIMAL;
+                break;
+            case SWT.KEYPAD_DIVIDE:
+                naturalKey = SpecialKey.NUMPAD_DIVIDE;
+                break;
+            case SWT.KEYPAD_EQUAL:
+                naturalKey = SpecialKey.NUMPAD_EQUAL;
+                break;
+            case SWT.KEYPAD_MULTIPLY:
+                naturalKey = SpecialKey.NUMPAD_MULTIPLY;
+                break;
+            case SWT.KEYPAD_SUBTRACT:
+                naturalKey = SpecialKey.NUMPAD_SUBTRACT;
+                break;
+            case SWT.NUM_LOCK:
+                naturalKey = SpecialKey.NUM_LOCK;
+                break;
+            case SWT.PAGE_DOWN:
+                naturalKey = SpecialKey.PAGE_DOWN;
+                break;
+            case SWT.PAGE_UP:
+                naturalKey = SpecialKey.PAGE_UP;
+                break;
+            case SWT.PAUSE:
+                naturalKey = SpecialKey.PAUSE;
+                break;
+            case SWT.PRINT_SCREEN:
+                naturalKey = SpecialKey.PRINT_SCREEN;
+                break;
+            case SWT.SCROLL_LOCK:
+                naturalKey = SpecialKey.SCROLL_LOCK;
+                break;
+            default:
+                naturalKey = CharacterKey
+                        .getInstance((char) (accelerator & 0xFFFF));
+            }
+        }
+
+        return KeyStroke.getInstance(modifierKeys, naturalKey);
+    }
+
+    /**
+     * <p>
+     * Converts the given event into an SWT accelerator value -- considering the
+     * modified character with the shift modifier. This is the third accelerator
+     * value that should be checked.
+     * </p>
+     * <p>
+     * For example, on a standard US keyboard, "Ctrl+Shift+5" would be viewed as
+     * "Ctrl+Shift+%".
+     * </p>
+     *
+     * @param event
+     *            The event to be converted; must not be <code>null</code>.
+     * @return The combination of the state mask and the unmodified character.
+     */
+    public static int convertEventToModifiedAccelerator(Event event) {
+        int modifiers = event.stateMask & SWT.MODIFIER_MASK;
+        char character = topKey(event);
+        return modifiers + toUpperCase(character);
+    }
+
+    /**
+     * <p>
+     * Converts the given event into an SWT accelerator value -- considering the
+     * unmodified character with all modifier keys. This is the first
+     * accelerator value that should be checked. However, all alphabetic
+     * characters are considered as their uppercase equivalents.
+     * </p>
+     * <p>
+     * For example, on a standard US keyboard, "Ctrl+Shift+5" would be viewed as
+     * "Ctrl+Shift+5".
+     * </p>
+     *
+     * @param event
+     *            The event to be converted; must not be <code>null</code>.
+     * @return The combination of the state mask and the unmodified character.
+     */
+    public static int convertEventToUnmodifiedAccelerator(Event event) {
+        return convertEventToUnmodifiedAccelerator(event.stateMask,
+                event.keyCode);
+    }
+
+    /**
+     * <p>
+     * Converts the given state mask and key code into an SWT accelerator value --
+     * considering the unmodified character with all modifier keys. All
+     * alphabetic characters are considered as their uppercase equivalents.
+     * </p>
+     * <p>
+     * For example, on a standard US keyboard, "Ctrl+Shift+5" would be viewed as
+     * "Ctrl+Shift+5".
+     * </p>
+     *
+     * @param stateMask
+     *            The integer mask of modifiers keys depressed when this was
+     *            pressed.
+     * @param keyCode
+     *            The key that was pressed, before being modified.
+     * @return The combination of the state mask and the unmodified character.
+     */
+    private static int convertEventToUnmodifiedAccelerator(int stateMask,
+            int keyCode) {
+        int modifiers = stateMask & SWT.MODIFIER_MASK;
+        int character = keyCode;
+        return modifiers + toUpperCase(character);
+    }
+
+    /**
+     * <p>
+     * Converts the given event into an SWT accelerator value -- considering the
+     * unmodified character with all modifier keys. This is the first
+     * accelerator value that should be checked. However, all alphabetic
+     * characters are considered as their uppercase equivalents.
+     * </p>
+     * <p>
+     * For example, on a standard US keyboard, "Ctrl+Shift+5" would be viewed as
+     * "Ctrl+%".
+     * </p>
+     *
+     * @param event
+     *            The event to be converted; must not be <code>null</code>.
+     * @return The combination of the state mask and the unmodified character.
+     */
+    public static int convertEventToUnmodifiedAccelerator(KeyEvent event) {
+        return convertEventToUnmodifiedAccelerator(event.stateMask,
+                event.keyCode);
+    }
+
+    /**
+     * Converts the given event into an SWT accelerator value -- considering
+     * the modified character without the shift modifier. This is the second
+     * accelerator value that should be checked. Key strokes with alphabetic
+     * natural keys are run through <code>convertEventToUnmodifiedAccelerator</code>
+     *
+     * @param event
+     *            The event to be converted; must not be <code>null</code>.
+     * @return The combination of the state mask without shift, and the
+     *         modified character.
+     */
+    public static int convertEventToUnshiftedModifiedAccelerator(Event event) {
+        // Disregard alphabetic key strokes.
+        if (Character.isLetter((char) event.keyCode)) {
+            return convertEventToUnmodifiedAccelerator(event);
+        }
+
+        int modifiers = event.stateMask & (SWT.MODIFIER_MASK ^ SWT.SHIFT);
+        char character = topKey(event);
+        return modifiers + toUpperCase(character);
+    }
+
+    /**
+     * Given a key stroke, this method provides the equivalent SWT accelerator
+     * value. The functional inverse of <code>convertAcceleratorToKeyStroke</code>.
+     *
+     * @param keyStroke
+     *            The key stroke to convert; must not be <code>null</code>.
+     * @return The SWT accelerator value
+     */
+    public static final int convertKeyStrokeToAccelerator(
+            final KeyStroke keyStroke) {
+        int accelerator = 0;
+        final Iterator iterator = keyStroke.getModifierKeys().iterator();
+
+        while (iterator.hasNext()) {
+            final ModifierKey modifierKey = (ModifierKey) iterator.next();
+
+            if (modifierKey == ModifierKey.ALT) {
+				accelerator |= SWT.ALT;
+			} else if (modifierKey == ModifierKey.COMMAND) {
+				accelerator |= SWT.COMMAND;
+			} else if (modifierKey == ModifierKey.CTRL) {
+				accelerator |= SWT.CTRL;
+			} else if (modifierKey == ModifierKey.SHIFT) {
+				accelerator |= SWT.SHIFT;
+			}
+        }
+
+        final NaturalKey naturalKey = keyStroke.getNaturalKey();
+
+        if (naturalKey instanceof CharacterKey) {
+			accelerator |= ((CharacterKey) naturalKey).getCharacter();
+		} else if (naturalKey instanceof SpecialKey) {
+            final SpecialKey specialKey = (SpecialKey) naturalKey;
+
+            if (specialKey == SpecialKey.ARROW_DOWN) {
+				accelerator |= SWT.ARROW_DOWN;
+			} else if (specialKey == SpecialKey.ARROW_LEFT) {
+				accelerator |= SWT.ARROW_LEFT;
+			} else if (specialKey == SpecialKey.ARROW_RIGHT) {
+				accelerator |= SWT.ARROW_RIGHT;
+			} else if (specialKey == SpecialKey.ARROW_UP) {
+				accelerator |= SWT.ARROW_UP;
+			} else if (specialKey == SpecialKey.END) {
+				accelerator |= SWT.END;
+			} else if (specialKey == SpecialKey.F1) {
+				accelerator |= SWT.F1;
+			} else if (specialKey == SpecialKey.F10) {
+				accelerator |= SWT.F10;
+			} else if (specialKey == SpecialKey.F11) {
+				accelerator |= SWT.F11;
+			} else if (specialKey == SpecialKey.F12) {
+				accelerator |= SWT.F12;
+			} else if (specialKey == SpecialKey.F2) {
+				accelerator |= SWT.F2;
+			} else if (specialKey == SpecialKey.F3) {
+				accelerator |= SWT.F3;
+			} else if (specialKey == SpecialKey.F4) {
+				accelerator |= SWT.F4;
+			} else if (specialKey == SpecialKey.F5) {
+				accelerator |= SWT.F5;
+			} else if (specialKey == SpecialKey.F6) {
+				accelerator |= SWT.F6;
+			} else if (specialKey == SpecialKey.F7) {
+				accelerator |= SWT.F7;
+			} else if (specialKey == SpecialKey.F8) {
+				accelerator |= SWT.F8;
+			} else if (specialKey == SpecialKey.F9) {
+				accelerator |= SWT.F9;
+			} else if (specialKey == SpecialKey.HOME) {
+				accelerator |= SWT.HOME;
+			} else if (specialKey == SpecialKey.INSERT) {
+				accelerator |= SWT.INSERT;
+			} else if (specialKey == SpecialKey.PAGE_DOWN) {
+				accelerator |= SWT.PAGE_DOWN;
+			} else if (specialKey == SpecialKey.PAGE_UP) {
+				accelerator |= SWT.PAGE_UP;
+			}
+        }
+
+        return accelerator;
+    }
+
+    private static final IKeyFormatter NATIVE_FORMATTER = new NativeKeyFormatter();
+
+    /**
+     * Provides an instance of <code>IKeyFormatter</code> appropriate for the
+     * current instance.
+     *
+     * @return an instance of <code>IKeyFormatter</code> appropriate for the
+     *         current instance; never <code>null</code>.
+     */
+    public static IKeyFormatter getKeyFormatterForPlatform() {
+        return NATIVE_FORMATTER;
+    }
+
+    /**
+     * Makes sure that a fully-modified character is converted to the normal
+     * form. This means that "Ctrl+" key strokes must reverse the modification
+     * caused by control-escaping. Also, all lower case letters are converted
+     * to uppercase.
+     *
+     * @param event
+     *            The event from which the fully-modified character should be
+     *            pulled.
+     * @return The modified character, uppercase and without control-escaping.
+     */
+    private static char topKey(Event event) {
+        char character = event.character;
+        boolean ctrlDown = (event.stateMask & SWT.CTRL) != 0;
+
+        if (ctrlDown && event.character != event.keyCode
+                && event.character < 0x20) {
+			character += 0x40;
+		}
+
+        return character;
+    }
+
+    /**
+     * Makes the given character uppercase if it is a letter.
+     *
+     * @param keyCode
+     *            The character to convert.
+     * @return The uppercase equivalent, if any; otherwise, the character
+     *         itself.
+     */
+    private static int toUpperCase(int keyCode) {
+        // Will this key code be truncated?
+        if (keyCode > 0xFFFF) {
+            return keyCode;
+        }
+
+        // Downcast in safety. Only make characters uppercase.
+        char character = (char) keyCode;
+        return Character.isLetter(character) ? Character.toUpperCase(character)
+                : keyCode;
+    }
+
+    /**
+     * This class should never be instantiated.
+     */
+    private SWTKeySupport() {
+        // This class should never be instantiated.
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/SpecialKey.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/SpecialKey.java
new file mode 100644
index 0000000..9f27d12
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/SpecialKey.java
@@ -0,0 +1,491 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.keys;
+
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.eclipse.jface.bindings.keys.IKeyLookup;
+import org.eclipse.jface.bindings.keys.KeyLookupFactory;
+
+/**
+ * <p>
+ * Instances of <code>SpecialKey</code> represent the keys on keyboard
+ * recognized as neither modifier keys nor character keys. These are special
+ * control keys specific to computers (e.g., "left arrow", "page down", "F10",
+ * etc.). They do not include keys representing letters, numbers or punctuation
+ * from a natural language, nor do they include any key that can be represented
+ * by a Unicode character (e.g., "backspace").
+ * </p>
+ * <p>
+ * <code>SpecialKey</code> objects are immutable. Clients are not permitted to
+ * extend this class.
+ * </p>
+ *
+ * @deprecated Please use org.eclipse.jface.bindings.keys.KeyStroke and
+ *             org.eclipse.jface.bindings.keys.KeyLookupFactory
+ * @since 3.0
+ */
+@Deprecated
+public final class SpecialKey extends NaturalKey {
+
+	/**
+	 * An internal map used to lookup instances of <code>SpecialKey</code>
+	 * given the formal string representation of a special key.
+	 */
+	static SortedMap specialKeysByName = new TreeMap();
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the 'Arrow Down' key.
+	 */
+	public final static SpecialKey ARROW_DOWN;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the 'Arrow Left' key.
+	 */
+	public final static SpecialKey ARROW_LEFT;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the 'Arrow Right' key.
+	 */
+	public final static SpecialKey ARROW_RIGHT;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the 'Arrow Up' key.
+	 */
+	public final static SpecialKey ARROW_UP;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the 'Break' key.
+	 */
+	public final static SpecialKey BREAK;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the 'Caps Lock' key.
+	 */
+	public final static SpecialKey CAPS_LOCK;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the 'End' key.
+	 */
+	public final static SpecialKey END;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the 'F1' key.
+	 */
+	public final static SpecialKey F1;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the 'F10' key.
+	 */
+	public final static SpecialKey F10;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the 'F11' key.
+	 */
+	public final static SpecialKey F11;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the 'F12' key.
+	 */
+	public final static SpecialKey F12;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the 'F13' key.
+	 */
+	public final static SpecialKey F13;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the 'F14' key.
+	 */
+	public final static SpecialKey F14;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the 'F15' key.
+	 */
+	public final static SpecialKey F15;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the 'F2' key.
+	 */
+	public final static SpecialKey F2;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the 'F3' key.
+	 */
+	public final static SpecialKey F3;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the 'F4' key.
+	 */
+	public final static SpecialKey F4;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the 'F5' key.
+	 */
+	public final static SpecialKey F5;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the 'F6' key.
+	 */
+	public final static SpecialKey F6;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the 'F7' key.
+	 */
+	public final static SpecialKey F7;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the 'F8' key.
+	 */
+	public final static SpecialKey F8;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the 'F9' key.
+	 */
+	public final static SpecialKey F9;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the 'Home' key.
+	 */
+	public final static SpecialKey HOME;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the 'Insert' key.
+	 */
+	public final static SpecialKey INSERT;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the 'NumLock' key.
+	 */
+	public final static SpecialKey NUM_LOCK;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the '0' key on the numpad.
+	 */
+	public final static SpecialKey NUMPAD_0;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the '1' key on the numpad.
+	 */
+	public final static SpecialKey NUMPAD_1;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the '2' key on the numpad.
+	 */
+	public final static SpecialKey NUMPAD_2;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the '3' key on the numpad.
+	 */
+	public final static SpecialKey NUMPAD_3;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the '4' key on the numpad.
+	 */
+	public final static SpecialKey NUMPAD_4;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the '5' key on the numpad.
+	 */
+	public final static SpecialKey NUMPAD_5;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the '6' key on the numpad.
+	 */
+	public final static SpecialKey NUMPAD_6;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the '7' key on the numpad.
+	 */
+	public final static SpecialKey NUMPAD_7;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the '8' key on the numpad.
+	 */
+	public final static SpecialKey NUMPAD_8;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the '9' key on the numpad.
+	 */
+	public final static SpecialKey NUMPAD_9;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the 'Add' key on the numpad.
+	 */
+	public final static SpecialKey NUMPAD_ADD;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the 'Decimal' key on the numpad.
+	 */
+	public final static SpecialKey NUMPAD_DECIMAL;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the 'Divide' key on the numpad.
+	 */
+	public final static SpecialKey NUMPAD_DIVIDE;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the 'Enter' key on the numpad.
+	 */
+	public final static SpecialKey NUMPAD_ENTER;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the '=' key on the numpad.
+	 */
+	public final static SpecialKey NUMPAD_EQUAL;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the 'Multiply' key on the numpad.
+	 */
+	public final static SpecialKey NUMPAD_MULTIPLY;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the 'Subtract' key on the numpad.
+	 */
+	public final static SpecialKey NUMPAD_SUBTRACT;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the 'Page Down' key.
+	 */
+	public final static SpecialKey PAGE_DOWN;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the 'Page Up' key.
+	 */
+	public final static SpecialKey PAGE_UP;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the 'Pause' key.
+	 */
+	public final static SpecialKey PAUSE;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the 'Print Screen' key.
+	 */
+	public final static SpecialKey PRINT_SCREEN;
+
+	/**
+	 * The single static instance of <code>SpecialKey</code> which represents
+	 * the 'Scroll Lock' key.
+	 */
+	public final static SpecialKey SCROLL_LOCK;
+
+	static {
+		final IKeyLookup lookup = KeyLookupFactory.getDefault();
+		ARROW_DOWN = new SpecialKey(lookup
+				.formalKeyLookup(IKeyLookup.ARROW_DOWN_NAME));
+		ARROW_LEFT = new SpecialKey(lookup
+				.formalKeyLookup(IKeyLookup.ARROW_LEFT_NAME));
+		ARROW_RIGHT = new SpecialKey(lookup
+				.formalKeyLookup(IKeyLookup.ARROW_RIGHT_NAME));
+		ARROW_UP = new SpecialKey(lookup
+				.formalKeyLookup(IKeyLookup.ARROW_UP_NAME));
+		BREAK = new SpecialKey(lookup.formalKeyLookup(IKeyLookup.BREAK_NAME));
+		CAPS_LOCK = new SpecialKey(lookup
+				.formalKeyLookup(IKeyLookup.CAPS_LOCK_NAME));
+		END = new SpecialKey(lookup.formalKeyLookup(IKeyLookup.END_NAME));
+		F1 = new SpecialKey(lookup.formalKeyLookup(IKeyLookup.F1_NAME));
+		F2 = new SpecialKey(lookup.formalKeyLookup(IKeyLookup.F2_NAME));
+		F3 = new SpecialKey(lookup.formalKeyLookup(IKeyLookup.F3_NAME));
+		F4 = new SpecialKey(lookup.formalKeyLookup(IKeyLookup.F4_NAME));
+		F5 = new SpecialKey(lookup.formalKeyLookup(IKeyLookup.F5_NAME));
+		F6 = new SpecialKey(lookup.formalKeyLookup(IKeyLookup.F6_NAME));
+		F7 = new SpecialKey(lookup.formalKeyLookup(IKeyLookup.F7_NAME));
+		F8 = new SpecialKey(lookup.formalKeyLookup(IKeyLookup.F8_NAME));
+		F9 = new SpecialKey(lookup.formalKeyLookup(IKeyLookup.F9_NAME));
+		F10 = new SpecialKey(lookup.formalKeyLookup(IKeyLookup.F10_NAME));
+		F11 = new SpecialKey(lookup.formalKeyLookup(IKeyLookup.F11_NAME));
+		F12 = new SpecialKey(lookup.formalKeyLookup(IKeyLookup.F12_NAME));
+		F13 = new SpecialKey(lookup.formalKeyLookup(IKeyLookup.F13_NAME));
+		F14 = new SpecialKey(lookup.formalKeyLookup(IKeyLookup.F14_NAME));
+		F15 = new SpecialKey(lookup.formalKeyLookup(IKeyLookup.F15_NAME));
+		HOME = new SpecialKey(lookup.formalKeyLookup(IKeyLookup.HOME_NAME));
+		INSERT = new SpecialKey(lookup.formalKeyLookup(IKeyLookup.INSERT_NAME));
+		NUM_LOCK = new SpecialKey(lookup
+				.formalKeyLookup(IKeyLookup.NUM_LOCK_NAME));
+		NUMPAD_0 = new SpecialKey(lookup
+				.formalKeyLookup(IKeyLookup.NUMPAD_0_NAME));
+		NUMPAD_1 = new SpecialKey(lookup
+				.formalKeyLookup(IKeyLookup.NUMPAD_1_NAME));
+		NUMPAD_2 = new SpecialKey(lookup
+				.formalKeyLookup(IKeyLookup.NUMPAD_2_NAME));
+		NUMPAD_3 = new SpecialKey(lookup
+				.formalKeyLookup(IKeyLookup.NUMPAD_3_NAME));
+		NUMPAD_4 = new SpecialKey(lookup
+				.formalKeyLookup(IKeyLookup.NUMPAD_4_NAME));
+		NUMPAD_5 = new SpecialKey(lookup
+				.formalKeyLookup(IKeyLookup.NUMPAD_5_NAME));
+		NUMPAD_6 = new SpecialKey(lookup
+				.formalKeyLookup(IKeyLookup.NUMPAD_6_NAME));
+		NUMPAD_7 = new SpecialKey(lookup
+				.formalKeyLookup(IKeyLookup.NUMPAD_7_NAME));
+		NUMPAD_8 = new SpecialKey(lookup
+				.formalKeyLookup(IKeyLookup.NUMPAD_8_NAME));
+		NUMPAD_9 = new SpecialKey(lookup
+				.formalKeyLookup(IKeyLookup.NUMPAD_9_NAME));
+		NUMPAD_ADD = new SpecialKey(lookup
+				.formalKeyLookup(IKeyLookup.NUMPAD_ADD_NAME));
+		NUMPAD_DECIMAL = new SpecialKey(lookup
+				.formalKeyLookup(IKeyLookup.NUMPAD_DECIMAL_NAME));
+		NUMPAD_DIVIDE = new SpecialKey(lookup
+				.formalKeyLookup(IKeyLookup.NUMPAD_DIVIDE_NAME));
+		NUMPAD_ENTER = new SpecialKey(lookup
+				.formalKeyLookup(IKeyLookup.NUMPAD_ENTER_NAME));
+		NUMPAD_EQUAL = new SpecialKey(lookup
+				.formalKeyLookup(IKeyLookup.NUMPAD_EQUAL_NAME));
+		NUMPAD_MULTIPLY = new SpecialKey(lookup
+				.formalKeyLookup(IKeyLookup.NUMPAD_MULTIPLY_NAME));
+		NUMPAD_SUBTRACT = new SpecialKey(lookup
+				.formalKeyLookup(IKeyLookup.NUMPAD_SUBTRACT_NAME));
+		PAGE_DOWN = new SpecialKey(lookup
+				.formalKeyLookup(IKeyLookup.PAGE_DOWN_NAME));
+		PAGE_UP = new SpecialKey(lookup
+				.formalKeyLookup(IKeyLookup.PAGE_UP_NAME));
+		PAUSE = new SpecialKey(lookup.formalKeyLookup(IKeyLookup.PAUSE_NAME));
+		PRINT_SCREEN = new SpecialKey(lookup
+				.formalKeyLookup(IKeyLookup.PRINT_SCREEN_NAME));
+		SCROLL_LOCK = new SpecialKey(lookup
+				.formalKeyLookup(IKeyLookup.SCROLL_LOCK_NAME));
+
+		specialKeysByName.put(SpecialKey.ARROW_DOWN.toString(),
+				SpecialKey.ARROW_DOWN);
+		specialKeysByName.put(SpecialKey.ARROW_LEFT.toString(),
+				SpecialKey.ARROW_LEFT);
+		specialKeysByName.put(SpecialKey.ARROW_RIGHT.toString(),
+				SpecialKey.ARROW_RIGHT);
+		specialKeysByName.put(SpecialKey.ARROW_UP.toString(),
+				SpecialKey.ARROW_UP);
+		specialKeysByName.put(SpecialKey.BREAK.toString(), SpecialKey.BREAK);
+		specialKeysByName.put(SpecialKey.CAPS_LOCK.toString(),
+				SpecialKey.CAPS_LOCK);
+		specialKeysByName.put(SpecialKey.END.toString(), SpecialKey.END);
+		specialKeysByName.put(SpecialKey.F1.toString(), SpecialKey.F1);
+		specialKeysByName.put(SpecialKey.F10.toString(), SpecialKey.F10);
+		specialKeysByName.put(SpecialKey.F11.toString(), SpecialKey.F11);
+		specialKeysByName.put(SpecialKey.F12.toString(), SpecialKey.F12);
+		specialKeysByName.put(SpecialKey.F13.toString(), SpecialKey.F13);
+		specialKeysByName.put(SpecialKey.F14.toString(), SpecialKey.F14);
+		specialKeysByName.put(SpecialKey.F15.toString(), SpecialKey.F15);
+		specialKeysByName.put(SpecialKey.F2.toString(), SpecialKey.F2);
+		specialKeysByName.put(SpecialKey.F3.toString(), SpecialKey.F3);
+		specialKeysByName.put(SpecialKey.F4.toString(), SpecialKey.F4);
+		specialKeysByName.put(SpecialKey.F5.toString(), SpecialKey.F5);
+		specialKeysByName.put(SpecialKey.F6.toString(), SpecialKey.F6);
+		specialKeysByName.put(SpecialKey.F7.toString(), SpecialKey.F7);
+		specialKeysByName.put(SpecialKey.F8.toString(), SpecialKey.F8);
+		specialKeysByName.put(SpecialKey.F9.toString(), SpecialKey.F9);
+		specialKeysByName.put(SpecialKey.NUM_LOCK.toString(),
+				SpecialKey.NUM_LOCK);
+		specialKeysByName.put(SpecialKey.NUMPAD_0.toString(),
+				SpecialKey.NUMPAD_0);
+		specialKeysByName.put(SpecialKey.NUMPAD_1.toString(),
+				SpecialKey.NUMPAD_1);
+		specialKeysByName.put(SpecialKey.NUMPAD_2.toString(),
+				SpecialKey.NUMPAD_2);
+		specialKeysByName.put(SpecialKey.NUMPAD_3.toString(),
+				SpecialKey.NUMPAD_3);
+		specialKeysByName.put(SpecialKey.NUMPAD_4.toString(),
+				SpecialKey.NUMPAD_4);
+		specialKeysByName.put(SpecialKey.NUMPAD_5.toString(),
+				SpecialKey.NUMPAD_5);
+		specialKeysByName.put(SpecialKey.NUMPAD_6.toString(),
+				SpecialKey.NUMPAD_6);
+		specialKeysByName.put(SpecialKey.NUMPAD_7.toString(),
+				SpecialKey.NUMPAD_7);
+		specialKeysByName.put(SpecialKey.NUMPAD_8.toString(),
+				SpecialKey.NUMPAD_8);
+		specialKeysByName.put(SpecialKey.NUMPAD_9.toString(),
+				SpecialKey.NUMPAD_9);
+		specialKeysByName.put(SpecialKey.NUMPAD_ADD.toString(),
+				SpecialKey.NUMPAD_ADD);
+		specialKeysByName.put(SpecialKey.NUMPAD_DECIMAL.toString(),
+				SpecialKey.NUMPAD_DECIMAL);
+		specialKeysByName.put(SpecialKey.NUMPAD_DIVIDE.toString(),
+				SpecialKey.NUMPAD_DIVIDE);
+		specialKeysByName.put(SpecialKey.NUMPAD_ENTER.toString(),
+				SpecialKey.NUMPAD_ENTER);
+		specialKeysByName.put(SpecialKey.NUMPAD_EQUAL.toString(),
+				SpecialKey.NUMPAD_EQUAL);
+		specialKeysByName.put(SpecialKey.NUMPAD_MULTIPLY.toString(),
+				SpecialKey.NUMPAD_MULTIPLY);
+		specialKeysByName.put(SpecialKey.NUMPAD_SUBTRACT.toString(),
+				SpecialKey.NUMPAD_SUBTRACT);
+		specialKeysByName.put(SpecialKey.HOME.toString(), SpecialKey.HOME);
+		specialKeysByName.put(SpecialKey.INSERT.toString(), SpecialKey.INSERT);
+		specialKeysByName.put(SpecialKey.PAGE_DOWN.toString(),
+				SpecialKey.PAGE_DOWN);
+		specialKeysByName
+				.put(SpecialKey.PAGE_UP.toString(), SpecialKey.PAGE_UP);
+		specialKeysByName.put(SpecialKey.PAUSE.toString(), SpecialKey.PAUSE);
+		specialKeysByName.put(SpecialKey.PRINT_SCREEN.toString(),
+				SpecialKey.PRINT_SCREEN);
+		specialKeysByName.put(SpecialKey.SCROLL_LOCK.toString(),
+				SpecialKey.SCROLL_LOCK);
+	}
+
+	/**
+	 * Constructs an instance of <code>SpecialKey</code> given a name.
+	 *
+	 * @param key
+	 *            The key to be wrapped.
+	 */
+	private SpecialKey(final int key) {
+		super(key);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/package.html b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/package.html
new file mode 100644
index 0000000..2b44963
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/keys/package.html
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <meta name="Author" content="IBM">
+   <meta name="GENERATOR" content="Mozilla/4.5 [en] (Win98; I) [Netscape]">
+   <title>Package-level Javadoc</title>
+</head>
+<body>
+<p>Provides support for integrating keys into the Eclipse workbench.</p>
+
+<h2>Package Specification</h2>
+<p>
+This package provides the classes required to integrate keys into the
+Eclipse workbench.
+</p>
+<p>
+To use the key integration, the method <code>getAdapter</code> is called on
+the Eclipse workbench, with the argument <code>IBindingService.class</code>.
+This will return an instance of <code>IBindingService</code>.
+</p>
+</body>
+</html>
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/AbstractContributionFactory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/AbstractContributionFactory.java
new file mode 100644
index 0000000..fad4532
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/AbstractContributionFactory.java
@@ -0,0 +1,127 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.menus;
+
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * ContributionFactories are used by the IMenuService to populate
+ * ContributionManagers. In {@link #createContributionItems(IServiceLocator, IContributionRoot)}
+ * you fill in the additions List with {@link IContributionItem} to be inserted at this
+ * factory's location. For example:
+ * <p>
+ *
+ * <pre>
+ * AbstractContributionFactory contributions = new AbstractContributionFactory(
+ * 		&quot;menu:org.eclipse.ui.tests.api.MenuTestHarness?after=additions&quot;) {
+ * 	public void createContributionItems(IMenuService menuService, List additions) {
+ * 		CommandContributionItem item = new CommandContributionItem(
+ * 				&quot;org.eclipse.ui.tests.menus.helloWorld&quot;,
+ * 				&quot;org.eclipse.ui.tests.commands.enabledHelloWorld&quot;, null, null,
+ * 				&quot;Say Hello&quot;, null);
+ * 		additions.add(item);
+ * 		item = new CommandContributionItem(
+ * 				&quot;org.eclipse.ui.tests.menus.refresh&quot;,
+ * 				&quot;org.eclipse.ui.tests.commands.refreshView&quot;, null, null,
+ * 				&quot;Refresh&quot;, null);
+ * 		menuService.registerVisibleWhen(item, new MyActiveContextExpression(
+ * 				&quot;org.eclipse.ui.tests.myview.context&quot;));
+ * 		additions.add(item);
+ * 	}
+ *
+ * 	public void releaseContributionItems(IMenuService menuService, List items) {
+ * 		// we have nothing to do
+ * 	}
+ * };
+ * IMenuService service = (IMenuService) PlatformUI.getWorkbench().getService(
+ * 		IMenuService.class);
+ * service.addContributionFactory(contributions);
+ * </pre>
+ *
+ * </p>
+ *
+ * <p>
+ * Clients who are providing factories via the <code>org.eclipse.ui.menus</code>
+ * extension point should subclass {@link ExtensionContributionFactory} instead.
+ * </p>
+ *
+ * <p>
+ * Only the abstract methods may be implemented.
+ * </p>
+ *
+ * @since 3.3
+ * @see org.eclipse.ui.menus.IMenuService
+ * @see org.eclipse.jface.action.MenuManager
+ * @see org.eclipse.jface.action.ToolBarManager
+ */
+public abstract class AbstractContributionFactory {
+	private String location = null;
+	private String namespace;
+
+	/**
+	 * The contribution factories must be instantiated with their location,
+	 * which which specifies the contributions insertion location.
+	 *
+	 * @param location
+	 *            the addition location in Menu API URI format. It must not be
+	 *            <code>null</code>.
+	 * @param namespace
+	 *            the namespace for this contribution. May be <code>null</code>.
+	 * @see #getNamespace()
+	 */
+	public AbstractContributionFactory(String location, String namespace) {
+		this.location = location;
+		this.namespace = namespace;
+	}
+
+	/**
+	 * Return the location as a String.
+	 *
+	 * @return the location - never <code>null</code>.
+	 */
+	public String getLocation() {
+		return location;
+	}
+
+	/**
+	 * This factory should create the IContributionItems that it wants to
+	 * contribute, and add them to the additions list. The menu service will
+	 * call this method at the appropriate time. It should always return new
+	 * instances of its contributions in the additions list.
+	 * <p>
+	 * This method is not meant to be called by clients. It will be called by
+	 * the menu service at the appropriate time.
+	 * </p>
+	 *
+	 * @param serviceLocator
+	 *            a service locator that may be used in the construction of
+	 *            items created by this factory
+	 * @param additions
+	 *            A {@link IContributionRoot} supplied by the framework. It will
+	 *            never be <code>null</code>.
+	 * @see org.eclipse.ui.menus.CommandContributionItem
+	 * @see org.eclipse.jface.action.MenuManager
+	 */
+	public abstract void createContributionItems(IServiceLocator serviceLocator,
+			IContributionRoot additions);
+
+	/**
+	 * Return the namespace for this cache. This corresponds to the plug-in that
+	 * is contributing this factory.
+	 *
+	 * @return the namespace the namespace of this factory
+	 */
+	public String getNamespace() {
+		return namespace;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/AbstractWorkbenchTrimWidget.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/AbstractWorkbenchTrimWidget.java
new file mode 100644
index 0000000..a88f6bd
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/AbstractWorkbenchTrimWidget.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.menus;
+
+import org.eclipse.jface.menus.AbstractTrimWidget;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.ui.IWorkbenchWindow;
+
+/**
+ * Extension for trim widgets contributed to the workbench.
+ * The extension point handler will call the <code>init</code>
+ * method to inform the contributed widgets as to which
+ * workbench window they're currently being hosted in.
+ *
+ * @since 3.2
+ *
+ */
+public abstract class AbstractWorkbenchTrimWidget extends AbstractTrimWidget implements IWorkbenchWidget {
+
+	private IWorkbenchWindow wbWindow;
+
+	/**
+	 *
+	 */
+	public AbstractWorkbenchTrimWidget() {
+		super();
+	}
+
+
+	/**
+	 * Define the IWorkbenchWindow that this trim is being hosted in.
+	 * Note that subclasses may extend but should not override. The
+	 * base implementation caches the value for access through the
+	 * <code>getWorkbenchWindow</code> method.
+	 *
+	 * @see org.eclipse.ui.menus.IWorkbenchWidget#init(org.eclipse.ui.IWorkbenchWindow)
+	 */
+	@Override
+	public void init(IWorkbenchWindow workbenchWindow) {
+		wbWindow = workbenchWindow;
+	}
+
+	/**
+	 * Convenience method to get the IWorkbenchWindow that is
+	 * hosting this widget.
+	 *
+	 * @return The IWorkbenchWindow hosting this widget.
+	 */
+	public IWorkbenchWindow getWorkbenchWindow() {
+		return wbWindow;
+	}
+
+	/**
+	 * @return The preferred size of this item
+	 * @since 3.3
+	 */
+	public Point getPreferredSize() {
+		return null;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/CommandContributionItem.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/CommandContributionItem.java
new file mode 100644
index 0000000..951a871
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/CommandContributionItem.java
@@ -0,0 +1,1020 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *******************************************************************************/
+package org.eclipse.ui.menus;
+
+import java.util.Map;
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.CommandEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.ICommandListener;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.core.commands.NotEnabledException;
+import org.eclipse.core.commands.NotHandledException;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.action.ContributionItem;
+import org.eclipse.jface.action.IContributionManager;
+import org.eclipse.jface.action.IMenuListener2;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.bindings.IBindingManagerListener;
+import org.eclipse.jface.bindings.TriggerSequence;
+import org.eclipse.jface.resource.DeviceResourceException;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+import org.eclipse.swt.widgets.Widget;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.commands.ICommandImageService;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.commands.IElementReference;
+import org.eclipse.ui.commands.IElementUpdater;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.help.IWorkbenchHelpSystem;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.handlers.HandlerProxy;
+import org.eclipse.ui.internal.menus.CommandMessages;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.internal.services.IWorkbenchLocationService;
+import org.eclipse.ui.keys.IBindingService;
+import org.eclipse.ui.services.IServiceLocator;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+/**
+ * A contribution item which delegates to a command. It can be used in {@link
+ * AbstractContributionFactory#createContributionItems(IServiceLocator,
+ * IContributionRoot)}.
+ * <p>
+ * It currently supports placement in menus and toolbars.
+ * </p>
+ * <p>
+ * This class may be instantiated; it is not intended to be subclassed.
+ * </p>
+ *
+ * @noextend This class is not intended to be subclassed by clients.
+ * @since 3.3
+ */
+public class CommandContributionItem extends ContributionItem {
+	/**
+	 * A push button tool item or menu item.
+	 */
+	public static final int STYLE_PUSH = SWT.PUSH;
+
+	/**
+	 * A checked tool item or menu item.
+	 */
+	public static final int STYLE_CHECK = SWT.CHECK;
+
+	/**
+	 * A radio-button style menu item.
+	 */
+	public static final int STYLE_RADIO = SWT.RADIO;
+
+	/**
+	 * A ToolBar pulldown item.
+	 */
+	public static final int STYLE_PULLDOWN = SWT.DROP_DOWN;
+
+	/**
+	 * Mode bit: Show text on tool items or buttons, even if an image is
+	 * present. If this mode bit is not set, text is only shown on tool items if
+	 * there is no image present.
+	 *
+	 * @since 3.4
+	 */
+	public static int MODE_FORCE_TEXT = 1;
+
+	private LocalResourceManager localResourceManager;
+
+	private Listener menuItemListener;
+
+	private Widget widget;
+
+	private IMenuService menuService;
+
+	private ICommandService commandService;
+
+	private IHandlerService handlerService;
+
+	private IBindingService bindingService;
+
+	private ParameterizedCommand command;
+
+	private ImageDescriptor icon;
+
+	private String label;
+
+	private String tooltip;
+
+	private ImageDescriptor disabledIcon;
+
+	private ImageDescriptor hoverIcon;
+
+	private String mnemonic;
+
+	private IElementReference elementRef;
+
+	private boolean checkedState;
+
+	private int style;
+
+	private ICommandListener commandListener;
+
+	private String dropDownMenuOverride;
+
+	private IWorkbenchHelpSystem workbenchHelpSystem;
+
+	private String helpContextId;
+
+	private int mode = 0;
+
+	/**
+	 * This is <code>true</code> when the menu contribution's visibleWhen
+	 * checkEnabled attribute is <code>true</code>.
+	 */
+	private boolean visibleEnabled;
+
+	private Display display;
+
+	// items contributed
+	private String contributedLabel;
+
+	private String contributedTooltip;
+
+	private ImageDescriptor contributedIcon;
+
+	private ImageDescriptor contributedDisabledIcon;
+
+	private ImageDescriptor contributedHoverIcon;
+
+	private IServiceLocator serviceLocator;
+
+	/**
+	 * Create a CommandContributionItem to place in a ContributionManager.
+	 *
+	 * @param contributionParameters
+	 * 		parameters necessary to render this contribution item.
+	 * @since 3.4
+	 */
+	public CommandContributionItem(
+			CommandContributionItemParameter contributionParameters) {
+		super(contributionParameters.id);
+
+		contributedLabel = contributionParameters.label;
+		contributedTooltip = contributionParameters.tooltip;
+		contributedIcon = contributionParameters.icon;
+		contributedDisabledIcon = contributionParameters.disabledIcon;
+		contributedHoverIcon = contributionParameters.hoverIcon;
+		this.serviceLocator = contributionParameters.serviceLocator;
+
+
+		this.icon = contributionParameters.icon;
+		this.disabledIcon = contributionParameters.disabledIcon;
+		this.hoverIcon = contributionParameters.hoverIcon;
+		this.label = contributionParameters.label;
+		this.mnemonic = contributionParameters.mnemonic;
+		this.tooltip = contributionParameters.tooltip;
+		this.style = contributionParameters.style;
+		this.helpContextId = contributionParameters.helpContextId;
+		this.visibleEnabled = contributionParameters.visibleEnabled;
+		this.mode = contributionParameters.mode;
+
+		menuService = contributionParameters.serviceLocator
+				.getService(IMenuService.class);
+		commandService = contributionParameters.serviceLocator
+				.getService(ICommandService.class);
+		handlerService = contributionParameters.serviceLocator
+				.getService(IHandlerService.class);
+		bindingService = contributionParameters.serviceLocator
+				.getService(IBindingService.class);
+		IWorkbenchLocationService workbenchLocationService = contributionParameters.serviceLocator.getService(IWorkbenchLocationService.class);
+		display = workbenchLocationService.getWorkbench().getDisplay();
+
+		createCommand(contributionParameters.commandId,
+				contributionParameters.parameters);
+
+		if (command != null) {
+				setImages(contributionParameters.serviceLocator,
+						contributionParameters.iconStyle);
+
+				if (contributionParameters.helpContextId == null) {
+					try {
+						this.helpContextId = commandService
+								.getHelpContextId(contributionParameters.commandId);
+					} catch (NotDefinedException e) {
+						// it's OK to not have a helpContextId
+					}
+				}
+				IWorkbenchLocationService wls = contributionParameters.serviceLocator
+						.getService(IWorkbenchLocationService.class);
+				final IWorkbench workbench = wls.getWorkbench();
+				if (workbench != null && helpContextId != null) {
+					this.workbenchHelpSystem = workbench.getHelpSystem();
+				}
+		}
+
+	}
+
+	/**
+	 * Create a CommandContributionItem to place in a ContributionManager.
+	 *
+	 * @param serviceLocator
+	 * 		a service locator that is most appropriate for this contribution.
+	 * 		Typically the local {@link IWorkbenchWindow} or {@link
+	 * 		IWorkbenchPartSite} will be sufficient.
+	 * @param id
+	 * 		The id for this item. May be <code>null</code>. Items without an id
+	 * 		cannot be referenced later.
+	 * @param commandId
+	 * 		A command id for a defined command. Must not be <code>null</code>.
+	 * @param parameters
+	 * 		A map of strings to strings which represent parameter names to
+	 * 		values. The parameter names must match those in the command
+	 * 		definition.
+	 * @param icon
+	 * 		An icon for this item. May be <code>null</code>.
+	 * @param disabledIcon
+	 * 		A disabled icon for this item. May be <code>null</code>.
+	 * @param hoverIcon
+	 * 		A hover icon for this item. May be <code>null</code>.
+	 * @param label
+	 * 		A label for this item. May be <code>null</code>.
+	 * @param mnemonic
+	 * 		A mnemonic for this item to be applied to the label. May be
+	 * 		<code>null</code>.
+	 * @param tooltip
+	 * 		A tooltip for this item. May be <code>null</code>. Tooltips are
+	 * 		currently only valid for toolbar contributions.
+	 * @param style
+	 * 		The style of this menu contribution. See the STYLE_* contants.
+	 * @deprecated create the {@link CommandContributionItemParameter}
+	 */
+	@Deprecated
+	public CommandContributionItem(IServiceLocator serviceLocator, String id,
+			String commandId, Map parameters, ImageDescriptor icon,
+			ImageDescriptor disabledIcon, ImageDescriptor hoverIcon,
+			String label, String mnemonic, String tooltip, int style) {
+		this(new CommandContributionItemParameter(serviceLocator, id,
+				commandId, parameters, icon, disabledIcon, hoverIcon, label,
+				mnemonic, tooltip, style, null, false));
+	}
+
+	private void setImages(IServiceLocator locator, String iconStyle) {
+		if (icon == null) {
+			ICommandImageService service = locator
+					.getService(ICommandImageService.class);
+			icon = service.getImageDescriptor(command.getId(),
+					ICommandImageService.TYPE_DEFAULT, iconStyle);
+			disabledIcon = service.getImageDescriptor(command.getId(),
+					ICommandImageService.TYPE_DISABLED, iconStyle);
+			hoverIcon = service.getImageDescriptor(command.getId(),
+					ICommandImageService.TYPE_HOVER, iconStyle);
+
+			if (contributedIcon == null)
+				contributedIcon = icon;
+			if (contributedDisabledIcon == null)
+				contributedDisabledIcon = disabledIcon;
+			if (contributedHoverIcon == null)
+				contributedHoverIcon = hoverIcon;
+		}
+	}
+
+	private ICommandListener getCommandListener() {
+		if (commandListener == null) {
+			commandListener = commandEvent -> {
+				if (commandEvent.isHandledChanged()
+						|| commandEvent.isEnabledChanged()
+						|| commandEvent.isDefinedChanged()) {
+					updateCommandProperties(commandEvent);
+				}
+			};
+		}
+		return commandListener;
+	}
+
+	private void updateCommandProperties(final CommandEvent commandEvent) {
+		if (commandEvent.isHandledChanged()) {
+			dropDownMenuOverride = null;
+		}
+		Runnable update = () -> {
+			if (commandEvent.isEnabledChanged()
+					|| commandEvent.isHandledChanged()) {
+				if (visibleEnabled) {
+					IContributionManager parent = getParent();
+					if (parent != null) {
+						parent.update(true);
+					}
+				}
+				IHandler handler = commandEvent.getCommand().getHandler();
+				if (shouldRestoreAppearance(handler)) {
+					label = contributedLabel;
+					tooltip = contributedTooltip;
+					icon = contributedIcon;
+					disabledIcon = contributedDisabledIcon;
+					hoverIcon = contributedHoverIcon;
+				}
+			}
+			if (commandEvent.getCommand().isDefined()) {
+				update(null);
+			}
+		};
+		if (display.getThread() == Thread.currentThread()) {
+			update.run();
+		} else {
+			display.asyncExec(update);
+		}
+	}
+
+	private boolean shouldRestoreAppearance(IHandler handler) {
+
+		// if no handler or handler doesn't implement IElementUpdater,
+		// restore the contributed elements
+		if (handler == null)
+			return true;
+
+		if (!(handler instanceof IElementUpdater))
+			return true;
+
+		// special case, if its HandlerProxy, then check the actual handler
+		if (handler instanceof HandlerProxy) {
+			HandlerProxy handlerProxy = (HandlerProxy) handler;
+			IHandler actualHandler = handlerProxy.getHandler();
+			return shouldRestoreAppearance(actualHandler);
+		}
+		return false;
+	}
+
+	/**
+	 * Returns the ParameterizedCommand for this contribution.
+	 * <p>
+	 * <strong>NOTE:</strong> The returned object should be treated as
+	 * 'read-only', do <b>not</b> execute this instance or attempt to modify its
+	 * state.
+	 * </p>
+	 *
+	 * @return The parameterized command for this contribution.
+	 *
+	 * @since 3.5
+	 */
+	public ParameterizedCommand getCommand() {
+		return command;
+	}
+
+	void createCommand(String commandId, Map parameters) {
+		if (commandId == null) {
+			StatusManager.getManager().handle(
+					StatusUtil.newStatus(IStatus.ERROR,
+							"Unable to create menu item \"" + getId() //$NON-NLS-1$
+									+ "\", no command id", null)); //$NON-NLS-1$
+			return;
+		}
+		Command cmd = commandService.getCommand(commandId);
+		if (!cmd.isDefined()) {
+			StatusManager
+					.getManager()
+					.handle(
+							StatusUtil
+									.newStatus(
+											IStatus.ERROR,
+											"Unable to create menu item \"" + getId() //$NON-NLS-1$
+													+ "\", command \"" + commandId + "\" not defined", null)); //$NON-NLS-1$ //$NON-NLS-2$
+			return;
+		}
+		command = ParameterizedCommand.generateCommand(cmd, parameters);
+	}
+
+	@Override
+	public void fill(Menu parent, int index) {
+		if (command == null) {
+			return;
+		}
+		if (widget != null || parent == null) {
+			return;
+		}
+
+		// Menus don't support the pulldown style
+		int tmpStyle = style;
+		if (tmpStyle == STYLE_PULLDOWN)
+			tmpStyle = STYLE_PUSH;
+
+		MenuItem item = null;
+		if (index >= 0) {
+			item = new MenuItem(parent, tmpStyle, index);
+		} else {
+			item = new MenuItem(parent, tmpStyle);
+		}
+		item.setData(this);
+		if (workbenchHelpSystem != null) {
+			workbenchHelpSystem.setHelp(item, helpContextId);
+		}
+		item.addListener(SWT.Dispose, getItemListener());
+		item.addListener(SWT.Selection, getItemListener());
+		widget = item;
+
+		update(null);
+		updateIcons();
+
+		establishReferences();
+	}
+
+	@Override
+	public void fill(Composite parent) {
+		if (command == null) {
+			return;
+		}
+		if (widget != null || parent == null) {
+			return;
+		}
+
+		// Buttons don't support the pulldown style
+		int tmpStyle = style;
+		if (tmpStyle == STYLE_PULLDOWN)
+			tmpStyle = STYLE_PUSH;
+
+		Button item = new Button(parent, tmpStyle);
+		item.setData(this);
+		if (workbenchHelpSystem != null) {
+			workbenchHelpSystem.setHelp(item, helpContextId);
+		}
+		item.addListener(SWT.Dispose, getItemListener());
+		item.addListener(SWT.Selection, getItemListener());
+		widget = item;
+
+		update(null);
+		updateIcons();
+
+		establishReferences();
+	}
+
+	@Override
+	public void fill(ToolBar parent, int index) {
+		if (command == null) {
+			return;
+		}
+		if (widget != null || parent == null) {
+			return;
+		}
+
+		ToolItem item = null;
+		if (index >= 0) {
+			item = new ToolItem(parent, style, index);
+		} else {
+			item = new ToolItem(parent, style);
+		}
+
+		item.setData(this);
+
+		item.addListener(SWT.Selection, getItemListener());
+		item.addListener(SWT.Dispose, getItemListener());
+		widget = item;
+
+		update(null);
+		updateIcons();
+
+		establishReferences();
+	}
+
+	@Override
+	public void update() {
+		update(null);
+	}
+
+	@Override
+	public void update(String id) {
+		if (widget != null) {
+			if (widget instanceof MenuItem) {
+				updateMenuItem();
+			} else if (widget instanceof ToolItem) {
+				updateToolItem();
+			} else if (widget instanceof Button) {
+				updateButton();
+			}
+		}
+	}
+
+	private void updateMenuItem() {
+		MenuItem item = (MenuItem) widget;
+
+		String text = label;
+		if (text == null) {
+			if (command != null) {
+				try {
+					text = command.getCommand().getName();
+				} catch (NotDefinedException e) {
+					StatusManager.getManager().handle(
+							StatusUtil.newStatus(IStatus.ERROR,
+									"Update item failed " //$NON-NLS-1$
+											+ getId(), e));
+				}
+			}
+		}
+		text = updateMnemonic(text);
+
+		String keyBindingText = null;
+		if (command != null) {
+			TriggerSequence binding = bindingService
+					.getBestActiveBindingFor(command);
+			if (binding != null) {
+				keyBindingText = binding.format();
+			}
+		}
+		if (text != null) {
+			if (keyBindingText == null) {
+				item.setText(text);
+			} else {
+				item.setText(text + '\t' + keyBindingText);
+			}
+		}
+
+		if (item.getSelection() != checkedState) {
+			item.setSelection(checkedState);
+		}
+
+		// allow the handler update its enablement
+		boolean shouldBeEnabled = isEnabled();
+		// disabled command + visibility follows enablement == disposed
+		if (!item.isDisposed() && item.getEnabled() != shouldBeEnabled) {
+			item.setEnabled(shouldBeEnabled);
+		}
+	}
+
+	private void updateToolItem() {
+		ToolItem item = (ToolItem) widget;
+
+		String text = label;
+		String tooltip = label;
+
+		if (text == null) {
+			if (command != null) {
+				try {
+					text = command.getCommand().getName();
+					tooltip = command.getCommand().getDescription();
+					if (tooltip == null || tooltip.trim().length() == 0) {
+						tooltip = text;
+					}
+				} catch (NotDefinedException e) {
+					StatusManager.getManager().handle(
+							StatusUtil.newStatus(IStatus.ERROR,
+									"Update item failed " //$NON-NLS-1$
+											+ getId(), e));
+				}
+			}
+		}
+
+		if ((icon == null || (mode & MODE_FORCE_TEXT) == MODE_FORCE_TEXT)
+				&& text != null) {
+			item.setText(text);
+		}
+
+		String toolTipText = getToolTipText(tooltip);
+		item.setToolTipText(toolTipText);
+
+		if (item.getSelection() != checkedState) {
+			item.setSelection(checkedState);
+		}
+
+		// allow the handler update its enablement
+		boolean shouldBeEnabled = isEnabled();
+		// disabled command + visibility follows enablement == disposed
+		if (!item.isDisposed() && item.getEnabled() != shouldBeEnabled) {
+			item.setEnabled(shouldBeEnabled);
+		}
+	}
+
+	private void updateButton() {
+		Button item = (Button) widget;
+
+		String text = label;
+		if (text == null) {
+			if (command != null) {
+				try {
+					text = command.getCommand().getName();
+				} catch (NotDefinedException e) {
+					StatusManager.getManager().handle(
+							StatusUtil.newStatus(IStatus.ERROR,
+									"Update item failed " //$NON-NLS-1$
+											+ getId(), e));
+				}
+			}
+		}
+
+		if (text != null) {
+			item.setText(text);
+		}
+
+		String toolTipText = getToolTipText(text);
+		item.setToolTipText(toolTipText);
+
+		if (item.getSelection() != checkedState) {
+			item.setSelection(checkedState);
+		}
+
+		// allow the handler update its enablement
+		boolean shouldBeEnabled = isEnabled();
+		// disabled command + visibility follows enablement == disposed
+		if (!item.isDisposed() && item.getEnabled() != shouldBeEnabled) {
+			item.setEnabled(shouldBeEnabled);
+		}
+	}
+
+	private String getToolTipText(String text) {
+		String tooltipText = tooltip;
+		if (tooltip == null)
+			if (text != null)
+				tooltipText = text;
+			else
+				tooltipText = ""; //$NON-NLS-1$
+
+		TriggerSequence activeBinding = bindingService
+				.getBestActiveBindingFor(command);
+		if (activeBinding != null && !activeBinding.isEmpty()) {
+			String acceleratorText = activeBinding.format();
+			if (acceleratorText != null
+					&& acceleratorText.length() != 0) {
+				tooltipText = NLS.bind(CommandMessages.Tooltip_Accelerator,
+						tooltipText, acceleratorText);
+			}
+		}
+
+		return tooltipText;
+	}
+
+	private String updateMnemonic(String s) {
+		if (mnemonic == null || s == null) {
+			return s;
+		}
+		int idx = s.indexOf(mnemonic);
+		if (idx == -1) {
+			return s;
+		}
+
+		return s.substring(0, idx) + '&' + s.substring(idx);
+	}
+
+	private void handleWidgetDispose(Event event) {
+		if (event.widget == widget) {
+			disconnectReferences();
+			widget.removeListener(SWT.Selection, getItemListener());
+			widget.removeListener(SWT.Dispose, getItemListener());
+			widget = null;
+			disposeOldImages();
+		}
+	}
+
+	@Override
+	public void setParent(IContributionManager parent) {
+		super.setParent(parent);
+		if (parent == null)
+			disconnectReferences();
+	}
+
+	private void establishReferences() {
+		if (command != null) {
+			UIElement callback = new UIElement(serviceLocator) {
+
+				@Override
+				public void setChecked(boolean checked) {
+					CommandContributionItem.this.setChecked(checked);
+				}
+
+				@Override
+				public void setDisabledIcon(ImageDescriptor desc) {
+					CommandContributionItem.this.setDisabledIcon(desc);
+				}
+
+				@Override
+				public void setHoverIcon(ImageDescriptor desc) {
+					CommandContributionItem.this.setHoverIcon(desc);
+				}
+
+				@Override
+				public void setIcon(ImageDescriptor desc) {
+					CommandContributionItem.this.setIcon(desc);
+				}
+
+				@Override
+				public void setText(String text) {
+					CommandContributionItem.this.setText(text);
+				}
+
+				@Override
+				public void setTooltip(String text) {
+					CommandContributionItem.this.setTooltip(text);
+				}
+
+				@Override
+				public void setDropDownId(String id) {
+					dropDownMenuOverride = id;
+				}
+			};
+			try {
+				elementRef = commandService.registerElementForCommand(command, callback);
+			} catch (NotDefinedException e) {
+				StatusManager.getManager().handle(
+						StatusUtil.newStatus(IStatus.ERROR, "Unable to register menu item \"" + getId() //$NON-NLS-1$
+								+ "\", command \"" + command.getId() + "\" not defined", //$NON-NLS-1$ //$NON-NLS-2$
+								null));
+			}
+			command.getCommand().addCommandListener(getCommandListener());
+		}
+		bindingService.addBindingManagerListener(bindingManagerListener);
+	}
+
+	private void disconnectReferences() {
+		if (elementRef != null) {
+			commandService.unregisterElement(elementRef);
+			elementRef = null;
+		}
+		if (commandListener != null) {
+			command.getCommand().removeCommandListener(commandListener);
+			commandListener = null;
+		}
+
+		if (bindingService != null) {
+			bindingService.removeBindingManagerListener(bindingManagerListener);
+		}
+	}
+
+	@Override
+	public void dispose() {
+		if (widget != null) {
+			widget.dispose();
+			widget = null;
+		}
+
+		disconnectReferences();
+
+		command = null;
+		commandService = null;
+		bindingService = null;
+		menuService = null;
+		handlerService = null;
+		disposeOldImages();
+		super.dispose();
+	}
+
+	private void disposeOldImages() {
+		if (localResourceManager != null) {
+			localResourceManager.dispose();
+			localResourceManager = null;
+		}
+	}
+
+	private Listener getItemListener() {
+		if (menuItemListener == null) {
+			menuItemListener = event -> {
+				switch (event.type) {
+				case SWT.Dispose:
+					handleWidgetDispose(event);
+					break;
+				case SWT.Selection:
+					if (event.widget != null) {
+						handleWidgetSelection(event);
+					}
+					break;
+				}
+			};
+		}
+		return menuItemListener;
+	}
+
+	private void handleWidgetSelection(Event event) {
+		// Special check for ToolBar dropdowns...
+		if (openDropDownMenu(event))
+			return;
+
+		if ((style & (SWT.TOGGLE | SWT.CHECK)) != 0) {
+			if (event.widget instanceof ToolItem) {
+				checkedState = ((ToolItem) event.widget).getSelection();
+			} else if (event.widget instanceof MenuItem) {
+				checkedState = ((MenuItem) event.widget).getSelection();
+			}
+		}
+
+		try {
+			handlerService.executeCommand(command, event);
+		} catch (ExecutionException e) {
+			StatusManager.getManager().handle(
+					StatusUtil.newStatus(IStatus.ERROR,
+							"Failed to execute item " //$NON-NLS-1$
+									+ getId(), e));
+		} catch (NotDefinedException e) {
+			StatusManager.getManager().handle(
+					StatusUtil.newStatus(IStatus.ERROR,
+							"Failed to execute item " //$NON-NLS-1$
+									+ getId(), e));
+		} catch (NotEnabledException e) {
+			StatusManager.getManager().handle(
+					StatusUtil.newStatus(IStatus.ERROR,
+							"Failed to execute item " //$NON-NLS-1$
+									+ getId(), e));
+		} catch (NotHandledException e) {
+			StatusManager.getManager().handle(
+					StatusUtil.newStatus(IStatus.ERROR,
+							"Failed to execute item " //$NON-NLS-1$
+									+ getId(), e));
+		}
+	}
+
+	/**
+	 * Determines if the selection was on the dropdown affordance and, if so,
+	 * opens the drop down menu (populated using the same id as this item...
+	 *
+	 * @param event
+	 * 		The <code>SWT.Selection</code> event to be tested
+	 *
+	 * @return <code>true</code> iff a drop down menu was opened
+	 */
+	private boolean openDropDownMenu(Event event) {
+		Widget item = event.widget;
+		if (item != null) {
+			int style = item.getStyle();
+			if ((style & SWT.DROP_DOWN) != 0) {
+				if (event.detail == 4) { // on drop-down button
+					ToolItem ti = (ToolItem) item;
+
+					final MenuManager menuManager = new MenuManager();
+					Menu menu = menuManager.createContextMenu(ti.getParent());
+					if (workbenchHelpSystem != null) {
+						workbenchHelpSystem.setHelp(menu, helpContextId);
+					}
+					menuManager.addMenuListener(new IMenuListener2() {
+						@Override
+						public void menuAboutToShow(IMenuManager manager) {
+							String id = getId();
+							if (dropDownMenuOverride != null) {
+								id = dropDownMenuOverride;
+							}
+							menuService.populateContributionManager(
+									menuManager, "menu:" + id); //$NON-NLS-1$
+						}
+						@Override
+						public void menuAboutToHide(IMenuManager manager) {
+							display.asyncExec(() -> {
+								menuService.releaseContributions(menuManager);
+								menuManager.dispose();
+							});
+						}
+					});
+
+					// position the menu below the drop down item
+					Point point = ti.getParent().toDisplay(
+							new Point(event.x, event.y));
+					menu.setLocation(point.x, point.y); // waiting for SWT
+					// 0.42
+					menu.setVisible(true);
+					return true; // we don't fire the action
+				}
+			}
+		}
+
+		return false;
+	}
+
+	private void setIcon(ImageDescriptor desc) {
+		icon = desc;
+		updateIcons();
+	}
+
+	private void updateIcons() {
+		if (widget instanceof MenuItem) {
+			MenuItem item = (MenuItem) widget;
+			LocalResourceManager m = new LocalResourceManager(JFaceResources
+					.getResources());
+			try {
+				item.setImage(icon == null ? null : m.createImage(icon));
+			} catch (DeviceResourceException e) {
+				icon = ImageDescriptor.getMissingImageDescriptor();
+				item.setImage(m.createImage(icon));
+				// as we replaced the failed icon, log the message once.
+				StatusManager.getManager().handle(
+						new Status(IStatus.ERROR, WorkbenchPlugin.PI_WORKBENCH,
+								"Failed to load image", e)); //$NON-NLS-1$
+			}
+			disposeOldImages();
+			localResourceManager = m;
+		} else if (widget instanceof ToolItem) {
+			ToolItem item = (ToolItem) widget;
+			LocalResourceManager m = new LocalResourceManager(JFaceResources
+					.getResources());
+			item.setDisabledImage(disabledIcon == null ? null : m
+					.createImage(disabledIcon));
+			item.setHotImage(hoverIcon == null ? null : m
+					.createImage(hoverIcon));
+			item.setImage(icon == null ? null : m.createImage(icon));
+			disposeOldImages();
+			localResourceManager = m;
+		}
+	}
+
+	private void setText(String text) {
+		label = text;
+		update(null);
+	}
+
+	private void setChecked(boolean checked) {
+		if (checkedState == checked) {
+			return;
+		}
+		checkedState = checked;
+		if (widget instanceof MenuItem) {
+			((MenuItem) widget).setSelection(checkedState);
+		} else if (widget instanceof ToolItem) {
+			((ToolItem) widget).setSelection(checkedState);
+		}
+	}
+
+	private void setTooltip(String text) {
+		tooltip = text;
+		if (widget instanceof ToolItem) {
+			((ToolItem) widget).setToolTipText(text);
+		}
+	}
+
+	private void setDisabledIcon(ImageDescriptor desc) {
+		disabledIcon = desc;
+		updateIcons();
+	}
+
+	private void setHoverIcon(ImageDescriptor desc) {
+		hoverIcon = desc;
+		updateIcons();
+	}
+
+	@Override
+	public boolean isEnabled() {
+		if (command != null) {
+			command.getCommand().setEnabled(menuService.getCurrentState());
+			return command.getCommand().isEnabled();
+		}
+		return false;
+	}
+
+	/**
+	 * @since 3.4
+	 */
+	@Override
+	public boolean isVisible() {
+		if (visibleEnabled) {
+			return super.isVisible() && isEnabled();
+		}
+		return super.isVisible();
+	}
+
+	private IBindingManagerListener bindingManagerListener = event -> {
+		if (event.isActiveBindingsChanged()
+				&& event.isActiveBindingsChangedFor(getCommand())) {
+			update();
+		}
+
+	};
+
+	/**
+	 * Provide info on the rendering data contained in this item.
+	 *
+	 * @return a {@link CommandContributionItemParameter}. Valid fields are
+	 *         serviceLocator, id, style, icon, disabledIcon, hoverIcon, label,
+	 *         helpContextId, mnemonic, tooltip. The Object will never be
+	 *         <code>null</code>, although any of the fields may be
+	 *         <code>null</code>.
+	 * @since 3.100
+	 */
+	public CommandContributionItemParameter getData() {
+		CommandContributionItemParameter data = new CommandContributionItemParameter(
+				serviceLocator, getId(), null, style);
+		data.icon = contributedIcon;
+		data.disabledIcon = contributedDisabledIcon;
+		data.hoverIcon = contributedHoverIcon;
+		data.label = contributedLabel;
+		data.tooltip = contributedTooltip;
+		data.helpContextId = helpContextId;
+		data.mnemonic = mnemonic;
+		return data;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/CommandContributionItemParameter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/CommandContributionItemParameter.java
new file mode 100644
index 0000000..0737ef7
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/CommandContributionItemParameter.java
@@ -0,0 +1,205 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.menus;
+
+import java.util.Map;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * A help class for the various parameters that can be used with command
+ * contributions. Mandatory parameters are in the constructor, and public fields
+ * can be set to fill in other parameters.
+ *
+ * @since 3.4
+ */
+public class CommandContributionItemParameter {
+	/**
+	 * a service locator that is most appropriate for this contribution.
+	 * Typically the local {@link IWorkbenchWindow} or
+	 * {@link IWorkbenchPartSite} will be sufficient. Must not be
+	 * <code>null</code>.
+	 */
+	public IServiceLocator serviceLocator;
+
+	/**
+	 * The id for this item. May be <code>null</code>. Items without an id
+	 * cannot be referenced later.
+	 */
+	public String id;
+
+	/**
+	 * A command id for a defined command. Must not be <code>null</code>.
+	 */
+	public String commandId;
+
+	/**
+	 * A map of strings to strings which represent parameter names to values.
+	 * The parameter names must match those in the command definition. May be
+	 * <code>null</code>
+	 */
+	public Map parameters;
+
+	/**
+	 * An icon for this item. May be <code>null</code>.
+	 */
+	public ImageDescriptor icon;
+
+	/**
+	 * A disabled icon for this item. May be <code>null</code>.
+	 */
+	public ImageDescriptor disabledIcon;
+
+	/**
+	 * A hover icon for this item. May be <code>null</code>.
+	 */
+	public ImageDescriptor hoverIcon;
+
+	/**
+	 * A label for this item. May be <code>null</code>.
+	 */
+	public String label;
+
+	/**
+	 * A mnemonic for this item to be applied to the label. May be
+	 * <code>null</code>.
+	 */
+	public String mnemonic;
+
+	/**
+	 * A tooltip for this item. May be <code>null</code>. Tooltips are
+	 * currently only valid for toolbar contributions.
+	 */
+	public String tooltip;
+
+	/**
+	 * The style of this menu contribution. See the CommandContributionItem
+	 * STYLE_* contants.
+	 */
+	public int style;
+
+	/**
+	 * The help context id to be applied to this contribution. May be
+	 * <code>null</code>
+	 */
+	public String helpContextId;
+
+	/**
+	 * The icon style to use. May be <code>null</code> for default style.
+	 *
+	 * @see org.eclipse.ui.commands.ICommandImageService
+	 */
+	public String iconStyle;
+
+	/**
+	 * The visibility tracking for a menu contribution.
+	 */
+	public boolean visibleEnabled;
+
+	/**
+	 * Any number of mode bits, like
+	 * {@link CommandContributionItem#MODE_FORCE_TEXT}.
+	 */
+	public int mode;
+
+	/**
+	 * Create the parameter object. Nullable attributes can be set directly.
+	 *
+	 * @param serviceLocator
+	 *            a service locator that is most appropriate for this
+	 *            contribution. Typically the local {@link IWorkbenchWindow} or
+	 *            {@link IWorkbenchPartSite} will be sufficient. Must not be
+	 *            <code>null</code>.
+	 * @param id
+	 *            The id for this item. May be <code>null</code>. Items
+	 *            without an id cannot be referenced later.
+	 * @param commandId
+	 *            A command id for a defined command. Must not be
+	 *            <code>null</code>.
+	 * @param style
+	 *            The style of this menu contribution. See the STYLE_* contants.
+	 */
+	public CommandContributionItemParameter(IServiceLocator serviceLocator,
+			String id, String commandId, int style) {
+		this.serviceLocator = serviceLocator;
+		this.id = id;
+		this.commandId = commandId;
+		this.style = style;
+	}
+
+	/**
+	 * Build the parameter object.
+	 * <p>
+	 * <b>Note:</b> This constructor should not be called outside the framework.
+	 * </p>
+	 *
+	 * @param serviceLocator
+	 *            a service locator that is most appropriate for this
+	 *            contribution. Typically the local {@link IWorkbenchWindow} or
+	 *            {@link IWorkbenchPartSite} will be sufficient. Must not be
+	 *            <code>null</code>.
+	 * @param id
+	 *            The id for this item. May be <code>null</code>. Items
+	 *            without an id cannot be referenced later.
+	 * @param commandId
+	 *            A command id for a defined command. Must not be
+	 *            <code>null</code>.
+	 * @param parameters
+	 *            A map of strings to strings which represent parameter names to
+	 *            values. The parameter names must match those in the command
+	 *            definition. May be <code>null</code>
+	 * @param icon
+	 *            An icon for this item. May be <code>null</code>.
+	 * @param disabledIcon
+	 *            A disabled icon for this item. May be <code>null</code>.
+	 * @param hoverIcon
+	 *            A hover icon for this item. May be <code>null</code>.
+	 * @param label
+	 *            A label for this item. May be <code>null</code>.
+	 * @param mnemonic
+	 *            A mnemonic for this item to be applied to the label. May be
+	 *            <code>null</code>.
+	 * @param tooltip
+	 *            A tooltip for this item. May be <code>null</code>. Tooltips
+	 *            are currently only valid for toolbar contributions.
+	 * @param style
+	 *            The style of this menu contribution. See the STYLE_* contants.
+	 * @param helpContextId
+	 *            the help context id to be applied to this contribution. May be
+	 *            <code>null</code>
+	 * @param visibleEnabled
+	 *            Visibility tracking for the menu contribution.
+	 * @noreference This constructor is not intended to be referenced by clients.
+	 */
+	public CommandContributionItemParameter(IServiceLocator serviceLocator,
+			String id, String commandId, Map parameters, ImageDescriptor icon,
+			ImageDescriptor disabledIcon, ImageDescriptor hoverIcon,
+			String label, String mnemonic, String tooltip, int style,
+			String helpContextId, boolean visibleEnabled) {
+		this.serviceLocator = serviceLocator;
+		this.id = id;
+		this.commandId = commandId;
+		this.parameters = parameters;
+		this.icon = icon;
+		this.disabledIcon = disabledIcon;
+		this.hoverIcon = hoverIcon;
+		this.label = label;
+		this.mnemonic = mnemonic;
+		this.tooltip = tooltip;
+		this.style = style;
+		this.helpContextId = helpContextId;
+		this.visibleEnabled = visibleEnabled;
+	}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/ExtensionContributionFactory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/ExtensionContributionFactory.java
new file mode 100644
index 0000000..7db0608
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/ExtensionContributionFactory.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2015 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.ui.menus;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExecutableExtension;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+
+/**
+ * <p>
+ * Clients who wish to contribute factories via the
+ * <code>org.eclipse.ui.menus</code> extension point should subclass this class
+ * rather than the {@link AbstractContributionFactory} as this class provides a
+ * default constructor.
+ * </p>
+ *
+ * <p>
+ * Clients must be aware that the results of {@link #getLocation()} and
+ * {@link #getNamespace()} will not be valid until
+ * {@link #setInitializationData(IConfigurationElement, String, Object)} is
+ * invoked. This will occur before
+ * {@link #createContributionItems(org.eclipse.ui.services.IServiceLocator, IContributionRoot)}
+ * is invoked.
+ * </p>
+ *
+ * @since 3.5
+ */
+public abstract class ExtensionContributionFactory extends
+		AbstractContributionFactory implements IExecutableExtension {
+
+	private String namespace;
+	private String locationURI;
+
+	/**
+	 * Create an instance of this class.
+	 */
+	public ExtensionContributionFactory() {
+		super(null, null);
+	}
+
+	@Override
+	public final String getLocation() {
+		return locationURI;
+	}
+
+	@Override
+	public final String getNamespace() {
+		return namespace;
+	}
+
+	/**
+	 * Clients who wish to implement their own {@link IExecutableExtension}
+	 * behaviour <strong>must</strong> invoke this method prior to any
+	 * customization they perform.
+	 *
+	 * @throws CoreException
+	 *             so that a subclass may throw this
+	 */
+	@Override
+	public void setInitializationData(IConfigurationElement config,
+			String propertyName, Object data) throws CoreException {
+		locationURI = config
+				.getAttribute(IWorkbenchRegistryConstants.TAG_LOCATION_URI);
+		namespace = config.getNamespaceIdentifier();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/IContributionRoot.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/IContributionRoot.java
new file mode 100644
index 0000000..bb9b608
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/IContributionRoot.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.menus;
+
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.IContributionManager;
+
+/**
+ * Instances of this interface represent a position in the contribution
+ * hierarchy into which {@link AbstractContributionFactory} instances may insert
+ * elements. Instances of this interface are provided by the platform and this
+ * interface should <b>NOT</b> be implemented by clients.
+ *
+ *
+ * @since 3.3
+ */
+public interface IContributionRoot {
+	/**
+	 * Adds a given contribution item with provided visibility expression and
+	 * kill-switch filtering as a direct child of this container. This should be
+	 * called for all top-level elements created in
+	 * {@link AbstractContributionFactory#createContributionItems(org.eclipse.ui.services.IServiceLocator, IContributionRoot)}
+	 *
+	 * @param item
+	 *            the item to add
+	 * @param visibleWhen
+	 *            the visibility expression. May be <code>null</code>.
+	 */
+	public void addContributionItem(IContributionItem item,
+			Expression visibleWhen);
+
+	/**
+	 * Registers visibilty for arbitrary {@link IContributionItem} instances
+	 * that are <b>NOT</b> direct children of this container. Ie: children of a
+	 * {@link IContributionManager} that has been previously registered with a
+	 * call to {{@link #addContributionItem(IContributionItem, Expression)}.
+	 *
+	 * @param item
+	 *            the item for which to register a visibility clause
+	 * @param visibleWhen
+	 *            the visibility expression. May be <code>null</code> in which
+	 *            case this method is a no-op.
+	 */
+	public void registerVisibilityForChild(IContributionItem item,
+			Expression visibleWhen);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/IMenuService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/IMenuService.java
new file mode 100644
index 0000000..e0ca299
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/IMenuService.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.menus;
+
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.jface.action.ContributionManager;
+import org.eclipse.ui.services.IServiceWithSources;
+
+/**
+ * <p>
+ * Provides services related to the menu architecture within the workbench. It
+ * can be used to contribute additional items to the menu, tool bar and status
+ * line.
+ * </p>
+ * <p>
+ * This service can be acquired from your service locator:
+ * <pre>
+ * 	IMenuService service = (IMenuService) getSite().getService(IMenuService.class);
+ * </pre>
+ * <ul>
+ * <li>This service is available globally.</li>
+ * </ul>
+ * </p>
+ *
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noextend This interface is not intended to be extended by clients.
+ *
+ * @since 3.3
+ */
+public interface IMenuService extends IServiceWithSources {
+
+	/**
+	 * Contribute and initialize the contribution factory. This should only be
+	 * called once per factory. After the call, the factory should be treated as
+	 * an unmodifiable object.
+	 * <p>
+	 * <b>Note:</b> factories should be removed when no longer necessary. If
+	 * not, they will be removed when the IServiceLocator used to acquire this
+	 * service is disposed.
+	 * </p>
+	 *
+	 * @param factory
+	 *            the contribution factory. Must not be <code>null</code>
+	 * @see #removeContributionFactory(AbstractContributionFactory)
+	 */
+	public void addContributionFactory(AbstractContributionFactory factory);
+
+	/**
+	 * Remove the contributed factory from the menu service. If the factory is
+	 * not contained by this service, this call does nothing.
+	 *
+	 * @param factory
+	 *            the contribution factory to remove. Must not be
+	 *            <code>null</code>.
+	 */
+	public void removeContributionFactory(AbstractContributionFactory factory);
+
+	/**
+	 * Populate a <code>ContributionManager</code> at the specified starting
+	 * location with a set of <code>IContributionItems</code>s. It applies
+	 * <code>AbstractContributionFactory</code>s that are stored against the
+	 * provided location.
+	 *
+	 * @param mgr
+	 *            The ContributionManager to populate
+	 * @param location
+	 *            The starting location to begin populating this contribution
+	 *            manager. The format is the Menu API URI format.
+	 * @see #releaseContributions(ContributionManager)
+	 */
+	public void populateContributionManager(ContributionManager mgr,
+			String location);
+
+	/**
+	 * Before calling dispose() on a ContributionManager populated by the menu
+	 * service, you must inform the menu service to release its contributions.
+	 * This takes care of unregistering any IContributionItems that have their
+	 * visibleWhen clause managed by this menu service.
+	 * <p>
+	 * This will not update the ContributionManager (and any widgets). It will
+	 * simply remove all menu service references to the contents of this
+	 * ContributionManager.
+	 * </p>
+	 *
+	 * @param mgr
+	 *            The manager that was populated by a call to
+	 *            {@link #populateContributionManager(ContributionManager, String)}
+	 */
+	public void releaseContributions(ContributionManager mgr);
+
+	/**
+	 * Get the current state of eclipse as seen by the menu service.
+	 *
+	 * @return an IEvaluationContext containing state variables.
+	 *
+	 * @see org.eclipse.ui.ISources
+	 * @see org.eclipse.ui.services.IEvaluationService
+	 */
+	public IEvaluationContext getCurrentState();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/IWorkbenchContribution.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/IWorkbenchContribution.java
new file mode 100644
index 0000000..b7b795d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/IWorkbenchContribution.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2015 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.ui.menus;
+
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * Allow a menu contribution to be initialized with the appropriate service
+ * locator.
+ *
+ * @since 3.4
+ */
+public interface IWorkbenchContribution {
+	/**
+	 * The service locator for this contribution. It will potentially exist
+	 * longer than the lifecycle of this specific contribution, so
+	 * ContributionItems should remove themselves from any listeners or services
+	 * in their dispose() calls.
+	 *
+	 * @param serviceLocator
+	 *            the locator which services can be retrieved. Will not be
+	 *            <code>null</code>
+	 */
+	public void initialize(IServiceLocator serviceLocator);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/IWorkbenchWidget.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/IWorkbenchWidget.java
new file mode 100644
index 0000000..88a8c02
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/IWorkbenchWidget.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.ui.menus;
+
+import org.eclipse.jface.menus.IWidget;
+import org.eclipse.ui.IWorkbenchWindow;
+
+
+/**
+ * Interface used for IWidget's contributed to the
+ * Workbench. Allows the contributed widget to be
+ * informed as to which WorkbenchWindow it's being
+ * hosted in.
+ *
+ * @see org.eclipse.jface.menus.IWidget
+ *
+ * @since 3.2
+ */
+public interface IWorkbenchWidget extends IWidget {
+    /**
+     * Initializes this widget contribution by supplying the
+     * <code>IWorkbenchWindow</code> that it's being hosted in.
+     * <p>
+     * This method is called after the no argument constructor and
+     * before other methods are called.
+     * </p>
+     *
+     * @param workbenchWindow the current workbench
+     */
+    void init(IWorkbenchWindow workbenchWindow);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/MenuUtil.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/MenuUtil.java
new file mode 100644
index 0000000..7e9e988
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/MenuUtil.java
@@ -0,0 +1,151 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.menus;
+
+/**
+ * Provides utilities and constants for use with the new menus API.
+ *
+ * @since 3.3
+ * @noextend This class is not intended to be subclassed by clients.
+ * @noinstantiate This class is not intended to be instantiated by clients.
+ */
+public class MenuUtil {
+	/**
+	 * Workbench Menu. On supported platforms, this menu is shown when no
+	 * workbench windows are active
+	 *
+	 * @since 3.7
+	 */
+	public final static String WORKBENCH_MENU = "menu:org.eclipse.ui.workbench.menu"; //$NON-NLS-1$
+	/** Main Menu */
+	public final static String MAIN_MENU = "menu:org.eclipse.ui.main.menu"; //$NON-NLS-1$
+	/** Main ToolBar (CoolBar) */
+	public final static String MAIN_TOOLBAR = "toolbar:org.eclipse.ui.main.toolbar"; //$NON-NLS-1$
+
+	/** -Any- Popup Menu */
+	public final static String ANY_POPUP = "popup:org.eclipse.ui.popup.any"; //$NON-NLS-1$
+
+	/** Top Left Trim Area */
+	public final static String TRIM_COMMAND1 = "toolbar:org.eclipse.ui.trim.command1"; //$NON-NLS-1$
+	/** Top Right Trim Area */
+	public final static String TRIM_COMMAND2 = "toolbar:org.eclipse.ui.trim.command2"; //$NON-NLS-1$
+	/** Left Vertical Trim Area */
+	public final static String TRIM_VERTICAL1 = "toolbar:org.eclipse.ui.trim.vertical1"; //$NON-NLS-1$
+	/** Right Vertical Trim Area */
+	public final static String TRIM_VERTICAL2 = "toolbar:org.eclipse.ui.trim.vertical2"; //$NON-NLS-1$
+	/** Bottom (Status) Trim Area */
+	public final static String TRIM_STATUS = "toolbar:org.eclipse.ui.trim.status"; //$NON-NLS-1$
+
+	/**
+	 * Valid query attribute. Usage <b>menu:menu.id?before=contribution.id</b>.
+	 *
+	 * @since 3.6
+	 */
+	public final static String QUERY_BEFORE = "before"; //$NON-NLS-1$
+
+	/**
+	 * Valid query attribute. Usage <b>menu:menu.id?after=contribution.id</b>.
+	 *
+	 * @since 3.6
+	 */
+	public final static String QUERY_AFTER = "after"; //$NON-NLS-1$
+
+	/**
+	 * Valid query attribute. Usage <b>menu:menu.id?endof=contribution.id</b>.
+	 * <p>
+	 * This menu contribution will be placed at the end of the group defined by
+	 * <b>contribution.id</b> (usually right in front of the next group marker
+	 * or separator). Further contribution processing can still place other
+	 * contributions after this one.
+	 * </p>
+	 *
+	 * @since 3.6
+	 */
+	public final static String QUERY_ENDOF = "endof"; //$NON-NLS-1$
+
+	/**
+	 * Contributions of targets to this location will be included with the show
+	 * in menu.
+	 *
+	 * @since 3.4
+	 */
+	public final static String SHOW_IN_MENU_ID = "popup:org.eclipse.ui.menus.showInMenu"; //$NON-NLS-1$
+
+	/**
+	 * @param id
+	 *            The menu's id
+	 * @return The locator URI for a menu with the given id
+	 */
+	public static String menuUri(String id) {
+		return "menu:" + id; //$NON-NLS-1$
+	}
+
+	/**
+	 * @param id
+	 *            The id of the menu
+	 * @param location
+	 *            The relative location specifier
+	 * @param refId
+	 *            The id of the menu element to be relative to
+	 * @return A location URI formatted with the given parameters
+	 */
+	public static String menuAddition(String id, String location, String refId) {
+		return menuUri(id) + '?' + location + '=' + refId;
+	}
+
+	/**
+	 * Convenience method to create a standard menu addition The resulting
+	 * string has the format: "menu:[id]?after=additions"
+	 *
+	 * @param id
+	 *            The id of the root element to contribute to
+	 * @return The formatted string
+	 */
+	public static String menuAddition(String id) {
+		return menuAddition(id, "after", "additions"); //$NON-NLS-1$//$NON-NLS-2$
+	}
+
+	/**
+	 * @param id
+	 *            The toolbar's id
+	 * @return The lcoation URI for a toolbar with the given id
+	 */
+	public static String toolbarUri(String id) {
+		return "toolbar:" + id; //$NON-NLS-1$
+	}
+
+	/**
+	 * @param id
+	 *            The id of the toolbar
+	 * @param location
+	 *            The relative location specifier
+	 * @param refId
+	 *            The id of the toolbar element to be relative to
+	 * @return A location URI formatted with the given parameters
+	 */
+	public static String toolbarAddition(String id, String location,
+			String refId) {
+		return toolbarUri(id) + '?' + location + '=' + refId;
+	}
+
+	/**
+	 * Convenience method to create a standard toolbar addition The resulting
+	 * string has the format: "toolbar:[id]?after=additions"
+	 *
+	 * @param id
+	 *            The id of the root element to contribute to
+	 * @return The formatted string
+	 */
+	public static String toolbarAddition(String id) {
+		return toolbarAddition(id, "after", "additions"); //$NON-NLS-1$//$NON-NLS-2$
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/UIElement.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/UIElement.java
new file mode 100644
index 0000000..ad4fed7
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/UIElement.java
@@ -0,0 +1,133 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.menus;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * Allow a command or application to provide feedback to a user through updating
+ * a MenuItem or ToolItem. Initially used to update properties for UI elements
+ * created by the CommandContributionItem.
+ * <p>
+ * This class may be extended by clients.
+ * </p>
+ *
+ * @since 3.3
+ */
+public abstract class UIElement {
+
+	private IServiceLocator serviceLocator;
+
+	/**
+	 * Construct a new instance of this class keyed off of the provided service
+	 * locator.
+	 *
+	 * @param serviceLocator
+	 *            the locator. May not be <code>null</code>.
+	 */
+	protected UIElement(IServiceLocator serviceLocator)
+			throws IllegalArgumentException {
+		if (serviceLocator == null)
+			throw new IllegalArgumentException();
+		this.serviceLocator = serviceLocator;
+	}
+
+	/**
+	 * Update the label on this UI element.
+	 *
+	 * @param text
+	 *            The new label to display.
+	 */
+	public abstract void setText(String text);
+
+	/**
+	 * Update the tooltip on this UI element. Tooltips are currently only valid
+	 * for toolbar contributions.
+	 *
+	 * @param text
+	 *            The new tooltip to display.
+	 */
+	public abstract void setTooltip(String text);
+
+	/**
+	 * Update the icon on this UI element.
+	 *
+	 * @param desc
+	 *            The descriptor for the new icon to display.
+	 */
+	public abstract void setIcon(ImageDescriptor desc);
+
+	/**
+	 * Update the disabled icon on this UI element.
+	 *
+	 * @param desc
+	 *            The descriptor for the new icon to display.
+	 */
+	public abstract void setDisabledIcon(ImageDescriptor desc);
+
+	/**
+	 * Update the hover icon on this UI element.
+	 *
+	 * @param desc
+	 *            The descriptor for the new icon to display.
+	 */
+	public abstract void setHoverIcon(ImageDescriptor desc);
+
+	/**
+	 * Update the checked state on this UI element. For example, if this was a
+	 * toggle or radio button.
+	 *
+	 * @param checked
+	 *            true to set toggle on
+	 */
+	public abstract void setChecked(boolean checked);
+
+	/**
+	 * Get the service locator scope in which this UI element resides. May not
+	 * be <code>null</code>.
+	 *
+	 * <p>
+	 * The locator may be used to obtain services that are scoped in the same
+	 * way as the {@link UIElement}. Such services include but are not limited
+	 * to {@link IWorkbench}, {@link IWorkbenchWindow}, and
+	 * {@link IWorkbenchPartSite}. While this method may not return
+	 * <code>null</code> requests for any of these particular services may
+	 * return <code>null</code>.
+	 * </p>
+	 *
+	 * @return the service locator for this element
+	 * @see IServiceLocator#getService(Class)
+	 */
+	public final IServiceLocator getServiceLocator() {
+		return serviceLocator;
+	}
+
+	/**
+	 * Set the menu contribution id to use. This is only applicable to menu
+	 * contributions that support a drop-down style menu. The default
+	 * implementation does nothing.
+	 * <p>
+	 * Example: element.setDropdownId("org.eclipse.ui.navigate.back.my.menu");
+	 * </p>
+	 *
+	 * @param id
+	 *            used to populate the dropdown menu. Must not be
+	 *            <code>null</code>.
+	 */
+	public void setDropDownId(String id) {
+		// This does nothing.
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/WorkbenchWindowControlContribution.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/WorkbenchWindowControlContribution.java
new file mode 100644
index 0000000..a3e0763
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/WorkbenchWindowControlContribution.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2007 - 2015 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.ui.menus;
+
+import org.eclipse.jface.action.ControlContribution;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.internal.menus.InternalControlContribution;
+
+/**
+ * Abstract base class from which all controls contributions to
+ * the workbench through the 'org.eclipse.ui.menus' extension
+ * point must derive.
+ * <p>
+ * The extends the {@link ControlContribution} by adding accessor
+ * methods that provide extra state information about the placement
+ * of the control:
+ * <ul>
+ * <li>getWorkbenchWindow() - indicates which workbench window this control
+ * is being hosted by</li>
+ * <li>getCurSide() - indicates which side of the workbench window the
+ * control is being displayed on</li>
+ * </ul>
+ * </p>
+ *
+ * @since 3.3
+ *
+ * @see ControlContribution
+ */
+public abstract class WorkbenchWindowControlContribution extends InternalControlContribution {
+
+	/**
+	 * Default contstructor that allows the use of this class as
+	 * the basis for XML contributions and will be used by the
+	 * workbench implementation. This is public only by necessity
+	 * and should not be used outside of the workbench implemenation
+	 * code.
+	 */
+	public WorkbenchWindowControlContribution() {
+		this("unknown ID"); //$NON-NLS-1$
+	}
+
+	/**
+	 * Constructor for use by clients programmatically creating
+	 * control contributions in the workbench.
+	 *
+	 * @param id The id of this contribution
+	 */
+	public WorkbenchWindowControlContribution(String id) {
+		super(id);
+	}
+
+	/**
+	 * @return Returns the workbench window currently hosting
+	 * the control.
+	 */
+	@Override
+	public final IWorkbenchWindow getWorkbenchWindow() {
+		return super.getWorkbenchWindow();
+	}
+
+	/**
+	 * @return Returns the side of the workbench window that the
+	 * control is currently being display on. This allows derivatives
+	 * to tailor their created control based on the orientation...
+	 */
+	@Override
+	public final int getCurSide() {
+		return super.getCurSide();
+	}
+
+	@Override
+	public final int getOrientation() {
+		if (getCurSide() == SWT.LEFT || getCurSide() == SWT.RIGHT)
+			return SWT.VERTICAL;
+
+		return SWT.HORIZONTAL;
+	}
+
+	/**
+	 * Important: This method is *NOT* to be used/extended by clients. This is
+	 * for the internal use inside Workbench
+	 *
+	 * @param parent
+	 *            the parent composite
+	 * @return newly created Control
+	 * @since 3.6
+	 *
+	 * @noreference This method is not intended to be referenced by clients.
+	 * @nooverride This method is not intended to be re-implemented or extended
+	 *             by clients.
+	 */
+	public Control delegateCreateControl(Composite parent) {
+		return createControl(parent);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/package.html b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/package.html
new file mode 100644
index 0000000..af3889b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/menus/package.html
@@ -0,0 +1,17 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>Package-level Javadoc</title>
+</head>
+
+<body>
+
+Provides the public API and default implementation for contributing menu
+and toolbars to the menu service.  Also for contributed Trim
+widgets.
+
+</body>
+
+</html>
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/AdaptableList.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/AdaptableList.java
new file mode 100644
index 0000000..a76dfd3
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/AdaptableList.java
@@ -0,0 +1,149 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2016 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.ui.model;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IAdaptable;
+
+/**
+ * A modifiable list of <code>IAdaptable</code> objects.
+ * The list is adaptable to <code>IWorkbenchAdapter</code>, and can be used to
+ * display an arbitrary set of adaptable objects in a viewer.
+ * <p>
+ * This class is not intended to be subclassed.
+ * </p>
+ *
+ * @since 3.0
+ * @see org.eclipse.ui.model.IWorkbenchAdapter
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class AdaptableList extends WorkbenchAdapter implements IAdaptable {
+
+    protected List children = null;
+
+    /**
+     * Creates a new adaptable list. All of the elements in the list must
+     * implement <code>IAdaptable</code>.
+     */
+    public AdaptableList() {
+        children = new ArrayList();
+    }
+
+    /**
+     * Creates a new adaptable list with the given initial capacity.
+     * All of the elements in the list must implement <code>IAdaptable</code>.
+     *
+     * @param initialCapacity the initial capacity of the list
+     */
+    public AdaptableList(int initialCapacity) {
+        children = new ArrayList(initialCapacity);
+    }
+
+    /**
+     * Creates a new adaptable list containing the given children.
+     *
+     * @param newChildren the list of children
+     */
+    public AdaptableList(IAdaptable[] newChildren) {
+        this(newChildren.length);
+        for (IAdaptable adaptable : newChildren) {
+            children.add(adaptable);
+        }
+    }
+
+    /**
+     * Creates a new adaptable list containing the elements of the specified
+     * collection, in the order they are returned by the collection's iterator.
+     * All of the elements in the list must implement <code>IAdaptable</code>.
+     *
+     * @param c the initial elements of this list (element type:
+     * <code>IAdaptable</code>)
+     */
+    public AdaptableList(Collection c) {
+        this(c.size());
+        children.addAll(c);
+    }
+
+    /**
+     * Adds the given adaptable object to this list.
+     *
+     * @param adaptable the new element
+     * @return this list
+     */
+    public AdaptableList add(IAdaptable adaptable) {
+        Assert.isNotNull(adaptable);
+        children.add(adaptable);
+        return this;
+    }
+
+    /**
+     * Removes the given adaptable object from this list.
+     *
+     * @param adaptable the element to remove
+     */
+    public void remove(IAdaptable adaptable) {
+        Assert.isNotNull(adaptable);
+        children.remove(adaptable);
+    }
+
+    /**
+     * Returns the number of children in this list.
+     *
+     * @return the length of this list
+     */
+    public int size() {
+        return children.size();
+    }
+
+	@Override
+	public <T> T getAdapter(Class<T> adapter) {
+        if (adapter == IWorkbenchAdapter.class) {
+			return adapter.cast(this);
+        }
+        return null;
+    }
+
+    @Override
+	public Object[] getChildren(Object o) {
+        // @issue suspicious - does not reference parameter
+        return children.toArray();
+    }
+
+    /**
+     * Returns the elements in this list.
+     *
+     * @return the elements in this list
+     */
+    public Object[] getChildren() {
+        return children.toArray();
+    }
+
+    /**
+     * Return the elements in this list in an array of the given type.
+     *
+     * @param type the type of the array to create
+     * @return the elements in the list
+     * @since 3.1
+     */
+    public Object[] getTypedChildren(Class type) {
+		return children.toArray((Object[]) Array.newInstance(type, children
+				.size()));
+	}
+
+    @Override
+	public String toString() {
+        return children.toString();
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/BaseWorkbenchContentProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/BaseWorkbenchContentProvider.java
new file mode 100644
index 0000000..4d7b608
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/BaseWorkbenchContentProvider.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.model;
+
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+
+/**
+ * Tree content provider for objects that can be adapted to the interface
+ * {@link org.eclipse.ui.model.IWorkbenchAdapter IWorkbenchAdapter}.
+ * <p>
+ * This class may be instantiated, or subclassed.
+ * </p>
+ *
+ * @see IWorkbenchAdapter
+ * @since 3.0
+ */
+public class BaseWorkbenchContentProvider implements ITreeContentProvider {
+
+    /**
+     * Creates a new workbench content provider.
+     *
+     */
+    public BaseWorkbenchContentProvider() {
+        super();
+    }
+
+    @Override
+	public void dispose() {
+        // do nothing
+    }
+
+    /**
+     * Returns the implementation of IWorkbenchAdapter for the given
+     * object.  Returns null if the adapter is not defined or the
+     * object is not adaptable.
+     * <p>
+     * </p>
+     *
+     * @param element the element
+     * @return the corresponding workbench adapter object
+     */
+    protected IWorkbenchAdapter getAdapter(Object element) {
+        return Adapters.adapt(element, IWorkbenchAdapter.class);
+    }
+
+    @Override
+	public Object[] getChildren(Object element) {
+        IWorkbenchAdapter adapter = getAdapter(element);
+        if (adapter != null) {
+            return adapter.getChildren(element);
+        }
+        return new Object[0];
+    }
+
+    @Override
+	public Object[] getElements(Object element) {
+        return getChildren(element);
+    }
+
+    @Override
+	public Object getParent(Object element) {
+        IWorkbenchAdapter adapter = getAdapter(element);
+        if (adapter != null) {
+            return adapter.getParent(element);
+        }
+        return null;
+    }
+
+    @Override
+	public boolean hasChildren(Object element) {
+        return getChildren(element).length > 0;
+    }
+
+    @Override
+	public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+        // do nothing
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/ContributionComparator.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/ContributionComparator.java
new file mode 100644
index 0000000..a6afeb3
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/ContributionComparator.java
@@ -0,0 +1,154 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2015 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.ui.model;
+
+import java.util.Comparator;
+
+import org.eclipse.jface.preference.IPreferenceNode;
+import org.eclipse.jface.util.Policy;
+import org.eclipse.jface.viewers.StructuredViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+
+/**
+ * A ContributionComparator is capable of ordering
+ * {@link IComparableContribution} instances, either as a
+ * {@link ViewerComparator} (for {@link StructuredViewer}s) or as a traditional
+ * {@link Comparator}.
+ *
+ * This class orders contributions by first grouping by priority ({@link IComparableContribution#getPriority()})
+ * and then by utilizing the JFace policy comparator to order by label ({@link IComparableContribution#getLabel()}).
+ *
+ * @see IComparableContribution
+ *
+ * @since 3.4
+ */
+public class ContributionComparator extends ViewerComparator implements
+		Comparator {
+
+	/**
+	 * This implementation of {@link Comparator#compare(Object, Object)} does a
+	 * blind cast on each element to {@link IComparableContribution}.
+	 */
+	@Override
+	public int compare(Object o1, Object o2) {
+		IComparableContribution c1 = null, c2 = null;
+
+		if (o1 instanceof IComparableContribution)
+			c1 = (IComparableContribution) o1;
+
+		if (o2 instanceof IComparableContribution)
+			c2 = (IComparableContribution) o2;
+
+		// neither are comparable contributions, we need to be consistent
+		if (c1 == null && c2 == null) {
+			String s1 = getComparisonString(o1);
+			String s2 = getComparisonString(o2);
+
+			return Policy.getComparator().compare(s1, s2);
+		}
+
+		// if we're in a mixed scenario the comparable contribution wins.
+		if (c1 == null)
+			return 1;
+		if (c2 == null)
+			return -1;
+		return compare(c1, c2);
+	}
+
+	/**
+	 * Tries to extract a useful string for comparison from the provided object.
+	 * This method is a workaround for bug 226547. Looking forward we need a
+	 * more sensible answer to this problem.
+	 *
+	 * @param o
+	 * 		the object to test
+	 * @return the comparison string
+	 * TODO : remove this method and replace it with a sensible solution
+	 */
+	private String getComparisonString(Object o) {
+		if (o instanceof IPreferenceNode) {
+			return ((IPreferenceNode)o).getLabelText();
+		}
+		return o.toString();
+	}
+
+	/**
+	 * Returns a negative, zero, or positive number depending on whether the
+	 * first element is less than, equal to, or greater than the second element.
+	 * <p>
+	 * The default implementation of this method is based on comparing the
+	 * elements' categories as computed by the <code>category</code> framework
+	 * method. Elements within the same category are further subjected to a case
+	 * insensitive compare of their label strings. Subclasses may override.
+	 * </p>
+	 *
+	 * @param c1
+	 *            the first element
+	 * @param c2
+	 *            the second element
+	 * @return a negative number if the first element is less than the second
+	 *         element; the value <code>0</code> if the first element is equal
+	 *         to the second element; and a positive number if the first element
+	 *         is greater than the second element
+	 */
+	public int compare(IComparableContribution c1, IComparableContribution c2) {
+		int cat1 = category(c1);
+		int cat2 = category(c2);
+
+		if (cat1 != cat2) {
+			return cat1 - cat2;
+		}
+
+		String name1 = c1.getLabel();
+		String name2 = c2.getLabel();
+
+		if (name1 == null) {
+			name1 = "";//$NON-NLS-1$
+		}
+		if (name2 == null) {
+			name2 = "";//$NON-NLS-1$
+		}
+
+		// use the comparator to compare the strings
+		return Policy.getComparator().compare(name1, name2);
+	}
+
+	@Override
+	public int compare(Viewer viewer, Object e1, Object e2) {
+		return compare(e1, e2);
+	}
+
+	/**
+	 * Returns the category of the given element. The category is a number used
+	 * to allocate elements to bins; the bins are arranged in ascending numeric
+	 * order. The elements within a bin are arranged via a second level sort
+	 * criterion.
+	 * <p>
+	 * The default implementation of this framework method returns the result of
+	 * {@link IComparableContribution#getPriority()}. Subclasses may
+	 * re-implement this method to provide non-trivial categorization.
+	 * </p>
+	 *
+	 * @param c
+	 *            the element
+	 * @return the category
+	 */
+	public int category(IComparableContribution c) {
+		return c.getPriority();
+	}
+
+	@Override
+	public int category(Object element) {
+		return category((IComparableContribution) element);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/IComparableContribution.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/IComparableContribution.java
new file mode 100644
index 0000000..03a4cdc
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/IComparableContribution.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2016 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.ui.model;
+
+import org.eclipse.core.runtime.IAdaptable;
+
+/**
+ * Instances of this interface represent a contribution within the workbench.
+ * This interface is typically implemented by the workbench itself although
+ * extension developers may wish to implement it as well for their own
+ * extensions.
+ *
+ * @since 3.4
+ */
+public interface IComparableContribution extends IAdaptable {
+
+	/**
+	 * The default priority (0);
+	 */
+	public static final int PRIORITY_DEFAULT = 0;
+
+	/**
+	 * Return the priority of this contribution. Lower values constitute higher
+	 * priorities.
+	 *
+	 * @return the priority
+	 */
+	int getPriority();
+
+	/**
+	 * Return the human readable label for this contribution. Must not be
+	 * <code>null</code>.
+	 *
+	 * @return the label for this contribution
+	 */
+	String getLabel();
+
+	/**
+	 * Possible adaptations include:
+	 * <dl>
+	 * <dt>{@link org.eclipse.core.runtime.IConfigurationElement}</dt>
+	 * <dd>useful for contributions that eventually work back to registry
+	 * elements. The majority of {@link IComparableContribution} instances
+	 * provided by the platform will provide this adapter.</dd>
+	 * </dl>
+	 */
+	@Override
+	public <T> T getAdapter(Class<T> adapter);
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/IContributionService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/IContributionService.java
new file mode 100644
index 0000000..ea4f18a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/IContributionService.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2015 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.ui.model;
+
+/**
+ * Instances of this service are capable of providing standard mechanisms that
+ * clients may use to order, display, and generally work with contributions to
+ * the Workbench.
+ *
+ * @since 3.4
+ *
+ */
+public interface IContributionService {
+
+	/**
+	 * contributionType value for the PropertyDialog
+	 */
+	public static final String TYPE_PROPERTY = "property"; //$NON-NLS-1$
+
+	/**
+	 * contributionType value for Preferences
+	 */
+	public static final String TYPE_PREFERENCE = "preference"; //$NON-NLS-1$
+
+	/**
+	 * Return a comparator for ordering contributions within the user interface.
+	 *
+	 * @param contributionType
+	 *            the type of contribution, must not be <code>null</code>.
+	 * @return the comparator
+	 * @see #TYPE_PREFERENCE
+	 * @see #TYPE_PROPERTY
+	 */
+	public ContributionComparator getComparatorFor(String contributionType);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/IWorkbenchAdapter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/IWorkbenchAdapter.java
new file mode 100644
index 0000000..a381256
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/IWorkbenchAdapter.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 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.ui.model;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+
+/**
+ * This adapter interface provides visual presentation and hierarchical structure
+ * for workbench elements, allowing them to be displayed in the UI
+ * without having to know the concrete type of the element.
+ * <p>
+ * There is an associate label provider and content provider for showing
+ * elements with a registered workbench adapter in JFace structured viewers.
+ * </p>
+ * @see WorkbenchLabelProvider
+ * @see BaseWorkbenchContentProvider
+ */
+public interface IWorkbenchAdapter {
+    /**
+     * Returns the children of this object.  When this object
+     * is displayed in a tree, the returned objects will be this
+     * element's children.  Returns an empty array if this
+     * object has no children.
+     *
+     * @param o The object to get the children for.
+     * @return Object[]
+     */
+    public Object[] getChildren(Object o);
+
+    /**
+     * Returns an image descriptor to be used for displaying an object in the workbench.
+     * Returns <code>null</code> if there is no appropriate image.
+     *
+     * @param object The object to get an image descriptor for.
+     * @return ImageDescriptor
+     */
+    public ImageDescriptor getImageDescriptor(Object object);
+
+    /**
+     * Returns the label text for this element.  This is typically
+     * used to assign a label to this object when displayed
+     * in the UI.  Returns an empty string if there is no appropriate
+     * label text for this object.
+     *
+     * @param o The object to get a label for.
+     * @return String
+     */
+    public String getLabel(Object o);
+
+    /**
+     * Returns the logical parent of the given object in its tree.
+     * Returns <code>null</code> if there is no parent, or if this object doesn't
+     * belong to a tree.
+     *
+     * @param o The object to get the parent for.
+     * @return Object
+     */
+    public Object getParent(Object o);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/IWorkbenchAdapter2.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/IWorkbenchAdapter2.java
new file mode 100644
index 0000000..aaca256
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/IWorkbenchAdapter2.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.model;
+
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.RGB;
+
+/**
+ * Extension interface for <code>IWorkbenchAdapter</code> that allows for color
+ * and font support.
+ * <p>
+ * There is an associate label provider and content provider for showing
+ * elements with a registered workbench adapter in JFace structured viewers.
+ * </p>
+ * @see IWorkbenchAdapter
+ * @see WorkbenchLabelProvider
+ * @see BaseWorkbenchContentProvider
+ * @since 3.0
+ */
+public interface IWorkbenchAdapter2 {
+
+    /**
+     * Provides a foreground color for the given element.
+     *
+     * @param element the element
+     * @return	the foreground color for the element, or <code>null</code>
+     *   to use the default foreground color
+     */
+    public RGB getForeground(Object element);
+
+    /**
+     * Provides a background color for the given element.
+     *
+     * @param element the element
+     * @return	the background color for the element, or <code>null</code>
+     *   to use the default background color
+     */
+    public RGB getBackground(Object element);
+
+    /**
+     * Provides a font the given element.
+     *
+     * @param element the element
+     * @return	the font for the element, or <code>null</code>
+     *   to use the default font
+     */
+    public FontData getFont(Object element);
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/IWorkbenchAdapter3.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/IWorkbenchAdapter3.java
new file mode 100644
index 0000000..d923285
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/IWorkbenchAdapter3.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2015 Fair Isaac 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:
+ *     Fair Isaac Corporation <Hemant.Singh@Gmail.com> - Initial API and implementation(Bug 326695)
+ ******************************************************************************/
+
+package org.eclipse.ui.model;
+
+/**
+ * Extension interface for <code>IWorkbenchAdapter</code> that allows for
+ * StyledString support.
+ *
+ * @see IWorkbenchAdapter
+ * @see WorkbenchLabelProvider
+ * @see BaseWorkbenchContentProvider
+ * @see org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider.IStyledLabelProvider
+ *
+ * @since 3.7
+ */
+public interface IWorkbenchAdapter3 {
+
+	/**
+	 * Returns the styled text label for the given element.
+	 *
+	 * @param element
+	 *            the element to evaluate the styled string for.
+	 *
+	 * @return the styled string.
+	 */
+	public StringBuilder getStyledText(Object element);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/PerspectiveLabelProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/PerspectiveLabelProvider.java
new file mode 100644
index 0000000..a2af5bd
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/PerspectiveLabelProvider.java
@@ -0,0 +1,129 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.model;
+
+import java.util.HashMap;
+import java.util.Iterator;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.internal.WorkbenchMessages;
+
+/**
+ * A table label provider implementation for showing workbench perspectives
+ * (objects of type <code>IPerspectiveDescriptor</code>) in table- and
+ * tree-structured viewers.
+ * <p>
+ * Clients may instantiate this class. It is not intended to be subclassed.
+ * </p>
+ *
+ * @since 3.0
+ */
+public final class PerspectiveLabelProvider extends LabelProvider implements
+        ITableLabelProvider {
+
+    /**
+     * List of all Image objects this label provider is responsible for.
+     */
+    private HashMap imageCache = new HashMap(5);
+
+    /**
+     * Indicates whether the default perspective is visually marked.
+     */
+    private boolean markDefault;
+
+    /**
+     * Creates a new label provider for perspectives.
+     * The default perspective is visually marked.
+     */
+    public PerspectiveLabelProvider() {
+        this(true);
+    }
+
+    /**
+     * Creates a new label provider for perspectives.
+     *
+     * @param markDefault <code>true</code> if the default perspective is to be
+     * visually marked, and <code>false</code> if the default perspective is
+     * not treated as anything special
+     */
+    public PerspectiveLabelProvider(boolean markDefault) {
+        super();
+        this.markDefault = markDefault;
+    }
+
+    @Override
+	public final Image getImage(Object element) {
+        if (element instanceof IPerspectiveDescriptor) {
+            IPerspectiveDescriptor desc = (IPerspectiveDescriptor) element;
+            ImageDescriptor imageDescriptor = desc.getImageDescriptor();
+            if (imageDescriptor == null) {
+                imageDescriptor = WorkbenchImages
+                        .getImageDescriptor(ISharedImages.IMG_ETOOL_DEF_PERSPECTIVE);
+            }
+            Image image = (Image) imageCache.get(imageDescriptor);
+            if (image == null) {
+                image = imageDescriptor.createImage();
+                imageCache.put(imageDescriptor, image);
+            }
+            return image;
+        }
+        return null;
+    }
+
+    @Override
+	public final void dispose() {
+        for (Iterator i = imageCache.values().iterator(); i.hasNext();) {
+            ((Image) i.next()).dispose();
+        }
+        imageCache.clear();
+    }
+
+    @Override
+	public final String getText(Object element) {
+        if (element instanceof IPerspectiveDescriptor) {
+            IPerspectiveDescriptor desc = (IPerspectiveDescriptor) element;
+            String label = desc.getLabel();
+            if (markDefault) {
+                String def = PlatformUI.getWorkbench().getPerspectiveRegistry()
+                        .getDefaultPerspective();
+                if (desc.getId().equals(def)) {
+                    label = NLS.bind(WorkbenchMessages.get().PerspectivesPreference_defaultLabel, label );
+                }
+            }
+            return label;
+        }
+        return WorkbenchMessages.get().PerspectiveLabelProvider_unknown;
+    }
+
+    /**
+     * @see ITableLabelProvider#getColumnImage
+     */
+    @Override
+	public final Image getColumnImage(Object element, int columnIndex) {
+        return getImage(element);
+    }
+
+    /**
+     * @see ITableLabelProvider#getColumnText
+     */
+    @Override
+	public final String getColumnText(Object element, int columnIndex) {
+        return getText(element);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/WorkbenchAdapter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/WorkbenchAdapter.java
new file mode 100644
index 0000000..39b1c04
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/WorkbenchAdapter.java
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Fair Isaac Corporation <Hemant.Singh@Gmail.com> - Bug 326695
+ *******************************************************************************/
+package org.eclipse.ui.model;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.RGB;
+
+/**
+ * Abstract base class with basic implementations of the IWorkbenchAdapter
+ * interface. Intended to be subclassed.
+ *
+ * @since 3.0
+ */
+public abstract class WorkbenchAdapter implements IWorkbenchAdapter,
+        IWorkbenchAdapter2, IWorkbenchAdapter3 {
+    /**
+     * The empty list of children.
+     */
+    protected static final Object[] NO_CHILDREN = new Object[0];
+
+    /**
+     * The default implementation of this <code>IWorkbenchAdapter</code> method
+     * returns the empty list. Subclasses may override.
+     */
+    @Override
+	public Object[] getChildren(Object object) {
+        return NO_CHILDREN;
+    }
+
+    /**
+     * The default implementation of this <code>IWorkbenchAdapter</code> method
+     * returns <code>null</code>. Subclasses may override.
+     */
+    @Override
+	public ImageDescriptor getImageDescriptor(Object object) {
+        return null;
+    }
+
+    /**
+     * The default implementation of this <code>IWorkbenchAdapter</code> method
+     * returns the empty string if the object is <code>null</code>, and
+     * the object's <code>toString</code> otherwise. Subclasses may override.
+     */
+    @Override
+	public String getLabel(Object object) {
+        return object == null ? "" : object.toString(); //$NON-NLS-1$
+    }
+
+    /**
+     * The default implementation of this <code>IWorkbenchAdapter</code> method
+     * returns <code>null</code>. Subclasses may override.
+     */
+    @Override
+	public Object getParent(Object object) {
+        return null;
+    }
+
+    /**
+     * The default implementation of this <code>IWorkbenchAdapter2</code> method
+     * returns <code>null</code>. Subclasses may override.
+     */
+    @Override
+	public RGB getBackground(Object element) {
+        return null;
+    }
+
+    /**
+     * The default implementation of this <code>IWorkbenchAdapter2</code> method
+     * returns <code>null</code>. Subclasses may override.
+     */
+    @Override
+	public RGB getForeground(Object element) {
+        return null;
+    }
+
+    /**
+     * The default implementation of this <code>IWorkbenchAdapter2</code> method
+     * returns <code>null</code>. Subclasses may override.
+     */
+    @Override
+	public FontData getFont(Object element) {
+        return null;
+    }
+
+	/**
+	 * The default implementation of this <code>IWorkbenchAdapter3</code> method
+	 * returns the {@link StyledString} which wraps the label of the element.
+	 * Subclasses may override.
+	 *
+	 * @return Return the {@link StyledString} which wraps the label of the
+	 *         element.
+	 *
+	 * @since 3.7
+	 */
+	@Override
+	public StringBuilder getStyledText(Object object) {
+		return new StringBuilder(getLabel(object));
+    }
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/WorkbenchLabelProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/WorkbenchLabelProvider.java
new file mode 100644
index 0000000..3bd6bd3
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/WorkbenchLabelProvider.java
@@ -0,0 +1,285 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Fair Isaac Corporation <Hemant.Singh@Gmail.com> - Bug 326695
+ *******************************************************************************/
+package org.eclipse.ui.model;
+
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.jface.resource.ColorDescriptor;
+import org.eclipse.jface.resource.FontDescriptor;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.jface.resource.ResourceManager;
+import org.eclipse.jface.viewers.DecoratingLabelProvider;
+import org.eclipse.jface.viewers.IColorProvider;
+import org.eclipse.jface.viewers.IFontProvider;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.LabelProviderChangedEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.ui.IEditorRegistry;
+import org.eclipse.ui.IPropertyListener;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * Provides basic labels for adaptable objects that have the
+ * <code>IWorkbenchAdapter</code> adapter associated with them.  All dispensed
+ * images are cached until the label provider is explicitly disposed.
+ * This class provides a facility for subclasses to define annotations
+ * on the labels and icons of adaptable objects.
+ */
+public class WorkbenchLabelProvider extends LabelProvider implements
+        IColorProvider, IFontProvider {
+
+    /**
+     * Returns a workbench label provider that is hooked up to the decorator
+     * mechanism.
+     *
+     * @return a new <code>DecoratingLabelProvider</code> which wraps a <code>
+     *   new <code>WorkbenchLabelProvider</code>
+     */
+    public static ILabelProvider getDecoratingWorkbenchLabelProvider() {
+        return new DecoratingLabelProvider(new WorkbenchLabelProvider(),
+                PlatformUI.getWorkbench().getDecoratorManager()
+                        .getLabelDecorator());
+    }
+
+    /**
+     * Listener that tracks changes to the editor registry and does a full update
+     * when it changes, since many workbench adapters derive their icon from the file
+     * associations in the registry.
+     */
+    private IPropertyListener editorRegistryListener = (source, propId) -> {
+		if (propId == IEditorRegistry.PROP_CONTENTS) {
+			fireLabelProviderChanged(new LabelProviderChangedEvent(WorkbenchLabelProvider.this));
+		}
+	};
+	private ResourceManager resourceManager;
+
+    /**
+     * Creates a new workbench label provider.
+     */
+    public WorkbenchLabelProvider() {
+    	PlatformUI.getWorkbench().getEditorRegistry().addPropertyListener(editorRegistryListener);
+    }
+
+    /**
+     * Returns an image descriptor that is based on the given descriptor,
+     * but decorated with additional information relating to the state
+     * of the provided object.
+     *
+     * Subclasses may reimplement this method to decorate an object's
+     * image.
+     *
+     * @param input The base image to decorate.
+     * @param element The element used to look up decorations.
+     * @return the resuling ImageDescriptor.
+     * @see org.eclipse.jface.resource.CompositeImageDescriptor
+     */
+    protected ImageDescriptor decorateImage(ImageDescriptor input,
+            Object element) {
+        return input;
+    }
+
+    /**
+     * Returns a label that is based on the given label,
+     * but decorated with additional information relating to the state
+     * of the provided object.
+     *
+     * Subclasses may implement this method to decorate an object's
+     * label.
+     * @param input The base text to decorate.
+     * @param element The element used to look up decorations.
+     * @return the resulting text
+     */
+    protected String decorateText(String input, Object element) {
+        return input;
+    }
+
+    @Override
+	public void dispose() {
+    	PlatformUI.getWorkbench().getEditorRegistry().removePropertyListener(editorRegistryListener);
+		if (resourceManager != null)
+			resourceManager.dispose();
+    	resourceManager = null;
+    	super.dispose();
+    }
+
+    /**
+     * Returns the implementation of IWorkbenchAdapter for the given
+     * object.
+     * @param o the object to look up.
+     * @return IWorkbenchAdapter or<code>null</code> if the adapter is not defined or the
+     * object is not adaptable.
+     */
+    protected final IWorkbenchAdapter getAdapter(Object o) {
+        return Adapters.adapt(o, IWorkbenchAdapter.class);
+    }
+
+    /**
+     * Returns the implementation of IWorkbenchAdapter2 for the given
+     * object.
+     * @param o the object to look up.
+     * @return IWorkbenchAdapter2 or<code>null</code> if the adapter is not defined or the
+     * object is not adaptable.
+     */
+    protected final IWorkbenchAdapter2 getAdapter2(Object o) {
+        return Adapters.adapt(o, IWorkbenchAdapter2.class);
+    }
+
+	/**
+	 * Returns the implementation of IWorkbenchAdapter3 for the given object.
+	 *
+	 * @param o
+	 *            the object to look up.
+	 * @return IWorkbenchAdapter3 or<code>null</code> if the adapter is not
+	 *         defined or the object is not adaptable.
+	 * @since 3.7
+	 */
+	protected final IWorkbenchAdapter3 getAdapter3(Object o) {
+		return Adapters.adapt(o, IWorkbenchAdapter3.class);
+	}
+
+	/**
+	 * Lazy load the resource manager
+	 *
+	 * @return The resource manager, create one if necessary
+	 */
+	private ResourceManager getResourceManager() {
+		if (resourceManager == null) {
+			resourceManager = new LocalResourceManager(JFaceResources
+					.getResources());
+		}
+
+		return resourceManager;
+	}
+
+    @Override
+	public final Image getImage(Object element) {
+        //obtain the base image by querying the element
+        IWorkbenchAdapter adapter = getAdapter(element);
+        if (adapter == null) {
+            return null;
+        }
+        ImageDescriptor descriptor = adapter.getImageDescriptor(element);
+        if (descriptor == null) {
+            return null;
+        }
+
+        //add any annotations to the image descriptor
+        descriptor = decorateImage(descriptor, element);
+
+		return (Image) getResourceManager().get(descriptor);
+    }
+
+//	/**
+//	 * The default implementation of this returns the styled text label for the
+//	 * given element.
+//	 *
+//	 * @param element
+//	 *            the element to evaluate the styled string for
+//	 *
+//	 * @return the styled string.
+//	 *
+//	 * @since 3.7
+//	 */
+//    @Override
+//	public StringBuilder getStyledText(Object element) {
+//        IWorkbenchAdapter3 adapter = getAdapter3(element);
+//		if (adapter == null) {
+//			// If adapter class doesn't implement IWorkbenchAdapter3 than use
+//			// StyledString with text of element. Since the output of getText is
+//			// already decorated, so we don't need to call decorateText again
+//			// here.
+//			return new StyledString(getText(element));
+//		}
+//		StyledString styledString = adapter.getStyledText(element);
+//		// Now, re-use any existing decorateText implementation, to decorate
+//		// this styledString.
+//		String decorated = decorateText(styledString.getString(), element);
+//		Styler styler = getDecorationStyle(element);
+//		return StyledCellLabelProvider.styleDecoratedString(decorated, styler, styledString);
+//    }
+//
+//	/**
+//	 * Sets the {@link Styler} to be used for string decorations. By default the
+//	 * {@link StyledString#DECORATIONS_STYLER decoration style}. Clients can
+//	 * override.
+//	 *
+//	 * @param element
+//	 *            the element that has been decorated
+//	 *
+//	 * @return return the decoration style
+//	 *
+//	 * @since 3.7
+//	 */
+//	protected Styler getDecorationStyle(Object element) {
+//		return StyledString.DECORATIONS_STYLER;
+//	}
+
+    @Override
+	public final String getText(Object element) {
+        //query the element for its label
+        IWorkbenchAdapter adapter = getAdapter(element);
+        if (adapter == null) {
+            return ""; //$NON-NLS-1$
+        }
+        String label = adapter.getLabel(element);
+
+        //return the decorated label
+        return decorateText(label, element);
+    }
+
+    @Override
+	public Color getForeground(Object element) {
+        return getColor(element, true);
+    }
+
+    @Override
+	public Color getBackground(Object element) {
+        return getColor(element, false);
+    }
+
+    @Override
+	public Font getFont(Object element) {
+        IWorkbenchAdapter2 adapter = getAdapter2(element);
+        if (adapter == null) {
+            return null;
+        }
+
+        FontData descriptor = adapter.getFont(element);
+        if (descriptor == null) {
+            return null;
+        }
+
+		return (Font) getResourceManager().get(
+				FontDescriptor.createFrom(descriptor));
+    }
+
+    private Color getColor(Object element, boolean forground) {
+        IWorkbenchAdapter2 adapter = getAdapter2(element);
+        if (adapter == null) {
+            return null;
+        }
+        RGB descriptor = forground ? adapter.getForeground(element) : adapter
+                .getBackground(element);
+        if (descriptor == null) {
+            return null;
+        }
+
+		return (Color) getResourceManager().get(
+				ColorDescriptor.createFrom(descriptor));
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/WorkbenchPartLabelProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/WorkbenchPartLabelProvider.java
new file mode 100644
index 0000000..072ca99
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/WorkbenchPartLabelProvider.java
@@ -0,0 +1,120 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.model;
+
+import java.util.HashMap;
+
+import org.eclipse.jface.resource.DeviceResourceException;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.jface.resource.ResourceManager;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.Saveable;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+
+/**
+ * A table label provider implementation for showing workbench views and
+ * editors (objects of type <code>IWorkbenchPart</code>) in tree- and
+ * table-structured viewers.
+ * <p>
+ * Clients may instantiate this class. It is not intended to be subclassed.
+ * </p>
+ *
+ * @since 3.0
+ */
+public final class WorkbenchPartLabelProvider extends LabelProvider implements
+        ITableLabelProvider {
+
+	private ResourceManager resourceManager = new LocalResourceManager(JFaceResources.getResources());
+	private HashMap images = new HashMap();
+
+    /**
+     * Creates a new label provider for workbench parts.
+     */
+    public WorkbenchPartLabelProvider() {
+        super();
+    }
+
+    @Override
+	public final Image getImage(Object element) {
+        if (element instanceof IWorkbenchPart) {
+            return ((IWorkbenchPart) element).getTitleImage();
+        }
+        if (element instanceof Saveable) {
+        	Saveable model = (Saveable) element;
+        	ImageDescriptor imageDesc = model.getImageDescriptor();
+        	// convert from ImageDescriptor to Image
+        	if (imageDesc == null) {
+				return null;
+			}
+        	Image image = (Image) images.get(imageDesc);
+        	if (image == null) {
+        		try {
+        			image = resourceManager.createImage(imageDesc);
+        			images.put(imageDesc, image);
+        		}
+        		catch (DeviceResourceException e) {
+        			WorkbenchPlugin.log(getClass(), "getImage", e); //$NON-NLS-1$
+        		}
+        	}
+        	return image;
+        }
+        return null;
+    }
+
+    @Override
+	public final String getText(Object element) {
+        if (element instanceof IWorkbenchPart) {
+            IWorkbenchPart part = (IWorkbenchPart) element;
+            String path = part.getTitleToolTip();
+            if (path == null || path.trim().length() == 0) {
+                return part.getTitle();
+            }
+            return part.getTitle() + "  [" + path + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        if (element instanceof Saveable) {
+        	Saveable model = (Saveable) element;
+            String path = model.getToolTipText();
+            if (path == null || path.trim().length() == 0) {
+                return model.getName();
+            }
+            return model.getName() + "  [" + path + "]";  //$NON-NLS-1$ //$NON-NLS-2$
+
+        }
+        return null;
+    }
+
+    /**
+     * @see ITableLabelProvider#getColumnImage
+     */
+    @Override
+	public final Image getColumnImage(Object element, int columnIndex) {
+        return getImage(element);
+    }
+
+    /**
+     * @see ITableLabelProvider#getColumnText
+     */
+    @Override
+	public final String getColumnText(Object element, int columnIndex) {
+        return getText(element);
+    }
+
+    @Override
+	public void dispose() {
+    	resourceManager.dispose();
+    	super.dispose();
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/WorkbenchViewerComparator.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/WorkbenchViewerComparator.java
new file mode 100644
index 0000000..27d63b1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/WorkbenchViewerComparator.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.model;
+
+import java.util.Comparator;
+
+import org.eclipse.jface.viewers.IBasicPropertyConstants;
+import org.eclipse.jface.viewers.ViewerComparator;
+
+/**
+ *
+ * A viewer comparator that sorts elements with registered workbench adapters by
+ * their text property. Note that capitalization differences are not considered
+ * by this sorter, so a &gt; B &gt; c
+ *
+ * @see IWorkbenchAdapter
+ * @since 3.3
+ */
+public class WorkbenchViewerComparator extends ViewerComparator {
+
+    /**
+     * Creates a workbench viewer sorter using the default collator.
+     */
+    public WorkbenchViewerComparator() {
+        super();
+    }
+
+    /**
+     * Creates a workbench viewer sorter using the given collator.
+     *
+     * @param comparator the comparator to use to sort strings
+     */
+    public WorkbenchViewerComparator(Comparator comparator) {
+        super(comparator);
+    }
+
+    @Override
+	public boolean isSorterProperty(Object element, String propertyId) {
+        return propertyId.equals(IBasicPropertyConstants.P_TEXT);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/WorkbenchViewerSorter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/WorkbenchViewerSorter.java
new file mode 100644
index 0000000..53cd51d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/WorkbenchViewerSorter.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.model;
+
+import java.text.Collator; // can't use ICU, public API
+
+import org.eclipse.jface.viewers.IBasicPropertyConstants;
+import org.eclipse.jface.viewers.ViewerSorter;
+
+/**
+ * A viewer sorter that sorts elements with registered workbench adapters by their text property.
+ * Note that capitalization differences are not considered by this
+ * sorter, so a &gt; B &gt; c
+ *
+ * @see IWorkbenchAdapter
+ * @deprecated as of 3.3, use {@link WorkbenchViewerComparator} instead
+ */
+@Deprecated
+public class WorkbenchViewerSorter extends ViewerSorter {
+
+    /**
+     * Creates a workbench viewer sorter using the default collator.
+     */
+    public WorkbenchViewerSorter() {
+        super();
+    }
+
+    /**
+     * Creates a workbench viewer sorter using the given collator.
+     *
+     * @param collator the collator to use to sort strings
+     */
+    public WorkbenchViewerSorter(Collator collator) {
+        super(collator);
+    }
+
+    @Override
+	public boolean isSorterProperty(Object element, String propertyId) {
+        return propertyId.equals(IBasicPropertyConstants.P_TEXT);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/package.html b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/package.html
new file mode 100644
index 0000000..7652c46
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/model/package.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<meta name="Author" content="IBM">
+<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
+<meta name="ProgId" content="FrontPage.Editor.Document">
+<title>Package-level Javadoc</title>
+</head>
+
+<body>
+
+Provides a workbench adapter for displaying workbench elements in the UI without
+having to know the concrete type of the element, and various label providers for
+workbench-specific objects like editors, views, and perspectives.
+
+</body>
+
+</html>
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/operations/IWorkbenchOperationSupport.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/operations/IWorkbenchOperationSupport.java
new file mode 100644
index 0000000..eaa4c6e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/operations/IWorkbenchOperationSupport.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.operations;
+
+import org.eclipse.core.commands.operations.IOperationHistory;
+import org.eclipse.core.commands.operations.IUndoContext;
+
+/**
+ * An instance of this interface provides support for managing a
+ * a shared operations history and an shared undo context at the <code>IWorkbench</code>
+ * level.
+ * <p>
+ * This interface is not intended to be extended or implemented by clients.
+ * </p>
+ *
+ * @since 3.1
+ *
+ * @see org.eclipse.ui.IWorkbench#getOperationSupport()
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IWorkbenchOperationSupport {
+
+	/**
+	 * Returns the undo context for workbench-wide operations.
+	 *
+	 * @return the workbench operation context
+	 */
+	public IUndoContext getUndoContext();
+
+	/**
+	 * Returns the operation history for the workbench.
+	 *
+	 * @return the workbench operation history
+	 */
+	public IOperationHistory getOperationHistory();
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/operations/LinearUndoViolationUserApprover.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/operations/LinearUndoViolationUserApprover.java
new file mode 100644
index 0000000..30321b5
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/operations/LinearUndoViolationUserApprover.java
@@ -0,0 +1,164 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.operations;
+
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.operations.IOperationHistory;
+import org.eclipse.core.commands.operations.IUndoContext;
+import org.eclipse.core.commands.operations.IUndoableOperation;
+import org.eclipse.core.commands.operations.LinearUndoViolationDetector;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPart2;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchMessages;
+
+/**
+ * <p>
+ * An operation approver that prompts the user to see if linear undo violations
+ * are permitted. A linear undo violation is detected when an operation being
+ * undone or redone shares an undo context with another operation appearing more
+ * recently in the history.
+ * </p>
+ * <p>
+ * This class may be instantiated by clients.
+ * </p>
+ *
+ * @since 3.1
+ */
+public final class LinearUndoViolationUserApprover extends
+		LinearUndoViolationDetector {
+
+	private IWorkbenchPart part;
+
+	private IUndoContext context;
+
+	/**
+	 * Create a LinearUndoViolationUserApprover associated with the specified
+	 * workbench part.
+	 *
+	 * @param context
+	 *            the undo context with the linear undo violation
+	 * @param part
+	 *            the part that should be used for prompting the user
+	 */
+	public LinearUndoViolationUserApprover(IUndoContext context,
+			IWorkbenchPart part) {
+		super();
+		this.part = part;
+		this.context = context;
+	}
+
+	@Override
+	protected IStatus allowLinearRedoViolation(IUndoableOperation operation,
+			IUndoContext context, IOperationHistory history, IAdaptable uiInfo) {
+
+		if (this.context != context) {
+			return Status.OK_STATUS;
+		}
+
+		final String message = NLS.bind(
+				WorkbenchMessages.get().Operations_linearRedoViolation,
+				getTitle(part), operation.getLabel());
+		final boolean [] proceed = new boolean[1];
+		PlatformUI.getWorkbench().getDisplay().syncExec(() -> {
+			// Show a dialog.
+			part.setFocus();
+			proceed[0] = MessageDialog.openQuestion(part.getSite()
+					.getShell(), getTitle(part), message);
+		});
+
+		if (proceed[0]) {
+			// redo the local changes first
+			while (operation != history.getRedoOperation(context)) {
+				try {
+					IStatus status = history.redo(context, null, uiInfo);
+					if (!status.isOK()) {
+						// flush the redo history because the operation
+						// failed
+						history.dispose(context, false, true, false);
+						return Status.CANCEL_STATUS;
+					}
+				} catch (ExecutionException e) {
+					// flush the redo history here because it failed.
+					history.dispose(context, false, true, false);
+					return Status.CANCEL_STATUS;
+				}
+			}
+			return Status.OK_STATUS;
+		}
+
+		return Status.CANCEL_STATUS;
+	}
+
+	@Override
+	protected IStatus allowLinearUndoViolation(IUndoableOperation operation,
+			IUndoContext context, IOperationHistory history, IAdaptable uiInfo) {
+
+		if (this.context != context) {
+			return Status.OK_STATUS;
+		}
+
+		final String message = NLS.bind(
+				WorkbenchMessages.get().Operations_linearUndoViolation,
+				getTitle(part), operation.getLabel());
+		final boolean [] proceed = new boolean[1];
+		PlatformUI.getWorkbench().getDisplay().syncExec(() -> {
+			// Show a dialog.
+			part.setFocus();
+			proceed[0] = MessageDialog.openQuestion(part.getSite()
+					.getShell(), getTitle(part), message);
+		});
+
+		if (proceed[0]) {
+			// redo the local changes first
+			while (operation != history.getUndoOperation(context)) {
+				try {
+					IStatus status = history.undo(context, null, uiInfo);
+					if (!status.isOK()) {
+						// flush the operation history because the operation
+						// failed.
+						history.dispose(context, true, false, false);
+						return Status.CANCEL_STATUS;
+					}
+				} catch (ExecutionException e) {
+					// flush the undo history here because something went wrong.
+					history.dispose(context, true, false, false);
+					return Status.CANCEL_STATUS;
+				}
+			}
+			return Status.OK_STATUS;
+		}
+		return Status.CANCEL_STATUS;
+	}
+
+	/*
+	 * Get the title for the specified part. Use the newer interface
+	 * IWorkbenchPart2 if available.
+	 */
+	private String getTitle(IWorkbenchPart part) {
+		String title;
+		if (part instanceof IWorkbenchPart2) {
+			title = ((IWorkbenchPart2) part).getPartName();
+		} else {
+			title = part.getTitle();
+		}
+		// Null title is unexpected, but use an empty string if encountered.
+		if (title == null) {
+			title = ""; //$NON-NLS-1$
+		}
+		return title;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/operations/NonLocalUndoUserApprover.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/operations/NonLocalUndoUserApprover.java
new file mode 100644
index 0000000..2cf0430
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/operations/NonLocalUndoUserApprover.java
@@ -0,0 +1,278 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.operations;
+
+import java.util.ArrayList;
+
+import org.eclipse.core.commands.operations.IAdvancedUndoableOperation;
+import org.eclipse.core.commands.operations.IOperationApprover;
+import org.eclipse.core.commands.operations.IOperationHistory;
+import org.eclipse.core.commands.operations.IUndoContext;
+import org.eclipse.core.commands.operations.IUndoableOperation;
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchMessages;
+
+/**
+ * <p>
+ * An operation approver that prompts the user to see if a non-local undo should
+ * proceed inside an editor. A non-local undo is detected when an operation
+ * being undone or redone affects elements other than those described by the
+ * editor itself. Clients can optionally specify a class, the preferred
+ * comparison class, that should be used when comparing objects affected by the
+ * editor with objects affected by an undo or redo operation. Comparisons
+ * between the affected objects inside the editor and those described by the
+ * operation will first be done by simply performing an equality check, using
+ * {@link java.lang.Object#equals(java.lang.Object)}. If an object described by
+ * an operation is not equal to one of the objects affected by the editor, and
+ * if it is not an instance of the preferred comparison class, but is an
+ * instance of {@link org.eclipse.core.runtime.IAdaptable}, then the operation
+ * approver will also attempt to retrieve an adapter on that object for the
+ * preferred comparison class and perform a second equality check using the
+ * adapter.
+ * </p>
+ * <p>
+ * This class may be instantiated by clients.
+ * </p>
+ *
+ *
+ * @since 3.1
+ */
+public final class NonLocalUndoUserApprover implements IOperationApprover {
+
+	private IUndoContext context;
+
+	private IEditorPart part;
+
+	private Object[] elements;
+
+	private Class affectedObjectsClass;
+
+	private ArrayList elementsAndAdapters;
+
+	/**
+	 * Create a NonLocalUndoUserApprover associated with the specified editor
+	 * and undo context
+	 *
+	 * @param context
+	 *            the undo context of operations in question.
+	 * @param part
+	 *            the editor part that is displaying the element
+	 * @param affectedObjects
+	 *            the objects that are affected by the editor and considered to
+	 *            be objects local to the editor. The objects are typically
+	 *            instances of the preferredComparisonClass or else provide
+	 *            adapters for the preferredComparisonClass, although this is
+	 *            not required.
+	 * @param preferredComparisonClass
+	 *            the preferred class to be used when comparing the editor's
+	 *            affectedObjects with those provided by the undoable operation
+	 *            using
+	 *            {@link org.eclipse.core.commands.operations.IAdvancedUndoableOperation#getAffectedObjects()}.
+	 *            If the operation's affected objects are not instances of the
+	 *            specified class, but are instances of
+	 *            {@link org.eclipse.core.runtime.IAdaptable}, then an adapter
+	 *            for this class will be requested. The preferredComparisonClass
+	 *            may be <code>null</code>, which indicates that there is no
+	 *            expected class or adapter necessary for the comparison.
+	 */
+	public NonLocalUndoUserApprover(IUndoContext context, IEditorPart part,
+			Object[] affectedObjects, Class preferredComparisonClass) {
+		super();
+		this.context = context;
+		this.part = part;
+		this.affectedObjectsClass = preferredComparisonClass;
+		this.elements = affectedObjects;
+	}
+
+	@Override
+	public IStatus proceedRedoing(IUndoableOperation operation,
+			IOperationHistory history, IAdaptable uiInfo) {
+
+		// return immediately if the operation is not relevant
+		if (!requiresApproval(operation, uiInfo)) {
+			return Status.OK_STATUS;
+		}
+
+		String message = NLS.bind(
+				WorkbenchMessages.get().Operations_nonLocalRedoWarning, operation
+						.getLabel(), part.getEditorInput().getName());
+		return proceedWithOperation(operation, message, WorkbenchMessages.get().Operations_discardRedo, WorkbenchMessages.get().Workbench_redoToolTip);
+	}
+
+	@Override
+	public IStatus proceedUndoing(IUndoableOperation operation,
+			IOperationHistory history, IAdaptable uiInfo) {
+
+		// return immediately if the operation is not relevant
+		if (!requiresApproval(operation, uiInfo)) {
+			return Status.OK_STATUS;
+		}
+
+		String message = NLS.bind(
+				WorkbenchMessages.get().Operations_nonLocalUndoWarning, operation
+						.getLabel(), part.getEditorInput().getName());
+		return proceedWithOperation(operation, message, WorkbenchMessages.get().Operations_discardUndo, WorkbenchMessages.get().Workbench_undoToolTip);
+
+	}
+
+	/*
+	 * Determine whether the operation in question affects elements outside of
+	 * the editor. If this can be determined and it does affect other elements,
+	 * prompt the user as to whether the operation should proceed.
+	 */
+	private IStatus proceedWithOperation(IUndoableOperation operation,
+			final String message, final String discardButton, final String title) {
+
+		// if the operation cannot tell us about its modified elements, there's
+		// nothing we can do.
+		if (!(operation instanceof IAdvancedUndoableOperation)) {
+			return Status.OK_STATUS;
+		}
+
+		// Obtain the operation's affected objects.
+		Object[] modifiedElements = ((IAdvancedUndoableOperation) operation)
+				.getAffectedObjects();
+
+		// Since the operation participates in describing its affected objects,
+		// we assume for the rest of this method that an inability to
+		// determine a match implies that a non-local operation is occurring.
+		// This is a conservative assumption that provides more user prompting.
+
+		boolean local;
+		if (modifiedElements == null) {
+			// The operation could not determine which elements are affected.
+			// Consider the operation non-local.
+			local = false;
+		} else {
+			// The operation answered some array of affected objects. Consider
+			// the operation local until a non-match is found. Note that an
+			// empty
+			// array of affected objects is considered a local change.
+			local = true;
+			for (Object modifiedElement : modifiedElements) {
+				if (!elementsContains(modifiedElement)) {
+					// the modified element is not known by the editor
+					local = false;
+					// one last try - try to adapt the modified element if a
+					// preferred
+					// comparison class has been provided.
+					if (affectedObjectsClass != null) {
+						Object adapter = Adapters.adapt(modifiedElement, affectedObjectsClass);
+						if (adapter != null && elementsContains(adapter)) {
+							local = true;
+						}
+					}
+					// if the element did not match the affected objects, no
+					// need to check any others.
+					if (!local) {
+						break;
+					}
+				}
+			}
+		}
+		if (local) {
+			return Status.OK_STATUS;
+		}
+
+		// The operation affects more than just our element.  Find out if
+		// we should proceed, cancel, or discard the undo.  Must be done in
+		// a syncExec because operation approval notifications may come from
+		// a background thread.
+		final int[] answer = new int[1];
+		PlatformUI.getWorkbench().getDisplay().syncExec(() -> {
+			MessageDialog dialog = new MessageDialog(part.getSite().getShell(), title,
+					null, message, MessageDialog.QUESTION, new String[] { IDialogConstants.get().OK_LABEL, discardButton,
+					IDialogConstants.get().CANCEL_LABEL}, 0); // yes is the default
+		    answer[0] = dialog.open();
+});
+		switch (answer[0]) {
+		case 0:
+			return Status.OK_STATUS;
+		case 1:
+			return IOperationHistory.OPERATION_INVALID_STATUS;
+		default:
+			// Cancel by default to include ESC key and shell close,
+			// which return SWT.DEFAULT, and any other unexpected return codes
+			return Status.CANCEL_STATUS;
+		}
+	}
+
+	/*
+	 * Answer whether this operation is relevant enough to this operation
+	 * approver that it should be examined in detail.
+	 */
+	private boolean requiresApproval(IUndoableOperation operation,
+			IAdaptable uiInfo) {
+		// no approval is required if the operation doesn't have our undo
+		// context
+		if (!(operation.hasContext(context))) {
+			return false;
+		}
+
+		// no approval is required if the operation only has our context
+		if (operation.getContexts().length == 1) {
+			return false;
+		}
+
+		// no approval is required if we can ascertain that the operation did
+		// not originate
+		// in our context.
+		if (uiInfo != null) {
+			IUndoContext originatingContext = Adapters.adapt(uiInfo, IUndoContext.class);
+			if (originatingContext != null
+					&& !(originatingContext.matches(context))) {
+				return false;
+			}
+		}
+
+		return true;
+	}
+
+	/*
+	 * Return whether or not the collection of editor elements plus any of their
+	 * adapters contains the specified object.
+	 */
+	private boolean elementsContains(Object someObject) {
+		if (elements == null) {
+			return false;
+		}
+		if (elementsAndAdapters == null) {
+			// Compute a list of not just the elements, but any adapters they
+			// may provide on the preferred class if they are not instances of
+			// the preferred class. This is done only once.
+			elementsAndAdapters = new ArrayList(elements.length);
+			for (Object element : elements) {
+				elementsAndAdapters.add(element);
+				if (affectedObjectsClass != null
+						&& !affectedObjectsClass.isInstance(element)) {
+					Object adapter = Adapters.adapt(element, affectedObjectsClass);
+					if (adapter != null) {
+						elementsAndAdapters.add(adapter);
+					}
+				}
+			}
+		}
+		for (int i = 0; i < elementsAndAdapters.size(); i++) {
+			if (elementsAndAdapters.get(i).equals(someObject)) {
+				return true;
+			}
+		}
+		return false;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/operations/OperationHistoryActionHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/operations/OperationHistoryActionHandler.java
new file mode 100644
index 0000000..f8354a0
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/operations/OperationHistoryActionHandler.java
@@ -0,0 +1,492 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.operations;
+
+import java.lang.reflect.InvocationTargetException;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.operations.IAdvancedUndoableOperation2;
+import org.eclipse.core.commands.operations.IOperationHistory;
+import org.eclipse.core.commands.operations.IOperationHistoryListener;
+import org.eclipse.core.commands.operations.IUndoContext;
+import org.eclipse.core.commands.operations.IUndoableOperation;
+import org.eclipse.core.commands.operations.OperationHistoryEvent;
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.LegacyActionTools;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IPartListener;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.ActionFactory;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.internal.operations.TimeTriggeredProgressMonitorDialog;
+import org.eclipse.ui.part.MultiPageEditorSite;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+/**
+ * <p>
+ * OperationHistoryActionHandler implements common behavior for the undo and
+ * redo actions. It supports filtering of undo or redo on a particular undo
+ * context. If an undo context is not specified, or there has been no history
+ * available for the specified undo context, then the workbench undo context
+ * will be used.
+ * </p>
+ * <p>
+ * OperationHistoryActionHandler provides an adapter in the info parameter of
+ * the IOperationHistory undo and redo methods that is used to get UI info for
+ * prompting the user during operations or operation approval. Adapters are
+ * provided for org.eclipse.ui.IWorkbenchWindow, org.eclipse.swt.widgets.Shell,
+ * org.eclipse.ui.IWorkbenchPart, org.eclipse.core.commands.IUndoContext, and
+ * org.eclipse.runtime.IProgressMonitor.
+ * </p>
+ * <p>
+ * OperationHistoryActionHandler assumes a linear undo/redo model. When the
+ * handler is run, the operation history is asked to perform the most recent
+ * undo/redo for the handler's undo context. The handler can be configured
+ * (using #setPruneHistory(true)) to flush the operation undo or redo history
+ * for the handler's undo context when there is no valid operation on top of the
+ * history. This avoids keeping a stale history of invalid operations. By
+ * default, pruning does not occur and it is assumed that clients of the
+ * particular undo context are pruning the history when necessary.
+ * </p>
+ *
+ * @since 3.1
+ */
+public abstract class OperationHistoryActionHandler extends Action implements
+		ActionFactory.IWorkbenchAction, IAdaptable {
+
+	private static final int MAX_LABEL_LENGTH = 33;
+
+	private class PartListener implements IPartListener {
+		/**
+		 * @see IPartListener#partActivated(IWorkbenchPart)
+		 */
+		@Override
+		public void partActivated(IWorkbenchPart part) {
+		}
+
+		/**
+		 * @see IPartListener#partBroughtToTop(IWorkbenchPart)
+		 */
+		@Override
+		public void partBroughtToTop(IWorkbenchPart part) {
+		}
+
+		/**
+		 * @see IPartListener#partClosed(IWorkbenchPart)
+		 */
+		@Override
+		public void partClosed(IWorkbenchPart part) {
+			if (site != null && part.equals(site.getPart())) {
+				dispose();
+				// Special case for MultiPageEditorSite
+				// See https://bugs.eclipse.org/bugs/show_bug.cgi?id=103379
+			} else if ((site instanceof MultiPageEditorSite)
+					&& (part.equals(((MultiPageEditorSite) site)
+							.getMultiPageEditor()))) {
+				dispose();
+			}
+		}
+
+		/**
+		 * @see IPartListener#partDeactivated(IWorkbenchPart)
+		 */
+		@Override
+		public void partDeactivated(IWorkbenchPart part) {
+		}
+
+		/**
+		 * @see IPartListener#partOpened(IWorkbenchPart)
+		 */
+		@Override
+		public void partOpened(IWorkbenchPart part) {
+		}
+
+	}
+
+	private class HistoryListener implements IOperationHistoryListener {
+		@Override
+		public void historyNotification(final OperationHistoryEvent event) {
+			IWorkbenchWindow workbenchWindow = getWorkbenchWindow();
+			if (workbenchWindow == null)
+				return;
+
+			Display display = workbenchWindow.getWorkbench().getDisplay();
+			if (display == null)
+				return;
+
+			switch (event.getEventType()) {
+			case OperationHistoryEvent.OPERATION_ADDED:
+			case OperationHistoryEvent.OPERATION_REMOVED:
+			case OperationHistoryEvent.UNDONE:
+			case OperationHistoryEvent.REDONE:
+				if (event.getOperation().hasContext(undoContext)) {
+					display.asyncExec(() -> update());
+				}
+				break;
+			case OperationHistoryEvent.OPERATION_NOT_OK:
+				if (event.getOperation().hasContext(undoContext)) {
+					display.asyncExec(() -> {
+						if (pruning) {
+							IStatus status = event.getStatus();
+							/*
+							 * Prune the history unless we can determine
+							 * that this was a cancelled attempt. See
+							 * https://bugs.eclipse.org/bugs/show_bug.cgi?id=101215
+							 */
+							if (status == null
+									|| status.getSeverity() != IStatus.CANCEL) {
+								flush();
+							}
+							// not all flushes will trigger an update so
+							// force it here
+							update();
+						} else {
+							update();
+						}
+					});
+				}
+				break;
+			case OperationHistoryEvent.OPERATION_CHANGED:
+				if (event.getOperation() == getOperation()) {
+					display.asyncExec(() -> update());
+				}
+				break;
+			}
+		}
+	}
+
+	private boolean pruning = false;
+
+	private IPartListener partListener = new PartListener();
+
+	private IOperationHistoryListener historyListener = new HistoryListener();
+
+	private TimeTriggeredProgressMonitorDialog progressDialog;
+
+	private IUndoContext undoContext = null;
+
+	IWorkbenchPartSite site;
+
+	/**
+	 * Construct an operation history action for the specified workbench window
+	 * with the specified undo context.
+	 *
+	 * @param site -
+	 *            the workbench part site for the action.
+	 * @param context -
+	 *            the undo context to be used
+	 */
+	OperationHistoryActionHandler(IWorkbenchPartSite site, IUndoContext context) {
+		// string will be reset inside action
+		super(""); //$NON-NLS-1$
+		this.site = site;
+		undoContext = context;
+		site.getPage().addPartListener(partListener);
+		getHistory().addOperationHistoryListener(historyListener);
+		// An update must be forced in case the undo limit is 0.
+		// see bug #89707
+		update();
+	}
+
+	@Override
+	public void dispose() {
+
+		IOperationHistory history = getHistory();
+		if (history != null) {
+			history.removeOperationHistoryListener(historyListener);
+		}
+
+		if (isInvalid()) {
+			return;
+		}
+
+		site.getPage().removePartListener(partListener);
+		site = null;
+		progressDialog = null;
+		// We do not flush the history for our undo context because it may be
+		// used elsewhere. It is up to clients to clean up the history
+		// appropriately.
+		// We do null out the context to signify that this handler is no longer
+		// accessing the history.
+		undoContext = null;
+	}
+
+	/*
+	 * Flush the history associated with this action.
+	 */
+	abstract void flush();
+
+	/*
+	 * Return the string describing the command, including the binding for the
+	 * operation label.
+	 */
+	abstract String getCommandString();
+
+	/*
+	 * Return the string describing the command for a tooltip, including the
+	 * binding for the operation label.
+	 */
+	abstract String getTooltipString();
+
+	/*
+	 * Return the simple string describing the command, with no binding to any
+	 * operation.
+	 */
+	abstract String getSimpleCommandString();
+
+	/*
+	 * Return the simple string describing the tooltip, with no binding to any
+	 * operation.
+	 */
+	abstract String getSimpleTooltipString();
+
+	/*
+	 * Return the operation history we are using.
+	 */
+	IOperationHistory getHistory() {
+		if (PlatformUI.getWorkbench() == null) {
+			return null;
+		}
+
+		return PlatformUI.getWorkbench().getOperationSupport()
+				.getOperationHistory();
+	}
+
+	/*
+	 * Return the current operation.
+	 */
+	abstract IUndoableOperation getOperation();
+
+	@Override
+	public final void run() {
+		if (isInvalid()) {
+			return;
+		}
+
+		Shell parent = getWorkbenchWindow().getShell();
+		progressDialog = new TimeTriggeredProgressMonitorDialog(parent,
+				getWorkbenchWindow().getWorkbench().getProgressService()
+						.getLongOperationTime());
+		IRunnableWithProgress runnable = pm -> {
+try {
+		runCommand(pm);
+} catch (ExecutionException e) {
+		if (pruning) {
+			flush();
+		}
+		throw new InvocationTargetException(e);
+}
+};
+		try {
+			boolean runInBackground = false;
+			if (getOperation() instanceof IAdvancedUndoableOperation2) {
+				runInBackground = ((IAdvancedUndoableOperation2) getOperation())
+						.runInBackground();
+			}
+			progressDialog.run(runInBackground, true, runnable);
+		} catch (InvocationTargetException e) {
+			Throwable t = e.getTargetException();
+			if (t == null) {
+				reportException(e);
+			} else {
+				reportException(t);
+			}
+		} catch (InterruptedException e) {
+			// Operation was cancelled and acknowledged by runnable with this
+			// exception.
+			// Do nothing.
+		} catch (OperationCanceledException e) {
+			// the operation was cancelled. Do nothing.
+		} finally {
+			progressDialog = null;
+		}
+	}
+
+	abstract IStatus runCommand(IProgressMonitor pm) throws ExecutionException;
+
+	@SuppressWarnings("unchecked")
+	@Override
+	public <T> T getAdapter(Class<T> adapter) {
+		if (adapter.equals(IUndoContext.class)) {
+			return (T) undoContext;
+		}
+		if (adapter.equals(IProgressMonitor.class)) {
+			if (progressDialog != null) {
+				return (T) progressDialog.getProgressMonitor();
+			}
+		}
+		if (site != null) {
+			if (adapter.equals(Shell.class)) {
+				return (T) getWorkbenchWindow().getShell();
+			}
+			if (adapter.equals(IWorkbenchWindow.class)) {
+				return (T) getWorkbenchWindow();
+			}
+			if (adapter.equals(IWorkbenchPart.class)) {
+				return (T) site.getPart();
+			}
+			// Refer all other requests to the part itself.
+			// See https://bugs.eclipse.org/bugs/show_bug.cgi?id=108144
+			IWorkbenchPart part = site.getPart();
+			if (part != null) {
+				return Adapters.adapt(part, adapter);
+			}
+		}
+		return null;
+	}
+
+	/*
+	 * Return the workbench window for this action handler
+	 */
+	private IWorkbenchWindow getWorkbenchWindow() {
+		if (site != null) {
+			return site.getWorkbenchWindow();
+		}
+		return null;
+	}
+
+	/**
+	 * The undo and redo subclasses should implement this.
+	 *
+	 * @return - a boolean indicating enablement state
+	 */
+	abstract boolean shouldBeEnabled();
+
+	/**
+	 * Set the context shown by the handler. Normally the context is set up when
+	 * the action handler is created, but the context can also be changed
+	 * dynamically.
+	 *
+	 * @param context
+	 *            the context to be used for the undo history
+	 */
+	public void setContext(IUndoContext context) {
+		// optimization - do nothing if there was no real change
+		if (context == undoContext) {
+			return;
+		}
+		undoContext = context;
+		update();
+	}
+
+	/**
+	 * Specify whether the action handler should actively prune the operation
+	 * history when invalid operations are encountered. The default value is
+	 * <code>false</code>.
+	 *
+	 * @param prune
+	 *            <code>true</code> if the history should be pruned by the
+	 *            handler, and <code>false</code> if it should not.
+	 *
+	 */
+	public void setPruneHistory(boolean prune) {
+		pruning = prune;
+	}
+
+	/**
+	 * Update enabling and labels according to the current status of the
+	 * operation history.
+	 */
+	public void update() {
+		if (isInvalid()) {
+			return;
+		}
+
+		boolean enabled = shouldBeEnabled();
+		String text, tooltipText;
+		if (enabled) {
+			tooltipText = NLS.bind(getTooltipString(), getOperation()
+					.getLabel());
+			text = NLS.bind(getCommandString(),
+					LegacyActionTools.escapeMnemonics(shortenText(getOperation().getLabel()))) + '@';
+		} else {
+			tooltipText = NLS.bind(
+					WorkbenchMessages.get().Operations_undoRedoCommandDisabled,
+					getSimpleTooltipString());
+			text = getSimpleCommandString();
+			/*
+			 * if there is nothing to do and we are pruning the history, flush
+			 * the history of this context.
+			 */
+			if (undoContext != null && pruning) {
+				flush();
+			}
+		}
+		setText(text);
+		setToolTipText(tooltipText);
+		setEnabled(enabled);
+	}
+
+	/*
+	 * Shorten the specified command label if it is too long
+	 */
+	private String shortenText(String message) {
+		int length = message.length();
+		if (length > MAX_LABEL_LENGTH) {
+			StringBuffer result = new StringBuffer();
+			int end = MAX_LABEL_LENGTH / 2 - 1;
+			result.append(message.substring(0, end));
+			result.append("..."); //$NON-NLS-1$
+			result.append(message.substring(length - end));
+			return result.toString();
+		}
+		return message;
+	}
+
+	/*
+	 * Report the specified exception to the log and to the user.
+	 */
+	final void reportException(Throwable t) {
+		// get any nested exceptions
+		Throwable nestedException = StatusUtil.getCause(t);
+		Throwable exception = (nestedException == null) ? t : nestedException;
+
+		// Messages
+		String exceptionMessage = exception.getMessage();
+		if (exceptionMessage == null) {
+			exceptionMessage = WorkbenchMessages.get().WorkbenchWindow_exceptionMessage;
+		}
+		IStatus status = StatusUtil.newStatus(WorkbenchPlugin.PI_WORKBENCH,
+				exceptionMessage, exception);
+
+		// Log and show the problem
+		WorkbenchPlugin.log(exceptionMessage, status);
+		StatusUtil.handleStatus(status, StatusManager.SHOW,
+				getWorkbenchWindow().getShell());
+	}
+
+	/*
+	 * Answer true if the receiver is not valid for running commands, accessing
+	 * the history, etc.
+	 */
+	final boolean isInvalid() {
+		return undoContext == null || site == null;
+	}
+
+	/*
+	 * Get the undo context that should be used.
+	 */
+	final IUndoContext getUndoContext() {
+		return undoContext;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/operations/RedoActionHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/operations/RedoActionHandler.java
new file mode 100644
index 0000000..8fbe2ed
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/operations/RedoActionHandler.java
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.operations;
+
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.operations.IUndoContext;
+import org.eclipse.core.commands.operations.IUndoableOperation;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchMessages;
+
+/**
+ * <p>
+ * RedoActionHandler provides common behavior for redoing an operation, as well
+ * as labelling and enabling the menu item.  This class may be instantiated by
+ * clients.
+ * </p>
+ *
+ * @since 3.1
+ */
+public final class RedoActionHandler extends OperationHistoryActionHandler {
+
+	/**
+	 * Construct an action handler that handles the labelling and enabling of
+	 * the redo action for the specified undo context.
+	 *
+	 * @param site
+	 *            the workbench part site that created the action.
+	 * @param context
+	 *            the undo context to be used for redoing.
+	 */
+	public RedoActionHandler(IWorkbenchPartSite site, IUndoContext context) {
+		super(site, context);
+		setImageDescriptor(PlatformUI.getWorkbench().getSharedImages()
+				.getImageDescriptor(ISharedImages.IMG_TOOL_REDO));
+		setDisabledImageDescriptor(PlatformUI.getWorkbench().getSharedImages()
+				.getImageDescriptor(ISharedImages.IMG_TOOL_REDO_DISABLED));
+		setActionDefinitionId(IWorkbenchCommandConstants.EDIT_REDO);
+	}
+
+	@Override
+	void flush() {
+		getHistory().dispose(getUndoContext(), false, true, false);
+	}
+
+	@Override
+	String getCommandString() {
+		return WorkbenchMessages.get().Operations_redoCommand;
+	}
+
+	@Override
+	String getTooltipString() {
+		return WorkbenchMessages.get().Operations_redoTooltipCommand;
+	}
+
+	@Override
+	String getSimpleCommandString() {
+		return WorkbenchMessages.get().Workbench_redo;
+	}
+
+	@Override
+	String getSimpleTooltipString() {
+		return WorkbenchMessages.get().Workbench_redoToolTip;
+	}
+
+
+	@Override
+	IUndoableOperation getOperation() {
+		return getHistory().getRedoOperation(getUndoContext());
+	}
+
+	@Override
+	IStatus runCommand(IProgressMonitor pm) throws ExecutionException {
+		return getHistory().redo(getUndoContext(), pm, this);
+	}
+
+	@Override
+	boolean shouldBeEnabled() {
+		return getHistory().canRedo(getUndoContext());
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/operations/UndoActionHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/operations/UndoActionHandler.java
new file mode 100644
index 0000000..db62745
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/operations/UndoActionHandler.java
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.operations;
+
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.operations.IUndoContext;
+import org.eclipse.core.commands.operations.IUndoableOperation;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchMessages;
+
+
+/**
+ * <p>
+ * UndoActionHandler provides common behavior for performing an undo, as
+ * well as labelling and enabling the undo menu item.  This class may be
+ * instantiated by clients.
+ * </p>
+ *
+ * @since 3.1
+ */
+public final class UndoActionHandler extends OperationHistoryActionHandler {
+
+	/**
+	 * Construct an action handler that handles the labelling and enabling of
+	 * the undo action for the specified undo context.
+	 *
+	 * @param site
+	 *            the workbench part site that created the action.
+	 * @param context
+	 *            the undo context to be used for the undo
+	 */
+	public UndoActionHandler(IWorkbenchPartSite site, IUndoContext context) {
+		super(site, context);
+        setImageDescriptor(PlatformUI.getWorkbench().getSharedImages()
+                .getImageDescriptor(ISharedImages.IMG_TOOL_UNDO));
+        setDisabledImageDescriptor(PlatformUI.getWorkbench().getSharedImages()
+                .getImageDescriptor(ISharedImages.IMG_TOOL_UNDO_DISABLED));
+		setActionDefinitionId(IWorkbenchCommandConstants.EDIT_UNDO);
+	}
+
+	@Override
+	void flush() {
+		getHistory().dispose(getUndoContext(), true, false, false);
+	}
+
+	@Override
+	String getCommandString() {
+		return WorkbenchMessages.get().Operations_undoCommand;
+	}
+
+	@Override
+	String getTooltipString() {
+		return WorkbenchMessages.get().Operations_undoTooltipCommand;
+	}
+
+	@Override
+	String getSimpleCommandString() {
+		return WorkbenchMessages.get().Workbench_undo;
+	}
+
+	@Override
+	String getSimpleTooltipString() {
+		return WorkbenchMessages.get().Workbench_undoToolTip;
+	}
+
+	@Override
+	IUndoableOperation getOperation() {
+		return getHistory().getUndoOperation(getUndoContext());
+
+	}
+
+	@Override
+	IStatus runCommand(IProgressMonitor pm) throws ExecutionException  {
+		return getHistory().undo(getUndoContext(), pm, this);
+	}
+
+	@Override
+	boolean shouldBeEnabled() {
+		return getHistory().canUndo(getUndoContext());
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/operations/UndoRedoActionGroup.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/operations/UndoRedoActionGroup.java
new file mode 100644
index 0000000..63f285e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/operations/UndoRedoActionGroup.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.operations;
+
+import org.eclipse.core.commands.operations.IUndoContext;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.actions.ActionFactory;
+import org.eclipse.ui.actions.ActionGroup;
+
+/**
+ * <p>
+ * UndoRedoActionGroup provides standard undo and redo action handlers for a
+ * workbench part site. It supports filtering of undo or redo on a particular
+ * undo context. The undo context can be optionally pruned, which means the
+ * context will be flushed actively whenever an invalid operation is found on
+ * top of its history. This class may be instantiated by clients.
+ * </p>
+ *
+ * @since 3.1
+ */
+public final class UndoRedoActionGroup extends ActionGroup {
+
+	private UndoActionHandler undoActionHandler;
+
+	private RedoActionHandler redoActionHandler;
+
+	/**
+	 * Construct an undo redo action group for the specified workbench part
+	 * site, using the specified undo context.
+	 *
+	 * @param site
+	 *            the workbench part site that is creating the action group
+	 * @param undoContext
+	 *            the undo context to be used for filtering the operation
+	 *            history
+	 * @param pruneHistory
+	 *            a boolean that indicates whether the history for the specified
+	 *            context should be pruned whenever an invalid operation is
+	 *            encountered.
+	 */
+	public UndoRedoActionGroup(IWorkbenchPartSite site,
+			IUndoContext undoContext, boolean pruneHistory) {
+
+		// create the undo action handler
+		undoActionHandler = new UndoActionHandler(site, undoContext);
+		undoActionHandler.setPruneHistory(pruneHistory);
+
+		// create the redo action handler
+		redoActionHandler = new RedoActionHandler(site, undoContext);
+		redoActionHandler.setPruneHistory(pruneHistory);
+	}
+
+	@Override
+	public void fillActionBars(IActionBars actionBars) {
+		super.fillActionBars(actionBars);
+		if (undoActionHandler != null) {
+			actionBars.setGlobalActionHandler(ActionFactory.UNDO.getId(),
+					undoActionHandler);
+			actionBars.setGlobalActionHandler(ActionFactory.REDO.getId(),
+					redoActionHandler);
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/operations/package.html b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/operations/package.html
new file mode 100644
index 0000000..9bc8a30
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/operations/package.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <meta name="Author" content="IBM">
+   <meta name="GENERATOR" content="Mozilla/4.5 [en] (WinNT; I) [Netscape]">
+   <title>Package-level Javadoc</title>
+</head>
+<body>
+Classes that provide the basic workbench UI support for undo and redo of
+operations. 
+<h2>
+Package Specification</h2>
+This package provides utilities that implement the common function for interacting
+with the workbench operation history.  The <b>workbench operation support</b> provides 
+access to the operation history used by the workbench and a context that should
+be used to identify operations global to the workbench.  The workbench history is used 
+to maintain all undoable operations that occur in the workbench.  Standard action 
+handlers and an associated action group are provided so that any view or editor 
+can easily add undo/redo support that works with the workbench operations history. 
+Specialized <b>operation approvers</b> can be used by clients to get user approval
+for unexpected conditions in the operation history. 
+</body>
+</html>
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/package.html b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/package.html
new file mode 100644
index 0000000..08c8791
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/package.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <meta name="Author" content="IBM">
+   <meta name="GENERATOR" content="Mozilla/4.5 [en] (WinNT; I) [Netscape]">
+   <title>Package-level Javadoc</title>
+</head>
+<body>
+Application programming interfaces for interaction
+with and extension of the Eclipse Platform User Interface.
+<h2>
+Package Specification</h2>
+This package provides application programming interfaces for interaction
+with and extension of the Eclipse Platform User Interface.
+<p>The <b>PlatformUI</b> class provides access to a single <b>workbench</b>.&nbsp;
+A workbench is the root object for the UI and has one or more <b>workbench
+windows</b>.&nbsp; Each workbench window has a collection of <b>workbench
+pages</b>, only one of which is active and visible to the end user.&nbsp;
+Each workbench page has a collection of <b>workbench parts.&nbsp; </b>A
+page's parts are arranged (tiled or stacked) for presentation on the screen.&nbsp;
+Within a page and its parts the user can interact with and modify a model
+(typically resources in a workspace).&nbsp;&nbsp; There are two kinds of
+workbench parts: views and editors.&nbsp; An editor is typically used to
+edit or browse a document or input object.&nbsp; A view is typically used
+to navigate a hierarchy of information (like the workspace), open an editor,
+or display properties for the active editor.
+<p>The platform creates a workbench when the workbench plug-in is activated.&nbsp;
+Since this happens at most once during the life of the running platform,
+there is only one workbench instance. Due to its singular nature, it is
+commonly referred to as <i>the</i> workbench.
+<p>Within a workbench the user will interact with many different resource
+types.&nbsp; Because different tools are required for each, the workbench
+defines a number of extension points which allow for the integration of
+new tools.&nbsp; There are extension points for views, editors, action
+sets, import wizards, export wizards, etc.
+<br>&nbsp;
+</body>
+</html>
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/AbstractMultiEditor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/AbstractMultiEditor.java
new file mode 100644
index 0000000..b663159
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/AbstractMultiEditor.java
@@ -0,0 +1,293 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Nikolay Botev - bug 240651
+ *******************************************************************************/
+
+package org.eclipse.ui.part;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorReference;
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.IPartListener2;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartReference;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.internal.e4.compatibility.E4Util;
+
+/**
+ * A AbstractMultiEditor is a composite of editors.
+ *
+ * This class is intended to be subclassed.
+ *
+ * @since 3.5
+ */
+public abstract class AbstractMultiEditor extends EditorPart {
+
+    private int activeEditorIndex;
+
+    private IEditorPart innerEditors[];
+
+	private IPartListener2 propagationListener;
+
+	/**
+	 * Constructs an editor to contain other editors.
+	 */
+    public AbstractMultiEditor() {
+        super();
+    }
+
+	/**
+	 * Handles a property change notification from a nested editor. The default
+	 * implementation simply forwards the change to listeners on this multi
+	 * editor by calling <code>firePropertyChange</code> with the same property
+	 * id. For example, if the dirty state of a nested editor changes (property
+	 * id <code>ISaveablePart.PROP_DIRTY</code>), this method handles it by
+	 * firing a property change event for <code>ISaveablePart.PROP_DIRTY</code>
+	 * to property listeners on this multi editor.
+	 * <p>
+	 * Subclasses may extend or reimplement this method.
+	 * </p>
+	 *
+	 * @param propId
+	 *            the id of the property that changed
+	 * @since 3.6
+	 */
+	protected void handlePropertyChange(int propId) {
+		firePropertyChange(propId);
+	}
+
+    /*
+     * @see IEditorPart#doSave(IProgressMonitor)
+     */
+    @Override
+	public void doSave(IProgressMonitor monitor) {
+        for (IEditorPart e : innerEditors) {
+            e.doSave(monitor);
+        }
+    }
+
+    /*
+     * @see IEditorPart#doSaveAs()
+     */
+    @Override
+	public void doSaveAs() {
+        //no-op
+    }
+
+    /*
+     * @see IEditorPart#init(IEditorSite, IEditorInput)
+     */
+    @Override
+	public void init(IEditorSite site, IEditorInput input)
+            throws PartInitException {
+        init(site, (MultiEditorInput) input);
+    }
+
+    /**
+     * @param site
+     * @param input
+     * @throws PartInitException
+	 *
+	 * @see IEditorPart#init(IEditorSite, IEditorInput)
+     */
+    public void init(IEditorSite site, MultiEditorInput input)
+            throws PartInitException {
+        setInput(input);
+        setSite(site);
+        setPartName(input.getName());
+        setTitleToolTip(input.getToolTipText());
+        setupEvents();
+    }
+
+    /*
+     * @see IEditorPart#isDirty()
+     */
+    @Override
+	public boolean isDirty() {
+        for (IEditorPart e : innerEditors) {
+            if (e.isDirty()) {
+				return true;
+			}
+        }
+        return false;
+    }
+
+    /*
+     * @see IEditorPart#isSaveAsAllowed()
+     */
+    @Override
+	public boolean isSaveAsAllowed() {
+        return false;
+    }
+
+	/*
+     * @see IWorkbenchPart#setFocus()
+     */
+    @Override
+	public void setFocus() {
+        innerEditors[activeEditorIndex].setFocus();
+    }
+
+    /**
+     * Returns the active inner editor.
+     * @return the active editor
+     */
+    public final IEditorPart getActiveEditor() {
+        return innerEditors[activeEditorIndex];
+    }
+
+    /**
+     * Returns an array with all inner editors.
+     * @return the inner editors
+     */
+    public final IEditorPart[] getInnerEditors() {
+        return innerEditors;
+    }
+
+	/**
+	 * Set the inner editors.
+	 *
+	 * Should not be called by clients.
+	 *
+	 * @param children
+	 *            the inner editors of this multi editor
+	 * @noreference This method is not intended to be referenced by clients.
+	 */
+    public final void setChildren(IEditorPart[] children) {
+        innerEditors = children;
+        activeEditorIndex = 0;
+
+		for (IEditorPart child : children) {
+			child.addPropertyListener( (source, propId) -> handlePropertyChange(propId));
+		}
+
+        innerEditorsCreated();
+    }
+
+	/**
+	 * Called as soon as the inner editors have been created and are available.
+	 */
+	protected abstract void innerEditorsCreated();
+
+    /**
+     * Activates the given nested editor.
+     *
+     * @param part the nested editor
+     * @since 3.0
+     */
+    public void activateEditor(IEditorPart part) {
+        activeEditorIndex = getIndex(part);
+		// IEditorPart e = getActiveEditor();
+		// EditorSite innerSite = (EditorSite) e.getEditorSite();
+		// ((WorkbenchPage) innerSite.getPage()).requestActivation(e);
+		E4Util.unsupported("We need to request an activation of this part"); //$NON-NLS-1$
+    }
+
+    /**
+     * Returns the index of the given nested editor.
+     *
+     * @return the index of the nested editor
+     * @since 3.0
+     */
+    protected int getIndex(IEditorPart editor) {
+        for (int i = 0; i < innerEditors.length; i++) {
+            if (innerEditors[i] == editor) {
+				return i;
+			}
+        }
+        return -1;
+    }
+
+    /**
+     * Set up the AbstractMultiEditor to propagate events like partClosed().
+     *
+     * @since 3.2
+     */
+    private void setupEvents() {
+		propagationListener = new IPartListener2() {
+			@Override
+			public void partActivated(IWorkbenchPartReference partRef) {
+			}
+
+			@Override
+			public void partBroughtToTop(IWorkbenchPartReference partRef) {
+			}
+
+			@Override
+			public void partClosed(IWorkbenchPartReference partRef) {
+				IWorkbenchPart part = partRef.getPart(false);
+				if (part == AbstractMultiEditor.this && innerEditors != null) {
+					// propagate the events
+					E4Util.unsupported("propogate the events needed"); //$NON-NLS-1$
+				}
+			}
+
+			@Override
+			public void partDeactivated(IWorkbenchPartReference partRef) {
+			}
+
+			@Override
+			public void partOpened(IWorkbenchPartReference partRef) {
+				IWorkbenchPart part = partRef.getPart(false);
+				if (part == AbstractMultiEditor.this && innerEditors != null) {
+					// PartService partService = ((WorkbenchPage) getSite()
+					// .getPage()).getPartService();
+					// for (int i = 0; i < innerEditors.length; i++) {
+					// IEditorPart editor = innerEditors[i];
+					// IWorkbenchPartReference innerRef = ((PartSite) editor
+					// .getSite()).getPartReference();
+					// partService.firePartOpened(innerRef);
+					// }
+					// propagate the events
+					E4Util.unsupported("propogate the events needed"); //$NON-NLS-1$
+				}
+			}
+
+			@Override
+			public void partHidden(IWorkbenchPartReference partRef) {
+			}
+
+			@Override
+			public void partVisible(IWorkbenchPartReference partRef) {
+			}
+
+			@Override
+			public void partInputChanged(IWorkbenchPartReference partRef) {
+			}
+		};
+		getSite().getPage().addPartListener(propagationListener);
+    }
+
+    /**
+     * Release the added listener.
+     *
+     * @since 3.2
+     */
+	@Override
+	public void dispose() {
+		getSite().getPage().removePartListener(propagationListener);
+		super.dispose();
+	}
+
+	/**
+	 * This method is called after createPartControl has been executed and
+	 * should return the container for the given inner editor.
+	 *
+	 * @param innerEditorReference
+	 *            a reference to the inner editor that is being created.
+	 * @return the container in which the inner editor's pane and part controls
+	 *         are to be created.
+	 */
+	public abstract Composite getInnerEditorContainer(IEditorReference innerEditorReference);
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/CellEditorActionHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/CellEditorActionHandler.java
new file mode 100644
index 0000000..301f7be
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/CellEditorActionHandler.java
@@ -0,0 +1,813 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2014 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.ui.part;
+
+import java.util.HashMap;
+import java.util.Iterator;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.ActionFactory;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.WorkbenchMessages;
+
+/**
+ * Handles the redirection of the global actions Cut, Copy, Paste,
+ * Delete, Select All, Find, Undo and Redo to either the current
+ * inline cell editor or the part's supplied action handler.
+ * <p>
+ * This class may be instantiated; it is not intended to be subclassed.
+ * </p><p>
+ * Example usage:
+ * <pre>
+ * actionHandler = new CellEditorActionHandler(this.getViewSite().getActionBars());
+ * actionHandler.addCellEditor(textCellEditor1);
+ * actionHandler.addCellEditor(textCellEditor2);
+ * actionHandler.setSelectAllAction(selectAllAction);
+ * </pre>
+ * </p>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class CellEditorActionHandler {
+    private CutActionHandler cellCutAction = new CutActionHandler();
+
+    private CopyActionHandler cellCopyAction = new CopyActionHandler();
+
+    private PasteActionHandler cellPasteAction = new PasteActionHandler();
+
+    private DeleteActionHandler cellDeleteAction = new DeleteActionHandler();
+
+    private SelectAllActionHandler cellSelectAllAction = new SelectAllActionHandler();
+
+    private FindActionHandler cellFindAction = new FindActionHandler();
+
+    private UndoActionHandler cellUndoAction = new UndoActionHandler();
+
+    private RedoActionHandler cellRedoAction = new RedoActionHandler();
+
+    private IAction cutAction;
+
+    private IAction copyAction;
+
+    private IAction pasteAction;
+
+    private IAction deleteAction;
+
+    private IAction selectAllAction;
+
+    private IAction findAction;
+
+    private IAction undoAction;
+
+    private IAction redoAction;
+
+    private IPropertyChangeListener cutActionListener = new ActionEnabledChangeListener(
+            cellCutAction);
+
+    private IPropertyChangeListener copyActionListener = new ActionEnabledChangeListener(
+            cellCopyAction);
+
+    private IPropertyChangeListener pasteActionListener = new ActionEnabledChangeListener(
+            cellPasteAction);
+
+    private IPropertyChangeListener deleteActionListener = new ActionEnabledChangeListener(
+            cellDeleteAction);
+
+    private IPropertyChangeListener selectAllActionListener = new ActionEnabledChangeListener(
+            cellSelectAllAction);
+
+    private IPropertyChangeListener findActionListener = new ActionEnabledChangeListener(
+            cellFindAction);
+
+    private IPropertyChangeListener undoActionListener = new ActionEnabledChangeListener(
+            cellUndoAction);
+
+    private IPropertyChangeListener redoActionListener = new ActionEnabledChangeListener(
+            cellRedoAction);
+
+    private CellEditor activeEditor;
+
+    private IPropertyChangeListener cellListener = new CellChangeListener();
+
+    private Listener controlListener = new ControlListener();
+
+    private HashMap controlToEditor = new HashMap();
+
+    private class ControlListener implements Listener {
+        @Override
+		public void handleEvent(Event event) {
+            switch (event.type) {
+            case SWT.Activate:
+                activeEditor = (CellEditor) controlToEditor.get(event.widget);
+                if (activeEditor != null) {
+					activeEditor.addPropertyChangeListener(cellListener);
+				}
+                updateActionsEnableState();
+                break;
+            case SWT.Deactivate:
+                if (activeEditor != null) {
+					activeEditor.removePropertyChangeListener(cellListener);
+				}
+                activeEditor = null;
+                updateActionsEnableState();
+                break;
+            default:
+                break;
+            }
+        }
+    }
+
+    private class ActionEnabledChangeListener implements
+            IPropertyChangeListener {
+        private IAction actionHandler;
+
+        protected ActionEnabledChangeListener(IAction actionHandler) {
+            super();
+            this.actionHandler = actionHandler;
+        }
+
+        @Override
+		public void propertyChange(PropertyChangeEvent event) {
+            if (activeEditor != null) {
+				return;
+			}
+            if (event.getProperty().equals(IAction.ENABLED)) {
+                Boolean bool = (Boolean) event.getNewValue();
+                actionHandler.setEnabled(bool.booleanValue());
+                return;
+            }
+            // If the underlying action's text has changed, we need to
+            // change the text.  See
+            // https://bugs.eclipse.org/bugs/show_bug.cgi?id=154410
+            if (event.getProperty().equals(IAction.TEXT)) {
+                String text = (String) event.getNewValue();
+                actionHandler.setText(text);
+                return;
+            }
+            if (event.getProperty().equals(IAction.TOOL_TIP_TEXT)) {
+                String text = (String) event.getNewValue();
+                actionHandler.setToolTipText(text);
+                return;
+            }
+        }
+    }
+
+    private class CellChangeListener implements IPropertyChangeListener {
+        @Override
+		public void propertyChange(PropertyChangeEvent event) {
+            if (activeEditor == null) {
+				return;
+			}
+            if (event.getProperty().equals(CellEditor.CUT)) {
+                cellCutAction.setEnabled(activeEditor.isCutEnabled());
+                return;
+            }
+            if (event.getProperty().equals(CellEditor.COPY)) {
+                cellCopyAction.setEnabled(activeEditor.isCopyEnabled());
+                return;
+            }
+            if (event.getProperty().equals(CellEditor.PASTE)) {
+                cellPasteAction.setEnabled(activeEditor.isPasteEnabled());
+                return;
+            }
+            if (event.getProperty().equals(CellEditor.DELETE)) {
+                cellDeleteAction.setEnabled(activeEditor.isDeleteEnabled());
+                return;
+            }
+            if (event.getProperty().equals(CellEditor.SELECT_ALL)) {
+                cellSelectAllAction.setEnabled(activeEditor
+                        .isSelectAllEnabled());
+                return;
+            }
+            if (event.getProperty().equals(CellEditor.FIND)) {
+                cellFindAction.setEnabled(activeEditor.isFindEnabled());
+                return;
+            }
+            if (event.getProperty().equals(CellEditor.UNDO)) {
+                cellUndoAction.setEnabled(activeEditor.isUndoEnabled());
+                return;
+            }
+            if (event.getProperty().equals(CellEditor.REDO)) {
+                cellRedoAction.setEnabled(activeEditor.isRedoEnabled());
+                return;
+            }
+        }
+    }
+
+    private class CutActionHandler extends Action {
+        protected CutActionHandler() {
+            setId("CellEditorCutActionHandler");//$NON-NLS-1$
+            setEnabled(false);
+            PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IWorkbenchHelpContextIds.CELL_CUT_ACTION);
+        }
+
+        @Override
+		public void runWithEvent(Event event) {
+            if (activeEditor != null) {
+                activeEditor.performCut();
+                return;
+            }
+            if (cutAction != null) {
+                cutAction.runWithEvent(event);
+                return;
+            }
+        }
+
+        public void updateEnabledState() {
+            if (activeEditor != null) {
+                setEnabled(activeEditor.isCutEnabled());
+                return;
+            }
+            if (cutAction != null) {
+                setEnabled(cutAction.isEnabled());
+                return;
+            }
+            setEnabled(false);
+        }
+    }
+
+    private class CopyActionHandler extends Action {
+        protected CopyActionHandler() {
+            setId("CellEditorCopyActionHandler");//$NON-NLS-1$
+            setEnabled(false);
+            PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IWorkbenchHelpContextIds.CELL_COPY_ACTION);
+        }
+
+        @Override
+		public void runWithEvent(Event event) {
+            if (activeEditor != null) {
+                activeEditor.performCopy();
+                return;
+            }
+            if (copyAction != null) {
+                copyAction.runWithEvent(event);
+                return;
+            }
+        }
+
+        public void updateEnabledState() {
+            if (activeEditor != null) {
+                setEnabled(activeEditor.isCopyEnabled());
+                return;
+            }
+            if (copyAction != null) {
+                setEnabled(copyAction.isEnabled());
+                return;
+            }
+            setEnabled(false);
+        }
+    }
+
+    private class PasteActionHandler extends Action {
+        protected PasteActionHandler() {
+            setId("CellEditorPasteActionHandler");//$NON-NLS-1$
+            setEnabled(false);
+            PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IWorkbenchHelpContextIds.CELL_PASTE_ACTION);
+        }
+
+        @Override
+		public void runWithEvent(Event event) {
+            if (activeEditor != null) {
+                activeEditor.performPaste();
+                return;
+            }
+            if (pasteAction != null) {
+                pasteAction.runWithEvent(event);
+                return;
+            }
+        }
+
+        public void updateEnabledState() {
+            if (activeEditor != null) {
+                setEnabled(activeEditor.isPasteEnabled());
+                return;
+            }
+            if (pasteAction != null) {
+                setEnabled(pasteAction.isEnabled());
+                return;
+            }
+            setEnabled(false);
+        }
+    }
+
+    private class DeleteActionHandler extends Action {
+        protected DeleteActionHandler() {
+            setId("CellEditorDeleteActionHandler");//$NON-NLS-1$
+            setEnabled(false);
+            PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IWorkbenchHelpContextIds.CELL_DELETE_ACTION);
+        }
+
+        @Override
+		public void runWithEvent(Event event) {
+            if (activeEditor != null) {
+                activeEditor.performDelete();
+                return;
+            }
+            if (deleteAction != null) {
+                deleteAction.runWithEvent(event);
+                return;
+            }
+        }
+
+        public void updateEnabledState() {
+            if (activeEditor != null) {
+                setEnabled(activeEditor.isDeleteEnabled());
+                return;
+            }
+            if (deleteAction != null) {
+                setEnabled(deleteAction.isEnabled());
+                return;
+            }
+            setEnabled(false);
+        }
+    }
+
+    private class SelectAllActionHandler extends Action {
+        protected SelectAllActionHandler() {
+            setId("CellEditorSelectAllActionHandler");//$NON-NLS-1$
+            setEnabled(false);
+            PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IWorkbenchHelpContextIds.CELL_SELECT_ALL_ACTION);
+        }
+
+        @Override
+		public void runWithEvent(Event event) {
+            if (activeEditor != null) {
+                activeEditor.performSelectAll();
+                return;
+            }
+            if (selectAllAction != null) {
+                selectAllAction.runWithEvent(event);
+                return;
+            }
+        }
+
+        public void updateEnabledState() {
+            if (activeEditor != null) {
+                setEnabled(activeEditor.isSelectAllEnabled());
+                return;
+            }
+            if (selectAllAction != null) {
+                setEnabled(selectAllAction.isEnabled());
+                return;
+            }
+            setEnabled(false);
+        }
+    }
+
+    private class FindActionHandler extends Action {
+        protected FindActionHandler() {
+            setId("CellEditorFindActionHandler");//$NON-NLS-1$
+            setEnabled(false);
+            PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IWorkbenchHelpContextIds.CELL_FIND_ACTION);
+        }
+
+        @Override
+		public void runWithEvent(Event event) {
+            if (activeEditor != null) {
+                activeEditor.performFind();
+                return;
+            }
+            if (findAction != null) {
+                findAction.runWithEvent(event);
+                return;
+            }
+        }
+
+        public void updateEnabledState() {
+            if (activeEditor != null) {
+                setEnabled(activeEditor.isFindEnabled());
+                return;
+            }
+            if (findAction != null) {
+                setEnabled(findAction.isEnabled());
+                return;
+            }
+            setEnabled(false);
+        }
+    }
+
+    private class UndoActionHandler extends Action {
+        protected UndoActionHandler() {
+            setId("CellEditorUndoActionHandler");//$NON-NLS-1$
+            setEnabled(false);
+            PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IWorkbenchHelpContextIds.CELL_UNDO_ACTION);
+        }
+
+        @Override
+		public void runWithEvent(Event event) {
+            if (activeEditor != null) {
+                activeEditor.performUndo();
+                return;
+            }
+            if (undoAction != null) {
+                undoAction.runWithEvent(event);
+                return;
+            }
+        }
+
+        public void updateEnabledState() {
+            if (activeEditor != null) {
+                setEnabled(activeEditor.isUndoEnabled());
+                setText(WorkbenchMessages.get().Workbench_undo);
+                setToolTipText(WorkbenchMessages.get().Workbench_undoToolTip);
+                return;
+            }
+            if (undoAction != null) {
+                setEnabled(undoAction.isEnabled());
+                setText(undoAction.getText());
+                setToolTipText(undoAction.getToolTipText());
+                return;
+            }
+            setEnabled(false);
+        }
+    }
+
+    private class RedoActionHandler extends Action {
+        protected RedoActionHandler() {
+            setId("CellEditorRedoActionHandler");//$NON-NLS-1$
+            setEnabled(false);
+            PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IWorkbenchHelpContextIds.CELL_REDO_ACTION);
+        }
+
+        @Override
+		public void runWithEvent(Event event) {
+            if (activeEditor != null) {
+                activeEditor.performRedo();
+                return;
+            }
+            if (redoAction != null) {
+                redoAction.runWithEvent(event);
+                return;
+            }
+        }
+
+        public void updateEnabledState() {
+            if (activeEditor != null) {
+                setEnabled(activeEditor.isRedoEnabled());
+                setText(WorkbenchMessages.get().Workbench_redo);
+                setToolTipText(WorkbenchMessages.get().Workbench_redoToolTip);
+                return;
+            }
+            if (redoAction != null) {
+                setEnabled(redoAction.isEnabled());
+                setText(redoAction.getText());
+                setToolTipText(redoAction.getToolTipText());
+                return;
+            }
+            setEnabled(false);
+        }
+    }
+
+    /**
+     * Creates a <code>CellEditor</code> action handler
+     * for the global Cut, Copy, Paste, Delete, Select All,
+     * Find, Undo, and Redo of the action bar.
+     *
+     * @param actionBar the action bar to register global
+     *    action handlers.
+     */
+    public CellEditorActionHandler(IActionBars actionBar) {
+        super();
+        actionBar.setGlobalActionHandler(ActionFactory.CUT.getId(),
+                cellCutAction);
+        actionBar.setGlobalActionHandler(ActionFactory.COPY.getId(),
+                cellCopyAction);
+        actionBar.setGlobalActionHandler(ActionFactory.PASTE.getId(),
+                cellPasteAction);
+        actionBar.setGlobalActionHandler(ActionFactory.DELETE.getId(),
+                cellDeleteAction);
+        actionBar.setGlobalActionHandler(ActionFactory.SELECT_ALL.getId(),
+                cellSelectAllAction);
+        actionBar.setGlobalActionHandler(ActionFactory.FIND.getId(),
+                cellFindAction);
+        actionBar.setGlobalActionHandler(ActionFactory.UNDO.getId(),
+                cellUndoAction);
+        actionBar.setGlobalActionHandler(ActionFactory.REDO.getId(),
+                cellRedoAction);
+    }
+
+    /**
+     * Adds a <code>CellEditor</code> to the handler so that the
+     * Cut, Copy, Paste, Delete, Select All, Find, Undo, and Redo
+     * actions are redirected to it when active.
+     *
+     * @param editor the <code>CellEditor</code>
+     */
+    public void addCellEditor(CellEditor editor) {
+        if (editor == null) {
+			return;
+		}
+
+        Control control = editor.getControl();
+        Assert.isNotNull(control);
+        controlToEditor.put(control, editor);
+        control.addListener(SWT.Activate, controlListener);
+        control.addListener(SWT.Deactivate, controlListener);
+
+        if (control.isFocusControl()) {
+            activeEditor = editor;
+            editor.addPropertyChangeListener(cellListener);
+            updateActionsEnableState();
+        }
+    }
+
+    /**
+     * Disposes of this action handler
+     */
+    public void dispose() {
+        setCutAction(null);
+        setCopyAction(null);
+        setPasteAction(null);
+        setDeleteAction(null);
+        setSelectAllAction(null);
+        setFindAction(null);
+        setUndoAction(null);
+        setRedoAction(null);
+
+        Iterator itr = controlToEditor.keySet().iterator();
+        while (itr.hasNext()) {
+            Control control = (Control) itr.next();
+            if (!control.isDisposed()) {
+                control.removeListener(SWT.Activate, controlListener);
+                control.removeListener(SWT.Deactivate, controlListener);
+            }
+        }
+        controlToEditor.clear();
+
+        if (activeEditor != null) {
+			activeEditor.removePropertyChangeListener(cellListener);
+		}
+        activeEditor = null;
+
+    }
+
+    /**
+     * Removes a <code>CellEditor</code> from the handler
+     * so that the Cut, Copy, Paste, Delete, Select All, Find
+     * Undo, and Redo actions are no longer redirected to it.
+     *
+     * @param editor the <code>CellEditor</code>
+     */
+    public void removeCellEditor(CellEditor editor) {
+        if (editor == null) {
+			return;
+		}
+
+        if (activeEditor == editor) {
+            activeEditor.removePropertyChangeListener(cellListener);
+            activeEditor = null;
+        }
+
+        Control control = editor.getControl();
+        if (control != null) {
+            controlToEditor.remove(control);
+            if (!control.isDisposed()) {
+                control.removeListener(SWT.Activate, controlListener);
+                control.removeListener(SWT.Deactivate, controlListener);
+            }
+        }
+    }
+
+    /**
+     * Sets the default <code>IAction</code> handler for the Copy
+     * action. This <code>IAction</code> is run only if no active
+     * cell editor control.
+     *
+     * @param action the <code>IAction</code> to run for the
+     *    Copy action, or <code>null</code> if not interested.
+     */
+    public void setCopyAction(IAction action) {
+        if (copyAction == action) {
+			return;
+		}
+
+        if (copyAction != null) {
+			copyAction.removePropertyChangeListener(copyActionListener);
+		}
+
+        copyAction = action;
+
+        if (copyAction != null) {
+			copyAction.addPropertyChangeListener(copyActionListener);
+		}
+
+        cellCopyAction.updateEnabledState();
+    }
+
+    /**
+     * Sets the default <code>IAction</code> handler for the Cut
+     * action. This <code>IAction</code> is run only if no active
+     * cell editor control.
+     *
+     * @param action the <code>IAction</code> to run for the
+     *    Cut action, or <code>null</code> if not interested.
+     */
+    public void setCutAction(IAction action) {
+        if (cutAction == action) {
+			return;
+		}
+
+        if (cutAction != null) {
+			cutAction.removePropertyChangeListener(cutActionListener);
+		}
+
+        cutAction = action;
+
+        if (cutAction != null) {
+			cutAction.addPropertyChangeListener(cutActionListener);
+		}
+
+        cellCutAction.updateEnabledState();
+    }
+
+    /**
+     * Sets the default <code>IAction</code> handler for the Delete
+     * action. This <code>IAction</code> is run only if no active
+     * cell editor control.
+     *
+     * @param action the <code>IAction</code> to run for the
+     *    Delete action, or <code>null</code> if not interested.
+     */
+    public void setDeleteAction(IAction action) {
+        if (deleteAction == action) {
+			return;
+		}
+
+        if (deleteAction != null) {
+			deleteAction.removePropertyChangeListener(deleteActionListener);
+		}
+
+        deleteAction = action;
+
+        if (deleteAction != null) {
+			deleteAction.addPropertyChangeListener(deleteActionListener);
+		}
+
+        cellDeleteAction.updateEnabledState();
+    }
+
+    /**
+     * Sets the default <code>IAction</code> handler for the Find
+     * action. This <code>IAction</code> is run only if no active
+     * cell editor control.
+     *
+     * @param action the <code>IAction</code> to run for the
+     *    Find action, or <code>null</code> if not interested.
+     */
+    public void setFindAction(IAction action) {
+        if (findAction == action) {
+			return;
+		}
+
+        if (findAction != null) {
+			findAction.removePropertyChangeListener(findActionListener);
+		}
+
+        findAction = action;
+
+        if (findAction != null) {
+			findAction.addPropertyChangeListener(findActionListener);
+		}
+
+        cellFindAction.updateEnabledState();
+    }
+
+    /**
+     * Sets the default <code>IAction</code> handler for the Paste
+     * action. This <code>IAction</code> is run only if no active
+     * cell editor control.
+     *
+     * @param action the <code>IAction</code> to run for the
+     *    Paste action, or <code>null</code> if not interested.
+     */
+    public void setPasteAction(IAction action) {
+        if (pasteAction == action) {
+			return;
+		}
+
+        if (pasteAction != null) {
+			pasteAction.removePropertyChangeListener(pasteActionListener);
+		}
+
+        pasteAction = action;
+
+        if (pasteAction != null) {
+			pasteAction.addPropertyChangeListener(pasteActionListener);
+		}
+
+        cellPasteAction.updateEnabledState();
+    }
+
+    /**
+     * Sets the default <code>IAction</code> handler for the Redo
+     * action. This <code>IAction</code> is run only if no active
+     * cell editor control.
+     *
+     * @param action the <code>IAction</code> to run for the
+     *    Redo action, or <code>null</code> if not interested.
+     */
+    public void setRedoAction(IAction action) {
+        if (redoAction == action) {
+			return;
+		}
+
+        if (redoAction != null) {
+			redoAction.removePropertyChangeListener(redoActionListener);
+		}
+
+        redoAction = action;
+
+        if (redoAction != null) {
+			redoAction.addPropertyChangeListener(redoActionListener);
+		}
+
+        cellRedoAction.updateEnabledState();
+    }
+
+    /**
+     * Sets the default <code>IAction</code> handler for the Select All
+     * action. This <code>IAction</code> is run only if no active
+     * cell editor control.
+     *
+     * @param action the <code>IAction</code> to run for the
+     *    Select All action, or <code>null</code> if not interested.
+     */
+    public void setSelectAllAction(IAction action) {
+        if (selectAllAction == action) {
+			return;
+		}
+
+        if (selectAllAction != null) {
+			selectAllAction
+                    .removePropertyChangeListener(selectAllActionListener);
+		}
+
+        selectAllAction = action;
+
+        if (selectAllAction != null) {
+			selectAllAction.addPropertyChangeListener(selectAllActionListener);
+		}
+
+        cellSelectAllAction.updateEnabledState();
+    }
+
+    /**
+     * Sets the default <code>IAction</code> handler for the Undo
+     * action. This <code>IAction</code> is run only if no active
+     * cell editor control.
+     *
+     * @param action the <code>IAction</code> to run for the
+     *    Undo action, or <code>null</code> if not interested.
+     */
+    public void setUndoAction(IAction action) {
+        if (undoAction == action) {
+			return;
+		}
+
+        if (undoAction != null) {
+			undoAction.removePropertyChangeListener(undoActionListener);
+		}
+
+        undoAction = action;
+
+        if (undoAction != null) {
+			undoAction.addPropertyChangeListener(undoActionListener);
+		}
+
+        cellUndoAction.updateEnabledState();
+    }
+
+    /**
+     * Updates the enable state of the Cut, Copy,
+     * Paste, Delete, Select All, Find, Undo, and
+     * Redo action handlers
+     */
+    private void updateActionsEnableState() {
+        cellCutAction.updateEnabledState();
+        cellCopyAction.updateEnabledState();
+        cellPasteAction.updateEnabledState();
+        cellDeleteAction.updateEnabledState();
+        cellSelectAllAction.updateEnabledState();
+        cellFindAction.updateEnabledState();
+        cellUndoAction.updateEnabledState();
+        cellRedoAction.updateEnabledState();
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/CoolItemGroupMarker.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/CoolItemGroupMarker.java
new file mode 100644
index 0000000..522a228
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/CoolItemGroupMarker.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.part;
+
+import org.eclipse.jface.action.GroupMarker;
+
+/**
+ * A group marker used by EditorActionBars to delineate CoolItem groups.
+ * Use this marker when contributing to the ToolBar for the EditorActionBar.
+ * <p>
+ * This class may be instantiated; it is not intended to be subclassed.
+ * </p>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class CoolItemGroupMarker extends GroupMarker {
+    /**
+     * Create a new group marker with the given name.
+     * The group name must not be <code>null</code> or the empty string.
+     * The group name is also used as the item id.
+     *
+     * Note that CoolItemGroupMarkers must have a group name and the name must
+     * be unique.
+     *
+     * @param groupName the name of the group
+     */
+    public CoolItemGroupMarker(String groupName) {
+        super(groupName);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/DrillDownAdapter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/DrillDownAdapter.java
new file mode 100644
index 0000000..363650f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/DrillDownAdapter.java
@@ -0,0 +1,343 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.part;
+
+import java.util.Arrays;
+import java.util.List;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchImages;
+import org.eclipse.ui.internal.WorkbenchMessages;
+
+/**
+ * Implements a simple web style navigation metaphor for a <code>TreeViewer</code>.
+ * Home, back, and "drill into" functions are supported for the viewer,
+ * <p>
+ * To use the <code>DrillDownAdapter</code> ..
+ * </p>
+ * <ul>
+ * <li>Create an instance of <code>TreeViewer</code>. </li>
+ * <li>Create a <code>DrillDownAdapter</code> for the viewer. </li>
+ * <li>Create a container for your viewer with a toolbar or a popup menu.
+ *		Add actions for "goBack", "goHome", and "goInto" to either one by calling
+ *		</code>addNavigationActions</code> with the popup menu or toolbar.</li>
+ * </ol>
+ * <p>
+ * If the input for the underlying viewer is changed by something other than the
+ * adapter the <code>reset</code> method should be called.  This will clear
+ * the drill stack and update the navigation buttons to reflect the new
+ * state of the underlying viewer.
+ * </p>
+ * </p>
+ */
+public class DrillDownAdapter implements ISelectionChangedListener {
+    private TreeViewer fChildTree;
+
+    private DrillStack fDrillStack;
+
+    private Action homeAction;
+
+    private Action backAction;
+
+    private Action forwardAction;
+
+    /**
+     * Allocates a new DrillDownTreePart.
+     *
+     * @param tree the target tree for refocusing
+     */
+    public DrillDownAdapter(TreeViewer tree) {
+        fDrillStack = new DrillStack();
+        fChildTree = tree;
+    }
+
+    /**
+     * Adds actions for "go back", "go home", and "go into" to a menu manager.
+     *
+     * @param manager is the target manager to update
+     */
+    public void addNavigationActions(IMenuManager manager) {
+        createActions();
+        manager.add(homeAction);
+        manager.add(backAction);
+        manager.add(forwardAction);
+        updateNavigationButtons();
+    }
+
+    /**
+     * Adds actions for "go back", "go home", and "go into" to a tool bar manager.
+     *
+     * @param toolBar is the target manager to update
+     */
+    public void addNavigationActions(IToolBarManager toolBar) {
+        createActions();
+        toolBar.add(homeAction);
+        toolBar.add(backAction);
+        toolBar.add(forwardAction);
+        updateNavigationButtons();
+    }
+
+    /**
+     * Returns whether expansion is possible for the current selection.  This
+     * will only be true if it has children.
+     *
+     * @param element the object to test for expansion
+     * @return <code>true</code> if expansion is possible; otherwise
+     *		return <code>false</code
+     */
+    public boolean canExpand(Object element) {
+        return fChildTree.isExpandable(element);
+    }
+
+    /**
+     * Returns whether "go back" is possible for child tree.  This is only possible
+     * if the client has performed one or more drilling operations.
+     *
+     * @return <code>true</code> if "go back" is possible; <code>false</code> otherwise
+     */
+    public boolean canGoBack() {
+        return fDrillStack.canGoBack();
+    }
+
+    /**
+     * Returns whether "go home" is possible for child tree.  This is only possible
+     * if the client has performed one or more drilling operations.
+     *
+     * @return <code>true</code> if "go home" is possible; <code>false</code> otherwise
+     */
+    public boolean canGoHome() {
+        return fDrillStack.canGoHome();
+    }
+
+    /**
+     * Returns whether "go into" is possible for child tree.  This is only possible
+     * if the current selection in the client has one item and it has children.
+     *
+     * @return <code>true</code> if "go into" is possible; <code>false</code> otherwise
+     */
+    public boolean canGoInto() {
+		IStructuredSelection oSelection = fChildTree.getStructuredSelection();
+        if (oSelection == null || oSelection.size() != 1) {
+			return false;
+		}
+        Object anElement = oSelection.getFirstElement();
+        return canExpand(anElement);
+    }
+
+    /**
+     * Create the actions for navigation.
+     *
+     */
+    private void createActions() {
+        // Only do this once.
+        if (homeAction != null) {
+			return;
+		}
+
+        // Home.
+        homeAction = new Action(WorkbenchMessages.get().GoHome_text) {
+            @Override
+			public void run() {
+                goHome();
+            }
+        };
+        homeAction
+                .setToolTipText(WorkbenchMessages.get().GoHome_toolTip);
+        homeAction
+                .setImageDescriptor(WorkbenchImages
+                        .getImageDescriptor(ISharedImages.IMG_ETOOL_HOME_NAV));
+
+        // Back.
+        ISharedImages images = PlatformUI.getWorkbench().getSharedImages();
+        backAction = new Action(WorkbenchMessages.get().GoBack_text) {
+            @Override
+			public void run() {
+                goBack();
+            }
+        };
+        backAction
+                .setToolTipText(WorkbenchMessages.get().GoBack_toolTip);
+        backAction.setImageDescriptor(images
+                .getImageDescriptor(ISharedImages.IMG_TOOL_BACK));
+        backAction.setDisabledImageDescriptor(images
+                .getImageDescriptor(ISharedImages.IMG_TOOL_BACK_DISABLED));
+
+        // Forward.
+        forwardAction = new Action(WorkbenchMessages.get().GoInto_text) {
+            @Override
+			public void run() {
+                goInto();
+            }
+        };
+        forwardAction.setToolTipText(WorkbenchMessages.get().GoInto_toolTip);
+        forwardAction.setImageDescriptor(images
+                .getImageDescriptor(ISharedImages.IMG_TOOL_FORWARD));
+        forwardAction.setDisabledImageDescriptor(images
+                .getImageDescriptor(ISharedImages.IMG_TOOL_FORWARD_DISABLED));
+
+        // Update the buttons when a selection change occurs.
+        fChildTree.addSelectionChangedListener(this);
+        updateNavigationButtons();
+    }
+
+    /**
+     * Expands the given items in the tree.  The list of items passed should be
+     * derived by calling <code>getExpanded</code>.
+     *
+     * @param items is a list of items within the tree which should be expanded
+     */
+    private void expand(List items) {
+        fChildTree.setExpandedElements(items.toArray());
+    }
+
+    /**
+     * Returns a list of elements corresponding to expanded nodes in
+     * child tree.
+     *
+     * @return a list of expandd elements
+     */
+    private List getExpanded() {
+        return Arrays.asList(fChildTree.getExpandedElements());
+    }
+
+    /**
+     * Reverts the input for the tree back to the state when <code>goInto</code>
+     * was last called.
+     * <p>
+     * A frame is removed from the drill stack.  Then that frame is used to reset the
+     * input and expansion state for the child tree.
+     * </p>
+     */
+    public void goBack() {
+        Object currentInput = fChildTree.getInput();
+        DrillFrame oFrame = fDrillStack.goBack();
+        Object input = oFrame.getElement();
+        fChildTree.setInput(input);
+        expand(oFrame.getExpansion());
+        // if there was a selection, it should have been preserved,
+        // but if not, select the element that was drilled into
+        if (fChildTree.getSelection().isEmpty()) {
+			fChildTree
+                    .setSelection(new StructuredSelection(currentInput), true);
+		}
+        updateNavigationButtons();
+    }
+
+    /**
+     * Reverts the input for the tree back to the state when the adapter was
+     * created.
+     * <p>
+     * All of the frames are removed from the drill stack.  Then the oldest frame is
+     * used to reset the input and expansion state for the child tree.
+     * </p>
+     */
+    public void goHome() {
+        Object currentInput = fChildTree.getInput();
+        DrillFrame oFrame = fDrillStack.goHome();
+        Object input = oFrame.getElement();
+        fChildTree.setInput(input);
+        expand(oFrame.getExpansion());
+        // if there was a selection, it should have been preserved,
+        // but if not, select the element that was last drilled into
+        if (fChildTree.getSelection().isEmpty()) {
+			fChildTree
+                    .setSelection(new StructuredSelection(currentInput), true);
+		}
+        updateNavigationButtons();
+    }
+
+    /**
+     * Sets the input for the tree to the current selection.
+     * <p>
+     * The current input and expansion state are saved in a frame and added to the
+     * drill stack.  Then the input for the tree is changed to be the current selection.
+     * The expansion state for the tree is maintained during the operation.
+     * </p><p>
+     * On return the client may revert back to the previous state by invoking
+     * <code>goBack</code> or <code>goHome</code>.
+     * </p>
+     */
+    public void goInto() {
+		IStructuredSelection sel = fChildTree.getStructuredSelection();
+        Object element = sel.getFirstElement();
+        goInto(element);
+    }
+
+    /**
+     * Sets the input for the tree to a particular item in the tree.
+     * <p>
+     * The current input and expansion state are saved in a frame and added to the
+     * drill stack.  Then the input for the tree is changed to be <code>newInput</code>.
+     * The expansion state for the tree is maintained during the operation.
+     * </p><p>
+     * On return the client may revert back to the previous state by invoking
+     * <code>goBack</code> or <code>goHome</code>.
+     * </p>
+     *
+     * @param newInput the new input element
+     */
+    public void goInto(Object newInput) {
+        // If we can drill ..
+        if (canExpand(newInput)) {
+            // Save the old state.
+            Object oldInput = fChildTree.getInput();
+            List expandedList = getExpanded();
+            fDrillStack.add(new DrillFrame(oldInput, "null", expandedList));//$NON-NLS-1$
+
+            // Install the new state.
+            fChildTree.setInput(newInput);
+            expand(expandedList);
+            updateNavigationButtons();
+        }
+    }
+
+    /**
+     * Resets the drill down adapter.
+     * <p>
+     * This method is typically called when the input for the underlying view
+     * is reset by something other than the adapter.
+     * On return the drill stack has been cleared and the navigation buttons
+     * reflect the new state of the underlying viewer.
+     * </p>
+     */
+    public void reset() {
+        fDrillStack.reset();
+        updateNavigationButtons();
+    }
+
+    /**
+     * Updates the navigation buttons when a selection change occurs
+     * in the tree.
+     */
+    @Override
+	public void selectionChanged(SelectionChangedEvent event) {
+        updateNavigationButtons();
+    }
+
+    /**
+     * Updates the enabled state for each navigation button.
+     */
+    protected void updateNavigationButtons() {
+        if (homeAction != null) {
+            homeAction.setEnabled(canGoHome());
+            backAction.setEnabled(canGoBack());
+            forwardAction.setEnabled(canGoInto());
+        }
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/DrillDownComposite.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/DrillDownComposite.java
new file mode 100644
index 0000000..c301404
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/DrillDownComposite.java
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.part;
+
+import org.eclipse.jface.action.ToolBarManager;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.ToolBar;
+
+/**
+ * Class <code>DrillDownComposite</code> implements a simple web
+ * style navigation metaphor.  Home, back, and "drill into" buttons are
+ * added to a tree viewer for easier navigation.
+ * <p>
+ * To use the DrillDownComposite..
+ * </p>
+ * <ul>
+ * <li>Create an instance of <code>DrillDownComposite</code>.</li>
+ * <li>Create a tree viewer.  </li>
+ * <li>Pass the second tree viewer into the composite by
+ *   calling <code>setChildTree</code>.</li>
+ * </ol>
+ */
+public class DrillDownComposite extends Composite {
+    private ToolBarManager toolBarMgr;
+
+    private TreeViewer fChildTree;
+
+    private DrillDownAdapter adapter;
+
+    /**
+     * Constructs a new DrillDownTreeViewer.
+     *
+     * @param parent the parent composite for this control
+     * @param style the SWT style for this control
+     */
+    public DrillDownComposite(Composite parent, int style) {
+        super(parent, style);
+        createNavigationButtons();
+    }
+
+    /**
+     * Creates the navigation buttons for this viewer.
+     */
+    protected void createNavigationButtons() {
+        GridData gid;
+        GridLayout layout;
+
+        // Define layout.
+        layout = new GridLayout();
+        layout.marginHeight = layout.marginWidth = layout.horizontalSpacing = layout.verticalSpacing = 0;
+        setLayout(layout);
+
+        // Create a toolbar.
+        toolBarMgr = new ToolBarManager(SWT.FLAT);
+        ToolBar toolBar = toolBarMgr.createControl(this);
+        gid = new GridData();
+        gid.horizontalAlignment = GridData.FILL;
+        gid.verticalAlignment = GridData.BEGINNING;
+        toolBar.setLayoutData(gid);
+    }
+
+    /**
+     * Sets the child viewer.  This method should only be called once, after the
+     * viewer has been created.
+     *
+     * @param aViewer the new child viewer
+     */
+    public void setChildTree(TreeViewer aViewer) {
+        // Save viewer.
+        fChildTree = aViewer;
+
+        // Create adapter.
+        adapter = new DrillDownAdapter(fChildTree);
+        adapter.addNavigationActions(toolBarMgr);
+        toolBarMgr.update(true);
+
+        // Set tree layout.
+        fChildTree.getTree().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+        layout();
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/DrillFrame.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/DrillFrame.java
new file mode 100644
index 0000000..cac7ed7
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/DrillFrame.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.part;
+
+import java.util.List;
+
+/* A <code>DrillFrame</code> is used to record the input element and
+ * selection state for one frame in a <code>DrillDownTreeViewer</code>.
+ * This class is not intended for use beyond the package.
+ */
+
+/* package */class DrillFrame {
+    Object fElement;
+
+    Object fPropertyName;
+
+    List fExpansion = null;
+
+    /**
+     * Allocates a new DrillFrame.
+     *
+     * @param oElement the tree input element
+     * @param strPropertyName the visible tree property
+     * @param vExpansion the current expansion state of the tree
+     */
+    public DrillFrame(Object oElement, Object strPropertyName, List vExpansion) {
+        fElement = oElement;
+        fPropertyName = strPropertyName;
+        fExpansion = vExpansion;
+    }
+
+    /**
+     * Compares two Objects for equality.
+     * <p>
+     *
+     * @param   obj   the reference object with which to compare.
+     * @return  <code>true</code> if this object is the same as the obj
+     *          argument; <code>false</code> otherwise.
+     */
+    @Override
+	public boolean equals(Object obj) {
+        // Compare handles.
+        if (this == obj) {
+			return true;
+		}
+
+        // Compare class.
+        if (!(obj instanceof DrillFrame)) {
+			return false;
+		}
+
+        // Compare contents.
+        DrillFrame oOther = (DrillFrame) obj;
+        return ((fElement == oOther.fElement) && (fPropertyName
+                .equals(oOther.fPropertyName)));
+    }
+
+    /**
+     * Returns the input element.
+     *
+     * @return the input element
+     */
+    public Object getElement() {
+        return fElement;
+    }
+
+    /**
+     * Returns the expansion state for a tree.
+     *
+     * @return the expansion state for a tree
+     */
+    public List getExpansion() {
+        return fExpansion;
+    }
+
+    /**
+     * Returns the property name.
+     *
+     * @return the property name
+     */
+    public Object getPropertyName() {
+        return fPropertyName;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/DrillStack.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/DrillStack.java
new file mode 100644
index 0000000..19511e0
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/DrillStack.java
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.part;
+
+import java.util.Stack;
+
+/*
+ * A <code>DrillStack</code> manages a stack of DrillFrames.
+ * This class is not intended for use beyond the package.
+ */
+
+/* package */class DrillStack {
+    Stack fStack = null;
+
+    /**
+     * Allocates a new DrillStack.
+     */
+    public DrillStack() {
+        reset();
+    }
+
+    /**
+     * Adds a drill frame to the stack.
+     *
+     * @param oRecord the new drill frame
+     */
+    public DrillFrame add(DrillFrame oRecord) {
+        fStack.push(oRecord);
+        return oRecord;
+    }
+
+    /**
+     * Returns true if backward navigation is possible.  This is only true
+     * if the stack size is greater than 0.
+     *
+     * @return true if backward navigation is possible
+     */
+    public boolean canGoBack() {
+        return (fStack.size() > 0);
+    }
+
+    /**
+     * Returns true if "go home" is possible.  This is only true
+     * if the stack size is greater than 0.
+     *
+     * @return true if "go home" is possible
+     */
+    public boolean canGoHome() {
+        return (fStack.size() > 0);
+    }
+
+    /**
+     * Navigate backwards one record.
+     */
+    public DrillFrame goBack() {
+        DrillFrame aFrame = (DrillFrame) fStack.pop();
+        return aFrame;
+    }
+
+    /**
+     * Navigate to the home record.
+     */
+    public DrillFrame goHome() {
+        DrillFrame aFrame = (DrillFrame) fStack.elementAt(0);
+        reset();
+        return aFrame;
+    }
+
+    /**
+     * Clears the navigation stack.
+     */
+    public void reset() {
+        fStack = new Stack();
+    }
+
+    /**
+     * Returns the stack size.
+     *
+     * @return the stack size
+     */
+    public int size() {
+        return fStack.size();
+    }
+
+    /**
+     * Returns the top element on the stack.
+     *
+     * @return the top element on the stack
+     */
+    public DrillFrame top() {
+        return (DrillFrame) fStack.peek();
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/EditorActionBarContributor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/EditorActionBarContributor.java
new file mode 100644
index 0000000..65ba958
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/EditorActionBarContributor.java
@@ -0,0 +1,192 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.part;
+
+import org.eclipse.jface.action.ICoolBarManager;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.IStatusLineManager;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IActionBars2;
+import org.eclipse.ui.IEditorActionBarContributor;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchPage;
+
+/**
+ * Standard implementation of <code>IEditorActionBarContributor</code>.
+ * <p>
+ * If instantiated and used as-is, nothing is contribututed. Clients should
+ * subclass in order to contribute to some or all of the action bars.
+ * <p>
+ * Subclasses may reimplement the following methods:
+ * <ul>
+ *   <li><code>contributeToMenu</code> - reimplement to contribute to menu</li>
+ *   <li><code>contributeToToolBar</code> - reimplement to contribute to tool
+ *     bar</li>
+ *   <li><code>contributeToStatusLine</code> - reimplement to contribute to
+ *     status line</li>
+ *   <li><code>setActiveEditor</code> - reimplement to react to editor changes</li>
+ * </ul>
+ * </p>
+ */
+public class EditorActionBarContributor implements IEditorActionBarContributor {
+    /**
+     * The action bars; <code>null</code> until <code>init</code> is called.
+     */
+    private IActionBars bars;
+
+    /**
+     * The workbench page; <code>null</code> until <code>init</code> is called.
+     */
+    private IWorkbenchPage page;
+
+    /**
+     * Creates an empty editor action bar contributor. The action bars are
+     * furnished later via the <code>init</code> method.
+     */
+    public EditorActionBarContributor() {
+    }
+
+    /**
+     * Contributes to the given menu.
+     * <p>
+     * The <code>EditorActionBarContributor</code> implementation of this method
+     * does nothing. Subclasses may reimplement to add to the menu portion of this
+     * contribution.
+     * </p>
+     *
+     * @param menuManager the manager that controls the menu
+     */
+    public void contributeToMenu(IMenuManager menuManager) {
+    }
+
+    /**
+     * Contributes to the given status line.
+     * <p>
+     * The <code>EditorActionBarContributor</code> implementation of this method
+     * does nothing. Subclasses may reimplement to add to the status line portion of
+     * this contribution.
+     * </p>
+     *
+     * @param statusLineManager the manager of the status line
+     */
+    public void contributeToStatusLine(IStatusLineManager statusLineManager) {
+    }
+
+    /**
+     * Contributes to the given tool bar.
+     * <p>
+     * The <code>EditorActionBarContributor</code> implementation of this method
+     * does nothing. Subclasses may reimplement to add to the tool bar portion of
+     * this contribution.
+     * </p>
+     *
+     * @param toolBarManager the manager that controls the workbench tool bar
+     */
+    public void contributeToToolBar(IToolBarManager toolBarManager) {
+    }
+
+    /**
+     * Contributes to the given cool bar.
+     * <p>
+     * The <code>EditorActionBarContributor</code> implementation of this method
+     * does nothing. Subclasses may reimplement to add to the cool bar portion of
+     * this contribution. There can only be contributions from a cool bar or a tool bar.
+     * </p>
+     *
+     * @param coolBarManager the manager that controls the workbench cool bar.
+     *
+     * @since 3.0
+     */
+    public void contributeToCoolBar(ICoolBarManager coolBarManager) {
+    }
+
+    /**
+     * Returns this contributor's action bars.
+     *
+     * @return the action bars
+     */
+    public IActionBars getActionBars() {
+        return bars;
+    }
+
+    /**
+     * Returns this contributor's workbench page.
+     *
+     * @return the workbench page
+     */
+    public IWorkbenchPage getPage() {
+        return page;
+    }
+
+    /**
+     * The <code>EditorActionBarContributor</code> implementation of this
+     * <code>IEditorActionBarContributor</code> method does nothing,
+     * subclasses may override.
+     */
+    @Override
+	public void dispose() {
+    }
+
+    /**
+     * The <code>EditorActionBarContributor</code> implementation of this
+     * <code>IEditorActionBarContributor</code> method remembers the page
+     * then forwards the call to <code>init(IActionBars)</code> for
+     * backward compatibility
+     */
+    @Override
+	public void init(IActionBars bars, IWorkbenchPage page) {
+        this.page = page;
+        init(bars);
+    }
+
+    /**
+     * This method calls:
+     * <ul>
+     *  <li><code>contributeToMenu</code> with <code>bars</code>' menu manager</li>
+     *  <li><code>contributeToToolBar</code> with <code>bars</code>' tool bar
+     *    manager</li>
+     *  <li><code>contributeToCoolBar</code> with <code>bars</code>' cool bar
+     *    manager if <code>IActionBars</code> is of extended type <code>IActionBars2</code> </li>
+     *  <li><code>contributeToStatusLine</code> with <code>bars</code>' status line
+     *    manager</li>
+     * </ul>
+     * The given action bars are also remembered and made accessible via
+     * <code>getActionBars</code>.
+     *
+     * @param bars the action bars
+     */
+    public void init(IActionBars bars) {
+        this.bars = bars;
+        contributeToMenu(bars.getMenuManager());
+        contributeToToolBar(bars.getToolBarManager());
+        if (bars instanceof IActionBars2) {
+            contributeToCoolBar(((IActionBars2) bars).getCoolBarManager());
+        }
+        contributeToStatusLine(bars.getStatusLineManager());
+
+    }
+
+    /**
+     * Sets the active editor for the contributor.
+     * <p>
+     * The <code>EditorActionBarContributor</code> implementation of this method does
+     * nothing. Subclasses may reimplement. This generally entails disconnecting
+     * from the old editor, connecting to the new editor, and updating the actions
+     * to reflect the new editor.
+     * </p>
+     *
+     * @param targetEditor the new target editor
+     */
+    @Override
+	public void setActiveEditor(IEditorPart targetEditor) {
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/EditorInputTransfer.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/EditorInputTransfer.java
new file mode 100644
index 0000000..9f8b88d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/EditorInputTransfer.java
@@ -0,0 +1,269 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.part;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.swt.dnd.ByteArrayTransfer;
+import org.eclipse.swt.dnd.TransferData;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IElementFactory;
+import org.eclipse.ui.IPersistableElement;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.WorkbenchException;
+import org.eclipse.ui.XMLMemento;
+
+/**
+ * The <code>EditorInputTransfer</code> class is used to transfer an
+ * <code>IEditorInput</code> and corresponding editorId from one part to another
+ * in a drag and drop operation.  Only opening of internal editors is supported.
+ * <p>
+ * In every drag and drop operation there is a <code>DragSource</code> and a
+ * <code>DropTarget</code>.  When a drag occurs a <code>Transfer</code> is used
+ * to marshall the drag data from the source into a byte array.  If a drop
+ * occurs another <code>Transfer</code> is used to marshall the byte array into
+ * drop data for the target.
+ * </p>
+ * <p>
+ * This class can be used for a <code>Viewer</code> or an SWT component directly.
+ * A singleton is provided which may be serially reused (see <code>getInstance</code>).
+ * For an implementor of <code>IEditorInput</code> to be supported by
+ * <code>EditorInputTransfer</code>, it must provide a proper implementation of
+ * <code>IEditorInput</code>.<code>getPersistable</code>.  For further details,
+ * consult the <code>org.eclipse.ui.elementFactories</code> extension point.
+ * </p>
+ * <p>
+ * The data for a transfer is represented by the <code>EditorInputData</code>
+ * class, and a convenience method <code>createEditorInputData</code> is
+ * provided.  A <code>DragSource</code>.<code>dragSetData</code> implementation
+ * should set the data to an array of <code>EditorInputData</code>.  In this
+ * way, the dragging of multiple editor inputs is supported.
+ * </p>
+ * <p>
+ * Below is an example of how to set the data for dragging a single editor
+ * input using a <code>EditorInputTransfer</code>.
+ * </p>
+ * <p>
+ * <pre>
+ * public void dragSetData(DragSourceEvent event) {
+ * 		if (EditorInputTransfer.getInstance().isSupportedType(event.dataType)) {
+ *
+ * 			EditorInputTransfer.EditorInputData data =
+ * 				EditorInputTransfer.
+ * 				createEditorInputData(EDITOR_ID, getEditorInput());
+ * 			event.data = new EditorInputTransfer.EditorInputData [] {data};
+ * 		}
+ * }
+ * </pre>
+ * </p>
+ *
+ * @see org.eclipse.jface.viewers.StructuredViewer
+ * @see org.eclipse.swt.dnd.DropTarget
+ * @see org.eclipse.swt.dnd.DragSource
+ * @see org.eclipse.ui.IEditorInput
+ * @see org.eclipse.ui.IPersistableElement
+ * @see org.eclipse.ui.IElementFactory
+ */
+public class EditorInputTransfer extends ByteArrayTransfer {
+
+    /**
+     * Singleton instance.
+     */
+    private static final EditorInputTransfer instance = new EditorInputTransfer();
+
+    // Create a unique ID to make sure that different Eclipse
+    // applications use different "types" of <code>EditorInputTransfer</code>
+    private static final String TYPE_NAME = "editor-input-transfer-format:" + System.currentTimeMillis() + ":" + instance.hashCode(); //$NON-NLS-2$//$NON-NLS-1$
+
+    private static final int TYPEID = registerType(TYPE_NAME);
+
+    public static class EditorInputData {
+
+        public String editorId;
+
+        public IEditorInput input;
+
+        private EditorInputData(String editorId, IEditorInput input) {
+            this.editorId = editorId;
+            this.input = input;
+        }
+    }
+
+    /**
+     * Creates a new transfer object.
+     */
+    private EditorInputTransfer() {
+    }
+
+    /**
+     * Returns the singleton instance.
+     *
+     * @return the singleton instance
+     */
+    public static EditorInputTransfer getInstance() {
+        return instance;
+    }
+
+    @Override
+	protected int[] getTypeIds() {
+        return new int[] { TYPEID };
+    }
+
+    @Override
+	protected String[] getTypeNames() {
+        return new String[] { TYPE_NAME };
+    }
+
+    @Override
+	public void javaToNative(Object data, TransferData transferData) {
+
+        if (!(data instanceof EditorInputData[])) {
+            return;
+        }
+
+        EditorInputData[] editorInputs = (EditorInputData[]) data;
+        /**
+         * The editor input serialization format is:
+         * (int)	number of editor inputs
+         * Then, the following for each editor input:
+         * (String)	editorId
+         * (String)	factoryId
+         * (String)	data used to recreate the IEditorInput
+         */
+
+        int editorInputCount = editorInputs.length;
+
+        try {
+            ByteArrayOutputStream out = new ByteArrayOutputStream();
+            DataOutputStream dataOut = new DataOutputStream(out);
+
+            //write the number of resources
+            dataOut.writeInt(editorInputCount);
+
+            //write each resource
+            for (EditorInputData editorInput : editorInputs) {
+                writeEditorInput(dataOut, editorInput);
+            }
+
+            //cleanup
+            dataOut.close();
+            out.close();
+            byte[] bytes = out.toByteArray();
+            super.javaToNative(bytes, transferData);
+        } catch (IOException e) {
+        }
+    }
+
+    @Override
+	public Object nativeToJava(TransferData transferData) {
+
+        byte[] bytes = (byte[]) super.nativeToJava(transferData);
+        if (bytes == null) {
+			return null;
+		}
+        DataInputStream in = new DataInputStream(
+                new ByteArrayInputStream(bytes));
+        try {
+            int count = in.readInt();
+            EditorInputData[] results = new EditorInputData[count];
+            for (int i = 0; i < count; i++) {
+                results[i] = readEditorInput(in);
+            }
+            return results;
+        } catch (IOException e) {
+            return null;
+        } catch (WorkbenchException e) {
+            return null;
+        }
+
+    }
+
+    /**
+     * Method readEditorInput.
+     * @param in
+     * @return EditorInputData
+     */
+    private EditorInputData readEditorInput(DataInputStream dataIn)
+            throws IOException, WorkbenchException {
+
+        String editorId = dataIn.readUTF();
+        String factoryId = dataIn.readUTF();
+        String xmlString = dataIn.readUTF();
+
+        if (xmlString == null || xmlString.length() == 0) {
+			return null;
+		}
+
+        StringReader reader = new StringReader(xmlString);
+
+        // Restore the editor input
+        XMLMemento memento = XMLMemento.createReadRoot(reader);
+
+        IElementFactory factory = PlatformUI.getWorkbench().getElementFactory(
+                factoryId);
+
+        if (factory != null) {
+            IAdaptable adaptable = factory.createElement(memento);
+            if (adaptable != null && (adaptable instanceof IEditorInput)) {
+                return new EditorInputData(editorId, (IEditorInput) adaptable);
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Method writeEditorInput.
+     * @param dataOut
+     * @param editorInputData
+     */
+    private void writeEditorInput(DataOutputStream dataOut,
+            EditorInputData editorInputData) throws IOException {
+        //write the id of the editor
+        dataOut.writeUTF(editorInputData.editorId);
+
+        //write the information needed to recreate the editor input
+        if (editorInputData.input != null) {
+            // Capture the editor information
+            XMLMemento memento = XMLMemento.createWriteRoot("IEditorInput");//$NON-NLS-1$
+
+            IPersistableElement element = editorInputData.input
+                    .getPersistable();
+            if (element != null) {
+                //get the IEditorInput to save its state
+                element.saveState(memento);
+
+                //convert memento to String
+                StringWriter writer = new StringWriter();
+                memento.save(writer);
+                writer.close();
+
+                //write the factor ID and state information
+                dataOut.writeUTF(element.getFactoryId());
+                dataOut.writeUTF(writer.toString());
+            }
+        }
+    }
+
+    public static EditorInputData createEditorInputData(String editorId,
+            IEditorInput input) {
+        return new EditorInputData(editorId, input);
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/EditorPart.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/EditorPart.java
new file mode 100644
index 0000000..5e79a34
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/EditorPart.java
@@ -0,0 +1,301 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.part;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.IPropertyListener;
+import org.eclipse.ui.IWorkbenchPartConstants;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.PartInitException;
+
+/**
+ * Abstract base implementation of all workbench editors.
+ * <p>
+ * This class should be subclassed by clients wishing to define new editors.
+ * The name of the subclass should be given as the <code>"class"</code>
+ * attribute in a <code>editor</code> extension contributed to the workbench's
+ * view extension point (named <code>"org.eclipse.ui.editors"</code>).
+ * For example, the plug-in's XML markup might contain:
+ * <pre>
+ * &LT;extension point="org.eclipse.ui.editors"&GT;
+ *      &LT;editor id="com.example.myplugin.ed"
+ *         name="My Editor"
+ *         icon="./images/cedit.gif"
+ * 		   extensions="foo"
+ * 		   class="com.example.myplugin.MyFooEditor"
+ * 		   contributorClass="com.example.myplugin.MyFooEditorContributor"
+ *      /&GT;
+ * &LT;/extension&GT;
+ * </pre>
+ * where <code>com.example.myplugin.MyEditor</code> is the name of the
+ * <code>EditorPart</code> subclass.
+ * </p>
+ * <p>
+ * Subclasses must implement the following methods:
+ * <ul>
+ *   <li><code>IEditorPart.init</code> - to initialize editor when assigned its site</li>
+ *   <li><code>IWorkbenchPart.createPartControl</code> - to create the editor's controls </li>
+ *   <li><code>IWorkbenchPart.setFocus</code> - to accept focus</li>
+ *   <li><code>IEditorPart.isDirty</code> - to decide whether a significant change has
+ *       occurred</li>
+ *   <li><code>IEditorPart.doSave</code> - to save contents of editor</li>
+ *   <li><code>IEditorPart.doSaveAs</code> - to save contents of editor</li>
+ *   <li><code>IEditorPart.isSaveAsAllowed</code> - to control Save As</li>
+ * </ul>
+ * </p>
+ * <p>
+ * Subclasses may extend or reimplement the following methods as required:
+ * <ul>
+ *   <li><code>IExecutableExtension.setInitializationData</code> - extend to provide additional
+ *       initialization when editor extension is instantiated</li>
+ *   <li><code>IWorkbenchPart.dispose</code> - extend to provide additional cleanup</li>
+ *   <li><code>IAdaptable.getAdapter</code> - reimplement to make the editor
+ *       adaptable</li>
+ * </ul>
+ * </p>
+ */
+public abstract class EditorPart extends WorkbenchPart implements IEditorPart {
+
+    /**
+     * Editor input, or <code>null</code> if none.
+     */
+    private IEditorInput editorInput = null;
+
+    /**
+     * Listens to PROP_TITLE property changes in this object until the first call to
+     * setContentDescription. Used for compatibility with old parts that call setTitle
+     * or overload getTitle instead of using setContentDescription.
+     */
+    private IPropertyListener compatibilityTitleListener = (source, propId) -> {
+	    if (propId == IWorkbenchPartConstants.PROP_TITLE) {
+	        setDefaultPartName();
+	    }
+	};
+
+    /**
+     * Creates a new workbench editor.
+     */
+    protected EditorPart() {
+        super();
+
+        addPropertyListener(compatibilityTitleListener);
+    }
+
+	/*
+	 * Saves the contents of this editor.
+	 * <p>
+	 * Subclasses must override this method to implement the open-save-close
+	 * lifecycle for an editor. For greater details, see
+	 * <code>IEditorPart</code>
+	 * </p>
+	 *
+	 * @see IEditorPart
+	 */
+    @Override
+	public abstract void doSave(IProgressMonitor monitor);
+
+	/*
+	 * Saves the contents of this editor to another object.
+	 * <p>
+	 * Subclasses must override this method to implement the open-save-close
+	 * lifecycle for an editor. For greater details, see
+	 * <code>IEditorPart</code>
+	 * </p>
+	 *
+	 * @see IEditorPart
+	 */
+    @Override
+	public abstract void doSaveAs();
+
+    @Override
+	public IEditorInput getEditorInput() {
+        return editorInput;
+    }
+
+    @Override
+	public IEditorSite getEditorSite() {
+        return (IEditorSite) getSite();
+    }
+
+    @Override
+	public String getTitleToolTip() {
+        if (editorInput == null) {
+			return super.getTitleToolTip();
+		}
+		return editorInput.getToolTipText();
+    }
+
+
+    /*
+     * Initializes the editor part with a site and input.
+     * <p>
+     * Subclasses of <code>EditorPart</code> must implement this method.  Within
+     * the implementation subclasses should verify that the input type is acceptable
+     * and then save the site and input.  Here is sample code:
+     * </p>
+     * <pre>
+     *		if (!(input instanceof IFileEditorInput))
+     *			throw new PartInitException("Invalid Input: Must be IFileEditorInput");
+     *		setSite(site);
+     *		setInput(input);
+     * </pre>
+     */
+    @Override
+	public abstract void init(IEditorSite site, IEditorInput input)
+            throws PartInitException;
+
+
+    /* Returns whether the contents of this editor have changed since the last save
+     * operation.
+     * <p>
+     * Subclasses must override this method to implement the open-save-close lifecycle
+     * for an editor.  For greater details, see <code>IEditorPart</code>
+     * </p>
+     *
+     * @see IEditorPart
+     */
+    @Override
+	public abstract boolean isDirty();
+
+
+    /*
+	 * Returns whether the "save as" operation is supported by this editor. 
+	 * <p>
+	 * Subclasses must override this method to implement the open-save-close
+	 * lifecycle for an editor. For greater details, see
+	 * <code>IEditorPart</code> 
+	 * </p>
+	 *
+	 * @see IEditorPart
+	 */
+    @Override
+	public abstract boolean isSaveAsAllowed();
+
+    /* Returns whether the contents of this editor should be saved when the editor
+     * is closed.
+     * <p>
+     * This method returns <code>true</code> if and only if the editor is dirty
+     * (<code>isDirty</code>).
+     * </p>
+     */
+    @Override
+	public boolean isSaveOnCloseNeeded() {
+        return isDirty();
+    }
+
+    /**
+     * Sets the input to this editor.  This method simply updates the internal
+     * member variable.
+     *
+     * <p>Unlike most of the other set methods on this class, this method does
+     * not fire a property change. Clients that call this method from a subclass
+     * must ensure that they fire an IWorkbenchPartConstants.PROP_INPUT property
+     * change after calling this method but before leaving whatever public method
+     * they are in. Clients that expose this method as public API must fire
+     * the property change within their implementation of setInput.</p>
+     *
+     * <p>Note that firing a property change may cause listeners to immediately
+     * reach back and call methods on this editor. Care should be taken not to
+     * fire the property change until the editor has fully updated its internal
+     * state to reflect the new input.</p>
+     *
+     * @param input the editor input
+     *
+     * @see #setInputWithNotify(IEditorInput)
+     */
+    protected void setInput(IEditorInput input) {
+    	Assert.isLegal(input != null);
+        editorInput = input;
+    }
+
+    /**
+     * Sets the input to this editor and fires a PROP_INPUT property change if
+     * the input has changed.  This is the convenience method implementation.
+     *
+     * <p>Note that firing a property change may cause other objects to reach back
+     * and invoke methods on the editor. Care should be taken not to call this method
+     * until the editor has fully updated its internal state to reflect the
+     * new input.</p>
+     *
+     * @since 3.2
+     *
+     * @param input the editor input
+     */
+    protected void setInputWithNotify(IEditorInput input) {
+		Assert.isLegal(input != null);
+        editorInput = input;
+        firePropertyChange(PROP_INPUT);
+    }
+
+    @Override
+	protected void setContentDescription(String description) {
+        if (compatibilityTitleListener != null) {
+            removePropertyListener(compatibilityTitleListener);
+            compatibilityTitleListener = null;
+        }
+
+        super.setContentDescription(description);
+    }
+
+    @Override
+	protected void setPartName(String partName) {
+        if (compatibilityTitleListener != null) {
+            removePropertyListener(compatibilityTitleListener);
+            compatibilityTitleListener = null;
+        }
+
+        super.setPartName(partName);
+    }
+
+    @Override
+	public void setInitializationData(IConfigurationElement cfig,
+            String propertyName, Object data) {
+        super.setInitializationData(cfig, propertyName, data);
+
+        setDefaultPartName();
+    }
+
+
+    private void setDefaultPartName() {
+        if (compatibilityTitleListener == null) {
+            return;
+        }
+
+        internalSetPartName(getTitle());
+    }
+
+    /**
+     * Set the default title for the receiver.
+     */
+    @Override
+	void setDefaultTitle() {
+        setTitle(getPartName());
+    }
+
+    /**
+     * Checks that the given site is valid for this type of part.
+     * The site for an editor must be an <code>IEditorSite</code>.
+     *
+     * @param site the site to check
+     * @since 3.1
+     */
+    @Override
+	protected final void checkSite(IWorkbenchPartSite site) {
+        super.checkSite(site);
+        Assert.isTrue(site instanceof IEditorSite, "The site for an editor must be an IEditorSite"); //$NON-NLS-1$
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/IContributedContentsView.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/IContributedContentsView.java
new file mode 100644
index 0000000..a3c11c0
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/IContributedContentsView.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 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.ui.part;
+
+import org.eclipse.ui.IWorkbenchPart;
+
+/**
+ * This interface is used to identify workbench views which
+ * allow other parts (typically the active part) to supply
+ * their contents.
+ * The interface allows access to the part which contributed the current
+ * contents.
+ */
+public interface IContributedContentsView {
+    /**
+     * Returns the workbench part which contributed the
+     * current contents of this view.
+     *
+     * @return the part which contributed the current contents
+     */
+    public IWorkbenchPart getContributingPart();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/IDropActionDelegate.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/IDropActionDelegate.java
new file mode 100644
index 0000000..4b551a4
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/IDropActionDelegate.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 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.ui.part;
+
+/**
+ * Interface for actions supplied by extensions to the
+ * org.eclipse.ui.dropActions extension point.
+ */
+public interface IDropActionDelegate {
+    /**
+     * Runs the drop action on the given source and target.
+     * @param source The object that is being dragged.
+     * @param target The object that the drop is occurring over.
+     * @return boolean True if the drop was successful, and false otherwise.
+     */
+    public boolean run(Object source, Object target);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/IPage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/IPage.java
new file mode 100644
index 0000000..e4d8a24
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/IPage.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.part;
+
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IActionBars;
+
+/**
+ * This interface has been replaced by <code>IPageBookViewPage</code>
+ * but is preserved for backward compatibility.
+ * <p>
+ * This class is not intended to be directly implemented by clients; clients
+ * should instead subclass <code>Page</code>.
+ * </p>
+ *
+ * @see PageBookView
+ * @see Page
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IPage {
+    /**
+     * Creates the SWT control for this page under the given parent
+     * control.
+     * <p>
+     * Clients should not call this method (the workbench calls this method when
+     * it needs to, which may be never).
+     * </p>
+     *
+     * @param parent the parent control
+     */
+    public void createControl(Composite parent);
+
+    /**
+     * Disposes of this page.
+     * <p>
+     * This is the last method called on the <code>IPage</code>. Implementors should
+     * clean up any resources associated with the page.
+     * </p>
+     * Callers of this method should ensure that the page's control (if it exists)
+     * has been disposed before calling this method. However, for backward compatibilty,
+     * implementors must also ensure that the page's control has been disposed before
+     * this method returns.
+     * </p>
+     * <p>
+     * Note that there is no guarantee that createControl() has been called,
+     * so the control may never have been created.
+     * </p>
+     */
+    public void dispose();
+
+    /**
+     * Returns the SWT control for this page.
+     *
+     * @return the SWT control for this page, or <code>null</code> if this
+     *   page does not have a control
+     */
+    public Control getControl();
+
+    /**
+     * Allows the page to make contributions to the given action bars.
+     * The contributions will be visible when the page is visible.
+     * <p>
+     * This method is automatically called shortly after
+     * <code>createControl</code> is called
+     * </p>
+     *
+     * @param actionBars the action bars for this page
+     */
+    public void setActionBars(IActionBars actionBars);
+
+    /**
+     * Asks this page to take focus within its pagebook view.
+     */
+    public void setFocus();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/IPageBookViewPage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/IPageBookViewPage.java
new file mode 100644
index 0000000..5865d1f
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/IPageBookViewPage.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.part;
+
+import org.eclipse.ui.PartInitException;
+
+/**
+ * Interface for a page in a pagebook view.
+ * <p>
+ * Pages should implement this interface.
+ * </p>
+ * @see PageBookView
+ * @see Page
+ */
+public interface IPageBookViewPage extends IPage {
+    /**
+     * Returns the site for this page. May be <code>null</code>
+     * if no site has been set.
+     *
+     * @return the page site or <code>null</code>
+     */
+    public IPageSite getSite();
+
+    /**
+     * Initializes this page with the given page site.
+     * <p>
+     * This method is automatically called by the workbench shortly after page
+     * construction.  It marks the start of the pages's lifecycle. Clients must
+     * not call this method.
+     * </p>
+     *
+     * @param site the page site
+     * @exception PartInitException if this page was not initialized successfully
+     */
+    public void init(IPageSite site) throws PartInitException;
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/IPageSite.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/IPageSite.java
new file mode 100644
index 0000000..764c329
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/IPageSite.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.part;
+
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IWorkbenchSite;
+
+/**
+ * The primary interface between a page and the outside world.
+ * <p>
+ * The workbench exposes its implemention of page sites via this interface,
+ * which is not intended to be implemented or extended by clients.
+ * </p>
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+
+public interface IPageSite extends IWorkbenchSite {
+    /**
+     * Registers a pop-up menu with a particular id for extension.
+     * <p>
+     * Within the workbench one plug-in may extend the pop-up menus for a view
+     * or editor within another plug-in.  In order to be eligible for extension,
+     * the menu must be registered by calling <code>registerContextMenu</code>.
+     * Once this has been done the workbench will automatically insert any action
+     * extensions which exist.
+     * </p>
+     * <p>
+     * A unique menu id must be provided for each registered menu. This id should
+     * be published in the Javadoc for the page.
+     * </p>
+     * <p>
+     * Any pop-up menu which is registered with the workbench should also define a
+     * <code>GroupMarker</code> in the registered menu with id
+     * <code>IWorkbenchActionConstants.MB_ADDITIONS</code>.  Other plug-ins will use this
+     * group as a reference point for insertion.  The marker should be defined at an
+     * appropriate location within the menu for insertion.
+     * </p>
+     *
+     * @param menuId the menu id
+     * @param menuManager the menu manager
+     * @param selectionProvider the selection provider
+     */
+    public void registerContextMenu(String menuId, MenuManager menuManager,
+            ISelectionProvider selectionProvider);
+
+    /**
+     * Returns the action bars for this page site.
+     * Pages have exclusive use of their site's action bars.
+     *
+     * @return the action bars
+     */
+    public IActionBars getActionBars();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/ISetSelectionTarget.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/ISetSelectionTarget.java
new file mode 100644
index 0000000..5b04b68
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/ISetSelectionTarget.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 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.ui.part;
+
+import org.eclipse.jface.viewers.ISelection;
+
+/**
+ * Interface for views which support reveal and select.
+ * <p>
+ * This interface may be implemented by subclasses of <code>ViewPart</code>.
+ * This interface is commonly used by a New wizard to reveal and select a
+ * resource in a workbench part which it has just created.
+ * </p>
+ *
+ * @see org.eclipse.ui.IViewPart
+ * @see org.eclipse.ui.part.ViewPart
+ */
+public interface ISetSelectionTarget {
+    /**
+     * Reveals and selects the given element within this target view.
+     *
+     * @param selection the new element to select
+     */
+    public void selectReveal(ISelection selection);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/IShowInSource.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/IShowInSource.java
new file mode 100644
index 0000000..20efc50
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/IShowInSource.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.part;
+
+/**
+ * Parts which need to provide a particular context to a Show In...
+ * target can provide this interface.
+ * The part can either directly implement this interface, or provide it
+ * via <code>IAdaptable.getAdapter(IShowInSource.class)</code>.
+ *
+ * @see IShowInTarget
+ *
+ * @since 2.1
+ */
+public interface IShowInSource {
+
+    /**
+     * Returns the context to show, or <code>null</code> if there is
+     * currently no valid context to show.
+     *
+     * @return the context to show, or <code>null</code>
+     */
+    public ShowInContext getShowInContext();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/IShowInTarget.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/IShowInTarget.java
new file mode 100644
index 0000000..c61d4aa
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/IShowInTarget.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.part;
+
+/**
+ * This interface must be provided by Show In targets (parts listed
+ * in the Show In prompter).
+ * The part can either directly implement this interface, or provide it
+ * via <code>IAdaptable.getAdapter(IShowInTarget.class)</code>.
+ *
+ * @see org.eclipse.ui.IPageLayout#addShowInPart
+ *
+ * @since 2.1
+ */
+public interface IShowInTarget {
+
+    /**
+     * Shows the given context in this target.
+     * The target should check the context's selection for elements
+     * to show.  If there are no relevant elements in the selection,
+     * then it should check the context's input.
+     *
+     * @param context the context to show
+     * @return <code>true</code> if the context could be shown,
+     *   <code>false</code> otherwise
+     */
+    public boolean show(ShowInContext context);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/IShowInTargetList.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/IShowInTargetList.java
new file mode 100644
index 0000000..585f174
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/IShowInTargetList.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.part;
+
+/**
+ * Show In sources which need to provide additional entries to the Show In list of targets
+ * can provide this interface.
+ * The part can either directly implement this interface, or provide it
+ * via <code>IAdaptable.getAdapter(IShowInTargetList)</code>.
+ *
+ * @see IShowInSource
+ * @see IShowInTarget
+ *
+ * @since 2.1
+ */
+public interface IShowInTargetList {
+
+    /**
+     * Returns the identifiers for the target parts to show.
+     * The target parts must be Show In targets.
+     *
+     * @return the identifiers for the target parts to show
+     *
+     * @see IShowInTarget
+     */
+    public String[] getShowInTargetIds();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/IWorkbenchPartOrientation.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/IWorkbenchPartOrientation.java
new file mode 100644
index 0000000..d704f5b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/IWorkbenchPartOrientation.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.part;
+
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+
+/**
+ * The IWorkbenchPartOrientation is the interface that defines the orientation
+ * of the part. If a type does not implement this interface an orientation of
+ * SWT.NONE will be assumed.
+ *
+ * @see org.eclipse.swt.SWT#RIGHT_TO_LEFT
+ * @see org.eclipse.swt.SWT#LEFT_TO_RIGHT
+ * @see org.eclipse.swt.SWT#NONE
+ * @see Window#getDefaultOrientation()
+ * @since 3.1
+ */
+public interface IWorkbenchPartOrientation {
+	/**
+	 * Return the orientation of this part.
+	 *
+	 * @return int SWT#RIGHT_TO_LEFT or SWT#LEFT_TO_RIGHT
+	 * @see Window#getDefaultOrientation()
+	 * @see SWT#RIGHT_TO_LEFT
+	 * @see SWT#LEFT_TO_RIGHT
+	 * @see Window#getDefaultOrientation()
+	 */
+	public int getOrientation();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/IntroPart.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/IntroPart.java
new file mode 100644
index 0000000..7e6fd31
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/IntroPart.java
@@ -0,0 +1,306 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2016 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.ui.part;
+
+import org.eclipse.core.commands.common.EventManager;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExecutableExtension;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.util.SafeRunnable;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IPropertyListener;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.intro.IntroMessages;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+import org.eclipse.ui.internal.util.Util;
+import org.eclipse.ui.intro.IIntroPart;
+import org.eclipse.ui.intro.IIntroSite;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+/**
+ * Abstract base implementation of an intro part.
+ * <p>
+ * Subclasses must implement the following methods:
+ * <ul>
+ * <li><code>createPartControl</code>- to create the intro part's controls
+ * </li>
+ * <li><code>setFocus</code>- to accept focus</li>
+ * <li><code>standbyStateChanged</code>- to change the standby mode</li>
+ * </ul>
+ * </p>
+ * <p>
+ * Subclasses may extend or reimplement the following methods as required:
+ * <ul>
+ * <li><code>setInitializationData</code>- extend to provide additional
+ * initialization when the intro extension is instantiated</li>
+ * <li><code>init(IIntroSite, IMemento)</code>- extend to provide additional
+ * initialization when intro is assigned its site</li>
+ * <li><code>dispose</code>- extend to provide additional cleanup</li>
+ * <li><code>getAdapter</code>- reimplement to make their intro adaptable
+ * </li>
+ * </ul>
+ * </p>
+ * @since 3.0
+ */
+public abstract class IntroPart extends EventManager implements IIntroPart,
+		IExecutableExtension {
+
+    private IConfigurationElement configElement;
+
+    private ImageDescriptor imageDescriptor;
+
+    private IIntroSite partSite;
+
+    private Image titleImage;
+
+	private String titleLabel;
+
+    /**
+     * Creates a new intro part.
+     */
+    protected IntroPart() {
+        super();
+    }
+
+    @Override
+	public void addPropertyListener(IPropertyListener l) {
+        addListenerObject(l);
+    }
+
+    @Override
+	public abstract void createPartControl(Composite parent);
+
+    /**
+     * The <code>IntroPart</code> implementation of this
+     * <code>IIntroPart</code> method disposes the title image loaded by
+     * <code>setInitializationData</code>. Subclasses may extend.
+     */
+    @Override
+	public void dispose() {
+        if (titleImage != null) {
+            JFaceResources.getResources().destroyImage(imageDescriptor);
+            titleImage = null;
+        }
+
+        // Clear out the property change listeners as we
+        // should not be notifying anyone after the part
+        // has been disposed.
+        clearListeners();
+    }
+
+    /**
+     * Fires a property changed event.
+     *
+     * @param propertyId
+     *            the id of the property that changed
+     */
+    protected void firePropertyChange(final int propertyId) {
+		for (Object listener : getListeners()) {
+			final IPropertyListener propertyListener = (IPropertyListener) listener;
+            SafeRunner.run(new SafeRunnable() {
+
+                @Override
+				public void run() {
+					propertyListener.propertyChanged(this, propertyId);
+                }
+            });
+        }
+    }
+
+    /**
+     * This implementation of the method declared by <code>IAdaptable</code>
+     * passes the request along to the platform's adapter manager; roughly
+     * <code>Platform.getAdapterManager().getAdapter(this, adapter)</code>.
+     * Subclasses may override this method (however, if they do so, they should
+     * invoke the method on their superclass to ensure that the Platform's
+     * adapter manager is consulted).
+     */
+    @Override
+	public <T> T getAdapter(Class<T> adapter) {
+        return Platform.getAdapterManager().getAdapter(this, adapter);
+    }
+
+    /**
+     * Returns the configuration element for this part. The configuration
+     * element comes from the plug-in registry entry for the extension defining
+     * this part.
+     *
+     * @return the configuration element for this part
+     */
+    protected IConfigurationElement getConfigurationElement() {
+        return configElement;
+    }
+
+    /**
+     * Returns the default title image.
+     *
+     * @return the default image
+     */
+    protected Image getDefaultImage() {
+        return PlatformUI.getWorkbench().getSharedImages().getImage(
+                ISharedImages.IMG_DEF_VIEW);
+    }
+
+    @Override
+	public final IIntroSite getIntroSite() {
+        return partSite;
+    }
+
+    @Override
+	public Image getTitleImage() {
+        if (titleImage != null) {
+            return titleImage;
+        }
+        return getDefaultImage();
+    }
+
+    @Override
+	public String getTitle() {
+    	if (titleLabel != null) {
+    		return titleLabel;
+    	}
+    	return getDefaultTitle();
+    }
+
+    /**
+     * Return the default title string.
+     *
+	 * @return the default title string
+	 */
+	private String getDefaultTitle() {
+		return IntroMessages.Intro_default_title;
+	}
+
+	/**
+     * The base implementation of this {@link org.eclipse.ui.intro.IIntroPart}method ignores the
+     * memento and initializes the part in a fresh state. Subclasses may extend
+     * to perform any state restoration, but must call the super method.
+     *
+     * @param site
+     *            the intro site
+     * @param memento
+     *            the intro part state or <code>null</code> if there is no
+     *            previous saved state
+     * @exception PartInitException
+     *                if this part was not initialized successfully
+     */
+    @Override
+	public void init(IIntroSite site, IMemento memento)
+            throws PartInitException {
+        setSite(site);
+    }
+
+    /**
+     * Sets the part site.
+     * <p>
+     * Subclasses must invoke this method from {@link org.eclipse.ui.intro.IIntroPart#init(IIntroSite, IMemento)}.
+     * </p>
+     *
+     * @param site the intro part site
+     */
+    protected void setSite(IIntroSite site) {
+        this.partSite = site;
+    }
+
+    @Override
+	public void removePropertyListener(IPropertyListener l) {
+        removeListenerObject(l);
+    }
+
+    /**
+     * The base implementation of this {@link org.eclipse.ui.intro.IIntroPart} method does nothing.
+     * Subclasses may override.
+     *
+     * @param memento
+     *            a memento to receive the object state
+     */
+    @Override
+	public void saveState(IMemento memento) {
+        //no-op
+    }
+
+    @Override
+	public abstract void setFocus();
+
+    /**
+     * The <code>IntroPart</code> implementation of this
+     * <code>IExecutableExtension</code> records the configuration element in
+     * and internal state variable (accessible via <code>getConfigElement</code>).
+     * It also loads the title image, if one is specified in the configuration
+     * element. Subclasses may extend.
+     *
+     * Should not be called by clients. It is called by the core plugin when
+     * creating this executable extension.
+     */
+    @Override
+	public void setInitializationData(IConfigurationElement cfig,
+            String propertyName, Object data) {
+
+        // Save config element.
+        configElement = cfig;
+
+        titleLabel = cfig.getAttribute(IWorkbenchRegistryConstants.ATT_LABEL);
+
+        // Icon.
+        String strIcon = cfig.getAttribute(IWorkbenchRegistryConstants.ATT_ICON);
+        if (strIcon == null) {
+			return;
+		}
+
+        imageDescriptor = AbstractUIPlugin.imageDescriptorFromPlugin(
+                configElement.getNamespace(), strIcon);
+
+        if (imageDescriptor == null) {
+			return;
+		}
+
+        Image image = JFaceResources.getResources().createImageWithDefault(imageDescriptor);
+        titleImage = image;
+    }
+
+    /**
+     * Sets or clears the title image of this part.
+     *
+     * @param titleImage
+     *            the title image, or <code>null</code> to clear
+     */
+    protected void setTitleImage(Image titleImage) {
+        Assert.isTrue(titleImage == null || !titleImage.isDisposed());
+        //Do not send changes if they are the same
+        if (this.titleImage == titleImage) {
+			return;
+		}
+        this.titleImage = titleImage;
+        firePropertyChange(IIntroPart.PROP_TITLE);
+    }
+
+    /**
+     * Set the title string for this part.
+     *
+     * @param titleLabel the title string.  Must not be <code>null</code>.
+     * @since 3.2
+     */
+    protected void setTitle(String titleLabel) {
+    	Assert.isNotNull(titleLabel);
+    	if (Util.equals(this.titleLabel, titleLabel))
+    		return;
+    	this.titleLabel = titleLabel;
+    	firePropertyChange(IIntroPart.PROP_TITLE);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/MessagePage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/MessagePage.java
new file mode 100644
index 0000000..edd69e1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/MessagePage.java
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2014 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.ui.part;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+
+/**
+ * A message page display a message in a pagebook view.
+ * <p>
+ * This class may be instantiated; it is not intended to be subclassed.
+ * </p>
+ *
+ * @see PageBookView
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class MessagePage extends Page {
+    private Composite pgComp;
+
+    private Label msgLabel;
+
+    private String message = "";//$NON-NLS-1$
+
+    /**
+     * Creates a new page. The message is the empty string.
+     */
+    public MessagePage() {
+        // do nothing
+    }
+
+    @Override
+	public void createControl(Composite parent) {
+        // Message in default page of Outline should have margins
+        pgComp = new Composite(parent, SWT.NULL);
+        pgComp.setLayout(new FillLayout());
+
+        msgLabel = new Label(pgComp, SWT.LEFT | SWT.TOP | SWT.WRAP);
+        msgLabel.setText(message);
+    }
+
+    @Override
+	public Control getControl() {
+        return pgComp;
+    }
+
+    /**
+     * Sets focus to a part in the page.
+     */
+    @Override
+	public void setFocus() {
+        // important to give focus to the composite rather than the label
+        // as the composite will actually take focus (though hidden),
+        // but setFocus on a Label is a no-op
+        pgComp.setFocus();
+    }
+
+    /**
+     * Sets the message to the given string.
+     *
+     * @param message the message text
+     */
+    public void setMessage(String message) {
+        this.message = message;
+        if (msgLabel != null) {
+			msgLabel.setText(message);
+		}
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/MultiEditor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/MultiEditor.java
new file mode 100644
index 0000000..373ac03
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/MultiEditor.java
@@ -0,0 +1,157 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2015 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
+ *     Nikolay Botev - bug 240651
+ ******************************************************************************/
+
+package org.eclipse.ui.part;
+
+import org.eclipse.jface.resource.ColorRegistry;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorReference;
+import org.eclipse.ui.internal.IWorkbenchThemeConstants;
+import org.eclipse.ui.internal.WorkbenchWindow;
+import org.eclipse.ui.themes.ITheme;
+
+/**
+ * A MultiEditor is a composite of editors.
+ *
+ * This class is intended to be subclassed.
+ *
+ */
+public abstract class MultiEditor extends AbstractMultiEditor {
+
+	/**
+     * The colors used to draw the title bar of the inner editors
+     */
+    public static class Gradient {
+        public Color fgColor;
+
+        public Color[] bgColors;
+
+        public int[] bgPercents;
+    }
+
+	/**
+	 * Updates the gradient in the title bar.
+	 * @param editor
+	 */
+	public void updateGradient(IEditorPart editor) {
+	    boolean activeEditor = editor == getSite().getPage().getActiveEditor();
+	    boolean activePart = editor == getSite().getPage().getActivePart();
+
+	    ITheme theme = editor.getEditorSite().getWorkbenchWindow()
+	            .getWorkbench().getThemeManager().getCurrentTheme();
+	    Gradient g = new Gradient();
+
+	    ColorRegistry colorRegistry = theme.getColorRegistry();
+	    if (activePart) {
+	        g.fgColor = colorRegistry
+	                .get(IWorkbenchThemeConstants.ACTIVE_TAB_TEXT_COLOR);
+	        g.bgColors = new Color[2];
+	        g.bgColors[0] = colorRegistry
+	                .get(IWorkbenchThemeConstants.ACTIVE_TAB_BG_START);
+	        g.bgColors[1] = colorRegistry
+	                .get(IWorkbenchThemeConstants.ACTIVE_TAB_BG_END);
+	    } else {
+	        if (activeEditor) {
+	            g.fgColor = colorRegistry
+	                    .get(IWorkbenchThemeConstants.ACTIVE_TAB_TEXT_COLOR);
+	            g.bgColors = new Color[2];
+	            g.bgColors[0] = colorRegistry
+	                    .get(IWorkbenchThemeConstants.ACTIVE_TAB_BG_START);
+	            g.bgColors[1] = colorRegistry
+	                    .get(IWorkbenchThemeConstants.ACTIVE_TAB_BG_END);
+	        } else {
+	            g.fgColor = colorRegistry
+	                    .get(IWorkbenchThemeConstants.INACTIVE_TAB_TEXT_COLOR);
+	            g.bgColors = new Color[2];
+	            g.bgColors[0] = colorRegistry
+	                    .get(IWorkbenchThemeConstants.INACTIVE_TAB_BG_START);
+	            g.bgColors[1] = colorRegistry
+	                    .get(IWorkbenchThemeConstants.INACTIVE_TAB_BG_END);
+	        }
+	    }
+	    g.bgPercents = new int[] { theme
+	            .getInt(IWorkbenchThemeConstants.ACTIVE_TAB_PERCENT) };
+
+	    drawGradient(editor, g);
+	}
+
+	/**
+	 * Draw the gradient in the title bar.
+	 */
+	protected abstract void drawGradient(IEditorPart innerEditor, Gradient g);
+
+    /**
+     * Create the control of the inner editor.
+     *
+     * Must be called by subclass.
+     */
+    public Composite createInnerPartControl(Composite parent,
+            final IEditorPart e) {
+        Composite content = new Composite(parent, SWT.NONE);
+        content.setLayout(new FillLayout());
+        e.createPartControl(content);
+        parent.addListener(SWT.Activate, event -> {
+		    if (event.type == SWT.Activate) {
+				activateEditor(e);
+			}
+		});
+        return content;
+    }
+
+    /*
+     * @see IWorkbenchPart#setFocus()
+     */
+    @Override
+	public void setFocus() {
+    	super.setFocus();
+        updateGradient(getActiveEditor());
+    }
+
+    /**
+     * Activates the given nested editor.
+     *
+     * @param part the nested editor
+     * @since 3.5
+     */
+    @Override
+	public void activateEditor(IEditorPart part) {
+        IEditorPart oldEditor = getActiveEditor();
+        super.activateEditor(part);
+        updateGradient(oldEditor);
+    }
+
+    /**
+     * Return true if the shell is activated.
+     */
+    protected boolean getShellActivated() {
+        WorkbenchWindow window = (WorkbenchWindow) getSite().getPage()
+                .getWorkbenchWindow();
+        return window.getShellActivated();
+    }
+
+	@Override
+	public Composite getInnerEditorContainer(
+			IEditorReference innerEditorReference) {
+		// This method is not used by MutliEditor
+		return null;
+	}
+
+	@Override
+	protected void innerEditorsCreated() {
+		// Nothing to do
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/MultiEditorInput.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/MultiEditorInput.java
new file mode 100644
index 0000000..6ce3244
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/MultiEditorInput.java
@@ -0,0 +1,134 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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.ui.part;
+
+import java.util.Arrays;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IPersistableElement;
+
+/**
+ * Implements an input for a <code>AbstractMultiEditor</code>.
+ *
+ * This class is intended to be instantiated by clients but is
+ * not intended to be subclassed.
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class MultiEditorInput implements IEditorInput {
+
+    IEditorInput input[];
+
+    String editors[];
+
+    /**
+     * Constructs a new MultiEditorInput.
+     */
+    public MultiEditorInput(String[] editorIDs, IEditorInput[] innerEditors) {
+        Assert.isNotNull(editorIDs);
+        Assert.isNotNull(innerEditors);
+        editors = editorIDs;
+        input = innerEditors;
+    }
+
+    /**
+     * Returns an array with the input of all inner editors.
+     */
+    public IEditorInput[] getInput() {
+        return input;
+    }
+
+    /**
+     * Retunrs an array with the id of all inner editors.
+     */
+    public String[] getEditors() {
+        return editors;
+    }
+
+    /*
+     * @see IEditorInput#exists()
+     */
+    @Override
+	public boolean exists() {
+        return true;
+    }
+
+    /*
+     * @see IEditorInput#getImageDescriptor()
+     */
+    @Override
+	public ImageDescriptor getImageDescriptor() {
+        return null;
+    }
+
+    /*
+     * @see IEditorInput#getName()
+     */
+    @Override
+	public String getName() {
+        String name = ""; //$NON-NLS-1$
+        for (int i = 0; i < (input.length - 1); i++) {
+            name = name + input[i].getName() + "/"; //$NON-NLS-1$
+        }
+        name = name + input[input.length - 1].getName();
+        return name;
+    }
+
+    /*
+     * @see IEditorInput#getPersistable()
+     */
+    @Override
+	public IPersistableElement getPersistable() {
+        return null;
+    }
+
+    /*
+     * @see IEditorInput#getToolTipText()
+     */
+    @Override
+	public String getToolTipText() {
+        return getName();
+    }
+
+    /*
+     * @see IAdaptable#getAdapter(Class)
+     */
+    @Override
+	public <T> T getAdapter(Class<T> adapter) {
+        return null;
+    }
+
+
+    @Override
+	public boolean equals(Object obj) {
+        if (this == obj) {
+			return true;
+		}
+        if (!(obj instanceof MultiEditorInput)) {
+			return false;
+		}
+        MultiEditorInput other = (MultiEditorInput) obj;
+        return Arrays.equals(this.editors, other.editors) && Arrays.equals(this.input, other.input);
+    }
+
+
+    @Override
+	public int hashCode() {
+        int hash = 0;
+        for (String editor : editors) {
+            hash = hash * 37 + editor.hashCode();
+        }
+        for (IEditorInput editorInput : input) {
+            hash = hash * 37 + editorInput.hashCode();
+        }
+        return hash;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/MultiPageEditor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/MultiPageEditor.java
new file mode 100644
index 0000000..eeda1f5
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/MultiPageEditor.java
@@ -0,0 +1,174 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.part;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.TabFolder;
+
+/**
+ * Abstract superclass of all multi-page workbench editors.
+ * <p>
+ * This class should be subclassed by clients wishing to define new
+ * multi-page editor.
+ * </p>
+ * <p>
+ * Subclasses must implement the following methods:
+ * <ul>
+ *   <li><code>createPartControl</code> - to create the view's controls </li>
+ *   <li><code>setFocus</code> - to accept focus</li>
+ *   <li><code>isDirty</code> - to decide whether a significant change has
+ *       occurred</li>
+ *   <li><code>doSave</code> - to save contents of editor</li>
+ *   <li><code>doSaveAs</code> - to save contents of editor</li>
+ * </ul>
+ * </p>
+ * <p>
+ * Subclasses may extend or reimplement the following methods as required:
+ * <ul>
+ *   <li><code>setInitializationData</code> - extend to provide additional
+ *       initialization when editor extension is instantiated</li>
+ *   <li><code>init(IEditorSite,IEditorInput)</code> - extend to provide
+ *       additional initialization when editor is assigned its site</li>
+ *   <li><code>isSaveOnCloseNeeded</code> - override to control saving</li>
+ *   <li><code>isSaveAsAllowed</code> - override to control saving</li>
+ *   <li><code>gotoMarker</code> - reimplement to make selections based on
+ *       markers</li>
+ *   <li><code>dispose</code> - extend to provide additional cleanup</li>
+ *   <li><code>getAdapter</code> - reimplement to make their editor
+ *       adaptable</li>
+ * </ul>
+ * </p>
+ *
+ * @deprecated Use the class <code>MultiPageEditorPart</code> instead
+ */
+@Deprecated
+public abstract class MultiPageEditor extends EditorPart {
+    private List syncVector;
+
+    private TabFolder tabFolder;
+
+    /**
+     * Creates a new multi-page editor.
+     *
+     * @deprecated Use the class <code>MultiPageEditorPart</code> instead
+     */
+    @Deprecated
+	public MultiPageEditor() {
+        super();
+    }
+
+    /**
+     * Adds a synchronized pagebook to this editor.  Once added, the
+     * visible page of the pagebook and the visible page of the editor
+     * will be synchronized.
+     *
+     * @param pageBook the pagebook to add
+     */
+    protected void addSyncroPageBook(PageBook pageBook) {
+        // Add the page.
+        if (syncVector == null) {
+			syncVector = new ArrayList(1);
+		}
+        syncVector.add(pageBook);
+
+        // Set the visible page.
+        syncPageBook(pageBook);
+    }
+
+    /**
+     * The <code>MultiPageEditor</code> implementation of this <code>IWorkbenchPart</code>
+     * method creates a <code>TabFolder</code> control.
+     */
+    @Override
+	public void createPartControl(Composite parent) {
+        tabFolder = new TabFolder(parent, SWT.NONE);
+        tabFolder.addSelectionListener(new SelectionAdapter()
+        {
+            /** {@inheritDoc} */
+            @Override
+            public void widgetSelected(SelectionEvent e)
+            {
+                sync();
+            }
+        });
+    }
+
+    /**
+     * Returns this editor's workbook.
+     *
+     * @return the editor workbook
+     */
+    protected TabFolder getFolder() {
+        return tabFolder;
+    }
+
+    /**
+     * Indicates that a page change has occurred.  Updates the sync vector.
+     */
+    protected void onPageChange() {
+        if (syncVector != null) {
+            Iterator itr = syncVector.iterator();
+            while (itr.hasNext()) {
+                PageBook pageBook = (PageBook) itr.next();
+                syncPageBook(pageBook);
+            }
+        }
+    }
+
+    /**
+     * Removes a synchronized pagebook from this editor.
+     *
+     * @param pageBook the pagebook to remove
+     * @see #addSyncroPageBook(PageBook)
+     */
+    protected void removeSyncroPageBook(PageBook pageBook) {
+        if (syncVector != null) {
+			syncVector.remove(pageBook);
+		}
+        pageBook.dispose();
+    }
+
+    /**
+     * Synchronizes each registered pagebook with the editor page.
+     */
+    protected void sync() {
+        if (syncVector != null) {
+            Iterator itr = syncVector.iterator();
+            while (itr.hasNext()) {
+                PageBook pageBook = (PageBook) itr.next();
+                syncPageBook(pageBook);
+            }
+        }
+    }
+
+    /**
+     * Sets the visible page of the given pagebook to be the same as
+     * the visible page of this editor.
+     *
+     * @param pageBook a pagebook to synchronize
+     */
+    protected void syncPageBook(PageBook pageBook) {
+        int pos = tabFolder.getSelectionIndex();
+        Control children[] = pageBook.getChildren();
+        int size = children.length;
+        if (pos < size) {
+			pageBook.showPage(children[pos]);
+		}
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/MultiPageEditorActionBarContributor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/MultiPageEditorActionBarContributor.java
new file mode 100644
index 0000000..d840774
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/MultiPageEditorActionBarContributor.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.part;
+
+import org.eclipse.ui.IEditorPart;
+
+/**
+ * Abstract base class for managing the installation/deinstallation of global
+ * actions for multi-page editors.
+ * <p>
+ * Subclasses must implement <code>setActivePage</code>, and may reimplement
+ * any of the following methods:
+ * <ul>
+ *   <li><code>contributeToMenu</code> - reimplement to contribute to menu</li>
+ *   <li><code>contributeToToolBar</code> - reimplement to contribute to tool
+ *     bar</li>
+ *   <li><code>contributeToStatusLine</code> - reimplement to contribute to
+ *     status line</li>
+ * </ul>
+ * </p>
+ */
+public abstract class MultiPageEditorActionBarContributor extends
+        EditorActionBarContributor {
+    /**
+     * Creates a multi-page editor action contributor.
+     */
+    protected MultiPageEditorActionBarContributor() {
+        super();
+    }
+
+	/*
+	 * Registers the contributor with the multi-page editor for future editor
+	 * action redirection when the active page is changed, and sets the active
+	 * page.
+	 */
+    @Override
+	public void setActiveEditor(IEditorPart part) {
+        IEditorPart activeNestedEditor = null;
+        if (part instanceof MultiPageEditorPart) {
+            activeNestedEditor = ((MultiPageEditorPart) part).getActiveEditor();
+        }
+        setActivePage(activeNestedEditor);
+    }
+
+    /**
+     * Sets the active page of the the multi-page editor to be the given editor.
+     * Redirect actions to the given editor if actions are not already being sent to it.
+     * <p>
+     * This method is called whenever the page changes.
+     * Subclasses must implement this method to redirect actions to the given
+     * editor (if not already directed to it).
+     * </p>
+     *
+     * @param activeEditor the new active editor, or <code>null</code> if there is no active page, or if the
+     *   active page does not have a corresponding editor
+     */
+    public abstract void setActivePage(IEditorPart activeEditor);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/MultiPageEditorPart.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/MultiPageEditorPart.java
new file mode 100644
index 0000000..87a5831
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/MultiPageEditorPart.java
@@ -0,0 +1,1297 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *******************************************************************************/
+package org.eclipse.ui.part;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.util.Tracing;
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.jface.dialogs.IPageChangeProvider;
+import org.eclipse.jface.dialogs.IPageChangedListener;
+import org.eclipse.jface.dialogs.PageChangedEvent;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.util.SafeRunnable;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CTabFolder;
+import org.eclipse.swt.custom.CTabItem;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Item;
+import org.eclipse.swt.widgets.Widget;
+import org.eclipse.ui.IEditorActionBarContributor;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.IKeyBindingService;
+import org.eclipse.ui.INestableKeyBindingService;
+import org.eclipse.ui.IPartService;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.internal.PartSite;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.misc.Policy;
+import org.eclipse.ui.internal.services.INestable;
+import org.eclipse.ui.internal.services.IServiceLocatorCreator;
+import org.eclipse.ui.services.IDisposable;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * A multi-page editor is an editor with multiple pages, each of which may
+ * contain an editor or an arbitrary SWT control.
+ * <p>
+ * Subclasses must implement the following methods:
+ * <ul>
+ * <li><code>createPages</code> - to create the required pages by calling one of
+ * the <code>addPage</code> methods</li>
+ * <li><code>IEditorPart.doSave</code> - to save contents of editor</li>
+ * <li><code>IEditorPart.doSaveAs</code> - to save contents of editor</li>
+ * <li><code>IEditorPart.isSaveAsAllowed</code> - to enable Save As</li>
+ * <li><code>IEditorPart.gotoMarker</code> - to scroll to a marker</li>
+ * </ul>
+ * </p>
+ * <p>
+ * Multi-page editors have a single action bar contributor, which manages
+ * contributions for all the pages. The contributor must be a subclass of
+ * <code>MultiPageEditorActionBarContributor</code>. Note that since any nested
+ * editors are created directly in code by callers of
+ * <code>addPage(IEditorPart,IEditorInput)</code>, nested editors do not have
+ * their own contributors.
+ * </p>
+ * <p>
+ * As of 3.5 multi-page editors will post PageChangedEvents at the end of
+ * {@link #pageChange(int)}. Subclasses may override {@link #getSelectedPage()}
+ * to return a page appropriate to their multi-page editor. IPartListener2
+ * listeners registered with the IPartService can implement IPageChangedListener
+ * to be notified about all page change events within the workbench page or
+ * workbench window.
+ * </p>
+ *
+ * @see org.eclipse.ui.part.MultiPageEditorActionBarContributor
+ * @see org.eclipse.jface.dialogs.IPageChangeProvider
+ * @see org.eclipse.jface.dialogs.IPageChangedListener
+ * @see org.eclipse.ui.IPartService
+ */
+public abstract class MultiPageEditorPart extends EditorPart implements IPageChangeProvider {
+
+	private static final String COMMAND_NEXT_SUB_TAB = "org.eclipse.ui.navigate.nextSubTab"; //$NON-NLS-1$
+	private static final String COMMAND_PREVIOUS_SUB_TAB = "org.eclipse.ui.navigate.previousSubTab"; //$NON-NLS-1$
+
+	/**
+	 * Subclasses that override {@link #createPageContainer(Composite)} can use
+	 * this constant to get a site for the container that can be active while
+	 * the current page is deactivated.
+	 *
+	 * @since 3.4
+	 * @see #activateSite()
+	 * @see #deactivateSite(boolean, boolean)
+	 * @see #getPageSite(int)
+	 */
+	protected static final int PAGE_CONTAINER_SITE = 65535;
+
+	/**
+	 * Private tracing output.
+	 */
+	private static final String TRACING_COMPONENT = "MPE"; //$NON-NLS-1$
+
+	/**
+	 * The active service locator. This value may be <code>null</code> if
+	 * there is no selected page, or if the selected page is a control with
+	 * no site.
+	 */
+	private INestable activeServiceLocator;
+
+	/**
+	 * The container widget.
+	 */
+	private CTabFolder container;
+
+	/**
+	 * List of nested editors. Element type: IEditorPart. Need to hang onto them
+	 * here, in addition to using get/setData on the items, because dispose()
+	 * needs to access them, but widgetry has already been disposed at that
+	 * point.
+	 */
+	private ArrayList nestedEditors = new ArrayList(3);
+
+	private List pageSites = new ArrayList(3);
+
+	private IServiceLocator pageContainerSite;
+
+	private ListenerList<IPageChangedListener> pageChangeListeners = new ListenerList<>(
+			ListenerList.IDENTITY);
+
+	/**
+	 * Creates an empty multi-page editor with no pages.
+	 */
+	protected MultiPageEditorPart() {
+		super();
+	}
+
+	/**
+	 * Creates and adds a new page containing the given control to this
+	 * multi-page editor. The control may be <code>null</code>, allowing it
+	 * to be created and set later using <code>setControl</code>.
+	 *
+	 * @param control
+	 *            the control, or <code>null</code>
+	 * @return the index of the new page
+	 *
+	 * @see MultiPageEditorPart#setControl(int, Control)
+	 */
+	public int addPage(Control control) {
+		int index = getPageCount();
+		addPage(index, control);
+		return index;
+	}
+
+	/**
+	 * Creates and adds a new page containing the given control to this
+	 * multi-page editor. The page is added at the given index. The control may
+	 * be <code>null</code>, allowing it to be created and set later using
+	 * <code>setControl</code>.
+	 *
+	 * @param index
+	 *            the index at which to add the page (0-based)
+	 * @param control
+	 *            the control, or <code>null</code>
+	 *
+	 * @see MultiPageEditorPart#setControl(int, Control)
+	 */
+	public void addPage(int index, Control control) {
+		createItem(index, control);
+	}
+
+	/**
+	 * Creates and adds a new page containing the given editor to this
+	 * multi-page editor. This also hooks a property change listener on the
+	 * nested editor.
+	 *
+	 * @param editor
+	 *            the nested editor
+	 * @param input
+	 *            the input for the nested editor
+	 * @return the index of the new page
+	 * @exception PartInitException
+	 *                if a new page could not be created
+	 *
+	 * @see MultiPageEditorPart#handlePropertyChange(int) the handler for
+	 *      property change events from the nested editor
+	 */
+	public int addPage(IEditorPart editor, IEditorInput input)
+			throws PartInitException {
+		int index = getPageCount();
+		addPage(index, editor, input);
+		return index;
+	}
+
+	/**
+	 * Creates and adds a new page containing the given editor to this
+	 * multi-page editor. The page is added at the given index. This also hooks
+	 * a property change listener on the nested editor.
+	 *
+	 * @param index
+	 *            the index at which to add the page (0-based)
+	 * @param editor
+	 *            the nested editor
+	 * @param input
+	 *            the input for the nested editor
+	 * @exception PartInitException
+	 *                if a new page could not be created
+	 *
+	 * @see MultiPageEditorPart#handlePropertyChange(int) the handler for
+	 *      property change events from the nested editor
+	 */
+	public void addPage(int index, IEditorPart editor, IEditorInput input)
+			throws PartInitException {
+		IEditorSite site = createSite(editor);
+		// call init first so that if an exception is thrown, we have created no
+		// new widgets
+		editor.init(site, input);
+		Composite parent2 = new Composite(getContainer(),
+				getOrientation(editor));
+		parent2.setLayout(new FillLayout());
+		editor.createPartControl(parent2);
+		editor.addPropertyListener((source, propertyId) -> MultiPageEditorPart.this.handlePropertyChange(propertyId));
+		// create item for page only after createPartControl has succeeded
+		Item item = createItem(index, parent2);
+		// remember the editor, as both data on the item, and in the list of
+		// editors (see field comment)
+		item.setData(editor);
+		nestedEditors.add(editor);
+	}
+
+	/**
+	 * Get the orientation of the editor.
+	 *
+	 * @param editor
+	 * @return int the orientation flag
+	 * @see SWT#RIGHT_TO_LEFT
+	 * @see SWT#LEFT_TO_RIGHT
+	 * @see SWT#NONE
+	 */
+	private int getOrientation(IEditorPart editor) {
+		if (editor instanceof IWorkbenchPartOrientation) {
+			return ((IWorkbenchPartOrientation) editor).getOrientation();
+		}
+		return getOrientation();
+	}
+
+	/**
+	 * Creates an empty container. Creates a CTabFolder with no style bits set,
+	 * and hooks a selection listener which calls <code>pageChange()</code>
+	 * whenever the selected tab changes.
+	 * 
+	 * @param parent
+	 *            The composite in which the container tab folder should be
+	 *            created; must not be <code>null</code>.
+	 * @return a new container
+	 */
+	private CTabFolder createContainer(Composite parent) {
+		// use SWT.FLAT style so that an extra 1 pixel border is not reserved
+		// inside the folder
+		parent.setLayout(new FillLayout());
+		final CTabFolder newContainer = new CTabFolder(parent, SWT.BOTTOM
+				| SWT.FLAT);
+		newContainer.addSelectionListener(new SelectionAdapter()
+        {
+		    /** {@inheritDoc} */
+		    @Override
+		    public void widgetSelected(SelectionEvent e)
+		    {
+		        int newPageIndex = newContainer.indexOf((CTabItem) e.item);
+	            pageChange(newPageIndex);
+		    }
+        });
+		// RAP [bm]: no traverse listener
+//		newContainer.addTraverseListener(e -> {
+//			switch (e.detail) {
+//				case SWT.TRAVERSE_PAGE_NEXT:
+//				case SWT.TRAVERSE_PAGE_PREVIOUS:
+//					int detail = e.detail;
+//					e.doit = true;
+//					e.detail = SWT.TRAVERSE_NONE;
+//					Control control = newContainer.getParent();
+//					do {
+//						if (control.traverse(detail))
+//							return;
+//						if (control.getListeners(SWT.Traverse).length != 0)
+//							return;
+//						if (control instanceof Shell)
+//							return;
+//						control = control.getParent();
+//					} while (control != null);
+//			}
+//		});
+		return newContainer;
+	}
+
+	/**
+	 * Creates a tab item at the given index and places the given control in the
+	 * new item. The item is a CTabItem with no style bits set.
+	 *
+	 * @param index
+	 *            the index at which to add the control
+	 * @param control
+	 *            is the control to be placed in an item
+	 * @return a new item
+	 */
+	private CTabItem createItem(int index, Control control) {
+		CTabItem item = new CTabItem(getTabFolder(), SWT.NONE, index);
+		item.setControl(control);
+		return item;
+	}
+
+	/**
+	 * Creates the pages of this multi-page editor.
+	 * <p>
+	 * Subclasses must implement this method.
+	 * </p>
+	 */
+	protected abstract void createPages();
+
+	/**
+	 * The <code>MultiPageEditor</code> implementation of this
+	 * <code>IWorkbenchPart</code> method creates the control for the
+	 * multi-page editor by calling <code>createContainer</code>, then
+	 * <code>createPages</code>. Subclasses should implement
+	 * <code>createPages</code> rather than overriding this method.
+	 *
+	 * @param parent
+	 *            The parent in which the editor should be created; must not be
+	 *            <code>null</code>.
+	 */
+	@Override
+	public final void createPartControl(Composite parent) {
+		Composite pageContainer = createPageContainer(parent);
+		this.container = createContainer(pageContainer);
+		createPages();
+		// set the active page (page 0 by default), unless it has already been
+		// done
+		if (getActivePage() == -1) {
+			setActivePage(0);
+			IEditorPart part = getEditor(0);
+			if (part!=null) {
+				final IServiceLocator serviceLocator = part.getEditorSite();
+				if (serviceLocator instanceof INestable) {
+					activeServiceLocator = (INestable) serviceLocator;
+					activeServiceLocator.activate();
+				}
+			}
+		}
+		initializePageSwitching();
+		initializeSubTabSwitching();
+	}
+
+	/**
+	 * Initialize the MultiPageEditorPart to use the page switching command.
+	 * Clients can override this method with an empty body if they wish to
+	 * opt-out.
+	 *
+	 * @since 3.4
+	 */
+	protected void initializePageSwitching() {
+		new PageSwitcher(this) {
+			@Override
+			public Object[] getPages() {
+				int pageCount = getPageCount();
+				Object[] result = new Object[pageCount];
+				for (int i = 0; i < pageCount; i++) {
+					result[i] = Integer.valueOf(i);
+				}
+				return result;
+			}
+
+			@Override
+			public String getName(Object page) {
+				return getPageText(((Integer) page).intValue());
+			}
+
+			@Override
+			public ImageDescriptor getImageDescriptor(Object page) {
+				Image image = getPageImage(((Integer) page).intValue());
+				if (image == null)
+					return null;
+
+				return ImageDescriptor.createFromImage(image);
+			}
+
+			@Override
+			public void activatePage(Object page) {
+				setActivePage(((Integer) page).intValue());
+			}
+
+			@Override
+			public int getCurrentPageIndex() {
+				return getActivePage();
+			}
+		};
+	}
+
+	/**
+	 * Initialize the MultiPageEditorPart to use the sub-tab switching commands.
+	 *
+	 * @since 3.5
+	 */
+	private void initializeSubTabSwitching() {
+		IHandlerService service = getSite().getService(IHandlerService.class);
+		service.activateHandler(COMMAND_NEXT_SUB_TAB, new AbstractHandler() {
+			/**
+			 * {@inheritDoc}
+			 * @throws ExecutionException
+			 *             if an exception occurred during execution
+			 */
+			@Override
+			public Object execute(ExecutionEvent event) throws ExecutionException {
+				int n= getPageCount();
+				if (n == 0)
+					return null;
+
+				int i= getActivePage() + 1;
+				if (i >= n)
+					i= 0;
+				setActivePage(i);
+				return null;
+			}
+		});
+
+		service.activateHandler(COMMAND_PREVIOUS_SUB_TAB, new AbstractHandler() {
+			/**
+			 * {@inheritDoc}
+			 * @throws ExecutionException
+			 *             if an exception occurred during execution
+			 */
+			@Override
+			public Object execute(ExecutionEvent event) throws ExecutionException {
+				int n= getPageCount();
+				if (n == 0)
+					return null;
+
+				int i= getActivePage() - 1;
+				if (i < 0)
+					i= n - 1;
+				setActivePage(i);
+				return null;
+			}
+		});
+	}
+
+	/**
+	 * Creates the parent control for the container returned by
+	 * {@link #getContainer() }.
+	 *
+	 * <p>
+	 * Subclasses may extend and must call super implementation first.
+	 * </p>
+	 *
+	 * @param parent
+	 *            the parent for all of the editors contents.
+	 * @return the parent for this editor's container. Must not be
+	 *         <code>null</code>.
+	 *
+	 * @since 3.2
+	 */
+	protected Composite createPageContainer(Composite parent) {
+		return parent;
+	}
+
+	/**
+	 * Creates the site for the given nested editor. The
+	 * <code>MultiPageEditorPart</code> implementation of this method creates
+	 * an instance of <code>MultiPageEditorSite</code>. Subclasses may
+	 * reimplement to create more specialized sites.
+	 *
+	 * @param editor
+	 *            the nested editor
+	 * @return the editor site
+	 */
+	protected IEditorSite createSite(IEditorPart editor) {
+		return new MultiPageEditorSite(this, editor);
+	}
+
+	/**
+	 * The <code>MultiPageEditorPart</code> implementation of this
+	 * <code>IWorkbenchPart</code> method disposes all nested editors.
+	 * Subclasses may extend.
+	 */
+	@Override
+	public void dispose() {
+		deactivateSite(true, false);
+
+		pageChangeListeners.clear();
+		for (int i = 0; i < nestedEditors.size(); ++i) {
+			IEditorPart editor = (IEditorPart) nestedEditors.get(i);
+			disposePart(editor);
+		}
+		nestedEditors.clear();
+		if (pageContainerSite instanceof IDisposable) {
+			((IDisposable) pageContainerSite).dispose();
+			pageContainerSite = null;
+		}
+		for (int i = 0; i < pageSites.size(); i++) {
+			IServiceLocator sl = (IServiceLocator) pageSites.get(i);
+			if (sl instanceof IDisposable) {
+				((IDisposable) sl).dispose();
+			}
+		}
+		pageSites.clear();
+		super.dispose();
+	}
+
+	/**
+	 * Returns the active nested editor if there is one.
+	 * <p>
+	 * Subclasses should not override this method
+	 * </p>
+	 *
+	 * @nooverride
+	 * @return the active nested editor, or <code>null</code> if none
+	 */
+	protected IEditorPart getActiveEditor() {
+		int index = getActivePage();
+		if (index != -1) {
+			return getEditor(index);
+		}
+		return null;
+	}
+
+	/**
+	 * Returns the index of the currently active page, or -1 if there is no
+	 * active page.
+	 * <p>
+	 * Subclasses should not override this method
+	 * </p>
+	 *
+	 * @nooverride
+	 *
+	 * @return the index of the active page, or -1 if there is no active page
+	 * @since 3.5
+	 */
+	public int getActivePage() {
+		CTabFolder tabFolder = getTabFolder();
+		if (tabFolder != null && !tabFolder.isDisposed()) {
+			return tabFolder.getSelectionIndex();
+		}
+		return -1;
+	}
+
+	/**
+	 * Returns the composite control containing this multi-page editor's pages.
+	 * This should be used as the parent when creating controls for the
+	 * individual pages. That is, when calling <code>addPage(Control)</code>,
+	 * the passed control should be a child of this container.
+	 * <p>
+	 * Warning: Clients should not assume that the container is any particular
+	 * subclass of Composite. The actual class used may change in order to
+	 * improve the look and feel of multi-page editors. Any code making
+	 * assumptions on the particular subclass would thus be broken.
+	 * </p>
+	 * <p>
+	 * Subclasses should not override this method
+	 * </p>
+	 *
+	 * @return the composite, or <code>null</code> if
+	 *         <code>createPartControl</code> has not been called yet
+	 */
+	protected Composite getContainer() {
+		return container;
+	}
+
+	/**
+	 * Returns the control for the given page index, or <code>null</code> if
+	 * no control has been set for the page. The page index must be valid.
+	 * <p>
+	 * Subclasses should not override this method
+	 * </p>
+	 *
+	 * @param pageIndex
+	 *            the index of the page
+	 * @return the control for the specified page, or <code>null</code> if
+	 *         none has been set
+	 */
+	protected Control getControl(int pageIndex) {
+		return getItem(pageIndex).getControl();
+	}
+
+	/**
+	 * Returns the editor for the given page index. The page index must be
+	 * valid.
+	 *
+	 * @param pageIndex
+	 *            the index of the page
+	 * @return the editor for the specified page, or <code>null</code> if the
+	 *         specified page was not created with
+	 *         <code>addPage(IEditorPart,IEditorInput)</code>
+	 */
+	protected IEditorPart getEditor(int pageIndex) {
+		Item item = getItem(pageIndex);
+		if (item != null) {
+			Object data = item.getData();
+			if (data instanceof IEditorPart) {
+				return (IEditorPart) data;
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Returns the service locator for the given page index. This method can be
+	 * used to create service locators for pages that are just controls. The
+	 * page index must be valid.
+	 * <p>
+	 * This will return the editor site service locator for an editor, and
+	 * create one for a page that is just a control.
+	 * </p>
+	 *
+	 * @param pageIndex
+	 *            the index of the page
+	 * @return the editor for the specified page, or <code>null</code> if the
+	 *         specified page was not created with
+	 *         <code>addPage(IEditorPart,IEditorInput)</code>
+	 * @since 3.4
+	 */
+	protected final IServiceLocator getPageSite(int pageIndex) {
+		if (pageIndex == PAGE_CONTAINER_SITE) {
+			return getPageContainerSite();
+		}
+
+		Item item = getItem(pageIndex);
+		if (item != null) {
+			Object data = item.getData();
+			if (data instanceof IEditorPart) {
+				return ((IEditorPart) data).getSite();
+			} else if (data instanceof IServiceLocator) {
+				return (IServiceLocator) data;
+			} else if (data == null) {
+				IServiceLocatorCreator slc = getSite()
+						.getService(IServiceLocatorCreator.class);
+				IServiceLocator sl = slc.createServiceLocator(getSite(), null, () -> close());
+				item.setData(sl);
+				pageSites.add(sl);
+				return sl;
+			}
+		}
+		return null;
+	}
+
+	void close() {
+		// 3.x implementation closes the editor when the ISL is disposed
+		PartSite partSite = (PartSite) getSite();
+		MPart model = partSite.getModel();
+		Widget widget = (Widget) model.getWidget();
+		if (widget != null && !widget.isDisposed()) {
+			getSite().getPage().closeEditor(MultiPageEditorPart.this, true);
+		}
+	}
+
+	/**
+	 * @return A site that can be used with a header.
+	 * @since 3.4
+	 * @see #createPageContainer(Composite)
+	 * @see #PAGE_CONTAINER_SITE
+	 * @see #getPageSite(int)
+	 */
+	private IServiceLocator getPageContainerSite() {
+		if (pageContainerSite == null) {
+			IServiceLocatorCreator slc = getSite()
+					.getService(IServiceLocatorCreator.class);
+			pageContainerSite = slc.createServiceLocator(getSite(), null, () -> close());
+		}
+		return pageContainerSite;
+	}
+
+	/**
+	 * Returns the tab item for the given page index (page index is 0-based).
+	 * The page index must be valid.
+	 *
+	 * @param pageIndex
+	 *            the index of the page
+	 * @return the tab item for the given page index
+	 */
+	private CTabItem getItem(int pageIndex) {
+		return getTabFolder().getItem(pageIndex);
+	}
+
+	/**
+	 * Returns the number of pages in this multi-page editor.
+	 *
+	 * @return the number of pages
+	 */
+	protected int getPageCount() {
+		CTabFolder folder = getTabFolder();
+		// May not have been created yet, or may have been disposed.
+		if (folder != null && !folder.isDisposed()) {
+			return folder.getItemCount();
+		}
+		return 0;
+	}
+
+	/**
+	 * Returns the image for the page with the given index, or <code>null</code>
+	 * if no image has been set for the page. The page index must be valid.
+	 *
+	 * @param pageIndex
+	 *            the index of the page
+	 * @return the image, or <code>null</code> if none
+	 */
+	protected Image getPageImage(int pageIndex) {
+		return getItem(pageIndex).getImage();
+	}
+
+	/**
+	 * Returns the text label for the page with the given index. Returns the
+	 * empty string if no text label has been set for the page. The page index
+	 * must be valid.
+	 *
+	 * @param pageIndex
+	 *            the index of the page
+	 * @return the text label for the page
+	 */
+	protected String getPageText(int pageIndex) {
+		return getItem(pageIndex).getText();
+	}
+
+	/**
+	 * Returns the tab folder containing this multi-page editor's pages.
+	 *
+	 * @return the tab folder, or <code>null</code> if
+	 *         <code>createPartControl</code> has not been called yet
+	 */
+	private CTabFolder getTabFolder() {
+		return container;
+	}
+
+	/**
+	 * Handles a property change notification from a nested editor. The default
+	 * implementation simply forwards the change to listeners on this multi-page
+	 * editor by calling <code>firePropertyChange</code> with the same
+	 * property id. For example, if the dirty state of a nested editor changes
+	 * (property id <code>IEditorPart.PROP_DIRTY</code>), this method handles
+	 * it by firing a property change event for
+	 * <code>IEditorPart.PROP_DIRTY</code> to property listeners on this
+	 * multi-page editor.
+	 * <p>
+	 * Subclasses may extend or reimplement this method.
+	 * </p>
+	 *
+	 * @param propertyId
+	 *            the id of the property that changed
+	 */
+	protected void handlePropertyChange(int propertyId) {
+		firePropertyChange(propertyId);
+	}
+
+	/**
+	 * The <code>MultiPageEditorPart</code> implementation of this
+	 * <code>IEditorPart</code> method sets its site to the given site, its
+	 * input to the given input, and the site's selection provider to a
+	 * <code>MultiPageSelectionProvider</code>. Subclasses may extend this
+	 * method.
+	 *
+	 * @param site
+	 *            The site for which this part is being created; must not be
+	 *            <code>null</code>.
+	 * @param input
+	 *            The input on which this editor should be created; must not be
+	 *            <code>null</code>.
+	 * @throws PartInitException
+	 *             If the initialization of the part fails -- currently never.
+	 */
+	@Override
+	public void init(IEditorSite site, IEditorInput input)
+			throws PartInitException {
+		setSite(site);
+		setInput(input);
+		site.setSelectionProvider(new MultiPageSelectionProvider(this));
+	}
+
+	/**
+	 * The <code>MultiPageEditorPart</code> implementation of this
+	 * <code>IEditorPart</code> method returns whether the contents of any of
+	 * this multi-page editor's nested editors have changed since the last save.
+	 * Pages created with <code>addPage(Control)</code> are ignored.
+	 * <p>
+	 * Subclasses may extend or reimplement this method.
+	 * </p>
+	 *
+	 * @return <code>true</code> if any of the nested editors are dirty;
+	 *         <code>false</code> otherwise.
+	 */
+	@Override
+	public boolean isDirty() {
+		// use nestedEditors to avoid SWT requests; see bug 12996
+		for (Iterator i = nestedEditors.iterator(); i.hasNext();) {
+			IEditorPart editor = (IEditorPart) i.next();
+			if (editor.isDirty()) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Notifies this multi-page editor that the page with the given id has been
+	 * activated. This method is called when the user selects a different tab.
+	 * <p>
+	 * The <code>MultiPageEditorPart</code> implementation of this method sets
+	 * focus to the new page, and notifies the action bar contributor (if there
+	 * is one). This checks whether the action bar contributor is an instance of
+	 * <code>MultiPageEditorActionBarContributor</code>, and, if so, calls
+	 * <code>setActivePage</code> with the active nested editor. This also
+	 * fires a selection change event if required.
+	 * </p>
+	 * <p>
+	 * Subclasses may extend this method.
+	 * </p>
+	 *
+	 * @param newPageIndex
+	 *            the index of the activated page
+	 */
+	protected void pageChange(int newPageIndex) {
+		deactivateSite(false, false);
+
+		IPartService partService = getSite().getService(
+				IPartService.class);
+		if (partService.getActivePart() == this) {
+			setFocus();
+		}
+
+		IEditorPart activeEditor = getEditor(newPageIndex);
+
+		IEditorActionBarContributor contributor = getEditorSite()
+				.getActionBarContributor();
+		if (contributor != null
+				&& contributor instanceof MultiPageEditorActionBarContributor) {
+			((MultiPageEditorActionBarContributor) contributor)
+					.setActivePage(activeEditor);
+		}
+
+		if (activeEditor != null) {
+			ISelectionProvider selectionProvider = activeEditor.getSite()
+					.getSelectionProvider();
+			if (selectionProvider != null) {
+				ISelectionProvider outerProvider = getSite()
+						.getSelectionProvider();
+				if (outerProvider instanceof MultiPageSelectionProvider) {
+					SelectionChangedEvent event = new SelectionChangedEvent(
+							selectionProvider, selectionProvider.getSelection());
+
+					MultiPageSelectionProvider provider = (MultiPageSelectionProvider) outerProvider;
+					provider.fireSelectionChanged(event);
+					provider.firePostSelectionChanged(event);
+				} else {
+					if (Policy.DEBUG_MPE) {
+						Tracing.printTrace(TRACING_COMPONENT,
+								"MultiPageEditorPart " + getTitle() //$NON-NLS-1$
+										+ " did not propogate selection for " //$NON-NLS-1$
+										+ activeEditor.getTitle());
+					}
+				}
+			}
+		}
+
+		activateSite();
+		Object selectedPage = getSelectedPage();
+		if (selectedPage != null) {
+			firePageChanged(new PageChangedEvent(this, selectedPage));
+		}
+	}
+
+	/**
+	 * This method can be used by implementors of
+	 * {@link MultiPageEditorPart#createPageContainer(Composite)} to deactivate
+	 * the active inner editor services while their header has focus. A
+	 * deactivateSite() must have a matching call to activateSite() when
+	 * appropriate.
+	 * <p>
+	 * An new inner editor will have its site activated on a
+	 * {@link MultiPageEditorPart#pageChange(int)}.
+	 * </p>
+	 * <p>
+	 * <b>Note:</b> This API is evolving in 3.4 and this might not be its final
+	 * form.
+	 * </p>
+	 *
+	 * @param immediate
+	 *            immediately deactivate the legacy keybinding service
+	 * @param containerSiteActive
+	 *            Leave the page container site active.
+	 * @since 3.4
+	 * @see #activateSite()
+	 * @see #createPageContainer(Composite)
+	 * @see #getPageSite(int)
+	 * @see #PAGE_CONTAINER_SITE
+	 */
+	protected final void deactivateSite(boolean immediate,
+			boolean containerSiteActive) {
+		// Deactivate the nested services from the last active service locator.
+		if (activeServiceLocator != null) {
+			activeServiceLocator.deactivate();
+			activeServiceLocator = null;
+		}
+
+		final int pageIndex = getActivePage();
+		final IKeyBindingService service = getSite().getKeyBindingService();
+		if (pageIndex < 0 || pageIndex >= getPageCount() || immediate) {
+			// There is no selected page, so deactivate the active service.
+			if (service instanceof INestableKeyBindingService) {
+				final INestableKeyBindingService nestableService = (INestableKeyBindingService) service;
+				nestableService.activateKeyBindingService(null);
+			} else {
+				WorkbenchPlugin
+						.log("MultiPageEditorPart.deactivateSite()   Parent key binding service was not an instance of INestableKeyBindingService.  It was an instance of " + service.getClass().getName() + " instead."); //$NON-NLS-1$ //$NON-NLS-2$
+			}
+		}
+
+		if (containerSiteActive) {
+			IServiceLocator containerSite = getPageContainerSite();
+			if (containerSite instanceof INestable) {
+				activeServiceLocator = (INestable) containerSite;
+				activeServiceLocator.activate();
+			}
+		}
+	}
+
+	/**
+	 * This method can be used by implementors of
+	 * {@link #createPageContainer(Composite)} to activate the active inner
+	 * editor services when their header loses focus.
+	 * <p>
+	 * An new inner editor will have its site activated on a
+	 * {@link #pageChange(int)}.
+	 * </p>
+	 * <p>
+	 * <b>Note:</b> This API is evolving in 3.4 and this might not be its final
+	 * form.
+	 * </p>
+	 *
+	 * @since 3.4
+	 * @see #deactivateSite(boolean,boolean)
+	 * @see #createPageContainer(Composite)
+	 * @see #getPageSite(int)
+	 */
+	protected final void activateSite() {
+		if (activeServiceLocator != null) {
+			activeServiceLocator.deactivate();
+			activeServiceLocator = null;
+		}
+
+		final IKeyBindingService service = getSite().getKeyBindingService();
+		final int pageIndex = getActivePage();
+		final IEditorPart editor = getEditor(pageIndex);
+
+		if (editor != null) {
+			// active the service for this inner editor
+			if (service instanceof INestableKeyBindingService) {
+				final INestableKeyBindingService nestableService = (INestableKeyBindingService) service;
+				nestableService.activateKeyBindingService(editor
+						.getEditorSite());
+
+			} else {
+				WorkbenchPlugin
+						.log("MultiPageEditorPart.activateSite()   Parent key binding service was not an instance of INestableKeyBindingService.  It was an instance of " + service.getClass().getName() + " instead."); //$NON-NLS-1$ //$NON-NLS-2$
+			}
+			// Activate the services for the new service locator.
+			final IServiceLocator serviceLocator = editor.getEditorSite();
+			if (serviceLocator instanceof INestable) {
+				activeServiceLocator = (INestable) serviceLocator;
+				activeServiceLocator.activate();
+			}
+
+		} else {
+			Item item = getItem(pageIndex);
+
+			// There is no selected editor, so deactivate the active service.
+			if (service instanceof INestableKeyBindingService) {
+				final INestableKeyBindingService nestableService = (INestableKeyBindingService) service;
+				nestableService.activateKeyBindingService(null);
+			} else {
+				WorkbenchPlugin
+						.log("MultiPageEditorPart.activateSite()   Parent key binding service was not an instance of INestableKeyBindingService.  It was an instance of " + service.getClass().getName() + " instead."); //$NON-NLS-1$ //$NON-NLS-2$
+			}
+
+			if (item.getData() instanceof INestable) {
+				activeServiceLocator = (INestable) item.getData();
+				activeServiceLocator.activate();
+			}
+		}
+	}
+
+	/**
+	 * Disposes the given part and its site.
+	 *
+	 * @param part
+	 *            The part to dispose; must not be <code>null</code>.
+	 */
+	private void disposePart(final IWorkbenchPart part) {
+		SafeRunner.run(new ISafeRunnable() {
+			@Override
+			public void run() {
+				IWorkbenchPartSite partSite = part.getSite();
+				part.dispose();
+				if (partSite instanceof MultiPageEditorSite) {
+					((MultiPageEditorSite) partSite).dispose();
+				}
+			}
+
+			@Override
+			public void handleException(Throwable e) {
+				// Exception has already being logged by Core. Do nothing.
+			}
+		});
+	}
+
+	/**
+	 * Removes the page with the given index from this multi-page editor. The
+	 * controls for the page are disposed of; if the page has an editor, it is
+	 * disposed of too. The page index must be valid.
+	 *
+	 * @param pageIndex
+	 *            the index of the page
+	 * @see MultiPageEditorPart#addPage(Control)
+	 * @see MultiPageEditorPart#addPage(IEditorPart, IEditorInput)
+	 */
+	public void removePage(int pageIndex) {
+		Assert.isTrue(pageIndex >= 0 && pageIndex < getPageCount());
+		// get editor (if any) before disposing item
+		IEditorPart editor = getEditor(pageIndex);
+
+		// get control for the item if it's not an editor
+		CTabItem item = getItem(pageIndex);
+		IServiceLocator pageLocator = null;
+		if (item.getData() instanceof IServiceLocator) {
+			pageLocator = (IServiceLocator) item.getData();
+		}
+		Control pageControl = item.getControl();
+
+		// dispose item before disposing editor, in case there's an exception
+		// in editor's dispose
+		item.dispose();
+
+		if (pageControl != null) {
+			pageControl.dispose();
+		}
+
+		// dispose editor (if any)
+		if (editor != null) {
+			nestedEditors.remove(editor);
+			disposePart(editor);
+		}
+		if (pageLocator != null) {
+			pageSites.remove(pageLocator);
+			if (pageLocator instanceof IDisposable) {
+				((IDisposable) pageLocator).dispose();
+			}
+		}
+	}
+
+	/**
+	 * Sets the currently active page.
+	 *
+	 * @param pageIndex
+	 *            the index of the page to be activated; the index must be valid
+	 */
+	protected void setActivePage(int pageIndex) {
+		Assert.isTrue(pageIndex >= 0 && pageIndex < getPageCount());
+		getTabFolder().setSelection(pageIndex);
+		pageChange(pageIndex);
+	}
+
+	/**
+	 * Sets the control for the given page index. The page index must be valid.
+	 *
+	 * @param pageIndex
+	 *            the index of the page
+	 * @param control
+	 *            the control for the specified page, or <code>null</code> to
+	 *            clear the control
+	 */
+	protected void setControl(int pageIndex, Control control) {
+		getItem(pageIndex).setControl(control);
+	}
+
+	/**
+	 * The <code>MultiPageEditor</code> implementation of this
+	 * <code>IWorkbenchPart</code> method sets focus on the active nested
+	 * editor, if there is one.
+	 * <p>
+	 * Subclasses may extend or reimplement.
+	 * </p>
+	 */
+	@Override
+	public void setFocus() {
+		setFocus(getActivePage());
+	}
+
+	/**
+	 * Sets focus to the control for the given page. If the page has an editor,
+	 * this calls its <code>setFocus()</code> method. Otherwise, this calls
+	 * <code>setFocus</code> on the control for the page.
+	 *
+	 * @param pageIndex
+	 *            the index of the page
+	 */
+	private void setFocus(int pageIndex) {
+		if (pageIndex < 0 || pageIndex >= getPageCount()) {
+			// page index out of bounds, don't set focus.
+			return;
+		}
+		final IEditorPart editor = getEditor(pageIndex);
+		if (editor != null) {
+			editor.setFocus();
+
+		} else {
+			// Give the page's control focus.
+			final Control control = getControl(pageIndex);
+			if (control != null) {
+				control.setFocus();
+			}
+		}
+	}
+
+	/**
+	 * Sets the image for the page with the given index, or <code>null</code>
+	 * to clear the image for the page. The page index must be valid.
+	 *
+	 * @param pageIndex
+	 *            the index of the page
+	 * @param image
+	 *            the image, or <code>null</code>
+	 */
+	protected void setPageImage(int pageIndex, Image image) {
+		getItem(pageIndex).setImage(image);
+	}
+
+	/**
+	 * Sets the text label for the page with the given index. The page index
+	 * must be valid. The text label must not be null.
+	 *
+	 * @param pageIndex
+	 *            the index of the page
+	 * @param text
+	 *            the text label
+	 */
+	protected void setPageText(int pageIndex, String text) {
+		getItem(pageIndex).setText(text);
+	}
+
+	/**
+	 * If there is an adapter registered against the subclass of
+	 * MultiPageEditorPart return that. Otherwise, delegate to the internal
+	 * editor.
+	 *
+	 * @see org.eclipse.ui.part.WorkbenchPart#getAdapter(java.lang.Class)
+	 */
+	@Override
+	public <T> T getAdapter(Class<T> adapter) {
+		T result = super.getAdapter(adapter);
+		// restrict delegating to the UI thread for bug 144851
+		if (result == null && Display.getCurrent()!=null) {
+			IEditorPart innerEditor = getActiveEditor();
+			// see bug 138823 - prevent some subclasses from causing
+			// an infinite loop
+			if (innerEditor != null && innerEditor != this) {
+				result = Adapters.adapt(innerEditor, adapter);
+			}
+		}
+		return result;
+	}
+
+	/**
+	 * Find the editors contained in this multi-page editor
+	 * whose editor input match the provided input.
+	 * @param input the editor input
+	 * @return the editors contained in this multi-page editor
+	 * whose editor input match the provided input
+	 * @since 3.3
+	 */
+	public final IEditorPart[] findEditors(IEditorInput input) {
+		List result = new ArrayList();
+		int count = getPageCount();
+		for (int i = 0; i < count; i++) {
+			IEditorPart editor = getEditor(i);
+			if (editor != null
+					&& editor.getEditorInput() != null
+					&& editor.getEditorInput().equals(input)) {
+				result.add(editor);
+			}
+		}
+		return (IEditorPart[]) result.toArray(new IEditorPart[result.size()]);
+	}
+
+	/**
+	 * Set the active page of this multi-page editor to the
+	 * page that contains the given editor part. This method has
+	 * no effect of the given editor part is not contained in this
+	 * multi-page editor.
+	 * @param editorPart the editor part
+	 * @since 3.3
+	 */
+	public final void setActiveEditor(IEditorPart editorPart) {
+		int count = getPageCount();
+		for (int i = 0; i < count; i++) {
+			IEditorPart editor = getEditor(i);
+			if (editor == editorPart) {
+				setActivePage(i);
+				break;
+			}
+		}
+	}
+
+	/**
+	 * Returns the selected page for the current active page index, either the
+	 * IEditorPart for editors or the Control for other pages.
+	 * <p>
+	 * <b>Note:</b> clients may override this method to return a page
+	 * appropriate for their editors. Maybe be <code>null</code>.
+	 * </p>
+	 *
+	 * @return The IEditorPart or Control representing the current active page,
+	 *         or <code>null</code> if there are no active pages.
+	 * @since 3.5
+	 * @see #getActivePage()
+	 */
+	@Override
+	public Object getSelectedPage() {
+		int index = getActivePage();
+		if (index == -1) {
+			return null;
+		}
+		IEditorPart editor = getEditor(index);
+		if (editor != null) {
+			return editor;
+		}
+		return getControl(index);
+	}
+
+	/**
+	 * Add the page change listener to be notified when the page changes. The
+	 * newly selected page will be the Object returned from
+	 * {@link #getSelectedPage()}. In the default case, this will be the active
+	 * page Control, IEditorPart, or <code>null</code>.
+	 * <p>
+	 * This method has no effect if the listener has already been added.
+	 * </p>
+	 *
+	 * @nooverride
+	 *
+	 * @since 3.5
+	 */
+	@Override
+	public void addPageChangedListener(IPageChangedListener listener) {
+		pageChangeListeners.add(listener);
+	}
+
+	/**
+	 * Remove the page change listener.
+	 * <p>
+	 * This method has no effect if the listener is not in the list.
+	 * </p>
+	 *
+	 * @nooverride
+	 *
+	 * @since 3.5
+	 */
+	@Override
+	public void removePageChangedListener(IPageChangedListener listener) {
+		pageChangeListeners.remove(listener);
+	}
+
+	private void firePageChanged(final PageChangedEvent event) {
+		for (final IPageChangedListener l : pageChangeListeners) {
+			SafeRunnable.run(new SafeRunnable() {
+				@Override
+				public void run() {
+					l.pageChanged(event);
+				}
+			});
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/MultiPageEditorSite.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/MultiPageEditorSite.java
new file mode 100644
index 0000000..3e3cb3b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/MultiPageEditorSite.java
@@ -0,0 +1,592 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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.ui.part;
+
+import java.util.ArrayList;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.e4.core.contexts.ContextFunction;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.viewers.ILabelDecorator;
+import org.eclipse.jface.viewers.IPostSelectionProvider;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IEditorActionBarContributor;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.IKeyBindingService;
+import org.eclipse.ui.INestableKeyBindingService;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.contexts.IContextService;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.internal.KeyBindingService;
+import org.eclipse.ui.internal.PartSite;
+import org.eclipse.ui.internal.PopupMenuExtender;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.contexts.NestableContextService;
+import org.eclipse.ui.internal.expressions.ActivePartExpression;
+import org.eclipse.ui.internal.handlers.LegacyHandlerService;
+import org.eclipse.ui.internal.part.IMultiPageEditorSiteHolder;
+import org.eclipse.ui.internal.services.INestable;
+import org.eclipse.ui.internal.services.IServiceLocatorCreator;
+import org.eclipse.ui.internal.services.IWorkbenchLocationService;
+import org.eclipse.ui.internal.services.ServiceLocator;
+import org.eclipse.ui.internal.services.WorkbenchLocationService;
+import org.eclipse.ui.services.IServiceScopes;
+
+/**
+ * Site for a nested editor within a multi-page editor. Selection is handled by
+ * forwarding the event to the multi-page editor's selection listeners; most
+ * other methods are forwarded to the multi-page editor's site.
+ * <p>
+ * The base implementation of <code>MultiPageEditor.createSite</code> creates
+ * an instance of this class. This class may be instantiated or subclassed.
+ * </p>
+ */
+public class MultiPageEditorSite implements IEditorSite, INestable {
+
+	/**
+	 * The nested editor.
+	 */
+	private IEditorPart editor;
+
+	/**
+	 * The list of popup menu extenders; <code>null</code> if none registered.
+	 */
+	private ArrayList menuExtenders;
+
+	/**
+	 * The multi-page editor.
+	 */
+	private MultiPageEditorPart multiPageEditor;
+
+	/**
+	 * The post selection changed listener.
+	 */
+	private ISelectionChangedListener postSelectionChangedListener = null;
+
+	/**
+	 * The selection change listener, initialized lazily; <code>null</code> if
+	 * not yet created.
+	 */
+	private ISelectionChangedListener selectionChangedListener = null;
+
+	/**
+	 * The selection provider; <code>null</code> if none.
+	 *
+	 * @see MultiPageEditorSite#setSelectionProvider(ISelectionProvider)
+	 */
+	private ISelectionProvider selectionProvider = null;
+
+	/**
+	 * The cached copy of the key binding service specific to this multi-page
+	 * editor site. This value is <code>null</code> if it is not yet
+	 * initialized.
+	 */
+	private IKeyBindingService service = null;
+
+	/**
+	 * The local service locator for this multi-page editor site. This value is
+	 * never <code>null</code>.
+	 */
+	private final ServiceLocator serviceLocator;
+
+	private NestableContextService contextService;
+
+	private IEclipseContext context;
+
+	private boolean active = false;
+
+	/**
+	 * Creates a site for the given editor nested within the given multi-page
+	 * editor.
+	 *
+	 * @param multiPageEditor
+	 *            the multi-page editor
+	 * @param editor
+	 *            the nested editor
+	 */
+	public MultiPageEditorSite(MultiPageEditorPart multiPageEditor,
+			IEditorPart editor) {
+		Assert.isNotNull(multiPageEditor);
+		Assert.isNotNull(editor);
+		this.multiPageEditor = multiPageEditor;
+		this.editor = editor;
+
+		PartSite site = (PartSite) multiPageEditor.getSite();
+
+		IServiceLocatorCreator slc = site
+				.getService(IServiceLocatorCreator.class);
+		context = site.getModel().getContext().createChild("MultiPageEditorSite"); //$NON-NLS-1$
+		serviceLocator = (ServiceLocator) slc.createServiceLocator(
+				multiPageEditor.getSite(), null, () -> getMultiPageEditor().close(), context);
+
+		initializeDefaultServices();
+	}
+
+	/**
+	 * Initialize the slave services for this site.
+	 */
+	private void initializeDefaultServices() {
+		serviceLocator.registerService(IWorkbenchLocationService.class,
+				new WorkbenchLocationService(IServiceScopes.MPESITE_SCOPE,
+						getWorkbenchWindow().getWorkbench(),
+						getWorkbenchWindow(), getMultiPageEditor().getSite(),
+						this, null, 3));
+		serviceLocator.registerService(IMultiPageEditorSiteHolder.class,
+				(IMultiPageEditorSiteHolder) () -> MultiPageEditorSite.this);
+
+		context.set(IContextService.class.getName(), new ContextFunction() {
+			@Override
+			public Object compute(IEclipseContext ctxt, String contextKey) {
+				if (contextService == null) {
+					contextService = new NestableContextService(ctxt.getParent().get(
+							IContextService.class), new ActivePartExpression(multiPageEditor));
+				}
+				return contextService;
+			}
+		});
+
+		// create a local handler service so that when this page
+		// activates/deactivates, its handlers will also be taken into/out of
+		// consideration during handler lookups
+		IHandlerService handlerService = new LegacyHandlerService(context);
+		context.set(IHandlerService.class, handlerService);
+	}
+
+	/**
+	 * Notifies the multi page editor service that the component within which it
+	 * exists has become active.
+	 *
+	 * @since 3.2
+	 */
+	@Override
+	public final void activate() {
+		active = true;
+		context.activate();
+		serviceLocator.activate();
+
+		if (contextService != null) {
+			contextService.activate();
+		}
+	}
+
+	/**
+	 * Notifies the multi page editor service that the component within which it
+	 * exists has been deactived.
+	 *
+	 * @since 3.2
+	 */
+	@Override
+	public final void deactivate() {
+		active = false;
+		if (contextService != null) {
+			contextService.deactivate();
+		}
+
+		serviceLocator.deactivate();
+		context.deactivate();
+	}
+
+	/**
+	 * Dispose the contributions.
+	 */
+	public void dispose() {
+		if (menuExtenders != null) {
+			for (int i = 0; i < menuExtenders.size(); i++) {
+				((PopupMenuExtender) menuExtenders.get(i)).dispose();
+			}
+			menuExtenders = null;
+		}
+
+		// Remove myself from the list of nested key binding services.
+		if (service != null) {
+			IKeyBindingService parentService = getMultiPageEditor().getEditorSite()
+					.getKeyBindingService();
+			if (parentService instanceof INestableKeyBindingService) {
+				INestableKeyBindingService nestableParent = (INestableKeyBindingService) parentService;
+				nestableParent.removeKeyBindingService(this);
+			}
+			if (service instanceof KeyBindingService) {
+				((KeyBindingService) service).dispose();
+			}
+			service = null;
+		}
+
+		if (contextService != null) {
+			contextService.dispose();
+		}
+
+		if (serviceLocator != null) {
+			serviceLocator.dispose();
+		}
+		context.dispose();
+	}
+
+	/**
+	 * The <code>MultiPageEditorSite</code> implementation of this
+	 * <code>IEditorSite</code> method returns <code>null</code>, since
+	 * nested editors do not have their own action bar contributor.
+	 *
+	 * @return <code>null</code>
+	 */
+	@Override
+	public IEditorActionBarContributor getActionBarContributor() {
+		return null;
+	}
+
+	/**
+	 * The <code>MultiPageEditorSite</code> implementation of this
+	 * <code>IEditorSite</code> method forwards to the multi-page editor to
+	 * return the action bars.
+	 *
+	 * @return The action bars from the parent multi-page editor.
+	 */
+	@Override
+	public IActionBars getActionBars() {
+		return multiPageEditor.getEditorSite().getActionBars();
+	}
+
+	@Override
+	public <T> T getAdapter(Class<T> adapter) {
+		return null;
+	}
+
+	/**
+	 * The <code>MultiPageEditorSite</code> implementation of this
+	 * <code>IWorkbenchPartSite</code> method forwards to the multi-page
+	 * editor to return the decorator manager.
+	 *
+	 * @return The decorator from the workbench window.
+	 * @deprecated use IWorkbench.getDecoratorManager()
+	 */
+	@Deprecated
+	public ILabelDecorator getDecoratorManager() {
+		return getWorkbenchWindow().getWorkbench().getDecoratorManager()
+				.getLabelDecorator();
+	}
+
+	/**
+	 * Returns the nested editor.
+	 *
+	 * @return the nested editor
+	 */
+	public IEditorPart getEditor() {
+		return editor;
+	}
+
+	/**
+	 * The <code>MultiPageEditorSite</code> implementation of this
+	 * <code>IWorkbenchPartSite</code> method returns an empty string since
+	 * the nested editor is not created from the registry.
+	 *
+	 * @return An empty string.
+	 */
+	@Override
+	public String getId() {
+		return ""; //$NON-NLS-1$
+	}
+
+	@Override
+	public IKeyBindingService getKeyBindingService() {
+		if (service == null) {
+			service = getMultiPageEditor().getEditorSite()
+					.getKeyBindingService();
+			if (service instanceof INestableKeyBindingService) {
+				INestableKeyBindingService nestableService = (INestableKeyBindingService) service;
+				service = nestableService.getKeyBindingService(this);
+
+			} else {
+				/*
+				 * This is an internal reference, and should not be copied by
+				 * client code. If you are thinking of copying this, DON'T DO
+				 * IT.
+				 */
+				WorkbenchPlugin
+						.log("MultiPageEditorSite.getKeyBindingService()   Parent key binding service was not an instance of INestableKeyBindingService.  It was an instance of " + service.getClass().getName() + " instead."); //$NON-NLS-1$ //$NON-NLS-2$
+			}
+		}
+		return service;
+	}
+
+	/**
+	 * Returns the multi-page editor.
+	 *
+	 * @return the multi-page editor
+	 */
+	public MultiPageEditorPart getMultiPageEditor() {
+		return multiPageEditor;
+	}
+
+	/**
+	 * The <code>MultiPageEditorSite</code> implementation of this
+	 * <code>IWorkbenchPartSite</code> method forwards to the multi-page
+	 * editor to return the workbench page.
+	 *
+	 * @return The workbench page in which this editor site resides.
+	 */
+	@Override
+	public IWorkbenchPage getPage() {
+		return getMultiPageEditor().getSite().getPage();
+	}
+
+	@Override
+	public IWorkbenchPart getPart() {
+		return editor;
+	}
+
+	/**
+	 * The <code>MultiPageEditorSite</code> implementation of this
+	 * <code>IWorkbenchPartSite</code> method returns an empty string since
+	 * the nested editor is not created from the registry.
+	 *
+	 * @return An empty string.
+	 */
+	@Override
+	public String getPluginId() {
+		return ""; //$NON-NLS-1$
+	}
+
+	/**
+	 * Returns the post selection change listener which listens to the nested
+	 * editor's selection changes.
+	 *
+	 * @return the post selection change listener.
+	 */
+	private ISelectionChangedListener getPostSelectionChangedListener() {
+		if (postSelectionChangedListener == null) {
+			postSelectionChangedListener = event -> MultiPageEditorSite.this.handlePostSelectionChanged(event);
+		}
+		return postSelectionChangedListener;
+	}
+
+	/**
+	 * The <code>MultiPageEditorSite</code> implementation of this
+	 * <code>IWorkbenchPartSite</code> method returns an empty string since
+	 * the nested editor is not created from the registry.
+	 *
+	 * @return An empty string.
+	 */
+	@Override
+	public String getRegisteredName() {
+		return ""; //$NON-NLS-1$
+	}
+
+	/**
+	 * Returns the selection changed listener which listens to the nested
+	 * editor's selection changes, and calls <code>handleSelectionChanged</code>.
+	 *
+	 * @return the selection changed listener
+	 */
+	private ISelectionChangedListener getSelectionChangedListener() {
+		if (selectionChangedListener == null) {
+			selectionChangedListener = event -> MultiPageEditorSite.this.handleSelectionChanged(event);
+		}
+		return selectionChangedListener;
+	}
+
+	/**
+	 * The <code>MultiPageEditorSite</code> implementation of this
+	 * <code>IWorkbenchPartSite</code> method returns the selection provider
+	 * set by <code>setSelectionProvider</code>.
+	 *
+	 * @return The current selection provider.
+	 */
+	@Override
+	public ISelectionProvider getSelectionProvider() {
+		return selectionProvider;
+	}
+
+	@Override
+	public final <T> T getService(final Class<T> key) {
+		T service = serviceLocator.getService(key);
+		if (active && service instanceof INestable) {
+			// services need to know that it is currently in an active state
+			((INestable) service).activate();
+		}
+		return service;
+	}
+
+	/**
+	 * The <code>MultiPageEditorSite</code> implementation of this
+	 * <code>IWorkbenchPartSite</code> method forwards to the multi-page
+	 * editor to return the shell.
+	 *
+	 * @return The shell in which this editor site resides.
+	 */
+	@Override
+	public Shell getShell() {
+		return getMultiPageEditor().getSite().getShell();
+	}
+
+	/**
+	 * The <code>MultiPageEditorSite</code> implementation of this
+	 * <code>IWorkbenchPartSite</code> method forwards to the multi-page
+	 * editor to return the workbench window.
+	 *
+	 * @return The workbench window in which this editor site resides.
+	 */
+	@Override
+	public IWorkbenchWindow getWorkbenchWindow() {
+		return getMultiPageEditor().getSite().getWorkbenchWindow();
+	}
+
+	/**
+	 * Handles a post selection changed even from the nexted editor.
+	 * <p>
+	 * Subclasses may extend or reimplement this method
+	 *
+	 * @param event  the event
+	 *
+	 * @since 3.2
+	 */
+	protected void handlePostSelectionChanged(SelectionChangedEvent event) {
+		ISelectionProvider parentProvider = getMultiPageEditor().getSite()
+				.getSelectionProvider();
+		if (parentProvider instanceof MultiPageSelectionProvider) {
+			SelectionChangedEvent newEvent = new SelectionChangedEvent(
+					parentProvider, event.getSelection());
+			MultiPageSelectionProvider prov = (MultiPageSelectionProvider) parentProvider;
+			prov.firePostSelectionChanged(newEvent);
+		}
+	}
+
+	/**
+	 * Handles a selection changed event from the nested editor. The default
+	 * implementation gets the selection provider from the multi-page editor's
+	 * site, and calls <code>fireSelectionChanged</code> on it (only if it is
+	 * an instance of <code>MultiPageSelectionProvider</code>), passing a new
+	 * event object.
+	 * <p>
+	 * Subclasses may extend or reimplement this method.
+	 * </p>
+	 *
+	 * @param event
+	 *            the event
+	 */
+	protected void handleSelectionChanged(SelectionChangedEvent event) {
+		ISelectionProvider parentProvider = getMultiPageEditor().getSite()
+				.getSelectionProvider();
+		if (parentProvider instanceof MultiPageSelectionProvider) {
+			SelectionChangedEvent newEvent = new SelectionChangedEvent(
+					parentProvider, event.getSelection());
+			MultiPageSelectionProvider prov = (MultiPageSelectionProvider) parentProvider;
+			prov.fireSelectionChanged(newEvent);
+		}
+	}
+
+	@Override
+	public final boolean hasService(final Class key) {
+		return serviceLocator.hasService(key);
+	}
+
+	/**
+	 * The <code>MultiPageEditorSite</code> implementation of this
+	 * <code>IWorkbenchPartSite</code> method forwards to the multi-page
+	 * editor for registration.
+	 *
+	 * @param menuManager
+	 *            The menu manager
+	 * @param selProvider
+	 *            The selection provider.
+	 */
+	@Override
+	public void registerContextMenu(MenuManager menuManager,
+			ISelectionProvider selProvider) {
+		getMultiPageEditor().getSite().registerContextMenu(menuManager,
+				selProvider);
+	}
+
+	@Override
+	public final void registerContextMenu(final MenuManager menuManager,
+			final ISelectionProvider selectionProvider,
+			final boolean includeEditorInput) {
+		registerContextMenu(getId(), menuManager, selectionProvider,
+				includeEditorInput);
+	}
+
+	/**
+	 * The <code>MultiPageEditorSite</code> implementation of this
+	 * <code>IWorkbenchPartSite</code> method forwards to the multi-page
+	 * editor for registration.
+	 *
+	 * @param menuID
+	 *            The identifier for the menu.
+	 * @param menuMgr
+	 *            The menu manager
+	 * @param selProvider
+	 *            The selection provider.
+	 */
+	@Override
+	public void registerContextMenu(String menuID, MenuManager menuMgr,
+			ISelectionProvider selProvider) {
+		if (menuExtenders == null) {
+			menuExtenders = new ArrayList(1);
+		}
+		PartSite.registerContextMenu(menuID, menuMgr, selProvider, true, editor, context,
+				menuExtenders);
+	}
+
+	@Override
+	public final void registerContextMenu(final String menuId,
+			final MenuManager menuManager,
+			final ISelectionProvider selectionProvider,
+			final boolean includeEditorInput) {
+		if (menuExtenders == null) {
+			menuExtenders = new ArrayList(1);
+		}
+		PartSite.registerContextMenu(menuId, menuManager, selectionProvider, includeEditorInput,
+				editor, context, menuExtenders);
+	}
+
+	/**
+	 * The <code>MultiPageEditorSite</code> implementation of this
+	 * <code>IWorkbenchPartSite</code> method remembers the selection
+	 * provider, and also hooks a listener on it, which calls
+	 * <code>handleSelectionChanged</code> when a selection changed event
+	 * occurs.
+	 *
+	 * @param provider
+	 *            The selection provider.
+	 * @see MultiPageEditorSite#handleSelectionChanged(SelectionChangedEvent)
+	 */
+	@Override
+	public void setSelectionProvider(ISelectionProvider provider) {
+		ISelectionProvider oldSelectionProvider = selectionProvider;
+		selectionProvider = provider;
+		if (oldSelectionProvider != null) {
+			oldSelectionProvider
+					.removeSelectionChangedListener(getSelectionChangedListener());
+			if (oldSelectionProvider instanceof IPostSelectionProvider) {
+				((IPostSelectionProvider) oldSelectionProvider)
+						.removePostSelectionChangedListener(getPostSelectionChangedListener());
+			} else {
+				oldSelectionProvider
+						.removeSelectionChangedListener(getPostSelectionChangedListener());
+			}
+		}
+		if (selectionProvider != null) {
+			selectionProvider
+					.addSelectionChangedListener(getSelectionChangedListener());
+			if (selectionProvider instanceof IPostSelectionProvider) {
+				((IPostSelectionProvider) selectionProvider)
+						.addPostSelectionChangedListener(getPostSelectionChangedListener());
+			} else {
+				selectionProvider.addSelectionChangedListener(getPostSelectionChangedListener());
+			}
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/MultiPageSelectionProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/MultiPageSelectionProvider.java
new file mode 100644
index 0000000..d3f8ad0
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/MultiPageSelectionProvider.java
@@ -0,0 +1,163 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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.ui.part;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.jface.util.SafeRunnable;
+import org.eclipse.jface.viewers.IPostSelectionProvider;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.ui.IEditorPart;
+
+/**
+ * Manages the current selection in a multi-page editor by tracking the active
+ * nested editor within the multi-page editor. When the selection changes,
+ * notifications are sent to all registered listeners.
+ * <p>
+ * This class may be instantiated; it is not intended to be subclassed.
+ * The base implementation of <code>MultiPageEditor.init</code> creates
+ * an instance of this class.
+ * </p>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class MultiPageSelectionProvider implements IPostSelectionProvider {
+
+    /**
+     * Registered selection changed listeners (element type:
+     * <code>ISelectionChangedListener</code>).
+     */
+	private ListenerList<ISelectionChangedListener> listeners = new ListenerList<>();
+
+    /**
+     * Registered post selection changed listeners.
+     */
+	private ListenerList<ISelectionChangedListener> postListeners = new ListenerList<>();
+
+    /**
+     * The multi-page editor.
+     */
+    private MultiPageEditorPart multiPageEditor;
+
+    /**
+     * Creates a selection provider for the given multi-page editor.
+     *
+     * @param multiPageEditor the multi-page editor
+     */
+    public MultiPageSelectionProvider(MultiPageEditorPart multiPageEditor) {
+        Assert.isNotNull(multiPageEditor);
+        this.multiPageEditor = multiPageEditor;
+    }
+
+    @Override
+	public void addSelectionChangedListener(ISelectionChangedListener listener) {
+        listeners.add(listener);
+    }
+
+    /**
+     * Adds a listener for post selection changes in this multi page selection provider.
+     *
+     * @param listener a selection changed listener
+     * @since 3.2
+     */
+    @Override
+	public void addPostSelectionChangedListener(ISelectionChangedListener listener) {
+    	postListeners.add(listener);
+	}
+
+	/**
+     * Notifies all registered selection changed listeners that the editor's
+     * selection has changed. Only listeners registered at the time this method is
+     * called are notified.
+     *
+     * @param event the selection changed event
+     */
+    public void fireSelectionChanged(final SelectionChangedEvent event) {
+        fireEventChange(event, listeners);
+    }
+
+    /**
+     * Notifies all post selection changed listeners that the editor's
+     * selection has changed.
+     *
+     * @param event the event to propogate.
+     * @since 3.2
+     */
+    public void firePostSelectionChanged(final SelectionChangedEvent event) {
+		fireEventChange(event, postListeners);
+	}
+
+	private void fireEventChange(final SelectionChangedEvent event,
+			ListenerList<ISelectionChangedListener> listenersList) {
+		for (final ISelectionChangedListener l : listenersList) {
+            SafeRunner.run(new SafeRunnable() {
+                @Override
+				public void run() {
+                    l.selectionChanged(event);
+                }
+            });
+        }
+	}
+
+    /**
+	 * Returns the multi-page editor.
+	 * @return the multi-page editor.
+	 */
+    public MultiPageEditorPart getMultiPageEditor() {
+        return multiPageEditor;
+    }
+
+    @Override
+	public ISelection getSelection() {
+        IEditorPart activeEditor = multiPageEditor.getActiveEditor();
+        if (activeEditor != null) {
+            ISelectionProvider selectionProvider = activeEditor.getSite()
+                    .getSelectionProvider();
+            if (selectionProvider != null) {
+				return selectionProvider.getSelection();
+			}
+        }
+        return StructuredSelection.EMPTY;
+    }
+
+    @Override
+	public void removeSelectionChangedListener(
+            ISelectionChangedListener listener) {
+        listeners.remove(listener);
+    }
+
+    /**
+     * Removes a listener for post selection changes in this multi page selection provider.
+     *
+     * @param listener a selection changed listener
+     * @since 3.2
+     */
+    @Override
+	public void removePostSelectionChangedListener(ISelectionChangedListener listener) {
+    	postListeners.remove(listener);
+	}
+
+    @Override
+	public void setSelection(ISelection selection) {
+        IEditorPart activeEditor = multiPageEditor.getActiveEditor();
+        if (activeEditor != null) {
+            ISelectionProvider selectionProvider = activeEditor.getSite()
+                    .getSelectionProvider();
+            if (selectionProvider != null) {
+				selectionProvider.setSelection(selection);
+			}
+        }
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/Page.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/Page.java
new file mode 100644
index 0000000..172a7fe
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/Page.java
@@ -0,0 +1,131 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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.ui.part;
+
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.IStatusLineManager;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IActionBars;
+
+/**
+ * Abstract base superclass for pages in a pagebook view.
+ * <p>
+ * This class should be subclassed by clients wishing to define new types
+ * of pages for multi-page views.
+ * </p>
+ * <p>
+ * Subclasses must implement the following methods:
+ * <ul>
+ *   <li><code>createControl</code> - to create the page's control</li>
+ *   <li><code>getControl</code> - to retrieve the page's control</li>
+ * </ul>
+ * </p>
+ * <p>
+ * Subclasses may extend or reimplement the following methods as required:
+ * <ul>
+ *   <li><code>dispose</code> - extend to provide additional cleanup</li>
+ *   <li><code>setFocus</code> - reimplement to accept focus</li>
+ *   <li><code>setActionBars</code> - reimplement to make contributions</li>
+ *   <li><code>makeContributions</code> - this method exists to support previous versions</li>
+ *   <li><code>setActionBars</code> - this method exists to support previous versions</li>
+ *   <li><code>init</code> - extend to provide additional setup</li>
+ * </ul>
+ * </p>
+ *
+ * @see PageBookView
+ */
+public abstract class Page implements IPageBookViewPage {
+    /**
+     * The site which contains this page
+     */
+    private IPageSite site;
+
+    /*
+     * Creates a new page for a pagebook view.
+     */
+    protected Page() {
+    }
+
+    @Override
+	public abstract void createControl(Composite parent);
+
+    /**
+     * The <code>Page</code> implementation of this <code>IPage</code> method
+     * disposes of this page's control (if it has one and it has not already
+     * been disposed). Subclasses may extend.
+     */
+    @Override
+	public void dispose() {
+        Control ctrl = getControl();
+        if (ctrl != null && !ctrl.isDisposed()) {
+			ctrl.dispose();
+		}
+    }
+
+    /**
+     * The <code>Page</code> implementation of this <code>IPage</code> method returns
+     * <code>null</code>. Subclasses must reimplement.
+     */
+    @Override
+    public abstract Control getControl();
+
+    /**
+	 * This method exists for backward compatibility. Subclasses should
+	 * reimplement <code>init</code>.
+	 */
+    public void makeContributions(IMenuManager menuManager,
+            IToolBarManager toolBarManager, IStatusLineManager statusLineManager) {
+    }
+
+    /**
+	 * This method exists for backward compatibility. Subclasses should
+	 * reimplement <code>init</code>.
+	 */
+    @Override
+    public void setActionBars(IActionBars actionBars) {
+        makeContributions(actionBars.getMenuManager(), actionBars
+                .getToolBarManager(), actionBars.getStatusLineManager());
+    }
+
+    /**
+     * The <code>Page</code> implementation of this <code>IPageBookViewPage</code> method
+     * stores a reference to the supplied site (the site which contains this
+     * page).
+     * <p>
+     * Subclasses may extend.
+     * </p>
+     *
+     * @since 2.0
+     */
+    @Override
+    public void init(IPageSite pageSite) {
+        site = pageSite;
+    }
+
+    /**
+     * Returns the site which contains this page.
+     *
+     * @return the site which contains this page
+     */
+    @Override
+    public IPageSite getSite() {
+        return site;
+    }
+
+    /**
+     * The <code>Page</code> implementation of this <code>IPage</code> method
+     * does nothing. Subclasses must implement.
+     */
+    @Override
+	public abstract void setFocus();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/PageBook.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/PageBook.java
new file mode 100644
index 0000000..53d8dea
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/PageBook.java
@@ -0,0 +1,115 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2014 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.ui.part;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Layout;
+
+/**
+ * A pagebook is a composite control where only a single control is visible
+ * at a time. It is similar to a notebook, but without tabs.
+ * <p>
+ * This class may be instantiated; it is not intended to be subclassed.
+ * </p>
+ * <p>
+ * Note that although this class is a subclass of <code>Composite</code>,
+ * it does not make sense to set a layout on it.
+ * </p>
+ *
+ * @see PageBookView
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class PageBook extends Composite {
+
+    /**
+     * <p>
+     * [Issue: This class should be declared private.]
+     * </p>
+     */
+    public class PageBookLayout extends Layout {
+
+        @Override
+		protected Point computeSize(Composite composite, int wHint, int hHint,
+                boolean flushCache) {
+            if (wHint != SWT.DEFAULT && hHint != SWT.DEFAULT) {
+				return new Point(wHint, hHint);
+			}
+
+            Point result = null;
+            if (currentPage != null) {
+                result = currentPage.computeSize(wHint, hHint, flushCache);
+            } else {
+                //Rectangle rect= composite.getClientArea();
+                //result= new Point(rect.width, rect.height);
+                result = new Point(0, 0);
+            }
+            if (wHint != SWT.DEFAULT) {
+				result.x = wHint;
+			}
+            if (hHint != SWT.DEFAULT) {
+				result.y = hHint;
+			}
+            return result;
+        }
+
+        @Override
+		protected void layout(Composite composite, boolean flushCache) {
+			if (currentPage != null && !currentPage.isDisposed()) {
+                currentPage.setBounds(composite.getClientArea());
+            }
+        }
+    }
+
+    /**
+     * The current control; <code>null</code> if none.
+     */
+    private Control currentPage = null;
+
+    /**
+     * Creates a new empty pagebook.
+     *
+     * @param parent the parent composite
+     * @param style the SWT style bits
+     */
+    public PageBook(Composite parent, int style) {
+        super(parent, style);
+        setLayout(new PageBookLayout());
+    }
+
+    /**
+     * Shows the given page. This method has no effect if the given page is not
+     * contained in this pagebook.
+     *
+     * @param page the page to show
+     */
+    public void showPage(Control page) {
+		if (page.isDisposed() || page.getParent() != this) {
+			return;
+		}
+
+		currentPage = page;
+
+        // show new page
+		page.setVisible(true);
+		layout(true);
+
+		// hide old (and all others) *after* new page has been made visible in
+		// order to avoid flashing
+		for (Control child : getChildren()) {
+			if (child != page && !child.isDisposed()) {
+				child.setVisible(false);
+			}
+		}
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/PageBookView.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/PageBookView.java
new file mode 100644
index 0000000..6b9ad73
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/PageBookView.java
@@ -0,0 +1,1123 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.part;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import org.eclipse.core.commands.common.EventManager;
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.SafeRunnable;
+import org.eclipse.jface.viewers.IPostSelectionProvider;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IPartListener;
+import org.eclipse.ui.IPartListener2;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IViewSite;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartReference;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.SubActionBars;
+import org.eclipse.ui.internal.WorkbenchPage;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+
+/**
+ * Abstract superclass of all multi-page workbench views.
+ * <p>
+ * Within the workbench there are many views which track the active part. If a
+ * part is activated these views display some properties for the active part. A
+ * simple example is the <code>Outline View</code>, which displays the
+ * outline for the active editor. To avoid loss of context when part activation
+ * changes, these views may implement a multi-page approach. A separate page is
+ * maintained within the view for each source view. If a part is activated the
+ * associated page for the part is brought to top. If a part is closed the
+ * associated page is disposed. <code>PageBookView</code> is a base
+ * implementation for multi page views.
+ * </p>
+ * <p>
+ * <code>PageBookView</code>s provide an <code>IPageSite</code> for each of
+ * their pages. This site is supplied during the page's initialization. The page
+ * may supply a selection provider for this site. <code>PageBookView</code>s
+ * deal with these selection providers in a similar way to a workbench page's
+ * <code>SelectionService</code>. When a page is made visible, if its site
+ * has a selection provider, then changes in the selection are listened for and
+ * the current selection is obtained and fired as a selection change event.
+ * Selection changes are no longer listened for when a page is made invisible.
+ * </p>
+ * <p>
+ * This class should be subclassed by clients wishing to define new multi-page
+ * views.
+ * </p>
+ * <p>
+ * When a <code>PageBookView</code> is created the following methods are
+ * invoked. Subclasses must implement these.
+ * <ul>
+ * <li><code>createDefaultPage</code> - called to create a default page for
+ * the view. This page is displayed when the active part in the workbench does
+ * not have a page.</li>
+ * <li><code>getBootstrapPart</code> - called to determine the active part in
+ * the workbench. A page will be created for this part</li>
+ * </ul>
+ * </p>
+ * <p>
+ * When a part is activated the base implementation does not know if a page
+ * should be created for the part. Therefore, it delegates creation to the
+ * subclass.
+ * <ul>
+ * <li><code>isImportant</code> - called when a workbench part is activated.
+ * Subclasses return whether a page should be created for the new part.</li>
+ * <li><code>doCreatePage</code> - called to create a page for a particular
+ * part in the workbench. This is only invoked when <code>isImportant</code>
+ * returns </code>true</code>.</li>
+ * </ul>
+ * </p>
+ * <p>
+ * When a part is closed the base implementation will destroy the page
+ * associated with the particular part. The page was created by a subclass, so
+ * the subclass must also destroy it. Subclasses must implement these.
+ * <ul>
+ * <li><code>doDestroyPage</code> - called to destroy a page for a particular
+ * part in the workbench.</li>
+ * </ul>
+ * </p>
+ */
+public abstract class PageBookView extends ViewPart implements IPartListener {
+	/**
+	 * The pagebook control, or <code>null</code> if not initialized.
+	 */
+	private PageBook book;
+
+	/**
+	 * The page record for the default page.
+	 */
+	private PageRec defaultPageRec;
+
+	/**
+	 * Map from parts to part records (key type: <code>IWorkbenchPart</code>;
+	 * value type: <code>PartRec</code>).
+	 */
+	private Map mapPartToRec = new HashMap();
+
+	/**
+	 * Map from pages to view sites Note that view sites were not added to page
+	 * recs to avoid breaking binary compatibility with previous builds
+	 */
+	private Map mapPageToSite = new HashMap();
+
+	/**
+	 * Map from pages to the number of pageRecs actively associated with a page.
+	 */
+	private Map mapPageToNumRecs = new HashMap();
+
+	/**
+	 * The page rec which provided the current page or <code>null</code>
+	 */
+	private PageRec activeRec;
+
+	/**
+	 * If the part is hidden (usually an editor) then store it so we can
+	 * continue to track it when it becomes visible.
+	 */
+	private IWorkbenchPart hiddenPart = null;
+
+	/**
+	 * The action bar property listener.
+	 */
+	private IPropertyChangeListener actionBarPropListener = event -> {
+		if (event.getProperty().equals(SubActionBars.P_ACTION_HANDLERS)
+				&& activeRec != null
+				&& event.getSource() == activeRec.subActionBars) {
+			refreshGlobalActionHandlers();
+		}
+	};
+
+	/**
+	 * Selection change listener to listen for page selection changes
+	 */
+	private ISelectionChangedListener selectionChangedListener = event -> pageSelectionChanged(event);
+
+	/**
+	 * Selection change listener to listen for page selection changes
+	 */
+	private ISelectionChangedListener postSelectionListener = event -> postSelectionChanged(event);
+
+	/**
+	 * Selection provider for this view's site
+	 */
+	private SelectionProvider selectionProvider = new SelectionProvider();
+
+	/**
+	 * A data structure used to store the information about a single page within
+	 * a pagebook view.
+	 */
+	protected static class PageRec {
+
+		/**
+		 * The part.
+		 */
+		public IWorkbenchPart part;
+
+		/**
+		 * The page.
+		 */
+		public IPage page;
+
+		/**
+		 * The page's action bars
+		 */
+		public SubActionBars subActionBars;
+
+		/**
+		 * Creates a new page record initialized to the given part and page.
+		 *
+		 * @param part
+		 * @param page
+		 */
+		public PageRec(IWorkbenchPart part, IPage page) {
+			this.part = part;
+			this.page = page;
+		}
+
+		/**
+		 * Disposes of this page record by <code>null</code>ing its fields.
+		 */
+		public void dispose() {
+			part = null;
+			page = null;
+		}
+	}
+
+	private static class SelectionManager extends EventManager {
+		/**
+		 *
+		 * @param listener
+		 *            listen
+		 */
+		public void addSelectionChangedListener(
+				ISelectionChangedListener listener) {
+			addListenerObject(listener);
+		}
+
+		/**
+		 *
+		 * @param listener
+		 *            listen
+		 */
+		public void removeSelectionChangedListener(
+				ISelectionChangedListener listener) {
+			removeListenerObject(listener);
+		}
+
+		/**
+		 *
+		 * @param event
+		 *            the event
+		 */
+		public void selectionChanged(final SelectionChangedEvent event) {
+			// pass on the notification to listeners
+			for (Object listener : getListeners()) {
+				final ISelectionChangedListener selectionChangedListener = (ISelectionChangedListener) listener;
+				SafeRunner.run(new SafeRunnable() {
+					@Override
+					public void run() {
+						selectionChangedListener.selectionChanged(event);
+					}
+				});
+			}
+		}
+
+	}
+
+	/**
+	 * A selection provider/listener for this view. It is a selection provider
+	 * for this view's site.
+	 */
+	protected class SelectionProvider implements IPostSelectionProvider {
+
+		private SelectionManager fSelectionListener = new SelectionManager();
+
+		private SelectionManager fPostSelectionListeners = new SelectionManager();
+
+		@Override
+		public void addSelectionChangedListener(
+				ISelectionChangedListener listener) {
+			fSelectionListener.addSelectionChangedListener(listener);
+		}
+
+		@Override
+		public ISelection getSelection() {
+			// get the selection provider from the current page
+			IPage currentPage = getCurrentPage();
+			// during workbench startup we may be in a state when
+			// there is no current page
+			if (currentPage == null) {
+				return StructuredSelection.EMPTY;
+			}
+			IPageSite site = getPageSite(currentPage);
+			if (site == null) {
+				return StructuredSelection.EMPTY;
+			}
+			ISelectionProvider selProvider = site.getSelectionProvider();
+			if (selProvider != null) {
+				return selProvider.getSelection();
+			}
+			return StructuredSelection.EMPTY;
+		}
+
+		@Override
+		public void removeSelectionChangedListener(
+				ISelectionChangedListener listener) {
+			fSelectionListener.removeSelectionChangedListener(listener);
+		}
+
+		/**
+		 * The selection has changed. Process the event, notifying selection
+		 * listeners and post selection listeners.
+		 *
+		 * @param event
+		 *            the change
+		 */
+		public void selectionChanged(final SelectionChangedEvent event) {
+			fSelectionListener.selectionChanged(event);
+		}
+
+		/**
+		 * The selection has changed, so notify any post-selection listeners.
+		 *
+		 * @param event
+		 *            the change
+		 */
+		public void postSelectionChanged(final SelectionChangedEvent event) {
+			fPostSelectionListeners.selectionChanged(event);
+		}
+
+		@Override
+		public void setSelection(ISelection selection) {
+			// get the selection provider from the current page
+			IPage currentPage = getCurrentPage();
+			// during workbench startup we may be in a state when
+			// there is no current page
+			if (currentPage == null) {
+				return;
+			}
+			IPageSite site = getPageSite(currentPage);
+			if (site == null) {
+				return;
+			}
+			ISelectionProvider selProvider = site.getSelectionProvider();
+			// and set its selection
+			if (selProvider != null) {
+				selProvider.setSelection(selection);
+			}
+		}
+
+		@Override
+		public void addPostSelectionChangedListener(
+				ISelectionChangedListener listener) {
+			fPostSelectionListeners.addSelectionChangedListener(listener);
+		}
+
+		@Override
+		public void removePostSelectionChangedListener(
+				ISelectionChangedListener listener) {
+			fPostSelectionListeners.removeSelectionChangedListener(listener);
+		}
+	}
+
+	/**
+	 * Creates a new pagebook view.
+	 */
+	protected PageBookView() {
+		super();
+	}
+
+	/**
+	 * Creates and returns the default page for this view.
+	 * <p>
+	 * Subclasses must implement this method.
+	 * </p>
+	 * <p>
+	 * Subclasses must call initPage with the new page (if it is an
+	 * <code>IPageBookViewPage</code>) before calling createControl on the
+	 * page.
+	 * </p>
+	 *
+	 * @param book
+	 *            the pagebook control
+	 * @return the default page
+	 */
+	protected abstract IPage createDefaultPage(PageBook book);
+
+	/**
+	 * Creates a page for a given part. Adds it to the pagebook but does not
+	 * show it.
+	 *
+	 * @param part
+	 *            The part we are making a page for.
+	 * @return IWorkbenchPart
+	 */
+	private PageRec createPage(IWorkbenchPart part) {
+		PageRec rec = doCreatePage(part);
+		if (rec != null) {
+			mapPartToRec.put(part, rec);
+			preparePage(rec);
+		}
+		return rec;
+	}
+
+	/**
+	 * Prepares the page in the given page rec for use in this view.
+	 *
+	 * @param rec
+	 */
+	private void preparePage(PageRec rec) {
+		IPageSite site = null;
+		Integer count;
+
+		if (!doesPageExist(rec.page)) {
+			if (rec.page instanceof IPageBookViewPage) {
+				site = ((IPageBookViewPage) rec.page).getSite();
+			}
+			if (site == null) {
+				// We will create a site for our use
+				site = new PageSite(getViewSite());
+			}
+			mapPageToSite.put(rec.page, site);
+
+			rec.subActionBars = (SubActionBars) site.getActionBars();
+			rec.subActionBars.addPropertyChangeListener(actionBarPropListener);
+			// for backward compability with IPage
+			rec.page.setActionBars(rec.subActionBars);
+
+			count = Integer.valueOf(0);
+		} else {
+			site = (IPageSite) mapPageToSite.get(rec.page);
+			rec.subActionBars = (SubActionBars) site.getActionBars();
+			count = ((Integer) mapPageToNumRecs.get(rec.page));
+		}
+
+		mapPageToNumRecs.put(rec.page, Integer.valueOf(count.intValue() + 1));
+	}
+
+	/**
+	 * Initializes the given page with a page site.
+	 * <p>
+	 * Subclasses should call this method after the page is created but before
+	 * creating its controls.
+	 * </p>
+	 * <p>
+	 * Subclasses may override
+	 * </p>
+	 *
+	 * @param page
+	 *            The page to initialize
+	 */
+	protected void initPage(IPageBookViewPage page) {
+		try {
+			page.init(new PageSite(getViewSite()));
+		} catch (PartInitException e) {
+			WorkbenchPlugin.log(getClass(), "initPage", e); //$NON-NLS-1$
+		}
+	}
+
+	/**
+	 * The <code>PageBookView</code> implementation of this
+	 * <code>IWorkbenchPart</code> method creates a <code>PageBook</code>
+	 * control with its default page showing. Subclasses may extend.
+	 */
+	@Override
+	public void createPartControl(Composite parent) {
+
+		// Create the page book.
+		book = new PageBook(parent, SWT.NONE);
+
+		// Create the default page rec.
+		IPage defaultPage = createDefaultPage(book);
+		defaultPageRec = new PageRec(null, defaultPage);
+		preparePage(defaultPageRec);
+
+		// Show the default page
+		showPageRec(defaultPageRec);
+
+		// Listen to part activation events.
+		getSite().getPage().addPartListener(partListener);
+		showBootstrapPart();
+	}
+
+	/**
+	 * The <code>PageBookView</code> implementation of this
+	 * <code>IWorkbenchPart</code> method cleans up all the pages. Subclasses
+	 * may extend.
+	 */
+	@Override
+	public void dispose() {
+		// stop listening to part activation
+		getSite().getPage().removePartListener(partListener);
+
+		// Deref all of the pages.
+		activeRec = null;
+		if (defaultPageRec != null) {
+			// check for null since the default page may not have
+			// been created (ex. perspective never visible)
+			removePage(defaultPageRec, false);
+			defaultPageRec = null;
+		}
+		Map clone = (Map) ((HashMap) mapPartToRec).clone();
+		Iterator itr = clone.values().iterator();
+		while (itr.hasNext()) {
+			PageRec rec = (PageRec) itr.next();
+			removePage(rec, true);
+		}
+
+		// Run super.
+		super.dispose();
+	}
+
+	/**
+	 * Creates a new page in the pagebook for a particular part. This page will
+	 * be made visible whenever the part is active, and will be destroyed with a
+	 * call to <code>doDestroyPage</code>.
+	 * <p>
+	 * Subclasses must implement this method.
+	 * </p>
+	 * <p>
+	 * Subclasses must call initPage with the new page (if it is an
+	 * <code>IPageBookViewPage</code>) before calling createControl on the
+	 * page.
+	 * </p>
+	 *
+	 * @param part
+	 *            the input part
+	 * @return the record describing a new page for this view
+	 * @see #doDestroyPage
+	 */
+	protected abstract PageRec doCreatePage(IWorkbenchPart part);
+
+	/**
+	 * Destroys a page in the pagebook for a particular part. This page was
+	 * returned as a result from <code>doCreatePage</code>.
+	 * <p>
+	 * Subclasses must implement this method.
+	 * </p>
+	 *
+	 * @param part
+	 *            the input part
+	 * @param pageRecord
+	 *            a page record for the part
+	 * @see #doCreatePage
+	 */
+	protected abstract void doDestroyPage(IWorkbenchPart part,
+			PageRec pageRecord);
+
+	/**
+	 * Returns true if the page has already been created.
+	 *
+	 * @param page
+	 *            the page to test
+	 * @return true if this page has already been created.
+	 */
+	protected boolean doesPageExist(IPage page) {
+		return mapPageToNumRecs.containsKey(page);
+	}
+
+	/**
+	 * The <code>PageBookView</code> implementation of this
+	 * <code>IAdaptable</code> method delegates to the current page, if it
+	 * implements <code>IAdaptable</code>.
+	 */
+	@Override
+	public <T> T getAdapter(Class<T> key) {
+		// delegate to the current page, if supported
+		IPage page = getCurrentPage();
+		T adapter = Adapters.adapt(page, key);
+		if (adapter != null) {
+			return adapter;
+		}
+		// if the page did not find the adapter, look for one provided by
+		// this view before delegating to super.
+		adapter = getViewAdapter(key);
+		if (adapter != null) {
+			return adapter;
+		}
+		// delegate to super
+		return super.getAdapter(key);
+	}
+
+	/**
+	 * Returns an adapter of the specified type, as provided by this view (not
+	 * the current page), or <code>null</code> if this view does not provide
+	 * an adapter of the specified adapter.
+	 * <p>
+	 * The default implementation returns <code>null</code>. Subclasses may
+	 * override.
+	 * </p>
+	 *
+	 * @param adapter
+	 *            the adapter class to look up
+	 * @return a object castable to the given class, or <code>null</code> if
+	 *         this object does not have an adapter for the given class
+	 * @since 3.2
+	 */
+	protected <T> T getViewAdapter(Class<T> adapter) {
+		return null;
+	}
+
+	/**
+	 * Returns the active, important workbench part for this view.
+	 * <p>
+	 * When the page book view is created it has no idea which part within the
+	 * workbook should be used to generate the first page. Therefore, it
+	 * delegates the choice to subclasses of <code>PageBookView</code>.
+	 * </p>
+	 * <p>
+	 * Implementors of this method should return an active, important part in
+	 * the workbench or <code>null</code> if none found.
+	 * </p>
+	 * <p>
+	 * Subclasses must implement this method.
+	 * </p>
+	 *
+	 * @return the active important part, or <code>null</code> if none
+	 */
+	protected abstract IWorkbenchPart getBootstrapPart();
+
+	/**
+	 * Returns the part which contributed the current page to this view.
+	 *
+	 * @return the part which contributed the current page or <code>null</code>
+	 *         if no part contributed the current page
+	 */
+	protected IWorkbenchPart getCurrentContributingPart() {
+		if (activeRec == null) {
+			return null;
+		}
+		return activeRec.part;
+	}
+
+	/**
+	 * Returns the currently visible page for this view or <code>null</code>
+	 * if no page is currently visible.
+	 *
+	 * @return the currently visible page
+	 */
+	public IPage getCurrentPage() {
+		if (activeRec == null) {
+			return null;
+		}
+		return activeRec.page;
+	}
+
+	/**
+	 * Returns the view site for the given page of this view.
+	 *
+	 * @param page
+	 *            the page
+	 * @return the corresponding site, or <code>null</code> if not found
+	 */
+	protected PageSite getPageSite(IPage page) {
+		return (PageSite) mapPageToSite.get(page);
+	}
+
+	/**
+	 * Returns the default page for this view.
+	 *
+	 * @return the default page
+	 */
+	public IPage getDefaultPage() {
+		return defaultPageRec.page;
+	}
+
+	/**
+	 * Returns the pagebook control for this view.
+	 *
+	 * @return the pagebook control, or <code>null</code> if not initialized
+	 */
+	protected PageBook getPageBook() {
+		return book;
+	}
+
+	/**
+	 * Returns the page record for the given part.
+	 *
+	 * @param part
+	 *            the part
+	 * @return the corresponding page record, or <code>null</code> if not
+	 *         found
+	 */
+	protected PageRec getPageRec(IWorkbenchPart part) {
+		return (PageRec) mapPartToRec.get(part);
+	}
+
+	/**
+	 * Returns the page record for the given page of this view.
+	 *
+	 * @param page
+	 *            the page
+	 * @return the corresponding page record, or <code>null</code> if not
+	 *         found
+	 */
+	protected PageRec getPageRec(IPage page) {
+		Iterator itr = mapPartToRec.values().iterator();
+		while (itr.hasNext()) {
+			PageRec rec = (PageRec) itr.next();
+			if (rec.page == page) {
+				return rec;
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Returns whether the given part should be added to this view.
+	 * <p>
+	 * Subclasses must implement this method.
+	 * </p>
+	 *
+	 * @param part
+	 *            the input part
+	 * @return <code>true</code> if the part is relevant, and
+	 *         <code>false</code> otherwise
+	 */
+	protected abstract boolean isImportant(IWorkbenchPart part);
+
+	@Override
+	public void init(IViewSite site) throws PartInitException {
+		site.setSelectionProvider(selectionProvider);
+		super.init(site);
+	}
+
+	/**
+	 * The <code>PageBookView</code> implementation of this
+	 * <code>IPartListener</code> method shows the page when the given part is
+	 * activated. Subclasses may extend.
+	 */
+	@Override
+	public void partActivated(IWorkbenchPart part) {
+		// Is this an important part? If not just return.
+		if (isImportant(part)) {
+			hiddenPart = null;
+
+			// Create a page for the part.
+			PageRec rec = getPageRec(part);
+			if (rec == null) {
+				rec = createPage(part);
+			}
+
+			// Show the page.
+			if (rec != null) {
+				showPageRec(rec);
+			} else {
+				showPageRec(defaultPageRec);
+			}
+		}
+
+		// If *we* are activating then activate the context
+		if (part == this) {
+			PageSite pageSite = getPageSite(getCurrentPage());
+			if (pageSite != null) {
+				IEclipseContext pageContext = pageSite.getSiteContext();
+				if (pageContext != null) {
+					pageContext.activate();
+				}
+			}
+		}
+	}
+
+	/**
+	 * The <code>PageBookView</code> implementation of this
+	 * <code>IPartListener</code> method does nothing. Subclasses may extend.
+	 */
+	@Override
+	public void partBroughtToTop(IWorkbenchPart part) {
+		// Do nothing by default
+	}
+
+	/**
+	 * The <code>PageBookView</code> implementation of this
+	 * <code>IPartListener</code> method deal with the closing of the active
+	 * part. Subclasses may extend.
+	 */
+	@Override
+	public void partClosed(IWorkbenchPart part) {
+		// Update the active part.
+		if (activeRec != null && activeRec.part == part) {
+			showPageRec(defaultPageRec);
+		}
+
+		// Find and remove the part page.
+		PageRec rec = getPageRec(part);
+		if (rec != null) {
+			removePage(rec, true);
+		}
+		if (part == hiddenPart) {
+			hiddenPart = null;
+		}
+	}
+
+	/**
+	 * The <code>PageBookView</code> implementation of this
+	 * <code>IPartListener</code> method does nothing. Subclasses may extend.
+	 */
+	@Override
+	public void partDeactivated(IWorkbenchPart part) {
+		// Do nothing.
+	}
+
+	@Override
+	public void partOpened(IWorkbenchPart part) {
+		// Do nothing by default.
+	}
+
+	/**
+	 * Refreshes the global actions for the active page.
+	 */
+	private void refreshGlobalActionHandlers() {
+		// Clear old actions.
+		IActionBars bars = getViewSite().getActionBars();
+		bars.clearGlobalActionHandlers();
+
+		// Set new actions.
+		Map newActionHandlers = activeRec.subActionBars
+				.getGlobalActionHandlers();
+		if (newActionHandlers != null) {
+			Set keys = newActionHandlers.entrySet();
+			Iterator iter = keys.iterator();
+			while (iter.hasNext()) {
+				Map.Entry entry = (Map.Entry) iter.next();
+				bars.setGlobalActionHandler((String) entry.getKey(),
+						(IAction) entry.getValue());
+			}
+		}
+	}
+
+	/**
+	 * Removes a page record. If it is the last reference to the page dispose of
+	 * it - otherwise just decrement the reference count.
+	 *
+	 * @param rec
+	 * @param doDestroy
+	 *            if <code>true</code>, also call
+	 *            {@link #doDestroyPage(IWorkbenchPart, PageRec)}
+	 */
+	private void removePage(PageRec rec, boolean doDestroy) {
+		mapPartToRec.remove(rec.part);
+
+		int newCount = ((Integer) mapPageToNumRecs.get(rec.page)).intValue() - 1;
+
+		if (newCount == 0) {
+			Object site = mapPageToSite.remove(rec.page);
+			mapPageToNumRecs.remove(rec.page);
+
+			Control control = rec.page.getControl();
+			if (control != null && !control.isDisposed()) {
+				// Dispose the page's control so pages don't have to do this in
+				// their
+				// dispose method.
+				// The page's control is a child of this view's control so if
+				// this view
+				// is closed, the page's control will already be disposed.
+				control.dispose();
+			}
+
+			if (doDestroy) {
+				// free the page
+				doDestroyPage(rec.part, rec);
+			}
+
+			if (rec.subActionBars != null) {
+				rec.subActionBars.dispose();
+			}
+
+			if (site instanceof PageSite) {
+				((PageSite) site).dispose();
+			}
+		} else {
+			mapPageToNumRecs.put(rec.page, Integer.valueOf(newCount));
+		}
+	}
+
+	@Override
+	public void setFocus() {
+		// first set focus on the page book, in case the page
+		// doesn't properly handle setFocus
+		if (book != null) {
+			book.setFocus();
+		}
+		// then set focus on the page, if any
+		if (activeRec != null) {
+			activeRec.page.setFocus();
+		}
+	}
+
+	/**
+	 * Handle page selection changes.
+	 *
+	 * @param event
+	 */
+	private void pageSelectionChanged(SelectionChangedEvent event) {
+		// forward this change from a page to our site's selection provider
+		SelectionProvider provider = (SelectionProvider) getSite()
+				.getSelectionProvider();
+		if (provider != null) {
+			provider.selectionChanged(event);
+		}
+	}
+
+	/**
+	 * Handle page selection changes.
+	 *
+	 * @param event
+	 */
+	private void postSelectionChanged(SelectionChangedEvent event) {
+		// forward this change from a page to our site's selection provider
+		SelectionProvider provider = (SelectionProvider) getSite()
+				.getSelectionProvider();
+		if (provider != null) {
+			provider.postSelectionChanged(event);
+		}
+	}
+
+	/**
+	 * Shows a page for the active workbench part.
+	 */
+	private void showBootstrapPart() {
+		IWorkbenchPart part = getBootstrapPart();
+		if (part != null) {
+			partActivated(part);
+		}
+	}
+
+	/**
+	 * Shows page contained in the given page record in this view. The page
+	 * record must be one from this pagebook view.
+	 * <p>
+	 * The <code>PageBookView</code> implementation of this method asks the
+	 * pagebook control to show the given page's control, and records that the
+	 * given page is now current. Subclasses may extend.
+	 * </p>
+	 *
+	 * @param pageRec
+	 *            the page record containing the page to show
+	 */
+	protected void showPageRec(PageRec pageRec) {
+		// If already showing do nothing
+		if (activeRec == pageRec) {
+			return;
+		}
+		// If the page is the same, just set activeRec to pageRec
+		if (activeRec != null && pageRec != null
+				&& activeRec.page == pageRec.page) {
+			activeRec = pageRec;
+			return;
+		}
+
+		// Hide old page.
+		if (activeRec != null) {
+			PageSite pageSite = (PageSite) mapPageToSite.get(activeRec.page);
+
+			activeRec.subActionBars.deactivate();
+
+			// deactivate the nested services
+			pageSite.deactivate();
+
+			// remove our selection listener
+			ISelectionProvider provider = pageSite.getSelectionProvider();
+			if (provider != null) {
+				provider
+						.removeSelectionChangedListener(selectionChangedListener);
+				if (provider instanceof IPostSelectionProvider) {
+					((IPostSelectionProvider) provider)
+							.removePostSelectionChangedListener(postSelectionListener);
+				} else {
+					provider.removeSelectionChangedListener(postSelectionListener);
+				}
+			}
+		}
+
+		// Show new page.
+		activeRec = pageRec;
+		Control pageControl = activeRec.page.getControl();
+		if (pageControl != null && !pageControl.isDisposed()) {
+			PageSite pageSite = (PageSite) mapPageToSite.get(activeRec.page);
+
+			// Verify that the page control is not disposed
+			// If we are closing, it may have already been disposed
+			book.showPage(pageControl);
+			activeRec.subActionBars.activate();
+			refreshGlobalActionHandlers();
+
+			// activate the nested services
+			pageSite.activate();
+
+			// add our selection listener
+			ISelectionProvider provider = pageSite.getSelectionProvider();
+			if (provider == null) {
+				/* BEGIN workaround for bug 319846 BEGIN */
+				WorkbenchPage page = (WorkbenchPage) getSite().getPage();
+				MPart part = page.findPart(this);
+				if (part != null) {
+					part.getContext().get(ESelectionService.class)
+							.setSelection(StructuredSelection.EMPTY);
+				}
+				/* END workaround for bug 319846 END */
+			} else {
+				provider.addSelectionChangedListener(selectionChangedListener);
+				if (provider instanceof IPostSelectionProvider) {
+					((IPostSelectionProvider) provider)
+							.addPostSelectionChangedListener(postSelectionListener);
+				} else {
+					provider.addSelectionChangedListener(postSelectionListener);
+				}
+
+				/* BEGIN workaround for bug 319846 BEGIN */
+				WorkbenchPage page = (WorkbenchPage) getSite().getPage();
+				MPart part = page.findPart(this);
+				if (part != null) {
+					part.getContext().get(ESelectionService.class)
+							.setSelection(provider.getSelection());
+				}
+				/* END workaround for bug 319846 END */
+			}
+			// Update action bars.
+			getViewSite().getActionBars().updateActionBars();
+		}
+	}
+
+	/**
+	 * Returns the selectionProvider for this page book view.
+	 *
+	 * @return a SelectionProvider
+	 */
+	protected SelectionProvider getSelectionProvider() {
+		return selectionProvider;
+	}
+
+	private IPartListener2 partListener = new IPartListener2() {
+		@Override
+		public void partActivated(IWorkbenchPartReference partRef) {
+			if (partRef == null) {
+				WorkbenchPlugin.log("partRef is null in PageBookView partActivated"); //$NON-NLS-1$
+				return;
+			}
+			IWorkbenchPart part = partRef.getPart(false);
+			PageBookView.this.partActivated(part);
+		}
+
+		@Override
+		public void partBroughtToTop(IWorkbenchPartReference partRef) {
+			PageBookView.this.partBroughtToTop(partRef.getPart(false));
+		}
+
+		@Override
+		public void partClosed(IWorkbenchPartReference partRef) {
+			PageBookView.this.partClosed(partRef.getPart(false));
+		}
+
+		@Override
+		public void partDeactivated(IWorkbenchPartReference partRef) {
+			PageBookView.this.partDeactivated(partRef.getPart(false));
+		}
+
+		@Override
+		public void partHidden(IWorkbenchPartReference partRef) {
+			PageBookView.this.partHidden(partRef.getPart(false));
+		}
+
+		@Override
+		public void partInputChanged(IWorkbenchPartReference partRef) {
+		}
+
+		@Override
+		public void partOpened(IWorkbenchPartReference partRef) {
+			PageBookView.this.partOpened(partRef.getPart(false));
+		}
+
+		@Override
+		public void partVisible(IWorkbenchPartReference partRef) {
+			PageBookView.this.partVisible(partRef.getPart(false));
+		}
+	};
+
+	/**
+	 * Make sure that the part is not considered if it is hidden.
+	 * @param part
+	 * @since 3.5
+	 */
+	protected void partHidden(IWorkbenchPart part) {
+		if (part == null || part != getCurrentContributingPart()) {
+			return;
+		}
+		// if we've minimized the editor stack, that's no reason to
+		// drop our content
+		if (getSite().getPage().getPartState(
+				getSite().getPage().getReference(part)) == IWorkbenchPage.STATE_MINIMIZED) {
+			return;
+		}
+		// if we're switching from a part source in our own stack,
+		// we also don't want to clear our content.
+		if (part instanceof IViewPart) {
+			final IViewPart[] viewStack = getSite().getPage()
+					.getViewStack(this);
+			if (containsPart(viewStack, part)) {
+				return;
+			}
+		}
+		hiddenPart = part;
+		showPageRec(defaultPageRec);
+	}
+
+	/**
+	 * @param viewStack
+	 * @param part
+	 * @return <code>true</code> if the part is in the viewStack
+	 */
+	private boolean containsPart(IViewPart[] viewStack, IWorkbenchPart part) {
+		if (viewStack == null) {
+			return false;
+		}
+		for (IViewPart viewPart : viewStack) {
+			if (viewPart == part) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Make sure that the part is not considered if it is hidden.
+	 *
+	 * @param part
+	 * @since 3.5
+	 */
+	protected void partVisible(IWorkbenchPart part) {
+		if (part == null || part != hiddenPart) {
+			return;
+		}
+		partActivated(part);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/PageSite.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/PageSite.java
new file mode 100644
index 0000000..ec6829c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/PageSite.java
@@ -0,0 +1,259 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ *******************************************************************************/
+package org.eclipse.ui.part;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.e4.core.contexts.ContextFunction;
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IViewSite;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.SubActionBars;
+import org.eclipse.ui.contexts.IContextService;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.internal.PartSite;
+import org.eclipse.ui.internal.PopupMenuExtender;
+import org.eclipse.ui.internal.contexts.NestableContextService;
+import org.eclipse.ui.internal.expressions.ActivePartExpression;
+import org.eclipse.ui.internal.handlers.LegacyHandlerService;
+import org.eclipse.ui.internal.part.IPageSiteHolder;
+import org.eclipse.ui.internal.services.INestable;
+import org.eclipse.ui.internal.services.IServiceLocatorCreator;
+import org.eclipse.ui.internal.services.IWorkbenchLocationService;
+import org.eclipse.ui.internal.services.ServiceLocator;
+import org.eclipse.ui.internal.services.WorkbenchLocationService;
+import org.eclipse.ui.services.IServiceScopes;
+
+/**
+ * This implementation of <code>IPageSite</code> provides a site for a page
+ * within a <code>PageBookView</code>. Most methods are forwarded to the
+ * view's site.
+ */
+public class PageSite implements IPageSite, INestable {
+
+	/**
+	 * The list of menu extender for each registered menu.
+	 */
+	private ArrayList menuExtenders;
+
+	/**
+	 * The "parent" view site
+	 */
+	private IViewSite parentSite;
+
+	/**
+	 * A selection provider set by the page. Value is <code>null</code> until
+	 * set.
+	 */
+	private ISelectionProvider selectionProvider;
+
+	/**
+	 * The localized service locator for this page site. This locator is never
+	 * <code>null</code>.
+	 */
+	private final ServiceLocator serviceLocator;
+
+	/**
+	 * The action bars for this site
+	 */
+	private SubActionBars subActionBars;
+
+	private IEclipseContext e4Context;
+
+	private NestableContextService contextService;
+
+	private boolean active = false;
+
+	/**
+	 * Creates a new sub view site of the given parent view site.
+	 *
+	 * @param parentViewSite
+	 *            the parent view site
+	 */
+	public PageSite(final IViewSite parentViewSite) {
+		Assert.isNotNull(parentViewSite);
+		parentSite = parentViewSite;
+		subActionBars = new SubActionBars(parentViewSite.getActionBars(), this);
+
+		// Initialize the service locator.
+		IServiceLocatorCreator slc = parentSite
+				.getService(IServiceLocatorCreator.class);
+		e4Context = ((PartSite) parentViewSite).getContext().createChild("PageSite"); //$NON-NLS-1$
+		this.serviceLocator = (ServiceLocator) slc.createServiceLocator(parentViewSite, null,
+				() -> {
+					// final Control control =
+					// ((PartSite)parentViewSite).getPane().getControl();
+					// if (control != null && !control.isDisposed()) {
+					// ((PartSite)parentViewSite).getPane().doHide();
+					// }
+					// TODO compat: not tsure what this should do
+				}, e4Context);
+		initializeDefaultServices();
+	}
+
+	/**
+	 * Initialize the slave services for this site.
+	 */
+	private void initializeDefaultServices() {
+		serviceLocator.registerService(IWorkbenchLocationService.class,
+				new WorkbenchLocationService(IServiceScopes.PAGESITE_SCOPE,
+						getWorkbenchWindow().getWorkbench(),
+						getWorkbenchWindow(), parentSite, null, this, 3));
+		serviceLocator.registerService(IPageSiteHolder.class,
+				(IPageSiteHolder) () -> PageSite.this);
+
+		// create a local handler service so that when this page
+		// activates/deactivates, its handlers will also be taken into/out of
+		// consideration during handler lookups
+		IHandlerService handlerService = new LegacyHandlerService(e4Context);
+		e4Context.set(IHandlerService.class, handlerService);
+
+		e4Context.set(IContextService.class.getName(), new ContextFunction() {
+			@Override
+			public Object compute(IEclipseContext context, String contextKey) {
+				if (contextService == null) {
+					contextService = new NestableContextService(context.getParent().get(
+							IContextService.class), new ActivePartExpression(parentSite.getPart()));
+				}
+				return contextService;
+			}
+		});
+	}
+
+	/**
+	 * Disposes of the menu extender contributions.
+	 */
+	protected void dispose() {
+		if (menuExtenders != null) {
+			HashSet managers = new HashSet(menuExtenders.size());
+			for (int i = 0; i < menuExtenders.size(); i++) {
+				PopupMenuExtender ext = (PopupMenuExtender) menuExtenders.get(i);
+				managers.add(ext.getManager());
+				ext.dispose();
+			}
+			if (managers.size()>0) {
+				for (Iterator iterator = managers.iterator(); iterator
+						.hasNext();) {
+					MenuManager mgr = (MenuManager) iterator.next();
+					mgr.dispose();
+				}
+			}
+			menuExtenders = null;
+		}
+		subActionBars.dispose();
+
+		if (contextService != null) {
+			contextService.dispose();
+		}
+
+		serviceLocator.dispose();
+		e4Context.dispose();
+	}
+
+	/**
+	 * The PageSite implementation of this <code>IPageSite</code> method
+	 * returns the <code>SubActionBars</code> for this site.
+	 *
+	 * @return the subactionbars for this site
+	 */
+	@Override
+	public IActionBars getActionBars() {
+		return subActionBars;
+	}
+
+	@Override
+	public <T> T getAdapter(Class<T> adapter) {
+		return Platform.getAdapterManager().getAdapter(this, adapter);
+	}
+
+	@Override
+	public IWorkbenchPage getPage() {
+		return parentSite.getPage();
+	}
+
+	@Override
+	public ISelectionProvider getSelectionProvider() {
+		return selectionProvider;
+	}
+
+	@Override
+	public final <T> T getService(final Class<T> key) {
+		T service = serviceLocator.getService(key);
+		if (active && service instanceof INestable) {
+			((INestable) service).activate();
+		}
+		return service;
+	}
+
+	@Override
+	public Shell getShell() {
+		return parentSite.getShell();
+	}
+
+	@Override
+	public IWorkbenchWindow getWorkbenchWindow() {
+		return parentSite.getWorkbenchWindow();
+	}
+
+	@Override
+	public final boolean hasService(final Class<?> key) {
+		return serviceLocator.hasService(key);
+	}
+
+	@Override
+	public void registerContextMenu(String menuID, MenuManager menuMgr,
+			ISelectionProvider selProvider) {
+		if (menuExtenders == null) {
+			menuExtenders = new ArrayList(1);
+		}
+		PartSite.registerContextMenu(menuID, menuMgr, selProvider, false, parentSite.getPart(),
+				e4Context, menuExtenders);
+	}
+
+	@Override
+	public void setSelectionProvider(ISelectionProvider provider) {
+		selectionProvider = provider;
+	}
+
+	/* Package */IEclipseContext getSiteContext() {
+		return e4Context;
+	}
+
+	@Override
+	public void activate() {
+		active = true;
+
+		serviceLocator.activate();
+
+		if (contextService != null) {
+			contextService.activate();
+		}
+	}
+
+	@Override
+	public void deactivate() {
+		active = false;
+		if (contextService != null) {
+			contextService.deactivate();
+		}
+
+		serviceLocator.deactivate();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/PageSwitcher.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/PageSwitcher.java
new file mode 100644
index 0000000..4302cd9
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/PageSwitcher.java
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
+ ******************************************************************************/
+
+package org.eclipse.ui.part;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.internal.handlers.CyclePageHandler;
+
+/**
+ * Provides the implementation for switching pages in a view. A view may track
+ * pages however it wishes. The view should subclass PageSwitcher to provide the
+ * abstract methods, and then instantiate their page switcher once.
+ *
+ * @since 3.4
+ *
+ */
+public abstract class PageSwitcher {
+
+	/**
+	 * Register the handlers for page switching with this view or editor.
+	 *
+	 * @param part
+	 *            The part to register against.
+	 */
+	public PageSwitcher(IWorkbenchPart part) {
+		IHandlerService service = part.getSite().getService(
+				IHandlerService.class);
+		service.activateHandler(IWorkbenchCommandConstants.NAVIGATE_NEXT_PAGE, new CyclePageHandler(this));
+		service.activateHandler(IWorkbenchCommandConstants.NAVIGATE_PREVIOUS_PAGE, new CyclePageHandler(
+				this));
+	}
+
+	/**
+	 * Displays the given page in the view. The page must already exist in the
+	 * view.
+	 *
+	 * @param page
+	 *            the page to display, never <code>null</code>.
+	 */
+	public abstract void activatePage(Object page);
+
+	/**
+	 * Returns an {@link ImageDescriptor} for the page.
+	 *
+	 * @param page
+	 *            the page to retrieve an {@link ImageDescriptor}
+	 * @return An {@link ImageDescriptor} for the page, may be <code>null</code>.
+	 */
+	public abstract ImageDescriptor getImageDescriptor(Object page);
+
+	/**
+	 * Returns a readable name to identify the page.
+	 *
+	 * @param page
+	 *            the page to get the name
+	 * @return the name of the page
+	 */
+	public abstract String getName(Object page);
+
+	/**
+	 * Returns the pages available in the view. These may be used for populating
+	 * the pop-up dialog when switching pages. These are the objects that will
+	 * be used in {@link #activatePage(Object)}.
+	 *
+	 * @return an array of pages
+	 */
+	public abstract Object[] getPages();
+
+	/**
+	 * Returns the index of the currently active page. The default
+	 * implementation returns 0. Subclasses can override.
+	 *
+	 * @return the 0-based index of the currently active page from
+	 *         {@link #getPages()}, or an arbitrary value if
+	 *         {@link #getPages()} is an empty array.
+	 */
+	public int getCurrentPageIndex() {
+		return 0;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/PluginDropAdapter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/PluginDropAdapter.java
new file mode 100644
index 0000000..1a91bc1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/PluginDropAdapter.java
@@ -0,0 +1,136 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.part;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.viewers.StructuredViewer;
+import org.eclipse.jface.viewers.ViewerDropAdapter;
+import org.eclipse.swt.dnd.DND;
+import org.eclipse.swt.dnd.DropTargetEvent;
+import org.eclipse.swt.dnd.TransferData;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
+
+/**
+ * Adapter for adding handling of the <code>PluginTransfer</code> drag and drop
+ * transfer type to a drop action.
+ * <p>
+ * This class may be instantiated or subclassed.
+ * </p>
+ */
+public class PluginDropAdapter extends ViewerDropAdapter {
+    /**
+     * The extension point attribute that defines the drop action class.
+     */
+    public static final String ATT_CLASS = "class";//$NON-NLS-1$
+
+    /**
+     * The current transfer data, or <code>null</code> if none.
+     */
+    private TransferData currentTransfer;
+
+    /**
+     * Creates a plug-in drop adapter for the given viewer.
+     *
+     * @param viewer the viewer
+     */
+    public PluginDropAdapter(StructuredViewer viewer) {
+        super(viewer);
+    }
+
+    @Override
+	public void drop(DropTargetEvent event) {
+        try {
+            if (PluginTransfer.getInstance().isSupportedType(
+                    event.currentDataType)) {
+                PluginTransferData pluginData = (PluginTransferData) event.data;
+                IDropActionDelegate delegate = getPluginAdapter(pluginData);
+                if (!delegate.run(pluginData.getData(), getCurrentTarget())) {
+                    event.detail = DND.DROP_NONE;
+                }
+            } else {
+                super.drop(event);
+            }
+        } catch (CoreException e) {
+            WorkbenchPlugin.log("Drop Failed", e.getStatus());//$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Returns the current transfer.
+     */
+    protected TransferData getCurrentTransfer() {
+        return currentTransfer;
+    }
+
+    /**
+     * Loads the class that will perform the action associated with the given drop
+     * data.
+     *
+     * @param data the drop data
+     * @return the viewer drop adapter
+     */
+    protected static IDropActionDelegate getPluginAdapter(
+            PluginTransferData data) throws CoreException {
+
+        IExtensionRegistry registry = Platform.getExtensionRegistry();
+        String adapterName = data.getExtensionId();
+        IExtensionPoint xpt = registry.getExtensionPoint(PlatformUI.PLUGIN_ID,
+                IWorkbenchRegistryConstants.PL_DROP_ACTIONS);
+        IExtension[] extensions = xpt.getExtensions();
+        for (IExtension extension : extensions) {
+            IConfigurationElement[] configs = extension.getConfigurationElements();
+            if (configs != null && configs.length > 0) {
+                for (IConfigurationElement config : configs) {
+                	String id = config.getAttribute("id");//$NON-NLS-1$
+                    if (id != null && id.equals(adapterName)) {
+                        return (IDropActionDelegate) WorkbenchPlugin
+                                .createExtension(config, ATT_CLASS);
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * @see ViewerDropAdapter#performDrop
+     */
+    @Override
+	public boolean performDrop(Object data) {
+        //should never be called, since we override the drop() method.
+        return false;
+    }
+
+    /**
+     * The <code>PluginDropAdapter</code> implementation of this
+     * <code>ViewerDropAdapter</code> method is used to notify the action that some
+     * aspect of the drop operation has changed. Subclasses may override.
+     */
+    @Override
+	public boolean validateDrop(Object target, int operation,
+            TransferData transferType) {
+        currentTransfer = transferType;
+        if (currentTransfer != null
+                && PluginTransfer.getInstance()
+                        .isSupportedType(currentTransfer)) {
+            //plugin cannot be loaded without the plugin data
+            return true;
+        }
+        return false;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/PluginTransfer.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/PluginTransfer.java
new file mode 100644
index 0000000..7864330
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/PluginTransfer.java
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.part;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import org.eclipse.swt.dnd.ByteArrayTransfer;
+import org.eclipse.swt.dnd.TransferData;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+
+/**
+ * This class can be used to transfer an instance of <code>PluginTransferData</code>
+ * between two parts in a workbench in a drag and drop operation.
+ * <p>
+ * In every drag and drop operation there is a <code>DragSource</code> and
+ * a <code>DropTarget</code>.  When a drag occurs a <code>Transfer</code> is
+ * used to marshall the drag data from the source into a byte array.  If a drop
+ * occurs another <code>Transfer</code> is used to marshall the byte array into
+ * drop data for the target.
+ * </p><p>
+ * A <code>PluginTransferData</code> contains the id of a drop action extension.
+ * If a drop occurs the extension is invoked to perform a drop action.  As a benefit,
+ * the destination viewer doesn't need to have any knowledge of the items being
+ * dropped into it.
+ * </p><p>
+ * This class can be used for a <code>Viewer<code> or an SWT component directly.
+ * A singleton is provided which may be serially reused (see <code>getInstance</code>).
+ * It is not intended to be subclassed.
+ * </p>
+ *
+ * @see org.eclipse.jface.viewers.StructuredViewer
+ * @see org.eclipse.swt.dnd.DropTarget
+ * @see org.eclipse.swt.dnd.DragSource
+ */
+public class PluginTransfer extends ByteArrayTransfer {
+
+    private static final String TYPE_NAME = "pluggable-transfer-format";//$NON-NLS-1$
+
+    private static final int TYPEID = registerType(TYPE_NAME);
+
+    /**
+     * Singleton instance.
+     */
+    private static PluginTransfer instance = new PluginTransfer();
+
+    /**
+     * Creates a new transfer object.
+     */
+    private PluginTransfer() {
+        super();
+    }
+
+    /**
+     * Returns the singleton instance.
+     *
+     * @return the singleton instance
+     */
+    public static PluginTransfer getInstance() {
+        return instance;
+    }
+
+    @Override
+	protected int[] getTypeIds() {
+        return new int[] { TYPEID };
+    }
+
+    @Override
+	protected String[] getTypeNames() {
+        return new String[] { TYPE_NAME };
+    }
+
+    @Override
+	public void javaToNative(Object data, TransferData transferData) {
+        PluginTransferData realData = (PluginTransferData) data;
+        if (data == null) {
+			return;
+		}
+        try {
+            ByteArrayOutputStream out = new ByteArrayOutputStream();
+            DataOutputStream dataOut = new DataOutputStream(out);
+            dataOut.writeUTF(realData.getExtensionId());
+            dataOut.writeInt(realData.getData().length);
+            dataOut.write(realData.getData());
+            dataOut.close();
+            super.javaToNative(out.toByteArray(), transferData);
+        } catch (IOException e) {
+			WorkbenchPlugin.log(e);
+        }
+    }
+
+    @Override
+	public Object nativeToJava(TransferData transferData) {
+        try {
+            byte[] bytes = (byte[]) super.nativeToJava(transferData);
+            ByteArrayInputStream in = new ByteArrayInputStream(bytes);
+            DataInputStream dataIn = new DataInputStream(in);
+            String extensionName = dataIn.readUTF();
+            int len = dataIn.readInt();
+            byte[] pluginData = new byte[len];
+            dataIn.readFully(pluginData);
+            return new PluginTransferData(extensionName, pluginData);
+        } catch (IOException e) {
+			WorkbenchPlugin.log(e);
+        }
+        //can't get here
+        return null;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/PluginTransferData.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/PluginTransferData.java
new file mode 100644
index 0000000..6fec43b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/PluginTransferData.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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.ui.part;
+
+/**
+ * Record for transferring data during a drag and drop operation between
+ * different plug-ins. This object contains an extension identifier and a block
+ * of bytes. When the drop occurs, the data is interpreted by an action defined
+ * in the specified extension.
+ * <p>
+ * Clients using PluginTransfer should create an instance to contain the
+ * drop data.
+ * </p>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class PluginTransferData {
+    String extensionName;
+
+    byte[] transferData;
+
+    /**
+     * Creates a new record for the given extension id and data.
+     *
+     * @param extensionId the extension id
+     * @param data the data to transfer
+     */
+    public PluginTransferData(String extensionId, byte[] data) {
+        this.extensionName = extensionId;
+        this.transferData = data;
+    }
+
+    /**
+     * Returns the data being transferred.
+     *
+     * @return the data
+     */
+    public byte[] getData() {
+        return transferData;
+    }
+
+    /**
+     * Returns the id of the extension that will provide the drop action.
+     *
+     * @return the extension id
+     */
+    public String getExtensionId() {
+        return extensionName;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/ShowInContext.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/ShowInContext.java
new file mode 100644
index 0000000..8314429
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/ShowInContext.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.part;
+
+import org.eclipse.jface.viewers.ISelection;
+
+/**
+ * Carries the context for the Show In action.
+ * The default implementation carries an input and a selection.
+ * Subclasses may extend.
+ *
+ * @see IShowInSource
+ * @see IShowInTarget
+ *
+ * @since 2.1
+ */
+public class ShowInContext {
+
+    private Object input;
+
+    private ISelection selection;
+
+    /**
+     * Constructs a new <code>ShowInContext</code> with the given input and
+     * selection.
+     *
+     * @param input the input or <code>null</code>
+     * @param selection the selection or <code>null</code>
+     */
+    public ShowInContext(Object input, ISelection selection) {
+        setInput(input);
+        setSelection(selection);
+    }
+
+    /**
+     * Returns the input, or <code>null</code> to indicate no input
+     *
+     * @return the input or <code>null</code>.
+     */
+    public Object getInput() {
+        return input;
+    }
+
+    /**
+     * Returns the selection, or <code>null</code> to indicate no selection.
+     *
+     * @return the selection or <code>null</code>
+     */
+    public ISelection getSelection() {
+        return selection;
+    }
+
+    /**
+     * Sets the input, or <code>null</code> to indicate no input.
+     *
+     * @param input the input or <code>null</code>
+     */
+    public void setInput(Object input) {
+        this.input = input;
+    }
+
+    /**
+     * Sets the selection, or <code>null</code> to indicate no selection.
+     *
+     * @param selection the selection or <code>null</code>
+     */
+    public void setSelection(ISelection selection) {
+        this.selection = selection;
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/ViewPart.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/ViewPart.java
new file mode 100644
index 0000000..e4e5d7e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/ViewPart.java
@@ -0,0 +1,167 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.part;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IPropertyListener;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IViewSite;
+import org.eclipse.ui.IWorkbenchPartConstants;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.internal.util.Util;
+
+/**
+ * Abstract base implementation of all workbench views.
+ * <p>
+ * This class should be subclassed by clients wishing to define new views.
+ * The name of the subclass should be given as the <code>"class"</code>
+ * attribute in a <code>view</code> extension contributed to the workbench's
+ * view extension point (named <code>"org.eclipse.ui.views"</code>).
+ * For example, the plug-in's XML markup might contain:
+ * <pre>
+ * &LT;extension point="org.eclipse.ui.views"&GT;
+ *      &LT;view id="com.example.myplugin.view"
+ *         name="My View"
+ *         class="com.example.myplugin.MyView"
+ *         icon="images/eview.gif"
+ *      /&GT;
+ * &LT;/extension&GT;
+ * </pre>
+ * where <code>com.example.myplugin.MyView</code> is the name of the
+ * <code>ViewPart</code> subclass.
+ * </p>
+ * <p>
+ * Subclasses must implement the following methods:
+ * <ul>
+ *   <li><code>createPartControl</code> - to create the view's controls </li>
+ *   <li><code>setFocus</code> - to accept focus</li>
+ * </ul>
+ * </p>
+ * <p>
+ * Subclasses may extend or reimplement the following methods as required:
+ * <ul>
+ *   <li><code>setInitializationData</code> - extend to provide additional
+ *       initialization when view extension is instantiated</li>
+ *   <li><code>init(IWorkbenchPartSite)</code> - extend to provide additional
+ *       initialization when view is assigned its site</li>
+ *   <li><code>dispose</code> - extend to provide additional cleanup</li>
+ *   <li><code>getAdapter</code> - reimplement to make their view adaptable</li>
+ * </ul>
+ * </p>
+ */
+public abstract class ViewPart extends WorkbenchPart implements IViewPart {
+
+    /**
+     * Listens to PROP_TITLE property changes in this object until the first call to
+     * setContentDescription. Used for compatibility with old parts that call setTitle
+     * or overload getTitle instead of using setContentDescription.
+     */
+    private IPropertyListener compatibilityTitleListener = (source, propId) -> {
+	    if (propId == IWorkbenchPartConstants.PROP_TITLE) {
+	        setDefaultContentDescription();
+	    }
+	};
+
+    /**
+     * Creates a new view.
+     */
+    protected ViewPart() {
+        super();
+
+        addPropertyListener(compatibilityTitleListener);
+    }
+
+    @Override
+	public IViewSite getViewSite() {
+        return (IViewSite) getSite();
+    }
+
+
+    @Override
+	public void init(IViewSite site) throws PartInitException {
+        setSite(site);
+
+        setDefaultContentDescription();
+    }
+
+    @Override
+	public void init(IViewSite site, IMemento memento) throws PartInitException {
+    	/*
+    	* Initializes this view with the given view site.  A memento is passed to
+        * the view which contains a snapshot of the views state from a previous
+        * session.  Where possible, the view should try to recreate that state
+        * within the part controls.
+        * <p>
+        * This implementation will ignore the memento and initialize the view in
+        * a fresh state.  Subclasses may override the implementation to perform any
+        * state restoration as needed.
+        */
+        init(site);
+    }
+
+
+    @Override
+	public void saveState(IMemento memento) {
+        // do nothing
+    }
+
+    @Override
+	protected void setPartName(String partName) {
+        if (compatibilityTitleListener != null) {
+            removePropertyListener(compatibilityTitleListener);
+            compatibilityTitleListener = null;
+        }
+
+        super.setPartName(partName);
+    }
+
+    @Override
+	protected void setContentDescription(String description) {
+        if (compatibilityTitleListener != null) {
+            removePropertyListener(compatibilityTitleListener);
+            compatibilityTitleListener = null;
+        }
+
+        super.setContentDescription(description);
+    }
+
+    @Override
+	public void setInitializationData(IConfigurationElement cfig,
+            String propertyName, Object data) {
+        super.setInitializationData(cfig, propertyName, data);
+
+        setDefaultContentDescription();
+    }
+
+    private void setDefaultContentDescription() {
+        if (compatibilityTitleListener == null) {
+            return;
+        }
+
+        String partName = getPartName();
+        String title = getTitle();
+
+        if (Util.equals(partName, title)) {
+            internalSetContentDescription(""); //$NON-NLS-1$
+        } else {
+            internalSetContentDescription(title);
+        }
+    }
+
+    @Override
+	protected final void checkSite(IWorkbenchPartSite site) {
+        super.checkSite(site);
+        Assert.isTrue(site instanceof IViewSite, "The site for a view must be an IViewSite"); //$NON-NLS-1$
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/WorkbenchPart.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/WorkbenchPart.java
new file mode 100644
index 0000000..05b1832
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/WorkbenchPart.java
@@ -0,0 +1,501 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ *******************************************************************************/
+package org.eclipse.ui.part;
+
+import com.ibm.icu.text.MessageFormat;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import org.eclipse.core.commands.common.EventManager;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExecutableExtension;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.e4.ui.workbench.renderers.swt.ContributedPartRenderer;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IPropertyListener;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPart3;
+import org.eclipse.ui.IWorkbenchPartConstants;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.PartSite;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.util.Util;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+/**
+ * Abstract base implementation of all workbench parts.
+ * <p>
+ * This class is not intended to be subclassed by clients outside this
+ * package; clients should instead subclass <code>ViewPart</code> or
+ * <code>EditorPart</code>.
+ * </p>
+ *
+ * @see org.eclipse.ui.part.ViewPart
+ * @see org.eclipse.ui.part.EditorPart
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public abstract class WorkbenchPart extends EventManager implements
+		IWorkbenchPart3, IExecutableExtension, IWorkbenchPartOrientation {
+    private String title = ""; //$NON-NLS-1$
+
+    private ImageDescriptor imageDescriptor;
+
+    private Image titleImage;
+
+	private String toolTip = ""; //$NON-NLS-1$
+
+    private IConfigurationElement configElement;
+
+    private IWorkbenchPartSite partSite;
+
+    private String partName = ""; //$NON-NLS-1$
+
+    private String contentDescription = ""; //$NON-NLS-1$
+
+	private ListenerList<IPropertyChangeListener> partChangeListeners = new ListenerList<>();
+
+    /**
+     * Creates a new workbench part.
+     */
+    protected WorkbenchPart() {
+        super();
+    }
+
+    @Override
+	public void addPropertyListener(IPropertyListener l) {
+        addListenerObject(l);
+    }
+
+    @Override
+	public abstract void createPartControl(Composite parent);
+
+    /**
+     * The <code>WorkbenchPart</code> implementation of this
+     * <code>IWorkbenchPart</code> method disposes the title image
+     * loaded by <code>setInitializationData</code>. Subclasses may extend.
+     */
+    @Override
+	public void dispose() {
+        if (imageDescriptor != null) {
+            JFaceResources.getResources().destroyImage(imageDescriptor);
+        }
+
+        // Clear out the property change listeners as we
+        // should not be notifying anyone after the part
+        // has been disposed.
+        clearListeners();
+        partChangeListeners.clear();
+    }
+
+    /**
+     * Fires a property changed event.
+     *
+     * @param propertyId the id of the property that changed
+     */
+    protected void firePropertyChange(final int propertyId) {
+		for (Object listener : getListeners()) {
+			final IPropertyListener propertyListener = (IPropertyListener) listener;
+            try {
+				propertyListener.propertyChanged(WorkbenchPart.this, propertyId);
+            } catch (RuntimeException e) {
+                WorkbenchPlugin.log(e);
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Subclasses may override this method (however, if they do so, they
+     * should invoke the method on their superclass to ensure that the
+     * Platform's adapter manager is consulted).
+     */
+    @Override
+	public <T> T getAdapter(Class<T> adapter) {
+
+        /**
+         * This implementation of the method declared by <code>IAdaptable</code>
+         * passes the request along to the platform's adapter manager; roughly
+         * <code>Platform.getAdapterManager().getAdapter(this, adapter)</code>.
+         */
+
+        return Platform.getAdapterManager().getAdapter(this, adapter);
+    }
+
+    /**
+     * Returns the configuration element for this part. The configuration element
+     * comes from the plug-in registry entry for the extension defining this part.
+     *
+     * @return the configuration element for this part
+     */
+    protected IConfigurationElement getConfigurationElement() {
+        return configElement;
+    }
+
+    /**
+     * Returns the default title image.
+     *
+     * @return the default image
+     */
+    protected Image getDefaultImage() {
+        return PlatformUI.getWorkbench().getSharedImages().getImage(
+                ISharedImages.IMG_DEF_VIEW);
+    }
+
+    @Override
+	public IWorkbenchPartSite getSite() {
+        return partSite;
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * It is considered bad practise to overload or extend this method.
+     * Parts should set their title by calling setPartName and/or setContentDescription.
+     * </p>
+     */
+    @Override
+	public String getTitle() {
+        return title;
+    }
+
+    @Override
+	public Image getTitleImage() {
+        if (titleImage != null) {
+            return titleImage;
+        }
+        return getDefaultImage();
+    }
+
+    @Override
+	public String getTitleToolTip() {
+        return toolTip;
+    }
+
+    @Override
+	public void removePropertyListener(IPropertyListener l) {
+        removeListenerObject(l);
+    }
+
+    @Override
+	public abstract void setFocus();
+
+    /**
+     * {@inheritDoc}
+     * The <code>WorkbenchPart</code> implementation of this
+     * <code>IExecutableExtension</code> records the configuration element in
+     * and internal state variable (accessible via <code>getConfigElement</code>).
+     * It also loads the title image, if one is specified in the configuration element.
+     * Subclasses may extend.
+     *
+     * Should not be called by clients. It is called by the core plugin when creating
+     * this executable extension.
+     */
+    @Override
+	public void setInitializationData(IConfigurationElement cfig,
+            String propertyName, Object data) {
+
+        // Save config element.
+        configElement = cfig;
+
+        // Part name and title.
+        partName = Util.safeString(cfig.getAttribute("name"));//$NON-NLS-1$;
+        title = partName;
+
+        // Icon.
+        String strIcon = cfig.getAttribute("icon");//$NON-NLS-1$
+        if (strIcon == null) {
+			return;
+		}
+
+        imageDescriptor = AbstractUIPlugin.imageDescriptorFromPlugin(
+                configElement.getNamespace(), strIcon);
+
+        if (imageDescriptor == null) {
+			return;
+		}
+
+        titleImage = JFaceResources.getResources().createImageWithDefault(imageDescriptor);
+    }
+
+    /**
+     * Sets the part site.
+     * <p>
+     * Subclasses must invoke this method from <code>IEditorPart.init</code>
+     * and <code>IViewPart.init</code>.
+     *
+     * @param site the workbench part site
+     */
+    protected void setSite(IWorkbenchPartSite site) {
+        checkSite(site);
+        this.partSite = site;
+    }
+
+    /**
+     * Checks that the given site is valid for this type of part.
+     * The default implementation does nothing.
+     *
+     * @param site the site to check
+     * @since 3.1
+     */
+    protected void checkSite(IWorkbenchPartSite site) {
+        // do nothing
+    }
+
+    /**
+     * Sets or clears the title of this part. Clients should call this method instead
+     * of overriding getTitle.
+     * <p>
+     * This may change a title that was previously set using setPartName or setContentDescription.
+     * </p>
+     *
+     * @deprecated new code should use setPartName and setContentDescription
+     *
+     * @param title the title, or <code>null</code> to clear
+     */
+    @Deprecated
+	protected void setTitle(String title) {
+        title = Util.safeString(title);
+
+        //Do not send changes if they are the same
+        if (Util.equals(this.title, title)) {
+			return;
+		}
+        this.title = title;
+        firePropertyChange(IWorkbenchPart.PROP_TITLE);
+    }
+
+    /**
+     * Sets or clears the title image of this part.
+     *
+     * @param titleImage the title image, or <code>null</code> to clear
+     */
+    protected void setTitleImage(Image titleImage) {
+        Assert.isTrue(titleImage == null || !titleImage.isDisposed());
+        //Do not send changes if they are the same
+        if (this.titleImage == titleImage) {
+			return;
+		}
+        this.titleImage = titleImage;
+        firePropertyChange(IWorkbenchPart.PROP_TITLE);
+        if (imageDescriptor != null) {
+            JFaceResources.getResources().destroyImage(imageDescriptor);
+            imageDescriptor = null;
+        }
+    }
+
+    /**
+     * Sets or clears the title tool tip text of this part. Clients should
+     * call this method instead of overriding <code>getTitleToolTip</code>
+     *
+     * @param toolTip the new tool tip text, or <code>null</code> to clear
+     */
+    protected void setTitleToolTip(String toolTip) {
+        toolTip = Util.safeString(toolTip);
+        //Do not send changes if they are the same
+        if (Util.equals(this.toolTip, toolTip)) {
+			return;
+		}
+        this.toolTip = toolTip;
+        firePropertyChange(IWorkbenchPart.PROP_TITLE);
+    }
+
+    /**
+     * Show that this part is busy due to a Job running that it
+     * is listening to.
+     * @param busy boolean to indicate that the busy state has started
+     *  	or ended.
+     * @see org.eclipse.ui.progress.IWorkbenchSiteProgressService#showBusyForFamily(Object)
+     * @since 3.0
+     */
+    public void showBusy(boolean busy) {
+        //By default do nothing
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * It is considered bad practise to overload or extend this method.
+     * Parts should call setPartName to change their part name.
+     * </p>
+     */
+    @Override
+	public String getPartName() {
+        return partName;
+    }
+
+    /**
+     * Sets the name of this part. The name will be shown in the tab area for
+     * the part. Clients should call this method instead of overriding getPartName.
+     * Setting this to the empty string will cause a default part name to be used.
+     *
+     * <p>
+     * setPartName and setContentDescription are intended to replace setTitle.
+     * This may change a value that was previously set using setTitle.
+     * </p>
+     *
+     * @param partName the part name, as it should be displayed in tabs.
+     *
+     * @since 3.0
+     */
+    protected void setPartName(String partName) {
+
+        internalSetPartName(partName);
+
+        setDefaultTitle();
+    }
+
+    void setDefaultTitle() {
+        String description = getContentDescription();
+        String name = getPartName();
+        String newTitle = name;
+
+        if (!Util.equals(description, "")) { //$NON-NLS-1$
+            newTitle = MessageFormat
+                    .format(
+                            WorkbenchMessages.get().WorkbenchPart_AutoTitleFormat, name, description);
+        }
+
+        setTitle(newTitle);
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * It is considered bad practise to overload or extend this method.
+     * Parts should call setContentDescription to change their content description.
+     * </p>
+     */
+    @Override
+	public String getContentDescription() {
+        return contentDescription;
+    }
+
+    /**
+     * Sets the content description for this part. The content description is typically
+     * a short string describing the current contents of the part. Setting this to the
+     * empty string will cause a default content description to be used. Clients should
+     * call this method instead of overriding getContentDescription(). For views, the
+     * content description is shown (by default) in a line near the top of the view. For
+     * editors, the content description is shown beside the part name when showing a
+     * list of editors. If the editor is open on a file, this typically contains the path
+     * to the input file, without the filename or trailing slash.
+     *
+     * <p>
+     * This may overwrite a value that was previously set in setTitle
+     * </p>
+     *
+     * @param description the content description
+     *
+     * @since 3.0
+     */
+    protected void setContentDescription(String description) {
+        internalSetContentDescription(description);
+
+        setDefaultTitle();
+    }
+
+    void internalSetContentDescription(String description) {
+        Assert.isNotNull(description);
+
+        //Do not send changes if they are the same
+        if (Util.equals(contentDescription, description)) {
+			return;
+		}
+        this.contentDescription = description;
+
+		if (partSite instanceof PartSite) {
+			PartSite site = (PartSite) partSite;
+			ContributedPartRenderer.setDescription(site.getModel(), description);
+		}
+        firePropertyChange(IWorkbenchPartConstants.PROP_CONTENT_DESCRIPTION);
+    }
+
+    void internalSetPartName(String partName) {
+        partName = Util.safeString(partName);
+
+        Assert.isNotNull(partName);
+
+        //Do not send changes if they are the same
+        if (Util.equals(this.partName, partName)) {
+			return;
+		}
+        this.partName = partName;
+
+        firePropertyChange(IWorkbenchPartConstants.PROP_PART_NAME);
+
+    }
+
+    @Override
+	public int getOrientation(){
+		//By default use the orientation in Window
+    	return Window.getDefaultOrientation();
+    }
+
+    @Override
+	public void addPartPropertyListener(IPropertyChangeListener listener) {
+    	partChangeListeners.add(listener);
+    }
+
+    @Override
+	public void removePartPropertyListener(IPropertyChangeListener listener) {
+    	partChangeListeners.remove(listener);
+    }
+
+    /**
+	 * @since 3.3
+	 */
+    protected void firePartPropertyChanged(String key, String oldValue, String newValue) {
+    	final PropertyChangeEvent event = new PropertyChangeEvent(this, key, oldValue, newValue);
+		for (IPropertyChangeListener l : partChangeListeners) {
+			try {
+				l.propertyChange(event);
+			} catch (RuntimeException e) {
+				WorkbenchPlugin.log(e);
+			}
+		}
+    }
+
+	private Map<String, String> partProperties = new HashMap<>();
+
+    @Override
+	public void setPartProperty(String key, String value) {
+		String oldValue = partProperties.get(key);
+		if (value == null) {
+    		partProperties.remove(key);
+    	} else {
+    		partProperties.put(key, value);
+    	}
+    	firePartPropertyChanged(key, oldValue, value);
+    }
+
+    @Override
+	public String getPartProperty(String key) {
+		return partProperties.get(key);
+    }
+
+    @Override
+	public Map<String, String> getPartProperties() {
+    	return Collections.unmodifiableMap(partProperties);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/package.html b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/package.html
new file mode 100644
index 0000000..d29290b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/part/package.html
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <meta name="Author" content="IBM">
+   <meta name="GENERATOR" content="Mozilla/4.5 [en] (WinNT; I) [Netscape]">
+   <title>Package-level Javadoc</title>
+</head>
+<body>
+Classes for the creation of workbench parts that integrate
+with the Eclipse Platform User Interface.
+<h2>
+Package Specification</h2>
+A <b>workbench part</b> is a visual component within a <b>workbench page</b>.&nbsp;
+There are two types: <b>view</b> and <b>editor</b>, as defined by <tt>IViewPart</tt>
+and <tt>IEditorPart</tt>.&nbsp;&nbsp; An editor is typically used to edit
+or browse a document or input object.&nbsp; A view is typically used to
+navigate a hierarchy of information (like the workspace), open an editor,
+or display properties for the active editor.&nbsp; This package provides
+a base implementation for the definition of views and editors.
+<br>&nbsp;
+</body>
+</html>
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/plugin/AbstractUIPlugin.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/plugin/AbstractUIPlugin.java
new file mode 100644
index 0000000..cdea219
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/plugin/AbstractUIPlugin.java
@@ -0,0 +1,739 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2016 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 481319, 481318
+ *     Philipp Kunz <philipp.kunz@paratix.ch> - Bug 297922
+ *******************************************************************************/
+package org.eclipse.ui.plugin;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IPluginDescriptor;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Plugin;
+import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.jface.dialogs.DialogSettings;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTError;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WWinPluginAction;
+import org.eclipse.ui.internal.util.BundleUtility;
+import org.eclipse.ui.preferences.ScopedPreferenceStore;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleListener;
+
+/**
+ * Abstract base class for plug-ins that integrate with the Eclipse platform UI.
+ * <p>
+ * Subclasses obtain the following capabilities:
+ * </p>
+ * <p>
+ * Preferences
+ * <ul>
+ * <li> The platform core runtime contains general support for plug-in
+ *      preferences (<code>org.eclipse.core.runtime.Preferences</code>).
+ *      This class provides appropriate conversion to the older JFace preference
+ *      API (<code>org.eclipse.jface.preference.IPreferenceStore</code>).</li>
+ * <li> The method <code>getPreferenceStore</code> returns the JFace preference
+ *      store (cf. <code>Plugin.getPluginPreferences</code> which returns
+ *      a core runtime preferences object.</li>
+ * <li> Subclasses may reimplement <code>initializeDefaultPreferences</code>
+ *      to set up any default values for preferences using JFace API. In this
+ *      case, <code>initializeDefaultPluginPreferences</code> should not be
+ *      overridden.</li>
+ * <li> Subclasses may reimplement
+ *      <code>initializeDefaultPluginPreferences</code> to set up any default
+ *      values for preferences using core runtime API. In this
+ *      case, <code>initializeDefaultPreferences</code> should not be
+ *      overridden.</li>
+ * <li> Preferences are also saved automatically on plug-in shutdown.
+ *      However, saving preferences immediately after changing them is
+ *      strongly recommended, since that ensures that preference settings
+ *      are not lost even in the event of a platform crash.</li>
+ * </ul>
+ * Dialogs
+ * <ul>
+ * <li> The dialog store is read the first time <code>getDialogSettings</code>
+ *      is called.</li>
+ * <li> The dialog store allows the plug-in to "record" important choices made
+ *      by the user in a wizard or dialog, so that the next time the
+ *      wizard/dialog is used the widgets can be defaulted to better values. A
+ *      wizard could also use it to record the last 5 values a user entered into
+ *      an editable combo - to show "recent values". </li>
+ * <li> The dialog store is found in the file whose name is given by the
+ *      constant <code>FN_DIALOG_STORE</code>. A dialog store file is first
+ *      looked for in the plug-in's read/write state area; if not found there,
+ *      the plug-in's install directory is checked.
+ *      This allows a plug-in to ship with a read-only copy of a dialog store
+ *      file containing initial values for certain settings.</li>
+ * <li> Plug-in code can call <code>saveDialogSettings</code> to cause settings to
+ *      be saved in the plug-in's read/write state area. A plug-in may opt to do
+ *      this each time a wizard or dialog is closed to ensure the latest
+ *      information is always safe on disk. </li>
+ * <li> Dialog settings are also saved automatically on plug-in shutdown.</li>
+ * </ul>
+ * Images
+ * <ul>
+ * <li> A typical UI plug-in will have some images that are used very frequently
+ *      and so need to be cached and shared.  The plug-in's image registry
+ *      provides a central place for a plug-in to store its common images.
+ *      Images managed by the registry are created lazily as needed, and will be
+ *      automatically disposed of when the plug-in shuts down. Note that the
+ *      number of registry images should be kept to a minimum since many OSs
+ *      have severe limits on the number of images that can be in memory at once.
+ * </ul>
+ * <p>
+ * For easy access to your plug-in object, use the singleton pattern. Declare a
+ * static variable in your plug-in class for the singleton. Store the first
+ * (and only) instance of the plug-in class in the singleton when it is created.
+ * Then access the singleton when needed through a static <code>getDefault</code>
+ * method.
+ * </p>
+ * <p>
+ * See the description on {@link Plugin}.
+ * </p>
+ */
+public abstract class AbstractUIPlugin extends Plugin {
+
+    /**
+     * The name of the dialog settings file (value
+     * <code>"dialog_settings.xml"</code>).
+     */
+    private static final String FN_DIALOG_SETTINGS = "dialog_settings.xml"; //$NON-NLS-1$
+
+    /**
+     * Storage for dialog and wizard data; <code>null</code> if not yet
+     * initialized.
+     */
+    private IDialogSettings dialogSettings = null;
+
+    /**
+     * Storage for preferences.
+     */
+    private ScopedPreferenceStore preferenceStore;
+
+    /**
+     * The registry for all graphic images; <code>null</code> if not yet
+     * initialized.
+     */
+    private ImageRegistry imageRegistry = null;
+
+    /**
+     * The bundle listener used for kicking off refreshPluginActions().
+     *
+     * @since 3.0.1
+     */
+    private BundleListener bundleListener;
+
+    /**
+	 * The {@link #AbstractUIPlugin(IPluginDescriptor)} constructor was called
+	 * only for plug-ins which explicitly require the
+	 * org.eclipse.core.runtime.compatibility plug-in.
+	 *
+	 * It is not called anymore as Eclipse 4.6 removed this plug-in.
+	 */
+    @Deprecated
+	public AbstractUIPlugin(IPluginDescriptor descriptor) {
+        super(descriptor);
+    }
+
+    /**
+     * Creates an abstract UI plug-in runtime object.
+     * <p>
+     * Plug-in runtime classes are <code>BundleActivators</code> and so must
+     * have an default constructor.  This method is called by the runtime when
+     * the associated bundle is being activated.
+     * <p>
+     * For more details, see <code>Plugin</code>'s default constructor.
+     *
+     * @see Plugin#Plugin()
+     * @since 3.0
+     */
+    public AbstractUIPlugin() {
+        super();
+    }
+
+    /**
+     * Returns a new image registry for this plugin-in.  The registry will be
+     * used to manage images which are frequently used by the plugin-in.
+     * <p>
+     * The default implementation of this method creates an empty registry.
+     * Subclasses may override this method if needed.
+     * </p>
+     *
+     * @return ImageRegistry the resulting registry.
+     * @see #getImageRegistry
+     */
+    protected ImageRegistry createImageRegistry() {
+
+    	//If we are in the UI Thread use that
+    	if(Display.getCurrent() != null) {
+			return new ImageRegistry(Display.getCurrent());
+		}
+
+    	if(PlatformUI.isWorkbenchRunning()) {
+			return new ImageRegistry(PlatformUI.getWorkbench().getDisplay());
+		}
+
+    	//Invalid thread access if it is not the UI Thread
+    	//and the workbench is not created.
+    	throw new SWTError(SWT.ERROR_THREAD_INVALID_ACCESS);
+    }
+
+    /**
+     * Returns the dialog settings for this UI plug-in.
+     * The dialog settings is used to hold persistent state data for the various
+     * wizards and dialogs of this plug-in in the context of a workbench.
+     * <p>
+     * If an error occurs reading the dialog store, an empty one is quietly created
+     * and returned.
+     * </p>
+     * <p>
+     * Subclasses may override this method but are not expected to.
+     * </p>
+     *
+     * @return the dialog settings
+     */
+    public IDialogSettings getDialogSettings() {
+        if (dialogSettings == null) {
+			loadDialogSettings();
+		}
+        return dialogSettings;
+    }
+
+    /**
+     * Returns the image registry for this UI plug-in.
+     * <p>
+     * The image registry contains the images used by this plug-in that are very
+     * frequently used and so need to be globally shared within the plug-in. Since
+     * many OSs have a severe limit on the number of images that can be in memory at
+     * any given time, a plug-in should only keep a small number of images in their
+     * registry.
+     * <p>
+     * Subclasses should reimplement <code>initializeImageRegistry</code> if they have
+     * custom graphic images to load.
+     * </p>
+     * <p>
+     * Subclasses may override this method but are not expected to.
+     * </p>
+     *
+     * @return the image registry
+     */
+    public ImageRegistry getImageRegistry() {
+     // RAP [bm]: replaced by session scoped one
+//      if (imageRegistry == null) {
+//          imageRegistry = createImageRegistry();
+//          initializeImageRegistry(imageRegistry);
+//      }
+      String imageRegistryKey
+          = AbstractUIPlugin.class.getName()
+          + ".imageRegistry-"
+          + getBundle().getSymbolicName();
+      ImageRegistry imageRegistry = ( ImageRegistry )RWT.getUISession().getAttribute( imageRegistryKey );
+      if( imageRegistry == null ) {
+        imageRegistry = createImageRegistry();
+        initializeImageRegistry( imageRegistry );
+        RWT.getUISession().setAttribute( imageRegistryKey, imageRegistry );
+      }
+      return imageRegistry;
+    }
+
+    /**
+     * Returns the preference store for this UI plug-in.
+     * This preference store is used to hold persistent settings for this plug-in in
+     * the context of a workbench. Some of these settings will be user controlled,
+     * whereas others may be internal setting that are never exposed to the user.
+     * <p>
+     * If an error occurs reading the preference store, an empty preference store is
+     * quietly created, initialized with defaults, and returned.
+     * </p>
+     * <p>
+     * <strong>NOTE:</strong> As of Eclipse 3.1 this method is
+     * no longer referring to the core runtime compatibility layer and so
+     * plug-ins relying on Plugin#initializeDefaultPreferences
+     * will have to access the compatibility layer themselves.
+     * </p>
+     *
+     * @return the preference store
+     */
+    public IPreferenceStore getPreferenceStore() {
+        // Create the preference store lazily.
+        if (preferenceStore == null) {
+			preferenceStore = new ScopedPreferenceStore(InstanceScope.INSTANCE, getBundle().getSymbolicName());
+
+        }
+        return preferenceStore;
+    }
+
+    /**
+     * Returns the Platform UI workbench.
+     * <p>
+     * This method exists as a convenience for plugin implementors.  The
+     * workbench can also be accessed by invoking <code>PlatformUI.getWorkbench()</code>.
+     * </p>
+     * @return IWorkbench the workbench for this plug-in
+     */
+    public IWorkbench getWorkbench() {
+        return PlatformUI.getWorkbench();
+    }
+
+    /**
+     * Initializes a preference store with default preference values
+     * for this plug-in.
+     * <p>
+     * This method is called after the preference store is initially loaded
+     * (default values are never stored in preference stores).
+     * </p>
+     * <p>
+     * The default implementation of this method does nothing.
+     * Subclasses should reimplement this method if the plug-in has any preferences.
+     * </p>
+     * <p>
+     * A subclass may reimplement this method to set default values for the
+     * preference store using JFace API. This is the older way of initializing
+     * default values. If this method is reimplemented, do not override
+     * <code>initializeDefaultPluginPreferences()</code>.
+     * </p>
+     *
+     * @param store the preference store to fill
+     *
+     * @deprecated this is only called if the runtime compatibility layer is
+     *             present. See {@link #initializeDefaultPluginPreferences}.
+     */
+    @Deprecated
+	protected void initializeDefaultPreferences(IPreferenceStore store) {
+        // spec'ed to do nothing
+    }
+
+    /**
+     * The <code>AbstractUIPlugin</code> implementation of this
+     * <code>Plugin</code> method forwards to
+     * <code>initializeDefaultPreferences(IPreferenceStore)</code>.
+     * <p>
+     * A subclass may reimplement this method to set default values for the core
+     * runtime preference store in the standard way. This is the recommended way
+     * to do this. The older
+     * <code>initializeDefaultPreferences(IPreferenceStore)</code> method
+     * serves a similar purpose. If this method is reimplemented, do not send
+     * super, and do not override
+     * <code>initializeDefaultPreferences(IPreferenceStore)</code>.
+     * </p>
+     *
+     * @deprecated this is only called if the runtime compatibility layer is
+     *             present. See the deprecated comment in
+     *             {@link Plugin#initializeDefaultPluginPreferences}.
+     *
+     * @see #initializeDefaultPreferences
+     * @since 2.0
+     */
+    @Deprecated
+	@Override
+	protected void initializeDefaultPluginPreferences() {
+        // N.B. by the time this method is called, the plug-in has a
+        // core runtime preference store (no default values)
+
+        // call loadPreferenceStore (only) for backwards compatibility with Eclipse 1.0
+        loadPreferenceStore();
+        // call initializeDefaultPreferences (only) for backwards compatibility
+        // with Eclipse 1.0
+        initializeDefaultPreferences(getPreferenceStore());
+    }
+
+    /**
+     * Initializes an image registry with images which are frequently used by the
+     * plugin.
+     * <p>
+     * The image registry contains the images used by this plug-in that are very
+     * frequently used and so need to be globally shared within the plug-in. Since
+     * many OSs have a severe limit on the number of images that can be in memory
+     * at any given time, each plug-in should only keep a small number of images in
+     * its registry.
+     * </p><p>
+     * Implementors should create a JFace image descriptor for each frequently used
+     * image.  The descriptors describe how to create/find the image should it be needed.
+     * The image described by the descriptor is not actually allocated until someone
+     * retrieves it.
+     * </p><p>
+     * Subclasses may override this method to fill the image registry.
+     * </p>
+     * @param reg the registry to initialize
+     *
+     * @see #getImageRegistry
+     */
+    protected void initializeImageRegistry(ImageRegistry reg) {
+        // spec'ed to do nothing
+    }
+
+    /**
+     * Loads the dialog settings for this plug-in.
+     * The default implementation first looks for a standard named file in the
+     * plug-in's read/write state area; if no such file exists, the plug-in's
+     * install directory is checked to see if one was installed with some default
+     * settings; if no file is found in either place, a new empty dialog settings
+     * is created. If a problem occurs, an empty settings is silently used.
+     * <p>
+     * This framework method may be overridden, although this is typically
+     * unnecessary.
+     * </p>
+     */
+    protected void loadDialogSettings() {
+        dialogSettings = new DialogSettings("Workbench"); //$NON-NLS-1$
+
+        // bug 69387: The instance area should not be created (in the call to
+        // #getStateLocation) if -data @none or -data @noDefault was used
+        IPath dataLocation = getStateLocationOrNull();
+        if (dataLocation != null) {
+	        // try r/w state area in the local file system
+	        String readWritePath = dataLocation.append(FN_DIALOG_SETTINGS)
+	                .toOSString();
+	        File settingsFile = new File(readWritePath);
+	        if (settingsFile.exists()) {
+	            try {
+	                dialogSettings.load(readWritePath);
+	            } catch (IOException e) {
+	                // load failed so ensure we have an empty settings
+	                dialogSettings = new DialogSettings("Workbench"); //$NON-NLS-1$
+	            }
+
+	            return;
+	        }
+        }
+
+        // otherwise look for bundle specific dialog settings
+        URL dsURL = BundleUtility.find(getBundle(), FN_DIALOG_SETTINGS);
+        if (dsURL == null) {
+			return;
+		}
+
+        InputStream is = null;
+        try {
+            is = dsURL.openStream();
+            BufferedReader reader = new BufferedReader(
+					new InputStreamReader(is, StandardCharsets.UTF_8));
+            dialogSettings.load(reader);
+        } catch (IOException e) {
+            // load failed so ensure we have an empty settings
+            dialogSettings = new DialogSettings("Workbench"); //$NON-NLS-1$
+        } finally {
+            try {
+                if (is != null) {
+					is.close();
+				}
+            } catch (IOException e) {
+                // do nothing
+            }
+        }
+    }
+
+    /**
+     * Loads the preference store for this plug-in.
+     * The default implementation looks for a standard named file in the
+     * plug-in's read/write state area. If no file is found or a problem
+     * occurs, a new empty preference store is silently created.
+     * <p>
+     * This framework method may be overridden, although this is typically
+     * unnecessary.
+     * </p>
+     *
+     * @deprecated As of Eclipse 2.0, a basic preference store exists for all
+     * plug-ins. This method now exists only for backwards compatibility.
+     * It is called as the plug-in's preference store is being initialized.
+     * The plug-ins preferences are loaded from the file regardless of what
+     * this method does.
+     */
+    @Deprecated
+	protected void loadPreferenceStore() {
+        // do nothing by default
+    }
+
+    /**
+     * Refreshes the actions for the plugin.
+     * This method is called from <code>startup</code>.
+     * <p>
+     * This framework method may be overridden, although this is typically
+     * unnecessary.
+     * </p>
+     */
+    protected void refreshPluginActions() {
+        // If the workbench is not started yet, or is no longer running, do nothing.
+        if (!PlatformUI.isWorkbenchRunning()) {
+			return;
+		}
+
+        // startup() is not guaranteed to be called in the UI thread,
+        // but refreshPluginActions must run in the UI thread,
+        // so use asyncExec.  See bug 6623 for more details.
+        Display.getDefault().asyncExec(() -> WWinPluginAction.refreshActionList());
+    }
+
+    /**
+     * Saves this plug-in's dialog settings.
+     * Any problems which arise are silently ignored.
+     */
+    protected void saveDialogSettings() {
+        if (dialogSettings == null) {
+            return;
+        }
+
+        try {
+        	IPath path = getStateLocationOrNull();
+        	if(path == null) {
+				return;
+			}
+            String readWritePath = path
+                    .append(FN_DIALOG_SETTINGS).toOSString();
+            dialogSettings.save(readWritePath);
+        } catch (IOException e) {
+            // spec'ed to ignore problems
+        } catch (IllegalStateException e) {
+            // spec'ed to ignore problems
+        }
+    }
+
+    /**
+     * Saves this plug-in's preference store.
+     * Any problems which arise are silently ignored.
+     *
+     * @see Plugin#savePluginPreferences()
+     * @deprecated As of Eclipse 2.0, preferences exist for all plug-ins. The
+     * equivalent of this method is <code>Plugin.savePluginPreferences</code>.
+     * This method now calls <code>savePluginPreferences</code>, and exists only for
+     * backwards compatibility.
+     */
+    @Deprecated
+	protected void savePreferenceStore() {
+        savePluginPreferences();
+    }
+
+    /**
+	 * The startup method was called
+	 * only for plug-ins which explicitly require the
+	 * org.eclipse.core.runtime.compatibility plug-in.
+	 *
+	 * It is not called anymore as Eclipse 4.6 removed this plug-in.
+	 */
+    @Deprecated
+	@Override
+	public void startup() throws CoreException {
+        // this method no longer does anything
+        // the code that used to be here in 2.1 has moved to start(BundleContext)
+        super.startup();
+    }
+
+    /**
+     * The <code>AbstractUIPlugin</code> implementation of this <code>Plugin</code>
+     * method does nothing. Subclasses may extend this method, but must send
+     * super first.
+     * @deprecated
+     * In Eclipse 3.0, <code>shutdown</code> has been replaced by {@link Plugin#stop(BundleContext context)}.
+     * Implementations of <code>shutdown</code> should be changed to extend
+     * <code>stop(BundleContext context)</code> and call <code>super.stop(context)</code>
+     * instead of <code>super.shutdown()</code>. Unlike <code>super.shutdown()</code>,
+     * <code>super.stop(context)</code> must be called as the very <b>last</b> thing rather
+     * than as the very first thing. The <code>shutdown</code> method is called
+     * only for plug-ins which explicitly require the
+     * org.eclipse.core.runtime.compatibility plug-in;
+     * in contrast, the <code>stop</code> method is always called.
+     */
+    @Deprecated
+	@Override
+	public void shutdown() throws CoreException {
+        // this method no longer does anything interesting
+        // the code that used to be here in 2.1 has moved to stop(BundleContext),
+        //   which is called regardless of whether the plug-in being instantiated
+        //   requires org.eclipse.core.runtime.compatibility
+        super.shutdown();
+    }
+
+    /**
+     * The <code>AbstractUIPlugin</code> implementation of this <code>Plugin</code>
+     * method refreshes the plug-in actions.  Subclasses may extend this method,
+     * but must send super <b>first</b>.
+     * {@inheritDoc}
+     *
+     * @since 3.0
+     */
+    @Override
+	public void start(BundleContext context) throws Exception {
+        super.start(context);
+		final BundleContext fc = context;
+        // Should only attempt refreshPluginActions() once the bundle
+        // has been fully started.  Otherwise, action delegates
+        // can be created while in the process of creating
+        // a triggering action delegate (if UI events are processed during startup).
+        // Also, if the start throws an exception, the bundle will be shut down.
+        // We don't want to have created any delegates if this happens.
+        // See bug 63324 for more details.
+        bundleListener = new BundleListener() {
+            @Override
+			public void bundleChanged(BundleEvent event) {
+                if (event.getBundle() == getBundle()) {
+                    if (event.getType() == BundleEvent.STARTED) {
+                        // We're getting notified that the bundle has been started.
+                        // Make sure it's still active.  It may have been shut down between
+                        // the time this event was dispatched and now.
+                        if (getBundle().getState() == Bundle.ACTIVE) {
+                            refreshPluginActions();
+                        }
+                        try {
+                            fc.removeBundleListener(this);
+                        } catch (IllegalStateException ex) {
+                            // bundleListener is removed in stop(BundleContext)
+                        }
+                    }
+                }
+            }
+        };
+        context.addBundleListener(bundleListener);
+    }
+
+    /**
+     * The <code>AbstractUIPlugin</code> implementation of this {@link Plugin}
+     * method saves this plug-in's preference and dialog stores and shuts down
+     * its image registry (if they are in use). Subclasses may extend this
+     * method, but must send super <b>last</b>. A try-finally statement should
+     * be used where necessary to ensure that <code>super.stop()</code> is
+     * always done.
+     * {@inheritDoc}
+     *
+     * @since 3.0
+     */
+    @Override
+	public void stop(BundleContext context) throws Exception {
+        try {
+            if (bundleListener != null) {
+                context.removeBundleListener(bundleListener);
+            }
+            saveDialogSettings();
+            savePreferenceStore();
+            preferenceStore = null;
+            if (imageRegistry != null)
+            	imageRegistry.dispose();
+            imageRegistry = null;
+        } finally {
+            super.stop(context);
+        }
+    }
+
+	/**
+	 * Creates and returns a new image descriptor for an image file located
+	 * within the specified plug-in.
+	 * <p>
+	 * This is a convenience method that simply locates the image file in within
+	 * the plug-in. It will now query the ISharedImages registry first. The path
+	 * is relative to the root of the plug-in, and takes into account files
+	 * coming from plug-in fragments. The path may include $arg$ elements.
+	 * However, the path must not have a leading "." or path separator. Clients
+	 * should use a path like "icons/mysample.png" rather than
+	 * "./icons/mysample.png" or "/icons/mysample.png".
+	 * </p>
+	 *
+	 * @param pluginId
+	 *            the id of the plug-in containing the image file;
+	 *            <code>null</code> is returned if the plug-in does not exist
+	 * @param imageFilePath
+	 *            the relative path of the image file, relative to the root of
+	 *            the plug-in; the path must be legal
+	 * @return an image descriptor, or <code>null</code> if no image could be
+	 *         found
+	 * @since 3.0
+	 */
+    public static ImageDescriptor imageDescriptorFromPlugin(String pluginId,
+            String imageFilePath) {
+        if (pluginId == null || imageFilePath == null) {
+            throw new IllegalArgumentException();
+        }
+
+		IWorkbench workbench = PlatformUI.isWorkbenchRunning() ? PlatformUI.getWorkbench() : null;
+		ImageDescriptor imageDescriptor = workbench == null ? null : workbench
+				.getSharedImages().getImageDescriptor(imageFilePath);
+		if (imageDescriptor != null)
+			return imageDescriptor; // found in the shared images
+
+        // if the bundle is not ready then there is no image
+        Bundle bundle = Platform.getBundle(pluginId);
+        if (!BundleUtility.isReady(bundle)) {
+			return null;
+		}
+
+		// Don't resolve the URL here, but create a URL using the
+		// "platform:/plugin" protocol, which also supports fragments.
+		// Caveat: The resulting URL may contain $nl$ etc., which is not
+		// directly supported by PlatformURLConnection and needs to go through
+		// FileLocator#find(URL), see bug 250432.
+		IPath uriPath = new Path("/plugin").append(pluginId).append(imageFilePath); //$NON-NLS-1$
+		URL url;
+		try {
+			URI uri = new URI("platform", null, uriPath.toString(), null); //$NON-NLS-1$
+			url = uri.toURL();
+		} catch (MalformedURLException | URISyntaxException e) {
+			return null;
+		}
+
+		// look for the image
+		URL fullPathString = FileLocator.find(url);
+		url = fullPathString;
+		if (fullPathString == null) {
+			// If not found, reinterpret imageFilePath as full URL.
+			// This is unspecified, but apparently widely-used, see bug 395126.
+			try {
+				url = new URL(imageFilePath);
+			} catch (MalformedURLException e) {
+				return null;
+			}
+		}
+		// create image descriptor with the platform:/ URL
+		return ImageDescriptor.createFromURL(url);
+    }
+
+    /**
+     * FOR INTERNAL WORKBENCH USE ONLY.
+     *
+     * Returns the path to a location in the file system that can be used
+     * to persist/restore state between workbench invocations.
+     * If the location did not exist prior to this call it will  be created.
+     * Returns <code>null</code> if no such location is available.
+     *
+     * @return path to a location in the file system where this plug-in can
+     * persist data between sessions, or <code>null</code> if no such
+     * location is available.
+     * @since 3.1
+     */
+    private IPath getStateLocationOrNull() {
+        try {
+            return getStateLocation();
+        } catch (IllegalStateException e) {
+            // This occurs if -data=@none is explicitly specified, so ignore this silently.
+            // Is this OK? See bug 85071.
+            return null;
+        }
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/plugin/package.html b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/plugin/package.html
new file mode 100644
index 0000000..45c39da
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/plugin/package.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <meta name="Author" content="IBM">
+   <meta name="GENERATOR" content="Mozilla/4.5 [en] (WinNT; I) [Netscape]">
+   <title>Package-level Javadoc</title>
+</head>
+<body>
+Class hierarchies for plug-ins that integrate with
+the Eclipse Platform UI.
+<h2>
+Package Specification</h2>
+A <b>Plug-in</b> is a bundle of extensions for the Platform.&nbsp; This
+package contains support for the creation of User Interface Plug-ins, plug-ins
+which define extension points for the Platform User Interface.
+<br>&nbsp;
+</body>
+</html>
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/preferences/IWorkbenchPreferenceContainer.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/preferences/IWorkbenchPreferenceContainer.java
new file mode 100644
index 0000000..9eb152c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/preferences/IWorkbenchPreferenceContainer.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.preferences;
+
+import org.eclipse.core.runtime.jobs.Job;
+
+/**
+ * IWorkbenchPreferenceContainer is the class that specifies
+ * the workbench specific preferences support.
+ * @since 3.1
+ *
+ */
+public interface IWorkbenchPreferenceContainer {
+
+	/**
+	 * Open the page specified in the org.eclipse.ui.preferencePage
+	 * extension point with id pageId. Apply data to it
+	 * when it is opened.
+	 * @param preferencePageId String the id specified for a page in
+	 *    the plugin.xml of its defining plug-in.
+	 * @param data The data to be applied to the page when it
+	 * 		opens.
+	 * @return boolean <code>true</code> if the page was
+	 * opened successfully and data was applied.
+	 */
+	public boolean openPage(String preferencePageId, Object data);
+
+	/**
+	 * Get the working copy manager in use by this preference
+	 * page container. This IWorkingCopyManager will have
+	 * IWorkingCopyManager#applyChanges()
+	 * @return IWorkingCopyManager
+	 */
+	public IWorkingCopyManager getWorkingCopyManager();
+
+	/**
+	 * Register a job to be run after the container has been closed.
+	 * @param job
+	 */
+	public void registerUpdateJob(Job job);
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/preferences/IWorkingCopyManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/preferences/IWorkingCopyManager.java
new file mode 100644
index 0000000..7f4ec35
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/preferences/IWorkingCopyManager.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.preferences;
+
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.osgi.service.prefs.BackingStoreException;
+
+/**
+ * IWorkingCopyManager is the interface for the working copy
+ * support for references to shared preference nodes.
+ * @since 3.1
+ *
+ */
+public interface IWorkingCopyManager {
+	/**
+	 * Return a working copy instance based on the given preference node. If a
+	 * working copy already exists then return it, otherwise create one and keep
+	 * track of it for other clients who are looking for it.
+	 *
+	 * @param original
+	 *            the original node
+	 * @return the working copy node
+	 */
+	public IEclipsePreferences getWorkingCopy(IEclipsePreferences original);
+
+	/**
+	 * Apply the changes for <em>all</em> working copies, to their original
+	 * preference nodes. Alternatively, if a client wishes to apply the changes
+	 * for a single working copy they can call <code>#flush</code> on that
+	 * working copy node.
+	 *
+	 * @throws BackingStoreException
+	 *             if there were problems accessing the backing store
+	 */
+	public void applyChanges() throws BackingStoreException;
+
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/preferences/ScopedPreferenceStore.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/preferences/ScopedPreferenceStore.java
new file mode 100644
index 0000000..2f67b28
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/preferences/ScopedPreferenceStore.java
@@ -0,0 +1,967 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2012 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
+ *     Yves YANG <yves.yang@soyatec.com> -
+ *     		Initial Fix for Bug 138078 [Preferences] Preferences Store for i18n support
+ *******************************************************************************/
+package org.eclipse.ui.preferences;
+
+import java.io.IOException;
+
+import org.eclipse.core.commands.common.EventManager;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.IScopeContext;
+import org.eclipse.jface.preference.IPersistentPreferenceStore;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.rap.rwt.service.UISession;
+import org.eclipse.rap.ui.internal.preferences.SessionScope;
+
+/**
+ * The ScopedPreferenceStore is an IPreferenceStore that uses the scopes
+ * provided in org.eclipse.core.runtime.preferences.
+ * <p>
+ * A ScopedPreferenceStore does the lookup of a preference based on it's search
+ * scopes and sets the value of the preference based on its store scope.
+ * </p>
+ * <p>
+ * The default scope is always included in the search scopes when searching for
+ * preference values.
+ * </p>
+ * 
+ * @see org.eclipse.core.runtime.preferences
+ * @since 1.1
+ */
+public class ScopedPreferenceStore extends EventManager implements
+		IPreferenceStore, IPersistentPreferenceStore {
+
+    // RAP [fappel]: key used to access the session local core implementation
+    private static final String KEY_SCOPED_PREF_CORE
+      = ScopedPreferenceStoreCore.class.getName() + "#Store"; //$NON-NLS-1$
+
+    // RAP [fappel]: reference for non session specifics
+    private ScopedPreferenceStoreCore defaultScopedPrefStore;
+    
+// RAP [fappel]: moved to session specific core	
+//	/**
+//	 * The storeContext is the context where values will stored with the
+//	 * setValue methods. If there are no searchContexts this will be the search
+//	 * context. (along with the "default" context)
+//	 */
+//	private IScopeContext storeContext;
+	
+    private IScopeContext scopeContext;
+
+// RAP [fappel]: moved to session specific core	
+//	/**
+//	 * The searchContext is the array of contexts that will be used by the get
+//	 * methods for searching for values.
+//	 */
+//	private IScopeContext[] searchContexts;
+
+// RAP [fappel]: moved to session specific core	
+//	/**
+//	 * A boolean to indicate the property changes should not be propagated.
+//	 */
+//	protected boolean silentRunning = false;
+
+// RAP [fappel]: moved to session specific core	
+//	/**
+//	 * The listener on the IEclipsePreferences. This is used to forward updates
+//	 * to the property change listeners on the preference store.
+//	 */
+//	IEclipsePreferences.IPreferenceChangeListener preferencesListener;
+
+// RAP [fappel]: moved to session specific core	
+//	/**
+//	 * The default context is the context where getDefault and setDefault
+//	 * methods will search. This context is also used in the search.
+//	 */
+//	private IScopeContext defaultContext = new DefaultScope();
+
+	/**
+	 * The nodeQualifer is the string used to look up the node in the contexts.
+	 */
+	String nodeQualifier;
+
+	/**
+	 * The defaultQualifier is the string used to look up the default node.
+	 */
+	String defaultQualifier;
+
+// RAP [fappel]: moved to session specific core	
+//	/**
+//	 * Boolean value indicating whether or not this store has changes to be
+//	 * saved.
+//	 */
+//	private boolean dirty;
+
+	/**
+	 * Create a new instance of the receiver. Store the values in context in the
+	 * node looked up by qualifier. <strong>NOTE:</strong> Any instance of
+	 * ScopedPreferenceStore should call
+	 * 
+	 * @param context
+	 *            the scope to store to
+	 * @param qualifier
+	 *            the qualifier used to look up the preference node
+	 * @param defaultQualifierPath
+	 *            the qualifier used when looking up the defaults
+	 */
+	public ScopedPreferenceStore(IScopeContext context, String qualifier,
+			String defaultQualifierPath) {
+		this(context, qualifier);
+		this.defaultQualifier = defaultQualifierPath;
+	}
+
+	/**
+	 * Create a new instance of the receiver. Store the values in context in the
+	 * node looked up by qualifier.
+	 *
+	 * @param context
+	 *            the scope to store to
+	 * @param qualifier
+	 *            the qualifer used to look up the preference node
+	 */
+    public ScopedPreferenceStore(IScopeContext context, String qualifier) {
+        // RAP [fappel]:
+        createScopedPreferenceStoreCore( context, qualifier, qualifier );
+        
+          this.scopeContext = context;
+          this.nodeQualifier = qualifier;
+          this.defaultQualifier = qualifier;
+
+// RAP [fappel]: moved to session specific core 
+//        ((IEclipsePreferences) getStorePreferences().parent())
+//                .addNodeChangeListener(getNodeChangeListener());
+      }
+    
+// RAP [fappel]:    
+    private void createScopedPreferenceStoreCore( final IScopeContext context,
+                                                  final String qualifier,
+                                                  final String defaultQualifier )
+    {
+      // The defaultScopedPrefStore instance is used for non session scope 
+      // contexts and the default values settings
+      defaultScopedPrefStore
+        = new ScopedPreferenceStoreCore( context, qualifier, defaultQualifier );
+    }
+    
+// RAP [fappel]:
+    private ScopedPreferenceStoreCore getCore() {
+      ScopedPreferenceStoreCore result = defaultScopedPrefStore;
+      // In case the scopeContext is of type SessionScope we need to reference
+      // an own ScopedPreferenceStore for each session
+      if( scopeContext instanceof SessionScope ) {
+        UISession uiSession = RWT.getUISession();
+        String key
+          = KEY_SCOPED_PREF_CORE + "/" + nodeQualifier + "/" + defaultQualifier;
+        result = ( ScopedPreferenceStoreCore )uiSession.getAttribute( key );
+        if( result == null ) {
+          result = new ScopedPreferenceStoreCore( scopeContext, 
+                                                  nodeQualifier, 
+                                                  defaultQualifier );
+          uiSession.setAttribute( key, result );
+        }
+      }
+      return result;
+    }
+    
+// RAP [fappel]: moved to core
+//	/**
+//	 * Return a node change listener that adds a removes the receiver when nodes
+//	 * change.
+//	 *
+//	 * @return INodeChangeListener
+//	 */
+//	private INodeChangeListener getNodeChangeListener() {
+//		return new IEclipsePreferences.INodeChangeListener() {
+//			@Override
+//			public void added(NodeChangeEvent event) {
+//				if (nodeQualifier.equals(event.getChild().name())
+//						&& isListenerAttached()) {
+//					getStorePreferences().addPreferenceChangeListener(
+//							preferencesListener);
+//				}
+//			}
+//
+//			@Override
+//			public void removed(NodeChangeEvent event) {
+//				// Do nothing as there are no events from removed node
+//			}
+//		};
+//	}
+//
+//	/**
+//	 * Initialize the preferences listener.
+//	 */
+//	private void initializePreferencesListener() {
+//		if (preferencesListener == null) {
+//			preferencesListener = event -> {
+//
+//				if (silentRunning) {
+//					return;
+//				}
+//
+//				Object oldValue = event.getOldValue();
+//				Object newValue = event.getNewValue();
+//				String key = event.getKey();
+//				if (newValue == null) {
+//					newValue = getDefault(key, oldValue);
+//				} else if (oldValue == null) {
+//					oldValue = getDefault(key, newValue);
+//				}
+//				firePropertyChangeEvent(event.getKey(), oldValue, newValue);
+//			};
+//			getStorePreferences().addPreferenceChangeListener(
+//					preferencesListener);
+//		}
+//
+//	}
+
+	/**
+	 * Does its best at determining the default value for the given key. Checks
+	 * the given object's type and then looks in the list of defaults to see if
+	 * a value exists. If not or if there is a problem converting the value, the
+	 * default default value for that type is returned.
+	 *
+	 * @param key
+	 *            the key to search
+	 * @param obj
+	 *            the object who default we are looking for
+	 * @return Object or <code>null</code>
+	 */
+	Object getDefault(String key, Object obj) {
+// RAP [fappel]: moved to core
+//		IEclipsePreferences defaults = getDefaultPreferences();
+//		if (obj instanceof String) {
+//			return defaults.get(key, STRING_DEFAULT_DEFAULT);
+//		} else if (obj instanceof Integer) {
+//			return new Integer(defaults.getInt(key, INT_DEFAULT_DEFAULT));
+//		} else if (obj instanceof Double) {
+//			return new Double(defaults.getDouble(key, DOUBLE_DEFAULT_DEFAULT));
+//		} else if (obj instanceof Float) {
+//			return new Float(defaults.getFloat(key, FLOAT_DEFAULT_DEFAULT));
+//		} else if (obj instanceof Long) {
+//			return new Long(defaults.getLong(key, LONG_DEFAULT_DEFAULT));
+//		} else if (obj instanceof Boolean) {
+//			return defaults.getBoolean(key, BOOLEAN_DEFAULT_DEFAULT) ? Boolean.TRUE
+//					: Boolean.FALSE;
+//		} else {
+//			return null;
+//		}
+	  return defaultScopedPrefStore.getDefault( key, obj );
+	}
+
+	/**
+	 * Return the IEclipsePreferences node associated with this store.
+	 * 
+	 * @return the preference node for this store
+	 */
+	IEclipsePreferences getStorePreferences() {
+// RAP [fappel]: moved to core
+//		return storeContext.getNode(nodeQualifier);
+	  return getCore().getStorePreferences();
+	}
+
+// RAP [fappel]: moved to core
+//	/**
+//	 * Return the default IEclipsePreferences for this store.
+//	 * 
+//	 * @return this store's default preference node
+//	 */
+//	private IEclipsePreferences getDefaultPreferences() {
+//		return defaultContext.getNode(defaultQualifier);
+//	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.eclipse.jface.preference.IPreferenceStore#addPropertyChangeListener(org.eclipse.jface.util.IPropertyChangeListener)
+	 */
+	public void addPropertyChangeListener(IPropertyChangeListener listener) {
+// RAP [fappel]: moved to core
+//		initializePreferencesListener();// Create the preferences listener if it
+//		// does not exist
+//		addListenerObject(listener);
+	  getCore().addPropertyChangeListener( listener );
+	}
+
+	/**
+	 * Return the preference path to search preferences on. This is the list of
+	 * preference nodes based on the scope contexts for this store. If there are
+	 * no search contexts set, then return this store's context.
+	 * <p>
+	 * Whether or not the default context should be included in the resulting
+	 * list is specified by the <code>includeDefault</code> parameter.
+	 * </p>
+	 * 
+	 * @param includeDefault
+	 *            <code>true</code> if the default context should be included
+	 *            and <code>false</code> otherwise
+	 * @return IEclipsePreferences[]
+	 */
+	public IEclipsePreferences[] getPreferenceNodes(boolean includeDefault) {
+// RAP [fappel]: moved to core
+//		// if the user didn't specify a search order, then return the scope that
+//		// this store was created on. (and optionally the default)
+//		if (searchContexts == null) {
+//			if (includeDefault) {
+//				return new IEclipsePreferences[] { getStorePreferences(),
+//						getDefaultPreferences() };
+//			}
+//			return new IEclipsePreferences[] { getStorePreferences() };
+//		}
+//		// otherwise the user specified a search order so return the appropriate
+//		// nodes based on it
+//		int length = searchContexts.length;
+//		if (includeDefault) {
+//			length++;
+//		}
+//		IEclipsePreferences[] preferences = new IEclipsePreferences[length];
+//		for (int i = 0; i < searchContexts.length; i++) {
+//			preferences[i] = searchContexts[i].getNode(nodeQualifier);
+//		}
+//		if (includeDefault) {
+//			preferences[length - 1] = getDefaultPreferences();
+//		}
+//		return preferences;
+	  return getCore().getPreferenceNodes( includeDefault );
+	}
+
+	/**
+	 * Set the search contexts to scopes. When searching for a value the seach
+	 * will be done in the order of scope contexts and will not search the
+	 * storeContext unless it is in this list.
+	 * <p>
+	 * If the given list is <code>null</code>, then clear this store's search
+	 * contexts. This means that only this store's scope context and default
+	 * scope will be used during preference value searching.
+	 * </p>
+	 * <p>
+	 * The defaultContext will be added to the end of this list automatically
+	 * and <em>MUST NOT</em> be included by the user.
+	 * </p>
+	 *
+	 * @param scopes
+	 *            a list of scope contexts to use when searching, or
+	 *            <code>null</code>
+	 */
+	public void setSearchContexts(IScopeContext[] scopes) {
+// RAP [fappel]: moved to core
+//		this.searchContexts = scopes;
+//		if (scopes == null) {
+//			return;
+//		}
+//
+//		// Assert that the default was not included (we automatically add it to
+//		// the end)
+//		for (IScopeContext scope : scopes) {
+//			if (scope.equals(defaultContext)) {
+//				Assert
+//						.isTrue(
+//								false,
+//								WorkbenchMessages.ScopedPreferenceStore_DefaultAddedError);
+//			}
+//		}
+	    getCore().setSearchContexts( scopes );
+	}
+
+	/*
+     * (non-Javadoc)
+     * 
+     * @see org.eclipse.jface.preference.IPreferenceStore#contains(java.lang.String)
+     */
+	@Override
+	public boolean contains(String name) {
+// RAP [fappel]: moved to core
+//		if (name == null) {
+//			return false;
+//		}
+//		return (Platform.getPreferencesService().get(name, null,
+//				getPreferenceNodes(true))) != null;
+	    return getCore().contains( name );
+	}
+
+	/*
+     * (non-Javadoc)
+     * 
+     * @see org.eclipse.jface.preference.IPreferenceStore#firePropertyChangeEvent(java.lang.String,
+     *      java.lang.Object, java.lang.Object)
+     */
+	@Override
+	public void firePropertyChangeEvent(String name, Object oldValue,
+			Object newValue) {
+// RAP [fappel]: moved to core	    
+//		// important: create intermediate array to protect against listeners
+//		// being added/removed during the notification
+//		final Object[] listeners = getListeners();
+//		if (listeners.length == 0) {
+//			return;
+//		}
+//		final PropertyChangeEvent event = new PropertyChangeEvent(this, name, oldValue, newValue);
+//		for (Object listener : listeners) {
+//			final IPropertyChangeListener propertyChangeListener = (IPropertyChangeListener) listener;
+//			SafeRunner.run(new SafeRunnable(JFaceResources.getString("PreferenceStore.changeError")) { //$NON-NLS-1$
+//				@Override
+//				public void run() {
+//					propertyChangeListener.propertyChange(event);
+//				}
+//			});
+//		}
+	    getCore().firePropertyChangeEvent( name, oldValue, newValue );
+	}
+
+	/*
+     * (non-Javadoc)
+     * 
+     * @see org.eclipse.jface.preference.IPreferenceStore#getBoolean(java.lang.String)
+     */
+	@Override
+	public boolean getBoolean(String name) {
+// RAP [fappel]: moved to core	    
+//		String value = internalGet(name);
+//		return value == null ? BOOLEAN_DEFAULT_DEFAULT : Boolean.valueOf(value)
+//				.booleanValue();
+	    return getCore().getBoolean( name );
+	}
+
+	   /*
+     * (non-Javadoc)
+     * 
+     * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultBoolean(java.lang.String)
+     */
+	@Override
+	public boolean getDefaultBoolean(String name) {
+// RAP [fappel]: moved to core
+//		return getDefaultPreferences()
+//				.getBoolean(name, BOOLEAN_DEFAULT_DEFAULT);
+	    return defaultScopedPrefStore.getDefaultBoolean( name );
+	}
+
+	/*
+     * (non-Javadoc)
+     * 
+     * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultDouble(java.lang.String)
+     */
+	@Override
+	public double getDefaultDouble(String name) {
+// RAP [fappel]: moved to core
+//		return getDefaultPreferences().getDouble(name, DOUBLE_DEFAULT_DEFAULT);
+	    return defaultScopedPrefStore.getDefaultDouble( name );
+	}
+
+	   /*
+     * (non-Javadoc)
+     * 
+     * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultFloat(java.lang.String)
+     */
+    public float getDefaultFloat(String name) {
+// RAP [fappel]: moved to core
+//      return getDefaultPreferences().getFloat(name, FLOAT_DEFAULT_DEFAULT);
+        return defaultScopedPrefStore.getDefaultFloat( name );
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultInt(java.lang.String)
+     */
+    public int getDefaultInt(String name) {
+// RAP [fappel]: moved to core
+//      return getDefaultPreferences().getInt(name, INT_DEFAULT_DEFAULT);
+        return defaultScopedPrefStore.getDefaultInt( name );
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultLong(java.lang.String)
+     */
+    public long getDefaultLong(String name) {
+// RAP [fappel]: moved to core
+//      return getDefaultPreferences().getLong(name, LONG_DEFAULT_DEFAULT);
+        return defaultScopedPrefStore.getDefaultLong( name );
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultString(java.lang.String)
+     */
+    public String getDefaultString(String name) {
+// RAP [fappel]: moved to core
+//      return getDefaultPreferences().get(name, STRING_DEFAULT_DEFAULT);
+        return defaultScopedPrefStore.getDefaultString( name );
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.eclipse.jface.preference.IPreferenceStore#getDouble(java.lang.String)
+     */
+    public double getDouble(String name) {
+// RAP [fappel]: moved to core
+//      String value = internalGet(name);
+//      if (value == null) {
+//          return DOUBLE_DEFAULT_DEFAULT;
+//      }
+//      try {
+//          return Double.parseDouble(value);
+//      } catch (NumberFormatException e) {
+//          return DOUBLE_DEFAULT_DEFAULT;
+//      }
+        return getCore().getDouble( name );
+    }
+
+// RAP [fappel] moved to core
+//	/**
+//	 * Return the string value for the specified key. Look in the nodes which
+//	 * are specified by this object's list of search scopes. If the value does
+//	 * not exist then return <code>null</code>.
+//	 *
+//	 * @param key
+//	 *            the key to search with
+//	 * @return String or <code>null</code> if the value does not exist.
+//	 */
+//	private String internalGet(String key) {
+//		return Platform.getPreferencesService().get(key, null,
+//				getPreferenceNodes(true));
+//	}
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.eclipse.jface.preference.IPreferenceStore#getFloat(java.lang.String)
+     */
+	@Override
+	public float getFloat(String name) {
+// RAP [fappel] moved to core
+//		String value = internalGet(name);
+//		if (value == null) {
+//			return FLOAT_DEFAULT_DEFAULT;
+//		}
+//		try {
+//			return Float.parseFloat(value);
+//		} catch (NumberFormatException e) {
+//			return FLOAT_DEFAULT_DEFAULT;
+//		}
+	    return getCore().getFloat( name );
+	}
+
+	/*
+     * (non-Javadoc)
+     * 
+     * @see org.eclipse.jface.preference.IPreferenceStore#getInt(java.lang.String)
+     */
+    public int getInt(String name) {
+// RAP [fappel] moved to core
+//      String value = internalGet(name);
+//      if (value == null) {
+//          return INT_DEFAULT_DEFAULT;
+//      }
+//      try {
+//          return Integer.parseInt(value);
+//      } catch (NumberFormatException e) {
+//          return INT_DEFAULT_DEFAULT;
+//      }
+        return getCore().getInt( name );
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.eclipse.jface.preference.IPreferenceStore#getLong(java.lang.String)
+     */
+    public long getLong(String name) {
+// RAP [fappel] moved to core
+//      String value = internalGet(name);
+//      if (value == null) {
+//          return LONG_DEFAULT_DEFAULT;
+//      }
+//      try {
+//          return Long.parseLong(value);
+//      } catch (NumberFormatException e) {
+//          return LONG_DEFAULT_DEFAULT;
+//      }
+        return getCore().getLong( name );
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.eclipse.jface.preference.IPreferenceStore#getString(java.lang.String)
+     */
+    public String getString(String name) {
+// RAP [fappel] moved to core
+//      String value = internalGet(name);
+//      return value == null ? STRING_DEFAULT_DEFAULT : value;
+        return getCore().getString( name );
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.eclipse.jface.preference.IPreferenceStore#isDefault(java.lang.String)
+     */
+    public boolean isDefault(String name) {
+// RAP [fappel] moved to core
+//      if (name == null) {
+//          return false;
+//      }
+//      return (Platform.getPreferencesService().get(name, null,
+//              getPreferenceNodes(false))) == null;
+        return getCore().isDefault( name );
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.eclipse.jface.preference.IPreferenceStore#needsSaving()
+     */
+    public boolean needsSaving() {
+// RAP [fappel] moved to core
+//      return dirty;
+        return getCore().needsSaving();
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.eclipse.jface.preference.IPreferenceStore#putValue(java.lang.String,
+     *      java.lang.String)
+     */
+    public void putValue(String name, String value) {
+// RAP [fappel] moved to core
+//      try {
+//          // Do not notify listeners
+//          silentRunning = true;
+//          getStorePreferences().put(name, value);
+//      } finally {
+//          // Be sure that an exception does not stop property updates
+//          silentRunning = false;
+//          dirty = true;
+//      }
+        getCore().putValue( name, value );
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.eclipse.jface.preference.IPreferenceStore#removePropertyChangeListener(org.eclipse.jface.util.IPropertyChangeListener)
+     */
+    public void removePropertyChangeListener(IPropertyChangeListener listener) {
+// RAP [fappel] moved to core
+//      removeListenerObject(listener);
+//      if (!isListenerAttached()) {
+//          disposePreferenceStoreListener();
+//      }
+        getCore().removePropertyChangeListener( listener );
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String,
+     *      double)
+     */
+    public void setDefault(String name, double value) {
+// RAP [fappel] moved to core
+//      getDefaultPreferences().putDouble(name, value);
+        defaultScopedPrefStore.setDefault( name, value );
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String,
+     *      float)
+     */
+    public void setDefault(String name, float value) {
+// RAP [fappel] moved to core
+//      getDefaultPreferences().putFloat(name, value);
+        defaultScopedPrefStore.setDefault( name, value );
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String,
+     *      int)
+     */
+    public void setDefault(String name, int value) {
+// RAP [fappel] moved to core
+//      getDefaultPreferences().putInt(name, value);
+        defaultScopedPrefStore.setDefault( name, value );
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String,
+     *      long)
+     */
+    public void setDefault(String name, long value) {
+// RAP [fappel] moved to core
+//      getDefaultPreferences().putLong(name, value);
+        defaultScopedPrefStore.setDefault( name, value );
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String,
+     *      java.lang.String)
+     */
+    public void setDefault(String name, String defaultObject) {
+// RAP [fappel] moved to core
+//      getDefaultPreferences().put(name, defaultObject);
+        defaultScopedPrefStore.setDefault( name, defaultObject );
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String,
+     *      boolean)
+     */
+    public void setDefault(String name, boolean value) {
+// RAP [fappel] moved to core
+//      getDefaultPreferences().putBoolean(name, value);
+        defaultScopedPrefStore.setDefault( name, value );
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.eclipse.jface.preference.IPreferenceStore#setToDefault(java.lang.String)
+     */
+    public void setToDefault(String name) {
+// RAP [fappel] moved to core
+//      String oldValue = getString(name);
+//      String defaultValue = getDefaultString(name);
+//      try {
+//          silentRunning = true;// Turn off updates from the store
+//          // removing a non-existing preference is a no-op so call the Core
+//          // API directly
+//          getStorePreferences().remove(name);
+//          if (oldValue != defaultValue){
+//              dirty = true;
+//              firePropertyChangeEvent(name, oldValue, defaultValue);
+//          }
+//              
+//      } finally {
+//          silentRunning = false;// Restart listening to preferences
+//      }
+        defaultScopedPrefStore.setToDefault( name );
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String,
+     *      double)
+     */
+    public void setValue(String name, double value) {
+// RAP [fappel] moved to core
+//      double oldValue = getDouble(name);
+//      if (oldValue == value) {
+//          return;
+//      }
+//      try {
+//          silentRunning = true;// Turn off updates from the store
+//          if (getDefaultDouble(name) == value) {
+//              getStorePreferences().remove(name);
+//          } else {
+//              getStorePreferences().putDouble(name, value);
+//          }
+//          dirty = true;
+//          firePropertyChangeEvent(name, new Double(oldValue), new Double(
+//                  value));
+//      } finally {
+//          silentRunning = false;// Restart listening to preferences
+//      }
+        getCore().setValue( name, value );
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String,
+     *      float)
+     */
+    public void setValue(String name, float value) {
+// RAP [fappel] moved to core
+//      float oldValue = getFloat(name);
+//      if (oldValue == value) {
+//          return;
+//      }
+//      try {
+//          silentRunning = true;// Turn off updates from the store
+//          if (getDefaultFloat(name) == value) {
+//              getStorePreferences().remove(name);
+//          } else {
+//              getStorePreferences().putFloat(name, value);
+//          }
+//          dirty = true;
+//          firePropertyChangeEvent(name, new Float(oldValue), new Float(value));
+//      } finally {
+//          silentRunning = false;// Restart listening to preferences
+//      }
+      getCore().setValue( name, value );
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String,
+     *      int)
+     */
+    public void setValue(String name, int value) {
+// RAP [fappel] moved to core
+//      int oldValue = getInt(name);
+//      if (oldValue == value) {
+//          return;
+//      }
+//      try {
+//          silentRunning = true;// Turn off updates from the store
+//          if (getDefaultInt(name) == value) {
+//              getStorePreferences().remove(name);
+//          } else {
+//              getStorePreferences().putInt(name, value);
+//          }
+//          dirty = true;
+//          firePropertyChangeEvent(name, new Integer(oldValue), new Integer(
+//                  value));
+//      } finally {
+//          silentRunning = false;// Restart listening to preferences
+//      }
+      getCore().setValue( name, value );
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String,
+     *      long)
+     */
+    public void setValue(String name, long value) {
+// RAP [fappel] moved to core
+//      long oldValue = getLong(name);
+//      if (oldValue == value) {
+//          return;
+//      }
+//      try {
+//          silentRunning = true;// Turn off updates from the store
+//          if (getDefaultLong(name) == value) {
+//              getStorePreferences().remove(name);
+//          } else {
+//              getStorePreferences().putLong(name, value);
+//          }
+//          dirty = true;
+//          firePropertyChangeEvent(name, new Long(oldValue), new Long(value));
+//      } finally {
+//          silentRunning = false;// Restart listening to preferences
+//      }
+      getCore().setValue( name, value );
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String,
+     *      java.lang.String)
+     */
+    public void setValue(String name, String value) {
+// RAP [fappel] moved to core
+//      // Do not turn on silent running here as Strings are propagated
+//      if (getDefaultString(name).equals(value)) {
+//          getStorePreferences().remove(name);
+//      } else {
+//          getStorePreferences().put(name, value);
+//      }
+//      dirty = true;
+      getCore().setValue( name, value );
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String,
+     *      boolean)
+     */
+    public void setValue(String name, boolean value) {
+// RAP [fappel] moved to core
+//      boolean oldValue = getBoolean(name);
+//      if (oldValue == value) {
+//          return;
+//      }
+//      try {
+//          silentRunning = true;// Turn off updates from the store
+//          if (getDefaultBoolean(name) == value) {
+//              getStorePreferences().remove(name);
+//          } else {
+//              getStorePreferences().putBoolean(name, value);
+//          }
+//          dirty = true;
+//          firePropertyChangeEvent(name, oldValue ? Boolean.TRUE
+//                  : Boolean.FALSE, value ? Boolean.TRUE : Boolean.FALSE);
+//      } finally {
+//          silentRunning = false;// Restart listening to preferences
+//      }
+      getCore().setValue( name, value );
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.eclipse.jface.preference.IPersistentPreferenceStore#save()
+     */
+    public void save() throws IOException {
+// RAP [fappel] moved to core
+//      try {
+//          getStorePreferences().flush();
+//          dirty = false;
+//      } catch (BackingStoreException e) {
+//          throw new IOException(e.getMessage());
+//      }
+        getCore().save();
+    }
+
+// RAP [fappel] moved to core
+//  /**
+//   * Dispose the receiver.
+//   */
+//  private void disposePreferenceStoreListener() {
+//
+//      IEclipsePreferences root = (IEclipsePreferences) Platform
+//              .getPreferencesService().getRootNode().node(
+//                      Plugin.PLUGIN_PREFERENCE_SCOPE);
+//      try {
+//          if (!(root.nodeExists(nodeQualifier))) {
+//              return;
+//          }
+//      } catch (BackingStoreException e) {
+//          return;// No need to report here as the node won't have the
+//          // listener
+//      }
+//
+//      IEclipsePreferences preferences = getStorePreferences();
+//      if (preferences == null) {
+//          return;
+//      }
+//      if (preferencesListener != null) {
+//          preferences.removePreferenceChangeListener(preferencesListener);
+//          preferencesListener = null;
+//      }
+//  }
+
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/preferences/ScopedPreferenceStoreCore.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/preferences/ScopedPreferenceStoreCore.java
new file mode 100644
index 0000000..0d44c58
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/preferences/ScopedPreferenceStoreCore.java
@@ -0,0 +1,842 @@
+/*******************************************************************************
+ * Copyright (c) 2002, 2008 Innoopract Informationssysteme GmbH.
+ * 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:
+ *     Innoopract Informationssysteme GmbH - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.ui.preferences;
+
+import java.io.IOException;
+
+import org.eclipse.core.commands.common.EventManager;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Plugin;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.core.runtime.preferences.DefaultScope;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.IScopeContext;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences.INodeChangeListener;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences.NodeChangeEvent;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent;
+import org.eclipse.jface.preference.IPersistentPreferenceStore;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.jface.util.SafeRunnable;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.osgi.service.prefs.BackingStoreException;
+
+final class  ScopedPreferenceStoreCore
+  extends EventManager
+  implements IPreferenceStore, IPersistentPreferenceStore
+{
+
+  /**
+   * The storeContext is the context where values will stored with the
+   * setValue methods. If there are no searchContexts this will be the search
+   * context. (along with the "default" context)
+   */
+  private IScopeContext storeContext;
+
+  /**
+   * The searchContext is the array of contexts that will be used by the get
+   * methods for searching for values.
+   */
+  private IScopeContext[] searchContexts;
+
+  /**
+   * A boolean to indicate the property changes should not be propagated.
+   */
+  protected boolean silentRunning = false;
+
+  /**
+   * The listener on the IEclipsePreferences. This is used to forward updates
+   * to the property change listeners on the preference store.
+   */
+  IEclipsePreferences.IPreferenceChangeListener preferencesListener;
+
+  /**
+   * The default context is the context where getDefault and setDefault
+   * methods will search. This context is also used in the search.
+   */
+  private IScopeContext defaultContext = new DefaultScope();
+
+  /**
+   * The nodeQualifer is the string used to look up the node in the contexts.
+   */
+  String nodeQualifier;
+
+  /**
+   * The defaultQualifier is the string used to look up the default node.
+   */
+  String defaultQualifier;
+
+  /**
+   * Boolean value indicating whether or not this store has changes to be
+   * saved.
+   */
+  private boolean dirty;
+
+  /**
+   * Create a new instance of the receiver. Store the values in context in the
+   * node looked up by qualifier. <strong>NOTE:</strong> Any instance of
+   * ScopedPreferenceStore should call
+   * 
+   * @param context
+   *            the scope to store to
+   * @param qualifier
+   *            the qualifier used to look up the preference node
+   * @param defaultQualifierPath
+   *            the qualifier used when looking up the defaults
+   */
+  ScopedPreferenceStoreCore(IScopeContext context, String qualifier,
+          String defaultQualifierPath) {
+      this(context, qualifier);
+      this.defaultQualifier = defaultQualifierPath;
+  }
+
+  /**
+   * Create a new instance of the receiver. Store the values in context in the
+   * node looked up by qualifier.
+   * 
+   * @param context
+   *            the scope to store to
+   * @param qualifier
+   *            the qualifer used to look up the preference node
+   */
+  ScopedPreferenceStoreCore(IScopeContext context, String qualifier) {
+      storeContext = context;
+      this.nodeQualifier = qualifier;
+      this.defaultQualifier = qualifier;
+
+      ((IEclipsePreferences) getStorePreferences().parent())
+              .addNodeChangeListener(getNodeChangeListener());
+  }
+
+  /**
+   * Return a node change listener that adds a removes the receiver when nodes
+   * change.
+   * 
+   * @return INodeChangeListener
+   */
+  private INodeChangeListener getNodeChangeListener() {
+      return new IEclipsePreferences.INodeChangeListener() {
+          /*
+           * (non-Javadoc)
+           * 
+           * @see org.eclipse.core.runtime.preferences.IEclipsePreferences.INodeChangeListener#added(org.eclipse.core.runtime.preferences.IEclipsePreferences.NodeChangeEvent)
+           */
+          public void added(NodeChangeEvent event) {
+              if (nodeQualifier.equals(event.getChild().name())
+                      && isListenerAttached()) {
+                  getStorePreferences().addPreferenceChangeListener(
+                          preferencesListener);
+              }
+          }
+
+          /*
+           * (non-Javadoc)
+           * 
+           * @see org.eclipse.core.runtime.preferences.IEclipsePreferences.INodeChangeListener#removed(org.eclipse.core.runtime.preferences.IEclipsePreferences.NodeChangeEvent)
+           */
+          public void removed(NodeChangeEvent event) {
+              // Do nothing as there are no events from removed node
+          }
+      };
+  }
+
+  /**
+   * Initialize the preferences listener.
+   */
+  private void initializePreferencesListener() {
+      if (preferencesListener == null) {
+          preferencesListener = new IEclipsePreferences.IPreferenceChangeListener() {
+              /*
+               * (non-Javadoc)
+               * 
+               * @see org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener#preferenceChange(org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent)
+               */
+              public void preferenceChange(PreferenceChangeEvent event) {
+
+                  if (silentRunning) {
+                      return;
+                  }
+
+                  Object oldValue = event.getOldValue();
+                  Object newValue = event.getNewValue();
+                  String key = event.getKey();
+                  if (newValue == null) {
+                      newValue = getDefault(key, oldValue);
+                  } else if (oldValue == null) {
+                      oldValue = getDefault(key, newValue);
+                  }
+                  firePropertyChangeEvent(event.getKey(), oldValue, newValue);
+              }
+          };
+          getStorePreferences().addPreferenceChangeListener(
+                  preferencesListener);
+      }
+
+  }
+
+  /**
+   * Does its best at determining the default value for the given key. Checks
+   * the given object's type and then looks in the list of defaults to see if
+   * a value exists. If not or if there is a problem converting the value, the
+   * default default value for that type is returned.
+   * 
+   * @param key
+   *            the key to search
+   * @param obj
+   *            the object who default we are looking for
+   * @return Object or <code>null</code>
+   */
+  Object getDefault(String key, Object obj) {
+      IEclipsePreferences defaults = getDefaultPreferences();
+      if (obj instanceof String) {
+          return defaults.get(key, STRING_DEFAULT_DEFAULT);
+      } else if (obj instanceof Integer) {
+          return new Integer(defaults.getInt(key, INT_DEFAULT_DEFAULT));
+      } else if (obj instanceof Double) {
+          return new Double(defaults.getDouble(key, DOUBLE_DEFAULT_DEFAULT));
+      } else if (obj instanceof Float) {
+          return new Float(defaults.getFloat(key, FLOAT_DEFAULT_DEFAULT));
+      } else if (obj instanceof Long) {
+          return new Long(defaults.getLong(key, LONG_DEFAULT_DEFAULT));
+      } else if (obj instanceof Boolean) {
+          return defaults.getBoolean(key, BOOLEAN_DEFAULT_DEFAULT) ? Boolean.TRUE : Boolean.FALSE;
+      } else {
+          return null;
+      }
+  }
+
+  /**
+   * Return the IEclipsePreferences node associated with this store.
+   * 
+   * @return the preference node for this store
+   */
+  IEclipsePreferences getStorePreferences() {
+      return storeContext.getNode(nodeQualifier);
+  }
+
+  /**
+   * Return the default IEclipsePreferences for this store.
+   * 
+   * @return this store's default preference node
+   */
+  private IEclipsePreferences getDefaultPreferences() {
+      return defaultContext.getNode(defaultQualifier);
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.eclipse.jface.preference.IPreferenceStore#addPropertyChangeListener(org.eclipse.jface.util.IPropertyChangeListener)
+   */
+  public void addPropertyChangeListener(IPropertyChangeListener listener) {
+      initializePreferencesListener();// Create the preferences listener if it
+      // does not exist
+      addListenerObject(listener);
+  }
+
+  /**
+   * Return the preference path to search preferences on. This is the list of
+   * preference nodes based on the scope contexts for this store. If there are
+   * no search contexts set, then return this store's context.
+   * <p>
+   * Whether or not the default context should be included in the resulting
+   * list is specified by the <code>includeDefault</code> parameter.
+   * </p>
+   * 
+   * @param includeDefault
+   *            <code>true</code> if the default context should be included
+   *            and <code>false</code> otherwise
+   * @return IEclipsePreferences[]
+   */
+  public IEclipsePreferences[] getPreferenceNodes(boolean includeDefault) {
+      // if the user didn't specify a search order, then return the scope that
+      // this store was created on. (and optionally the default)
+      if (searchContexts == null) {
+          if (includeDefault) {
+              return new IEclipsePreferences[] { getStorePreferences(),
+                      getDefaultPreferences() };
+          }
+          return new IEclipsePreferences[] { getStorePreferences() };
+      }
+      // otherwise the user specified a search order so return the appropriate
+      // nodes based on it
+      int length = searchContexts.length;
+      if (includeDefault) {
+          length++;
+      }
+      IEclipsePreferences[] preferences = new IEclipsePreferences[length];
+      for (int i = 0; i < searchContexts.length; i++) {
+          preferences[i] = searchContexts[i].getNode(nodeQualifier);
+      }
+      if (includeDefault) {
+          preferences[length - 1] = getDefaultPreferences();
+      }
+      return preferences;
+  }
+
+  /**
+   * Set the search contexts to scopes. When searching for a value the seach
+   * will be done in the order of scope contexts and will not search the
+   * storeContext unless it is in this list.
+   * <p>
+   * If the given list is <code>null</code>, then clear this store's search
+   * contexts. This means that only this store's scope context and default
+   * scope will be used during preference value searching.
+   * </p>
+   * <p>
+   * The defaultContext will be added to the end of this list automatically
+   * and <em>MUST NOT</em> be included by the user.
+   * </p>
+   * 
+   * @param scopes
+   *            a list of scope contexts to use when searching, or
+   *            <code>null</code>
+   */
+  public void setSearchContexts(IScopeContext[] scopes) {
+      this.searchContexts = scopes;
+      if (scopes == null) {
+          return;
+      }
+
+      // Assert that the default was not included (we automatically add it to
+      // the end)
+      for (int i = 0; i < scopes.length; i++) {
+          if (scopes[i].equals(defaultContext)) {
+              Assert
+                      .isTrue(
+                              false,
+                              WorkbenchMessages.get().ScopedPreferenceStore_DefaultAddedError);
+          }
+      }
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.eclipse.jface.preference.IPreferenceStore#contains(java.lang.String)
+   */
+  public boolean contains(String name) {
+      if (name == null) {
+          return false;
+      }
+      return (Platform.getPreferencesService().get(name, null,
+              getPreferenceNodes(true))) != null;
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.eclipse.jface.preference.IPreferenceStore#firePropertyChangeEvent(java.lang.String,
+   *      java.lang.Object, java.lang.Object)
+   */
+  public void firePropertyChangeEvent(String name, Object oldValue,
+          Object newValue) {
+      // important: create intermediate array to protect against listeners
+      // being added/removed during the notification
+      final Object[] list = getListeners();
+      if (list.length == 0) {
+          return;
+      }
+      final PropertyChangeEvent event = new PropertyChangeEvent(this, name,
+              oldValue, newValue);
+      for (int i = 0; i < list.length; i++) {
+          final IPropertyChangeListener listener = (IPropertyChangeListener) list[i];
+          SafeRunner.run(new SafeRunnable(JFaceResources
+                  .getString("PreferenceStore.changeError")) { //$NON-NLS-1$
+                      public void run() {
+                          listener.propertyChange(event);
+                      }
+                  });
+      }
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.eclipse.jface.preference.IPreferenceStore#getBoolean(java.lang.String)
+   */
+  public boolean getBoolean(String name) {
+      String value = internalGet(name);
+      return value == null ? BOOLEAN_DEFAULT_DEFAULT : Boolean.valueOf(value)
+              .booleanValue();
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultBoolean(java.lang.String)
+   */
+  public boolean getDefaultBoolean(String name) {
+      return getDefaultPreferences()
+              .getBoolean(name, BOOLEAN_DEFAULT_DEFAULT);
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultDouble(java.lang.String)
+   */
+  public double getDefaultDouble(String name) {
+      return getDefaultPreferences().getDouble(name, DOUBLE_DEFAULT_DEFAULT);
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultFloat(java.lang.String)
+   */
+  public float getDefaultFloat(String name) {
+      return getDefaultPreferences().getFloat(name, FLOAT_DEFAULT_DEFAULT);
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultInt(java.lang.String)
+   */
+  public int getDefaultInt(String name) {
+      return getDefaultPreferences().getInt(name, INT_DEFAULT_DEFAULT);
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultLong(java.lang.String)
+   */
+  public long getDefaultLong(String name) {
+      return getDefaultPreferences().getLong(name, LONG_DEFAULT_DEFAULT);
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultString(java.lang.String)
+   */
+  public String getDefaultString(String name) {
+      return getDefaultPreferences().get(name, STRING_DEFAULT_DEFAULT);
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.eclipse.jface.preference.IPreferenceStore#getDouble(java.lang.String)
+   */
+  public double getDouble(String name) {
+      String value = internalGet(name);
+      if (value == null) {
+          return DOUBLE_DEFAULT_DEFAULT;
+      }
+      try {
+          return Double.parseDouble(value);
+      } catch (NumberFormatException e) {
+          return DOUBLE_DEFAULT_DEFAULT;
+      }
+  }
+
+  /**
+   * Return the string value for the specified key. Look in the nodes which
+   * are specified by this object's list of search scopes. If the value does
+   * not exist then return <code>null</code>.
+   * 
+   * @param key
+   *            the key to search with
+   * @return String or <code>null</code> if the value does not exist.
+   */
+  private String internalGet(String key) {
+      return Platform.getPreferencesService().get(key, null,
+              getPreferenceNodes(true));
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.eclipse.jface.preference.IPreferenceStore#getFloat(java.lang.String)
+   */
+  public float getFloat(String name) {
+      String value = internalGet(name);
+      if (value == null) {
+          return FLOAT_DEFAULT_DEFAULT;
+      }
+      try {
+          return Float.parseFloat(value);
+      } catch (NumberFormatException e) {
+          return FLOAT_DEFAULT_DEFAULT;
+      }
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.eclipse.jface.preference.IPreferenceStore#getInt(java.lang.String)
+   */
+  public int getInt(String name) {
+      String value = internalGet(name);
+      if (value == null) {
+          return INT_DEFAULT_DEFAULT;
+      }
+      try {
+          return Integer.parseInt(value);
+      } catch (NumberFormatException e) {
+          return INT_DEFAULT_DEFAULT;
+      }
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.eclipse.jface.preference.IPreferenceStore#getLong(java.lang.String)
+   */
+  public long getLong(String name) {
+      String value = internalGet(name);
+      if (value == null) {
+          return LONG_DEFAULT_DEFAULT;
+      }
+      try {
+          return Long.parseLong(value);
+      } catch (NumberFormatException e) {
+          return LONG_DEFAULT_DEFAULT;
+      }
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.eclipse.jface.preference.IPreferenceStore#getString(java.lang.String)
+   */
+  public String getString(String name) {
+      String value = internalGet(name);
+      return value == null ? STRING_DEFAULT_DEFAULT : value;
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.eclipse.jface.preference.IPreferenceStore#isDefault(java.lang.String)
+   */
+  public boolean isDefault(String name) {
+      if (name == null) {
+          return false;
+      }
+      return (Platform.getPreferencesService().get(name, null,
+              getPreferenceNodes(false))) == null;
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.eclipse.jface.preference.IPreferenceStore#needsSaving()
+   */
+  public boolean needsSaving() {
+      return dirty;
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.eclipse.jface.preference.IPreferenceStore#putValue(java.lang.String,
+   *      java.lang.String)
+   */
+  public void putValue(String name, String value) {
+      try {
+          // Do not notify listeners
+          silentRunning = true;
+          getStorePreferences().put(name, value);
+      } finally {
+          // Be sure that an exception does not stop property updates
+          silentRunning = false;
+          dirty = true;
+      }
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.eclipse.jface.preference.IPreferenceStore#removePropertyChangeListener(org.eclipse.jface.util.IPropertyChangeListener)
+   */
+  public void removePropertyChangeListener(IPropertyChangeListener listener) {
+      removeListenerObject(listener);
+      if (!isListenerAttached()) {
+          disposePreferenceStoreListener();
+      }
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String,
+   *      double)
+   */
+  public void setDefault(String name, double value) {
+      getDefaultPreferences().putDouble(name, value);
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String,
+   *      float)
+   */
+  public void setDefault(String name, float value) {
+      getDefaultPreferences().putFloat(name, value);
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String,
+   *      int)
+   */
+  public void setDefault(String name, int value) {
+      getDefaultPreferences().putInt(name, value);
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String,
+   *      long)
+   */
+  public void setDefault(String name, long value) {
+      getDefaultPreferences().putLong(name, value);
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String,
+   *      java.lang.String)
+   */
+  public void setDefault(String name, String defaultObject) {
+      getDefaultPreferences().put(name, defaultObject);
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String,
+   *      boolean)
+   */
+  public void setDefault(String name, boolean value) {
+      getDefaultPreferences().putBoolean(name, value);
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.eclipse.jface.preference.IPreferenceStore#setToDefault(java.lang.String)
+   */
+  public void setToDefault( String name ) {
+    String oldValue = getString( name );
+    String defaultValue = getDefaultString( name );
+    try {
+      silentRunning = true;// Turn off updates from the store
+      // removing a non-existing preference is a no-op so call the Core
+      // API directly
+      getStorePreferences().remove( name );
+      if( oldValue != defaultValue ) {
+        dirty = true;
+        firePropertyChangeEvent( name, oldValue, defaultValue );
+      }
+    } finally {
+      silentRunning = false;// Restart listening to preferences
+    }
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String,
+   *      double)
+   */
+  public void setValue(String name, double value) {
+      double oldValue = getDouble(name);
+      if (oldValue == value) {
+          return;
+      }
+      try {
+          silentRunning = true;// Turn off updates from the store
+          if (getDefaultDouble(name) == value) {
+              getStorePreferences().remove(name);
+          } else {
+              getStorePreferences().putDouble(name, value);
+          }
+          dirty = true;
+          firePropertyChangeEvent(name, new Double(oldValue), new Double(
+                  value));
+      } finally {
+          silentRunning = false;// Restart listening to preferences
+      }
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String,
+   *      float)
+   */
+  public void setValue(String name, float value) {
+      float oldValue = getFloat(name);
+      if (oldValue == value) {
+          return;
+      }
+      try {
+          silentRunning = true;// Turn off updates from the store
+          if (getDefaultFloat(name) == value) {
+              getStorePreferences().remove(name);
+          } else {
+              getStorePreferences().putFloat(name, value);
+          }
+          dirty = true;
+          firePropertyChangeEvent(name, new Float(oldValue), new Float(value));
+      } finally {
+          silentRunning = false;// Restart listening to preferences
+      }
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String,
+   *      int)
+   */
+  public void setValue(String name, int value) {
+      int oldValue = getInt(name);
+      if (oldValue == value) {
+          return;
+      }
+      try {
+          silentRunning = true;// Turn off updates from the store
+          if (getDefaultInt(name) == value) {
+              getStorePreferences().remove(name);
+          } else {
+              getStorePreferences().putInt(name, value);
+          }
+          dirty = true;
+          firePropertyChangeEvent(name, new Integer(oldValue), new Integer(
+                  value));
+      } finally {
+          silentRunning = false;// Restart listening to preferences
+      }
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String,
+   *      long)
+   */
+  public void setValue(String name, long value) {
+      long oldValue = getLong(name);
+      if (oldValue == value) {
+          return;
+      }
+      try {
+          silentRunning = true;// Turn off updates from the store
+          if (getDefaultLong(name) == value) {
+              getStorePreferences().remove(name);
+          } else {
+              getStorePreferences().putLong(name, value);
+          }
+          dirty = true;
+          firePropertyChangeEvent(name, new Long(oldValue), new Long(value));
+      } finally {
+          silentRunning = false;// Restart listening to preferences
+      }
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String,
+   *      java.lang.String)
+   */
+  public void setValue(String name, String value) {
+      // Do not turn on silent running here as Strings are propagated
+      if (getDefaultString(name).equals(value)) {
+          getStorePreferences().remove(name);
+      } else {
+          getStorePreferences().put(name, value);
+      }
+      dirty = true;
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String,
+   *      boolean)
+   */
+  public void setValue(String name, boolean value) {
+      boolean oldValue = getBoolean(name);
+      if (oldValue == value) {
+          return;
+      }
+      try {
+          silentRunning = true;// Turn off updates from the store
+          if (getDefaultBoolean(name) == value) {
+              getStorePreferences().remove(name);
+          } else {
+              getStorePreferences().putBoolean(name, value);
+          }
+          dirty = true;
+          firePropertyChangeEvent(name, oldValue ? Boolean.TRUE : Boolean.FALSE, 
+              value ? Boolean.TRUE : Boolean.FALSE);
+      } finally {
+          silentRunning = false;// Restart listening to preferences
+      }
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see org.eclipse.jface.preference.IPersistentPreferenceStore#save()
+   */
+  public void save() throws IOException {
+      try {
+          getStorePreferences().flush();
+          dirty = false;
+      } catch (BackingStoreException e) {
+          throw new IOException(e.getMessage());
+      }
+
+  }
+
+  /**
+   * Dispose the receiver.
+   */
+  private void disposePreferenceStoreListener() {
+
+      IEclipsePreferences root = (IEclipsePreferences) Platform
+              .getPreferencesService().getRootNode().node(
+                      Plugin.PLUGIN_PREFERENCE_SCOPE);
+      try {
+          if (!(root.nodeExists(nodeQualifier))) {
+              return;
+          }
+      } catch (BackingStoreException e) {
+          return;// No need to report here as the node won't have the
+          // listener
+      }
+
+      IEclipsePreferences preferences = getStorePreferences();
+      if (preferences == null) {
+          return;
+      }
+      if (preferencesListener != null) {
+          preferences.removePreferenceChangeListener(preferencesListener);
+          preferencesListener = null;
+      }
+  }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/preferences/SettingsTransfer.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/preferences/SettingsTransfer.java
new file mode 100644
index 0000000..d20b0c8
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/preferences/SettingsTransfer.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.preferences;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.ui.internal.preferences.SettingsTransferRegistryReader;
+
+/**
+ * The SettingsTransfer is the abstract superclass of settings transfers
+ * used when switching workspaces.
+ * @since 3.3
+ *
+ */
+public abstract class SettingsTransfer {
+
+	/**
+	 * Return the configuration elements for all of the settings
+	 * transfers.
+	 * @return IConfigurationElement[]
+	 */
+	public static IConfigurationElement[] getSettingsTransfers(){
+		return (new SettingsTransferRegistryReader()).getSettingTransfers();
+	}
+
+	/**
+	 * Transfer the settings to a workspace rooted at newWorkspacwe
+	 * @param newWorkspaceRoot
+	 * @return {@link IStatus} the status of the transfer.
+	 */
+	public abstract IStatus transferSettings(IPath newWorkspaceRoot);
+
+	/**
+	 * Return the name for the receiver.
+	 * @return String
+	 */
+	public abstract String getName() ;
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/preferences/ViewPreferencesAction.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/preferences/ViewPreferencesAction.java
new file mode 100644
index 0000000..07cc841
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/preferences/ViewPreferencesAction.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.preferences;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.ui.internal.WorkbenchMessages;
+
+/**
+ * The ViewPreferencesAction is the action for opening
+ * a view preferences dialog on a class.
+ *
+ * @since 3.1
+ */
+public abstract class ViewPreferencesAction extends Action {
+
+	/**
+	 * Create a new instance of the receiver.
+	 */
+	public ViewPreferencesAction() {
+		super(WorkbenchMessages.get().OpenPreferences_text);
+	}
+
+	@Override
+	public void run() {
+		openViewPreferencesDialog();
+	}
+
+	/**
+	 * Open a view preferences dialog for the receiver.
+	 */
+	public abstract void openViewPreferencesDialog();
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/preferences/ViewSettingsDialog.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/preferences/ViewSettingsDialog.java
new file mode 100644
index 0000000..e3eb1f8
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/preferences/ViewSettingsDialog.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.preferences;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * The ViewSettingsDialog is an abstract class that
+ * provides some common functionality for view preferences.
+ *
+ * @since 3.1
+ */
+public class ViewSettingsDialog extends Dialog {
+
+	private static int DEFAULTS_BUTTON_ID = 25;
+
+	/**
+	 * Create a new instance of the receiver.
+	 * @param parentShell
+	 */
+	public ViewSettingsDialog(Shell parentShell) {
+		super(parentShell);
+	}
+
+	@Override
+	protected void buttonPressed(int buttonId) {
+		if (buttonId == DEFAULTS_BUTTON_ID) {
+			performDefaults();
+		}
+		super.buttonPressed(buttonId);
+	}
+
+	 /**
+     * Performs special processing when this dialog Defaults button has been pressed.
+     * <p>
+     * This is a framework hook method for subclasses to do special things when
+     * the Defaults button has been pressed.
+     * Subclasses may override, but should call <code>super.performDefaults</code>.
+     * </p>
+     */
+	protected void performDefaults() {
+		//Do nothing by default
+
+	}
+
+	@Override
+	protected void createButtonsForButtonBar(Composite parent) {
+		parent.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+		createButton(parent, DEFAULTS_BUTTON_ID, JFaceResources.getString("defaults"), false); //$NON-NLS-1$
+
+		Label l = new Label(parent, SWT.NONE);
+		l.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+		l = new Label(parent, SWT.NONE);
+		l.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+		GridLayout layout = (GridLayout) parent.getLayout();
+		layout.numColumns += 2;
+		layout.makeColumnsEqualWidth = false;
+
+		super.createButtonsForButtonBar(parent);
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/preferences/WizardPropertyPage.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/preferences/WizardPropertyPage.java
new file mode 100644
index 0000000..c5e6fa8
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/preferences/WizardPropertyPage.java
@@ -0,0 +1,291 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.preferences;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.dialogs.IMessageProvider;
+import org.eclipse.jface.dialogs.ProgressMonitorDialog;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.wizard.IWizard;
+import org.eclipse.jface.wizard.IWizardContainer;
+import org.eclipse.jface.wizard.IWizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.dialogs.PropertyPage;
+
+/**
+ * The wizard property page can wrap a property page around a wizard.
+ * The property page shows the first page of the wizard. It is therefore
+ * required, that the wizard consists of exactly one page.
+ *
+ * @since 3.4
+ */
+public abstract class WizardPropertyPage extends PropertyPage {
+
+	private static final class PropertyPageWizardContainer implements IWizardContainer {
+
+		private final IWizard fWizard;
+		private final PropertyPage fPage;
+		private String fMessage;
+
+		private PropertyPageWizardContainer(PropertyPage page, IWizard wizard) {
+			Assert.isLegal(wizard.getPageCount() == 1);
+
+			fPage= page;
+			fWizard= wizard;
+		}
+
+		@Override
+		public IWizardPage getCurrentPage() {
+			return fWizard.getPages()[0];
+		}
+
+		@Override
+		public Shell getShell() {
+			return fPage.getShell();
+		}
+
+		@Override
+		public void showPage(IWizardPage page) {
+		}
+
+		@Override
+		public void updateButtons() {
+			fPage.setValid(fWizard.canFinish());
+		}
+
+		@Override
+		public void updateMessage() {
+			IWizardPage page= getCurrentPage();
+
+			String message= fPage.getMessage();
+			if (message != null &&
+					fMessage == null)
+				fMessage= message;
+
+			if (page.getErrorMessage() != null) {
+				fPage.setMessage(page.getErrorMessage(), ERROR);
+			} else if (page instanceof IMessageProvider) {
+				IMessageProvider messageProvider= (IMessageProvider)page;
+				if (messageProvider.getMessageType() != IMessageProvider.NONE) {
+					fPage.setMessage(messageProvider.getMessage(), messageProvider.getMessageType());
+				} else {
+					if (messageProvider.getMessage() != null &&
+							fMessage == null)
+						fMessage= messageProvider.getMessage();
+
+					fPage.setMessage(fMessage, NONE);
+				}
+			} else {
+				fPage.setErrorMessage(null);
+			}
+		}
+
+		@Override
+		public void updateTitleBar() {
+			IWizardPage page= getCurrentPage();
+			String name= page.getTitle();
+			if (name == null)
+				name= page.getName();
+
+			fPage.setMessage(name);
+		}
+
+		@Override
+		public void updateWindowTitle() {
+		}
+
+		@Override
+		public void run(boolean fork, boolean cancelable, IRunnableWithProgress runnable) throws InvocationTargetException, InterruptedException {
+			ProgressMonitorDialog dialog= new ProgressMonitorDialog(getShell());
+			dialog.run(fork, cancelable, runnable);
+		}
+	}
+
+	private IWizard fWizard;
+	private Composite fWizardPageContainer;
+
+	public WizardPropertyPage() {
+	}
+
+	/**
+	 * @return the wizard which is wrapped by this page or <b>null</b> if not yet created
+	 */
+	public IWizard getWizard() {
+		return fWizard;
+	}
+
+	/**
+	 * Return a wizard.
+	 *
+	 * @return an instance of the wizard to be wrapped or <b>null</b> if creation failed
+	 */
+	protected abstract IWizard createWizard();
+
+	/**
+	 * Apply the changes made on the property page
+	 */
+	protected abstract void applyChanges();
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	protected Control createContents(final Composite parent) {
+		fWizardPageContainer= new Composite(parent, SWT.NONE);
+		fWizardPageContainer.setFont(parent.getFont());
+		fWizardPageContainer.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+		GridLayout layout= new GridLayout(1, false);
+		layout.marginHeight= 0;
+		layout.marginWidth= 0;
+		fWizardPageContainer.setLayout(layout);
+
+		createWizardPageContent(fWizardPageContainer);
+
+		return fWizardPageContainer;
+	}
+
+	private void createWizardPageContent(Composite parent) {
+		fWizard= createWizard();
+		if (fWizard == null)
+			return;
+
+		fWizard.addPages();
+
+		PropertyPageWizardContainer wizardContainer= new PropertyPageWizardContainer(this, fWizard);
+		wizardContainer.updateButtons();
+		wizardContainer.updateMessage();
+		fWizard.setContainer(wizardContainer);
+
+		Composite messageComposite= new Composite(parent, SWT.NONE);
+		messageComposite.setFont(parent.getFont());
+		messageComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
+		GridLayout layout= new GridLayout(1, false);
+		layout.marginHeight= 0;
+		messageComposite.setLayout(layout);
+
+		Label messageLabel= new Label(messageComposite, SWT.WRAP);
+		messageLabel.setFont(messageComposite.getFont());
+		messageLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+		fWizard.createPageControls(parent);
+
+		IWizardPage page= fWizard.getPages()[0];
+		if (page.getControl() == null)
+			page.createControl(parent);
+
+		Control pageControl= page.getControl();
+		pageControl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+		setPageName(page);
+		setDescription(page, messageLabel);
+
+		page.setVisible(true);
+
+		setValid(fWizard.canFinish());
+	}
+
+	private void setPageName(IWizardPage page) {
+		String name= page.getTitle();
+		if (name == null)
+			name= page.getName();
+
+		setMessage(name);
+	}
+
+	private void setDescription(IWizardPage page, Label messageLabel) {
+		String description= null;
+		if (page.getDescription() != null) {
+			description= page.getDescription();
+		} else if (page instanceof IMessageProvider) {
+			IMessageProvider messageProvider= (IMessageProvider)page;
+			if (messageProvider.getMessageType() == IMessageProvider.NONE) {
+				description= messageProvider.getMessage();
+			}
+		}
+
+		if (description != null) {
+			messageLabel.setText(description);
+		} else {
+			messageLabel.setVisible(false);
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean performOk() {
+		fWizard.performFinish();
+		applyChanges();
+		fWizard.dispose();
+
+		return super.performOk();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean performCancel() {
+		fWizard.performCancel();
+		fWizard.dispose();
+
+		return super.performCancel();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	protected void performApply() {
+		fWizard.performFinish();
+		applyChanges();
+		fWizard.dispose();
+
+		rebuildWizardPage();
+
+		super.performApply();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	protected void performDefaults() {
+		fWizard.performCancel();
+		fWizard.dispose();
+
+		rebuildWizardPage();
+
+		super.performDefaults();
+	}
+
+	/**
+	 * Rebuilds the wizard page
+	 */
+	private void rebuildWizardPage() {
+		Control[] children= fWizardPageContainer.getChildren();
+		for (Control controlElement : children) {
+			controlElement.dispose();
+		}
+
+		createWizardPageContent(fWizardPageContainer);
+		fWizardPageContainer.getParent().layout(true, true);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/preferences/WorkingCopyManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/preferences/WorkingCopyManager.java
new file mode 100644
index 0000000..2a1900d
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/preferences/WorkingCopyManager.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.preferences;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.ui.internal.preferences.WorkingCopyPreferences;
+import org.osgi.service.prefs.BackingStoreException;
+
+/**
+ * WorkingCopyManager is a concrete implementation of an
+ * IWorkingCopyManager.
+ * <p>
+ * This class is not intended to be sub-classed by clients.
+ * </p>
+ * @since 3.2
+ */
+public class WorkingCopyManager implements IWorkingCopyManager{
+
+	private static final String EMPTY_STRING = "";//$NON-NLS-1$
+	// all working copies - maps absolute path to PreferencesWorkingCopy instance
+	private Map workingCopies = new HashMap();
+
+
+	@Override
+	public IEclipsePreferences getWorkingCopy(IEclipsePreferences original) {
+		if (original instanceof WorkingCopyPreferences) {
+			throw new IllegalArgumentException("Trying to get a working copy of a working copy"); //$NON-NLS-1$
+		}
+		String absolutePath = original.absolutePath();
+		IEclipsePreferences preferences = (IEclipsePreferences) workingCopies.get(absolutePath);
+		if (preferences == null) {
+			preferences = new WorkingCopyPreferences(original, this);
+			workingCopies.put(absolutePath, preferences);
+		}
+		return preferences;
+	}
+
+
+	@Override
+	public void applyChanges() throws BackingStoreException {
+		Collection values = workingCopies.values();
+		WorkingCopyPreferences[] valuesArray = (WorkingCopyPreferences[]) values.toArray(new WorkingCopyPreferences[values.size()]);
+		for (WorkingCopyPreferences prefs : valuesArray) {
+			if (prefs.nodeExists(EMPTY_STRING))
+				prefs.flush();
+		}
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/preferences/package.html b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/preferences/package.html
new file mode 100644
index 0000000..2e10186
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/preferences/package.html
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <meta name="Author" content="IBM">
+   <meta name="GENERATOR" content="Mozilla/4.5 [en] (WinNT; I) [Netscape]">
+   <title>Package-level Javadoc</title>
+</head>
+<body>
+Classes for using the preferences support in org.eclipse.core.runtime.preferences 
+<h2>
+Package Specification</h2>
+This package has the convenience classes provided by the Eclipse workbench for 
+use by clients who wish to use the core preference support added in 3.0.<br>
+&nbsp;
+</body>
+</html>
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/progress/DeferredTreeContentManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/progress/DeferredTreeContentManager.java
new file mode 100644
index 0000000..1a8b886
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/progress/DeferredTreeContentManager.java
@@ -0,0 +1,531 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 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.ui.progress;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.core.runtime.jobs.*;
+import org.eclipse.jface.viewers.AbstractTreeViewer;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.rap.ui.internal.progress.ProgressUtil;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.internal.progress.ProgressMessages;
+import org.eclipse.ui.internal.util.Util;
+import org.eclipse.ui.model.IWorkbenchAdapter;
+
+/**
+ * The DeferredContentManager is a class that helps an ITreeContentProvider get
+ * its deferred input.
+ * 
+ * <b>NOTE</b> AbstractTreeViewer#isExpandable may need to be implemented in
+ * AbstractTreeViewer subclasses with deferred content that use filtering as a
+ * call to #getChildren may be required to determine the correct state of the
+ * expanding control.
+ * 
+ * AbstractTreeViewers which use this class may wish to sacrifice accuracy of
+ * the expandable state indicator for the performance benefits of deferring
+ * content.
+ * 
+ * @see IDeferredWorkbenchAdapter
+ * @since 1.0
+ */
+public class DeferredTreeContentManager {
+
+	AbstractTreeViewer treeViewer;
+
+	IWorkbenchSiteProgressService progressService;
+
+	private ListenerList updateCompleteListenerList;
+
+    // RAP [if] display used to access NLS messages   
+    private final Display display;
+
+	/**
+	 * The DeferredContentFamily is a class used to keep track of a
+	 * manager-object pair so that only jobs scheduled by the receiver are
+	 * canceled by the receiver.
+	 */
+	class DeferredContentFamily {
+		protected DeferredTreeContentManager manager;
+		protected Object element;
+
+		/**
+		 * Create a new instance of the receiver to define a family for object
+		 * in a particular scheduling manager.
+		 * 
+		 * @param schedulingManager
+		 * @param object
+		 */
+		DeferredContentFamily(DeferredTreeContentManager schedulingManager,
+				Object object) {
+			this.manager = schedulingManager;
+			this.element = object;
+		}
+	}
+
+	/**
+	 * Create a new instance of the receiver using the supplied content provider
+	 * and viewer. Run any jobs using the site.
+	 * 
+	 * @param provider
+	 * @param viewer
+	 * @param site
+	 * @deprecated in 3.4. provider is not used by this class
+	 */
+	public DeferredTreeContentManager(ITreeContentProvider provider,
+			AbstractTreeViewer viewer, IWorkbenchPartSite site) {
+		this(viewer, site);
+	}
+
+	/**
+	 * Create a new instance of the receiver using the supplied content provider
+	 * and viewer.
+	 * 
+	 * @param provider
+	 *            The content provider that will be updated
+	 * @param viewer
+	 *            The tree viewer that the results are added to
+	 * @deprecated in 3.4. provider is not used by this class
+	 */
+	public DeferredTreeContentManager(ITreeContentProvider provider,
+			AbstractTreeViewer viewer) {
+		this(viewer);
+	}
+
+	/**
+	 * Create a new instance of the receiver using the supplied content provider
+	 * and viewer. Run any jobs using the site.
+	 * 
+	 * @param viewer
+	 * @param site
+	 * 
+	 * @since 1.1
+	 */
+	public DeferredTreeContentManager(AbstractTreeViewer viewer,
+			IWorkbenchPartSite site) {
+		this(viewer);
+		Object siteService = Util.getAdapter(site,
+				IWorkbenchSiteProgressService.class);
+		if (siteService != null) {
+			progressService = (IWorkbenchSiteProgressService) siteService;
+		}
+	}
+
+	/**
+	 * Create a new instance of the receiver using the supplied content provider
+	 * and viewer.
+	 * 
+	 * @param viewer
+	 *            The tree viewer that the results are added to
+	 * 
+	 * @since 1.1
+	 */
+	public DeferredTreeContentManager(AbstractTreeViewer viewer) {
+		treeViewer = viewer;
+		// RAP [if] display used to access NLS messages 
+		display = treeViewer.getControl().getDisplay();
+	}
+
+	/**
+	 * Provides an optimized lookup for determining if an element has children.
+	 * This is required because elements that are populated lazilly can't answer
+	 * <code>getChildren</code> just to determine the potential for children.
+	 * Throw an AssertionFailedException if element is null.
+	 * 
+	 * @param element
+	 *            The Object being tested. This should not be <code>null</code>.
+	 * @return boolean <code>true</code> if there are potentially children.
+	 * @throws RuntimeException
+	 *             if the element is null.
+	 */
+	public boolean mayHaveChildren(Object element) {
+		Assert.isNotNull(element,
+				ProgressMessages.get( display ).DeferredTreeContentManager_NotDeferred);
+		IDeferredWorkbenchAdapter adapter = getAdapter(element);
+		return adapter != null && adapter.isContainer();
+	}
+
+	/**
+	 * Returns the child elements of the given element, or in the case of a
+	 * deferred element, returns a placeholder. If a deferred element is used, a
+	 * job is created to fetch the children in the background.
+	 * 
+	 * @param parent
+	 *            The parent object.
+	 * @return Object[] or <code>null</code> if parent is not an instance of
+	 *         IDeferredWorkbenchAdapter.
+	 */
+	public Object[] getChildren(final Object parent) {
+		IDeferredWorkbenchAdapter element = getAdapter(parent);
+		if (element == null) {
+			return null;
+		}
+		PendingUpdateAdapter placeholder = createPendingUpdateAdapter();
+		startFetchingDeferredChildren(parent, element, placeholder);
+		return new Object[] { placeholder };
+	}
+
+	/**
+	 * Factory method for creating the pending update adapter representing the
+	 * placeholder node. Subclasses may override.
+	 * 
+	 * @return a pending update adapter
+	 * @since 1.0
+	 */
+	protected PendingUpdateAdapter createPendingUpdateAdapter() {
+		return new PendingUpdateAdapter();
+	}
+
+	/**
+	 * Return the IDeferredWorkbenchAdapter for element or the element if it is
+	 * an instance of IDeferredWorkbenchAdapter. If it does not exist return
+	 * null.
+	 * 
+	 * @param element
+	 * @return IDeferredWorkbenchAdapter or <code>null</code>
+	 */
+	protected IDeferredWorkbenchAdapter getAdapter(Object element) {
+		return (IDeferredWorkbenchAdapter) Util.getAdapter(element,
+				IDeferredWorkbenchAdapter.class);
+	}
+
+	/**
+	 * Starts a job and creates a collector for fetching the children of this
+	 * deferred adapter. If children are waiting to be retrieved for this parent
+	 * already, that job is cancelled and another is started.
+	 * 
+	 * @param parent
+	 *            The parent object being filled in,
+	 * @param adapter
+	 *            The adapter being used to fetch the children.
+	 * @param placeholder
+	 *            The adapter that will be used to indicate that results are
+	 *            pending.
+	 */
+	protected void startFetchingDeferredChildren(final Object parent,
+			final IDeferredWorkbenchAdapter adapter,
+			final PendingUpdateAdapter placeholder) {
+		final IElementCollector collector = createElementCollector(parent,
+				placeholder);
+		// Cancel any jobs currently fetching children for the same parent
+		// instance.
+		cancel(parent);
+		String jobName = getFetchJobName(parent, adapter);
+		Job job = new Job(jobName) {
+			/*
+			 * (non-Javadoc)
+			 * 
+			 * @see org.eclipse.core.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
+			 */
+			public IStatus run(IProgressMonitor monitor) {
+				adapter.fetchDeferredChildren(parent, collector, monitor);
+				if (monitor.isCanceled()) {
+					return Status.CANCEL_STATUS;
+				}
+				return Status.OK_STATUS;
+			}
+
+			/*
+			 * (non-Javadoc)
+			 * 
+			 * @see org.eclipse.core.jobs.Job#belongsTo(java.lang.Object)
+			 */
+			public boolean belongsTo(Object family) {
+				if (family instanceof DeferredContentFamily) {
+					DeferredContentFamily contentFamily = (DeferredContentFamily) family;
+					if (contentFamily.manager == DeferredTreeContentManager.this) {
+						return isParent(contentFamily, parent);
+					}
+				}
+				return false;
+
+			}
+
+			/**
+			 * Check if the parent of element is equal to the parent used in
+			 * this job.
+			 * 
+			 * @param family
+			 *            The DeferredContentFamily that defines a potential
+			 *            ancestor of the current parent in a particular
+			 *            manager.
+			 * @param child
+			 *            The object to check against.
+			 * @return boolean <code>true</code> if the child or one of its
+			 *         parents are the same as the element of the family.
+			 */
+			private boolean isParent(DeferredContentFamily family, Object child) {
+				if (family.element.equals(child)) {
+					return true;
+				}
+				IWorkbenchAdapter workbenchAdapter = getWorkbenchAdapter(child);
+				if (workbenchAdapter == null) {
+					return false;
+				}
+				Object elementParent = workbenchAdapter.getParent(child);
+				if (elementParent == null) {
+					return false;
+				}
+				return isParent(family, elementParent);
+			}
+
+			/**
+			 * Get the workbench adapter for the element.
+			 * 
+			 * @param element
+			 *            The object we are adapting to.
+			 */
+			private IWorkbenchAdapter getWorkbenchAdapter(Object element) {
+				return (IWorkbenchAdapter) Util.getAdapter(element,
+						IWorkbenchAdapter.class);
+			}
+		};
+		job.addJobChangeListener(new JobChangeAdapter() {
+			/*
+			 * (non-Javadoc)
+			 * 
+			 * @see org.eclipse.core.runtime.jobs.JobChangeAdapter#done(org.eclipse.core.runtime.jobs.IJobChangeEvent)
+			 */
+			public void done(IJobChangeEvent event) {
+				runClearPlaceholderJob(placeholder);
+			}
+		});
+		job.setRule(adapter.getRule(parent));
+		if (progressService == null) {
+			job.schedule();
+		} else {
+			progressService.schedule(job);
+		}
+	}
+
+	/**
+	 * Returns a name to use for the job that fetches children of the given
+	 * parent. Subclasses may override. Default job name is parent's label.
+	 * 
+	 * @param parent
+	 *            parent that children are to be fetched for
+	 * @param adapter
+	 *            parent's deferred adapter
+	 * @return job name
+	 */
+	protected String getFetchJobName(Object parent,
+			IDeferredWorkbenchAdapter adapter) {
+		return NLS.bind(
+				ProgressMessages.get( display ).DeferredTreeContentManager_FetchingName,
+				adapter.getLabel(parent));
+	}
+
+	/**
+	 * Create a UIJob to add the children to the parent in the tree viewer.
+	 * 
+	 * @param parent
+	 * @param children
+	 * @param monitor
+	 */
+	protected void addChildren(final Object parent, final Object[] children,
+			IProgressMonitor monitor) {
+		WorkbenchJob updateJob = new WorkbenchJob( display,
+				ProgressMessages.get( display ).DeferredTreeContentManager_AddingChildren) {
+			/*
+			 * (non-Javadoc)
+			 * 
+			 * @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor)
+			 */
+			public IStatus runInUIThread(IProgressMonitor updateMonitor) {
+				// Cancel the job if the tree viewer got closed
+				if (treeViewer.getControl().isDisposed()
+						|| updateMonitor.isCanceled()) {
+					return Status.CANCEL_STATUS;
+				}
+				treeViewer.add(parent, children);
+				return Status.OK_STATUS;
+			}
+		};
+		updateJob.setSystem(true);
+		updateJob.schedule();
+
+	}
+
+	/**
+	 * Return whether or not the element is or adapts to an
+	 * IDeferredWorkbenchAdapter.
+	 * 
+	 * @param element
+	 * @return boolean <code>true</code> if the element is an
+	 *         IDeferredWorkbenchAdapter
+	 */
+	public boolean isDeferredAdapter(Object element) {
+		return getAdapter(element) != null;
+	}
+
+	/**
+	 * Run a job to clear the placeholder. This is used when the update for the
+	 * tree is complete so that the user is aware that no more updates are
+	 * pending.
+	 * 
+	 * @param placeholder
+	 */
+	protected void runClearPlaceholderJob(final PendingUpdateAdapter placeholder) {
+// RAP [fappel]: uses session aware approach
+//		if (placeholder.isRemoved() || !PlatformUI.isWorkbenchRunning()) {
+//			return;
+//		}
+        if (placeholder.isRemoved() || !ProgressUtil.isWorkbenchRunning( display )) {
+			return;
+		}
+
+		// Clear the placeholder if it is still there
+		WorkbenchJob clearJob = new WorkbenchJob( display,
+				ProgressMessages.get( display ).DeferredTreeContentManager_ClearJob) {
+			/*
+			 * (non-Javadoc)
+			 * 
+			 * @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor)
+			 */
+			public IStatus runInUIThread(IProgressMonitor monitor) {
+				if (!placeholder.isRemoved()) {
+					Control control = treeViewer.getControl();
+					if (control.isDisposed()) {
+						return Status.CANCEL_STATUS;
+					}
+					treeViewer.remove(placeholder);
+					placeholder.setRemoved(true);
+				}
+				return Status.OK_STATUS;
+			}
+		};
+		clearJob.setSystem(true);
+		
+		if (updateCompleteListenerList != null) {
+			Object[] listeners = updateCompleteListenerList.getListeners();
+			for (int i = 0; i < listeners.length; i++) {
+				clearJob
+						.addJobChangeListener((IJobChangeListener) listeners[i]);
+			}
+		}
+		clearJob.schedule();
+	}
+
+	/**
+	 * Cancel all jobs that are fetching content for the given parent or any of
+	 * its children.
+	 * 
+	 * @param parent
+	 */
+	public void cancel(Object parent) {
+		if (parent == null) {
+			return;
+		}
+
+		Job.getJobManager().cancel(new DeferredContentFamily(this, parent));
+	}
+
+	/**
+	 * Create the element collector for the receiver.
+	 * 
+	 * @param parent
+	 *            The parent object being filled in,
+	 * @param placeholder
+	 *            The adapter that will be used to indicate that results are
+	 *            pending.
+	 * @return IElementCollector
+	 */
+	protected IElementCollector createElementCollector(final Object parent,
+			final PendingUpdateAdapter placeholder) {
+		return new IElementCollector() {
+			/*
+			 * (non-Javadoc)
+			 * 
+			 * @see org.eclipse.jface.progress.IElementCollector#add(java.lang.Object,
+			 *      org.eclipse.core.runtime.IProgressMonitor)
+			 */
+			public void add(Object element, IProgressMonitor monitor) {
+				add(new Object[] { element }, monitor);
+			}
+
+			/*
+			 * (non-Javadoc)
+			 * 
+			 * @see org.eclipse.jface.progress.IElementCollector#add(java.lang.Object[],
+			 *      org.eclipse.core.runtime.IProgressMonitor)
+			 */
+			public void add(Object[] elements, IProgressMonitor monitor) {
+				addChildren(parent, elements, monitor);
+			}
+
+			/*
+			 * (non-Javadoc)
+			 * 
+			 * @see org.eclipse.jface.progress.IElementCollector#done()
+			 */
+			public void done() {
+				runClearPlaceholderJob(placeholder);
+			}
+		};
+	}
+
+	/**
+	 * Add a listener to list of update complete listeners. These listeners are
+	 * attached to the job that updates the viewer content (clears the pending
+	 * entry, etc.) after all deferred content has been retrieved.
+	 * 
+	 * This method has no effect if the listener has already been added to the
+	 * list of listeners.
+	 * 
+	 * Since 3.6, this listener is added to a list of listeners rather than
+	 * replacing the previously added listener. For backward compatibility,
+	 * adding a null listener will be interpreted as removal of a listener if
+	 * only one listener has been registered.
+	 * 
+	 * @param listener
+	 *            the listener to add to the list of update listeners
+	 * @since 1.1
+	 */
+	public void addUpdateCompleteListener(IJobChangeListener listener){
+		// Maintain backward compatibility.
+		// Earlier only one listener was supported, so it can be removed by
+		// passing null
+		if (listener == null && updateCompleteListenerList != null) {
+			Object[] listeners = updateCompleteListenerList.getListeners();
+			if (listeners.length == 1) {
+				removeUpdateCompleteListener((IJobChangeListener) listeners[0]);
+			}
+		} else {
+			if (updateCompleteListenerList == null) {
+				updateCompleteListenerList = new ListenerList();
+			}
+			updateCompleteListenerList.add(listener);
+		}
+	}
+
+	/**
+	 * Removes the listener from the list of update listeners that are attached
+	 * to the job that updates the viewer content (clears the pending entry,
+	 * etc.) after all deferred content has been retrieved. If the listener is
+	 * already attached to a running job, it is not removed, but it will not be
+	 * added to any subsequent jobs that are run.
+	 * 
+	 * This method has no effect if the listener was not previously added to the
+	 * listener list.
+	 * 
+	 * @param listener
+	 *            the listener to be removed
+	 * @since 3.6
+	 */
+	public void removeUpdateCompleteListener(IJobChangeListener listener) {
+		if (updateCompleteListenerList != null) {
+			updateCompleteListenerList.remove(listener);
+		}
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/progress/IDeferredWorkbenchAdapter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/progress/IDeferredWorkbenchAdapter.java
new file mode 100644
index 0000000..de6d7f3
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/progress/IDeferredWorkbenchAdapter.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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.ui.progress;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+import org.eclipse.ui.model.IWorkbenchAdapter;
+
+/**
+ * This adapter interface provides support for lazy initialization of UI workbench elements
+ * that are displayed visually. This adapter is used with an associated deferred content provider.
+ *
+ * @see DeferredTreeContentManager
+ * @since 3.0
+ */
+public interface IDeferredWorkbenchAdapter extends IWorkbenchAdapter {
+
+    /**
+     * Called by a job run in a separate thread to fetch the children of this adapter.
+     * The adapter should in return notify of new children via the collector.
+     * This is generally used when a content provider is getting elements.
+     * <p>
+     * It is good practice to check the passed in monitor for cancellation. This will
+     * provide good responsiveness for cancellation requests made by the user.
+     * </p>
+     *
+     * @param object the object to fetch the children for
+     * @param collector the collector to notify about new children. Should not
+     * 		be <code>null</code>.
+     * @param  monitor a progress monitor that will never be <code>null<code> to
+     *                   support reporting and cancellation.
+     */
+    public void fetchDeferredChildren(Object object,
+            IElementCollector collector, IProgressMonitor monitor);
+
+    /**
+     * Returns whether this adapter may have children. This is an optimized method
+     * used by content providers to allow showing the [+] expand icon without having
+     * yet fetched the children for the element.
+     * <p>
+     * If <code>false</code> is returned, then the content provider may assume
+     * that this adapter has no children. If <code>true</code> is returned,
+     * then the job manager may assume that this adapter may have children.
+     * <p>
+     *
+     * @return <code>true</code>if the adapter may have childen, and <code>false</code>
+     * 	otherwise.
+     */
+    public boolean isContainer();
+
+    /**
+     * Returns the rule used to schedule the deferred fetching of children for this adapter.
+     *
+     * @param object the object whose children are being fetched
+     * @return the scheduling rule. May be <code>null</code>.
+     * @see org.eclipse.core.runtime.jobs.Job#setRule(ISchedulingRule)
+     */
+    public ISchedulingRule getRule(Object object);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/progress/IElementCollector.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/progress/IElementCollector.java
new file mode 100644
index 0000000..745b05b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/progress/IElementCollector.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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.ui.progress;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * IElementCollector is a type that allows for the incremental update of a
+ * collection of objects. This used for updating trees incrementally with
+ * a progress monitor so that the update can be reported.
+ *
+ * @see org.eclipse.ui.progress.IDeferredWorkbenchAdapter
+ * @see org.eclipse.ui.progress.DeferredTreeContentManager
+ * @since 3.0
+ */
+public interface IElementCollector {
+    /**
+     * Add the element to the IElementCollector. Send any progress information
+     * to monitor.
+     *
+     * @param element
+     *            The element being added
+     * @param monitor
+     *            The monitor to send updates to.
+     */
+    public void add(Object element, IProgressMonitor monitor);
+
+    /**
+     * Add the elements to the IElementCollector. Send any progress information
+     * to monitor.
+     *
+     * @param elements
+     *            The elements being added
+     * @param monitor
+     *            The monitor to send updates to.
+     */
+    public void add(Object[] elements, IProgressMonitor monitor);
+
+    /**
+     * The element collection is done. Clean up any temporary state.
+     *
+     */
+    public void done();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/progress/IJobRunnable.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/progress/IJobRunnable.java
new file mode 100644
index 0000000..ac570a5
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/progress/IJobRunnable.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.progress;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+
+/**
+ * Interface for runnables that can be run as jobs.
+ *
+ * @since 3.3
+ */
+public interface IJobRunnable {
+
+	/**
+	 * Executes this runnable. Returns the result of the execution.
+	 * <p>
+	 * The provided monitor can be used to report progress and respond to
+	 * cancellation. If the progress monitor has been canceled, the runnable should
+	 * finish its execution at the earliest convenience and return a result
+	 * status of severity <code>IStatus.CANCEL</code>. The singleton cancel
+	 * status <code>Status.CANCEL_STATUS</code> can be used for this purpose.
+	 * <p>
+	 *
+	 * @param monitor
+	 *            the monitor to be used for reporting progress and responding
+	 *            to cancelation. The monitor is never <code>null</code>
+	 * @return resulting status of the run. The result must not be
+	 *         <code>null</code>
+	 */
+	public IStatus run(IProgressMonitor monitor);
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/progress/IProgressConstants.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/progress/IProgressConstants.java
new file mode 100644
index 0000000..8f90068
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/progress/IProgressConstants.java
@@ -0,0 +1,135 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.progress;
+
+import org.eclipse.core.runtime.QualifiedName;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * Constants relating to progress UI functionality of the workbench plug-in.
+ * <p>
+ * The four constants define property keys that are used to associate
+ * UI related information with Jobs (<code>org.eclipse.core.runtime.jobs.Job</code>).
+ *
+ * @see org.eclipse.core.runtime.jobs.Job#setProperty
+ * @since 3.0
+ */
+public interface IProgressConstants {
+
+    /**
+     * Common prefix for properties defined in this interface.
+     */
+    static final String PROPERTY_PREFIX = PlatformUI.PLUGIN_ID
+            + ".workbench.progress"; //$NON-NLS-1$
+
+    /**
+     * This property provides a hint to the progress UI to keep Jobs
+     * in the UI after they have finished. This can be used to communicate results of a Job
+     * back to the user.
+     * <p>
+     * The property must be of type <code>Boolean</code> and the hint is used
+     * if its value is <code>true</code>.
+     * </p>
+     */
+    public static final QualifiedName KEEP_PROPERTY = new QualifiedName(
+            PROPERTY_PREFIX, "keep"); //$NON-NLS-1$
+
+    /**
+     * The KEEPONE_PROPERTY is an extension to the KEEP_PROPERTY, that provides a hint
+     * to the progress UI to ensure that only a single Job of a Job family is kept in the
+     * set of kept Jobs. That is, whenever a Job that has the KEEPONE_PROPERTY starts or finishes,
+     * all other kept Jobs of the same family are removed first.
+     * <p>
+     * Membership to family is determined using a Job's <code>belongsTo</code>
+     * method. The progress service will pass each job that currently exists in the
+     * view to the <code>belongsTo</code> method of a newly added job. Clients who
+     * set the <code>KEEPONE_PROPERTY</code> must implement a <code>belongsTo</code>
+     * method that determines if the passed job is of the same family as their job
+     * and return <code>true</code> if it is.
+     * </p>
+     * <p>
+     * Please note that other Jobs of the same family are only removed if they have finished.
+     * Non finished jobs of the same family are left alone.
+     * </p>
+     **/
+    public static final QualifiedName KEEPONE_PROPERTY = new QualifiedName(
+            PROPERTY_PREFIX, "keepone"); //$NON-NLS-1$
+
+	/**
+	 * This property is used to associate an <code>IAction</code> with a Job. If
+	 * the Job is shown in the UI, the action might be represented as a button
+	 * or hyper link to allow the user to trigger a job specific action, like
+	 * showing the Job's results.
+	 * <p>
+	 * The progress UI will track the enabled state of the action and its
+	 * tooltip text.
+	 * </p>
+	 * <p>
+	 * If the action implements <code>ActionFactory.IWorkbenchAction</code>, its
+	 * <code>dispose</code> method will be called as soon as the Job is finally
+	 * removed from the set of kept jobs.
+	 * </p>
+	 * <p>
+	 * Note: Only one of <code>ACTION_PROPERTY</code> or
+	 * <code>COMMAND_PROPERTY</code> should be used
+	 * </p>
+	 *
+	 * @see org.eclipse.jface.action.IAction
+	 * @see org.eclipse.ui.actions.ActionFactory.IWorkbenchAction
+	 **/
+    public static final QualifiedName ACTION_PROPERTY = new QualifiedName(
+            PROPERTY_PREFIX, "action"); //$NON-NLS-1$
+
+    /**
+     * This property is used to associate an <code>ImageDescriptor</code> with a Job.
+     * If the Job is shown in the UI, this descriptor is used to create an icon that
+     * represents the Job.
+     * <p>
+     * Please note, that this property is only used if no <code>ImageDescriptor</code> has been
+     * registered for the Job family with the <code>IProgressService</code>.
+     * </p>
+     * @see org.eclipse.jface.resource.ImageDescriptor
+     * @see org.eclipse.ui.progress.IProgressService
+     **/
+    public static final QualifiedName ICON_PROPERTY = new QualifiedName(
+            PROPERTY_PREFIX, "icon"); //$NON-NLS-1$
+
+    /**
+     * Constant for the progress view id.
+     */
+    public static String PROGRESS_VIEW_ID = "org.eclipse.ui.views.ProgressView"; //$NON-NLS-1$
+
+    /**
+     * This is a property set on a user job if the user has not decided to
+     * run the job in the background.
+     * The value is set to <code>true</code> when the job starts and set to
+     * <code>false</code> if the user subsequently decides to complete the job in the
+     * background.
+     * <p>
+     * This property is not intended to be set by clients.
+     * </p>
+     * @see org.eclipse.core.runtime.jobs.Job#isUser()
+     */
+    public static final QualifiedName PROPERTY_IN_DIALOG = new QualifiedName(
+            IProgressConstants.PROPERTY_PREFIX, "inDialog"); //$NON-NLS-1$
+
+    /**
+     * This property provides a hint to the progress UI to not prompt on errors
+     * immediately but instead make the errors available through the progress UI.
+     * <p>
+     * The property must be of type <code>Boolean</code> and the hint is used
+     * if its value is <code>true</code>.
+     * </p>
+     * @since 3.1
+     */
+    public static final QualifiedName NO_IMMEDIATE_ERROR_PROMPT_PROPERTY = new QualifiedName(
+            PROPERTY_PREFIX, "delayErrorPrompt"); //$NON-NLS-1$
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/progress/IProgressConstants2.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/progress/IProgressConstants2.java
new file mode 100644
index 0000000..318709b
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/progress/IProgressConstants2.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2015 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
+ *     Tasktop Technologies - Bug 302529 [UX] [Progress] Show Eclipse IDE progress in the Eclipse icon on the Windows 7 Task Bar
+ *******************************************************************************/
+package org.eclipse.ui.progress;
+
+import org.eclipse.core.runtime.QualifiedName;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.progress.IProgressConstants;
+
+/**
+ * Constants relating to progress UI functionality of the workbench plug-in.
+ * <p>
+ * The constants define property keys that are used to associate UI related
+ * information with Jobs (<code>org.eclipse.core.runtime.jobs.Job</code>). This
+ * class is a superset of all previously defined progress constants.
+ *
+ * @see org.eclipse.core.runtime.jobs.Job#setProperty
+ * @see IProgressConstants
+ * @since 3.6
+ *
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IProgressConstants2 extends IProgressConstants {
+
+    /**
+     * Common prefix for properties defined in this interface.
+     */
+    static final String PROPERTY_PREFIX = PlatformUI.PLUGIN_ID
+            + ".workbench.progress"; //$NON-NLS-1$
+
+	/**
+	 * This property is used to associate a <code>ParameterizedCommand</code>
+	 * with a Job. If the Job is shown in the UI, the command might be
+	 * represented as a button or hyper link to allow the user to trigger a job
+	 * specific action, like showing the Job's results.
+	 * <p>
+	 * Note: Only one of <code>ACTION_PROPERTY</code> or
+	 * <code>COMMAND_PROPERTY</code> should be used
+	 * </p>
+	 *
+	 * @see org.eclipse.core.commands.ParameterizedCommand
+	 **/
+	public static final QualifiedName COMMAND_PROPERTY = new QualifiedName(
+			PROPERTY_PREFIX, "command"); //$NON-NLS-1$
+
+	/**
+	 * This property provides a hint to the progress UI to show the progress of
+	 * the job in the application TaskBar
+	 * <p>
+	 * The property must be of type <code>Boolean</code> and the hint is used if
+	 * its value is <code>true</code>.
+	 * </p>
+	 */
+	public static final QualifiedName SHOW_IN_TASKBAR_ICON_PROPERTY = new QualifiedName(
+			PROPERTY_PREFIX, "inTaskBarIcon"); //$NON-NLS-1$
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/progress/IProgressService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/progress/IProgressService.java
new file mode 100644
index 0000000..c212b62
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/progress/IProgressService.java
@@ -0,0 +1,165 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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 - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ui.progress;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.eclipse.core.runtime.jobs.IJobManager;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.core.runtime.jobs.ProgressProvider;
+import org.eclipse.jface.operation.IRunnableContext;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * The progress service is the primary interface to the workbench progress
+ * support. It can be obtained from the workbench and then used to show progress
+ * for both background operations and operations that run in the UI thread.
+ * <p>
+ * All methods on the progress service must be called from the UI thread.
+ * </p>
+ * <p>
+ * This service can be acquired from your service locator:
+ * <pre>
+ * 	IProgressService service = (IProgressService) getSite().getService(IProgressService.class);
+ * </pre>
+ * <ul>
+ * <li>This service is available globally.</li>
+ * </ul>
+ * </p>
+ * <p>
+ * <strong>NOTE</strong> The progress service must be referenced at least once
+ * before it will become the progress provider for the {@link IJobManager} in
+ * the workbench. This connection is done lazily so that RCP applications will
+ * not have to use the {@link IProgressService} as the {@link ProgressProvider}
+ * to the jobs framework if they do not wish to reference it.
+ * </p>
+ *
+ * @see org.eclipse.ui.IWorkbench#getProgressService()
+ * @see IJobManager#setProgressProvider(org.eclipse.core.runtime.jobs.ProgressProvider)
+ * @see org.eclipse.ui.services.IServiceLocator#getService(Class)
+ *
+ * @since 3.0
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IProgressService extends IRunnableContext {
+
+    /**
+     * The time at which an operation becomes considered a long
+     * operation. Used to determine when the busy cursor will
+     * be replaced with a progress monitor.
+     * @return int
+     * @see IProgressService#busyCursorWhile(IRunnableWithProgress)
+     */
+    public int getLongOperationTime();
+
+    /**
+     * Register the ImageDescriptor to be the icon used for
+     * all jobs that belong to family within the workbench.
+     * @param icon ImageDescriptor that will be used when the job is being displayed
+     * @param family The family to associate with
+     * @see Job#belongsTo(Object)
+     */
+    public void registerIconForFamily(ImageDescriptor icon, Object family);
+
+    /**
+     * Runs the given operation in the UI thread using the given runnable context.
+     * The given scheduling rule, if any, will be acquired for the duration of the operation.
+     * If the rule is not available when this method is called, a progress dialog will be
+     * displayed that gives users control over the background processes that may
+     * be blocking the runnable from proceeding.
+     * <p>
+     * This method can act as a wrapper for uses of <tt>IRunnableContext</tt>
+     * where the <tt>fork</tt> parameter was <tt>false</tt>.
+     * <p>
+     * Note: Running long operations in the UI thread is generally not
+     * recommended. This can result in the UI becoming unresponsive for
+     * the duration of the operation. Where possible, <tt>busyCursorWhile</tt>
+     * should be used instead.
+     * </p>
+     * <p>
+     * Modal dialogs should also be avoided in the runnable as there will already
+     * be a modal progress dialog open when this operation runs.
+     * </p>
+     * @see org.eclipse.jface.dialogs.Dialog
+     * @see org.eclipse.swt.SWT#APPLICATION_MODAL
+     *
+     * @param context The runnable context to run the operation in
+     * @param runnable The operation to run
+     * @param rule A scheduling rule, or <code>null</code>
+     * @throws InvocationTargetException wraps any exception or error which occurs
+     *  while running the runnable
+     * @throws InterruptedException propagated by the context if the runnable
+     *  acknowledges cancelation by throwing this exception.
+     *
+     */
+    public void runInUI(IRunnableContext context,
+            IRunnableWithProgress runnable, ISchedulingRule rule)
+            throws InvocationTargetException, InterruptedException;
+
+    /**
+     * Get the icon that has been registered for a Job by
+     * checking if the job belongs to any of the registered
+     * families.
+     * @param job
+     * @return Icon or <code>null</code> if there isn't one.
+     * @see IProgressService#registerIconForFamily(ImageDescriptor,Object)
+     */
+    public Image getIconFor(Job job);
+
+    /**
+     * Set the cursor to busy and run the runnable in a non-UI Thread.
+     * The calling thread will be blocked for the duration of the execution
+     * of the supplied runnable.
+     *
+     * After the cursor has been running for
+     * <code>getLongOperationTime()</code> replace it with
+     * a ProgressMonitorDialog so that the user may cancel.
+     * Do not open the ProgressMonitorDialog if there is already a modal
+     * dialog open.
+     *
+     * @param runnable The runnable to execute and show the progress for.
+     * @see IProgressService#getLongOperationTime
+     * @throws InvocationTargetException
+     * @throws InterruptedException
+     */
+    public void busyCursorWhile(IRunnableWithProgress runnable)
+            throws InvocationTargetException, InterruptedException;
+
+    /**
+     * This specialization of IRunnableContext#run(boolean, boolean,
+     * IRunnableWithProgress) might run the runnable asynchronously
+     * if <code>fork</code> is <code>true</code>.
+     *
+     * @since 3.2
+     */
+    @Override
+	public void run(boolean fork, boolean cancelable, IRunnableWithProgress runnable) throws InvocationTargetException, InterruptedException;
+
+    /**
+     * Open a dialog on job when it starts to run and close it
+     * when the job is finished. Wait for ProgressManagerUtil#SHORT_OPERATION_TIME
+     * before opening the dialog. Do not open if it is already done or
+     * if the user has set a preference to always run in the background.
+     *
+     * Parent the dialog from the shell.
+     *
+     * @param shell The Shell to parent the dialog from or
+     * <code>null</code> if the active shell is to be used.
+     * @param job The Job that will be reported in the dialog. job
+     * must not be <code>null</code>.
+     */
+    public void showInDialog(Shell shell, Job job);
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/progress/IWorkbenchSiteProgressService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/progress/IWorkbenchSiteProgressService.java
new file mode 100644
index 0000000..4e8eeed
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/progress/IWorkbenchSiteProgressService.java
@@ -0,0 +1,139 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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 - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ui.progress;
+
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.ui.IWorkbenchPartSite;
+
+/**
+ * IWorkbenchPartProgressService is an IProgressService that adds API for jobs
+ * that change the state in a IWorkbenchPartSite while they are being run.
+ * <p>
+ * This service can be acquired from your service locator (IWorkbenchPartSite):
+ *
+ * <pre>
+ * <code>
+ * 	IWorkbenchSiteProgressService service = (IWorkbenchSiteProgressService) getSite().getService(IWorkbenchSiteProgressService.class);
+ * </code>
+ * </pre>
+ *
+ * <ul>
+ * <li>This service is not available globally, only at the part site level.</li>
+ * </ul>
+ * </p>
+ * <p>
+ * WorkbenchParts may access an instance of IWorkbenchSiteProgressService by
+ * calling
+ * <code>getSite().getAdapter(IWorkbenchSiteProgressService.class);</code> ,
+ * although getSite().getService(IWorkbenchSiteProgressService.class) is
+ * preferred.
+ * </p>
+ *
+ * @see IWorkbenchPartSite#getAdapter(Class)
+ * @see org.eclipse.ui.services.IServiceLocator#getService(Class)
+ * @since 3.0
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IWorkbenchSiteProgressService extends IProgressService {
+
+    /**
+     * The property that is sent with busy notifications.
+     * @deprecated this property is no longer in use in the Eclipse SDK
+     */
+    @Deprecated
+	public static final String BUSY_PROPERTY = "SITE_BUSY"; //$NON-NLS-1$
+
+	/**
+	 * Jobs scheduled with this method will cause the part's presentation to be
+	 * changed to indicate that the part is busy and in a transient state until
+	 * the job completes. Parts can also add customized busy indication by
+	 * overriding <code>WorkbenchPart.showBusy()</code>. If useHalfBusyCursor is
+	 * true then the cursor will change to the half busy cursor for the duration
+	 * of the job.
+	 *
+	 * @param job
+	 *            The job to schedule
+	 * @param delay
+	 *            The delay in scheduling.
+	 * @param useHalfBusyCursor
+	 *            A boolean to indicate if the half busy cursor should be used
+	 *            while this job is running.
+	 * @see Job#schedule(long)
+	 */
+    public void schedule(Job job, long delay, boolean useHalfBusyCursor);
+
+	/**
+	 * Jobs scheduled with this method will cause the part's presentation to be
+	 * changed to indicate that the part is busy and in a transient state until
+	 * the job completes. Parts can also add customized busy indication by
+	 * overriding <code>WorkbenchPart.showBusy</code>.
+	 *
+	 * @param job
+	 *            The job to schedule
+	 * @param delay
+	 *            The delay in scheduling.
+	 * @see Job#schedule(long)
+	 */
+    public void schedule(Job job, long delay);
+
+	/**
+	 * Jobs scheduled with this method will cause the part's presentation to be
+	 * changed to indicate that the part is busy and in a transient state until
+	 * the job completes. Parts can also add customized busy indication by
+	 * overriding <code>WorkbenchPart.showBusy</code>.
+	 *
+	 * @param job
+	 *            The job to schedule
+	 * @see Job#schedule()
+	 */
+    public void schedule(Job job);
+
+    /**
+     * Show busy state if any job of the specified family is running.
+     * @param family Object
+     * @see Job#belongsTo(Object)
+     */
+    public void showBusyForFamily(Object family);
+
+    /**
+	 * Warn that the content of the part has changed. How this change is
+	 * displayed to the end user is left up to the workbench renderer.
+	 */
+    public void warnOfContentChange();
+
+    /**
+	 * Increments the busy counter for this workbench site. This API should only
+	 * be used for background work that does not use jobs. As long as there have
+	 * been more calls to incrementBusy() than to decrementBusy(), the part will
+	 * show a busy affordance. Each call to incrementBusy must be followed by a
+	 * call to decrementBusy once the caller no longer needs the part to show
+	 * the busy affordance.
+	 * <p>
+	 * Note that the job-related methods on this class are another way to let
+	 * the part show a busy affordance.  A part will only appear non-busy if no
+	 * jobs have been scheduled through this service, and the internal busy
+	 * counter is not positive.
+	 * </p>
+	 *
+	 * @since 3.3
+	 */
+	public void incrementBusy();
+
+    /**
+	 * Decrements the busy counter for this workbench site. This API should only
+	 * be used for background work that does not use jobs. It is an error to call
+	 * this method without first making a matching call to {@link #incrementBusy()}.
+	 *
+	 * @since 3.3
+	 */
+	public void decrementBusy();
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/progress/PendingUpdateAdapter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/progress/PendingUpdateAdapter.java
new file mode 100644
index 0000000..af3f143
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/progress/PendingUpdateAdapter.java
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2016 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.ui.progress;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.internal.progress.ProgressMessages;
+import org.eclipse.ui.model.IWorkbenchAdapter;
+
+/**
+ * The PendingUpdateAdapter is a convenience object that can be used
+ * by a BaseWorkbenchContentProvider that wants to show a pending update.
+ *
+ * @since 3.2
+ */
+public class PendingUpdateAdapter implements IWorkbenchAdapter, IAdaptable {
+
+    private boolean removed = false;
+
+    /**
+     * Return whether or not this has been removed from the tree.
+     * @return boolean
+     */
+    protected boolean isRemoved() {
+        return removed;
+    }
+
+    /**
+     * Set whether or not this has been removed from the tree.
+     * @param removedValue boolean
+     */
+    protected void setRemoved(boolean removedValue) {
+        this.removed = removedValue;
+    }
+
+    /**
+     * Create a new instance of the receiver.
+     */
+    public PendingUpdateAdapter() {
+        //No initial behavior
+    }
+
+	@Override
+	public <T> T getAdapter(Class<T> adapter) {
+        if (adapter == IWorkbenchAdapter.class) {
+			return adapter.cast(this);
+		}
+        return null;
+    }
+
+    @Override
+	public Object[] getChildren(Object o) {
+        return new Object[0];
+    }
+
+    @Override
+	public ImageDescriptor getImageDescriptor(Object object) {
+        return null;
+    }
+
+    @Override
+	public String getLabel(Object o) {
+        return ProgressMessages.get().PendingUpdateAdapter_PendingLabel;
+    }
+
+    @Override
+	public Object getParent(Object o) {
+        return null;
+    }
+
+    /**
+	 * @since 3.4
+	 */
+    @Override
+	public String toString() {
+    	return getLabel(null);
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/progress/UIJob.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/progress/UIJob.java
new file mode 100644
index 0000000..2a8ca75
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/progress/UIJob.java
@@ -0,0 +1,160 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2008 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 - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ui.progress;
+
+import org.eclipse.core.runtime.Assert;
+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.rap.rwt.internal.lifecycle.LifeCycleUtil;
+import org.eclipse.rap.rwt.internal.lifecycle.RWTLifeCycle;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.misc.UIStats;
+import org.eclipse.ui.internal.progress.ProgressMessages;
+
+/**
+ * The UIJob is a Job that runs within the UI Thread via an asyncExec.
+ * 
+ * @since 1.0
+ */
+public abstract class UIJob extends Job {
+    private Display cachedDisplay;
+
+    /**
+     * Create a new instance of the receiver with the supplied name. The display
+     * used will be the one from the workbench if this is available. UIJobs with
+     * this constructor will determine their display at runtime.
+     * 
+     * @param name
+     *            the job name
+     *  
+     */
+    public UIJob(String name) {
+// RAP [fappel]: discovering the display at runtime of a job is not
+//               possible in RAP
+//        super(name);
+        this( LifeCycleUtil.getSessionDisplay(), name );
+    }
+
+    /**
+     * Create a new instance of the receiver with the supplied Display.
+     * 
+     * @param jobDisplay
+     *            the display
+     * @param name
+     *            the job name
+     * @see Job
+     */
+    public UIJob(Display jobDisplay, String name) {
+// RAP [fappel]: avoid recursive constructor call
+//        this( name );
+        super(name);
+        setDisplay(jobDisplay);
+    }
+
+    /**
+     * Convenience method to return a status for an exception.
+     * 
+     * @param exception
+     * @return IStatus an error status built from the exception
+     * @see Job
+     */
+    public static IStatus errorStatus(Throwable exception) {
+        return WorkbenchPlugin.getStatus(exception); 
+    }
+
+    /**
+     * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
+     *      Note: this message is marked final. Implementors should use
+     *      runInUIThread() instead.
+     */
+    public final IStatus run(final IProgressMonitor monitor) {
+        if (monitor.isCanceled()) {
+			return Status.CANCEL_STATUS;
+		}
+        Display asyncDisplay = getDisplay();
+        if (asyncDisplay == null || asyncDisplay.isDisposed()) {
+            return Status.CANCEL_STATUS;
+        }
+        asyncDisplay.asyncExec(new Runnable() {
+            public void run() {
+                IStatus result = null;
+                Throwable throwable = null;
+                try {
+                    //As we are in the UI Thread we can
+                    //always know what to tell the job.
+                    setThread(Thread.currentThread());
+                    if (monitor.isCanceled()) {
+						result = Status.CANCEL_STATUS;
+					} else {
+                       	UIStats.start(UIStats.UI_JOB, getName());
+                        result = runInUIThread(monitor);
+                    }
+// RAP [rst] Catching Throwables not allowed in RAP
+//                  } catch(Throwable t){
+                } catch(Exception t){
+                	throwable = t;
+                } finally {
+               		UIStats.end(UIStats.UI_JOB, UIJob.this, getName());
+                    if (result == null) {
+						result = new Status(IStatus.ERROR,
+                                PlatformUI.PLUGIN_ID, IStatus.ERROR,
+                                ProgressMessages.get().InternalError,
+                                throwable);
+					}
+                    done(result);
+                }
+            }
+        });
+        return Job.ASYNC_FINISH;
+    }
+
+    /**
+     * Run the job in the UI Thread.
+     * 
+     * @param monitor
+     * @return IStatus
+     */
+    public abstract IStatus runInUIThread(IProgressMonitor monitor);
+
+    /**
+     * Sets the display to execute the asyncExec in. Generally this is not'
+     * used if there is a valid display available via PlatformUI.isWorkbenchRunning().
+     * 
+     * @param runDisplay
+     *            Display
+     * @see UIJob#getDisplay()
+     * @see PlatformUI#isWorkbenchRunning()
+     */
+    public void setDisplay(Display runDisplay) {
+        Assert.isNotNull(runDisplay);
+        cachedDisplay = runDisplay;
+    }
+
+    /**
+     * Returns the display for use by the receiver when running in an
+     * asyncExec. If it is not set then the display set in the workbench
+     * is used.
+     * If the display is null the job will not be run.
+     * 
+     * @return Display or <code>null</code>.
+     */
+    public Display getDisplay() {
+        //If it was not set get it from the workbench
+        if (cachedDisplay == null && PlatformUI.isWorkbenchRunning()) {
+			return PlatformUI.getWorkbench().getDisplay();
+		}
+        return cachedDisplay;
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/progress/WorkbenchJob.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/progress/WorkbenchJob.java
new file mode 100644
index 0000000..733b821
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/progress/WorkbenchJob.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2015 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 - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ui.progress;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.jobs.IJobChangeEvent;
+import org.eclipse.core.runtime.jobs.JobChangeAdapter;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * WorkbenchJob is a type of job that implements a done listener
+ * and does the shutdown checks before scheduling. This is used if
+ * a job is not meant to run when the Workbench is shutdown.
+ * @since 3.0
+ */
+public abstract class WorkbenchJob extends UIJob {
+
+    /**
+     * Create a new instance of the receiver with the
+     * supplied display and name.
+     * Normally this constructor would not be used as
+     * it is best to let the job find the display from
+     *  the workbench
+     * @param jobDisplay Display. The display to run the
+     * 		job with.
+     * @param name String
+     */
+    public WorkbenchJob(Display jobDisplay, String name) {
+        super(jobDisplay, name);
+        addDefaultJobChangeListener();
+    }
+
+    /**
+     * Add a new instance of the reciever with the
+     * supplied name.
+     * @param name String
+     */
+    public WorkbenchJob(String name) {
+        super(name);
+        addDefaultJobChangeListener();
+    }
+
+    /**
+     * Add a job change listeners that handles a done
+     * event if the result was IStatus.OK.
+     *
+     */
+    private void addDefaultJobChangeListener() {
+        addJobChangeListener(new JobChangeAdapter() {
+
+            @Override
+			public void done(IJobChangeEvent event) {
+
+                //Abort if it is not running
+                if (!PlatformUI.isWorkbenchRunning()) {
+					return;
+				}
+
+                if (event.getResult().getCode() == IStatus.OK) {
+					performDone(event);
+				}
+            }
+        });
+    }
+
+    /**
+     * Perform done with the supplied event. This will
+     * only occur if the returned status was OK.
+     * This is called only if the job is finished with an IStatus.OK
+     * result and the workbench is still running.
+     * @param event IJobChangeEvent
+     */
+    public void performDone(IJobChangeEvent event) {
+        //Do nothing by default.
+    }
+
+    @Override
+	public boolean shouldSchedule() {
+        return super.shouldSchedule() && PlatformUI.isWorkbenchRunning();
+    }
+
+    @Override
+	public boolean shouldRun() {
+        return super.shouldRun() && PlatformUI.isWorkbenchRunning();
+    }
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/progress/package.html b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/progress/package.html
new file mode 100644
index 0000000..5991ddf
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/progress/package.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <title>Package-level Javadoc</title>
+</head>
+<body>
+Application programming interfaces for interaction
+with and extension of the Eclipse Platform User Interface.
+<h2>Package Specification</h2>
+This package provides API for connecting to the progress support in the Eclipse 
+Workbench. The classes in this package are used to add information about the progress 
+of org.eclipse.core.runtime.Jobs created by plug-ins. 
+</body>
+</html>
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/services/AbstractServiceFactory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/services/AbstractServiceFactory.java
new file mode 100644
index 0000000..3a02475
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/services/AbstractServiceFactory.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.services;
+
+/**
+ * A factory for creating services for use with the
+ * <code>org.eclipse.ui.services</code> extension point. You are given a
+ * service locator to look up other services, and can retrieve your parent
+ * service (if one has already been created).
+ *
+ * @since 3.4
+ */
+public abstract class AbstractServiceFactory {
+
+	/**
+	 * When a service locator cannot find a service it will request one from the
+	 * registry, which will call this factory create method.
+	 * <p>
+	 * You can use the locator to get any needed services and a parent service
+	 * locator will be provided if you need access to the parent service. If the
+	 * parent object return from the parent locator is not <code>null</code>
+	 * it can be cast to the service interface that is requested. The parent
+	 * service locator will only return the serviceInterface service.
+	 * </p>
+	 *
+	 * @param serviceInterface
+	 *            the service we need to create. Will not be <code>null</code>.
+	 * @param parentLocator
+	 *            A locator that can return a parent service instance if
+	 *            desired. The parent service can be cast to serviceInterface.
+	 *            Will not be <code>null</code>.
+	 * @param locator
+	 *            the service locator which can be used to retrieve dependent
+	 *            services. Will not be <code>null</code>
+	 * @return the created service or <code>null</code>
+	 */
+	public abstract Object create(Class serviceInterface,
+			IServiceLocator parentLocator, IServiceLocator locator);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/services/IDisposable.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/services/IDisposable.java
new file mode 100644
index 0000000..11e21ca
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/services/IDisposable.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.services;
+
+/**
+ * <p>
+ * The interface that should be implemented by services that make themselves
+ * available through the <code>IAdaptable</code> mechanism. This is the
+ * interface that drives the majority of services provided at the workbench
+ * level.
+ * </p>
+ * <p>
+ * A service has life-cycle. When the constructor completes, the service must be
+ * fully functional. When it comes time for the service to go away, then the
+ * service will receive a {@link #dispose()} call. At this point, the service
+ * must release all resources and detach all listeners. A service can only be
+ * disposed once; it cannot be reused.
+ * </p>
+ * <p>
+ * This interface has nothing to do with OSGi services.
+ * </p>
+ * <p>
+ * This interface can be extended or implemented by clients.
+ * </p>
+ *
+ * @since 3.2
+ */
+public interface IDisposable {
+
+	/**
+	 * Disposes of this service. All resources must be freed. All listeners must
+	 * be detached. Dispose will only be called once during the life cycle of a
+	 * service.
+	 */
+	public void dispose();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/services/IEvaluationReference.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/services/IEvaluationReference.java
new file mode 100644
index 0000000..0ad0a08
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/services/IEvaluationReference.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.services;
+
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.ui.internal.services.IEvaluationResultCache;
+
+/**
+ * A token representing a core expression and property change listener currently
+ * working in the <code>IEvaluationService</code>.
+ *
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noextend This interface is not intended to be extended by clients.
+ * @since 3.4
+ */
+public interface IEvaluationReference extends IEvaluationResultCache {
+	/**
+	 * The property change listener associated with the evaluated expression.
+	 *
+	 * @return the listener for updates.
+	 */
+	public IPropertyChangeListener getListener();
+
+	/**
+	 * The property used in change notifications.
+	 *
+	 * @return the property name.
+	 */
+	public String getProperty();
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/services/IEvaluationService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/services/IEvaluationService.java
new file mode 100644
index 0000000..8f0e634
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/services/IEvaluationService.java
@@ -0,0 +1,190 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.services;
+
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.ui.ISources;
+
+/**
+ * Evaluate a core expression against the workbench application context and
+ * report updates using a Boolean property. Clients supply an
+ * <code>IPropertyChangeListener</code> that will be notified as changes
+ * occur.
+ * <p>
+ * This can be used to implement core expressions in client extension points
+ * similar to the &lt;enabledWhen&gt; of
+ * <code>org.eclipse.ui.handlers/handler</code> elements.
+ * </p>
+ * <p>
+ * The service will fire <code>Boolean.TRUE</code> and
+ * <code>Boolean.FALSE</code> for the oldValue and newValue in the property
+ * change events.
+ * </p>
+ * <p>
+ * Adding the evaluation listener will fire one change with oldValue=<code>null</code>
+ * and newValue=&quot;evaluated expression&quot;. Remove the
+ * <code>IEvaluationReference</code> will fire one change with
+ * oldValue=&quot;last evaluated value&quot; and newValue=<code>null</code>.
+ * </p>
+ * <p>
+ * Adding a service listener will fire the {@link #PROP_NOTIFYING} property
+ * change event with newValue=<code>Boolean.TRUE</code> when a source change
+ * causes expression evaluations to update and another {@link #PROP_NOTIFYING}
+ * property change event with newValue=<code>Boolean.FALSE</code> when the
+ * changes that started with a specific source change have finished. The
+ * {@link #PROP_NOTIFYING} change events will not be fired for source changes
+ * caused by the outer most recalculations.
+ * </p>
+ * <p>
+ * Variable sources can be provided to this service using the <code>org.eclipse.ui.services</code>
+ * Extension Point.  This makes the available to &lt;with/&gt; expressions.
+ * </p>
+ * <p>
+ * This service can be acquired from your service locator:
+ * <pre>
+ * 	IEvaluationService service = (IEvaluationService) getSite().getService(IEvaluationService.class);
+ * </pre>
+ * <ul>
+ * <li>This service is available globally.</li>
+ * </ul>
+ * </p>
+ *
+ * @since 3.4
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IEvaluationService extends IServiceWithSources {
+	/**
+	 * A general property that can be used.
+	 */
+	public static final String RESULT = "org.eclipse.ui.services.result"; //$NON-NLS-1$
+
+	/**
+	 * The property used to notify any service listeners.
+	 */
+	public static final String PROP_NOTIFYING = "org.eclipse.ui.services.notifying"; //$NON-NLS-1$
+
+	/**
+	 * When a source change starts recalculating expressions the
+	 * {@link #PROP_NOTIFYING} property change is fired with the newValue=<code>Boolean.TRUE</code>.
+	 * This property is not fired for any source changes caused by the outer
+	 * recalculations.
+	 * <p>
+	 * <b>Note:</b> listeners should be removed when no longer necessary. If
+	 * not, they will be removed when the IServiceLocator used to acquire this
+	 * service is disposed.
+	 * </p>
+	 *
+	 * @param listener
+	 *            The listener to be notified. Must not be <code>null</code>.
+	 *            Has no effect if the listener has already been added.
+	 */
+	public void addServiceListener(IPropertyChangeListener listener);
+
+	/**
+	 * Remove the listener for {@link #PROP_NOTIFYING} property changes.
+	 *
+	 * @param listener
+	 *            The listener to remove. Must not be <code>null</code>. Has
+	 *            no effect if the listener is not currently registered.
+	 */
+	public void removeServiceListener(IPropertyChangeListener listener);
+
+	/**
+	 * Add a listener that can be notified when the workbench application
+	 * context causes the expression evaluation value to change.
+	 * <p>
+	 * <b>Note:</b> listeners should be removed when no longer necessary. If
+	 * not, they will be removed when the IServiceLocator used to acquire this
+	 * service is disposed.
+	 * </p>
+	 *
+	 * @param expression
+	 *            the core expression to evaluate.
+	 * @param listener
+	 *            the listener to be notified.
+	 * @param property
+	 *            the property contained in the notification
+	 * @return a token that can be used to remove this listener.
+	 * {@link #removeEvaluationListener(IEvaluationReference)}
+	 */
+	public IEvaluationReference addEvaluationListener(Expression expression,
+			IPropertyChangeListener listener, String property);
+
+	/**
+	 * Re-add a property change listener that has already been removed by
+	 * {@link #removeEvaluationListener(IEvaluationReference)}.
+	 * <p>
+	 * It will only accept IEvaluationReferences returned from a previous call
+	 * to
+	 * {@link #addEvaluationListener(Expression, IPropertyChangeListener, String)}
+	 * on this service.
+	 * </p>
+	 * <p>
+	 * <b>Note:</b> references should be removed when no longer necessary. If
+	 * not, they will be removed when the IServiceLocator used to acquire this
+	 * service is disposed.
+	 * </p>
+	 *
+	 * @param ref
+	 *            The listener to re-add.
+	 * @see #removeEvaluationListener(IEvaluationReference)
+	 */
+	public void addEvaluationReference(IEvaluationReference ref);
+
+	/**
+	 * Remove the listener represented by the evaluation reference.
+	 *
+	 * @param ref
+	 *            the reference to be removed.
+	 */
+	public void removeEvaluationListener(IEvaluationReference ref);
+
+	/**
+	 * Get an IEvaluationContext that contains the current state of the
+	 * workbench application context. This context changes with the application
+	 * state, but becomes invalid when the global current selection changes.
+	 * <p>
+	 * Note: This context should not be modified.
+	 * </p>
+	 *
+	 * @return the latest context.
+	 * @see ISources#ACTIVE_CURRENT_SELECTION_NAME
+	 */
+	public IEvaluationContext getCurrentState();
+
+	/**
+	 * Request that this service re-evaluate all registered core expressions
+	 * that contain a property tester for the given property name. This will
+	 * fire a {@link #PROP_NOTIFYING} property change event to service
+	 * listeners.
+	 * <p>
+	 * Notes:
+	 * <ul>
+	 * <li>the property must be able to return the new value before this
+	 * re-evaluation is requested</li>
+	 * <li>limit calls to this method to avoid unnecessary churn</li>
+	 * <li>A re-evaluation that does not change the value of an expression will
+	 * not fire a property change event</li>
+	 * </ul>
+	 * </p>
+	 *
+	 * @param propertyName
+	 *            The fully qualified property name, like
+	 *            <code>org.eclipse.core.resources.name</code>. Must not be
+	 *            <code>null</code>.
+	 * @since 3.4
+	 */
+	public void requestEvaluation(String propertyName);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/services/IServiceLocator.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/services/IServiceLocator.java
new file mode 100644
index 0000000..2a05490
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/services/IServiceLocator.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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
+ *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 430981 - Generified API
+ *******************************************************************************/
+
+package org.eclipse.ui.services;
+
+/**
+ * <p>
+ * A component with which one or more services are registered. The services can
+ * be retrieved from this locator using some key -- typically the class
+ * representing the interface the service must implement. For example:
+ * </p>
+ *
+ * <pre>
+ * IHandlerService service = workbenchWindow.getService(IHandlerService.class);
+ * </pre>
+ *
+ * <p>
+ * This interface is not to be implemented or extended by clients.
+ * </p>
+ *
+ * @since 3.2
+ */
+public interface IServiceLocator {
+
+	/**
+	 * Retrieves the service corresponding to the given API.
+	 *
+	 * @param api
+	 *            This is the interface that the service implements. Must not be
+	 *            <code>null</code>.
+	 * @return The service, or <code>null</code> if no such service could be
+	 *         found.
+	 */
+
+	public <T> T getService(Class<T> api);
+
+	/**
+	 * Whether this service exists within the scope of this service locator.
+	 * This does not include looking for the service within the scope of the
+	 * parents. This method can be used to determine whether a particular
+	 * service supports nesting in this scope.
+	 *
+	 * @param api
+	 *            This is the interface that the service implements. Must not be
+	 *            <code>null</code>.
+	 * @return <code>true</code> if the service locator can find a service for
+	 *         the given API; <code>false</code> otherwise.
+	 */
+	public boolean hasService(Class<?> api);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/services/IServiceScopes.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/services/IServiceScopes.java
new file mode 100644
index 0000000..a5b8b88
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/services/IServiceScopes.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.services;
+
+
+/**
+ * Different levels of service locators supported by the workbench.
+ *
+ * @since 3.3
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IServiceScopes {
+	/**
+	 * The global service locator scope.
+	 */
+	public static final String WORKBENCH_SCOPE = "org.eclipse.ui.services.IWorkbench"; //$NON-NLS-1$
+
+	/**
+	 * A sub-scope to the global scope that is not the workbench window.
+	 *
+	 * @since 3.5
+	 */
+	public static final String DIALOG_SCOPE = "org.eclipse.ui.services.IDialog"; //$NON-NLS-1$
+	/**
+	 * A workbench window service locator scope.
+	 */
+	public static final String WINDOW_SCOPE = "org.eclipse.ui.IWorkbenchWindow"; //$NON-NLS-1$
+
+	/**
+	 * A part site service locator scope.  Found in editors and views.
+	 */
+	public static final String PARTSITE_SCOPE = "org.eclipse.ui.part.IWorkbenchPartSite"; //$NON-NLS-1$
+
+	/**
+	 * A page site service locator scope.  Found in pages in a PageBookView.
+	 */
+	public static final String PAGESITE_SCOPE = "org.eclipse.ui.part.PageSite"; //$NON-NLS-1$
+
+	/**
+	 * An editor site within a MultiPageEditorPart.
+	 */
+	public static final String MPESITE_SCOPE = "org.eclipse.ui.part.MultiPageEditorSite"; //$NON-NLS-1$
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/services/IServiceWithSources.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/services/IServiceWithSources.java
new file mode 100644
index 0000000..a8bedff
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/services/IServiceWithSources.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.services;
+
+import org.eclipse.ui.ISourceProvider;
+
+/**
+ * <p>
+ * A service that responds to changes in one or more sources. These sources can
+ * be plugged into the service. Sources represent a common event framework for
+ * services.
+ * </p>
+ * <p>
+ * Clients must not extend or implement.
+ * </p>
+ *
+ * @since 3.2
+ */
+public interface IServiceWithSources extends IDisposable {
+
+	/**
+	 * Adds a source provider to this service. A source provider will notify the
+	 * service when the source it provides changes. An example of a source might
+	 * be an active editor or the current selection. This amounts to a pluggable
+	 * state tracker for the service.
+	 *
+	 * @param provider
+	 *            The provider to add; must not be <code>null</code>.
+	 */
+	public void addSourceProvider(ISourceProvider provider);
+
+	/**
+	 * Removes a source provider from this service. Most of the time, this
+	 * method call is not required as source providers typically share the same
+	 * life span as the workbench itself.
+	 *
+	 * @param provider
+	 *            The provider to remove; must not be <code>null</code>.
+	 */
+	public void removeSourceProvider(ISourceProvider provider);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/services/ISourceProviderService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/services/ISourceProviderService.java
new file mode 100644
index 0000000..b77e0e5
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/services/ISourceProviderService.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.services;
+
+import org.eclipse.ui.ISourceProvider;
+
+/**
+ * <p>
+ * A service from which all of the source providers can be retrieved.
+ * </p>
+ * <p>
+ * This service can be acquired from your service locator:
+ * <pre>
+ * 	ISourceProviderService service = (ISourceProviderService) getSite().getService(ISourceProviderService.class);
+ * </pre>
+ * <ul>
+ * <li>This service is available globally.</li>
+ * </ul>
+ * </p>
+ *
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noextend This interface is not intended to be extended by clients.
+ *
+ * @since 3.4
+ * @see org.eclipse.ui.services.IEvaluationService
+ */
+public interface ISourceProviderService {
+
+	/**
+	 * Retrieves a source provider providing the given source. This is used by
+	 * clients who only need specific sources.
+	 *
+	 * @param sourceName
+	 *            The name of the source; must not be <code>null</code>.
+	 * @return A source provider which provides the request source, or
+	 *         <code>null</code> if no such source exists.
+	 * @see org.eclipse.ui.ISources
+	 */
+	public ISourceProvider getSourceProvider(final String sourceName);
+
+	/**
+	 * Retrieves all of the source providers registered with this service at the
+	 * time of this call.
+	 * <p>
+	 * <code>org.eclipse.ui.services.IEvaluationService</code> can be used
+	 * to receive notifications about source variable changes and to
+	 * evaluate core expressions against source providers.
+	 * </p>
+	 *
+	 * @return The source providers registered with this service. This value is
+	 *         never <code>null</code>, but may be empty.
+	 */
+	public ISourceProvider[] getSourceProviders();
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/services/package.html b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/services/package.html
new file mode 100644
index 0000000..5ee7669
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/services/package.html
@@ -0,0 +1,20 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <meta name="Author" content="IBM">
+   <meta name="GENERATOR" content="Mozilla/4.5 [en] (WinNT; I) [Netscape]">
+   <title>Package-level Javadoc</title>
+</head>
+<body>
+<p>Classes for service support.</p>
+<h2>
+Package Specification</h2>
+<p>
+This package has the base service support API.  IServiceLocator is used
+to retrieve any of the services contributed to the workbench, workbench
+window, or part site.
+</p>
+
+</body>
+</html>
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/splash/AbstractSplashHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/splash/AbstractSplashHandler.java
new file mode 100644
index 0000000..c4f50dc
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/splash/AbstractSplashHandler.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.splash;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferenceConstants;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.application.WorkbenchAdvisor;
+
+/**
+ * Base class for splash implementations. Please note that methods on this class
+ * will be invoked while the Workbench is being instantiated. As such, any
+ * resource provided by the workbench plug-in cannot be guaranteed to be
+ * available to this class while executing. No attempt should be made to access
+ * {@link IWorkbench} or any subordinate interfaces or resources.
+ *
+ * @since 3.3
+ */
+public abstract class AbstractSplashHandler {
+
+	private Shell shell;
+
+	/**
+	 * Initialize this splash implementation. This is called very early in the
+	 * workbench lifecycle before any window is created. The provided shell will
+	 * already have a background image provided to it but subclasses are free to
+	 * customize the shell in whatever way they see fit. Subclasses should
+	 * ensure that they call the base implementation of this method at some
+	 * point after their own method is invoked.
+	 *
+	 * <p>
+	 * Calls to this method will be made from the UI thread.
+	 * </p>
+	 *
+	 * @param splash
+	 *            the splash shell
+	 */
+	public void init(Shell splash) {
+		this.shell = splash;
+	}
+
+	/**
+	 * Signal the handler to end the splash and dispose of any resources.
+	 * Subclasses should ensure that they call the base implementation of this
+	 * method at some point after their own method is invoked.
+	 *
+	 * <p>
+	 * Calls to this method will be made from the UI thread.
+	 * </p>
+	 */
+	public void dispose() {
+		shell.close();
+		shell = null;
+	}
+
+	/**
+	 * Return the progress monitor responsible for showing bundle loading.
+	 * Default implementation returns a null progress monitor.
+	 *
+	 * <p>
+	 * Calls made to methods on this progress monitor may be made from non-UI
+	 * threads so implementors must take care to ensure proper synchronization
+	 * with the UI thread if necessary.
+	 * </p>
+	 *
+	 * <p>
+	 * Please note that progress will only be shown if the
+	 * "org.eclipse.ui/SHOW_PROGRESS_ON_STARTUP" property has been set to
+	 * <code>true</code>. Because this property defaults to <code>false</code>
+	 * RCP developers must set this property via a
+	 * <code>plugin_customization.ini</code> file or by setting the preference
+	 * on the Platform UI preference store in the
+	 * {@link WorkbenchAdvisor#initialize(org.eclipse.ui.application.IWorkbenchConfigurer)}
+	 * method if they wish to have progress reported on startup.
+	 * </p>
+	 *
+	 * @return the progress monitor
+	 * @see NullProgressMonitor
+	 * @see PlatformUI#getPreferenceStore()
+	 * @see IWorkbenchPreferenceConstants#SHOW_PROGRESS_ON_STARTUP
+	 * @see WorkbenchAdvisor#initialize(org.eclipse.ui.application.IWorkbenchConfigurer)
+	 */
+	public IProgressMonitor getBundleProgressMonitor() {
+		return new NullProgressMonitor();
+	}
+
+	/**
+	 * Get the {@link Shell} associated with this splash screen. If this method
+	 * returns a non-<code>null</code> value prior to the
+	 * {@link #init(Shell)} being invoked then this shell will be used for the
+	 * splash shell and it will subsequently be passed to the
+	 * {@link #init(Shell)} method. In this way a splash handler may participate
+	 * in splash processes prior to the workbench startup.
+	 *
+	 * <p>
+	 * Calls to this method may be made from any thread. Implementors must take
+	 * care to ensure proper synchronization with the UI thread if necessary.
+	 * </p>
+	 *
+	 * @return the splash shell
+	 */
+	public Shell getSplash() {
+		return shell;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/splash/BasicSplashHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/splash/BasicSplashHandler.java
new file mode 100644
index 0000000..9af2e64
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/splash/BasicSplashHandler.java
@@ -0,0 +1,271 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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
+ *     Stefan Winkler <stefan@winklerweb.net> - Bug 430848
+ *******************************************************************************/
+package org.eclipse.ui.splash;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+//import org.eclipse.e4.ui.css.swt.CSSSWTConstants;
+import org.eclipse.jface.dialogs.ProgressIndicator;
+import org.eclipse.jface.window.Window;
+import org.eclipse.jface.wizard.ProgressMonitorPart;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.internal.StartupThreading.StartupRunnable;
+
+/**
+ * Basic splash implementation that provides an absolute positioned progress bar
+ * and message string that is hooked up to a progress monitor.
+ *
+ * @since 3.3
+ */
+public abstract class BasicSplashHandler extends AbstractSplashHandler {
+
+	private static final String SPLASH_PROGRESS_PART_ID = "org-eclipse-ui-splash-progressPart"; //$NON-NLS-1$
+	private static final String SPLASH_PROGRESS_INDICATOR_ID = "org-eclipse-ui-splash-progressIndicator"; //$NON-NLS-1$
+	private static final String SPLASH_PROGRESS_TEXT_ID = "org-eclipse-ui-splash-progressText"; //$NON-NLS-1$
+
+	/**
+	 * Hacks the progress monitor to have absolute positioning for its controls.
+	 * In addition, all methods that access the controls will be wrapped in an
+	 * asynchExec().
+	 */
+	class AbsolutePositionProgressMonitorPart extends ProgressMonitorPart {
+		public AbsolutePositionProgressMonitorPart(Composite parent) {
+			super(parent, null);
+			setLayout(null);
+			setCSSData();
+		}
+
+		private void setCSSData() {
+//			this.setData(CSSSWTConstants.CSS_ID_KEY, SPLASH_PROGRESS_PART_ID);
+//			fProgressIndicator.setData(CSSSWTConstants.CSS_ID_KEY, SPLASH_PROGRESS_INDICATOR_ID);
+//			fLabel.setData(CSSSWTConstants.CSS_ID_KEY, SPLASH_PROGRESS_TEXT_ID);
+		}
+
+		public ProgressIndicator getProgressIndicator() {
+			return fProgressIndicator;
+		}
+
+		public Label getProgressText() {
+			return fLabel;
+		}
+
+		@Override
+		public void beginTask(final String name, final int totalWork) {
+
+			updateUI(() -> {
+				if (isDisposed())
+					return;
+				AbsolutePositionProgressMonitorPart.super.beginTask(name,
+						totalWork);
+			});
+
+		}
+
+		@Override
+		public void done() {
+
+			updateUI(() -> {
+				if (isDisposed())
+					return;
+				AbsolutePositionProgressMonitorPart.super.done();
+			});
+
+		}
+
+		@Override
+		public void internalWorked(final double work) {
+
+			updateUI(() -> {
+				if (isDisposed())
+					return;
+				AbsolutePositionProgressMonitorPart.super
+						.internalWorked(work);
+			});
+
+		}
+
+		@Override
+		public void setFont(final Font font) {
+
+			updateUI(() -> {
+				if (isDisposed())
+					return;
+				AbsolutePositionProgressMonitorPart.super.setFont(font);
+			});
+
+		}
+
+		@Override
+		protected void updateLabel() {
+
+			updateUI(() -> {
+				if (isDisposed())
+					return;
+				AbsolutePositionProgressMonitorPart.super.updateLabel();
+			});
+
+		}
+	}
+
+	private Color foreground = null;
+	private AbsolutePositionProgressMonitorPart monitor;
+	private Rectangle messageRect;
+	private Rectangle progressRect;
+
+	@Override
+	public IProgressMonitor getBundleProgressMonitor() {
+		if (monitor == null) {
+			Composite parent = new Composite(getSplash(), Window.getDefaultOrientation());
+			Point size = getSplash().getSize();
+			parent.setBounds(new Rectangle(0,0,size.x,size.y));
+			monitor = new AbsolutePositionProgressMonitorPart(parent);
+			monitor.setSize(size);
+			if (progressRect != null)
+				monitor.getProgressIndicator().setBounds(progressRect);
+			else
+				monitor.getProgressIndicator().setVisible(false);
+
+			if (messageRect != null)
+				monitor.getProgressText().setBounds(messageRect);
+			else
+				monitor.getProgressText().setVisible(false);
+
+			if (foreground != null)
+				monitor.getProgressText().setForeground(foreground);
+			monitor.setBackgroundMode(SWT.INHERIT_FORCE);
+			monitor.setBackgroundImage(getSplash().getShell()
+					.getBackgroundImage());
+		}
+		return monitor;
+	}
+
+	@Override
+	public void dispose() {
+		if (foreground != null)
+			foreground.dispose();
+		super.dispose();
+	}
+
+	/**
+	 * Set the foreground text color. This method has no effect after
+	 * {@link #getBundleProgressMonitor()} has been invoked.
+	 *
+	 * @param foregroundRGB
+	 *            the color
+	 */
+	protected void setForeground(RGB foregroundRGB) {
+		if (monitor != null)
+			return;
+		if (this.foreground != null)
+			this.foreground.dispose();
+		this.foreground = new Color(getSplash().getShell().getDisplay(),
+				foregroundRGB);
+	}
+
+	/**
+	 * Get the foreground text color. This color should not be disposed by
+	 * callers.
+	 *
+	 * @return the foreground color
+	 */
+	protected Color getForeground() {
+		return foreground;
+	}
+
+	/**
+	 * Set the location of the message text in the splash. This method has no
+	 * effect after {@link #getBundleProgressMonitor()} has been invoked.
+	 *
+	 * @param messageRect
+	 *            the location of the message text
+	 */
+	protected void setMessageRect(Rectangle messageRect) {
+		this.messageRect = messageRect;
+	}
+
+	/**
+	 * Set the location of the progress bar in the splash. This method has no
+	 * effect after {@link #getBundleProgressMonitor()} has been invoked.
+	 *
+	 * @param progressRect
+	 *            the location of the progress bar
+	 */
+	protected void setProgressRect(Rectangle progressRect) {
+		this.progressRect = progressRect;
+	}
+
+	/**
+	 * Get the composite on which any supplemental controls should be drawn.
+	 * This will not have a layout set and clients are responsible for setting
+	 * the location of child controls manually.
+	 *
+	 * <p>
+	 * This method must be called in the
+	 * {@link #init(org.eclipse.swt.widgets.Shell)} method of a subclasses to
+	 * ensure proper creation of controls
+	 * </p>
+	 *
+	 * <p>
+	 * Please note that the default implementation of this method assumes that
+	 * the {@link IProgressMonitor} returned from
+	 * {@link #getBundleProgressMonitor()} can be safely casted to a
+	 * {@link Composite}. If this is not the case this method must be
+	 * reimplemented to reflect the new progress controls.
+	 * </p>
+	 *
+	 * @see #init(org.eclipse.swt.widgets.Shell)
+	 * @return the composite
+	 */
+	protected Composite getContent() {
+		return (Composite) getBundleProgressMonitor();
+	}
+
+	/**
+	 * Perform some update on the splash. If called from a non-UI thread it will
+	 * be wrapped by a runnable that may be run before the workbench has been
+	 * fully realized.
+	 *
+	 * @param r
+	 *            the update runnable
+	 * @throws Throwable
+	 */
+	private void updateUI(final Runnable r) {
+		Shell splashShell = getSplash();
+		if (splashShell == null || splashShell.isDisposed())
+			return;
+
+		Display display = splashShell.getDisplay();
+
+		if (Thread.currentThread() == display.getThread())
+			r.run(); // run immediatley if we're on the UI thread
+		else {
+			// wrapper with a StartupRunnable to ensure that it will run before
+			// the UI is fully initialized
+			StartupRunnable startupRunnable = new StartupRunnable() {
+
+				@Override
+				public void runWithException() throws Throwable {
+					r.run();
+				}
+			};
+			display.asyncExec(startupRunnable);
+		}
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/splash/package.html b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/splash/package.html
new file mode 100644
index 0000000..32c4dc1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/splash/package.html
@@ -0,0 +1,13 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <title>Package-level Javadoc</title>
+</head>
+<body>
+Application programming interfaces for interaction
+with and extension of the Eclipse Platform User Interface.
+<h2>Package Specification</h2>
+This package provides API for augmenting or replacing the Eclipse splash process.  See the org.eclipse.ui.splashHandlers extension point.
+</body>
+</html>
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/statushandlers/AbstractStatusAreaProvider.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/statushandlers/AbstractStatusAreaProvider.java
new file mode 100644
index 0000000..3468ac9
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/statushandlers/AbstractStatusAreaProvider.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2015 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.ui.statushandlers;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.dialogs.ErrorSupportProvider;
+import org.eclipse.jface.util.Policy;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+/**
+ * <p>
+ * A status area provider creates an area that displays detailed information
+ * about {@link StatusAdapter} or {@link IStatus}.
+ * </p>
+ *
+ * <p>
+ * The area provider can be set in {@link WorkbenchStatusDialogManager} as well as in
+ * JFace {@link Policy} since its extends {@link ErrorSupportProvider}.
+ * </p>
+ *
+ * @see Policy#setErrorSupportProvider(ErrorSupportProvider)
+ * @see WorkbenchStatusDialogManager#setSupportAreaProvider(AbstractStatusAreaProvider)
+ * @see WorkbenchStatusDialogManager#setDetailsAreaProvider(AbstractStatusAreaProvider)
+ * @since 3.4
+ */
+public abstract class AbstractStatusAreaProvider extends ErrorSupportProvider {
+
+	/**
+	 * Create an area for detailed support area as a child of the given parent.
+	 *
+	 * @param parent
+	 *            A {@link Composite} that will host support area.
+	 * @param statusAdapter
+	 *            The {@link StatusAdapter} to be supported.
+	 * @return a control, that hold all support elements.
+	 */
+	public abstract Control createSupportArea(Composite parent,
+			StatusAdapter statusAdapter);
+
+	@Override
+	public final Control createSupportArea(Composite parent, IStatus status) {
+		return createSupportArea(parent, new StatusAdapter(status));
+	}
+
+	/**
+	 * This method is called before
+	 * {@link #createSupportArea(Composite, StatusAdapter)} to check if it will
+	 * display any significant implementation.
+	 * <p>
+	 * <b>Important</b>: This API is a part of work in progress and therefore is
+	 * suitable only for support area providers (which are presented in the
+	 * status dialog tray).
+	 * </p>
+	 *
+	 * @param statusAdapter
+	 *            - {@link StatusAdapter} for which status are will be
+	 *            requested.
+	 * @return true if provider is able to process particular
+	 *         {@link StatusAdapter}
+	 * @since 3.6
+	 */
+	public boolean validFor(StatusAdapter statusAdapter) {
+		return true;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/statushandlers/AbstractStatusHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/statushandlers/AbstractStatusHandler.java
new file mode 100644
index 0000000..068979e
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/statushandlers/AbstractStatusHandler.java
@@ -0,0 +1,155 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.statushandlers;
+
+import java.util.Map;
+
+import org.eclipse.ui.application.WorkbenchAdvisor;
+
+/**
+ * <p>
+ * Status handlers are part of the status handling facility. The facility is
+ * responsible for handling errors and other important issues in Eclipse based
+ * applications. The handlers are responsible for presenting this errors by
+ * logging or showing error dialogs.
+ * </p>
+ *
+ * <p>
+ * All status handlers extends
+ * <code>org.eclipse.ui.statushandlers.AbstractStatusHandler</code>. Each
+ * handler implements <code>handle(StatusAdapter status, int style)</code>.
+ * This method handles statuses due to handling style. The style indicates how
+ * status handler should handle a status.
+ * </p>
+ *
+ * <p>
+ * For acceptable styles check {@link StatusManager}.
+ * </p>
+ *
+ * <p>
+ * Handlers shoudn't be used directly but through the {@link StatusManager}. It
+ * chooses which handler should be used for handling. There are two ways for
+ * adding handlers to the handling flow. First using extension point
+ * <code>org.eclipse.ui.statusHandlers</code>, second by the workbench
+ * advisor and its method {@link WorkbenchAdvisor#getWorkbenchErrorHandler()}.
+ * If a handler is associated with a product, it is used instead of this defined
+ * in advisor.
+ * </p>
+ *
+ * <p>
+ * A status handler has the id and a set of parameters. The handler can use them
+ * during handling. If the handler is added as an extension, both are set during
+ * initialization of the handler using elements and attributes of
+ * <code>statusHandler</code> element.
+ * </p>
+ *
+ * @since 3.3
+ */
+public abstract class AbstractStatusHandler {
+
+	private Map params;
+
+	private String id;
+
+	/**
+	 * Handles {@link StatusAdapter} objects based on the set style.
+	 *
+	 * @param statusAdapter
+	 *            the status adapter. May not be <code>null</code>.
+	 * @param style
+	 *            style constant. Acceptable values are defined in
+	 *            {@link StatusManager} and can be combined with logical OR.
+	 *
+	 * @see StatusManager#BLOCK
+	 * @see StatusManager#NONE
+	 * @see StatusManager#SHOW
+	 * @see StatusManager#LOG
+	 */
+	public abstract void handle(StatusAdapter statusAdapter, int style);
+
+	/**
+	 * Returns all parameters of the handler.
+	 *
+	 * @return the parameters
+	 */
+	public Map getParams() {
+		return params;
+	}
+
+	/**
+	 * Returns the value of the handler's parameter identified by the given key,
+	 * or <code>null</code> if this handler has no such parameter.
+	 *
+	 * @param key
+	 *            the name of the property
+	 * @return the value of the parameter, or <code>null</code> if this
+	 *         handler has no such parameter
+	 */
+	public Object getParam(Object key) {
+		if (params != null) {
+			return params.get(key);
+		}
+
+		return null;
+	}
+
+	/**
+	 * Sets the parameters for the handler. If the handler is added via the
+	 * <code> org.eclipse.ui.statushandlers extension</code>, the parameters are set
+	 * during initialization of the handler using <code>parameter</code>
+	 * elements from <code>statusHandler</code>
+	 * element.
+	 *
+	 * @param params
+	 *            the parameters to set
+	 */
+	public void setParams(Map params) {
+		this.params = params;
+	}
+
+	/**
+	 * Returns the id of the handler.
+	 *
+	 * @return the id
+	 */
+	public String getId() {
+		return id;
+	}
+
+	/**
+	 * Sets the id for the handler. If the handler is added as an extension, the
+	 * id is set during initialization of the handler using <code>id</code>
+	 * attribute of <code>statusHandler</code> element.
+	 *
+	 * @param id
+	 *            the id to set
+	 */
+	public void setId(String id) {
+		this.id = id;
+	}
+
+	/**
+	 * This methods indicates if particular notification type is supported and
+	 * if {@link StatusManager#fireNotification(int, StatusAdapter[])} will be
+	 * called after the event occurs. Only known notification types should be
+	 * accepted, whereas unknown types should be always rejected.
+	 *
+	 * @param type
+	 *            - a notification type that should be checked.
+	 * @return true if particular event notification is supported, false
+	 *         otherwise
+	 * @since 3.5
+	 */
+	public boolean supportsNotification(int type){
+		return false;
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/statushandlers/IStatusAdapterConstants.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/statushandlers/IStatusAdapterConstants.java
new file mode 100644
index 0000000..312635c
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/statushandlers/IStatusAdapterConstants.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2015 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.ui.statushandlers;
+
+import org.eclipse.core.runtime.QualifiedName;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * This interface contains common constants important for
+ * <code>StatusAdapter</code>.
+ *
+ * <p>
+ * This interface should not be implemented or extended by clients.
+ * </p>
+ *
+ * @since 3.4
+ */
+public interface IStatusAdapterConstants {
+
+	/**
+	 * Common prefix for properties defined in this interface.
+	 */
+	static final String PROPERTY_PREFIX = PlatformUI.PLUGIN_ID
+			+ ".workbench.statusHandlers.adapters"; //$NON-NLS-1$
+
+	/**
+	 * This property is used to add title to the adapter. If the adapter is
+	 * shown in a dialog, this property is used to create title of the dialog.
+	 *
+	 * <p>
+	 * The property must be of type <code>String</code>.
+	 * </p>
+	 */
+	public static final QualifiedName TITLE_PROPERTY = new QualifiedName(
+			PROPERTY_PREFIX, "title"); //$NON-NLS-1$
+
+	/**
+	 * This property is used to add a timestamp to the adapter. If the adapter
+	 * is shown in the UI, this property can be used for sorting and showing
+	 * information about the status creation time.
+	 *
+	 * <p>
+	 * The property must be of type <code>Long</code>.
+	 * </p>
+	 */
+	public static final QualifiedName TIMESTAMP_PROPERTY = new QualifiedName(
+			PROPERTY_PREFIX, "timestamp"); //$NON-NLS-1$
+
+	/**
+	 * This property is used to add an explanation to the adapter. If the
+	 * adapter is shown in the UI, this property should be used to present
+	 * additional explanation for the status.
+	 *
+	 * <p>
+	 * The property must be of type <code>String</code>.
+	 * </p>
+	 */
+	public static final QualifiedName EXPLANATION_PROPERTY = new QualifiedName(
+			PROPERTY_PREFIX, "explanation"); //$NON-NLS-1$
+
+	/**
+	 * This property is used to add a hint to the adapter. If the adapter is
+	 * shown in the UI, this property should be used to present suggested
+	 * actions that have to be performed by the user.
+	 *
+	 * <p>
+	 * The property must be of type <code>String</code>.
+	 * </p>
+	 */
+	public static final QualifiedName HINT_PROPERTY = new QualifiedName(
+			PROPERTY_PREFIX, "suggestedAction"); //$NON-NLS-1$
+
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/statushandlers/StatusAdapter.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/statushandlers/StatusAdapter.java
new file mode 100644
index 0000000..bb91555
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/statushandlers/StatusAdapter.java
@@ -0,0 +1,145 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2016 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.ui.statushandlers;
+
+import java.util.HashMap;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.QualifiedName;
+
+/**
+ * <p>
+ * The StatusAdapter wraps an instance of IStatus subclass and can hold
+ * additional information either by using properties or by adding a new adapter. Used during
+ * status handling process.
+ * </p>
+ *
+ * @since 3.3
+ */
+public class StatusAdapter implements IAdaptable {
+
+	/**
+	 * This property is used to add title to the adapter. If the adapter is
+	 * shown in a dialog, this property is used to create title of the dialog.
+	 *
+	 * @deprecated use {@link IStatusAdapterConstants#TITLE_PROPERTY} instead
+	 */
+	@Deprecated
+	public static final QualifiedName TITLE_PROPERTY = IStatusAdapterConstants.TITLE_PROPERTY;
+
+	/**
+	 * This property is used to add a timestamp to the adapter. If the adapter
+	 * is shown in the UI, this property can be used for sorting and showing
+	 * information about the status creation time.
+	 *
+	 * <p>
+	 * The property must be of type <code>Long</code>.
+	 * </p>
+	 *
+	 * @deprecated use {@link IStatusAdapterConstants#TIMESTAMP_PROPERTY}
+	 *             instead
+	 */
+	@Deprecated
+	public static final QualifiedName TIMESTAMP_PROPERTY = IStatusAdapterConstants.TIMESTAMP_PROPERTY;
+
+	private IStatus status;
+
+	private HashMap properties;
+
+	private HashMap adapters;
+
+	/**
+	 * Creates an instance of this class.
+	 *
+	 * @param status
+	 *            the status to wrap. May not be <code>null</code>.
+	 */
+	public StatusAdapter(IStatus status) {
+		this.status = status;
+	}
+
+	/**
+	 * Associates new object which is an instance of the given class with this
+	 * adapter. object will be returned when {@link IAdaptable#getAdapter(Class)}
+	 * is called on the receiver with {@link Class} adapter as a parameter.
+	 *
+	 * @param adapter
+	 *            the adapter class
+	 * @param object
+	 *            the adapter instance
+	 */
+	public void addAdapter(Class adapter, Object object) {
+		if (adapters == null) {
+			adapters = new HashMap();
+		}
+		adapters.put(adapter, object);
+	}
+
+	@Override
+	public <T> T getAdapter(Class<T> adapter) {
+		if (adapters == null) {
+			return null;
+		}
+		return adapter.cast(adapters.get(adapter));
+	}
+
+	/**
+	 * Returns the wrapped status.
+	 *
+	 * @return the wrapped status set in the constructor or in
+	 *         <code>setStatus(IStatus)</code>. Will not be <code>null</code>.
+	 */
+	public IStatus getStatus() {
+		return status;
+	}
+
+	/**
+	 * Sets a new status for this adapter.
+	 *
+	 * @param status
+	 *            the status to set. May not be <code>null</code>.
+	 */
+	public void setStatus(IStatus status) {
+		this.status = status;
+	}
+
+	/**
+	 * Returns the value of the adapter's property identified by the given key,
+	 * or <code>null</code> if this adapter has no such property.
+	 *
+	 * @param key
+	 *            the qualified name of the property
+	 * @return the value of the property, or <code>null</code> if this adapter
+	 *         has no such property
+	 */
+	public Object getProperty(QualifiedName key) {
+		if (properties == null) {
+			return null;
+		}
+		return properties.get(key);
+	}
+
+	/**
+	 * Sets the value of the receiver's property identified by the given key.
+	 *
+	 * @param key
+	 *            the qualified name of the property
+	 * @param value
+	 *            the value of the property
+	 */
+	public void setProperty(QualifiedName key, Object value) {
+		if (properties == null) {
+			properties = new HashMap();
+		}
+		properties.put(key, value);
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/statushandlers/StatusManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/statushandlers/StatusManager.java
new file mode 100644
index 0000000..f72d2da
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/statushandlers/StatusManager.java
@@ -0,0 +1,432 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2016 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
+ *     Gorkem Ercan (Red Hat) - Fix for Bug 427142
+ *******************************************************************************/
+
+package org.eclipse.ui.statushandlers;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.ILogListener;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.application.WorkbenchAdvisor;
+import org.eclipse.ui.internal.WorkbenchErrorHandlerProxy;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.misc.StatusUtil;
+import org.eclipse.ui.internal.statushandlers.StatusHandlerDescriptor;
+import org.eclipse.ui.internal.statushandlers.StatusHandlerRegistry;
+import org.eclipse.ui.progress.IProgressConstants;
+import org.osgi.framework.BundleContext;
+
+/**
+ * <p>
+ * StatusManager is the entry point for all statuses to be reported in the user
+ * interface.
+ * </p>
+ *
+ * <p>
+ * Handlers shoudn't be used directly but through the StatusManager singleton
+ * which keeps the status handling policy and chooses handlers.
+ * <code>StatusManager.getManager().handle(IStatus)</code> and
+ * <code>handle(IStatus status, int style)</code> are the methods are the
+ * primary access points to the StatusManager.
+ * </p>
+ *
+ * <p>
+ * Acceptable styles (can be combined with logical OR)
+ * <ul>
+ * <li>NONE - a style indicating that the status should not be acted on. This
+ * is used by objects such as log listeners that do not want to report a status
+ * twice</li>
+ * <li>LOG - a style indicating that the status should be logged only</li>
+ * <li>SHOW - a style indicating that handlers should show a problem to an user
+ * without blocking the calling method while awaiting user response. This is
+ * generally done using a non modal {@link Dialog}</li>
+ * <li>BLOCK - a style indicating that the handling should block the UI
+ * until the user has responded. This is generally done using a modal
+ * window such as a {@link Dialog}</li>
+ * </ul>
+ * </p>
+ *
+ * <p>
+ * Handlers are intended to be accessed via the status manager. The
+ * StatusManager chooses which handler should be used for a particular error.
+ * There are two ways for adding handlers to the handling flow. First using
+ * extension point <code>org.eclipse.ui.statusHandlers</code>, second by the
+ * workbench advisor and its method
+ * {@link WorkbenchAdvisor#getWorkbenchErrorHandler()}. If a handler is
+ * associated with a product, it is used instead of this defined in advisor.
+ * </p>
+ *
+ * @since 3.3
+ * @see AbstractStatusHandler
+ */
+public class StatusManager {
+	/**
+	 * A style indicating that the status should not be acted on. This is used
+	 * by objects such as log listeners that do not want to report a status
+	 * twice.
+	 */
+	public static final int NONE = 0;
+
+	/**
+	 * A style indicating that the status should be logged only.
+	 */
+	public static final int LOG = 0x01;
+
+	/**
+	 * A style indicating that handlers should show a problem to an user without
+	 * blocking the calling method while awaiting user response. This is
+	 * generally done using a non modal {@link Dialog}.
+	 */
+	public static final int SHOW = 0x02;
+
+	/**
+	 * A style indicating that the handling should block the calling thread
+	 * until the status has been handled.
+	 * <p>
+	 * A typical usage of this would be to ensure that the user's actions are
+	 * blocked until they've dealt with the status in some manner. It is
+	 * therefore likely but not required that the <code>StatusHandler</code>
+	 * would achieve this through the use of a modal dialog.
+	 * </p><p>Due to the fact
+	 * that use of <code>BLOCK</code> will block UI, care should be
+	 * taken in this use of this flag.
+	 * </p>
+	 */
+	public static final int BLOCK = 0x04;
+
+	private static volatile StatusManager MANAGER;
+
+	private volatile AbstractStatusHandler statusHandler;
+
+	private List loggedStatuses = new ArrayList();
+
+	private ListenerList<INotificationListener> listeners = new ListenerList<>();
+
+	/**
+	 * Returns StatusManager singleton instance.
+	 *
+	 * @return the manager instance
+	 */
+	public static StatusManager getManager() {
+		if (MANAGER != null) {
+			return MANAGER;
+		}
+		synchronized (StatusManager.class) {
+			if (MANAGER == null) {
+				MANAGER = new StatusManager();
+			}
+		}
+		return MANAGER;
+	}
+
+	private StatusManager() {
+		Platform.addLogListener(new StatusManagerLogListener());
+	}
+
+	private AbstractStatusHandler getStatusHandler(){
+		if (statusHandler != null) {
+			return statusHandler;
+		}
+		BundleContext bundleContext = WorkbenchPlugin.getDefault().getBundle().getBundleContext();
+		if (bundleContext == null) {
+			// bundle is not in the STARTING, ACTIVE, or STOPPING state: we
+			// should not do anything, most likely we are going to shut down
+			return null;
+		}
+
+		StatusHandlerDescriptor defaultHandlerDescriptor = StatusHandlerRegistry.getDefault()
+				.getDefaultHandlerDescriptor();
+
+		synchronized (this) {
+			if (statusHandler == null) {
+				if (defaultHandlerDescriptor != null) {
+					try {
+						statusHandler = defaultHandlerDescriptor.getStatusHandler();
+					} catch (CoreException ex) {
+						logError("Errors during the default handler creating", ex); //$NON-NLS-1$
+					}
+				}
+				if (statusHandler == null) {
+					statusHandler = new WorkbenchErrorHandlerProxy();
+				}
+			}
+		}
+		return statusHandler;
+	}
+	/**
+	 * Handles the given status adapter due to the style. Because the facility
+	 * depends on Workbench, this method will log the status, if Workbench isn't
+	 * initialized and the style isn't {@link #NONE}. If Workbench isn't
+	 * initialized and the style is {@link #NONE}, the manager will do nothing.
+	 *
+	 * @param statusAdapter
+	 *            the status adapter
+	 * @param style
+	 *            the style. Value can be combined with logical OR. One of
+	 *            {@link #NONE}, {@link #LOG}, {@link #SHOW} and
+	 *            {@link #BLOCK}.
+	 */
+	public void handle(StatusAdapter statusAdapter, int style) {
+		try {
+			// The manager will only log the error when the status adapter or
+			// the embedded status is null.
+			if (statusAdapter == null) {
+				logError(
+						"Error occurred during status handling",//$NON-NLS-1$
+						new NullPointerException("StatusAdapter object is null")); //$NON-NLS-1$
+				return;
+			}
+			if (statusAdapter.getStatus() == null) {
+				logError("Error occurred during status handling",//$NON-NLS-1$
+						new NullPointerException("Status object is null")); //$NON-NLS-1$
+				return;
+			}
+
+			// The manager will only log the status, if Workbench isn't
+			// initialized and the style isn't NONE. If Workbench isn't
+			// initialized and the style is NONE, the manager will do nothing.
+			if (!PlatformUI.isWorkbenchRunning()) {
+				if (style != StatusManager.NONE) {
+					logError(statusAdapter.getStatus());
+				}
+				return;
+			}
+
+			// delegates the problem to workbench handler
+			AbstractStatusHandler handler = getStatusHandler();
+			if (handler != null) {
+				handler.handle(statusAdapter, style);
+			} else if (style != StatusManager.NONE) {
+				logError(statusAdapter.getStatus());
+			}
+
+			// if attached status handler is not able to notify StatusManager
+			// about particular event, use the default policy and fake the
+			// notification
+			if (handler == null || !handler.supportsNotification(
+					INotificationTypes.HANDLED)) {
+				generateFakeNotification(statusAdapter, style);
+			}
+		} catch (Throwable ex) {
+			// The used status handler failed
+			if (statusAdapter != null) {
+				logError(statusAdapter.getStatus());
+			}
+			logError("Error occurred during status handling", ex); //$NON-NLS-1$
+		}
+	}
+
+	/**
+	 * Handles the given status adapter. The {@link #LOG} style is used when
+	 * this method is called.
+	 *
+	 * @param statusAdapter
+	 *            the status adapter
+	 */
+	public void handle(StatusAdapter statusAdapter) {
+		handle(statusAdapter, StatusManager.LOG);
+	}
+
+	/**
+	 * Handles the given status due to the style. Because the facility depends
+	 * on Workbench, this method will log the status, if Workbench isn't
+	 * initialized and the style isn't {@link #NONE}. If Workbench isn't
+	 * initialized and the style is {@link #NONE}, the manager will do nothing.
+	 *
+	 * @param status
+	 *            the status to handle
+	 * @param style
+	 *            the style. Value can be combined with logical OR. One of
+	 *            {@link #NONE}, {@link #LOG}, {@link #SHOW} and
+	 *            {@link #BLOCK}.
+	 */
+	public void handle(IStatus status, int style) {
+		StatusAdapter statusAdapter = new StatusAdapter(status);
+		handle(statusAdapter, style);
+	}
+
+	/**
+	 * Handles the given status. The {@link #LOG} style is used when this method
+	 * is called.
+	 *
+	 * @param status
+	 *            the status to handle
+	 */
+	public void handle(IStatus status) {
+		handle(status, StatusManager.LOG);
+	}
+
+	/**
+	 * Handles given CoreException. This method has been introduced to prevent
+	 * anti-pattern: <br/><code>
+	 * StatusManager.getManager().handle(coreException.getStatus());
+	 * </code><br/>
+	 * that does not print the stack trace to the log.
+	 *
+	 * @param coreException
+	 *            a CoreException to be handled.
+	 * @param pluginId
+	 *            the unique identifier of the relevant plug-in
+	 * @see StatusManager#handle(IStatus)
+	 * @since 3.4
+	 *
+	 */
+	public void handle(CoreException coreException,String pluginId) {
+		IStatus exceptionStatus = coreException.getStatus();
+		handle(new Status(exceptionStatus.getSeverity(), pluginId,
+				coreException
+				.getLocalizedMessage(), coreException));
+	}
+
+	/**
+	 * This method informs the StatusManager that this IStatus is being handled
+	 * by the handler and to ignore it when it shows up in our ILogListener.
+	 *
+	 * @param status
+	 *            already handled and logged status
+	 */
+	public void addLoggedStatus(IStatus status) {
+		loggedStatuses.add(status);
+	}
+
+	private void logError(String message, Throwable ex) {
+		IStatus status = StatusUtil.newStatus(WorkbenchPlugin.PI_WORKBENCH,
+				message, ex);
+		addLoggedStatus(status);
+		WorkbenchPlugin.log(status);
+	}
+
+	private void logError(IStatus status) {
+		addLoggedStatus(status);
+		WorkbenchPlugin.log(status);
+	}
+
+	/**
+	 * This log listener handles statuses added to a plug-in's log. If our own
+	 * WorkbenchErrorHandler inserts it into the log, then ignore it.
+	 *
+	 * @see #addLoggedStatus(IStatus)
+	 * @since 3.3
+	 */
+	private class StatusManagerLogListener implements ILogListener {
+
+		@Override
+		public void logging(IStatus status, String plugin) {
+			if (!loggedStatuses.contains(status)) {
+				handle(status, StatusManager.NONE);
+			} else {
+				loggedStatuses.remove(status);
+			}
+		}
+	}
+
+	/**
+	 * This method should be called by custom status handlers when an event
+	 * occurs. This method has no effect if statushandler does not support
+	 * particular event type.
+	 *
+	 * @param type
+	 *            - type of the event.
+	 * @param adapters
+	 *            - array of affected {@link StatusAdapter}s.
+	 * @see INotificationTypes
+	 * @see AbstractStatusHandler#supportsNotification(int)
+	 * @since 3.5
+	 */
+	public void fireNotification(int type, StatusAdapter[] adapters){
+		AbstractStatusHandler handler = getStatusHandler();
+		if (handler != null && handler.supportsNotification(type)) {
+			doFireNotification(type, adapters);
+		}
+	}
+
+	private void doFireNotification(int type, StatusAdapter[] adapters) {
+		for (INotificationListener listener : listeners) {
+			listener.statusManagerNotified(type, adapters);
+		}
+	}
+
+	private void generateFakeNotification(StatusAdapter statusAdapter, int style) {
+		if (((style & StatusManager.SHOW) == StatusManager.SHOW || (style & StatusManager.BLOCK) == StatusManager.BLOCK)
+				&& statusAdapter
+						.getProperty(IProgressConstants.NO_IMMEDIATE_ERROR_PROMPT_PROPERTY) != Boolean.TRUE) {
+			doFireNotification(INotificationTypes.HANDLED,
+					new StatusAdapter[] { statusAdapter });
+		}
+	}
+
+	/**
+	 * Adds a listener to the StatusManager.
+	 *
+	 * @param listener
+	 *            - a listener to be added.
+	 * @since 3.5
+	 */
+	public void addListener(INotificationListener listener) {
+		this.listeners.add(listener);
+	}
+
+	/**
+	 * Removes a listener from StatusManager.
+	 *
+	 * @param listener
+	 *            - a listener to be removed.
+	 * @since 3.5
+	 */
+	public void removeListener(INotificationListener listener){
+		this.listeners.remove(listener);
+	}
+
+	/**
+	 * This interface allows for listening to status handling framework changes.
+	 * Currently it is possible to be notified when:
+	 * <ul>
+	 * 	<li>all statuses has been handled</li>.
+	 * </ul>
+	 * @since 3.5
+	 *
+	 */
+	public interface INotificationListener{
+		/**
+		 *
+		 * @param type
+		 *            - a type of notification.
+		 * @param adapters
+		 *            - affected {@link StatusAdapter}s
+		 */
+		public void statusManagerNotified(int type, StatusAdapter[] adapters);
+	}
+
+	/**
+	 * This interface declares types of notification.
+	 *
+	 * @since 3.5
+	 * @noextend This interface is not intended to be extended by clients.
+	 * @noimplement This interface is not intended to be implemented by clients.
+	 *
+	 */
+	public interface INotificationTypes {
+
+		/**
+		 * This type notifications are used when a particular
+		 * {@link StatusAdapter} was handled.
+		 */
+		public static final int HANDLED = 0x01;
+
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/statushandlers/WorkbenchErrorHandler.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/statushandlers/WorkbenchErrorHandler.java
new file mode 100644
index 0000000..4fed5d8
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/statushandlers/WorkbenchErrorHandler.java
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 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.ui.statushandlers;
+
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.application.WorkbenchAdvisor;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.statushandlers.IStatusDialogConstants;
+import org.eclipse.ui.statushandlers.StatusManager.INotificationTypes;
+
+/**
+ * This is a default workbench error handler.
+ *
+ * @see WorkbenchAdvisor#getWorkbenchErrorHandler()
+ * @since 3.3
+ */
+public class WorkbenchErrorHandler extends AbstractStatusHandler {
+
+	@Override
+	public boolean supportsNotification(int type) {
+		if (type == INotificationTypes.HANDLED) {
+			return true;
+		}
+		return super.supportsNotification(type);
+	}
+
+	private WorkbenchStatusDialogManager statusDialogManager;
+
+	@Override
+	public void handle(final StatusAdapter statusAdapter, int style) {
+		statusAdapter.setProperty(WorkbenchStatusDialogManager.HINT, Integer.valueOf(style));
+		if (((style & StatusManager.SHOW) == StatusManager.SHOW)
+				|| ((style & StatusManager.BLOCK) == StatusManager.BLOCK)) {
+
+			final boolean block = ((style & StatusManager.BLOCK) == StatusManager.BLOCK);
+
+			if (Display.getCurrent() != null) {
+				showStatusAdapter(statusAdapter, block);
+			} else {
+				Display.getDefault().asyncExec(() -> showStatusAdapter(statusAdapter, block));
+			}
+		}
+
+		if ((style & StatusManager.LOG) == StatusManager.LOG) {
+			StatusManager.getManager().addLoggedStatus(
+					statusAdapter.getStatus());
+			WorkbenchPlugin.getDefault().getLog()
+					.log(statusAdapter.getStatus());
+		}
+	}
+
+	/**
+	 * Requests the status dialog manager to show the status adapter.
+	 *
+	 * @param statusAdapter
+	 *            the status adapter to show
+	 * @param block
+	 *            <code>true</code> to request a modal dialog and suspend the
+	 *            calling thread till the dialog is closed, <code>false</code>
+	 *            otherwise.
+	 */
+	private void showStatusAdapter(StatusAdapter statusAdapter, boolean block) {
+		if (!PlatformUI.isWorkbenchRunning()) {
+			// we are shutting down, so just log
+			WorkbenchPlugin.log(statusAdapter.getStatus());
+			return;
+		}
+
+		getStatusDialogManager().addStatusAdapter(statusAdapter, block);
+
+		if (block) {
+			Shell shell;
+			while ((shell = getStatusDialogShell()) != null
+					&& !shell.isDisposed()) {
+				if (!shell.getDisplay().readAndDispatch()) {
+					Display.getDefault().sleep();
+				}
+			}
+		}
+	}
+
+	private Shell getStatusDialogShell() {
+		return (Shell) getStatusDialogManager().getProperty(
+				IStatusDialogConstants.SHELL);
+	}
+
+	/**
+	 * This method returns current {@link WorkbenchStatusDialogManager}.
+	 *
+	 * @return current {@link WorkbenchStatusDialogManager}
+	 */
+	private WorkbenchStatusDialogManager getStatusDialogManager() {
+		if (statusDialogManager == null) {
+			synchronized (this) {
+				if (statusDialogManager == null) {
+					statusDialogManager = new WorkbenchStatusDialogManager(null);
+					statusDialogManager.setProperty(
+							IStatusDialogConstants.SHOW_SUPPORT, Boolean.TRUE);
+					statusDialogManager.setProperty(
+							IStatusDialogConstants.HANDLE_OK_STATUSES,
+							Boolean.TRUE);
+					statusDialogManager.setProperty(
+							IStatusDialogConstants.ERRORLOG_LINK, Boolean.TRUE);
+					configureStatusDialog(statusDialogManager);
+				}
+			}
+		}
+		return statusDialogManager;
+	}
+
+	/**
+	 * This methods should be overridden to configure
+	 * {@link WorkbenchStatusDialogManager} behavior. It is advised to use only
+	 * following methods of {@link WorkbenchStatusDialogManager}:
+	 * <ul>
+	 * <li>{@link WorkbenchStatusDialogManager#enableDefaultSupportArea(boolean)}</li>
+	 * <li>{@link WorkbenchStatusDialogManager#setDetailsAreaProvider(AbstractStatusAreaProvider)}</li>
+	 * <li>{@link WorkbenchStatusDialogManager#setSupportAreaProvider(AbstractStatusAreaProvider)}</li>
+	 * </ul>
+	 * Default configuration does nothing.
+	 *
+	 * @param statusDialog
+	 *            a status dialog to be configured.
+	 * @since 3.4
+	 */
+	protected void configureStatusDialog(
+			final WorkbenchStatusDialogManager statusDialog) {
+		// default configuration does nothing
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/statushandlers/WorkbenchStatusDialogManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/statushandlers/WorkbenchStatusDialogManager.java
new file mode 100644
index 0000000..3482819
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/statushandlers/WorkbenchStatusDialogManager.java
@@ -0,0 +1,306 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2015 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.ui.statushandlers;
+
+import org.eclipse.ui.internal.statushandlers.IStatusDialogConstants;
+
+import java.util.Collection;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.QualifiedName;
+import org.eclipse.jface.dialogs.ErrorDialog;
+import org.eclipse.jface.dialogs.ErrorSupportProvider;
+import org.eclipse.jface.util.Policy;
+import org.eclipse.jface.viewers.ILabelDecorator;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.internal.statushandlers.WorkbenchStatusDialogManagerImpl;
+import org.eclipse.ui.progress.IProgressConstants;
+
+/**
+ * <p>
+ * The {@link WorkbenchStatusDialogManager} is a utility class for displaying
+ * one or more messages (errors, warnings or infos) to the user. The dialog
+ * supplied has a Details button that opens/closes the details area. The default
+ * {@link AbstractStatusAreaProvider} displays a tree of {@link StatusAdapter}s
+ * related to the selected item on the messages list. The dialog also hasa
+ * Support button that opens/closes the support area which contains the provided
+ * {@link AbstractStatusAreaProvider}. The Support button is disabled and not
+ * visible unless
+ * {@link WorkbenchStatusDialogManager#enableDefaultSupportArea(boolean)} is
+ * invoked.
+ * </p>
+ *
+ * <p>
+ * The default details area can be replaced using
+ * {@link WorkbenchStatusDialogManager#setDetailsAreaProvider(AbstractStatusAreaProvider)}
+ * </p>
+ *
+ * <p>
+ * The default support area can be replaced using
+ * {@link WorkbenchStatusDialogManager#setSupportAreaProvider(AbstractStatusAreaProvider)}
+ * or {@link Policy#setErrorSupportProvider(ErrorSupportProvider)}.
+ * </p>
+ *
+ * <p>
+ * The manager can switch from a non-modal dialog to a modal dialog. See
+ * {@link #addStatusAdapter(StatusAdapter, boolean)}
+ * </p>
+ *
+ * @see Policy#setErrorSupportProvider(ErrorSupportProvider)
+ * @see ErrorSupportProvider
+ * @see AbstractStatusAreaProvider
+ *
+ * @since 3.4
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class WorkbenchStatusDialogManager {
+
+	static final QualifiedName HINT = new QualifiedName(
+			IStatusAdapterConstants.PROPERTY_PREFIX, "hint"); //$NON-NLS-1$
+
+	private WorkbenchStatusDialogManagerImpl manager;
+
+	/**
+	 * Creates workbench status dialog.
+	 *
+	 * @param displayMask
+	 *            the mask used to filter the handled <code>StatusAdapter</code>
+	 *            objects, the mask is a logical sum of status severities
+	 * @param dialogTitle
+	 *            the title of the dialog. If null, than default will be used.
+	 */
+
+	public WorkbenchStatusDialogManager(int displayMask, String dialogTitle) {
+		manager = new WorkbenchStatusDialogManagerImpl(displayMask, dialogTitle);
+	}
+
+	/**
+	 * Creates workbench status dialog.
+	 *
+	 * @param parentShell
+	 *            the parent shell for the dialog. It may be null.
+	 * @param displayMask
+	 *            the mask used to filter the handled <code>StatusAdapter</code>
+	 *            objects, the mask is a logical sum of status severities
+	 * @param dialogTitle
+	 *            the title of the dialog. If null, than default will be used.
+	 * @deprecated As of 3.4 the <code>parentShell<code> is ignored
+	 * @see #WorkbenchStatusDialogManager(int, String)
+	 */
+	@Deprecated
+	public WorkbenchStatusDialogManager(Shell parentShell, int displayMask,
+			String dialogTitle) {
+		this(displayMask, dialogTitle);
+	}
+
+	/**
+	 * Creates workbench status dialog.
+	 *
+	 * @param dialogTitle
+	 *            the title of the dialog. If null, than default will be used.
+	 */
+	public WorkbenchStatusDialogManager(String dialogTitle) {
+		this(IStatus.INFO | IStatus.WARNING | IStatus.ERROR | IStatus.CANCEL,
+				dialogTitle);
+	}
+
+	/**
+	 * Creates workbench status dialog.
+	 *
+	 * @param parentShell
+	 *            the parent shell for the dialog. It may be null.
+	 * @param dialogTitle
+	 *            the title of the dialog. If null, than default will be used.
+	 * @deprecated As of 3.4 the <code>parentShell<code> is ignored
+	 * @see #WorkbenchStatusDialogManager(String)
+	 */
+	@Deprecated
+	public WorkbenchStatusDialogManager(Shell parentShell, String dialogTitle) {
+		this(dialogTitle);
+	}
+
+	/**
+	 * <p>
+	 * Adds a new {@link StatusAdapter} to the status adapters list in the
+	 * dialog.
+	 * </p>
+	 * <p>
+	 * If the dialog is already visible, the status adapter will be shown
+	 * immediately. Otherwise, the dialog with the added status adapter will
+	 * show up, if all conditions below are false.
+	 * <ul>
+	 * <li>the status adapter has
+	 * {@link IProgressConstants#NO_IMMEDIATE_ERROR_PROMPT_PROPERTY} set to true</li>
+	 * </ul>
+	 * </p>
+	 * <p>
+	 * All not shown status adapters will be displayed as soon as the dialog
+	 * shows up.
+	 * </p>
+	 *
+	 * @param modal
+	 *            <code>true</code> if the dialog should be modal,
+	 *            <code>false</code> otherwise
+	 * @param statusAdapter
+	 *            the status adapter
+	 */
+	public void addStatusAdapter(final StatusAdapter statusAdapter,
+			final boolean modal) {
+		manager.addStatusAdapter(statusAdapter, modal);
+	}
+
+	/**
+	 * Enables the default support area that shows stack trace of the exception
+	 * contained in the selected status.
+	 *
+	 * @param enable
+	 *            true enables, false disables default support
+	 */
+	public void enableDefaultSupportArea(boolean enable) {
+		manager.getDialogState().put(
+				IStatusDialogConstants.ENABLE_DEFAULT_SUPPORT_AREA,
+				Boolean.valueOf(enable));
+	}
+
+	/**
+	 * Gets a collection of status adapters that were passed to the dialog.
+	 *
+	 * @return collection of {@link StatusAdapter} objects
+	 */
+	public Collection getStatusAdapters() {
+		return manager.getStatusAdapters();
+	}
+
+	/**
+	 * Sets the details area provider. If null is set, the default area provider
+	 * will be used.
+	 *
+	 * @param provider
+	 *            A details area provider to be set.
+	 */
+	public void setDetailsAreaProvider(AbstractStatusAreaProvider provider) {
+		manager.setProperty(IStatusDialogConstants.CUSTOM_DETAILS_PROVIDER,
+				provider);
+	}
+
+	/**
+	 * Sets new label provider for the status list. This label provider is used
+	 * also to display the second message on the dialog if only one status is
+	 * available.
+	 *
+	 * <p>
+	 * This method is no longer recommended to use as it is impossible to
+	 * achieve consistent behavior after changing only one label provider.
+	 * </p>
+	 *
+	 * @deprecated As of 3.5 {@link #setMessageDecorator} is recommended.
+	 *
+	 * @param labelProvider
+	 *            a label provider to be used when displaying status adapters.
+	 */
+	@Deprecated
+	public void setStatusListLabelProvider(ITableLabelProvider labelProvider) {
+		manager.setStatusListLabelProvider(labelProvider);
+	}
+
+	/**
+	 * Sets the support provider.
+	 *
+	 * The policy for choosing support provider is:
+	 * <ol>
+	 * <li>use the support provider set by this method, if set</li>
+	 * <li>use the support provider set in JFace Policy, if set</li>
+	 * <li>use the default support area, if enabled</li>
+	 * </ol>
+	 *
+	 * @param provider
+	 *            Support provider to be set.
+	 */
+	public void setSupportAreaProvider(AbstractStatusAreaProvider provider) {
+		manager.setProperty(IStatusDialogConstants.CUSTOM_SUPPORT_PROVIDER,
+				provider);
+	}
+
+	/**
+	 * <p>
+	 * This methods sets up the decorator, which is used to modify displayed
+	 * strings extracted from StatusAdapter. The decorator should be used to
+	 * remove technical codes from the dialog, f.e. following message
+	 * "<i>ERR2008 Invalid password</i>" can be translated into
+	 * "<i>Invalid password</i>".
+	 * </p>
+	 * <p>
+	 * The decorator will be applied only to messages extracted from
+	 * StatusAdapter (predefined messages like
+	 * "This status has children statuses. See 'Details' for more information."
+	 * are not affected.
+	 * </p>
+	 * <p>
+	 * This method should not be used together with
+	 * {@link #setStatusListLabelProvider(ITableLabelProvider)}.
+	 * </p>
+	 *
+	 * @param decorator
+	 *            - the decorator to be set. Only
+	 *            {@link ILabelDecorator#decorateText(String, Object)} method
+	 *            will be used. This method should return <code>null</code> if
+	 *            and only if the first argument is null. StatusAdapter is
+	 *            passed as second parameter. Other methods should have default
+	 *            behavior as they may be used in future versions of the dialog.
+	 * @since 3.5
+	 */
+	public void setMessageDecorator(ILabelDecorator decorator){
+		manager.setMessageDecorator(decorator);
+	}
+
+	/**
+	 * This method sets various properties on the manager.
+	 *
+	 * @param key
+	 *            a key of the property to be set.
+	 * @param value
+	 *            a value of the property to be set. The value must be of type
+	 *            specified by the property key. <code>null</code> should never
+	 *            be passed unless the property key javadoc allows for that.
+	 * @since 3.5
+	 */
+	public void setProperty(Object key, Object value){
+		manager.setProperty(key, value);
+	}
+
+	/**
+	 * This method gets various dialog properties.
+	 *
+	 * @param key
+	 *            a key of the property to be get.
+	 * @return a value of the property. The value will be of type specified by
+	 *         the property key. <code>null</code> can be returned.
+	 * @since 3.5
+	 */
+	public Object getProperty(Object key){
+		return manager.getProperty(key);
+	}
+
+
+	/**
+	 * This method makes the dialog to be similar to the JFace ErrorDialog. The
+	 * dialog handles {@link StatusAdapter}s wrapping {@link IStatus} with
+	 * severity {@link IStatus#OK}, does not display the link to the error log,
+	 * does not display the link to the support area but always opens it.
+	 *
+	 * @see ErrorDialog
+	 * @since 3.5
+	 */
+	public void enableErrorDialogCompatibility(){
+		manager.enableErrorDialogCompatibility();
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/statushandlers/package.html b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/statushandlers/package.html
new file mode 100644
index 0000000..7a7a092
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/statushandlers/package.html
@@ -0,0 +1,14 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <title>Package-level Javadoc</title>
+</head>
+<body>
+Application programming interfaces for interaction
+with and extension of the Eclipse Platform User Interface.
+<h2>Package Specification</h2>
+This package provides API for handling problems occured in the Eclipse based applications.
+See the org.eclipse.ui.statusHandlers extension point. 
+</body>
+</html>
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/swt/IFocusService.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/swt/IFocusService.java
new file mode 100644
index 0000000..e6545c1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/swt/IFocusService.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.ui.swt;
+
+import org.eclipse.swt.widgets.Control;
+
+/**
+ * Tracks focusGained and focusLost events for a Control registered with this
+ * service, and provides the control and its registered ID as variables to the
+ * application evaluation context for evaluation by the various services.
+ * <p>
+ * This service provides 2 variables, activeFocusControl (a Control) and
+ * activeFocusControlId (the ID registered with the service).
+ * </p>
+ * <p>
+ * You can use this service to provide default cut/copy/paste/selectAll for
+ * specific text controls outside of the normal workbench part lifecycle, like a
+ * control contributed to the trim. For example:
+ * </p>
+ * <p>
+ *
+ * <pre>
+ * &lt;handler
+ *      class=&quot;org.eclipse.ui.internal.handlers.WidgetMethodHandler:paste&quot;
+ *      commandId=&quot;org.eclipse.ui.edit.paste&quot;&gt;
+ *   &lt;activeWhen&gt;
+ *      &lt;with variable=&quot;activeFocusControlId&quot;&gt;
+ *         &lt;equals value=&quot;org.eclipse.ui.tests.focusText&quot;/&gt;
+ *      &lt;/with&gt;
+ *   &lt;/activeWhen&gt;
+ * &lt;/handler&gt;
+ * </pre>
+ *
+ * </p>
+ * <p>
+ * This service can be acquired from your service locator:
+ * <pre>
+ * 	IFocusService service = (IFocusService) getSite().getService(IFocusService.class);
+ * </pre>
+ * <ul>
+ * <li>This service is available globally.</li>
+ * </ul>
+ * </p>
+ *
+ * @noimplement This interface is not intended to be implemented by clients.
+ *
+ * @see org.eclipse.ui.ISources
+ * @since 3.3
+ */
+public interface IFocusService {
+	/**
+	 * Use the value to provide default copy behaviour in a handler element
+	 * class attribute.
+	 */
+	public static final String COPY_HANDLER = "org.eclipse.ui.internal.handlers.WidgetMethodHandler:copy"; //$NON-NLS-1$
+
+	/**
+	 * Use the value to provide default paste behaviour in a handler element
+	 * class attribute.
+	 */
+	public static final String PASTE_HANDLER = "org.eclipse.ui.internal.handlers.WidgetMethodHandler:paste"; //$NON-NLS-1$
+
+	/**
+	 * Use the value to provide default cut behaviour in a handler element class
+	 * attribute.
+	 */
+	public static final String CUT_HANDLER = "org.eclipse.ui.internal.handlers.WidgetMethodHandler:cut"; //$NON-NLS-1$
+
+	/**
+	 * Use the value to provide default select all behaviour in a handler
+	 * element class attribute.
+	 */
+	public static final String SELECT_ALL_HANDLER = "org.eclipse.ui.internal.handlers.SelectAllHandler"; //$NON-NLS-1$
+
+	/**
+	 * A Control for which the service will track focus. When in focus, this
+	 * Control and its ID will be provided as variables to core expressions for
+	 * the various services, as activeFocusControl and activeFocusControlId
+	 * respectively.
+	 * <p>
+	 * A control must only be registered once, but different controls can be
+	 * registered with the same ID. Expressions evaluated against the
+	 * activeFocusControlId would then be true for all of the controls thus
+	 * registered.
+	 * </p>
+	 * <p>
+	 * We will remove ourselves as a listener when the Control is disposed.
+	 * </p>
+	 *
+	 * @param control
+	 *            the control. Must not be <code>null</code>. If the control
+	 *            is already registered with this service this call is a no-op.
+	 * @param id
+	 *            an ID for this control. Must not be <code>null</code>.
+	 */
+	public void addFocusTracker(Control control, String id);
+
+	/**
+	 * No longer track focus events for this control. Use this method when the
+	 * control should no longer be tracked, but is not disposed.
+	 *
+	 * @param control
+	 *            the control registered with the service. Must not be
+	 *            <code>null</code>.
+	 */
+	public void removeFocusTracker(Control control);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/swt/package.html b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/swt/package.html
new file mode 100644
index 0000000..0fed817
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/swt/package.html
@@ -0,0 +1,14 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <title>Package-level Javadoc</title>
+</head>
+<body>
+Application programming interfaces for interaction
+with and extension of the Eclipse Platform User Interface.
+<h2>Package Specification</h2>
+This package provides API so an in-focus control can participate in the Commands
+and Handlers framework.
+</body>
+</html>
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/testing/ContributionInfo.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/testing/ContributionInfo.java
new file mode 100644
index 0000000..a0921cc
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/testing/ContributionInfo.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2010 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.ui.testing;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+
+/**
+ * Instances of this class describe a contribution of an element of a certain
+ * type to the UI.
+ * 
+ * @since 1.4
+ */
+public class ContributionInfo {
+
+	private String bundleId;
+	private String elementType;
+	private IConfigurationElement configurationElement;
+
+	/**
+	 * Creates a new instance.
+	 * 
+	 * @param bundleId
+	 * @param elementType
+	 *            a localized string describing the contribution (e.g., 'view',
+	 *            'editor', 'preference page')
+	 * @param configurationElement
+	 *            an optional configuration element, or <code>null</code>.
+	 */
+	public ContributionInfo(String bundleId, String elementType,
+			IConfigurationElement configurationElement) {
+		super();
+		this.bundleId = bundleId;
+		this.elementType = elementType;
+		this.configurationElement = configurationElement;
+	}
+
+	/**
+	 * @return Returns the bundleId.
+	 */
+	public String getBundleId() {
+		return bundleId;
+	}
+
+	/**
+	 * @return Returns the elementType, a localized string describing the
+	 *         contribution (e.g., 'view', 'editor', 'preference page').
+	 */
+	public String getElementType() {
+		return elementType;
+	}
+	
+	/**
+	 * @return Returns the configurationElement or <code>null</code> if no
+	 *         configuration element is available.
+	 */
+	public IConfigurationElement getConfigurationElement() {
+		return configurationElement;
+	}
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/testing/ITestHarness.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/testing/ITestHarness.java
new file mode 100644
index 0000000..a4a0542
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/testing/ITestHarness.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2006 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.ui.testing;
+
+/**
+ * Represents an arbitrary test harness.
+ * 
+ * @since 1.1
+ */
+public interface ITestHarness {
+
+    /**
+     * Runs the tests.
+     */
+    public void runTests();
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/testing/IWorkbenchPartTestable.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/testing/IWorkbenchPartTestable.java
new file mode 100644
index 0000000..2303ecd
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/testing/IWorkbenchPartTestable.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2006 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.ui.testing;
+
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * This interface provides methods that allow introspection of workbench parts.
+ * Instances may be obtained by calling
+ * {@link org.eclipse.core.runtime.IAdaptable#getAdapter(Class)} on
+ * {@link org.eclipse.ui.IWorkbenchPartSite}.
+ * 
+ * <p>
+ * This interface is not intended to be implemented or extended by clients.
+ * </p>
+ * 
+ * @since 1.1
+ */
+public interface IWorkbenchPartTestable {
+
+	/**
+	 * Get the {@link org.eclipse.swt.widgets.Composite} provided to the parts
+	 * {@link org.eclipse.ui.IWorkbenchPart#createPartControl(Composite)}
+	 * method.
+	 * 
+	 * @return the composite
+	 */
+	public Composite getControl();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/testing/TestableObject.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/testing/TestableObject.java
new file mode 100644
index 0000000..3b4a5c1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/testing/TestableObject.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2006 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.ui.testing;
+
+import org.eclipse.core.runtime.Assert;
+
+/**
+ * A testable object.
+ * Allows a test harness to register itself with a testable object.
+ * The test harness is notified of test-related lifecycle events,
+ * such as when is an appropriate time to run tests on the object.
+ * This also provides API for running tests as a runnable, and for signaling
+ * when the tests are starting and when they are finished.
+ * <p>
+ * The workbench provides an implementation of this facade, available
+ * via <code>PlatformUI.getTestableObject()</code>.
+ * </p>
+ * 
+ * @since 1.1
+ */
+public class TestableObject {
+
+    private ITestHarness testHarness;
+
+    /**
+     * Returns the test harness, or <code>null</code> if it has not yet been set.
+     * 
+     * @return the test harness or <code>null</code>
+     */
+    public ITestHarness getTestHarness() {
+        return testHarness;
+    }
+
+    /**
+     * Sets the test harness.
+     * 
+     * @param testHarness the test harness
+     */
+    public void setTestHarness(ITestHarness testHarness) {
+        Assert.isNotNull(testHarness);
+        this.testHarness = testHarness;
+    }
+
+    /**
+     * Runs the given test runnable.
+     * The default implementation simply invokes <code>run</code> on the
+     * given test runnable.  Subclasses may extend.
+     * 
+     * @param testRunnable the test runnable to run
+     */
+    public void runTest(Runnable testRunnable) {
+        testRunnable.run();
+    }
+
+    /**
+     * Notification from the test harness that it is starting to run
+     * the tests.
+     * The default implementation does nothing.
+     * Subclasses may override.
+     */
+    public void testingStarting() {
+        // do nothing
+    }
+
+    /**
+     * Notification from the test harness that it has finished running the
+     * tests.
+     * The default implementation does nothing.
+     * Subclasses may override.
+     */
+    public void testingFinished() {
+        // do nothing
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/testing/package.html b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/testing/package.html
new file mode 100644
index 0000000..d05b854
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/testing/package.html
@@ -0,0 +1,18 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <meta name="Author" content="IBM">
+   <meta name="GENERATOR" content="Mozilla/4.5 [en] (WinNT; I) [Netscape]">
+   <title>Package-level Javadoc</title>
+</head>
+<body>
+<p>Classes for testing support.</p>
+<h2>
+Package Specification</h2>
+<p>
+This package contains classes and interfaces to support testing and introspection.
+</p>
+
+</body>
+</html>
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/themes/ColorUtil.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/themes/ColorUtil.java
new file mode 100644
index 0000000..ed1f8ce
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/themes/ColorUtil.java
@@ -0,0 +1,208 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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
+ *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
+ *******************************************************************************/
+package org.eclipse.ui.themes;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import org.eclipse.jface.resource.DataFormatException;
+import org.eclipse.jface.resource.StringConverter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * Useful color utilities.
+ *
+ * @since 3.0 - initial release
+ * @since 3.2 - public API
+ */
+public final class ColorUtil {
+
+	private static Field[] cachedFields;
+
+	/**
+	 * Process the given string and return a corresponding RGB object.
+	 *
+	 * @param value
+	 *            the SWT constant <code>String</code>
+	 * @return the value of the SWT constant, or <code>SWT.COLOR_BLACK</code>
+	 *         if it could not be determined
+	 */
+	private static RGB process(String value) {
+		Field [] fields = getFields();
+		try {
+			for (Field field : fields) {
+				if (field.getName().equals(value)) {
+					return getSystemColor(field.getInt(null));
+				}
+			}
+		} catch (IllegalArgumentException e) {
+			// no op - shouldnt happen. We check for static before calling
+			// getInt(null)
+		} catch (IllegalAccessException e) {
+			// no op - shouldnt happen. We check for public before calling
+			// getInt(null)
+		}
+		return getSystemColor(SWT.COLOR_BLACK);
+	}
+
+	/**
+	 * Get the SWT constant fields.
+	 *
+	 * @return the fields
+	 * @since 3.3
+	 */
+	private static Field[] getFields() {
+		if (cachedFields == null) {
+			Class<SWT> clazz = SWT.class;
+			Field[] allFields = clazz.getDeclaredFields();
+			ArrayList<Field> applicableFields = new ArrayList<>(allFields.length);
+
+			for (Field field : allFields) {
+				if (field.getType() == Integer.TYPE
+						&& Modifier.isStatic(field.getModifiers())
+						&& Modifier.isPublic(field.getModifiers())
+						&& Modifier.isFinal(field.getModifiers())
+						&& field.getName().startsWith("COLOR")) { //$NON-NLS-1$
+
+					applicableFields.add(field);
+				}
+			}
+			cachedFields = applicableFields.toArray(new Field[applicableFields.size()]);
+		}
+		return cachedFields;
+	}
+
+	/**
+	 * Blends the two color values according to the provided ratio.
+	 *
+	 * @param c1
+	 *            first color
+	 * @param c2
+	 *            second color
+	 * @param ratio
+	 *            percentage of the first color in the blend (0-100)
+	 * @return the RGB value of the blended color
+	 *
+	 * @since 3.3
+	 */
+	public static RGB blend(RGB c1, RGB c2, int ratio) {
+		int r = blend(c1.red, c2.red, ratio);
+		int g = blend(c1.green, c2.green, ratio);
+		int b = blend(c1.blue, c2.blue, ratio);
+		return new RGB(r, g, b);
+	}
+
+	private static int blend(int v1, int v2, int ratio) {
+		int b = (ratio * v1 + (100 - ratio) * v2) / 100;
+		return Math.min(255, b);
+	}
+
+	/**
+	 * Blend the two color values returning a value that is halfway between
+	 * them.
+	 *
+	 * @param val1
+	 *            the first value
+	 * @param val2
+	 *            the second value
+	 * @return the blended color
+	 */
+	public static RGB blend(RGB val1, RGB val2) {
+		int red = blend(val1.red, val2.red);
+		int green = blend(val1.green, val2.green);
+		int blue = blend(val1.blue, val2.blue);
+		return new RGB(red, green, blue);
+	}
+
+	/**
+	 * Blend the two color values returning a value that is halfway between
+	 * them.
+	 *
+	 * @param temp1
+	 *            the first value
+	 * @param temp2
+	 *            the second value
+	 * @return the blended int value
+	 */
+	private static int blend(int temp1, int temp2) {
+		return (Math.abs(temp1 - temp2) / 2) + Math.min(temp1, temp2);
+	}
+
+	/**
+	 * Return the system color that matches the provided SWT constant value.
+	 *
+	 * @param colorId
+	 *            the system color identifier
+	 * @return the RGB value of the supplied system color
+	 */
+	private static RGB getSystemColor(int colorId) {
+		return Display.getCurrent().getSystemColor(colorId).getRGB();
+	}
+
+	/**
+	 * Get the RGB value for a given color.
+	 *
+	 * @param rawValue
+	 *            the raw value, either an RGB triple or an SWT constant name
+	 * @return the RGB value
+	 * @throws DataFormatException
+	 *             thrown if the value cannot be interpreted as a color
+	 */
+	public static RGB getColorValue(String rawValue) throws DataFormatException {
+		if (rawValue == null) {
+			return null;
+		}
+
+		rawValue = rawValue.trim();
+
+		if (!isDirectValue(rawValue)) {
+			return process(rawValue);
+		}
+
+		return StringConverter.asRGB(rawValue);
+	}
+
+	/**
+	 * Get the RGB values for a given color array.
+	 *
+	 * @param rawValues
+	 *            the raw values, either RGB triple or an SWT constant
+	 * @return the RGB values
+	 */
+	public static RGB[] getColorValues(String[] rawValues) {
+		RGB[] values = new RGB[rawValues.length];
+		for (int i = 0; i < rawValues.length; i++) {
+			values[i] = getColorValue(rawValues[i]);
+		}
+		return values;
+	}
+
+	/**
+	 * Return whether the value returned by <code>getValue()</code> is already
+	 * in RGB form.
+	 *
+	 * @return whether the value returned by <code>getValue()</code> is
+	 *         already in RGB form
+	 */
+	private static boolean isDirectValue(String rawValue) {
+		return rawValue.indexOf(',') >= 0;
+	}
+
+	/**
+	 * Not intended to be instantiated.
+	 */
+	private ColorUtil() {
+		// no-op
+	}
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/themes/IColorFactory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/themes/IColorFactory.java
new file mode 100644
index 0000000..f6eb621
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/themes/IColorFactory.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.themes;
+
+import org.eclipse.swt.graphics.RGB;
+
+/**
+ * A factory interface that may be used to specify a color value.  This is
+ * (optionally) used by the themes extension point for color value
+ * definitions.
+ * <p>
+ * Example usage:
+ * <br/>
+ * <code>
+ * &lt;colorDefinition
+ *     label="Custom Color"
+ *     id="example.customColor"
+ * 	   colorFactory="some.implementor.of.IColorFactory"&gt;
+ * &lt;/colorDefinition&gt;
+ * </code>
+ * </p>
+ *
+ * @since 3.0
+ */
+public interface IColorFactory {
+
+    /**
+     * Create a new color.
+     *
+     * @return a new color.  This must never be <code>null</code>.
+     */
+    RGB createColor();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/themes/ITheme.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/themes/ITheme.java
new file mode 100644
index 0000000..54603a1
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/themes/ITheme.java
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.themes;
+
+import java.util.Set;
+
+import org.eclipse.jface.resource.ColorRegistry;
+import org.eclipse.jface.resource.FontRegistry;
+import org.eclipse.jface.util.IPropertyChangeListener;
+
+/**
+ * A theme is a collection of colors, fonts and supporting data that may
+ * be used by plugins to help provide uniform look and feel to their components.
+ * The workbench has a default theme (one whos id has the value {@link org.eclipse.ui.themes.IThemeManager#DEFAULT_THEME})
+ * that defines the initial values for a collection of fonts and colors.  Other
+ * themes may extend and override the default theme to provide new values.
+ *
+ * <p>
+ * Clients may obtain themes via {@link org.eclipse.ui.themes.IThemeManager#getTheme(String)}.
+ * </p>
+ *
+ * <p>
+ * This interface is not intended to be implemented or extended by clients.
+ * </p>
+ *
+ * @see org.eclipse.ui.IWorkbench#getThemeManager()
+ * @since 3.0
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface ITheme {
+
+    /**
+     * Adds a property listener to the theme.  Any events fired by the
+     * underlying registries will cause an event to be fired.  This event is the
+     * same event that was fired by the registry.  As such, the "source"
+     * attribute of the event will not be this theme, but rather the color or
+     * font registry.
+     *
+     * @param listener the listener to add
+     */
+    void addPropertyChangeListener(IPropertyChangeListener listener);
+
+    /**
+     * Dispose of this theme.  This method is called by the workbench when
+     * appropriate and should never be called by a user.
+     */
+    void dispose();
+
+    /**
+     * Get arbitrary data associated with this theme.
+     *
+     * @param key the key
+     * @return the data, or the default value <code>false</code> if none exists
+     * or if the value cannot be treated as a boolean.
+     */
+    boolean getBoolean(String key);
+
+    /**
+     * Return this themes color registry.
+     *
+     * @return this themes color registry
+     */
+    ColorRegistry getColorRegistry();
+
+    /**
+     * Return this themes font registry.
+     *
+     * @return this themes font registry
+     */
+    FontRegistry getFontRegistry();
+
+    /**
+     * Returns the id of this theme.
+     *
+     * @return the id of this theme.  Guaranteed not to be <code>null</code>.
+     */
+    String getId();
+
+    /**
+     * Get arbitrary data associated with this theme.
+     *
+     * @param key the key
+     * @return the data, or the default value <code>0</code> if none exists or
+     * if the value cannot be treated as an integer.
+     */
+    public int getInt(String key);
+
+    /**
+     * Returns the label of this theme.
+     *
+     * @return the label of this theme.  Guaranteed not be <code>null</code>.
+     */
+    String getLabel();
+
+    /**
+     * Get arbitrary data associated with this theme.
+     *
+     * @param key the key
+     * @return the data, or <code>null</code> if none exists.
+     */
+    String getString(String key);
+
+    /**
+     * Get the set of keys associated with this theme.
+     *
+     * @return the Set of keys
+     */
+    Set keySet();
+
+    /**
+     * Removes a property listener from the theme.
+     *
+     * @param listener the listener to remove
+     */
+    void removePropertyChangeListener(IPropertyChangeListener listener);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/themes/IThemeManager.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/themes/IThemeManager.java
new file mode 100644
index 0000000..15debba
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/themes/IThemeManager.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.themes;
+
+import org.eclipse.jface.util.IPropertyChangeListener;
+
+/**
+ * A theme manager is an object that contains references to usable
+ * <code>ITheme</code> objects and maintains a reference to the currently active
+ * theme.  This theme will be used by the workbench to decorate tab folders and
+ * other controls where possible.  The workbench implementation of this
+ * interface will push the values of the current theme into the underlying jface
+ * registries ({@link org.eclipse.jface.resource.ColorRegistry} and
+ * {@link org.eclipse.jface.resource.FontRegistry} whenever the current theme
+ * changes.  Clients who do not need access to specific themes may instead
+ * attach listeners to these registries directly.
+ *
+ * <p>
+ * This interface is not intended to be implemented or extended by clients.
+ * </p>
+ *
+ * @see org.eclipse.ui.IWorkbench#getThemeManager()
+ * @since 3.0
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IThemeManager {
+
+    /**
+     * Indicates that the current theme has changed to a new theme.
+     */
+    public static final String CHANGE_CURRENT_THEME = "CHANGE_CURRENT_THEME"; //$NON-NLS-1$
+
+    /**
+     * The default theme id.
+     */
+    public static final String DEFAULT_THEME = "org.eclipse.ui.defaultTheme"; //$NON-NLS-1$
+
+    /**
+     * Adds a property listener to the manager.  Any events fired by the
+     * underlying registries of the current theme will cause an event to be
+     * fired.  This event is the same event that was fired by the registry.
+     * As such, the "source" attribute of the event will not be this manager,
+     * but rather the color or font registry.  Additionally, an event is fired
+     * when the current theme changes to a new theme.  The "property" attribute
+     * of such an event will have the value {@link IThemeManager#CHANGE_CURRENT_THEME}.
+     *
+     * @param listener the listener to add
+     */
+    void addPropertyChangeListener(IPropertyChangeListener listener);
+
+    /**
+     * Get the currently active theme.
+     *
+     * @return the current theme.  This will never be <code>null</code>.
+     */
+    ITheme getCurrentTheme();
+
+    /**
+     * Get a theme.
+     *
+     * @param id the theme to find.
+     * @return the <code>ITheme</code> or <code>null</code> if it cannot be found.
+     */
+    ITheme getTheme(String id);
+
+    /**
+     * Removes a property listener from the workbench.
+     *
+     * @param listener the listener to remove
+     */
+    void removePropertyChangeListener(IPropertyChangeListener listener);
+
+    /**
+     * Set the currently active theme.
+     *
+     * @param id the id of the new active theme
+     */
+    void setCurrentTheme(String id);
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/themes/IThemePreview.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/themes/IThemePreview.java
new file mode 100644
index 0000000..e8c3d24
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/themes/IThemePreview.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.themes;
+
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * Interface used by theme element developers to preview the usage of their
+ * elements within the colors and fonts preference page.
+ *
+ * @since 3.0
+ */
+public interface IThemePreview {
+
+    /**
+     * Create the preview control.
+     *
+     * @param parent the Composite in which to create the example
+     * @param currentTheme the theme to preview
+     */
+    void createControl(Composite parent, ITheme currentTheme);
+
+    /**
+     * Dispose of resources used by this previewer.   This method is called by
+     * the workbench when appropriate and should never be called by a user.
+     */
+    void dispose();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/themes/RGBBlendColorFactory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/themes/RGBBlendColorFactory.java
new file mode 100644
index 0000000..dc8f619
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/themes/RGBBlendColorFactory.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.themes;
+
+import java.util.Hashtable;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExecutableExtension;
+import org.eclipse.swt.graphics.RGB;
+
+/**
+ * A resuable <code>IColorFactory</code> that may be used to blend two colors.
+ * The colors to blend are specified as per method number two in
+ * {@link org.eclipse.core.runtime.IExecutableExtension}.
+ * <p>
+ * Example usage:
+ * <br/>
+ * <code>
+ * &lt;colorDefinition
+ *     label="Red/Blue Blend"
+ *     id="example.redblueblend"&gt;
+ *     &lt;colorFactory
+ * 				plugin="org.eclipse.ui"
+ * 				class="org.eclipse.ui.themes.RGBBlendColorFactory"&gt;
+ *      	&lt;parameter name="color1" value="255,0,0" /&gt;
+ *  		&lt;parameter name="color2" value="COLOR_BLUE" /&gt;
+ *     &lt;/colorFactory&gt;
+ * &lt;/colorDefinition&gt;
+ * </code>
+ * </p>
+ *
+ * <p>
+ * The color values may be specified as RGB triples or as SWT constants.
+ * </p>
+ *
+ * @see org.eclipse.swt.SWT
+ * @since 3.0
+ */
+public class RGBBlendColorFactory implements IColorFactory,
+        IExecutableExtension {
+
+    private String color1, color2;
+
+    @Override
+	public RGB createColor() {
+        if (color1 == null && color2 == null) {
+            return new RGB(0, 0, 0);
+        } else if (color1 != null && color2 == null) {
+            return ColorUtil.getColorValue(color1);
+        } else if (color1 == null && color2 != null) {
+            return ColorUtil.getColorValue(color2);
+        } else {
+            RGB rgb1 = ColorUtil.getColorValue(color1);
+            RGB rgb2 = ColorUtil.getColorValue(color2);
+            return ColorUtil.blend(rgb1, rgb2);
+        }
+    }
+
+    /**
+     * This executable extension requires parameters to be explicitly declared
+     * via the second method described in the <code>IExecutableExtension</code>
+     * documentation.  This class expects that there will be two parameters,
+     * <code>color1</code> and <code>color2</code>, that describe the two colors
+     * to be blended.  These values may either be RGB triples or SWT constants.
+     *
+     * @see org.eclipse.core.runtime.IExecutableExtension#setInitializationData(org.eclipse.core.runtime.IConfigurationElement, java.lang.String, java.lang.Object)
+     */
+    @Override
+	public void setInitializationData(IConfigurationElement config,
+            String propertyName, Object data) throws CoreException {
+
+        if (data instanceof Hashtable) {
+            Hashtable table = (Hashtable) data;
+            color1 = (String) table.get("color1"); //$NON-NLS-1$
+            color2 = (String) table.get("color2"); //$NON-NLS-1$
+        }
+    }
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/themes/package.html b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/themes/package.html
new file mode 100644
index 0000000..59d2ffd
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/themes/package.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <meta name="Author" content="IBM">
+   <title>Package-level Javadoc</title>
+</head>
+<body>
+Application programming interfaces for interaction
+with and extension of the Eclipse Platform User Interface.
+<h2>
+Package Specification</h2>
+This package provides application programming interfaces for interaction
+with the themes.  A theme is a collection of fonts, colors, and supporting data
+that may be used by plugin developers to apply a certain look and feel to their 
+components.  Themes are also used by the workbench to apply look and feel to their
+active presentation component.
+</body>
+</html>
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/views/IStickyViewDescriptor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/views/IStickyViewDescriptor.java
new file mode 100644
index 0000000..07dbde5
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/views/IStickyViewDescriptor.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.views;
+
+/**
+ * Supplemental view interface that describes various sticky characteristics
+ * that a view may possess.
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ *
+ * @see org.eclipse.ui.views.IViewRegistry
+ * @see org.eclipse.ui.views.IViewDescriptor
+ * @since 3.1
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IStickyViewDescriptor {
+    /**
+     * Return the id of the view to be made sticky.
+     *
+     * @return the id of the view to be made sticky
+     */
+    public String getId();
+
+    /**
+     * Return the location of this sticky view.  Must be one of
+     * <code>IPageLayout.LEFT</code>, <code>IPageLayout.RIGHT</code>,
+     * <code>IPageLayout.TOP</code>, or <code>IPageLayout.BOTTOM</code>.
+     *
+     * @return the location constant
+     */
+    public int getLocation();
+
+    /**
+     * Return whether this view should be closeable.
+     *
+     * @return whether this view should be closeeable
+     */
+    public boolean isCloseable();
+
+    /**
+     * Return whether this view should be moveable.
+     *
+     * @return whether this view should be moveable
+     */
+    public boolean isMoveable();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/views/IViewCategory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/views/IViewCategory.java
new file mode 100644
index 0000000..0d58a15
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/views/IViewCategory.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.ui.views;
+
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * Represents a categorization of views.
+ *
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ *
+ * @since 3.1
+ */
+public interface IViewCategory {
+
+    /**
+     * Return the views contained within this category. Never <code>null</code>,
+     * but may be empty.
+     *
+     * @return the views contained within this category
+     */
+    IViewDescriptor[] getViews();
+
+    /**
+     * Return the id of this category.  Never <code>null</code>.
+     *
+     * @return the id
+     */
+    String getId();
+
+    /**
+     * Return the human readable name of this view category.  Never <code>null</code>.
+     *
+     * @return the label
+     */
+    String getLabel();
+
+    /**
+     * Return this categories path. The segments of this path will correspond to
+     * category ids.
+     *
+     * @return the path
+     */
+    IPath getPath();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/views/IViewDescriptor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/views/IViewDescriptor.java
new file mode 100644
index 0000000..8724bd8
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/views/IViewDescriptor.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Markus Alexander Kuppe, Versant Corporation - bug #215797
+ *******************************************************************************/
+package org.eclipse.ui.views;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IWorkbenchPartDescriptor;
+
+/**
+ * This is a view descriptor. It provides a "description" of a given
+ * given view so that the view can later be constructed.
+ * <p>
+ * The view registry provides facilities to map from an extension
+ * to a IViewDescriptor.
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ *
+ * @see org.eclipse.ui.views.IViewRegistry
+ * @since 3.1
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IViewDescriptor extends IWorkbenchPartDescriptor, IAdaptable {
+    /**
+     * Creates an instance of the view defined in the descriptor.
+     *
+     * @return the view part
+     * @throws CoreException thrown if there is a problem creating the part
+     */
+    public IViewPart createView() throws CoreException;
+
+    /**
+     * Returns an array of strings that represent
+     * view's category path. This array will be used
+     * for hierarchical presentation of the
+     * view in places like submenus.
+     * @return array of category tokens or null if not specified.
+     */
+    public String[] getCategoryPath();
+
+    /**
+     * Returns the description of this view.
+     *
+     * @return the description
+     */
+    public String getDescription();
+
+    /**
+     * Returns the id of the view.
+     *
+     * @return the id
+     */
+    @Override
+	public String getId();
+
+    /**
+     * Returns the descriptor for the icon to show for this view.
+     */
+    @Override
+	public ImageDescriptor getImageDescriptor();
+
+    /**
+     * Returns the label to show for this view.
+     *
+     * @return the label
+     */
+    @Override
+	public String getLabel();
+
+    /**
+     * Returns the default fast view width ratio for this view.
+     *
+     * @return the fast view width ratio
+     */
+    public float getFastViewWidthRatio();
+
+    /**
+     * Returns whether this view allows multiple instances.
+     *
+     * @return whether this view allows multiple instances
+     */
+    public boolean getAllowMultiple();
+
+    /**
+     * Returns whether this view can be restored upon workbench restart.
+     *
+     * @return whether whether this view can be restored upon workbench restart
+     * @since 3.4
+     */
+    public boolean isRestorable();
+
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/views/IViewRegistry.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/views/IViewRegistry.java
new file mode 100644
index 0000000..5622b15
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/views/IViewRegistry.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 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
+ *     Jan-Hendrik Diederich, Bredex GmbH - bug 201052
+ *******************************************************************************/
+package org.eclipse.ui.views;
+
+
+/**
+ * The view registry maintains a list of views explicitly registered
+ * against the view extension point..
+ * <p>
+ * The description of a given view is kept in a <code>IViewDescriptor</code>.
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ *
+ * @see org.eclipse.ui.views.IViewDescriptor
+ * @see org.eclipse.ui.views.IStickyViewDescriptor
+ * @since 3.1
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IViewRegistry {
+    /**
+     * Return a view descriptor with the given extension id.  If no view exists
+     * with the id return <code>null</code>.
+     * Will also return <code>null</code> if the view descriptor exists, but
+     * is filtered by an expression-based activity.
+     *
+     * @param id the id to search for
+     * @return the descriptor or <code>null</code>
+     */
+    public IViewDescriptor find(String id);
+
+    /**
+     * Returns an array of view categories.
+     *
+     * @return the categories.  Never <code>null</code>.
+     */
+    public IViewCategory[] getCategories();
+
+    /**
+     * Return a list of views defined in the registry.
+     *
+     * @return the views.  Never <code>null</code>.
+     */
+    public IViewDescriptor[] getViews();
+
+    /**
+     * Return a list of sticky views defined in the registry.
+     *
+     * @return the sticky views.  Never <code>null</code>.
+     */
+    public IStickyViewDescriptor[] getStickyViews();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/views/package.html b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/views/package.html
new file mode 100644
index 0000000..d73f41a
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/views/package.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <meta name="Author" content="IBM">
+   <title>Package-level Javadoc</title>
+</head>
+<body>
+Application programming interfaces for interaction
+with and extension of the Eclipse Platform User Interface.
+<h2>
+Package Specification</h2>
+This package provides API for querying the installed views and their properties.
+The view registry can be obtained using {@link org.eclipse.ui.IWorkbench#getViewRegistry()}.
+</body>
+</html>
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/wizards/IWizardCategory.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/wizards/IWizardCategory.java
new file mode 100644
index 0000000..5bcf903
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/wizards/IWizardCategory.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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
+ *     Jan-Hendrik Diederich, Bredex GmbH - bug 201052
+ *******************************************************************************/
+package org.eclipse.ui.wizards;
+
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * A wizard category may contain other categories or wizard elements.
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ *
+ * @since 3.1
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IWizardCategory {
+
+	/**
+	 * Returns the category child object corresponding to the passed path
+	 * (relative to this object), or <code>null</code> if such an object could
+	 * not be found.  The segments of this path should correspond to category ids.
+	 *
+	 * @param path
+	 *            the search path
+	 * @return the category or <code>null</code>
+	 */
+	IWizardCategory findCategory(IPath path);
+
+	/**
+	 * Find a wizard that has the provided id. This will search recursivly over
+	 * this categories children.
+	 *
+	 * @param id
+	 *            the id to search for
+	 * @return the wizard or <code>null</code>
+	 */
+	IWizardDescriptor findWizard(String id);
+
+	/**
+	 * Return the immediate child categories.
+	 *
+	 * @return the child categories. Never <code>null</code>.
+	 */
+	IWizardCategory[] getCategories();
+
+	/**
+	 * Return the identifier of this category.
+	 *
+	 * @return the identifier of this category
+	 */
+	String getId();
+
+	/**
+	 * Return the label for this category.
+	 *
+	 * @return the label for this category
+	 */
+	String getLabel();
+
+	/**
+	 * Return the parent category.
+	 *
+	 * @return the parent category. May be <code>null</code>.
+	 */
+	IWizardCategory getParent();
+
+	/**
+	 * Return this wizards path. The segments of this path will correspond to
+	 * category ids.
+	 *
+	 * @return the path
+	 */
+	IPath getPath();
+
+	/**
+	 * Return the wizards in this category, minus the wizards which failed
+	 * the Expressions check.
+	 *
+	 * @return the wizards in this category. Never <code>null</code>
+	 */
+	IWizardDescriptor[] getWizards();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/wizards/IWizardDescriptor.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/wizards/IWizardDescriptor.java
new file mode 100644
index 0000000..5da2656
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/wizards/IWizardDescriptor.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.wizards;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.IWorkbenchPartDescriptor;
+import org.eclipse.ui.IWorkbenchWizard;
+
+/**
+ * Base interface for all wizards defined via workbench extension points.
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ *
+ * @since 3.1
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IWizardDescriptor extends IWorkbenchPartDescriptor, IAdaptable {
+
+	/**
+	 * Answer the selection for the reciever based on whether the it can handle
+	 * the selection. If it can return the selection. If it can handle the
+	 * adapted to IResource value of the selection. If it satisfies neither of
+	 * these conditions return an empty IStructuredSelection.
+	 *
+	 * @return IStructuredSelection
+	 * @param selection
+	 *            IStructuredSelection
+	 */
+	IStructuredSelection adaptedSelection(IStructuredSelection selection);
+
+	/**
+	 * Return the description.
+	 *
+	 * @return the description
+	 */
+	String getDescription();
+
+	/**
+	 * Return the tags associated with this wizard.
+	 *
+	 * @return the tags associated with this wizard
+	 */
+	String [] getTags();
+
+	/**
+	 * Create a wizard.
+	 *
+	 * @return the wizard
+	 * @throws CoreException thrown if there is a problem creating the wizard
+	 */
+	IWorkbenchWizard createWizard() throws CoreException;
+
+	/**
+	 * Return the description image for this wizard.
+	 *
+	 * @return the description image for this wizard or <code>null</code>
+	 */
+	public ImageDescriptor getDescriptionImage();
+
+	/**
+	 * Return the help system href for this wizard.
+	 *
+	 * @return the help system href for this wizard or <code>null</code>
+	 */
+	String getHelpHref();
+
+	/**
+	 * Return the category for this wizard.
+	 *
+	 * @return the category or <code>null</code>
+	 */
+	IWizardCategory getCategory();
+
+	/**
+	 * Answer <code>true</code> if this wizard is able to finish without
+	 * loading any pages. This is a hint to any
+	 * {@link org.eclipse.jface.wizard.WizardSelectionPage} or container that
+	 * may contain this wizard to allow the finish button to be pressed without
+	 * actually entering the wizard. If this occurs the
+	 * {@link org.eclipse.jface.wizard.IWizard#performFinish()} method should be
+	 * invoked by the containing wizard without creating any pages.
+	 *
+	 * @return <code>true</code> if this wizard can finish immediately
+	 */
+	boolean canFinishEarly();
+
+	/**
+	 * Answer <code>true</code> if this wizard has any pages. This is a
+	 * hint to any {@link org.eclipse.jface.wizard.WizardSelectionPage} or
+	 * container that may contain this wizard that they should enable the "Next"
+	 * button, if appropriate.
+	 *
+	 * @return <code>true</code> if this wizard has wizard pages
+	 */
+	boolean hasPages();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/wizards/IWizardRegistry.java b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/wizards/IWizardRegistry.java
new file mode 100644
index 0000000..c094eb6
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/wizards/IWizardRegistry.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2015 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.ui.wizards;
+
+
+/**
+ * A registry describing all wizard extensions known to the workbench.
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ *
+ * @since 3.1
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IWizardRegistry {
+
+	/**
+	 * Find a wizard with the given id.
+	 *
+	 * @param id the id to search for
+	 * @return the wizard descriptor matching the given id or <code>null</code>
+	 */
+	IWizardDescriptor findWizard(String id);
+
+	/**
+	 * Return the wizards that have been designated as "primary".
+	 *
+	 * @return the primary wizard descriptors.  Never <code>null</code>.
+	 */
+	IWizardDescriptor [] getPrimaryWizards();
+
+	/**
+	 * Find the category with the given id.
+	 *
+	 * @param id the id of the category to search for
+	 * @return the category matching the given id or <code>null</code>
+	 */
+	IWizardCategory findCategory(String id);
+
+	/**
+	 * Return the root category.
+	 *
+	 * @return the root category.  Never <code>null</code>.
+	 */
+	IWizardCategory getRootCategory();
+}
diff --git a/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/wizards/package.html b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/wizards/package.html
new file mode 100644
index 0000000..5077aef
--- /dev/null
+++ b/bundles/org.eclipse.rap.ui.workbench/src/org/eclipse/ui/wizards/package.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <meta name="Author" content="IBM">
+   <title>Package-level Javadoc</title>
+</head>
+<body>
+Application programming interfaces for interaction with and extension of the Eclipse 
+Platform User Interface wizard support. See the org.eclipse.ui.wizards extension 
+point. 
+<h2>
+Package Specification</h2>
+This package provides application programming interfaces for support for wizards 
+such as registries, categories and descriptors. These types are used to build 
+wizard selection interfaces such as the new, import and export wizards. 
+</body>
+</html>